Skip to content

Commit

Permalink
feat(data-table): Resolve issues with table footer controls
Browse files Browse the repository at this point in the history
  • Loading branch information
sullivanpj committed Nov 28, 2024
1 parent 9fe3473 commit 3e873cd
Show file tree
Hide file tree
Showing 22 changed files with 462 additions and 157 deletions.
16 changes: 11 additions & 5 deletions components/button/src/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ import {
} from "@tamagui/core";
import { withStaticProperties } from "@tamagui/helpers";
import { LinearGradient } from "@tamagui/linear-gradient";
import { ThemeableStack, XStack } from "@tamagui/stacks";
import { ThemeableStack } from "@tamagui/stacks";
import type { TextContextStyles, TextParentStyles } from "@tamagui/text";
import { useCallback, useMemo, type FunctionComponent } from "react";
import { GestureResponderEvent } from "react-native";
Expand Down Expand Up @@ -173,7 +173,7 @@ export const ButtonContext = createStyledContext<ButtonContextProps>({
animate: true
});

const ButtonFrame = styled(XStack, {
const ButtonFrame = styled(View, {
name: "Button",
context: ButtonContext,

Expand All @@ -189,8 +189,9 @@ const ButtonFrame = styled(XStack, {
borderColor: "$borderColor",
borderWidth: 1,
flexWrap: "nowrap",
flexDirection: "row",
flex: 1,
flexShrink: 1,
// flexShrink: 1,
overflow: "hidden",

hoverStyle: {
Expand Down Expand Up @@ -388,7 +389,6 @@ const ButtonTextFrame = styled(LabelText, {
textTransform: "capitalize",
whiteSpace: "nowrap",
textOverflow: "ellipsis",
display: "inline-flex",

// flexGrow 1 leads to inconsistent native style where text pushes to start of view
flexGrow: 0,
Expand Down Expand Up @@ -585,7 +585,13 @@ const ButtonIcon = View.styleable(
: ColorThemeName.BASE;

return (
<View ref={forwardedRef} zIndex="$md" alignItems="center">
<View
ref={forwardedRef}
zIndex="$md"
alignItems="center"
// flexGrow 1 leads to inconsistent native style where text pushes to start of view
flexGrow={0}
flexShrink={1}>
<Theme name={theme} componentName="ButtonIcon">
<ThemeableIcon
{...props}
Expand Down
3 changes: 2 additions & 1 deletion components/data-table/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
"react-native": "0.74.1"
},
"dependencies": {
"@storm-stack/string-fns": "latest",
"@storm-stack/types": "latest",
"@tamagui/adapt": "^1.116.15",
"@tamagui/animate-presence": "^1.116.15",
"@tamagui/core": "^1.116.15",
Expand All @@ -45,7 +47,6 @@
"@tamagui/web": "^1.116.15",
"@tanstack/react-table": "^8.17.3",
"@tanstack/table-core": "^8.17.3",
"react-native-svg": "^15.8.0",
"title-case": "^4.3.1"
},
"devDependencies": {
Expand Down
160 changes: 122 additions & 38 deletions components/data-table/src/DataTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import { Pagination } from "@cyclone-ui/pagination";
import { SearchInputField } from "@cyclone-ui/search-input-field";
import { SelectField } from "@cyclone-ui/select-field";
import { Table, type TableProps } from "@cyclone-ui/table";
import { titleCase } from "@storm-stack/string-fns/title-case";
import type { SelectOption } from "@storm-stack/types/utility-types/form";
import { Adapt } from "@tamagui/adapt";
import { createStyledContext, View } from "@tamagui/core";
import { ArrowDownAZ, ArrowUpZA, Filter } from "@tamagui/lucide-icons";
Expand Down Expand Up @@ -50,9 +52,9 @@ import {
SetStateAction,
useCallback,
useLayoutEffect,
useMemo,
useState
} from "react";
import { titleCase } from "title-case";

export type DataTableContextProps = {
sorting: SortingState;
Expand Down Expand Up @@ -173,16 +175,19 @@ export function DataTable<TData extends RowData>({
</Table.Body>
{pageCount > 1 && (
<Table.Footer>
<DataTablePagination
setPageIndex={table.setPageIndex}
nextPage={table.nextPage}
previousPage={table.previousPage}
firstPage={table.firstPage}
lastPage={table.lastPage}
pageIndex={pagination.pageIndex}
pageSize={pagination.pageSize}
pageCount={pageCount}
/>
<Table.Row header={true}>
<DataTablePagination
setPageIndex={table.setPageIndex}
nextPage={table.nextPage}
previousPage={table.previousPage}
firstPage={table.firstPage}
lastPage={table.lastPage}
rowCount={data.length}
pageIndex={pagination.pageIndex}
pageSize={pagination.pageSize}
pageCount={pageCount}
/>
</Table.Row>
</Table.Footer>
)}
</Table>
Expand All @@ -207,7 +212,7 @@ export const DataTableCell = <TData extends RowData, TValue = any>(
const value = props.value ? props.value : props.renderValue();
return (
<SizableText
animation="medium"
animation="normal"
fontFamily="$body"
color="$color"
$group-row-hover={{ color: "$primary" }}>
Expand Down Expand Up @@ -261,18 +266,18 @@ export const DataTableHeader = <TData extends RowData, TValue = any>(
borderRightWidth={1}>
<XStack gap="$2" onPress={handleSorting} flex={1} cursor="pointer">
<SizableText
animation="medium"
animation="normal"
fontFamily="$label"
color="$primary"
size="$6"
$group-header-hover={{ color: "$fg" }}>
{titleCase(id.replaceAll("_", " "))}
{titleCase(id.replaceAll("_", " "))}
</SizableText>
{isSorted && !desc && (
<XStack gap="$0.25" alignItems="center">
<ArrowDownAZ size="$1" color="$primary" />
<SizableText
animation="medium"
animation="normal"
fontFamily="$label"
fontWeight="$6"
color="$primary"
Expand All @@ -285,7 +290,7 @@ export const DataTableHeader = <TData extends RowData, TValue = any>(
<XStack gap="$0.25" alignItems="center">
<ArrowUpZA size="$1" color="$primary" />
<SizableText
animation="medium"
animation="normal"
fontFamily="$label"
fontWeight="$6"
color="$primary"
Expand Down Expand Up @@ -375,6 +380,7 @@ export type DataTablePaginationProps<TData extends RowData> = Pick<
> &
Pick<PaginationState, "pageIndex" | "pageSize"> & {
pageCount: number;
rowCount: number;
};

export function DataTablePagination<TData extends RowData>({
Expand All @@ -383,36 +389,114 @@ export function DataTablePagination<TData extends RowData>({
previousPage,
firstPage,
lastPage,
rowCount,
pageIndex,
pageSize,
pageCount
pageCount,
...props
}: DataTablePaginationProps<TData>) {
const pageSizes = useMemo(() => {
const result = [] as SelectOption<number>[];
if (rowCount >= 5) {
result.push({
index: result.length,
name: "5",
value: 5,
selected: false,
disabled: false
});
}
if (rowCount >= 10) {
result.push({
index: result.length,
name: "10",
value: 10,
selected: false,
disabled: false
});
}
if (rowCount >= 25) {
result.push({
index: result.length,
name: "25",
value: 25,
selected: false,
disabled: false
});
}
if (rowCount >= 50) {
result.push({
index: result.length,
name: "50",
value: 50,
selected: false,
disabled: false
});
}
if (rowCount >= 100) {
result.push({
index: result.length,
name: "100",
value: 100,
selected: false,
disabled: false
});
}
if (rowCount >= 500) {
result.push({
index: result.length,
name: "500",
value: 500,
selected: false,
disabled: false
});
}
if (rowCount >= 1000) {
result.push({
index: result.length,
name: "1000",
value: 1000,
selected: false,
disabled: false
});
}

result.push({
index: result.length,
name: String(rowCount),
value: rowCount,
selected: false,
disabled: false
});

result.sort((a, b) => a.value - b.value);

return result;
}, []);

return (
<XStack
group={"header" as any}
flexGrow={1}
justifyContent="space-between"
alignItems="center">
<Form name="pageSizing">
<SelectField
name="pageSize"
options={[
{ name: "5", value: 5 },
{ name: "10", value: 10 },
{ name: "25", value: 25 },
{ name: "50", value: 50 },
{ name: "100", value: 100 },
{ name: "500", value: 500 },
{ name: "1000", value: 1000 }
]}
value={pageSize}
defaultValue={10}>
<XStack alignItems="center" gap="$3">
<SelectField.Label>Items per page</SelectField.Label>
<SelectField.Control placeholder="Size" />
</XStack>
</SelectField>
</Form>
alignItems="center"
paddingHorizontal="$1">
<View flex={1}>
<Form
name="pageSizing"
defaultValues={{
pageSize
}}>
<SelectField name="pageSize" items={pageSizes} size="$4">
<XStack alignItems="center" gap="$4">
<SelectField.Label hideOptional={true}>
Per page
</SelectField.Label>
<SelectField.Control placeholder="Size" />
</XStack>
</SelectField>
</Form>
</View>

<Pagination
pageIndex={pageIndex}
Expand Down
12 changes: 10 additions & 2 deletions components/field/src/Field.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import {
useFieldStore,
Validator
} from "@cyclone-ui/form-state";
import { getSized } from "@cyclone-ui/helpers";
import { getFontSizedFromSize, getSized } from "@cyclone-ui/helpers";
import { LabelText } from "@cyclone-ui/label-text";
import { Spinner } from "@cyclone-ui/spinner";
import { getIconByTheme } from "@cyclone-ui/themeable-icon";
Expand Down Expand Up @@ -307,11 +307,16 @@ const FieldLabelText = styled(LabelText, {
color: "$colorDisabled",
cursor: "not-allowed"
}
},

size: {
"...size": getFontSizedFromSize
}
} as const,

defaultVariants: {
disabled: false
disabled: false,
size: "$true"
}
});

Expand All @@ -322,6 +327,7 @@ const LabelXStack = styled(XStack, {
gap: "$1.2",
flex: 1,
alignItems: "center",
paddingBottom: "$0.25",

variants: {
disabled: {
Expand Down Expand Up @@ -357,6 +363,7 @@ const FieldLabelTextImpl = FieldLabelText.styleable<{
const store = useFieldStore();
const fieldDisabled = store.get.disabled();
const name = store.get.name();
const size = store.get.size();

const disabled = useMemo(
() => Boolean(fieldDisabled || props.disabled),
Expand All @@ -368,6 +375,7 @@ const FieldLabelTextImpl = FieldLabelText.styleable<{
<LabelXStack disabled={disabled}>
<FieldLabelText
{...props}
size={size}
disabled={disabled}
theme={ColorThemeName.BASE}>
{children}
Expand Down
8 changes: 6 additions & 2 deletions components/input-field/src/InputField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { Field } from "@cyclone-ui/field";
import { useFieldActions, useFieldStore } from "@cyclone-ui/form-state";
import { Input } from "@cyclone-ui/input";
import { Theme, withStaticProperties } from "@tamagui/core";
import { useCallback } from "react";
import { useCallback, useLayoutEffect } from "react";

const InputFieldGroup = Field.styleable((props, forwardedRef) => {
const { children, ...rest } = props;
Expand Down Expand Up @@ -83,11 +83,15 @@ const InputFieldControlTextBoxValue = Input.TextBox.Value.styleable(
const initialValue = store.get.initialValue();
const options = store.get.options();

const { change } = useFieldActions();
const { change, mount } = useFieldActions();
const handleClear = useCallback(() => {
change(options?.defaultValue);
}, [change, options?.defaultValue]);

useLayoutEffect(() => {
mount(forwardedRef);
}, [mount]);

return (
<Theme name={theme}>
<Input.TextBox.Value
Expand Down
Loading

0 comments on commit 3e873cd

Please sign in to comment.