@lucasbernardosn/react-table 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -13,8 +13,9 @@ export type ColumnMenuPopupProps<TFeatures extends TableFeatures, TData extends
13
13
  }>;
14
14
  /**
15
15
  * A caixa do menu da coluna, já com o `Menu.Portal` e o `Menu.Positioner`. As props passam para o
16
- * `Menu.Popup`. Abre encostada no header, e a largura mínima cabe o item mais longo: sem ela, o
17
- * menu cresceria quando o "Remover ordenação" aparece.
16
+ * `Menu.Popup`, e os itens (os grupos padrão ou os `children`) ficam num `Menu.List` próprio, que
17
+ * rola. Abre encostada no header, e a largura mínima cabe o item mais longo: sem ela, o menu
18
+ * cresceria quando o "Remover ordenação" aparece.
18
19
  *
19
20
  * Sem `children`, mostra os grupos padrão separados por linhas: ordenação
20
21
  * (`ColumnMenu.SortItems`), fixação (`ColumnMenu.PinItems`) e visibilidade
@@ -9,8 +9,9 @@ import { Fragment as Fragment$1 } from "react";
9
9
  //#region src/components/column-menu/column-menu-popup.tsx
10
10
  /**
11
11
  * A caixa do menu da coluna, já com o `Menu.Portal` e o `Menu.Positioner`. As props passam para o
12
- * `Menu.Popup`. Abre encostada no header, e a largura mínima cabe o item mais longo: sem ela, o
13
- * menu cresceria quando o "Remover ordenação" aparece.
12
+ * `Menu.Popup`, e os itens (os grupos padrão ou os `children`) ficam num `Menu.List` próprio, que
13
+ * rola. Abre encostada no header, e a largura mínima cabe o item mais longo: sem ela, o menu
14
+ * cresceria quando o "Remover ordenação" aparece.
14
15
  *
15
16
  * Sem `children`, mostra os grupos padrão separados por linhas: ordenação
16
17
  * (`ColumnMenu.SortItems`), fixação (`ColumnMenu.PinItems`) e visibilidade
@@ -56,7 +57,7 @@ const ColumnMenuPopup = (props) => {
56
57
  "data-component": "ColumnMenu.Popup",
57
58
  className: mergeStateClassNames(["min-w-48"], className),
58
59
  ...rest,
59
- children: children ?? groups.map((group, index) => /* @__PURE__ */ jsxs(Fragment$1, { children: [index > 0 && /* @__PURE__ */ jsx(Menu.Separator, {}), group] }, group.key))
60
+ children: /* @__PURE__ */ jsx(Menu.List, { children: children ?? groups.map((group, index) => /* @__PURE__ */ jsxs(Fragment$1, { children: [index > 0 && /* @__PURE__ */ jsx(Menu.Separator, {}), group] }, group.key)) })
60
61
  })
61
62
  }) });
62
63
  };
@@ -1 +1 @@
1
- {"version":3,"file":"column-menu-popup.js","names":["Fragment"],"sources":["../../../src/components/column-menu/column-menu-popup.tsx"],"sourcesContent":["import { Menu } from '@lucasbernardosn/react-ui/overlays/menu';\nimport { mergeStateClassNames } from '@lucasbernardosn/react-ui/utils';\nimport type { MergeOverride } from '@lucasbernardosn/ts-utils';\nimport type { Header, RowData, TableFeatures } from '@tanstack/react-table';\nimport { Fragment } from 'react';\nimport { hasColumnFeature } from '../../utils';\nimport { ColumnMenuHideItem } from './column-menu-hide-item';\nimport type { ColumnMenuLabels } from './column-menu-labels';\nimport { ColumnMenuPinItems } from './column-menu-pin-items';\nimport { ColumnMenuSortItems } from './column-menu-sort-items';\n\nexport type ColumnMenuPopupProps<\n TFeatures extends TableFeatures,\n TData extends RowData,\n> = MergeOverride<\n Menu.PopupProps,\n {\n /** O header da coluna. */\n header: Header<TFeatures, TData>;\n /** O texto dos itens padrão; os que faltam ficam com o padrão. Sem efeito com `children`. */\n labels?: Partial<ColumnMenuLabels>;\n /** As props do `Menu.Positioner`, como `side` e `align`. */\n positionerProps?: Menu.PositionerProps;\n }\n>;\n\n/**\n * A caixa do menu da coluna, já com o `Menu.Portal` e o `Menu.Positioner`. As props passam para o\n * `Menu.Popup`. Abre encostada no header, e a largura mínima cabe o item mais longo: sem ela, o\n * menu cresceria quando o \"Remover ordenação\" aparece.\n *\n * Sem `children`, mostra os grupos padrão separados por linhas: ordenação\n * (`ColumnMenu.SortItems`), fixação (`ColumnMenu.PinItems`) e visibilidade\n * (`ColumnMenu.HideItem`). Cada grupo só aparece com a feature registrada na tabela e permitida na\n * coluna. Com `children`, eles substituem os grupos, para escolher, reordenar ou somar itens\n * próprios com o `Menu.Item`. Os grupos recebem a coluna, e não o header: servem também fora\n * dele, como no `ColumnsPanel.Item`.\n *\n * @example\n * ```tsx\n * <ColumnMenu.Popup header={header}>\n * <ColumnMenu.SortItems column={header.column} />\n * <Menu.Separator />\n * <Menu.Item onClick={openFilter}>Filtrar</Menu.Item>\n * </ColumnMenu.Popup>\n * ```\n */\nexport const ColumnMenuPopup = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n props: ColumnMenuPopupProps<TFeatures, TData>,\n) => {\n const { header, labels, positionerProps, className, children, ...rest } =\n props;\n\n /**\n * Os grupos padrão que a coluna aceita. A conta é feita aqui, e não pelo `null` de cada grupo,\n * para a linha separar só os grupos que aparecem.\n */\n const groups = [\n hasColumnFeature(header.column, 'rowSortingFeature') &&\n header.column.getCanSort() && (\n <ColumnMenuSortItems\n key=\"sort\"\n column={header.column}\n labels={labels}\n />\n ),\n hasColumnFeature(header.column, 'columnPinningFeature') &&\n header.column.getCanPin() && (\n <ColumnMenuPinItems\n key=\"pin\"\n column={header.column}\n labels={labels}\n />\n ),\n hasColumnFeature(header.column, 'columnVisibilityFeature') &&\n header.column.getCanHide() && (\n <ColumnMenuHideItem\n key=\"hide\"\n column={header.column}\n labels={labels}\n />\n ),\n ].filter((group) => group !== false);\n\n return (\n <Menu.Portal>\n <Menu.Positioner\n sideOffset={0}\n // Fixar ou mover a coluna leva o header para outro lugar enquanto o menu fecha: seguindo o\n // trigger, o menu deslizaria até lá na animação de saída. A rolagem continua acompanhada.\n disableAnchorTracking={true}\n {...positionerProps}\n >\n <Menu.Popup\n data-component=\"ColumnMenu.Popup\"\n className={mergeStateClassNames(['min-w-48'], className)}\n {...rest}\n >\n {children ??\n groups.map((group, index) => (\n <Fragment key={group.key}>\n {index > 0 && <Menu.Separator />}\n {group}\n </Fragment>\n ))}\n </Menu.Popup>\n </Menu.Positioner>\n </Menu.Portal>\n );\n};\n\nColumnMenuPopup.displayName = 'ColumnMenu.Popup';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+CA,MAAa,mBAIX,UACG;CACH,MAAM,EAAE,QAAQ,QAAQ,iBAAiB,WAAW,UAAU,GAAG,SAC/D;;;;;CAMF,MAAM,SAAS;EACb,iBAAiB,OAAO,QAAQ,mBAAmB,KACjD,OAAO,OAAO,WAAW,KACvB,oBAAC,qBAAD;GAEE,QAAQ,OAAO;GACP;EACT,GAHK,MAGL;EAEL,iBAAiB,OAAO,QAAQ,sBAAsB,KACpD,OAAO,OAAO,UAAU,KACtB,oBAAC,oBAAD;GAEE,QAAQ,OAAO;GACP;EACT,GAHK,KAGL;EAEL,iBAAiB,OAAO,QAAQ,yBAAyB,KACvD,OAAO,OAAO,WAAW,KACvB,oBAAC,oBAAD;GAEE,QAAQ,OAAO;GACP;EACT,GAHK,MAGL;CAEP,CAAC,CAAC,QAAQ,UAAU,UAAU,KAAK;CAEnC,OACE,oBAAC,KAAK,QAAN,EAAA,UACE,oBAAC,KAAK,YAAN;EACE,YAAY;EAGZ,uBAAuB;EACvB,GAAI;EAEJ,UAAA,oBAAC,KAAK,OAAN;GACE,kBAAe;GACf,WAAW,qBAAqB,CAAC,UAAU,GAAG,SAAS;GACvD,GAAI;GAEH,UAAA,YACC,OAAO,KAAK,OAAO,UACjB,qBAACA,YAAD,EAAA,UAAA,CACG,QAAQ,KAAK,oBAAC,KAAK,WAAN,CAAiB,CAAA,GAC9B,KACO,EAAA,GAHK,MAAM,GAGX,CACX;EACO,CAAA;CACG,CAAA,EACN,CAAA;AAEjB;AAEA,gBAAgB,cAAc"}
1
+ {"version":3,"file":"column-menu-popup.js","names":["Fragment"],"sources":["../../../src/components/column-menu/column-menu-popup.tsx"],"sourcesContent":["import { Menu } from '@lucasbernardosn/react-ui/overlays/menu';\nimport { mergeStateClassNames } from '@lucasbernardosn/react-ui/utils';\nimport type { MergeOverride } from '@lucasbernardosn/ts-utils';\nimport type { Header, RowData, TableFeatures } from '@tanstack/react-table';\nimport { Fragment } from 'react';\nimport { hasColumnFeature } from '../../utils';\nimport { ColumnMenuHideItem } from './column-menu-hide-item';\nimport type { ColumnMenuLabels } from './column-menu-labels';\nimport { ColumnMenuPinItems } from './column-menu-pin-items';\nimport { ColumnMenuSortItems } from './column-menu-sort-items';\n\nexport type ColumnMenuPopupProps<\n TFeatures extends TableFeatures,\n TData extends RowData,\n> = MergeOverride<\n Menu.PopupProps,\n {\n /** O header da coluna. */\n header: Header<TFeatures, TData>;\n /** O texto dos itens padrão; os que faltam ficam com o padrão. Sem efeito com `children`. */\n labels?: Partial<ColumnMenuLabels>;\n /** As props do `Menu.Positioner`, como `side` e `align`. */\n positionerProps?: Menu.PositionerProps;\n }\n>;\n\n/**\n * A caixa do menu da coluna, já com o `Menu.Portal` e o `Menu.Positioner`. As props passam para o\n * `Menu.Popup`, e os itens (os grupos padrão ou os `children`) ficam num `Menu.List` próprio, que\n * rola. Abre encostada no header, e a largura mínima cabe o item mais longo: sem ela, o menu\n * cresceria quando o \"Remover ordenação\" aparece.\n *\n * Sem `children`, mostra os grupos padrão separados por linhas: ordenação\n * (`ColumnMenu.SortItems`), fixação (`ColumnMenu.PinItems`) e visibilidade\n * (`ColumnMenu.HideItem`). Cada grupo só aparece com a feature registrada na tabela e permitida na\n * coluna. Com `children`, eles substituem os grupos, para escolher, reordenar ou somar itens\n * próprios com o `Menu.Item`. Os grupos recebem a coluna, e não o header: servem também fora\n * dele, como no `ColumnsPanel.Item`.\n *\n * @example\n * ```tsx\n * <ColumnMenu.Popup header={header}>\n * <ColumnMenu.SortItems column={header.column} />\n * <Menu.Separator />\n * <Menu.Item onClick={openFilter}>Filtrar</Menu.Item>\n * </ColumnMenu.Popup>\n * ```\n */\nexport const ColumnMenuPopup = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n props: ColumnMenuPopupProps<TFeatures, TData>,\n) => {\n const { header, labels, positionerProps, className, children, ...rest } =\n props;\n\n /**\n * Os grupos padrão que a coluna aceita. A conta é feita aqui, e não pelo `null` de cada grupo,\n * para a linha separar só os grupos que aparecem.\n */\n const groups = [\n hasColumnFeature(header.column, 'rowSortingFeature') &&\n header.column.getCanSort() && (\n <ColumnMenuSortItems\n key=\"sort\"\n column={header.column}\n labels={labels}\n />\n ),\n hasColumnFeature(header.column, 'columnPinningFeature') &&\n header.column.getCanPin() && (\n <ColumnMenuPinItems\n key=\"pin\"\n column={header.column}\n labels={labels}\n />\n ),\n hasColumnFeature(header.column, 'columnVisibilityFeature') &&\n header.column.getCanHide() && (\n <ColumnMenuHideItem\n key=\"hide\"\n column={header.column}\n labels={labels}\n />\n ),\n ].filter((group) => group !== false);\n\n return (\n <Menu.Portal>\n <Menu.Positioner\n sideOffset={0}\n // Fixar ou mover a coluna leva o header para outro lugar enquanto o menu fecha: seguindo o\n // trigger, o menu deslizaria até lá na animação de saída. A rolagem continua acompanhada.\n disableAnchorTracking={true}\n {...positionerProps}\n >\n <Menu.Popup\n data-component=\"ColumnMenu.Popup\"\n className={mergeStateClassNames(['min-w-48'], className)}\n {...rest}\n >\n <Menu.List>\n {children ??\n groups.map((group, index) => (\n <Fragment key={group.key}>\n {index > 0 && <Menu.Separator />}\n {group}\n </Fragment>\n ))}\n </Menu.List>\n </Menu.Popup>\n </Menu.Positioner>\n </Menu.Portal>\n );\n};\n\nColumnMenuPopup.displayName = 'ColumnMenu.Popup';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgDA,MAAa,mBAIX,UACG;CACH,MAAM,EAAE,QAAQ,QAAQ,iBAAiB,WAAW,UAAU,GAAG,SAC/D;;;;;CAMF,MAAM,SAAS;EACb,iBAAiB,OAAO,QAAQ,mBAAmB,KACjD,OAAO,OAAO,WAAW,KACvB,oBAAC,qBAAD;GAEE,QAAQ,OAAO;GACP;EACT,GAHK,MAGL;EAEL,iBAAiB,OAAO,QAAQ,sBAAsB,KACpD,OAAO,OAAO,UAAU,KACtB,oBAAC,oBAAD;GAEE,QAAQ,OAAO;GACP;EACT,GAHK,KAGL;EAEL,iBAAiB,OAAO,QAAQ,yBAAyB,KACvD,OAAO,OAAO,WAAW,KACvB,oBAAC,oBAAD;GAEE,QAAQ,OAAO;GACP;EACT,GAHK,MAGL;CAEP,CAAC,CAAC,QAAQ,UAAU,UAAU,KAAK;CAEnC,OACE,oBAAC,KAAK,QAAN,EAAA,UACE,oBAAC,KAAK,YAAN;EACE,YAAY;EAGZ,uBAAuB;EACvB,GAAI;EAEJ,UAAA,oBAAC,KAAK,OAAN;GACE,kBAAe;GACf,WAAW,qBAAqB,CAAC,UAAU,GAAG,SAAS;GACvD,GAAI;GAEJ,UAAA,oBAAC,KAAK,MAAN,EAAA,UACG,YACC,OAAO,KAAK,OAAO,UACjB,qBAACA,YAAD,EAAA,UAAA,CACG,QAAQ,KAAK,oBAAC,KAAK,WAAN,CAAiB,CAAA,GAC9B,KACO,EAAA,GAHK,MAAM,GAGX,CACX,EACM,CAAA;EACD,CAAA;CACG,CAAA,EACN,CAAA;AAEjB;AAEA,gBAAgB,cAAc"}
@@ -79,7 +79,7 @@ const ColumnsPanelItem = (props) => {
79
79
  align: "end",
80
80
  children: /* @__PURE__ */ jsx(Menu.Popup, {
81
81
  className: "min-w-48",
82
- children: /* @__PURE__ */ jsx(ColumnMenuPinItems, { column })
82
+ children: /* @__PURE__ */ jsx(Menu.List, { children: /* @__PURE__ */ jsx(ColumnMenuPinItems, { column }) })
83
83
  })
84
84
  }) })] }),
85
85
  pinned === false ? /* @__PURE__ */ jsx(IconButton, {
@@ -1 +1 @@
1
- {"version":3,"file":"columns-panel-item.js","names":[],"sources":["../../../src/components/columns-panel/columns-panel-item.tsx"],"sourcesContent":["import { mergeProps, useRender } from '@base-ui/react';\nimport { useSortable } from '@dnd-kit/react/sortable';\nimport { IconButton } from '@lucasbernardosn/react-ui/buttons/icon-button';\nimport { Checkbox } from '@lucasbernardosn/react-ui/fields/checkbox';\nimport { Menu } from '@lucasbernardosn/react-ui/overlays/menu';\nimport { mergeTwClassNames } from '@lucasbernardosn/react-ui/utils';\nimport type { MergeOverride } from '@lucasbernardosn/ts-utils';\nimport { ListIcon, PushPinIcon } from '@phosphor-icons/react';\nimport { useSelector } from '@tanstack/react-store';\nimport type { RowData, TableFeatures } from '@tanstack/react-table';\nimport type { ColumnWith } from '../../types';\nimport { getDefaultColumnLabel, hasColumnFeature } from '../../utils';\nimport { ColumnMenuPinItems } from '../column-menu/column-menu-pin-items';\n\nexport type ColumnsPanelItemProps<\n TFeatures extends TableFeatures,\n TData extends RowData,\n> = MergeOverride<\n useRender.ComponentProps<'li'>,\n {\n /** A coluna. Exige `columnVisibilityFeature`. */\n column: ColumnWith<TFeatures, TData, 'columnVisibilityFeature'>;\n /** A posição da coluna no grupo dela (fixadas no início, centro ou fixadas no fim). */\n index: number;\n /**\n * O nome da coluna.\n * @default getDefaultColumnLabel(column): o `header` quando é texto, e o id quando não é\n */\n label?: string;\n }\n>;\n\n/**\n * Uma coluna no `ColumnsPanel.Root`: o checkbox de visibilidade, o nome e, à direita, a alça de\n * arrastar. Só a alça pega o arrasto; o resto fica livre para o clique no checkbox. Uma coluna com\n * `enableHiding: false` fica com o checkbox desabilitado.\n *\n * Com `columnPinningFeature`, um alfinete antes da alça abre o menu da fixação, com os itens do\n * `ColumnMenu.PinItems`: fixa e solta a coluna sem o header, como nos cards ou numa coluna sem o\n * menu da coluna. Preenchido, a coluna está fixada. A fixada não tem alça e não se arrasta: o\n * `columnOrder` só ordena as colunas do centro, e as fixadas ficam nas pontas. Numa coluna com\n * `enablePinning: false`, o alfinete não aparece.\n */\nexport const ColumnsPanelItem = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n props: ColumnsPanelItemProps<TFeatures, TData>,\n) => {\n const { column, index, label, render, className, ref, ...rest } = props;\n\n /** Re-renderiza quando esta coluna aparece ou some. */\n const isVisible = useSelector(column.table.atoms.columnVisibility, () =>\n column.getIsVisible(),\n );\n\n /**\n * Re-renderiza quando esta coluna é fixada ou solta. O pinning é opcional, então assina o\n * store.\n */\n const pinned = useSelector(column.table.store, () =>\n hasColumnFeature(column, 'columnPinningFeature')\n ? column.getIsPinned()\n : false,\n );\n\n const columnLabel = label ?? getDefaultColumnLabel(column);\n\n /** O grupo separa as regiões: o arrasto não leva uma coluna do centro para as fixadas. */\n const sortable = useSortable({\n id: column.id,\n index,\n group: pinned || 'center',\n disabled: pinned !== false,\n });\n\n const baseProps = {\n 'data-component': 'ColumnsPanel.Item',\n 'data-dragging': sortable.isDragging ? '' : undefined,\n 'data-pinned': pinned || undefined,\n className: mergeTwClassNames(\n [\n 'flex',\n 'h-8',\n 'items-center',\n 'gap-2',\n\n 'rounded-md',\n 'corner-squircle',\n 'ps-2',\n 'pe-1',\n\n 'text-sm',\n\n // Em arrasto, destacada sobre as outras.\n 'data-dragging:bg-gray-3',\n 'data-dragging:shadow-md',\n ],\n className,\n ),\n children: (\n <>\n <label className=\"flex min-w-0 flex-1 items-center gap-2 select-none\">\n <Checkbox.Root\n checked={isVisible}\n disabled={!column.getCanHide()}\n onCheckedChange={(checked) => column.toggleVisibility(checked)}\n >\n <Checkbox.Indicator />\n </Checkbox.Root>\n\n <span className={isVisible ? 'truncate' : 'truncate text-gray-11'}>\n {columnLabel}\n </span>\n </label>\n\n {hasColumnFeature(column, 'columnPinningFeature') &&\n column.getCanPin() && (\n <Menu.Root>\n <Menu.Trigger\n render={\n <IconButton\n variant=\"ghost\"\n size=\"2xs\"\n icon={<PushPinIcon weight={pinned ? 'fill' : 'regular'} />}\n aria-label={`Fixação da coluna ${columnLabel}`}\n className={pinned ? 'text-gray-12' : 'text-gray-11'}\n />\n }\n />\n\n <Menu.Portal>\n <Menu.Positioner align=\"end\">\n <Menu.Popup className=\"min-w-48\">\n <ColumnMenuPinItems column={column} />\n </Menu.Popup>\n </Menu.Positioner>\n </Menu.Portal>\n </Menu.Root>\n )}\n\n {pinned === false ? (\n <IconButton\n ref={sortable.handleRef}\n variant=\"ghost\"\n size=\"2xs\"\n icon={<ListIcon />}\n aria-label={`Mover a coluna ${columnLabel}`}\n // `touch-none`: no toque, o gesto arrasta em vez de rolar.\n className=\"cursor-grab touch-none text-gray-11 active:cursor-grabbing\"\n />\n ) : (\n // A fixada não se arrasta: o espaço da alça fica vazio, para o alfinete ficar alinhado\n // com o das outras.\n <span\n aria-hidden=\"true\"\n className=\"inline-flex size-6 shrink-0\"\n />\n )}\n </>\n ),\n };\n\n return useRender({\n render,\n ref: [sortable.ref, ref ?? null],\n defaultTagName: 'li',\n props: mergeProps(baseProps, rest),\n });\n};\n\nColumnsPanelItem.displayName = 'ColumnsPanel.Item';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA2CA,MAAa,oBAIX,UACG;CACH,MAAM,EAAE,QAAQ,OAAO,OAAO,QAAQ,WAAW,KAAK,GAAG,SAAS;;CAGlE,MAAM,YAAY,YAAY,OAAO,MAAM,MAAM,wBAC/C,OAAO,aAAa,CACtB;;;;;CAMA,MAAM,SAAS,YAAY,OAAO,MAAM,aACtC,iBAAiB,QAAQ,sBAAsB,IAC3C,OAAO,YAAY,IACnB,KACN;CAEA,MAAM,cAAc,SAAS,sBAAsB,MAAM;;CAGzD,MAAM,WAAW,YAAY;EAC3B,IAAI,OAAO;EACX;EACA,OAAO,UAAU;EACjB,UAAU,WAAW;CACvB,CAAC;CAED,MAAM,YAAY;EAChB,kBAAkB;EAClB,iBAAiB,SAAS,aAAa,KAAK,KAAA;EAC5C,eAAe,UAAU,KAAA;EACzB,WAAW,kBACT;GACE;GACA;GACA;GACA;GAEA;GACA;GACA;GACA;GAEA;GAGA;GACA;EACF,GACA,SACF;EACA,UACE,qBAAA,UAAA,EAAA,UAAA;GACE,qBAAC,SAAD;IAAO,WAAU;IAAjB,UAAA,CACE,oBAAC,SAAS,MAAV;KACE,SAAS;KACT,UAAU,CAAC,OAAO,WAAW;KAC7B,kBAAkB,YAAY,OAAO,iBAAiB,OAAO;KAE7D,UAAA,oBAAC,SAAS,WAAV,CAAqB,CAAA;IACR,CAAA,GAEf,oBAAC,QAAD;KAAM,WAAW,YAAY,aAAa;KACvC,UAAA;IACG,CAAA,CACD;;GAEN,iBAAiB,QAAQ,sBAAsB,KAC9C,OAAO,UAAU,KACf,qBAAC,KAAK,MAAN,EAAA,UAAA,CACE,oBAAC,KAAK,SAAN,EACE,QACE,oBAAC,YAAD;IACE,SAAQ;IACR,MAAK;IACL,MAAM,oBAAC,aAAD,EAAa,QAAQ,SAAS,SAAS,UAAY,CAAA;IACzD,cAAY,qBAAqB;IACjC,WAAW,SAAS,iBAAiB;GACtC,CAAA,EAEJ,CAAA,GAED,oBAAC,KAAK,QAAN,EAAA,UACE,oBAAC,KAAK,YAAN;IAAiB,OAAM;IACrB,UAAA,oBAAC,KAAK,OAAN;KAAY,WAAU;KACpB,UAAA,oBAAC,oBAAD,EAA4B,OAAS,CAAA;IAC3B,CAAA;GACG,CAAA,EACN,CAAA,CACJ,EAAA,CAAA;GAGd,WAAW,QACV,oBAAC,YAAD;IACE,KAAK,SAAS;IACd,SAAQ;IACR,MAAK;IACL,MAAM,oBAAC,UAAD,CAAW,CAAA;IACjB,cAAY,kBAAkB;IAE9B,WAAU;GACX,CAAA,IAID,oBAAC,QAAD;IACE,eAAY;IACZ,WAAU;GACX,CAAA;EAEH,EAAA,CAAA;CAEN;CAEA,OAAO,UAAU;EACf;EACA,KAAK,CAAC,SAAS,KAAK,OAAO,IAAI;EAC/B,gBAAgB;EAChB,OAAO,WAAW,WAAW,IAAI;CACnC,CAAC;AACH;AAEA,iBAAiB,cAAc"}
1
+ {"version":3,"file":"columns-panel-item.js","names":[],"sources":["../../../src/components/columns-panel/columns-panel-item.tsx"],"sourcesContent":["import { mergeProps, useRender } from '@base-ui/react';\nimport { useSortable } from '@dnd-kit/react/sortable';\nimport { IconButton } from '@lucasbernardosn/react-ui/buttons/icon-button';\nimport { Checkbox } from '@lucasbernardosn/react-ui/fields/checkbox';\nimport { Menu } from '@lucasbernardosn/react-ui/overlays/menu';\nimport { mergeTwClassNames } from '@lucasbernardosn/react-ui/utils';\nimport type { MergeOverride } from '@lucasbernardosn/ts-utils';\nimport { ListIcon, PushPinIcon } from '@phosphor-icons/react';\nimport { useSelector } from '@tanstack/react-store';\nimport type { RowData, TableFeatures } from '@tanstack/react-table';\nimport type { ColumnWith } from '../../types';\nimport { getDefaultColumnLabel, hasColumnFeature } from '../../utils';\nimport { ColumnMenuPinItems } from '../column-menu/column-menu-pin-items';\n\nexport type ColumnsPanelItemProps<\n TFeatures extends TableFeatures,\n TData extends RowData,\n> = MergeOverride<\n useRender.ComponentProps<'li'>,\n {\n /** A coluna. Exige `columnVisibilityFeature`. */\n column: ColumnWith<TFeatures, TData, 'columnVisibilityFeature'>;\n /** A posição da coluna no grupo dela (fixadas no início, centro ou fixadas no fim). */\n index: number;\n /**\n * O nome da coluna.\n * @default getDefaultColumnLabel(column): o `header` quando é texto, e o id quando não é\n */\n label?: string;\n }\n>;\n\n/**\n * Uma coluna no `ColumnsPanel.Root`: o checkbox de visibilidade, o nome e, à direita, a alça de\n * arrastar. Só a alça pega o arrasto; o resto fica livre para o clique no checkbox. Uma coluna com\n * `enableHiding: false` fica com o checkbox desabilitado.\n *\n * Com `columnPinningFeature`, um alfinete antes da alça abre o menu da fixação, com os itens do\n * `ColumnMenu.PinItems`: fixa e solta a coluna sem o header, como nos cards ou numa coluna sem o\n * menu da coluna. Preenchido, a coluna está fixada. A fixada não tem alça e não se arrasta: o\n * `columnOrder` só ordena as colunas do centro, e as fixadas ficam nas pontas. Numa coluna com\n * `enablePinning: false`, o alfinete não aparece.\n */\nexport const ColumnsPanelItem = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n props: ColumnsPanelItemProps<TFeatures, TData>,\n) => {\n const { column, index, label, render, className, ref, ...rest } = props;\n\n /** Re-renderiza quando esta coluna aparece ou some. */\n const isVisible = useSelector(column.table.atoms.columnVisibility, () =>\n column.getIsVisible(),\n );\n\n /**\n * Re-renderiza quando esta coluna é fixada ou solta. O pinning é opcional, então assina o\n * store.\n */\n const pinned = useSelector(column.table.store, () =>\n hasColumnFeature(column, 'columnPinningFeature')\n ? column.getIsPinned()\n : false,\n );\n\n const columnLabel = label ?? getDefaultColumnLabel(column);\n\n /** O grupo separa as regiões: o arrasto não leva uma coluna do centro para as fixadas. */\n const sortable = useSortable({\n id: column.id,\n index,\n group: pinned || 'center',\n disabled: pinned !== false,\n });\n\n const baseProps = {\n 'data-component': 'ColumnsPanel.Item',\n 'data-dragging': sortable.isDragging ? '' : undefined,\n 'data-pinned': pinned || undefined,\n className: mergeTwClassNames(\n [\n 'flex',\n 'h-8',\n 'items-center',\n 'gap-2',\n\n 'rounded-md',\n 'corner-squircle',\n 'ps-2',\n 'pe-1',\n\n 'text-sm',\n\n // Em arrasto, destacada sobre as outras.\n 'data-dragging:bg-gray-3',\n 'data-dragging:shadow-md',\n ],\n className,\n ),\n children: (\n <>\n <label className=\"flex min-w-0 flex-1 items-center gap-2 select-none\">\n <Checkbox.Root\n checked={isVisible}\n disabled={!column.getCanHide()}\n onCheckedChange={(checked) => column.toggleVisibility(checked)}\n >\n <Checkbox.Indicator />\n </Checkbox.Root>\n\n <span className={isVisible ? 'truncate' : 'truncate text-gray-11'}>\n {columnLabel}\n </span>\n </label>\n\n {hasColumnFeature(column, 'columnPinningFeature') &&\n column.getCanPin() && (\n <Menu.Root>\n <Menu.Trigger\n render={\n <IconButton\n variant=\"ghost\"\n size=\"2xs\"\n icon={<PushPinIcon weight={pinned ? 'fill' : 'regular'} />}\n aria-label={`Fixação da coluna ${columnLabel}`}\n className={pinned ? 'text-gray-12' : 'text-gray-11'}\n />\n }\n />\n\n <Menu.Portal>\n <Menu.Positioner align=\"end\">\n <Menu.Popup className=\"min-w-48\">\n <Menu.List>\n <ColumnMenuPinItems column={column} />\n </Menu.List>\n </Menu.Popup>\n </Menu.Positioner>\n </Menu.Portal>\n </Menu.Root>\n )}\n\n {pinned === false ? (\n <IconButton\n ref={sortable.handleRef}\n variant=\"ghost\"\n size=\"2xs\"\n icon={<ListIcon />}\n aria-label={`Mover a coluna ${columnLabel}`}\n // `touch-none`: no toque, o gesto arrasta em vez de rolar.\n className=\"cursor-grab touch-none text-gray-11 active:cursor-grabbing\"\n />\n ) : (\n // A fixada não se arrasta: o espaço da alça fica vazio, para o alfinete ficar alinhado\n // com o das outras.\n <span\n aria-hidden=\"true\"\n className=\"inline-flex size-6 shrink-0\"\n />\n )}\n </>\n ),\n };\n\n return useRender({\n render,\n ref: [sortable.ref, ref ?? null],\n defaultTagName: 'li',\n props: mergeProps(baseProps, rest),\n });\n};\n\nColumnsPanelItem.displayName = 'ColumnsPanel.Item';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA2CA,MAAa,oBAIX,UACG;CACH,MAAM,EAAE,QAAQ,OAAO,OAAO,QAAQ,WAAW,KAAK,GAAG,SAAS;;CAGlE,MAAM,YAAY,YAAY,OAAO,MAAM,MAAM,wBAC/C,OAAO,aAAa,CACtB;;;;;CAMA,MAAM,SAAS,YAAY,OAAO,MAAM,aACtC,iBAAiB,QAAQ,sBAAsB,IAC3C,OAAO,YAAY,IACnB,KACN;CAEA,MAAM,cAAc,SAAS,sBAAsB,MAAM;;CAGzD,MAAM,WAAW,YAAY;EAC3B,IAAI,OAAO;EACX;EACA,OAAO,UAAU;EACjB,UAAU,WAAW;CACvB,CAAC;CAED,MAAM,YAAY;EAChB,kBAAkB;EAClB,iBAAiB,SAAS,aAAa,KAAK,KAAA;EAC5C,eAAe,UAAU,KAAA;EACzB,WAAW,kBACT;GACE;GACA;GACA;GACA;GAEA;GACA;GACA;GACA;GAEA;GAGA;GACA;EACF,GACA,SACF;EACA,UACE,qBAAA,UAAA,EAAA,UAAA;GACE,qBAAC,SAAD;IAAO,WAAU;IAAjB,UAAA,CACE,oBAAC,SAAS,MAAV;KACE,SAAS;KACT,UAAU,CAAC,OAAO,WAAW;KAC7B,kBAAkB,YAAY,OAAO,iBAAiB,OAAO;KAE7D,UAAA,oBAAC,SAAS,WAAV,CAAqB,CAAA;IACR,CAAA,GAEf,oBAAC,QAAD;KAAM,WAAW,YAAY,aAAa;KACvC,UAAA;IACG,CAAA,CACD;;GAEN,iBAAiB,QAAQ,sBAAsB,KAC9C,OAAO,UAAU,KACf,qBAAC,KAAK,MAAN,EAAA,UAAA,CACE,oBAAC,KAAK,SAAN,EACE,QACE,oBAAC,YAAD;IACE,SAAQ;IACR,MAAK;IACL,MAAM,oBAAC,aAAD,EAAa,QAAQ,SAAS,SAAS,UAAY,CAAA;IACzD,cAAY,qBAAqB;IACjC,WAAW,SAAS,iBAAiB;GACtC,CAAA,EAEJ,CAAA,GAED,oBAAC,KAAK,QAAN,EAAA,UACE,oBAAC,KAAK,YAAN;IAAiB,OAAM;IACrB,UAAA,oBAAC,KAAK,OAAN;KAAY,WAAU;KACpB,UAAA,oBAAC,KAAK,MAAN,EAAA,UACE,oBAAC,oBAAD,EAA4B,OAAS,CAAA,EAC5B,CAAA;IACD,CAAA;GACG,CAAA,EACN,CAAA,CACJ,EAAA,CAAA;GAGd,WAAW,QACV,oBAAC,YAAD;IACE,KAAK,SAAS;IACd,SAAQ;IACR,MAAK;IACL,MAAM,oBAAC,UAAD,CAAW,CAAA;IACjB,cAAY,kBAAkB;IAE9B,WAAU;GACX,CAAA,IAID,oBAAC,QAAD;IACE,eAAY;IACZ,WAAU;GACX,CAAA;EAEH,EAAA,CAAA;CAEN;CAEA,OAAO,UAAU;EACf;EACA,KAAK,CAAC,SAAS,KAAK,OAAO,IAAI;EAC/B,gBAAgB;EAChB,OAAO,WAAW,WAAW,IAAI;CACnC,CAAC;AACH;AAEA,iBAAiB,cAAc"}
@@ -51,7 +51,7 @@ export type DataTableRowProps<TFeatures extends TableFeatures, TData extends Row
51
51
  * }}
52
52
  * className={
53
53
  * row.original.overdue
54
- * ? '[--data-table-row-background:var(--color-gray-2)] text-gray-11'
54
+ * ? '[--data-table-row-background:var(--gray-2)] text-gray-11'
55
55
  * : undefined
56
56
  * }
57
57
  * >
@@ -46,7 +46,7 @@ import { Fragment as Fragment$1 } from "react";
46
46
  * }}
47
47
  * className={
48
48
  * row.original.overdue
49
- * ? '[--data-table-row-background:var(--color-gray-2)] text-gray-11'
49
+ * ? '[--data-table-row-background:var(--gray-2)] text-gray-11'
50
50
  * : undefined
51
51
  * }
52
52
  * >
@@ -122,11 +122,11 @@ const DataTableRow = (props) => {
122
122
  "[--data-table-row-base:var(--color-white)]",
123
123
  "dark:[--data-table-row-base:#0b0b0b]",
124
124
  "[--data-table-row-background:var(--data-table-row-base)]",
125
- "hover:[--data-table-row-background:var(--color-gray-2)]",
126
- "data-selected:[--data-table-row-background:var(--color-gray-3)]",
127
- "data-selected:hover:[--data-table-row-background:var(--color-gray-4)]",
128
- "has-[[data-popup-open]]:[--data-table-row-background:var(--color-gray-2)]",
129
- "data-selected:has-[[data-popup-open]]:[--data-table-row-background:var(--color-gray-4)]",
125
+ "hover:[--data-table-row-background:var(--gray-2)]",
126
+ "data-selected:[--data-table-row-background:var(--gray-3)]",
127
+ "data-selected:hover:[--data-table-row-background:var(--gray-4)]",
128
+ "has-[[data-popup-open]]:[--data-table-row-background:var(--gray-2)]",
129
+ "data-selected:has-[[data-popup-open]]:[--data-table-row-background:var(--gray-4)]",
130
130
  "bg-(--data-table-row-background)",
131
131
  "text-gray-12",
132
132
  "outline-none",
@@ -1 +1 @@
1
- {"version":3,"file":"data-table-row.js","names":["Fragment"],"sources":["../../../../src/components/data-table/body/data-table-row.tsx"],"sourcesContent":["import { mergeProps, useRender } from '@base-ui/react';\nimport { mergeTwClassNames } from '@lucasbernardosn/react-ui/utils';\nimport type { MergeOverride } from '@lucasbernardosn/ts-utils';\nimport { shallow, useSelector } from '@tanstack/react-store';\nimport type { Cell, Row, RowData, TableFeatures } from '@tanstack/react-table';\nimport type React from 'react';\nimport { Fragment } from 'react';\nimport { hasRowFeature } from '../../../utils';\nimport { dataTableGridClassNames } from '../root/data-table-grid-class-names';\nimport { DataTableCell } from './data-table-cell';\nimport {\n focusDataTableRow,\n getDataTableRowKeyTarget,\n} from './data-table-row-focus';\n\nexport type DataTableRowProps<\n TFeatures extends TableFeatures,\n TData extends RowData,\n> = MergeOverride<\n useRender.ComponentProps<'div'>,\n {\n /** A linha do row model. */\n row: Row<TFeatures, TData>;\n /**\n * Uma função que recebe cada célula visível e devolve o elemento dela. Com nós comuns, quem\n * usa faz o laço.\n * @default (cell) => <DataTable.Cell cell={cell} />\n */\n children?:\n | React.ReactNode\n | ((cell: Cell<TFeatures, TData>) => React.ReactNode);\n }\n>;\n\n/**\n * Uma linha do corpo (`role=\"row\"`). É um grid com as colunas do `--data-table-template`, que o\n * `DataTable.Root` escreve.\n *\n * Com render-prop ou sem `children`, faz o laço das células sozinha: assina as próprias células e\n * re-renderiza quando a ordem, a visibilidade ou o pinning das colunas mudam, que não mudam o row\n * model e não passam pelo `DataTable.Body`. Com `columnVisibilityFeature`, são as células\n * visíveis; sem ela, todas. Com `columnPinningFeature`, vêm na ordem das regiões: as fixadas no\n * início, as do centro e as fixadas no fim.\n *\n * Com `rowSelectionFeature`, a linha selecionada ganha `data-selected` e o fundo destacado, e com\n * `activeRowFeature`, também o `aria-selected`. O clique na linha não seleciona: o `onClick` fica\n * livre, e a seleção é do `DataTable.RowCheckbox` e do Espaço.\n *\n * Com `activeRowFeature`, entra na navegação por teclado. A linha ativa tem o ponto de Tab (sem\n * ela no row model, a primeira), e receber o foco, pelo teclado ou pelo clique, torna esta a\n * ativa, marcada com `data-active`. ↑↓, Home, End, PageUp e PageDown movem o foco entre as\n * linhas, e o Espaço alterna a seleção, com Shift para o intervalo. Os atalhos são do app, no\n * `onKeyDown`, que roda antes: um `preventDefault()` cancela o da linha. Num campo de texto de\n * dentro, as setas ficam com o campo.\n *\n * O fundo fica na variável `--data-table-row-background`, que as células fixadas repetem: o\n * hover a troca para `gray-2`, a selecionada para `gray-3`, e as duas juntas, para `gray-4`. Para\n * colorir uma linha, troque a variável, e não use `bg-*`, que deixaria as fixadas com a cor\n * antiga. A cor do texto fica na linha, e as células herdam.\n *\n * @example\n * ```tsx\n * <DataTable.Row\n * row={row}\n * onClick={() => openCustomer(row.original)}\n * onKeyDown={(event) => {\n * if (event.key === 'Enter') {\n * openCustomer(row.original);\n * }\n * }}\n * className={\n * row.original.overdue\n * ? '[--data-table-row-background:var(--color-gray-2)] text-gray-11'\n * : undefined\n * }\n * >\n * {(cell) => <DataTable.Cell cell={cell} />}\n * </DataTable.Row>\n * ```\n */\nexport const DataTableRow = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n props: DataTableRowProps<TFeatures, TData>,\n) => {\n const { row, render, className, children, ...rest } = props;\n\n /**\n * As listas que o TanStack memoiza, numa tupla: o `shallow` compara item a item, e só\n * re-renderiza quando uma delas muda com as colunas. Todas seguem a ordem dos headers folha, que\n * é a do template, e as células caem nos tracks certos. Com pinning, as três regiões, que\n * ordenam as fixadas mesmo sem `columnVisibilityFeature`.\n */\n const cellGroups = useSelector(\n row.table.store,\n () =>\n hasRowFeature(row, 'columnPinningFeature')\n ? [\n row.getStartVisibleCells(),\n row.getCenterVisibleCells(),\n row.getEndVisibleCells(),\n ]\n : hasRowFeature(row, 'columnVisibilityFeature')\n ? [row.getVisibleCells()]\n : [row.getAllCells()],\n { compare: shallow },\n );\n\n const cells = cellGroups.flat();\n\n /**\n * Só re-renderiza quando esta linha é marcada ou desmarcada. A seleção é opcional, então assina\n * o store; sem `rowSelectionFeature`, nenhuma linha fica selecionada.\n */\n const isSelected = useSelector(\n row.table.store,\n () => hasRowFeature(row, 'rowSelectionFeature') && row.getIsSelected(),\n );\n\n /**\n * O ponto de Tab da tabela: a linha ativa ou, sem ela no row model, a primeira. Re-renderiza\n * quando o ponto de Tab entra ou sai daqui. A navegação é opcional, então assina o store; sem\n * `activeRowFeature`, nenhuma linha entra no Tab.\n */\n const isTabStop = useSelector(row.table.store, () => {\n if (!hasRowFeature(row, 'activeRowFeature')) {\n return false;\n }\n\n const activeRow = row.table.getActiveRow();\n\n return activeRow\n ? activeRow.id === row.id\n : row.table.getRowModel().rows[0]?.id === row.id;\n });\n\n /** Só re-renderiza quando esta linha vira ou deixa de ser a ativa. */\n const isActive = useSelector(\n row.table.store,\n () => hasRowFeature(row, 'activeRowFeature') && row.getIsActive(),\n );\n\n /** Receber o foco, nela ou num controle de dentro, torna esta a linha ativa. */\n const handleFocus = () => {\n if (hasRowFeature(row, 'activeRowFeature') && !row.getIsActive()) {\n row.table.setActiveRowId(row.id);\n }\n };\n\n /** As teclas da navegação. O `onKeyDown` do app roda antes e cancela com `preventDefault()`. */\n const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (!hasRowFeature(row, 'activeRowFeature') || event.defaultPrevented) {\n return;\n }\n\n /** Na própria linha: num controle de dentro, como o checkbox, o Espaço é dele. */\n if (event.key === ' ' && event.target === event.currentTarget) {\n if (hasRowFeature(row, 'rowSelectionFeature') && row.getCanSelect()) {\n event.preventDefault();\n\n /** O handler do checkbox: lê o Shift do evento, para o intervalo, e move a âncora. */\n row.getToggleSelectedHandler()({\n target: { checked: !row.getIsSelected() },\n nativeEvent: event.nativeEvent,\n });\n }\n\n return;\n }\n\n const targetRow = getDataTableRowKeyTarget(event.currentTarget, event);\n\n if (targetRow) {\n event.preventDefault();\n focusDataTableRow(targetRow);\n }\n };\n\n const isNavigable = hasRowFeature(row, 'activeRowFeature');\n\n /** Com render-prop ou sem `children`, o laço é daqui; com nós comuns, de quem usa. */\n const content =\n typeof children === 'function' || children === undefined\n ? cells.map((cell) => (\n <Fragment key={cell.id}>\n {children === undefined ? (\n <DataTableCell cell={cell} />\n ) : (\n children(cell)\n )}\n </Fragment>\n ))\n : children;\n\n const baseProps = {\n 'data-component': 'DataTable.Row',\n 'data-selected': isSelected ? '' : undefined,\n 'data-active': isActive ? '' : undefined,\n role: 'row',\n // Só no `grid`: o ARIA não define o atributo na linha de uma `table`, e o leitor o ignora.\n 'aria-selected':\n isNavigable && hasRowFeature(row, 'rowSelectionFeature')\n ? isSelected\n : undefined,\n tabIndex: isNavigable ? (isTabStop ? 0 : -1) : undefined,\n onFocus: handleFocus,\n onKeyDown: handleKeyDown,\n className: mergeTwClassNames(\n [\n // O anel de foco se posiciona por aqui.\n 'relative',\n\n dataTableGridClassNames,\n // Sem a linha horizontal na última: embaixo dela já vem a borda da área de rolagem, e as\n // duas somariam 2px.\n 'last:border-b-0',\n\n // O fundo numa variável, que as células fixadas repetem para ficarem opacas. A base é\n // branca no claro e quase preta no escuro, numa variável à parte: a variante `dark` e o\n // `hover` disputariam a mesma propriedade, e a ordem delas no CSS decidiria. O hover sobe\n // um passo, a selecionada outro, e a selecionada com hover mais um: sem isso, passar o\n // mouse por ela não mudaria nada. Escala curta, para o fundo dos botões `ghost` das\n // células (`gray-3`) aparecer sobre a linha em hover.\n '[--data-table-row-base:var(--color-white)]',\n 'dark:[--data-table-row-base:#0b0b0b]',\n '[--data-table-row-background:var(--data-table-row-base)]',\n 'hover:[--data-table-row-background:var(--color-gray-2)]',\n 'data-selected:[--data-table-row-background:var(--color-gray-3)]',\n 'data-selected:hover:[--data-table-row-background:var(--color-gray-4)]',\n // Com um menu aberto num controle da linha, ela fica como em hover, com o ponteiro onde\n // estiver: o backdrop do menu cobre o resto da linha e deixa um recorte só sobre o\n // gatilho, e o `:hover` acenderia e apagaria a linha conforme o ponteiro passa por ele.\n 'has-[[data-popup-open]]:[--data-table-row-background:var(--color-gray-2)]',\n 'data-selected:has-[[data-popup-open]]:[--data-table-row-background:var(--color-gray-4)]',\n 'bg-(--data-table-row-background)',\n\n 'text-gray-12',\n\n // O anel de foco, com o foco na linha ou num controle de dentro, pelo teclado ou pelo\n // clique: com `focus-visible`, o clique tornaria a linha ativa sem mostrar qual é. Num\n // `::after` por cima das células fixadas (`z-1`), que cobririam o `outline` e o\n // `box-shadow` da própria linha. Por dentro: a linha seguinte cobriria o que sai por baixo.\n 'outline-none',\n 'after:pointer-events-none',\n 'after:absolute',\n 'after:inset-0',\n 'after:z-2',\n 'after:content-[\"\"]',\n 'focus-within:after:outline-2',\n 'focus-within:after:-outline-offset-2',\n 'focus-within:after:outline-gray-12',\n ],\n className,\n ),\n children: content,\n };\n\n return useRender({\n render,\n defaultTagName: 'div',\n props: mergeProps(baseProps, rest),\n });\n};\n\nDataTableRow.displayName = 'DataTable.Row';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgFA,MAAa,gBAIX,UACG;CACH,MAAM,EAAE,KAAK,QAAQ,WAAW,UAAU,GAAG,SAAS;CAuBtD,MAAM,QAfa,YACjB,IAAI,MAAM,aAER,cAAc,KAAK,sBAAsB,IACrC;EACE,IAAI,qBAAqB;EACzB,IAAI,sBAAsB;EAC1B,IAAI,mBAAmB;CACzB,IACA,cAAc,KAAK,yBAAyB,IAC1C,CAAC,IAAI,gBAAgB,CAAC,IACtB,CAAC,IAAI,YAAY,CAAC,GAC1B,EAAE,SAAS,QAAQ,CAGE,CAAC,CAAC,KAAK;;;;;CAM9B,MAAM,aAAa,YACjB,IAAI,MAAM,aACJ,cAAc,KAAK,qBAAqB,KAAK,IAAI,cAAc,CACvE;;;;;;CAOA,MAAM,YAAY,YAAY,IAAI,MAAM,aAAa;EACnD,IAAI,CAAC,cAAc,KAAK,kBAAkB,GACxC,OAAO;EAGT,MAAM,YAAY,IAAI,MAAM,aAAa;EAEzC,OAAO,YACH,UAAU,OAAO,IAAI,KACrB,IAAI,MAAM,YAAY,CAAC,CAAC,KAAK,EAAE,EAAE,OAAO,IAAI;CAClD,CAAC;;CAGD,MAAM,WAAW,YACf,IAAI,MAAM,aACJ,cAAc,KAAK,kBAAkB,KAAK,IAAI,YAAY,CAClE;;CAGA,MAAM,oBAAoB;EACxB,IAAI,cAAc,KAAK,kBAAkB,KAAK,CAAC,IAAI,YAAY,GAC7D,IAAI,MAAM,eAAe,IAAI,EAAE;CAEnC;;CAGA,MAAM,iBAAiB,UAA+C;EACpE,IAAI,CAAC,cAAc,KAAK,kBAAkB,KAAK,MAAM,kBACnD;;EAIF,IAAI,MAAM,QAAQ,OAAO,MAAM,WAAW,MAAM,eAAe;GAC7D,IAAI,cAAc,KAAK,qBAAqB,KAAK,IAAI,aAAa,GAAG;IACnE,MAAM,eAAe;;IAGrB,IAAI,yBAAyB,CAAC,CAAC;KAC7B,QAAQ,EAAE,SAAS,CAAC,IAAI,cAAc,EAAE;KACxC,aAAa,MAAM;IACrB,CAAC;GACH;GAEA;EACF;EAEA,MAAM,YAAY,yBAAyB,MAAM,eAAe,KAAK;EAErE,IAAI,WAAW;GACb,MAAM,eAAe;GACrB,kBAAkB,SAAS;EAC7B;CACF;CAEA,MAAM,cAAc,cAAc,KAAK,kBAAkB;;CAGzD,MAAM,UACJ,OAAO,aAAa,cAAc,aAAa,KAAA,IAC3C,MAAM,KAAK,SACT,oBAACA,YAAD,EAAA,UACG,aAAa,KAAA,IACZ,oBAAC,eAAD,EAAqB,KAAO,CAAA,IAE5B,SAAS,IAAI,EAEP,GANK,KAAK,EAMV,CACX,IACD;CAEN,MAAM,YAAY;EAChB,kBAAkB;EAClB,iBAAiB,aAAa,KAAK,KAAA;EACnC,eAAe,WAAW,KAAK,KAAA;EAC/B,MAAM;EAEN,iBACE,eAAe,cAAc,KAAK,qBAAqB,IACnD,aACA,KAAA;EACN,UAAU,cAAe,YAAY,IAAI,KAAM,KAAA;EAC/C,SAAS;EACT,WAAW;EACX,WAAW,kBACT;GAEE;GAEA;GAGA;GAQA;GACA;GACA;GACA;GACA;GACA;GAIA;GACA;GACA;GAEA;GAMA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EACF,GACA,SACF;EACA,UAAU;CACZ;CAEA,OAAO,UAAU;EACf;EACA,gBAAgB;EAChB,OAAO,WAAW,WAAW,IAAI;CACnC,CAAC;AACH;AAEA,aAAa,cAAc"}
1
+ {"version":3,"file":"data-table-row.js","names":["Fragment"],"sources":["../../../../src/components/data-table/body/data-table-row.tsx"],"sourcesContent":["import { mergeProps, useRender } from '@base-ui/react';\nimport { mergeTwClassNames } from '@lucasbernardosn/react-ui/utils';\nimport type { MergeOverride } from '@lucasbernardosn/ts-utils';\nimport { shallow, useSelector } from '@tanstack/react-store';\nimport type { Cell, Row, RowData, TableFeatures } from '@tanstack/react-table';\nimport type React from 'react';\nimport { Fragment } from 'react';\nimport { hasRowFeature } from '../../../utils';\nimport { dataTableGridClassNames } from '../root/data-table-grid-class-names';\nimport { DataTableCell } from './data-table-cell';\nimport {\n focusDataTableRow,\n getDataTableRowKeyTarget,\n} from './data-table-row-focus';\n\nexport type DataTableRowProps<\n TFeatures extends TableFeatures,\n TData extends RowData,\n> = MergeOverride<\n useRender.ComponentProps<'div'>,\n {\n /** A linha do row model. */\n row: Row<TFeatures, TData>;\n /**\n * Uma função que recebe cada célula visível e devolve o elemento dela. Com nós comuns, quem\n * usa faz o laço.\n * @default (cell) => <DataTable.Cell cell={cell} />\n */\n children?:\n | React.ReactNode\n | ((cell: Cell<TFeatures, TData>) => React.ReactNode);\n }\n>;\n\n/**\n * Uma linha do corpo (`role=\"row\"`). É um grid com as colunas do `--data-table-template`, que o\n * `DataTable.Root` escreve.\n *\n * Com render-prop ou sem `children`, faz o laço das células sozinha: assina as próprias células e\n * re-renderiza quando a ordem, a visibilidade ou o pinning das colunas mudam, que não mudam o row\n * model e não passam pelo `DataTable.Body`. Com `columnVisibilityFeature`, são as células\n * visíveis; sem ela, todas. Com `columnPinningFeature`, vêm na ordem das regiões: as fixadas no\n * início, as do centro e as fixadas no fim.\n *\n * Com `rowSelectionFeature`, a linha selecionada ganha `data-selected` e o fundo destacado, e com\n * `activeRowFeature`, também o `aria-selected`. O clique na linha não seleciona: o `onClick` fica\n * livre, e a seleção é do `DataTable.RowCheckbox` e do Espaço.\n *\n * Com `activeRowFeature`, entra na navegação por teclado. A linha ativa tem o ponto de Tab (sem\n * ela no row model, a primeira), e receber o foco, pelo teclado ou pelo clique, torna esta a\n * ativa, marcada com `data-active`. ↑↓, Home, End, PageUp e PageDown movem o foco entre as\n * linhas, e o Espaço alterna a seleção, com Shift para o intervalo. Os atalhos são do app, no\n * `onKeyDown`, que roda antes: um `preventDefault()` cancela o da linha. Num campo de texto de\n * dentro, as setas ficam com o campo.\n *\n * O fundo fica na variável `--data-table-row-background`, que as células fixadas repetem: o\n * hover a troca para `gray-2`, a selecionada para `gray-3`, e as duas juntas, para `gray-4`. Para\n * colorir uma linha, troque a variável, e não use `bg-*`, que deixaria as fixadas com a cor\n * antiga. A cor do texto fica na linha, e as células herdam.\n *\n * @example\n * ```tsx\n * <DataTable.Row\n * row={row}\n * onClick={() => openCustomer(row.original)}\n * onKeyDown={(event) => {\n * if (event.key === 'Enter') {\n * openCustomer(row.original);\n * }\n * }}\n * className={\n * row.original.overdue\n * ? '[--data-table-row-background:var(--gray-2)] text-gray-11'\n * : undefined\n * }\n * >\n * {(cell) => <DataTable.Cell cell={cell} />}\n * </DataTable.Row>\n * ```\n */\nexport const DataTableRow = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n props: DataTableRowProps<TFeatures, TData>,\n) => {\n const { row, render, className, children, ...rest } = props;\n\n /**\n * As listas que o TanStack memoiza, numa tupla: o `shallow` compara item a item, e só\n * re-renderiza quando uma delas muda com as colunas. Todas seguem a ordem dos headers folha, que\n * é a do template, e as células caem nos tracks certos. Com pinning, as três regiões, que\n * ordenam as fixadas mesmo sem `columnVisibilityFeature`.\n */\n const cellGroups = useSelector(\n row.table.store,\n () =>\n hasRowFeature(row, 'columnPinningFeature')\n ? [\n row.getStartVisibleCells(),\n row.getCenterVisibleCells(),\n row.getEndVisibleCells(),\n ]\n : hasRowFeature(row, 'columnVisibilityFeature')\n ? [row.getVisibleCells()]\n : [row.getAllCells()],\n { compare: shallow },\n );\n\n const cells = cellGroups.flat();\n\n /**\n * Só re-renderiza quando esta linha é marcada ou desmarcada. A seleção é opcional, então assina\n * o store; sem `rowSelectionFeature`, nenhuma linha fica selecionada.\n */\n const isSelected = useSelector(\n row.table.store,\n () => hasRowFeature(row, 'rowSelectionFeature') && row.getIsSelected(),\n );\n\n /**\n * O ponto de Tab da tabela: a linha ativa ou, sem ela no row model, a primeira. Re-renderiza\n * quando o ponto de Tab entra ou sai daqui. A navegação é opcional, então assina o store; sem\n * `activeRowFeature`, nenhuma linha entra no Tab.\n */\n const isTabStop = useSelector(row.table.store, () => {\n if (!hasRowFeature(row, 'activeRowFeature')) {\n return false;\n }\n\n const activeRow = row.table.getActiveRow();\n\n return activeRow\n ? activeRow.id === row.id\n : row.table.getRowModel().rows[0]?.id === row.id;\n });\n\n /** Só re-renderiza quando esta linha vira ou deixa de ser a ativa. */\n const isActive = useSelector(\n row.table.store,\n () => hasRowFeature(row, 'activeRowFeature') && row.getIsActive(),\n );\n\n /** Receber o foco, nela ou num controle de dentro, torna esta a linha ativa. */\n const handleFocus = () => {\n if (hasRowFeature(row, 'activeRowFeature') && !row.getIsActive()) {\n row.table.setActiveRowId(row.id);\n }\n };\n\n /** As teclas da navegação. O `onKeyDown` do app roda antes e cancela com `preventDefault()`. */\n const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (!hasRowFeature(row, 'activeRowFeature') || event.defaultPrevented) {\n return;\n }\n\n /** Na própria linha: num controle de dentro, como o checkbox, o Espaço é dele. */\n if (event.key === ' ' && event.target === event.currentTarget) {\n if (hasRowFeature(row, 'rowSelectionFeature') && row.getCanSelect()) {\n event.preventDefault();\n\n /** O handler do checkbox: lê o Shift do evento, para o intervalo, e move a âncora. */\n row.getToggleSelectedHandler()({\n target: { checked: !row.getIsSelected() },\n nativeEvent: event.nativeEvent,\n });\n }\n\n return;\n }\n\n const targetRow = getDataTableRowKeyTarget(event.currentTarget, event);\n\n if (targetRow) {\n event.preventDefault();\n focusDataTableRow(targetRow);\n }\n };\n\n const isNavigable = hasRowFeature(row, 'activeRowFeature');\n\n /** Com render-prop ou sem `children`, o laço é daqui; com nós comuns, de quem usa. */\n const content =\n typeof children === 'function' || children === undefined\n ? cells.map((cell) => (\n <Fragment key={cell.id}>\n {children === undefined ? (\n <DataTableCell cell={cell} />\n ) : (\n children(cell)\n )}\n </Fragment>\n ))\n : children;\n\n const baseProps = {\n 'data-component': 'DataTable.Row',\n 'data-selected': isSelected ? '' : undefined,\n 'data-active': isActive ? '' : undefined,\n role: 'row',\n // Só no `grid`: o ARIA não define o atributo na linha de uma `table`, e o leitor o ignora.\n 'aria-selected':\n isNavigable && hasRowFeature(row, 'rowSelectionFeature')\n ? isSelected\n : undefined,\n tabIndex: isNavigable ? (isTabStop ? 0 : -1) : undefined,\n onFocus: handleFocus,\n onKeyDown: handleKeyDown,\n className: mergeTwClassNames(\n [\n // O anel de foco se posiciona por aqui.\n 'relative',\n\n dataTableGridClassNames,\n // Sem a linha horizontal na última: embaixo dela já vem a borda da área de rolagem, e as\n // duas somariam 2px.\n 'last:border-b-0',\n\n // O fundo numa variável, que as células fixadas repetem para ficarem opacas. A base é\n // branca no claro e quase preta no escuro, numa variável à parte: a variante `dark` e o\n // `hover` disputariam a mesma propriedade, e a ordem delas no CSS decidiria. O hover sobe\n // um passo, a selecionada outro, e a selecionada com hover mais um: sem isso, passar o\n // mouse por ela não mudaria nada. Escala curta, para o fundo dos botões `ghost` das\n // células (`gray-3`) aparecer sobre a linha em hover.\n '[--data-table-row-base:var(--color-white)]',\n 'dark:[--data-table-row-base:#0b0b0b]',\n '[--data-table-row-background:var(--data-table-row-base)]',\n 'hover:[--data-table-row-background:var(--gray-2)]',\n 'data-selected:[--data-table-row-background:var(--gray-3)]',\n 'data-selected:hover:[--data-table-row-background:var(--gray-4)]',\n // Com um menu aberto num controle da linha, ela fica como em hover, com o ponteiro onde\n // estiver: o backdrop do menu cobre o resto da linha e deixa um recorte só sobre o\n // gatilho, e o `:hover` acenderia e apagaria a linha conforme o ponteiro passa por ele.\n 'has-[[data-popup-open]]:[--data-table-row-background:var(--gray-2)]',\n 'data-selected:has-[[data-popup-open]]:[--data-table-row-background:var(--gray-4)]',\n 'bg-(--data-table-row-background)',\n\n 'text-gray-12',\n\n // O anel de foco, com o foco na linha ou num controle de dentro, pelo teclado ou pelo\n // clique: com `focus-visible`, o clique tornaria a linha ativa sem mostrar qual é. Num\n // `::after` por cima das células fixadas (`z-1`), que cobririam o `outline` e o\n // `box-shadow` da própria linha. Por dentro: a linha seguinte cobriria o que sai por baixo.\n 'outline-none',\n 'after:pointer-events-none',\n 'after:absolute',\n 'after:inset-0',\n 'after:z-2',\n 'after:content-[\"\"]',\n 'focus-within:after:outline-2',\n 'focus-within:after:-outline-offset-2',\n 'focus-within:after:outline-gray-12',\n ],\n className,\n ),\n children: content,\n };\n\n return useRender({\n render,\n defaultTagName: 'div',\n props: mergeProps(baseProps, rest),\n });\n};\n\nDataTableRow.displayName = 'DataTable.Row';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgFA,MAAa,gBAIX,UACG;CACH,MAAM,EAAE,KAAK,QAAQ,WAAW,UAAU,GAAG,SAAS;CAuBtD,MAAM,QAfa,YACjB,IAAI,MAAM,aAER,cAAc,KAAK,sBAAsB,IACrC;EACE,IAAI,qBAAqB;EACzB,IAAI,sBAAsB;EAC1B,IAAI,mBAAmB;CACzB,IACA,cAAc,KAAK,yBAAyB,IAC1C,CAAC,IAAI,gBAAgB,CAAC,IACtB,CAAC,IAAI,YAAY,CAAC,GAC1B,EAAE,SAAS,QAAQ,CAGE,CAAC,CAAC,KAAK;;;;;CAM9B,MAAM,aAAa,YACjB,IAAI,MAAM,aACJ,cAAc,KAAK,qBAAqB,KAAK,IAAI,cAAc,CACvE;;;;;;CAOA,MAAM,YAAY,YAAY,IAAI,MAAM,aAAa;EACnD,IAAI,CAAC,cAAc,KAAK,kBAAkB,GACxC,OAAO;EAGT,MAAM,YAAY,IAAI,MAAM,aAAa;EAEzC,OAAO,YACH,UAAU,OAAO,IAAI,KACrB,IAAI,MAAM,YAAY,CAAC,CAAC,KAAK,EAAE,EAAE,OAAO,IAAI;CAClD,CAAC;;CAGD,MAAM,WAAW,YACf,IAAI,MAAM,aACJ,cAAc,KAAK,kBAAkB,KAAK,IAAI,YAAY,CAClE;;CAGA,MAAM,oBAAoB;EACxB,IAAI,cAAc,KAAK,kBAAkB,KAAK,CAAC,IAAI,YAAY,GAC7D,IAAI,MAAM,eAAe,IAAI,EAAE;CAEnC;;CAGA,MAAM,iBAAiB,UAA+C;EACpE,IAAI,CAAC,cAAc,KAAK,kBAAkB,KAAK,MAAM,kBACnD;;EAIF,IAAI,MAAM,QAAQ,OAAO,MAAM,WAAW,MAAM,eAAe;GAC7D,IAAI,cAAc,KAAK,qBAAqB,KAAK,IAAI,aAAa,GAAG;IACnE,MAAM,eAAe;;IAGrB,IAAI,yBAAyB,CAAC,CAAC;KAC7B,QAAQ,EAAE,SAAS,CAAC,IAAI,cAAc,EAAE;KACxC,aAAa,MAAM;IACrB,CAAC;GACH;GAEA;EACF;EAEA,MAAM,YAAY,yBAAyB,MAAM,eAAe,KAAK;EAErE,IAAI,WAAW;GACb,MAAM,eAAe;GACrB,kBAAkB,SAAS;EAC7B;CACF;CAEA,MAAM,cAAc,cAAc,KAAK,kBAAkB;;CAGzD,MAAM,UACJ,OAAO,aAAa,cAAc,aAAa,KAAA,IAC3C,MAAM,KAAK,SACT,oBAACA,YAAD,EAAA,UACG,aAAa,KAAA,IACZ,oBAAC,eAAD,EAAqB,KAAO,CAAA,IAE5B,SAAS,IAAI,EAEP,GANK,KAAK,EAMV,CACX,IACD;CAEN,MAAM,YAAY;EAChB,kBAAkB;EAClB,iBAAiB,aAAa,KAAK,KAAA;EACnC,eAAe,WAAW,KAAK,KAAA;EAC/B,MAAM;EAEN,iBACE,eAAe,cAAc,KAAK,qBAAqB,IACnD,aACA,KAAA;EACN,UAAU,cAAe,YAAY,IAAI,KAAM,KAAA;EAC/C,SAAS;EACT,WAAW;EACX,WAAW,kBACT;GAEE;GAEA;GAGA;GAQA;GACA;GACA;GACA;GACA;GACA;GAIA;GACA;GACA;GAEA;GAMA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EACF,GACA,SACF;EACA,UAAU;CACZ;CAEA,OAAO,UAAU;EACf;EACA,gBAAgB;EAChB,OAAO,WAAW,WAAW,IAAI;CACnC,CAAC;AACH;AAEA,aAAa,cAAc"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lucasbernardosn/react-table",
3
- "version": "0.4.0",
4
- "description": "Composable data table parts on TanStack Table v9, styled with @lucasbernardosn/react-ui.",
3
+ "version": "0.5.0",
4
+ "description": "Tabela de dados para React, em partes pequenas, sobre o TanStack Table v9 e com o visual do @lucasbernardosn/react-ui.",
5
5
  "type": "module",
6
6
  "exports": {
7
7
  "./types": {
@@ -27,14 +27,14 @@
27
27
  "@dnd-kit/dom": "0.5.0",
28
28
  "@dnd-kit/helpers": "0.5.0",
29
29
  "@dnd-kit/react": "0.5.0",
30
- "@lucasbernardosn/ts-utils": "^0.4.0",
30
+ "@lucasbernardosn/ts-utils": "^0.5.0",
31
31
  "@phosphor-icons/react": "2.1.10",
32
32
  "@tanstack/react-store": "0.11.2"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@biomejs/biome": "2.6.3",
36
- "@lucasbernardosn/react-ui": "0.4.0",
37
- "@lucasbernardosn/react-utils": "0.4.0",
36
+ "@lucasbernardosn/react-ui": "0.5.0",
37
+ "@lucasbernardosn/react-utils": "0.5.0",
38
38
  "@lucasbernardosn/ts-config": "0.2.0",
39
39
  "@tanstack/react-table": "9.2.4",
40
40
  "@testing-library/jest-dom": "7.0.1",
@@ -53,8 +53,8 @@
53
53
  "vitest": "5.0.3"
54
54
  },
55
55
  "peerDependencies": {
56
- "@lucasbernardosn/react-ui": "^0.4.0",
57
- "@lucasbernardosn/react-utils": "^0.4.0",
56
+ "@lucasbernardosn/react-ui": "^0.5.0",
57
+ "@lucasbernardosn/react-utils": "^0.5.0",
58
58
  "@tanstack/react-table": "^9.2.4",
59
59
  "react": "^19.0.0",
60
60
  "react-dom": "^19.0.0"
@@ -63,6 +63,15 @@
63
63
  "dist"
64
64
  ],
65
65
  "sideEffects": false,
66
+ "keywords": [
67
+ "react",
68
+ "table",
69
+ "data-table",
70
+ "tanstack-table",
71
+ "tailwindcss",
72
+ "typescript",
73
+ "pt-br"
74
+ ],
66
75
  "license": "MIT",
67
76
  "publishConfig": {
68
77
  "access": "public"