@alfakit/react 0.1.2 → 0.1.7

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.
Files changed (171) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/components/actions/action-modals.js +4 -0
  3. package/dist/components/actions/action-modals.js.map +1 -1
  4. package/dist/components/ai/copilot.d.ts +3 -1
  5. package/dist/components/ai/copilot.d.ts.map +1 -1
  6. package/dist/components/ai/copilot.js +4 -1
  7. package/dist/components/ai/copilot.js.map +1 -1
  8. package/dist/components/cms/live-preview.js +3 -2
  9. package/dist/components/cms/live-preview.js.map +1 -1
  10. package/dist/components/cms/page.js +1 -1
  11. package/dist/components/fields/builder.js +15 -6
  12. package/dist/components/fields/builder.js.map +1 -1
  13. package/dist/components/fields/image-editor-dialog.js +4 -2
  14. package/dist/components/fields/image-editor-dialog.js.map +1 -1
  15. package/dist/components/fields/item-actions.js +10 -10
  16. package/dist/components/fields/item-actions.js.map +1 -1
  17. package/dist/components/fields/key-value.d.ts.map +1 -1
  18. package/dist/components/fields/key-value.js +3 -3
  19. package/dist/components/fields/key-value.js.map +1 -1
  20. package/dist/components/fields/modal-table-select.js +6 -5
  21. package/dist/components/fields/modal-table-select.js.map +1 -1
  22. package/dist/components/fields/repeater.js +2 -2
  23. package/dist/components/fields/repeater.js.map +1 -1
  24. package/dist/components/fields/rich-editor.js +2 -1
  25. package/dist/components/fields/rich-editor.js.map +1 -1
  26. package/dist/components/form/form-block.js +1 -1
  27. package/dist/components/form/form-block.js.map +1 -1
  28. package/dist/components/form/form-context.js +2 -2
  29. package/dist/components/form/form-context.js.map +1 -1
  30. package/dist/components/kanban/kanban.js +4 -3
  31. package/dist/components/kanban/kanban.js.map +1 -1
  32. package/dist/components/layout/section.js +2 -2
  33. package/dist/components/layout/section.js.map +1 -1
  34. package/dist/components/panel/app-sidebar.d.ts +2 -3
  35. package/dist/components/panel/app-sidebar.d.ts.map +1 -1
  36. package/dist/components/panel/app-sidebar.js +1 -24
  37. package/dist/components/panel/app-sidebar.js.map +1 -1
  38. package/dist/components/panel/brand.d.ts +10 -0
  39. package/dist/components/panel/brand.d.ts.map +1 -0
  40. package/dist/components/panel/brand.js +37 -0
  41. package/dist/components/panel/brand.js.map +1 -0
  42. package/dist/components/panel/index.d.ts +2 -1
  43. package/dist/components/panel/topbar.js +1 -1
  44. package/dist/components/realtime/live-records-pill.d.ts.map +1 -1
  45. package/dist/components/realtime/live-records-pill.js +6 -3
  46. package/dist/components/realtime/live-records-pill.js.map +1 -1
  47. package/dist/components/table/cells.d.ts +6 -0
  48. package/dist/components/table/cells.d.ts.map +1 -1
  49. package/dist/components/table/cells.js +6 -2
  50. package/dist/components/table/cells.js.map +1 -1
  51. package/dist/components/table/column-manager.js +8 -7
  52. package/dist/components/table/column-manager.js.map +1 -1
  53. package/dist/components/table/content-layout.js +2 -1
  54. package/dist/components/table/content-layout.js.map +1 -1
  55. package/dist/components/table/pagination.js +16 -13
  56. package/dist/components/table/pagination.js.map +1 -1
  57. package/dist/components/table/table-block.js +14 -4
  58. package/dist/components/table/table-block.js.map +1 -1
  59. package/dist/components/ui/dialog.d.ts.map +1 -1
  60. package/dist/components/ui/dialog.js +3 -1
  61. package/dist/components/ui/dialog.js.map +1 -1
  62. package/dist/components/ui/popover.d.ts.map +1 -1
  63. package/dist/components/ui/popover.js +3 -1
  64. package/dist/components/ui/popover.js.map +1 -1
  65. package/dist/components/ui/sheet.d.ts.map +1 -1
  66. package/dist/components/ui/sheet.js +3 -1
  67. package/dist/components/ui/sheet.js.map +1 -1
  68. package/dist/components/ui/tooltip.js +3 -1
  69. package/dist/components/ui/tooltip.js.map +1 -1
  70. package/dist/context.d.ts +5 -0
  71. package/dist/context.d.ts.map +1 -1
  72. package/dist/context.js +5 -1
  73. package/dist/context.js.map +1 -1
  74. package/dist/create-alfakit.d.ts.map +1 -1
  75. package/dist/create-alfakit.js +8 -5
  76. package/dist/create-alfakit.js.map +1 -1
  77. package/dist/eject-manifest.json +16 -3
  78. package/dist/index.d.ts +6 -3
  79. package/dist/index.js +24 -21
  80. package/dist/layouts/app-layout.d.ts.map +1 -1
  81. package/dist/layouts/app-layout.js +2 -29
  82. package/dist/layouts/app-layout.js.map +1 -1
  83. package/dist/layouts/auth-layout.js +2 -2
  84. package/dist/layouts/auth-layout.js.map +1 -1
  85. package/dist/layouts/fullscreen-layout.js +1 -1
  86. package/dist/layouts/fullscreen-layout.js.map +1 -1
  87. package/dist/layouts/lazy-layouts.js +15 -0
  88. package/dist/layouts/lazy-layouts.js.map +1 -0
  89. package/dist/layouts/max-widths.js +34 -0
  90. package/dist/layouts/max-widths.js.map +1 -0
  91. package/dist/layouts/panel-layouts.d.ts +10 -0
  92. package/dist/layouts/panel-layouts.d.ts.map +1 -0
  93. package/dist/layouts/panel-layouts.js +20 -0
  94. package/dist/layouts/panel-layouts.js.map +1 -0
  95. package/dist/layouts/top-nav-layout.js +2 -2
  96. package/dist/layouts/top-nav-layout.js.map +1 -1
  97. package/dist/pages/page.d.ts.map +1 -1
  98. package/dist/pages/page.js +12 -7
  99. package/dist/pages/page.js.map +1 -1
  100. package/dist/standalone/alfakit-component.js +11 -6
  101. package/dist/standalone/alfakit-component.js.map +1 -1
  102. package/dist/standalone.css +7 -0
  103. package/dist/starter-kit/dashboard-widgets.d.ts +33 -0
  104. package/dist/starter-kit/dashboard-widgets.d.ts.map +1 -0
  105. package/dist/starter-kit/dashboard-widgets.js +53 -0
  106. package/dist/starter-kit/dashboard-widgets.js.map +1 -0
  107. package/dist/starter-kit/impersonation-banner.js +34 -0
  108. package/dist/starter-kit/impersonation-banner.js.map +1 -0
  109. package/dist/starter-kit/index.d.ts +3 -2
  110. package/dist/starter-kit/index.js +3 -2
  111. package/dist/starter-kit/starter-kit.d.ts +6 -0
  112. package/dist/starter-kit/starter-kit.d.ts.map +1 -1
  113. package/dist/starter-kit/starter-kit.js +18 -7
  114. package/dist/starter-kit/starter-kit.js.map +1 -1
  115. package/dist/starter-kit/widgets-loaded.js +20 -4
  116. package/dist/starter-kit/widgets-loaded.js.map +1 -1
  117. package/dist/starter-kit/widgets-triggers.js +34 -3
  118. package/dist/starter-kit/widgets-triggers.js.map +1 -1
  119. package/dist/starter-kit/widgets.d.ts +13 -5
  120. package/dist/starter-kit/widgets.d.ts.map +1 -1
  121. package/dist/starter-kit/widgets.js +56 -18
  122. package/dist/starter-kit/widgets.js.map +1 -1
  123. package/dist/styles.css +15 -2
  124. package/dist/themes.css +6 -1
  125. package/package.json +2 -2
  126. package/src/components/actions/action-modals.tsx +10 -0
  127. package/src/components/ai/copilot.tsx +14 -1
  128. package/src/components/cms/live-preview.tsx +5 -2
  129. package/src/components/fields/builder.tsx +14 -5
  130. package/src/components/fields/image-editor-dialog.tsx +7 -2
  131. package/src/components/fields/item-actions.tsx +32 -9
  132. package/src/components/fields/key-value.tsx +3 -2
  133. package/src/components/fields/modal-table-select.tsx +8 -3
  134. package/src/components/fields/repeater.tsx +2 -3
  135. package/src/components/fields/rich-editor.tsx +3 -0
  136. package/src/components/form/form-block.tsx +2 -1
  137. package/src/components/form/form-context.tsx +2 -2
  138. package/src/components/kanban/kanban.tsx +16 -3
  139. package/src/components/layout/section.tsx +2 -2
  140. package/src/components/panel/app-sidebar.tsx +2 -38
  141. package/src/components/panel/brand.tsx +46 -0
  142. package/src/components/realtime/live-records-pill.tsx +4 -3
  143. package/src/components/table/cells.tsx +9 -2
  144. package/src/components/table/column-manager.tsx +12 -10
  145. package/src/components/table/content-layout.tsx +5 -1
  146. package/src/components/table/pagination.tsx +16 -9
  147. package/src/components/table/table-block.tsx +25 -12
  148. package/src/components/ui/dialog.tsx +5 -1
  149. package/src/components/ui/popover.tsx +5 -1
  150. package/src/components/ui/sheet.tsx +5 -1
  151. package/src/components/ui/tooltip.tsx +5 -1
  152. package/src/context.tsx +10 -0
  153. package/src/create-alfakit.tsx +11 -2
  154. package/src/index.ts +2 -0
  155. package/src/layouts/app-layout.tsx +4 -28
  156. package/src/layouts/auth-layout.tsx +2 -2
  157. package/src/layouts/fullscreen-layout.tsx +1 -1
  158. package/src/layouts/lazy-layouts.ts +14 -0
  159. package/src/layouts/max-widths.ts +29 -0
  160. package/src/layouts/panel-layouts.ts +17 -0
  161. package/src/layouts/top-nav-layout.tsx +2 -2
  162. package/src/pages/page.tsx +21 -12
  163. package/src/standalone/alfakit-component.tsx +18 -7
  164. package/src/starter-kit/dashboard-widgets.tsx +78 -0
  165. package/src/starter-kit/impersonation-banner.tsx +48 -0
  166. package/src/starter-kit/index.ts +2 -0
  167. package/src/starter-kit/starter-kit.tsx +31 -4
  168. package/src/starter-kit/widgets-loaded.tsx +22 -0
  169. package/src/starter-kit/widgets-triggers.tsx +36 -1
  170. package/src/starter-kit/widgets.tsx +95 -20
  171. package/src/styles.css +15 -2
@@ -19,8 +19,12 @@ import { CheckIcon, ChevronsUpDownIcon } from "lucide-react";
19
19
  //#region src/components/table/cells.tsx
20
20
  function TableCellContent(props) {
21
21
  const { column } = props;
22
- const Custom = useRegistry().resolve(columnRegistryKey(column));
23
- if (Custom) return createElement(Custom, props);
22
+ const registry = useRegistry();
23
+ const Custom = props.fromRegistry ? void 0 : registry.resolve(columnRegistryKey(column));
24
+ if (Custom) return createElement(Custom, {
25
+ ...props,
26
+ fromRegistry: true
27
+ });
24
28
  switch (column.type) {
25
29
  case "IconColumn": return /* @__PURE__ */ jsx(IconCell, { ...props });
26
30
  case "ImageColumn": return /* @__PURE__ */ jsx(ImageCell, { ...props });
@@ -1 +1 @@
1
- {"version":3,"file":"cells.js","names":[],"sources":["../../../src/components/table/cells.tsx"],"sourcesContent":["import type {\n CellSchema,\n ColorColumnSchema,\n ColumnSchema,\n IconColumnSchema,\n Option,\n OptionOrGroup,\n RecordKey,\n SelectColumnSchema,\n TextInputColumnSchema,\n ToggleColumnSchema,\n ViewColumnSchema,\n} from '@alfakit/core'\nimport {\n columnRegistryKey,\n filterSelectColumnOptions,\n isOptionGroup,\n optionText,\n remainingTextSizeClass,\n resolvePartialProps,\n searchTableColumnOptions,\n selectColumnEmptyMessage,\n stackedImageStyle,\n updateTableCell,\n usesDefaultImageStack,\n} from '@alfakit/core'\nimport { router } from '@inertiajs/react'\nimport { CheckIcon, ChevronsUpDownIcon } from 'lucide-react'\nimport { createElement, useEffect, useId, useRef, useState } from 'react'\nimport { usePanel, useRegistry, useT } from '../../context'\nimport { extraProps } from '../../lib/attributes'\nimport {\n colorClass,\n iconSizeClasses,\n switchOffColorClasses,\n switchOnColorClasses,\n textColorClasses,\n} from '../../lib/colors'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport { FormattedText } from '../entries/text-entry'\nimport { Button } from '../ui/button'\nimport { Checkbox } from '../ui/checkbox'\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n} from '../ui/command'\nimport { Input } from '../ui/input'\nimport { Popover, PopoverContent, PopoverTrigger } from '../ui/popover'\nimport { Spinner } from '../ui/spinner'\nimport { Switch } from '../ui/switch'\n\nexport interface CellProps {\n column: ColumnSchema\n cell: CellSchema\n recordKey: RecordKey\n token: string\n component: string\n}\n\nexport function TableCellContent(props: CellProps) {\n const { column } = props\n // A component registered as `column:<type>` replaces the built-in cell renderer.\n const Custom = useRegistry().resolve(columnRegistryKey(column))\n\n if (Custom) {\n return createElement(Custom, props)\n }\n\n switch (column.type) {\n case 'IconColumn':\n return <IconCell {...props} />\n case 'ImageColumn':\n return <ImageCell {...props} />\n case 'ColorColumn':\n return <ColorCell {...props} />\n case 'ToggleColumn':\n case 'CheckboxColumn':\n return <BooleanCell {...props} />\n case 'SelectColumn':\n return <SelectCell {...props} />\n case 'TextInputColumn':\n return <TextInputCell {...props} />\n case 'ViewColumn':\n return <ViewCell {...props} />\n default:\n return <TextCell {...props} />\n }\n}\n\n/** `IconColumn`: one icon, or one per item of a list state (`wrap()` lets them wrap). */\nfunction IconCell({ column, cell }: CellProps) {\n const icons = cell.icons ?? (cell.icon ? [{ icon: cell.icon, color: cell.color }] : [])\n const sizeClass = colorClass(iconSizeClasses, cell.size, 'md')\n\n if (icons.length === 0) {\n return <span className=\"text-muted-foreground\">—</span>\n }\n\n if (!cell.icons) {\n return (\n <Icon\n name={icons[0]!.icon}\n className={cn(sizeClass, icons[0]!.color && textColorClasses[icons[0]!.color])}\n />\n )\n }\n\n return (\n <div\n data-slot=\"icon-column-icons\"\n className={cn(\n 'flex items-center gap-1.5',\n (column as IconColumnSchema).wrap ? 'flex-wrap' : 'flex-nowrap',\n )}\n >\n {icons.map((item, index) => (\n <Icon\n key={index}\n name={item.icon}\n className={cn(sizeClass, item.color && textColorClasses[item.color])}\n />\n ))}\n </div>\n )\n}\n\n/** `ViewColumn`: the application component registered under the column's `view()` name. */\nfunction ViewCell(props: CellProps) {\n const t = useT()\n const name = (props.column as ViewColumnSchema).component ?? ''\n const Custom = useRegistry().resolve(name)\n\n if (!name || !Custom) {\n return (\n <span className=\"text-destructive text-xs\">\n {t('component_not_registered', { component: name }, `Component ${name} is not registered.`)}\n </span>\n )\n }\n\n return createElement(Custom, { ...(props.cell.props ?? {}), state: props.cell.state, ...props })\n}\n\nfunction TextCell({ column, cell }: CellProps) {\n const text = (\n <FormattedText\n value={cell.state}\n schema={{\n ...(column as object),\n color: cell.color,\n icon: cell.icon,\n iconPosition: cell.iconPosition,\n iconColor: cell.iconColor,\n itemColors: cell.itemColors,\n itemIcons: cell.itemIcons,\n itemUrls: cell.itemUrls,\n }}\n />\n )\n const description = cell.description ? (\n <span className=\"text-muted-foreground block text-xs\">{cell.description}</span>\n ) : null\n const position =\n (column as { descriptionPosition?: 'above' | 'below' }).descriptionPosition ?? 'below'\n\n return (\n <div className=\"flex flex-col gap-0.5\">\n {position === 'above' && description}\n {text}\n {position === 'below' && description}\n </div>\n )\n}\n\nfunction ImageCell({ column, cell }: CellProps) {\n const urls = Array.isArray(cell.state) ? (cell.state as string[]) : []\n const schema = column as {\n circular?: boolean\n square?: boolean\n size?: number | string\n height?: number | string\n width?: string\n stacked?: boolean\n limit?: number\n limitedRemainingText?: boolean\n limitedRemainingTextSize?: string\n wrap?: boolean\n ring?: number\n overlap?: number\n }\n const limit = schema.limit ?? urls.length\n const size = schema.size ?? 40\n\n if (urls.length === 0) {\n return <span className=\"text-muted-foreground\">—</span>\n }\n\n return (\n <div\n className={cn(\n 'flex items-center',\n schema.wrap && 'flex-wrap',\n schema.stacked ? usesDefaultImageStack(schema) && '-space-x-2' : 'gap-1.5',\n schema.wrap && schema.stacked && 'gap-y-1.5',\n )}\n >\n {urls.slice(0, limit).map((url, index) => (\n <img\n key={index}\n src={url}\n alt={cell.alt ?? ''}\n style={{\n height: schema.height ?? size,\n width: schema.width ?? (schema.square || schema.circular ? size : undefined),\n ...stackedImageStyle(index, schema),\n }}\n {...extraProps(\n cell.extraImgAttributes,\n cn(\n 'object-cover',\n schema.circular ? 'rounded-full' : 'rounded-md',\n schema.stacked && usesDefaultImageStack(schema) && 'ring-background ring-2',\n ),\n )}\n />\n ))}\n {schema.limitedRemainingText && urls.length > limit && (\n <span\n data-slot=\"image-remaining\"\n className={cn(\n 'text-muted-foreground ms-1',\n remainingTextSizeClass(schema.limitedRemainingTextSize),\n )}\n >\n +{urls.length - limit}\n </span>\n )}\n </div>\n )\n}\n\nfunction ColorCell({ column, cell }: CellProps) {\n const t = useT()\n const schema = column as ColorColumnSchema\n const [copied, setCopied] = useState<string | null>(null)\n const colors = Array.isArray(cell.state)\n ? (cell.state as string[])\n : cell.state\n ? [String(cell.state)]\n : []\n\n if (colors.length === 0) {\n return <span className=\"text-muted-foreground\">—</span>\n }\n\n const copy = (color: string) => {\n void navigator.clipboard?.writeText(color).then(() => {\n setCopied(color)\n setTimeout(() => setCopied(null), schema.copyMessageDuration ?? 1500)\n })\n }\n\n return (\n <div className={cn('flex items-center gap-1.5', schema.wrap ? 'flex-wrap' : 'flex-nowrap')}>\n {colors.map((color) =>\n schema.copyable ? (\n <button\n key={color}\n type=\"button\"\n data-slot=\"color-copy\"\n title={color}\n aria-label={`${t('copy', {}, 'Copy')} ${color}`}\n className=\"focus-visible:ring-ring/50 inline-flex rounded outline-none focus-visible:ring-[3px]\"\n onClick={(event) => {\n // The cell may sit inside a link or a clickable row.\n event.preventDefault()\n event.stopPropagation()\n copy(color)\n }}\n >\n <span\n className=\"inline-flex size-5 items-center justify-center rounded border shadow-xs\"\n style={{ backgroundColor: color }}\n >\n {copied === color && <CheckIcon className=\"size-3 text-white mix-blend-difference\" />}\n </span>\n </button>\n ) : (\n <span\n key={color}\n title={color}\n className=\"size-5 rounded border shadow-xs\"\n style={{ backgroundColor: color }}\n />\n ),\n )}\n {schema.copyable && copied && (\n <span role=\"status\" className={cn('text-xs', !schema.copyMessage && 'sr-only')}>\n {schema.copyMessage ?? t('copied', {}, 'Copied')}\n </span>\n )}\n </div>\n )\n}\n\nfunction useCellUpdate({ recordKey, column, token, component }: CellProps) {\n const panel = usePanel()\n const [saving, setSaving] = useState(false)\n const [error, setError] = useState<string | null>(null)\n\n const update = async (state: unknown) => {\n if (!panel.endpoints.tableCell || !panel.endpoints.tableReorder) return\n\n setSaving(true)\n setError(null)\n\n try {\n await updateTableCell(\n { cell: panel.endpoints.tableCell, reorder: panel.endpoints.tableReorder },\n token,\n component,\n recordKey,\n column.name,\n state,\n )\n router.reload({ only: resolvePartialProps(['page']) })\n } catch (caught) {\n const errors = (caught as { errors?: Record<string, string[]> }).errors\n setError(errors?.state?.[0] ?? (caught as Error).message)\n } finally {\n setSaving(false)\n }\n }\n\n return { update, saving, error }\n}\n\nfunction BooleanCell(props: CellProps) {\n const { column, cell } = props\n const { update, saving } = useCellUpdate(props)\n const [checked, setChecked] = useState(Boolean(cell.state))\n const disabled = Boolean(cell.disabled) || saving\n const toggle = column as ToggleColumnSchema\n\n const onChange = (next: boolean) => {\n setChecked(next)\n void update(next)\n }\n\n if (column.type === 'CheckboxColumn') {\n return (\n <Checkbox\n checked={checked}\n disabled={disabled}\n aria-label={column.label || column.name}\n onCheckedChange={(value) => onChange(value === true)}\n onClick={(event) => event.stopPropagation()}\n />\n )\n }\n\n return (\n <span className=\"inline-flex items-center gap-2\" onClick={(event) => event.stopPropagation()}>\n <Switch\n checked={checked}\n disabled={disabled}\n aria-label={column.label || column.name}\n onCheckedChange={onChange}\n className={cn(\n toggle.onColor && colorClass(switchOnColorClasses, toggle.onColor),\n toggle.offColor && colorClass(switchOffColorClasses, toggle.offColor),\n )}\n />\n {(checked ? toggle.onIcon : toggle.offIcon) && (\n <Icon\n name={checked ? toggle.onIcon : toggle.offIcon}\n className={cn(\n colorClass(textColorClasses, checked ? toggle.onColor : toggle.offColor, 'gray'),\n )}\n />\n )}\n </span>\n )\n}\n\nfunction flatten(options: OptionOrGroup[]) {\n return options.flatMap((option) => (isOptionGroup(option) ? option.options : [option]))\n}\n\nfunction SelectCell(props: CellProps) {\n const schema = props.column as SelectColumnSchema\n\n return schema.native === false ? (\n <SelectComboboxCell {...props} />\n ) : (\n <NativeSelectCell {...props} />\n )\n}\n\n/**\n * An option label: sanitised HTML under `allowOptionsHtml()`, text otherwise. Long labels\n * wrap unless `wrapOptionLabels(false)` truncates them.\n */\nfunction SelectOptionLabel({\n label,\n html,\n truncate,\n}: {\n label: string\n html?: boolean\n truncate?: boolean\n}) {\n const className = truncate ? 'min-w-0 truncate' : 'min-w-0 break-words whitespace-normal'\n\n // The server sanitises HTML labels (`Support\\Html::sanitize`).\n return html ? (\n <span className={className} dangerouslySetInnerHTML={{ __html: label }} />\n ) : (\n <span className={className}>{label}</span>\n )\n}\n\n/**\n * `SelectColumn::native(false)`: a combobox, searchable with `searchableOptions()`. Options\n * come with the table, or from the server (`optionsSearchPath`) as the user types.\n */\nfunction SelectComboboxCell(props: CellProps) {\n const { column, cell, recordKey, token, component } = props\n const schema = column as SelectColumnSchema\n const t = useT()\n const panel = usePanel()\n const { update, saving, error } = useCellUpdate(props)\n const [value, setValue] = useState(\n cell.state === null || cell.state === undefined ? '' : String(cell.state),\n )\n const [label, setLabel] = useState(cell.optionLabel)\n const [open, setOpen] = useState(false)\n const [search, setSearch] = useState('')\n const [loading, setLoading] = useState(false)\n const [remote, setRemote] = useState<Option[]>([])\n const request = useRef(0)\n const isRemote = Boolean(schema.optionsSearchPath)\n const debounce = schema.optionsSearchDebounce ?? 300\n const staticOptions = flatten(schema.options)\n\n useEffect(() => {\n if (!open || !isRemote || !panel.endpoints.schemaOptions) return\n\n const url = panel.endpoints.schemaOptions\n const timer = setTimeout(() => {\n const current = ++request.current\n setLoading(true)\n\n void searchTableColumnOptions(url, token, component, schema, search)\n .then((results) => current === request.current && setRemote(results))\n .catch(() => current === request.current && setRemote([]))\n .finally(() => current === request.current && setLoading(false))\n }, debounce)\n\n return () => clearTimeout(timer)\n }, [open, search, isRemote, panel.endpoints.schemaOptions, token, component, schema, debounce])\n\n const options = filterSelectColumnOptions(\n isRemote ? remote : staticOptions,\n schema,\n isRemote ? '' : search,\n recordKey,\n )\n const emptyMessage = selectColumnEmptyMessage(schema, {\n loading,\n search,\n optionCount: options.length,\n })\n const currentLabel =\n staticOptions.find((option) => option.value === value)?.label ??\n remote.find((option) => option.value === value)?.label ??\n label\n\n const choose = (next: string, nextLabel?: string) => {\n setValue(next)\n setLabel(nextLabel)\n setOpen(false)\n void update(next === '' ? null : next)\n }\n\n return (\n <span onClick={(event) => event.stopPropagation()}>\n <Popover\n open={open}\n onOpenChange={(next) => {\n setOpen(next)\n\n if (!next) setSearch('')\n }}\n >\n <PopoverTrigger asChild>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n role=\"combobox\"\n aria-expanded={open}\n aria-label={column.label || column.name}\n aria-invalid={error ? true : undefined}\n disabled={Boolean(cell.disabled) || saving}\n className={cn(\n 'h-8 min-w-32 justify-between font-normal',\n error && 'border-destructive',\n )}\n >\n {value !== '' && currentLabel !== undefined ? (\n <SelectOptionLabel label={currentLabel} html={schema.allowOptionsHtml} truncate />\n ) : (\n <span className=\"text-muted-foreground\">\n {schema.placeholder ??\n (value !== '' ? value : t('select_option', {}, 'Select an option'))}\n </span>\n )}\n {loading ? (\n <Spinner className=\"opacity-50\" />\n ) : (\n <ChevronsUpDownIcon className=\"size-4 shrink-0 opacity-50\" />\n )}\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-64 p-0\" align=\"start\">\n <Command shouldFilter={false}>\n {schema.searchableOptions && (\n <CommandInput\n placeholder={\n schema.searchPrompt ?? t('form.search_placeholder', {}, 'Type to search…')\n }\n value={search}\n onValueChange={setSearch}\n />\n )}\n <CommandList>\n <CommandEmpty data-slot=\"select-column-message\">\n {emptyMessage.message ?? t(emptyMessage.key, {}, emptyMessage.fallback)}\n </CommandEmpty>\n <CommandGroup>\n {schema.selectablePlaceholder && value !== '' && (\n <CommandItem value=\"\" onSelect={() => choose('')}>\n <span className=\"text-muted-foreground\">\n {schema.placeholder ?? t('clear', {}, 'Clear')}\n </span>\n </CommandItem>\n )}\n {options.map((option) => (\n <CommandItem\n key={option.value}\n value={option.value}\n keywords={[optionText(option.label)]}\n disabled={option.disabled}\n onSelect={() => choose(option.value, option.label)}\n >\n <CheckIcon\n className={cn('size-4', option.value === value ? 'opacity-100' : 'opacity-0')}\n />\n <SelectOptionLabel\n label={option.label}\n html={schema.allowOptionsHtml}\n truncate={schema.wrapOptionLabels === false}\n />\n </CommandItem>\n ))}\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n {error && <span className=\"text-destructive block text-xs\">{error}</span>}\n </span>\n )\n}\n\nfunction NativeSelectCell(props: CellProps) {\n const { column, cell } = props\n const schema = column as SelectColumnSchema\n const { update, saving, error } = useCellUpdate(props)\n const [value, setValue] = useState(\n cell.state === null || cell.state === undefined ? '' : String(cell.state),\n )\n\n const errorId = useId()\n\n return (\n <span onClick={(event) => event.stopPropagation()}>\n <select\n value={value}\n disabled={Boolean(cell.disabled) || saving}\n onChange={(event) => {\n setValue(event.target.value)\n void update(event.target.value === '' ? null : event.target.value)\n }}\n aria-label={column.label || column.name}\n aria-invalid={error ? true : undefined}\n aria-describedby={error ? errorId : undefined}\n className={cn(\n 'border-input dark:bg-input/30 focus-visible:ring-ring/50 h-8 min-w-32 rounded-md border bg-transparent px-2 text-sm shadow-xs outline-none focus-visible:ring-[3px]',\n error && 'border-destructive',\n )}\n >\n {schema.selectablePlaceholder && <option value=\"\">{schema.placeholder ?? ''}</option>}\n {flatten(schema.options)\n .filter((option) => !(schema.ignoreRecord && option.value === String(props.recordKey)))\n .map((option) => (\n <option key={option.value} value={option.value} disabled={option.disabled}>\n {option.label}\n </option>\n ))}\n </select>\n {error && (\n <span id={errorId} className=\"text-destructive block text-xs\">\n {error}\n </span>\n )}\n </span>\n )\n}\n\nfunction TextInputCell(props: CellProps) {\n const { column, cell } = props\n const schema = column as TextInputColumnSchema\n const { update, saving, error } = useCellUpdate(props)\n const [value, setValue] = useState(\n cell.state === null || cell.state === undefined ? '' : String(cell.state),\n )\n const initial = cell.state === null || cell.state === undefined ? '' : String(cell.state)\n // `prefix()` / `suffix()`: text affixes around the input, like the TextInput field.\n const grouped = Boolean(cell.prefix || cell.suffix)\n const errorId = useId()\n\n const field = (\n <span className={cn('relative block', grouped && 'min-w-0 flex-1')}>\n {schema.prefixIcon && (\n <span\n data-slot=\"input-prefix-icon\"\n aria-hidden=\"true\"\n className={cn(\n 'pointer-events-none absolute start-2.5 top-1/2 flex -translate-y-1/2',\n colorClass(textColorClasses, schema.prefixIconColor, 'gray'),\n )}\n >\n <Icon name={schema.prefixIcon} className=\"size-4\" />\n </span>\n )}\n <Input\n type={schema.inputType}\n value={value}\n placeholder={schema.placeholder}\n step={schema.step}\n inputMode={schema.inputMode as React.HTMLAttributes<HTMLInputElement>['inputMode']}\n disabled={Boolean(cell.disabled) || saving}\n aria-label={column.label || column.name}\n aria-invalid={error ? true : undefined}\n aria-describedby={error ? errorId : undefined}\n className={cn(\n 'h-8 min-w-32',\n schema.prefixIcon && 'ps-8',\n schema.suffixIcon && 'pe-8',\n grouped &&\n 'h-full rounded-none border-0 bg-transparent shadow-none focus-visible:ring-0 dark:bg-transparent',\n )}\n onChange={(event) => setValue(event.target.value)}\n onBlur={() => value !== initial && void update(value)}\n onKeyDown={(event) => event.key === 'Enter' && (event.target as HTMLInputElement).blur()}\n />\n {schema.suffixIcon && (\n <span\n data-slot=\"input-suffix-icon\"\n aria-hidden=\"true\"\n className={cn(\n 'pointer-events-none absolute end-2.5 top-1/2 flex -translate-y-1/2',\n colorClass(textColorClasses, schema.suffixIconColor, 'gray'),\n )}\n >\n <Icon name={schema.suffixIcon} className=\"size-4\" />\n </span>\n )}\n </span>\n )\n\n return (\n <span onClick={(event) => event.stopPropagation()}>\n {grouped ? (\n <span\n data-slot=\"input-group\"\n className={cn(\n 'border-input dark:bg-input/30 has-[input:focus-visible]:border-ring has-[input:focus-visible]:ring-ring/50 flex h-8 min-w-32 items-stretch overflow-hidden rounded-md border shadow-xs has-[input:focus-visible]:ring-[3px]',\n error && 'border-destructive',\n )}\n >\n {cell.prefix && (\n <span\n data-slot=\"input-prefix\"\n className=\"text-muted-foreground bg-muted/50 flex items-center border-e px-2 text-sm\"\n >\n {cell.prefix}\n </span>\n )}\n {field}\n {cell.suffix && (\n <span\n data-slot=\"input-suffix\"\n className=\"text-muted-foreground bg-muted/50 flex items-center border-s px-2 text-sm\"\n >\n {cell.suffix}\n </span>\n )}\n </span>\n ) : (\n field\n )}\n {error && (\n <span id={errorId} className=\"text-destructive block text-xs\">\n {error}\n </span>\n )}\n </span>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"cells.js","names":[],"sources":["../../../src/components/table/cells.tsx"],"sourcesContent":["import type {\n CellSchema,\n ColorColumnSchema,\n ColumnSchema,\n IconColumnSchema,\n Option,\n OptionOrGroup,\n RecordKey,\n SelectColumnSchema,\n TextInputColumnSchema,\n ToggleColumnSchema,\n ViewColumnSchema,\n} from '@alfakit/core'\nimport {\n columnRegistryKey,\n filterSelectColumnOptions,\n isOptionGroup,\n optionText,\n remainingTextSizeClass,\n resolvePartialProps,\n searchTableColumnOptions,\n selectColumnEmptyMessage,\n stackedImageStyle,\n updateTableCell,\n usesDefaultImageStack,\n} from '@alfakit/core'\nimport { router } from '@inertiajs/react'\nimport { CheckIcon, ChevronsUpDownIcon } from 'lucide-react'\nimport { createElement, useEffect, useId, useRef, useState } from 'react'\nimport { usePanel, useRegistry, useT } from '../../context'\nimport { extraProps } from '../../lib/attributes'\nimport {\n colorClass,\n iconSizeClasses,\n switchOffColorClasses,\n switchOnColorClasses,\n textColorClasses,\n} from '../../lib/colors'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport { FormattedText } from '../entries/text-entry'\nimport { Button } from '../ui/button'\nimport { Checkbox } from '../ui/checkbox'\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n} from '../ui/command'\nimport { Input } from '../ui/input'\nimport { Popover, PopoverContent, PopoverTrigger } from '../ui/popover'\nimport { Spinner } from '../ui/spinner'\nimport { Switch } from '../ui/switch'\n\nexport interface CellProps {\n column: ColumnSchema\n cell: CellSchema\n recordKey: RecordKey\n token: string\n component: string\n /**\n * Set when this renderer was picked from the registry (`column:<type>`): it then renders\n * the built-in cell instead of looking itself up again, so an ejected `TableCellContent`\n * registered for a column type doesn't render itself forever.\n */\n fromRegistry?: boolean\n}\n\nexport function TableCellContent(props: CellProps) {\n const { column } = props\n const registry = useRegistry()\n // A component registered as `column:<type>` replaces the built-in cell renderer.\n const Custom = props.fromRegistry ? undefined : registry.resolve(columnRegistryKey(column))\n\n if (Custom) {\n return createElement(Custom, { ...props, fromRegistry: true })\n }\n\n switch (column.type) {\n case 'IconColumn':\n return <IconCell {...props} />\n case 'ImageColumn':\n return <ImageCell {...props} />\n case 'ColorColumn':\n return <ColorCell {...props} />\n case 'ToggleColumn':\n case 'CheckboxColumn':\n return <BooleanCell {...props} />\n case 'SelectColumn':\n return <SelectCell {...props} />\n case 'TextInputColumn':\n return <TextInputCell {...props} />\n case 'ViewColumn':\n return <ViewCell {...props} />\n default:\n return <TextCell {...props} />\n }\n}\n\n/** `IconColumn`: one icon, or one per item of a list state (`wrap()` lets them wrap). */\nfunction IconCell({ column, cell }: CellProps) {\n const icons = cell.icons ?? (cell.icon ? [{ icon: cell.icon, color: cell.color }] : [])\n const sizeClass = colorClass(iconSizeClasses, cell.size, 'md')\n\n if (icons.length === 0) {\n return <span className=\"text-muted-foreground\">—</span>\n }\n\n if (!cell.icons) {\n return (\n <Icon\n name={icons[0]!.icon}\n className={cn(sizeClass, icons[0]!.color && textColorClasses[icons[0]!.color])}\n />\n )\n }\n\n return (\n <div\n data-slot=\"icon-column-icons\"\n className={cn(\n 'flex items-center gap-1.5',\n (column as IconColumnSchema).wrap ? 'flex-wrap' : 'flex-nowrap',\n )}\n >\n {icons.map((item, index) => (\n <Icon\n key={index}\n name={item.icon}\n className={cn(sizeClass, item.color && textColorClasses[item.color])}\n />\n ))}\n </div>\n )\n}\n\n/** `ViewColumn`: the application component registered under the column's `view()` name. */\nfunction ViewCell(props: CellProps) {\n const t = useT()\n const name = (props.column as ViewColumnSchema).component ?? ''\n const Custom = useRegistry().resolve(name)\n\n if (!name || !Custom) {\n return (\n <span className=\"text-destructive text-xs\">\n {t('component_not_registered', { component: name }, `Component ${name} is not registered.`)}\n </span>\n )\n }\n\n return createElement(Custom, { ...(props.cell.props ?? {}), state: props.cell.state, ...props })\n}\n\nfunction TextCell({ column, cell }: CellProps) {\n const text = (\n <FormattedText\n value={cell.state}\n schema={{\n ...(column as object),\n color: cell.color,\n icon: cell.icon,\n iconPosition: cell.iconPosition,\n iconColor: cell.iconColor,\n itemColors: cell.itemColors,\n itemIcons: cell.itemIcons,\n itemUrls: cell.itemUrls,\n }}\n />\n )\n const description = cell.description ? (\n <span className=\"text-muted-foreground block text-xs\">{cell.description}</span>\n ) : null\n const position =\n (column as { descriptionPosition?: 'above' | 'below' }).descriptionPosition ?? 'below'\n\n return (\n <div className=\"flex flex-col gap-0.5\">\n {position === 'above' && description}\n {text}\n {position === 'below' && description}\n </div>\n )\n}\n\nfunction ImageCell({ column, cell }: CellProps) {\n const urls = Array.isArray(cell.state) ? (cell.state as string[]) : []\n const schema = column as {\n circular?: boolean\n square?: boolean\n size?: number | string\n height?: number | string\n width?: string\n stacked?: boolean\n limit?: number\n limitedRemainingText?: boolean\n limitedRemainingTextSize?: string\n wrap?: boolean\n ring?: number\n overlap?: number\n }\n const limit = schema.limit ?? urls.length\n const size = schema.size ?? 40\n\n if (urls.length === 0) {\n return <span className=\"text-muted-foreground\">—</span>\n }\n\n return (\n <div\n className={cn(\n 'flex items-center',\n schema.wrap && 'flex-wrap',\n schema.stacked ? usesDefaultImageStack(schema) && '-space-x-2' : 'gap-1.5',\n schema.wrap && schema.stacked && 'gap-y-1.5',\n )}\n >\n {urls.slice(0, limit).map((url, index) => (\n <img\n key={index}\n src={url}\n alt={cell.alt ?? ''}\n style={{\n height: schema.height ?? size,\n width: schema.width ?? (schema.square || schema.circular ? size : undefined),\n ...stackedImageStyle(index, schema),\n }}\n {...extraProps(\n cell.extraImgAttributes,\n cn(\n 'object-cover',\n schema.circular ? 'rounded-full' : 'rounded-md',\n schema.stacked && usesDefaultImageStack(schema) && 'ring-background ring-2',\n ),\n )}\n />\n ))}\n {schema.limitedRemainingText && urls.length > limit && (\n <span\n data-slot=\"image-remaining\"\n className={cn(\n 'text-muted-foreground ms-1',\n remainingTextSizeClass(schema.limitedRemainingTextSize),\n )}\n >\n +{urls.length - limit}\n </span>\n )}\n </div>\n )\n}\n\nfunction ColorCell({ column, cell }: CellProps) {\n const t = useT()\n const schema = column as ColorColumnSchema\n const [copied, setCopied] = useState<string | null>(null)\n const colors = Array.isArray(cell.state)\n ? (cell.state as string[])\n : cell.state\n ? [String(cell.state)]\n : []\n\n if (colors.length === 0) {\n return <span className=\"text-muted-foreground\">—</span>\n }\n\n const copy = (color: string) => {\n void navigator.clipboard?.writeText(color).then(() => {\n setCopied(color)\n setTimeout(() => setCopied(null), schema.copyMessageDuration ?? 1500)\n })\n }\n\n return (\n <div className={cn('flex items-center gap-1.5', schema.wrap ? 'flex-wrap' : 'flex-nowrap')}>\n {colors.map((color) =>\n schema.copyable ? (\n <button\n key={color}\n type=\"button\"\n data-slot=\"color-copy\"\n title={color}\n aria-label={`${t('copy', {}, 'Copy')} ${color}`}\n className=\"focus-visible:ring-ring/50 inline-flex rounded outline-none focus-visible:ring-[3px]\"\n onClick={(event) => {\n // The cell may sit inside a link or a clickable row.\n event.preventDefault()\n event.stopPropagation()\n copy(color)\n }}\n >\n <span\n className=\"inline-flex size-5 items-center justify-center rounded border shadow-xs\"\n style={{ backgroundColor: color }}\n >\n {copied === color && <CheckIcon className=\"size-3 text-white mix-blend-difference\" />}\n </span>\n </button>\n ) : (\n <span\n key={color}\n title={color}\n className=\"size-5 rounded border shadow-xs\"\n style={{ backgroundColor: color }}\n />\n ),\n )}\n {schema.copyable && copied && (\n <span role=\"status\" className={cn('text-xs', !schema.copyMessage && 'sr-only')}>\n {schema.copyMessage ?? t('copied', {}, 'Copied')}\n </span>\n )}\n </div>\n )\n}\n\nfunction useCellUpdate({ recordKey, column, token, component }: CellProps) {\n const panel = usePanel()\n const [saving, setSaving] = useState(false)\n const [error, setError] = useState<string | null>(null)\n\n const update = async (state: unknown) => {\n if (!panel.endpoints.tableCell || !panel.endpoints.tableReorder) return\n\n setSaving(true)\n setError(null)\n\n try {\n await updateTableCell(\n { cell: panel.endpoints.tableCell, reorder: panel.endpoints.tableReorder },\n token,\n component,\n recordKey,\n column.name,\n state,\n )\n router.reload({ only: resolvePartialProps(['page']) })\n } catch (caught) {\n const errors = (caught as { errors?: Record<string, string[]> }).errors\n setError(errors?.state?.[0] ?? (caught as Error).message)\n } finally {\n setSaving(false)\n }\n }\n\n return { update, saving, error }\n}\n\nfunction BooleanCell(props: CellProps) {\n const { column, cell } = props\n const { update, saving } = useCellUpdate(props)\n const [checked, setChecked] = useState(Boolean(cell.state))\n const disabled = Boolean(cell.disabled) || saving\n const toggle = column as ToggleColumnSchema\n\n const onChange = (next: boolean) => {\n setChecked(next)\n void update(next)\n }\n\n if (column.type === 'CheckboxColumn') {\n return (\n <Checkbox\n checked={checked}\n disabled={disabled}\n aria-label={column.label || column.name}\n onCheckedChange={(value) => onChange(value === true)}\n onClick={(event) => event.stopPropagation()}\n />\n )\n }\n\n return (\n <span className=\"inline-flex items-center gap-2\" onClick={(event) => event.stopPropagation()}>\n <Switch\n checked={checked}\n disabled={disabled}\n aria-label={column.label || column.name}\n onCheckedChange={onChange}\n className={cn(\n toggle.onColor && colorClass(switchOnColorClasses, toggle.onColor),\n toggle.offColor && colorClass(switchOffColorClasses, toggle.offColor),\n )}\n />\n {(checked ? toggle.onIcon : toggle.offIcon) && (\n <Icon\n name={checked ? toggle.onIcon : toggle.offIcon}\n className={cn(\n colorClass(textColorClasses, checked ? toggle.onColor : toggle.offColor, 'gray'),\n )}\n />\n )}\n </span>\n )\n}\n\nfunction flatten(options: OptionOrGroup[]) {\n return options.flatMap((option) => (isOptionGroup(option) ? option.options : [option]))\n}\n\nfunction SelectCell(props: CellProps) {\n const schema = props.column as SelectColumnSchema\n\n return schema.native === false ? (\n <SelectComboboxCell {...props} />\n ) : (\n <NativeSelectCell {...props} />\n )\n}\n\n/**\n * An option label: sanitised HTML under `allowOptionsHtml()`, text otherwise. Long labels\n * wrap unless `wrapOptionLabels(false)` truncates them.\n */\nfunction SelectOptionLabel({\n label,\n html,\n truncate,\n}: {\n label: string\n html?: boolean\n truncate?: boolean\n}) {\n const className = truncate ? 'min-w-0 truncate' : 'min-w-0 break-words whitespace-normal'\n\n // The server sanitises HTML labels (`Support\\Html::sanitize`).\n return html ? (\n <span className={className} dangerouslySetInnerHTML={{ __html: label }} />\n ) : (\n <span className={className}>{label}</span>\n )\n}\n\n/**\n * `SelectColumn::native(false)`: a combobox, searchable with `searchableOptions()`. Options\n * come with the table, or from the server (`optionsSearchPath`) as the user types.\n */\nfunction SelectComboboxCell(props: CellProps) {\n const { column, cell, recordKey, token, component } = props\n const schema = column as SelectColumnSchema\n const t = useT()\n const panel = usePanel()\n const { update, saving, error } = useCellUpdate(props)\n const [value, setValue] = useState(\n cell.state === null || cell.state === undefined ? '' : String(cell.state),\n )\n const [label, setLabel] = useState(cell.optionLabel)\n const [open, setOpen] = useState(false)\n const [search, setSearch] = useState('')\n const [loading, setLoading] = useState(false)\n const [remote, setRemote] = useState<Option[]>([])\n const request = useRef(0)\n const isRemote = Boolean(schema.optionsSearchPath)\n const debounce = schema.optionsSearchDebounce ?? 300\n const staticOptions = flatten(schema.options)\n\n useEffect(() => {\n if (!open || !isRemote || !panel.endpoints.schemaOptions) return\n\n const url = panel.endpoints.schemaOptions\n const timer = setTimeout(() => {\n const current = ++request.current\n setLoading(true)\n\n void searchTableColumnOptions(url, token, component, schema, search)\n .then((results) => current === request.current && setRemote(results))\n .catch(() => current === request.current && setRemote([]))\n .finally(() => current === request.current && setLoading(false))\n }, debounce)\n\n return () => clearTimeout(timer)\n }, [open, search, isRemote, panel.endpoints.schemaOptions, token, component, schema, debounce])\n\n const options = filterSelectColumnOptions(\n isRemote ? remote : staticOptions,\n schema,\n isRemote ? '' : search,\n recordKey,\n )\n const emptyMessage = selectColumnEmptyMessage(schema, {\n loading,\n search,\n optionCount: options.length,\n })\n const currentLabel =\n staticOptions.find((option) => option.value === value)?.label ??\n remote.find((option) => option.value === value)?.label ??\n label\n\n const choose = (next: string, nextLabel?: string) => {\n setValue(next)\n setLabel(nextLabel)\n setOpen(false)\n void update(next === '' ? null : next)\n }\n\n return (\n <span onClick={(event) => event.stopPropagation()}>\n <Popover\n open={open}\n onOpenChange={(next) => {\n setOpen(next)\n\n if (!next) setSearch('')\n }}\n >\n <PopoverTrigger asChild>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n role=\"combobox\"\n aria-expanded={open}\n aria-label={column.label || column.name}\n aria-invalid={error ? true : undefined}\n disabled={Boolean(cell.disabled) || saving}\n className={cn(\n 'h-8 min-w-32 justify-between font-normal',\n error && 'border-destructive',\n )}\n >\n {value !== '' && currentLabel !== undefined ? (\n <SelectOptionLabel label={currentLabel} html={schema.allowOptionsHtml} truncate />\n ) : (\n <span className=\"text-muted-foreground\">\n {schema.placeholder ??\n (value !== '' ? value : t('select_option', {}, 'Select an option'))}\n </span>\n )}\n {loading ? (\n <Spinner className=\"opacity-50\" />\n ) : (\n <ChevronsUpDownIcon className=\"size-4 shrink-0 opacity-50\" />\n )}\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-64 p-0\" align=\"start\">\n <Command shouldFilter={false}>\n {schema.searchableOptions && (\n <CommandInput\n placeholder={\n schema.searchPrompt ?? t('form.search_placeholder', {}, 'Type to search…')\n }\n value={search}\n onValueChange={setSearch}\n />\n )}\n <CommandList>\n <CommandEmpty data-slot=\"select-column-message\">\n {emptyMessage.message ?? t(emptyMessage.key, {}, emptyMessage.fallback)}\n </CommandEmpty>\n <CommandGroup>\n {schema.selectablePlaceholder && value !== '' && (\n <CommandItem value=\"\" onSelect={() => choose('')}>\n <span className=\"text-muted-foreground\">\n {schema.placeholder ?? t('clear', {}, 'Clear')}\n </span>\n </CommandItem>\n )}\n {options.map((option) => (\n <CommandItem\n key={option.value}\n value={option.value}\n keywords={[optionText(option.label)]}\n disabled={option.disabled}\n onSelect={() => choose(option.value, option.label)}\n >\n <CheckIcon\n className={cn('size-4', option.value === value ? 'opacity-100' : 'opacity-0')}\n />\n <SelectOptionLabel\n label={option.label}\n html={schema.allowOptionsHtml}\n truncate={schema.wrapOptionLabels === false}\n />\n </CommandItem>\n ))}\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n {error && <span className=\"text-destructive block text-xs\">{error}</span>}\n </span>\n )\n}\n\nfunction NativeSelectCell(props: CellProps) {\n const { column, cell } = props\n const schema = column as SelectColumnSchema\n const { update, saving, error } = useCellUpdate(props)\n const [value, setValue] = useState(\n cell.state === null || cell.state === undefined ? '' : String(cell.state),\n )\n\n const errorId = useId()\n\n return (\n <span onClick={(event) => event.stopPropagation()}>\n <select\n value={value}\n disabled={Boolean(cell.disabled) || saving}\n onChange={(event) => {\n setValue(event.target.value)\n void update(event.target.value === '' ? null : event.target.value)\n }}\n aria-label={column.label || column.name}\n aria-invalid={error ? true : undefined}\n aria-describedby={error ? errorId : undefined}\n className={cn(\n 'border-input dark:bg-input/30 focus-visible:ring-ring/50 h-8 min-w-32 rounded-md border bg-transparent px-2 text-sm shadow-xs outline-none focus-visible:ring-[3px]',\n error && 'border-destructive',\n )}\n >\n {schema.selectablePlaceholder && <option value=\"\">{schema.placeholder ?? ''}</option>}\n {flatten(schema.options)\n .filter((option) => !(schema.ignoreRecord && option.value === String(props.recordKey)))\n .map((option) => (\n <option key={option.value} value={option.value} disabled={option.disabled}>\n {option.label}\n </option>\n ))}\n </select>\n {error && (\n <span id={errorId} className=\"text-destructive block text-xs\">\n {error}\n </span>\n )}\n </span>\n )\n}\n\nfunction TextInputCell(props: CellProps) {\n const { column, cell } = props\n const schema = column as TextInputColumnSchema\n const { update, saving, error } = useCellUpdate(props)\n const [value, setValue] = useState(\n cell.state === null || cell.state === undefined ? '' : String(cell.state),\n )\n const initial = cell.state === null || cell.state === undefined ? '' : String(cell.state)\n // `prefix()` / `suffix()`: text affixes around the input, like the TextInput field.\n const grouped = Boolean(cell.prefix || cell.suffix)\n const errorId = useId()\n\n const field = (\n <span className={cn('relative block', grouped && 'min-w-0 flex-1')}>\n {schema.prefixIcon && (\n <span\n data-slot=\"input-prefix-icon\"\n aria-hidden=\"true\"\n className={cn(\n 'pointer-events-none absolute start-2.5 top-1/2 flex -translate-y-1/2',\n colorClass(textColorClasses, schema.prefixIconColor, 'gray'),\n )}\n >\n <Icon name={schema.prefixIcon} className=\"size-4\" />\n </span>\n )}\n <Input\n type={schema.inputType}\n value={value}\n placeholder={schema.placeholder}\n step={schema.step}\n inputMode={schema.inputMode as React.HTMLAttributes<HTMLInputElement>['inputMode']}\n disabled={Boolean(cell.disabled) || saving}\n aria-label={column.label || column.name}\n aria-invalid={error ? true : undefined}\n aria-describedby={error ? errorId : undefined}\n className={cn(\n 'h-8 min-w-32',\n schema.prefixIcon && 'ps-8',\n schema.suffixIcon && 'pe-8',\n grouped &&\n 'h-full rounded-none border-0 bg-transparent shadow-none focus-visible:ring-0 dark:bg-transparent',\n )}\n onChange={(event) => setValue(event.target.value)}\n onBlur={() => value !== initial && void update(value)}\n onKeyDown={(event) => event.key === 'Enter' && (event.target as HTMLInputElement).blur()}\n />\n {schema.suffixIcon && (\n <span\n data-slot=\"input-suffix-icon\"\n aria-hidden=\"true\"\n className={cn(\n 'pointer-events-none absolute end-2.5 top-1/2 flex -translate-y-1/2',\n colorClass(textColorClasses, schema.suffixIconColor, 'gray'),\n )}\n >\n <Icon name={schema.suffixIcon} className=\"size-4\" />\n </span>\n )}\n </span>\n )\n\n return (\n <span onClick={(event) => event.stopPropagation()}>\n {grouped ? (\n <span\n data-slot=\"input-group\"\n className={cn(\n 'border-input dark:bg-input/30 has-[input:focus-visible]:border-ring has-[input:focus-visible]:ring-ring/50 flex h-8 min-w-32 items-stretch overflow-hidden rounded-md border shadow-xs has-[input:focus-visible]:ring-[3px]',\n error && 'border-destructive',\n )}\n >\n {cell.prefix && (\n <span\n data-slot=\"input-prefix\"\n className=\"text-muted-foreground bg-muted/50 flex items-center border-e px-2 text-sm\"\n >\n {cell.prefix}\n </span>\n )}\n {field}\n {cell.suffix && (\n <span\n data-slot=\"input-suffix\"\n className=\"text-muted-foreground bg-muted/50 flex items-center border-s px-2 text-sm\"\n >\n {cell.suffix}\n </span>\n )}\n </span>\n ) : (\n field\n )}\n {error && (\n <span id={errorId} className=\"text-destructive block text-xs\">\n {error}\n </span>\n )}\n </span>\n )\n}\n"],"mappings":"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"}
@@ -101,18 +101,19 @@ function ColumnManager({ table, token, component }) {
101
101
  reorder(name, moveColumnInManager(names, name, offset, table.columnGroups));
102
102
  };
103
103
  const orderChanged = Boolean(orderDraft && columnOrderChanged(appliedNames, orderDraft));
104
- const apply = () => {
105
- if (orderDraft && orderChanged) save(orderDraft);
106
- if (draft && columnDraftChanged(table.visibleColumns, draft)) visitTable(table.identifier, { columns: draft }, ["page"]);
104
+ const apply = async () => {
105
+ const columns = draft && columnDraftChanged(table.visibleColumns, draft) ? draft : null;
107
106
  setDraft(null);
108
107
  setOrderDraft(null);
109
108
  setAnnouncement("");
110
109
  setOpen(false);
110
+ if (orderDraft && orderChanged) await save(orderDraft);
111
+ if (columns) visitTable(table.identifier, { columns }, ["page"]);
111
112
  };
112
- const reset = () => {
113
+ const reset = async () => {
113
114
  if (reorderable) {
114
115
  setOrderDraft(null);
115
- save([]);
116
+ await save([]);
116
117
  }
117
118
  if (toggleable) {
118
119
  setDraft(null);
@@ -132,7 +133,7 @@ function ColumnManager({ table, token, component }) {
132
133
  disabled: saving,
133
134
  "data-slot": "column-manager-reset",
134
135
  className: cn(!applyView && "w-full"),
135
- onClick: reset
136
+ onClick: () => void reset()
136
137
  }) : null;
137
138
  const inHeader = table.columnManagerResetActionPosition === "header";
138
139
  const list = /* @__PURE__ */ jsx("ul", {
@@ -250,7 +251,7 @@ function ColumnManager({ table, token, component }) {
250
251
  view: applyView,
251
252
  "data-slot": "column-manager-apply",
252
253
  disabled: !orderChanged && (!draft || !columnDraftChanged(table.visibleColumns, draft)),
253
- onClick: apply
254
+ onClick: () => void apply()
254
255
  })]
255
256
  })
256
257
  ]
@@ -1 +1 @@
1
- {"version":3,"file":"column-manager.js","names":[],"sources":["../../../src/components/table/column-manager.tsx"],"sourcesContent":["import type { TableSchema } from '@alfakit/core'\nimport {\n columnDraftChanged,\n columnManagerPosition,\n columnOrderChanged,\n defaultVisibleColumns,\n FILTERS_MODAL_WIDTH_CLASSES,\n gridColumnsClasses,\n keepMoveButtonFocus,\n moveColumnInManager,\n moveColumnTo,\n orderColumnsBy,\n saveColumnOrder,\n slideOverSide,\n toggleVisibleColumn,\n triggerButtonView,\n visitTable,\n} from '@alfakit/core'\nimport { ChevronDownIcon, ChevronUpIcon, Columns3Icon, GripVerticalIcon } from 'lucide-react'\nimport { useId, useState, type ReactNode } from 'react'\nimport { useDirection, usePanel, useT } from '../../context'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport { showToast } from '../notifications/flash-toasts'\nimport { Button } from '../ui/button'\nimport { Checkbox } from '../ui/checkbox'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from '../ui/dialog'\nimport { Popover, PopoverContent, PopoverTrigger } from '../ui/popover'\nimport {\n Sheet,\n SheetContent,\n SheetDescription,\n SheetHeader,\n SheetTitle,\n SheetTrigger,\n} from '../ui/sheet'\nimport { TableTriggerButton } from './trigger-button'\n\n/**\n * The column manager: show / hide toggleable columns (kept in the query string) and,\n * with `reorderableColumns()`, move columns (stored per user on the server) by dragging a\n * row onto another or with the move up / down buttons (the keyboard path).\n *\n * `deferColumnManager()` keeps toggles in a draft until \"Apply\"; `columnManagerLayout()`\n * opens it in a dialog; `columnManagerColumns()` lays the list out in a grid.\n */\nexport function ColumnManager({\n table,\n token,\n component,\n}: {\n table: TableSchema\n token: string\n component: string\n}) {\n const t = useT()\n const panel = usePanel()\n const direction = useDirection()\n const [open, setOpen] = useState(false)\n const [saving, setSaving] = useState(false)\n const [dragging, setDragging] = useState<string | null>(null)\n const [dropTarget, setDropTarget] = useState<string | null>(null)\n // Toggles of a deferred column manager wait here until \"Apply\".\n const [draft, setDraft] = useState<string[] | null>(null)\n // A moved column order: the draft of a deferred column manager, or shown at once\n // while it is saved.\n // It belongs to the columns it was made from: the server's next order replaces the\n // one shown while saving.\n const [orderState, setOrderState] = useState<{\n order: string[]\n columns: TableSchema['columns']\n } | null>(null)\n // Screen-reader announcement of the last move.\n const [announcement, setAnnouncement] = useState('')\n const idBase = useId()\n const reorderable = Boolean(table.reorderableColumns && panel.endpoints.tableColumns)\n const toggleable = Boolean(table.toggleableColumns)\n const deferred = Boolean(table.deferColumnManager)\n const orderDraft =\n orderState && (deferred || orderState.columns === table.columns) ? orderState.order : null\n const setOrderDraft = (order: string[] | null) =>\n setOrderState(order ? { order, columns: table.columns } : null)\n const appliedNames = table.columns.map((column) => column.name)\n const names = orderDraft ?? appliedNames\n const columns = orderColumnsBy(\n reorderable ? table.columns : table.columns.filter((column) => column.toggleable),\n orderDraft,\n )\n const visible = draft ?? table.visibleColumns\n\n if (!toggleable && !reorderable) return null\n\n const trigger = triggerButtonView(table, 'columnManager', {\n label: t('table.columns', {}, 'Columns'),\n showLabel: false,\n })\n\n if (!trigger) return null\n\n const toggle = (name: string) => {\n const next = toggleVisibleColumn(visible, name)\n\n if (deferred) {\n setDraft(next)\n } else {\n visitTable(table.identifier, { columns: next }, ['page'])\n }\n }\n\n const save = async (order: string[]): Promise<boolean> => {\n if (!panel.endpoints.tableColumns) return false\n\n setSaving(true)\n\n try {\n await saveColumnOrder(panel.endpoints.tableColumns, token, component, order)\n\n return true\n } catch (error) {\n showToast({\n id: 'alfakit-column-order-failed',\n title: t('table.column_order_failed', {}, \"Couldn't save the column order\"),\n body: error instanceof Error ? error.message : String(error),\n status: 'danger',\n format: 'alfakit',\n })\n\n return false\n } finally {\n setSaving(false)\n }\n }\n\n const announce = (name: string, order: string[]) => {\n const { position, count, group } = columnManagerPosition(order, name, table.columnGroups)\n const label = table.columns.find((column) => column.name === name)?.label ?? name\n const replace = { column: label, position, count, group: group ?? '' }\n\n setAnnouncement(\n group\n ? deferred\n ? t(\n 'table.column_manager.reordered_in_group_deferred',\n replace,\n `${label} moved to position ${position} of ${count} in ${group}. Apply columns to save your changes.`,\n )\n : t(\n 'table.column_manager.reordered_in_group',\n replace,\n `${label} moved to position ${position} of ${count} in ${group}.`,\n )\n : deferred\n ? t(\n 'table.column_manager.reordered_deferred',\n replace,\n `${label} moved to position ${position} of ${count}. Apply columns to save your changes.`,\n )\n : t(\n 'table.column_manager.reordered',\n replace,\n `${label} moved to position ${position} of ${count}.`,\n ),\n )\n }\n\n // A new order: kept as a draft until \"Apply\" (`deferColumnManager()`), else saved now.\n const reorder = (name: string, order: string[]) => {\n if (saving || !columnOrderChanged(names, order)) return\n\n setOrderDraft(order)\n setAnnouncement('')\n\n if (deferred) {\n announce(name, order)\n\n return\n }\n\n void save(order).then((saved) => (saved ? announce(name, order) : setOrderDraft(null)))\n }\n\n const move = (name: string, offset: -1 | 1, button: HTMLElement) => {\n keepMoveButtonFocus(button)\n reorder(name, moveColumnInManager(names, name, offset, table.columnGroups))\n }\n\n const orderChanged = Boolean(orderDraft && columnOrderChanged(appliedNames, orderDraft))\n\n const apply = () => {\n if (orderDraft && orderChanged) void save(orderDraft)\n\n if (draft && columnDraftChanged(table.visibleColumns, draft)) {\n visitTable(table.identifier, { columns: draft }, ['page'])\n }\n\n setDraft(null)\n setOrderDraft(null)\n setAnnouncement('')\n setOpen(false)\n }\n\n // Reset: the defined column order and, for toggleable columns, the default visibility.\n const reset = () => {\n if (reorderable) {\n setOrderDraft(null)\n void save([])\n }\n\n if (toggleable) {\n setDraft(null)\n visitTable(table.identifier, { columns: defaultVisibleColumns(table) }, ['page'])\n }\n }\n\n const resetView = triggerButtonView(table, 'columnManagerReset', {\n label: toggleable\n ? t('table.reset_columns', {}, 'Reset')\n : t('table.reset_column_order', {}, 'Reset column order'),\n variant: 'ghost',\n })\n const applyView = deferred\n ? triggerButtonView(table, 'columnManagerApply', {\n label: t('table_filters.apply', {}, 'Apply'),\n variant: 'default',\n })\n : null\n const resetButton = resetView ? (\n <TableTriggerButton\n view={resetView}\n disabled={saving}\n data-slot=\"column-manager-reset\"\n className={cn(!applyView && 'w-full')}\n onClick={reset}\n />\n ) : null\n const inHeader = table.columnManagerResetActionPosition === 'header'\n\n const list = (\n <ul\n className={cn(\n table.columnManagerColumns\n ? ['grid gap-0.5', gridColumnsClasses(table.columnManagerColumns)]\n : 'flex flex-col gap-0.5',\n )}\n aria-label={t('table.columns', {}, 'Columns')}\n >\n {columns.map((column) => {\n const { position, count, group } = columnManagerPosition(\n names,\n column.name,\n table.columnGroups,\n )\n const positionId = `${idBase}-${column.name}-position`\n\n return (\n <li\n key={column.name}\n data-column={column.name}\n draggable={reorderable && !saving}\n onDragStart={(event) => {\n if (event.dataTransfer) event.dataTransfer.effectAllowed = 'move'\n setDragging(column.name)\n }}\n onDragOver={(event) => {\n if (dragging === null) return\n\n event.preventDefault()\n if (event.dataTransfer) event.dataTransfer.dropEffect = 'move'\n setDropTarget(column.name)\n }}\n onDragLeave={() => dropTarget === column.name && setDropTarget(null)}\n onDragEnd={() => {\n setDragging(null)\n setDropTarget(null)\n }}\n onDrop={(event) => {\n event.preventDefault()\n\n if (dragging !== null && dragging !== column.name) {\n reorder(dragging, moveColumnTo(names, dragging, column.name))\n }\n\n setDragging(null)\n setDropTarget(null)\n }}\n className={cn(\n 'flex items-center gap-2 rounded-md px-2 py-1 text-sm',\n reorderable && 'cursor-grab',\n dragging === column.name && 'opacity-50',\n dropTarget === column.name && dragging !== column.name && 'bg-muted',\n )}\n >\n {reorderable && (\n <GripVerticalIcon\n className=\"text-muted-foreground size-4 shrink-0\"\n aria-hidden=\"true\"\n />\n )}\n {column.toggleable ? (\n <label className=\"flex min-w-0 flex-1 items-center gap-2\">\n <Checkbox\n checked={visible.includes(column.name)}\n onCheckedChange={() => toggle(column.name)}\n />\n <span className=\"truncate\">{column.label}</span>\n </label>\n ) : (\n <span className=\"min-w-0 flex-1 truncate\">{column.label}</span>\n )}\n {reorderable && (\n <span className=\"flex shrink-0 items-center\">\n <span id={positionId} className=\"sr-only\" data-slot=\"column-manager-position\">\n {group\n ? t(\n 'table.column_manager.position_in_group',\n { position, count, group },\n `Position ${position} of ${count} in ${group}.`,\n )\n : t(\n 'table.column_manager.position',\n { position, count },\n `Position ${position} of ${count}.`,\n )}\n </span>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n disabled={position <= 1}\n aria-disabled={saving || undefined}\n aria-describedby={positionId}\n aria-label={t(\n 'table.move_column_up',\n { column: column.label },\n `Move ${column.label} up`,\n )}\n onClick={(event) => move(column.name, -1, event.currentTarget)}\n >\n <ChevronUpIcon />\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n disabled={position >= count}\n aria-disabled={saving || undefined}\n aria-describedby={positionId}\n aria-label={t(\n 'table.move_column_down',\n { column: column.label },\n `Move ${column.label} down`,\n )}\n onClick={(event) => move(column.name, 1, event.currentTarget)}\n >\n <ChevronDownIcon />\n </Button>\n </span>\n )}\n </li>\n )\n })}\n </ul>\n )\n\n const body: ReactNode = (\n <div className=\"flex flex-col gap-1\">\n {inHeader && resetButton && <div className=\"flex justify-end\">{resetButton}</div>}\n {list}\n {reorderable && (\n <div\n role=\"status\"\n aria-live=\"polite\"\n aria-atomic=\"true\"\n className=\"sr-only\"\n data-slot=\"column-manager-announcement\"\n >\n {announcement}\n </div>\n )}\n {((!inHeader && resetButton) || applyView) && (\n <div className=\"mt-1 flex items-center justify-end gap-2\">\n {!inHeader && resetButton}\n {applyView && (\n <TableTriggerButton\n view={applyView}\n data-slot=\"column-manager-apply\"\n disabled={\n !orderChanged && (!draft || !columnDraftChanged(table.visibleColumns, draft))\n }\n onClick={apply}\n />\n )}\n </div>\n )}\n </div>\n )\n\n const onOpenChange = (next: boolean) => {\n // Closing without \"Apply\" drops the draft.\n if (!next) {\n setDraft(null)\n if (deferred) setOrderDraft(null)\n setAnnouncement('')\n }\n setOpen(next)\n }\n\n const triggerButton = (\n <TableTriggerButton\n view={trigger}\n defaultIcon={<Icon name=\"alfakit::tables.actions.column-manager\" fallback={Columns3Icon} />}\n aria-label={trigger.showLabel ? undefined : trigger.label}\n />\n )\n\n if (table.columnManagerLayout === 'modal') {\n // `columnManagerTriggerAction()` may set `slideOver()`, `modalWidth()` and the heading.\n const modal = table.triggerActions?.columnManager?.modal\n const heading = modal?.heading ?? t('table.columns', {}, 'Columns')\n const description = modal?.description ?? table.pluralModelLabel\n const widthClass = modal?.width ? FILTERS_MODAL_WIDTH_CLASSES[modal.width] : undefined\n\n if (modal?.slideOver) {\n return (\n <Sheet open={open} onOpenChange={onOpenChange}>\n <SheetTrigger asChild>{triggerButton}</SheetTrigger>\n <SheetContent\n side={slideOverSide(modal.slideOverPosition, direction)}\n className={cn('flex w-full flex-col gap-0 p-0', widthClass ?? 'sm:max-w-md')}\n data-slot=\"column-manager\"\n data-slide-over=\"\"\n >\n <SheetHeader className=\"border-b\">\n <SheetTitle>{heading}</SheetTitle>\n <SheetDescription className={modal.description ? undefined : 'sr-only'}>\n {description}\n </SheetDescription>\n </SheetHeader>\n <div className=\"flex-1 overflow-y-auto p-4\">{body}</div>\n </SheetContent>\n </Sheet>\n )\n }\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogTrigger asChild>{triggerButton}</DialogTrigger>\n <DialogContent className={widthClass ?? 'sm:max-w-lg'} data-slot=\"column-manager\">\n <DialogHeader>\n <DialogTitle>{heading}</DialogTitle>\n <DialogDescription className={modal?.description ? undefined : 'sr-only'}>\n {description}\n </DialogDescription>\n </DialogHeader>\n <div className=\"max-h-[60vh] overflow-y-auto\">{body}</div>\n </DialogContent>\n </Dialog>\n )\n }\n\n return (\n <Popover open={open} onOpenChange={onOpenChange}>\n <PopoverTrigger asChild>{triggerButton}</PopoverTrigger>\n <PopoverContent\n align=\"end\"\n className={cn('p-2', table.columnManagerColumns ? 'w-auto min-w-64' : 'w-64')}\n data-slot=\"column-manager\"\n >\n {body}\n </PopoverContent>\n </Popover>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"column-manager.js","names":[],"sources":["../../../src/components/table/column-manager.tsx"],"sourcesContent":["import type { TableSchema } from '@alfakit/core'\nimport {\n columnDraftChanged,\n columnManagerPosition,\n columnOrderChanged,\n defaultVisibleColumns,\n FILTERS_MODAL_WIDTH_CLASSES,\n gridColumnsClasses,\n keepMoveButtonFocus,\n moveColumnInManager,\n moveColumnTo,\n orderColumnsBy,\n saveColumnOrder,\n slideOverSide,\n toggleVisibleColumn,\n triggerButtonView,\n visitTable,\n} from '@alfakit/core'\nimport { ChevronDownIcon, ChevronUpIcon, Columns3Icon, GripVerticalIcon } from 'lucide-react'\nimport { useId, useState, type ReactNode } from 'react'\nimport { useDirection, usePanel, useT } from '../../context'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport { showToast } from '../notifications/flash-toasts'\nimport { Button } from '../ui/button'\nimport { Checkbox } from '../ui/checkbox'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from '../ui/dialog'\nimport { Popover, PopoverContent, PopoverTrigger } from '../ui/popover'\nimport {\n Sheet,\n SheetContent,\n SheetDescription,\n SheetHeader,\n SheetTitle,\n SheetTrigger,\n} from '../ui/sheet'\nimport { TableTriggerButton } from './trigger-button'\n\n/**\n * The column manager: show / hide toggleable columns (kept in the query string) and,\n * with `reorderableColumns()`, move columns (stored per user on the server) by dragging a\n * row onto another or with the move up / down buttons (the keyboard path).\n *\n * `deferColumnManager()` keeps toggles in a draft until \"Apply\"; `columnManagerLayout()`\n * opens it in a dialog; `columnManagerColumns()` lays the list out in a grid.\n */\nexport function ColumnManager({\n table,\n token,\n component,\n}: {\n table: TableSchema\n token: string\n component: string\n}) {\n const t = useT()\n const panel = usePanel()\n const direction = useDirection()\n const [open, setOpen] = useState(false)\n const [saving, setSaving] = useState(false)\n const [dragging, setDragging] = useState<string | null>(null)\n const [dropTarget, setDropTarget] = useState<string | null>(null)\n // Toggles of a deferred column manager wait here until \"Apply\".\n const [draft, setDraft] = useState<string[] | null>(null)\n // A moved column order: the draft of a deferred column manager, or shown at once\n // while it is saved.\n // It belongs to the columns it was made from: the server's next order replaces the\n // one shown while saving.\n const [orderState, setOrderState] = useState<{\n order: string[]\n columns: TableSchema['columns']\n } | null>(null)\n // Screen-reader announcement of the last move.\n const [announcement, setAnnouncement] = useState('')\n const idBase = useId()\n const reorderable = Boolean(table.reorderableColumns && panel.endpoints.tableColumns)\n const toggleable = Boolean(table.toggleableColumns)\n const deferred = Boolean(table.deferColumnManager)\n const orderDraft =\n orderState && (deferred || orderState.columns === table.columns) ? orderState.order : null\n const setOrderDraft = (order: string[] | null) =>\n setOrderState(order ? { order, columns: table.columns } : null)\n const appliedNames = table.columns.map((column) => column.name)\n const names = orderDraft ?? appliedNames\n const columns = orderColumnsBy(\n reorderable ? table.columns : table.columns.filter((column) => column.toggleable),\n orderDraft,\n )\n const visible = draft ?? table.visibleColumns\n\n if (!toggleable && !reorderable) return null\n\n const trigger = triggerButtonView(table, 'columnManager', {\n label: t('table.columns', {}, 'Columns'),\n showLabel: false,\n })\n\n if (!trigger) return null\n\n const toggle = (name: string) => {\n const next = toggleVisibleColumn(visible, name)\n\n if (deferred) {\n setDraft(next)\n } else {\n visitTable(table.identifier, { columns: next }, ['page'])\n }\n }\n\n const save = async (order: string[]): Promise<boolean> => {\n if (!panel.endpoints.tableColumns) return false\n\n setSaving(true)\n\n try {\n await saveColumnOrder(panel.endpoints.tableColumns, token, component, order)\n\n return true\n } catch (error) {\n showToast({\n id: 'alfakit-column-order-failed',\n title: t('table.column_order_failed', {}, \"Couldn't save the column order\"),\n body: error instanceof Error ? error.message : String(error),\n status: 'danger',\n format: 'alfakit',\n })\n\n return false\n } finally {\n setSaving(false)\n }\n }\n\n const announce = (name: string, order: string[]) => {\n const { position, count, group } = columnManagerPosition(order, name, table.columnGroups)\n const label = table.columns.find((column) => column.name === name)?.label ?? name\n const replace = { column: label, position, count, group: group ?? '' }\n\n setAnnouncement(\n group\n ? deferred\n ? t(\n 'table.column_manager.reordered_in_group_deferred',\n replace,\n `${label} moved to position ${position} of ${count} in ${group}. Apply columns to save your changes.`,\n )\n : t(\n 'table.column_manager.reordered_in_group',\n replace,\n `${label} moved to position ${position} of ${count} in ${group}.`,\n )\n : deferred\n ? t(\n 'table.column_manager.reordered_deferred',\n replace,\n `${label} moved to position ${position} of ${count}. Apply columns to save your changes.`,\n )\n : t(\n 'table.column_manager.reordered',\n replace,\n `${label} moved to position ${position} of ${count}.`,\n ),\n )\n }\n\n // A new order: kept as a draft until \"Apply\" (`deferColumnManager()`), else saved now.\n const reorder = (name: string, order: string[]) => {\n if (saving || !columnOrderChanged(names, order)) return\n\n setOrderDraft(order)\n setAnnouncement('')\n\n if (deferred) {\n announce(name, order)\n\n return\n }\n\n void save(order).then((saved) => (saved ? announce(name, order) : setOrderDraft(null)))\n }\n\n const move = (name: string, offset: -1 | 1, button: HTMLElement) => {\n keepMoveButtonFocus(button)\n reorder(name, moveColumnInManager(names, name, offset, table.columnGroups))\n }\n\n const orderChanged = Boolean(orderDraft && columnOrderChanged(appliedNames, orderDraft))\n\n // The order is saved before the visibility visit: both requests share the session, and a\n // visit running alongside the save would write the old order back when it finishes.\n const apply = async () => {\n const columns = draft && columnDraftChanged(table.visibleColumns, draft) ? draft : null\n\n setDraft(null)\n setOrderDraft(null)\n setAnnouncement('')\n setOpen(false)\n\n if (orderDraft && orderChanged) await save(orderDraft)\n\n if (columns) visitTable(table.identifier, { columns }, ['page'])\n }\n\n // Reset: the defined column order and, for toggleable columns, the default visibility.\n const reset = async () => {\n if (reorderable) {\n setOrderDraft(null)\n await save([])\n }\n\n if (toggleable) {\n setDraft(null)\n visitTable(table.identifier, { columns: defaultVisibleColumns(table) }, ['page'])\n }\n }\n\n const resetView = triggerButtonView(table, 'columnManagerReset', {\n label: toggleable\n ? t('table.reset_columns', {}, 'Reset')\n : t('table.reset_column_order', {}, 'Reset column order'),\n variant: 'ghost',\n })\n const applyView = deferred\n ? triggerButtonView(table, 'columnManagerApply', {\n label: t('table_filters.apply', {}, 'Apply'),\n variant: 'default',\n })\n : null\n const resetButton = resetView ? (\n <TableTriggerButton\n view={resetView}\n disabled={saving}\n data-slot=\"column-manager-reset\"\n className={cn(!applyView && 'w-full')}\n onClick={() => void reset()}\n />\n ) : null\n const inHeader = table.columnManagerResetActionPosition === 'header'\n\n const list = (\n <ul\n className={cn(\n table.columnManagerColumns\n ? ['grid gap-0.5', gridColumnsClasses(table.columnManagerColumns)]\n : 'flex flex-col gap-0.5',\n )}\n aria-label={t('table.columns', {}, 'Columns')}\n >\n {columns.map((column) => {\n const { position, count, group } = columnManagerPosition(\n names,\n column.name,\n table.columnGroups,\n )\n const positionId = `${idBase}-${column.name}-position`\n\n return (\n <li\n key={column.name}\n data-column={column.name}\n draggable={reorderable && !saving}\n onDragStart={(event) => {\n if (event.dataTransfer) event.dataTransfer.effectAllowed = 'move'\n setDragging(column.name)\n }}\n onDragOver={(event) => {\n if (dragging === null) return\n\n event.preventDefault()\n if (event.dataTransfer) event.dataTransfer.dropEffect = 'move'\n setDropTarget(column.name)\n }}\n onDragLeave={() => dropTarget === column.name && setDropTarget(null)}\n onDragEnd={() => {\n setDragging(null)\n setDropTarget(null)\n }}\n onDrop={(event) => {\n event.preventDefault()\n\n if (dragging !== null && dragging !== column.name) {\n reorder(dragging, moveColumnTo(names, dragging, column.name))\n }\n\n setDragging(null)\n setDropTarget(null)\n }}\n className={cn(\n 'flex items-center gap-2 rounded-md px-2 py-1 text-sm',\n reorderable && 'cursor-grab',\n dragging === column.name && 'opacity-50',\n dropTarget === column.name && dragging !== column.name && 'bg-muted',\n )}\n >\n {reorderable && (\n <GripVerticalIcon\n className=\"text-muted-foreground size-4 shrink-0\"\n aria-hidden=\"true\"\n />\n )}\n {column.toggleable ? (\n <label className=\"flex min-w-0 flex-1 items-center gap-2\">\n <Checkbox\n checked={visible.includes(column.name)}\n onCheckedChange={() => toggle(column.name)}\n />\n <span className=\"truncate\">{column.label}</span>\n </label>\n ) : (\n <span className=\"min-w-0 flex-1 truncate\">{column.label}</span>\n )}\n {reorderable && (\n <span className=\"flex shrink-0 items-center\">\n <span id={positionId} className=\"sr-only\" data-slot=\"column-manager-position\">\n {group\n ? t(\n 'table.column_manager.position_in_group',\n { position, count, group },\n `Position ${position} of ${count} in ${group}.`,\n )\n : t(\n 'table.column_manager.position',\n { position, count },\n `Position ${position} of ${count}.`,\n )}\n </span>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n disabled={position <= 1}\n aria-disabled={saving || undefined}\n aria-describedby={positionId}\n aria-label={t(\n 'table.move_column_up',\n { column: column.label },\n `Move ${column.label} up`,\n )}\n onClick={(event) => move(column.name, -1, event.currentTarget)}\n >\n <ChevronUpIcon />\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n disabled={position >= count}\n aria-disabled={saving || undefined}\n aria-describedby={positionId}\n aria-label={t(\n 'table.move_column_down',\n { column: column.label },\n `Move ${column.label} down`,\n )}\n onClick={(event) => move(column.name, 1, event.currentTarget)}\n >\n <ChevronDownIcon />\n </Button>\n </span>\n )}\n </li>\n )\n })}\n </ul>\n )\n\n const body: ReactNode = (\n <div className=\"flex flex-col gap-1\">\n {inHeader && resetButton && <div className=\"flex justify-end\">{resetButton}</div>}\n {list}\n {reorderable && (\n <div\n role=\"status\"\n aria-live=\"polite\"\n aria-atomic=\"true\"\n className=\"sr-only\"\n data-slot=\"column-manager-announcement\"\n >\n {announcement}\n </div>\n )}\n {((!inHeader && resetButton) || applyView) && (\n <div className=\"mt-1 flex items-center justify-end gap-2\">\n {!inHeader && resetButton}\n {applyView && (\n <TableTriggerButton\n view={applyView}\n data-slot=\"column-manager-apply\"\n disabled={\n !orderChanged && (!draft || !columnDraftChanged(table.visibleColumns, draft))\n }\n onClick={() => void apply()}\n />\n )}\n </div>\n )}\n </div>\n )\n\n const onOpenChange = (next: boolean) => {\n // Closing without \"Apply\" drops the draft.\n if (!next) {\n setDraft(null)\n if (deferred) setOrderDraft(null)\n setAnnouncement('')\n }\n setOpen(next)\n }\n\n const triggerButton = (\n <TableTriggerButton\n view={trigger}\n defaultIcon={<Icon name=\"alfakit::tables.actions.column-manager\" fallback={Columns3Icon} />}\n aria-label={trigger.showLabel ? undefined : trigger.label}\n />\n )\n\n if (table.columnManagerLayout === 'modal') {\n // `columnManagerTriggerAction()` may set `slideOver()`, `modalWidth()` and the heading.\n const modal = table.triggerActions?.columnManager?.modal\n const heading = modal?.heading ?? t('table.columns', {}, 'Columns')\n const description = modal?.description ?? table.pluralModelLabel\n const widthClass = modal?.width ? FILTERS_MODAL_WIDTH_CLASSES[modal.width] : undefined\n\n if (modal?.slideOver) {\n return (\n <Sheet open={open} onOpenChange={onOpenChange}>\n <SheetTrigger asChild>{triggerButton}</SheetTrigger>\n <SheetContent\n side={slideOverSide(modal.slideOverPosition, direction)}\n className={cn('flex w-full flex-col gap-0 p-0', widthClass ?? 'sm:max-w-md')}\n data-slot=\"column-manager\"\n data-slide-over=\"\"\n >\n <SheetHeader className=\"border-b\">\n <SheetTitle>{heading}</SheetTitle>\n <SheetDescription className={modal.description ? undefined : 'sr-only'}>\n {description}\n </SheetDescription>\n </SheetHeader>\n <div className=\"flex-1 overflow-y-auto p-4\">{body}</div>\n </SheetContent>\n </Sheet>\n )\n }\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogTrigger asChild>{triggerButton}</DialogTrigger>\n <DialogContent className={widthClass ?? 'sm:max-w-lg'} data-slot=\"column-manager\">\n <DialogHeader>\n <DialogTitle>{heading}</DialogTitle>\n <DialogDescription className={modal?.description ? undefined : 'sr-only'}>\n {description}\n </DialogDescription>\n </DialogHeader>\n <div className=\"max-h-[60vh] overflow-y-auto\">{body}</div>\n </DialogContent>\n </Dialog>\n )\n }\n\n return (\n <Popover open={open} onOpenChange={onOpenChange}>\n <PopoverTrigger asChild>{triggerButton}</PopoverTrigger>\n <PopoverContent\n align=\"end\"\n className={cn('p-2', table.columnManagerColumns ? 'w-auto min-w-64' : 'w-64')}\n data-slot=\"column-manager\"\n >\n {body}\n </PopoverContent>\n </Popover>\n )\n}\n"],"mappings":"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"}
@@ -183,6 +183,7 @@ function ContentLayoutSort({ table, columns }) {
183
183
  const sortable = columns.filter((column) => column.sortable);
184
184
  if (sortable.length === 0) return null;
185
185
  const direction = table.sort?.direction ?? "asc";
186
+ const selected = sortable.some((column) => column.name === table.sort?.column) ? table.sort?.column ?? "" : "";
186
187
  return /* @__PURE__ */ jsxs("div", {
187
188
  className: "flex items-center gap-1",
188
189
  children: [/* @__PURE__ */ jsxs("label", {
@@ -191,7 +192,7 @@ function ContentLayoutSort({ table, columns }) {
191
192
  className: "sr-only",
192
193
  children: t("table.sort_by", {}, "Sort by")
193
194
  }), /* @__PURE__ */ jsxs("select", {
194
- value: table.sort?.column ?? "",
195
+ value: selected,
195
196
  onChange: (event) => visitTable(table.identifier, {
196
197
  sort: event.target.value || null,
197
198
  direction: event.target.value ? direction : null
@@ -1 +1 @@
1
- {"version":3,"file":"content-layout.js","names":[],"sources":["../../../src/components/table/content-layout.tsx"],"sourcesContent":["import type {\n ActionContext,\n ColumnLayoutNode,\n ColumnSchema,\n TableRecordSchema,\n TableSchema,\n TableSelection,\n} from '@alfakit/core'\nimport {\n VIRTUAL_ESTIMATES,\n columnSpanClasses,\n columnStartClasses,\n columnVisibilityClasses,\n gridColumnsClasses,\n layoutNodeGrows,\n layoutVisibilityClasses,\n primaryColumnName,\n recordActionsAtStart,\n splitClasses,\n stackClasses,\n virtualizeOptions,\n visitTable,\n} from '@alfakit/core'\nimport { ArrowDownIcon, ArrowUpIcon, ChevronDownIcon } from 'lucide-react'\nimport { useId, useState, type ReactNode } from 'react'\nimport { useT } from '../../context'\nimport { useVirtualList } from '../../hooks/use-virtual-list'\nimport { extraProps } from '../../lib/attributes'\nimport { cn } from '../../lib/utils'\nimport { ActionList } from '../actions/action-list'\nimport { Button } from '../ui/button'\nimport { Checkbox } from '../ui/checkbox'\nimport { RecordCell } from './record-cell'\n\nexport interface ContentLayoutProps {\n table: TableSchema\n records: TableRecordSchema[]\n columns: ColumnSchema[]\n token: string\n component: string\n context: ActionContext\n selectable: boolean\n selection: TableSelection\n onRecordClick: (record: TableRecordSchema) => void\n}\n\nfunction hasCollapsiblePanel(nodes: ColumnLayoutNode[]): boolean {\n return nodes.some(\n (node) =>\n node.type !== 'Column' &&\n ((node.type === 'Panel' && Boolean(node.collapsible)) || hasCollapsiblePanel(node.schema)),\n )\n}\n\n/**\n * Records arranged by a content layout (`Split`, `Stack`, `Panel`, `Grid`) instead of\n * a row of cells, optionally as cards in a `contentGrid()`. Long pages render only the\n * records in view (plus a few around them), by whole rows of the card grid; the list\n * keeps `aria-setsize` / `aria-posinset` so assistive technology knows the real positions.\n */\nexport function ContentLayout(props: ContentLayoutProps) {\n const { table, records } = props\n const grid = table.contentGrid\n const { range, indexes, style, attach, item } = useVirtualList(\n records.length,\n virtualizeOptions(table.virtualize, VIRTUAL_ESTIMATES.item, grid ? 16 : 0, grid ? 'auto' : 1),\n )\n\n return (\n <div\n data-slot=\"table-content\"\n role={range.active ? 'list' : undefined}\n ref={attach}\n style={style}\n className={cn(grid ? cn('grid gap-4 p-4', gridColumnsClasses(grid)) : 'divide-y')}\n >\n {indexes.map((index) => {\n const record = records[index] as TableRecordSchema\n\n return (\n <ContentRecord\n key={String(record.key)}\n {...props}\n record={record}\n card={Boolean(grid)}\n index={index}\n position={range.active ? { size: records.length, item } : undefined}\n />\n )\n })}\n </div>\n )\n}\n\nfunction ContentRecord({\n table,\n record,\n columns,\n token,\n component,\n context,\n selectable,\n selection,\n onRecordClick,\n card,\n index,\n position,\n}: ContentLayoutProps & {\n record: TableRecordSchema\n card: boolean\n index: number\n /** Set while the list is windowed: the real list size and the item ref callback. */\n position?: { size: number; item: (element: HTMLElement | null) => void | (() => void) }\n}) {\n const t = useT()\n const panelId = useId()\n const layout = table.contentLayout ?? []\n const collapsible = hasCollapsiblePanel(layout)\n const startsCollapsed = !layout.some(\n (node) => node.type === 'Panel' && node.collapsible && !node.collapsed,\n )\n const [open, setOpen] = useState(!startsCollapsed)\n const clickable = Boolean(record.url || table.recordAction)\n const primary = primaryColumnName(columns)\n const visible = new Set(columns.map((column) => column.name))\n const selected = selection.isSelected(record.key)\n\n const renderNode = (node: ColumnLayoutNode, index: number, inSplit = false): ReactNode => {\n const grows = inSplit && layoutNodeGrows(node, columns)\n const sizing = inSplit ? (grows ? 'min-w-0 flex-1' : 'shrink-0') : undefined\n // `columnSpan()` / `columnStart()` of a column or layout inside a `Grid`.\n const span = cn(columnSpanClasses(node.columnSpan), columnStartClasses(node.columnStart))\n\n if (node.type === 'Column') {\n const column = columns.find((item) => item.name === node.name)\n\n if (!column || !visible.has(column.name)) return null\n\n return (\n <div\n key={`column:${column.name}`}\n data-column={column.name}\n className={cn(sizing, span, columnVisibilityClasses(column, 'block'))}\n >\n <RecordCell\n column={column}\n record={record}\n token={token}\n component={component}\n context={context}\n clickable={clickable}\n primary={column.name === primary}\n hasRecordAction={Boolean(table.recordAction)}\n onRecordClick={onRecordClick}\n />\n </div>\n )\n }\n\n const visibility = layoutVisibilityClasses(node)\n const key = `${node.type}:${index}`\n\n switch (node.type) {\n case 'Split':\n return (\n <div\n key={key}\n data-layout=\"split\"\n {...extraProps(node.extraAttributes, cn(splitClasses(node), visibility, sizing, span))}\n >\n {node.schema.map((child, childIndex) => renderNode(child, childIndex, true))}\n </div>\n )\n case 'Stack':\n return (\n <div\n key={key}\n data-layout=\"stack\"\n {...extraProps(node.extraAttributes, cn(stackClasses(node), visibility, sizing, span))}\n >\n {node.schema.map((child, childIndex) => renderNode(child, childIndex))}\n </div>\n )\n case 'Grid':\n return (\n <div\n key={key}\n data-layout=\"grid\"\n {...extraProps(\n node.extraAttributes,\n cn('grid gap-2', gridColumnsClasses(node.columns), visibility, sizing, span),\n )}\n >\n {node.schema.map((child, childIndex) => renderNode(child, childIndex))}\n </div>\n )\n case 'Panel':\n if (node.collapsible && !open) return null\n\n return (\n <div\n key={key}\n data-layout=\"panel\"\n {...extraProps(\n node.extraAttributes,\n cn('bg-muted/50 flex flex-col gap-2 rounded-lg p-3', visibility, sizing, span),\n )}\n >\n {node.schema.map((child, childIndex) => renderNode(child, childIndex))}\n </div>\n )\n default:\n return null\n }\n }\n\n // Collapsible panels at the top level go under the record's main row.\n const main = layout.filter((node) => !(node.type === 'Panel' && node.collapsible))\n const details = layout.filter((node) => node.type === 'Panel' && node.collapsible)\n const atStart = recordActionsAtStart(table.recordActionsPosition)\n const actions = record.actions?.length ? (\n <div className=\"shrink-0\" onClick={(event) => event.stopPropagation()}>\n <ActionList\n actions={record.actions}\n context={{ ...context, record: record.key }}\n size=\"sm\"\n align=\"end\"\n className=\"flex-nowrap\"\n />\n </div>\n ) : null\n\n return (\n <div\n data-slot=\"table-record\"\n data-state={selected ? 'selected' : undefined}\n data-index={index}\n ref={position?.item}\n role={position ? 'listitem' : undefined}\n aria-setsize={position?.size}\n aria-posinset={position ? index + 1 : undefined}\n className={cn(\n 'flex flex-col gap-3 p-4',\n card && 'bg-card rounded-lg border shadow-xs',\n clickable && 'hover:bg-muted/40 cursor-pointer',\n selected && 'bg-muted/60',\n record.classes,\n )}\n onClick={() => clickable && onRecordClick(record)}\n >\n <div className=\"flex items-start gap-3\">\n {atStart && table.recordActionsPosition === 'before-cells' && actions}\n {selectable && (\n <div className=\"pt-0.5\" onClick={(event) => event.stopPropagation()}>\n {record.selectable !== false && (\n <Checkbox\n checked={selected}\n onCheckedChange={(checked) => selection.toggle(record.key, checked === true)}\n aria-label={t('table.select_row', {}, 'Select row')}\n />\n )}\n </div>\n )}\n {atStart && table.recordActionsPosition === 'before-columns' && actions}\n <div className=\"flex min-w-0 flex-1 flex-col gap-3\">\n {main.map((node, index) => renderNode(node, index))}\n </div>\n {!atStart && actions}\n {collapsible && (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-expanded={open}\n aria-controls={open ? panelId : undefined}\n aria-label={\n open\n ? t('table.hide_details', {}, 'Hide details')\n : t('table.show_details', {}, 'Show details')\n }\n onClick={(event) => {\n event.stopPropagation()\n setOpen(!open)\n }}\n >\n <ChevronDownIcon className={cn('transition-transform', open && 'rotate-180')} />\n </Button>\n )}\n </div>\n {open && details.length > 0 && (\n <div id={panelId} className=\"flex flex-col gap-3\">\n {details.map((node, index) => renderNode(node, main.length + index))}\n </div>\n )}\n </div>\n )\n}\n\n/**\n * Sorting for content layouts, which have no column headers: a select of the sortable\n * columns and a direction toggle.\n */\nexport function ContentLayoutSort({\n table,\n columns,\n}: {\n table: TableSchema\n columns: ColumnSchema[]\n}) {\n const t = useT()\n const sortable = columns.filter((column) => column.sortable)\n\n if (sortable.length === 0) return null\n\n const direction = table.sort?.direction ?? 'asc'\n\n return (\n <div className=\"flex items-center gap-1\">\n <label className=\"flex items-center gap-2 text-sm\">\n <span className=\"sr-only\">{t('table.sort_by', {}, 'Sort by')}</span>\n <select\n value={table.sort?.column ?? ''}\n onChange={(event) =>\n visitTable(\n table.identifier,\n {\n sort: event.target.value || null,\n direction: event.target.value ? direction : null,\n },\n ['page'],\n )\n }\n className=\"border-input h-8 rounded-md border bg-transparent px-2 text-sm\"\n >\n <option value=\"\">\n {table.defaultSortOptionLabel ?? t('table.sort_by', {}, 'Sort by')}\n </option>\n {sortable.map((column) => (\n <option key={column.name} value={column.name}>\n {column.label}\n </option>\n ))}\n </select>\n </label>\n {table.sort && (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"icon-sm\"\n aria-label={\n direction === 'asc'\n ? t('table.sort_ascending', {}, 'Ascending')\n : t('table.sort_descending', {}, 'Descending')\n }\n onClick={() =>\n visitTable(\n table.identifier,\n { sort: table.sort?.column ?? null, direction: direction === 'asc' ? 'desc' : 'asc' },\n ['page'],\n )\n }\n >\n {direction === 'asc' ? <ArrowUpIcon /> : <ArrowDownIcon />}\n </Button>\n )}\n </div>\n )\n}\n"],"mappings":";;;;;;;;;;;;;AA8CA,SAAS,oBAAoB,OAAoC;CAC/D,OAAO,MAAM,MACV,SACC,KAAK,SAAS,aACZ,KAAK,SAAS,WAAW,QAAQ,KAAK,WAAW,KAAM,oBAAoB,KAAK,MAAM,EAC5F;AACF;;;;;;;AAQA,SAAgB,cAAc,OAA2B;CACvD,MAAM,EAAE,OAAO,YAAY;CAC3B,MAAM,OAAO,MAAM;CACnB,MAAM,EAAE,OAAO,SAAS,OAAO,QAAQ,SAAS,eAC9C,QAAQ,QACR,kBAAkB,MAAM,YAAY,kBAAkB,MAAM,OAAO,KAAK,GAAG,OAAO,SAAS,CAAC,CAC9F;CAEA,OACE,oBAAC,OAAD;EACE,aAAU;EACV,MAAM,MAAM,SAAS,SAAS,KAAA;EAC9B,KAAK;EACE;EACP,WAAW,GAAG,OAAO,GAAG,kBAAkB,mBAAmB,IAAI,CAAC,IAAI,UAAU;EAE/E,UAAA,QAAQ,KAAK,UAAU;GACtB,MAAM,SAAS,QAAQ;GAEvB,OACE,oBAAC,eAAD;IAEE,GAAI;IACI;IACR,MAAM,QAAQ,IAAI;IACX;IACP,UAAU,MAAM,SAAS;KAAE,MAAM,QAAQ;KAAQ;IAAK,IAAI,KAAA;GAC3D,GANM,OAAO,OAAO,GAAG,CAMvB;EAEL,CAAC;CACE,CAAA;AAET;AAEA,SAAS,cAAc,EACrB,OACA,QACA,SACA,OACA,WACA,SACA,YACA,WACA,eACA,MACA,OACA,YAOC;CACD,MAAM,IAAI,KAAK;CACf,MAAM,UAAU,MAAM;CACtB,MAAM,SAAS,MAAM,iBAAiB,CAAC;CACvC,MAAM,cAAc,oBAAoB,MAAM;CAC9C,MAAM,kBAAkB,CAAC,OAAO,MAC7B,SAAS,KAAK,SAAS,WAAW,KAAK,eAAe,CAAC,KAAK,SAC/D;CACA,MAAM,CAAC,MAAM,WAAW,SAAS,CAAC,eAAe;CACjD,MAAM,YAAY,QAAQ,OAAO,OAAO,MAAM,YAAY;CAC1D,MAAM,UAAU,kBAAkB,OAAO;CACzC,MAAM,UAAU,IAAI,IAAI,QAAQ,KAAK,WAAW,OAAO,IAAI,CAAC;CAC5D,MAAM,WAAW,UAAU,WAAW,OAAO,GAAG;CAEhD,MAAM,cAAc,MAAwB,OAAe,UAAU,UAAqB;EACxF,MAAM,QAAQ,WAAW,gBAAgB,MAAM,OAAO;EACtD,MAAM,SAAS,UAAW,QAAQ,mBAAmB,aAAc,KAAA;EAEnE,MAAM,OAAO,GAAG,kBAAkB,KAAK,UAAU,GAAG,mBAAmB,KAAK,WAAW,CAAC;EAExF,IAAI,KAAK,SAAS,UAAU;GAC1B,MAAM,SAAS,QAAQ,MAAM,SAAS,KAAK,SAAS,KAAK,IAAI;GAE7D,IAAI,CAAC,UAAU,CAAC,QAAQ,IAAI,OAAO,IAAI,GAAG,OAAO;GAEjD,OACE,oBAAC,OAAD;IAEE,eAAa,OAAO;IACpB,WAAW,GAAG,QAAQ,MAAM,wBAAwB,QAAQ,OAAO,CAAC;IAEpE,UAAA,oBAAC,YAAD;KACU;KACA;KACD;KACI;KACF;KACE;KACX,SAAS,OAAO,SAAS;KACzB,iBAAiB,QAAQ,MAAM,YAAY;KAC5B;IAChB,CAAA;GACE,GAfE,UAAU,OAAO,MAenB;EAET;EAEA,MAAM,aAAa,wBAAwB,IAAI;EAC/C,MAAM,MAAM,GAAG,KAAK,KAAK,GAAG;EAE5B,QAAQ,KAAK,MAAb;GACE,KAAK,SACH,OACE,oBAAC,OAAD;IAEE,eAAY;IACZ,GAAI,WAAW,KAAK,iBAAiB,GAAG,aAAa,IAAI,GAAG,YAAY,QAAQ,IAAI,CAAC;IAEpF,UAAA,KAAK,OAAO,KAAK,OAAO,eAAe,WAAW,OAAO,YAAY,IAAI,CAAC;GACxE,GALE,GAKF;GAET,KAAK,SACH,OACE,oBAAC,OAAD;IAEE,eAAY;IACZ,GAAI,WAAW,KAAK,iBAAiB,GAAG,aAAa,IAAI,GAAG,YAAY,QAAQ,IAAI,CAAC;IAEpF,UAAA,KAAK,OAAO,KAAK,OAAO,eAAe,WAAW,OAAO,UAAU,CAAC;GAClE,GALE,GAKF;GAET,KAAK,QACH,OACE,oBAAC,OAAD;IAEE,eAAY;IACZ,GAAI,WACF,KAAK,iBACL,GAAG,cAAc,mBAAmB,KAAK,OAAO,GAAG,YAAY,QAAQ,IAAI,CAC7E;IAEC,UAAA,KAAK,OAAO,KAAK,OAAO,eAAe,WAAW,OAAO,UAAU,CAAC;GAClE,GARE,GAQF;GAET,KAAK;IACH,IAAI,KAAK,eAAe,CAAC,MAAM,OAAO;IAEtC,OACE,oBAAC,OAAD;KAEE,eAAY;KACZ,GAAI,WACF,KAAK,iBACL,GAAG,kDAAkD,YAAY,QAAQ,IAAI,CAC/E;KAEC,UAAA,KAAK,OAAO,KAAK,OAAO,eAAe,WAAW,OAAO,UAAU,CAAC;IAClE,GARE,GAQF;GAET,SACE,OAAO;EACX;CACF;CAGA,MAAM,OAAO,OAAO,QAAQ,SAAS,EAAE,KAAK,SAAS,WAAW,KAAK,YAAY;CACjF,MAAM,UAAU,OAAO,QAAQ,SAAS,KAAK,SAAS,WAAW,KAAK,WAAW;CACjF,MAAM,UAAU,qBAAqB,MAAM,qBAAqB;CAChE,MAAM,UAAU,OAAO,SAAS,SAC9B,oBAAC,OAAD;EAAK,WAAU;EAAW,UAAU,UAAU,MAAM,gBAAgB;EAClE,UAAA,oBAAC,YAAD;GACE,SAAS,OAAO;GAChB,SAAS;IAAE,GAAG;IAAS,QAAQ,OAAO;GAAI;GAC1C,MAAK;GACL,OAAM;GACN,WAAU;EACX,CAAA;CACE,CAAA,IACH;CAEJ,OACE,qBAAC,OAAD;EACE,aAAU;EACV,cAAY,WAAW,aAAa,KAAA;EACpC,cAAY;EACZ,KAAK,UAAU;EACf,MAAM,WAAW,aAAa,KAAA;EAC9B,gBAAc,UAAU;EACxB,iBAAe,WAAW,QAAQ,IAAI,KAAA;EACtC,WAAW,GACT,2BACA,QAAQ,uCACR,aAAa,oCACb,YAAY,eACZ,OAAO,OACT;EACA,eAAe,aAAa,cAAc,MAAM;EAflD,UAAA,CAiBE,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA;IACG,WAAW,MAAM,0BAA0B,kBAAkB;IAC7D,cACC,oBAAC,OAAD;KAAK,WAAU;KAAS,UAAU,UAAU,MAAM,gBAAgB;KAC/D,UAAA,OAAO,eAAe,SACrB,oBAAC,UAAD;MACE,SAAS;MACT,kBAAkB,YAAY,UAAU,OAAO,OAAO,KAAK,YAAY,IAAI;MAC3E,cAAY,EAAE,oBAAoB,CAAC,GAAG,YAAY;KACnD,CAAA;IAEA,CAAA;IAEN,WAAW,MAAM,0BAA0B,oBAAoB;IAChE,oBAAC,OAAD;KAAK,WAAU;KACZ,UAAA,KAAK,KAAK,MAAM,UAAU,WAAW,MAAM,KAAK,CAAC;IAC/C,CAAA;IACJ,CAAC,WAAW;IACZ,eACC,oBAAC,QAAD;KACE,MAAK;KACL,SAAQ;KACR,MAAK;KACL,iBAAe;KACf,iBAAe,OAAO,UAAU,KAAA;KAChC,cACE,OACI,EAAE,sBAAsB,CAAC,GAAG,cAAc,IAC1C,EAAE,sBAAsB,CAAC,GAAG,cAAc;KAEhD,UAAU,UAAU;MAClB,MAAM,gBAAgB;MACtB,QAAQ,CAAC,IAAI;KACf;KAEA,UAAA,oBAAC,iBAAD,EAAiB,WAAW,GAAG,wBAAwB,QAAQ,YAAY,EAAI,CAAA;IACzE,CAAA;GAEP;EACJ,CAAA,GAAA,QAAQ,QAAQ,SAAS,KACxB,oBAAC,OAAD;GAAK,IAAI;GAAS,WAAU;GACzB,UAAA,QAAQ,KAAK,MAAM,UAAU,WAAW,MAAM,KAAK,SAAS,KAAK,CAAC;EAChE,CAAA,CAEJ;;AAET;;;;;AAMA,SAAgB,kBAAkB,EAChC,OACA,WAIC;CACD,MAAM,IAAI,KAAK;CACf,MAAM,WAAW,QAAQ,QAAQ,WAAW,OAAO,QAAQ;CAE3D,IAAI,SAAS,WAAW,GAAG,OAAO;CAElC,MAAM,YAAY,MAAM,MAAM,aAAa;CAE3C,OACE,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA,CACE,qBAAC,SAAD;GAAO,WAAU;GAAjB,UAAA,CACE,oBAAC,QAAD;IAAM,WAAU;IAAW,UAAA,EAAE,iBAAiB,CAAC,GAAG,SAAS;GAAQ,CAAA,GACnE,qBAAC,UAAD;IACE,OAAO,MAAM,MAAM,UAAU;IAC7B,WAAW,UACT,WACE,MAAM,YACN;KACE,MAAM,MAAM,OAAO,SAAS;KAC5B,WAAW,MAAM,OAAO,QAAQ,YAAY;IAC9C,GACA,CAAC,MAAM,CACT;IAEF,WAAU;IAZZ,UAAA,CAcE,oBAAC,UAAD;KAAQ,OAAM;KACX,UAAA,MAAM,0BAA0B,EAAE,iBAAiB,CAAC,GAAG,SAAS;IAC3D,CAAA,GACP,SAAS,KAAK,WACb,oBAAC,UAAD;KAA0B,OAAO,OAAO;KACrC,UAAA,OAAO;IACF,GAFK,OAAO,IAEZ,CACT,CACK;GACH,CAAA,CAAA;EACN,CAAA,GAAA,MAAM,QACL,oBAAC,QAAD;GACE,MAAK;GACL,SAAQ;GACR,MAAK;GACL,cACE,cAAc,QACV,EAAE,wBAAwB,CAAC,GAAG,WAAW,IACzC,EAAE,yBAAyB,CAAC,GAAG,YAAY;GAEjD,eACE,WACE,MAAM,YACN;IAAE,MAAM,MAAM,MAAM,UAAU;IAAM,WAAW,cAAc,QAAQ,SAAS;GAAM,GACpF,CAAC,MAAM,CACT;GAGD,UAAA,cAAc,QAAQ,oBAAC,aAAD,CAAc,CAAA,IAAI,oBAAC,eAAD,CAAgB,CAAA;EACnD,CAAA,CAEP;;AAET"}
1
+ {"version":3,"file":"content-layout.js","names":[],"sources":["../../../src/components/table/content-layout.tsx"],"sourcesContent":["import type {\n ActionContext,\n ColumnLayoutNode,\n ColumnSchema,\n TableRecordSchema,\n TableSchema,\n TableSelection,\n} from '@alfakit/core'\nimport {\n VIRTUAL_ESTIMATES,\n columnSpanClasses,\n columnStartClasses,\n columnVisibilityClasses,\n gridColumnsClasses,\n layoutNodeGrows,\n layoutVisibilityClasses,\n primaryColumnName,\n recordActionsAtStart,\n splitClasses,\n stackClasses,\n virtualizeOptions,\n visitTable,\n} from '@alfakit/core'\nimport { ArrowDownIcon, ArrowUpIcon, ChevronDownIcon } from 'lucide-react'\nimport { useId, useState, type ReactNode } from 'react'\nimport { useT } from '../../context'\nimport { useVirtualList } from '../../hooks/use-virtual-list'\nimport { extraProps } from '../../lib/attributes'\nimport { cn } from '../../lib/utils'\nimport { ActionList } from '../actions/action-list'\nimport { Button } from '../ui/button'\nimport { Checkbox } from '../ui/checkbox'\nimport { RecordCell } from './record-cell'\n\nexport interface ContentLayoutProps {\n table: TableSchema\n records: TableRecordSchema[]\n columns: ColumnSchema[]\n token: string\n component: string\n context: ActionContext\n selectable: boolean\n selection: TableSelection\n onRecordClick: (record: TableRecordSchema) => void\n}\n\nfunction hasCollapsiblePanel(nodes: ColumnLayoutNode[]): boolean {\n return nodes.some(\n (node) =>\n node.type !== 'Column' &&\n ((node.type === 'Panel' && Boolean(node.collapsible)) || hasCollapsiblePanel(node.schema)),\n )\n}\n\n/**\n * Records arranged by a content layout (`Split`, `Stack`, `Panel`, `Grid`) instead of\n * a row of cells, optionally as cards in a `contentGrid()`. Long pages render only the\n * records in view (plus a few around them), by whole rows of the card grid; the list\n * keeps `aria-setsize` / `aria-posinset` so assistive technology knows the real positions.\n */\nexport function ContentLayout(props: ContentLayoutProps) {\n const { table, records } = props\n const grid = table.contentGrid\n const { range, indexes, style, attach, item } = useVirtualList(\n records.length,\n virtualizeOptions(table.virtualize, VIRTUAL_ESTIMATES.item, grid ? 16 : 0, grid ? 'auto' : 1),\n )\n\n return (\n <div\n data-slot=\"table-content\"\n role={range.active ? 'list' : undefined}\n ref={attach}\n style={style}\n className={cn(grid ? cn('grid gap-4 p-4', gridColumnsClasses(grid)) : 'divide-y')}\n >\n {indexes.map((index) => {\n const record = records[index] as TableRecordSchema\n\n return (\n <ContentRecord\n key={String(record.key)}\n {...props}\n record={record}\n card={Boolean(grid)}\n index={index}\n position={range.active ? { size: records.length, item } : undefined}\n />\n )\n })}\n </div>\n )\n}\n\nfunction ContentRecord({\n table,\n record,\n columns,\n token,\n component,\n context,\n selectable,\n selection,\n onRecordClick,\n card,\n index,\n position,\n}: ContentLayoutProps & {\n record: TableRecordSchema\n card: boolean\n index: number\n /** Set while the list is windowed: the real list size and the item ref callback. */\n position?: { size: number; item: (element: HTMLElement | null) => void | (() => void) }\n}) {\n const t = useT()\n const panelId = useId()\n const layout = table.contentLayout ?? []\n const collapsible = hasCollapsiblePanel(layout)\n const startsCollapsed = !layout.some(\n (node) => node.type === 'Panel' && node.collapsible && !node.collapsed,\n )\n const [open, setOpen] = useState(!startsCollapsed)\n const clickable = Boolean(record.url || table.recordAction)\n const primary = primaryColumnName(columns)\n const visible = new Set(columns.map((column) => column.name))\n const selected = selection.isSelected(record.key)\n\n const renderNode = (node: ColumnLayoutNode, index: number, inSplit = false): ReactNode => {\n const grows = inSplit && layoutNodeGrows(node, columns)\n const sizing = inSplit ? (grows ? 'min-w-0 flex-1' : 'shrink-0') : undefined\n // `columnSpan()` / `columnStart()` of a column or layout inside a `Grid`.\n const span = cn(columnSpanClasses(node.columnSpan), columnStartClasses(node.columnStart))\n\n if (node.type === 'Column') {\n const column = columns.find((item) => item.name === node.name)\n\n if (!column || !visible.has(column.name)) return null\n\n return (\n <div\n key={`column:${column.name}`}\n data-column={column.name}\n className={cn(sizing, span, columnVisibilityClasses(column, 'block'))}\n >\n <RecordCell\n column={column}\n record={record}\n token={token}\n component={component}\n context={context}\n clickable={clickable}\n primary={column.name === primary}\n hasRecordAction={Boolean(table.recordAction)}\n onRecordClick={onRecordClick}\n />\n </div>\n )\n }\n\n const visibility = layoutVisibilityClasses(node)\n const key = `${node.type}:${index}`\n\n switch (node.type) {\n case 'Split':\n return (\n <div\n key={key}\n data-layout=\"split\"\n {...extraProps(node.extraAttributes, cn(splitClasses(node), visibility, sizing, span))}\n >\n {node.schema.map((child, childIndex) => renderNode(child, childIndex, true))}\n </div>\n )\n case 'Stack':\n return (\n <div\n key={key}\n data-layout=\"stack\"\n {...extraProps(node.extraAttributes, cn(stackClasses(node), visibility, sizing, span))}\n >\n {node.schema.map((child, childIndex) => renderNode(child, childIndex))}\n </div>\n )\n case 'Grid':\n return (\n <div\n key={key}\n data-layout=\"grid\"\n {...extraProps(\n node.extraAttributes,\n cn('grid gap-2', gridColumnsClasses(node.columns), visibility, sizing, span),\n )}\n >\n {node.schema.map((child, childIndex) => renderNode(child, childIndex))}\n </div>\n )\n case 'Panel':\n if (node.collapsible && !open) return null\n\n return (\n <div\n key={key}\n data-layout=\"panel\"\n {...extraProps(\n node.extraAttributes,\n cn('bg-muted/50 flex flex-col gap-2 rounded-lg p-3', visibility, sizing, span),\n )}\n >\n {node.schema.map((child, childIndex) => renderNode(child, childIndex))}\n </div>\n )\n default:\n return null\n }\n }\n\n // Collapsible panels at the top level go under the record's main row.\n const main = layout.filter((node) => !(node.type === 'Panel' && node.collapsible))\n const details = layout.filter((node) => node.type === 'Panel' && node.collapsible)\n const atStart = recordActionsAtStart(table.recordActionsPosition)\n const actions = record.actions?.length ? (\n <div className=\"shrink-0\" onClick={(event) => event.stopPropagation()}>\n <ActionList\n actions={record.actions}\n context={{ ...context, record: record.key }}\n size=\"sm\"\n align=\"end\"\n className=\"flex-nowrap\"\n />\n </div>\n ) : null\n\n return (\n <div\n data-slot=\"table-record\"\n data-state={selected ? 'selected' : undefined}\n data-index={index}\n ref={position?.item}\n role={position ? 'listitem' : undefined}\n aria-setsize={position?.size}\n aria-posinset={position ? index + 1 : undefined}\n className={cn(\n 'flex flex-col gap-3 p-4',\n card && 'bg-card rounded-lg border shadow-xs',\n clickable && 'hover:bg-muted/40 cursor-pointer',\n selected && 'bg-muted/60',\n record.classes,\n )}\n onClick={() => clickable && onRecordClick(record)}\n >\n <div className=\"flex items-start gap-3\">\n {atStart && table.recordActionsPosition === 'before-cells' && actions}\n {selectable && (\n <div className=\"pt-0.5\" onClick={(event) => event.stopPropagation()}>\n {record.selectable !== false && (\n <Checkbox\n checked={selected}\n onCheckedChange={(checked) => selection.toggle(record.key, checked === true)}\n aria-label={t('table.select_row', {}, 'Select row')}\n />\n )}\n </div>\n )}\n {atStart && table.recordActionsPosition === 'before-columns' && actions}\n <div className=\"flex min-w-0 flex-1 flex-col gap-3\">\n {main.map((node, index) => renderNode(node, index))}\n </div>\n {!atStart && actions}\n {collapsible && (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-expanded={open}\n aria-controls={open ? panelId : undefined}\n aria-label={\n open\n ? t('table.hide_details', {}, 'Hide details')\n : t('table.show_details', {}, 'Show details')\n }\n onClick={(event) => {\n event.stopPropagation()\n setOpen(!open)\n }}\n >\n <ChevronDownIcon className={cn('transition-transform', open && 'rotate-180')} />\n </Button>\n )}\n </div>\n {open && details.length > 0 && (\n <div id={panelId} className=\"flex flex-col gap-3\">\n {details.map((node, index) => renderNode(node, main.length + index))}\n </div>\n )}\n </div>\n )\n}\n\n/**\n * Sorting for content layouts, which have no column headers: a select of the sortable\n * columns and a direction toggle.\n */\nexport function ContentLayoutSort({\n table,\n columns,\n}: {\n table: TableSchema\n columns: ColumnSchema[]\n}) {\n const t = useT()\n const sortable = columns.filter((column) => column.sortable)\n\n if (sortable.length === 0) return null\n\n const direction = table.sort?.direction ?? 'asc'\n // A default sort on a column the select doesn't list (`created_at`) shows the placeholder.\n const selected = sortable.some((column) => column.name === table.sort?.column)\n ? (table.sort?.column ?? '')\n : ''\n\n return (\n <div className=\"flex items-center gap-1\">\n <label className=\"flex items-center gap-2 text-sm\">\n <span className=\"sr-only\">{t('table.sort_by', {}, 'Sort by')}</span>\n <select\n value={selected}\n onChange={(event) =>\n visitTable(\n table.identifier,\n {\n sort: event.target.value || null,\n direction: event.target.value ? direction : null,\n },\n ['page'],\n )\n }\n className=\"border-input h-8 rounded-md border bg-transparent px-2 text-sm\"\n >\n <option value=\"\">\n {table.defaultSortOptionLabel ?? t('table.sort_by', {}, 'Sort by')}\n </option>\n {sortable.map((column) => (\n <option key={column.name} value={column.name}>\n {column.label}\n </option>\n ))}\n </select>\n </label>\n {table.sort && (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"icon-sm\"\n aria-label={\n direction === 'asc'\n ? t('table.sort_ascending', {}, 'Ascending')\n : t('table.sort_descending', {}, 'Descending')\n }\n onClick={() =>\n visitTable(\n table.identifier,\n { sort: table.sort?.column ?? null, direction: direction === 'asc' ? 'desc' : 'asc' },\n ['page'],\n )\n }\n >\n {direction === 'asc' ? <ArrowUpIcon /> : <ArrowDownIcon />}\n </Button>\n )}\n </div>\n )\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { useT } from "../../context.js";
1
+ import { useFormatter, useT } from "../../context.js";
2
2
  import { Icon } from "../../lib/icons.js";
3
3
  import { Button } from "../ui/button.js";
4
4
  import { extremePageLinks, isAppendingPagination, nextPageQuery, prefetchTablePage, previousPageQuery, visitTable } from "@alfakit/core";
@@ -8,6 +8,7 @@ import { ChevronLeftIcon, ChevronRightIcon, ChevronsLeftIcon, ChevronsRightIcon
8
8
  //#region src/components/table/pagination.tsx
9
9
  function TablePagination({ table }) {
10
10
  const t = useT();
11
+ const format = useFormatter();
11
12
  const pagination = table.pagination;
12
13
  if (!pagination) return null;
13
14
  if (isAppendingPagination(pagination)) return /* @__PURE__ */ jsx(AppendingPagination, {
@@ -20,13 +21,13 @@ function TablePagination({ table }) {
20
21
  const next = nextPageQuery(pagination);
21
22
  const extremes = numbered ? extremePageLinks(table, pagination.currentPage, pagination.lastPage) : null;
22
23
  const summary = numbered ? t("table.showing", {
23
- first: pagination.from,
24
- last: pagination.to,
25
- total: pagination.total
26
- }, `Showing ${pagination.from}–${pagination.to} of ${pagination.total}`) : t("table.showing_range", {
27
- first: pagination.from,
28
- last: pagination.to
29
- }, `Showing ${pagination.from}–${pagination.to}`);
24
+ first: format.number(pagination.from),
25
+ last: format.number(pagination.to),
26
+ total: format.number(pagination.total)
27
+ }, "Showing :first–:last of :total") : t("table.showing_range", {
28
+ first: format.number(pagination.from),
29
+ last: format.number(pagination.to)
30
+ }, "Showing :first–:last");
30
31
  return /* @__PURE__ */ jsxs("div", {
31
32
  className: "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between",
32
33
  children: [/* @__PURE__ */ jsxs("div", {
@@ -84,7 +85,7 @@ function TablePagination({ table }) {
84
85
  size: "icon-sm",
85
86
  onClick: () => visitTable(table.identifier, { page }, ["page"]),
86
87
  "aria-current": page === pagination.currentPage ? "page" : void 0,
87
- children: page
88
+ children: format.number(page)
88
89
  }, page)),
89
90
  /* @__PURE__ */ jsx(Button, {
90
91
  type: "button",
@@ -121,6 +122,7 @@ function TablePagination({ table }) {
121
122
  }
122
123
  function PerPageSelect({ table, pagination }) {
123
124
  const t = useT();
125
+ const format = useFormatter();
124
126
  if (pagination.pageOptions.length <= 1) return null;
125
127
  return /* @__PURE__ */ jsxs("label", {
126
128
  className: "flex items-center gap-2",
@@ -133,7 +135,7 @@ function PerPageSelect({ table, pagination }) {
133
135
  className: "border-input h-8 rounded-md border bg-transparent px-2 text-sm",
134
136
  children: pagination.pageOptions.map((option) => /* @__PURE__ */ jsx("option", {
135
137
  value: String(option),
136
- children: option === "all" ? t("table.all", {}, "All") : option
138
+ children: option === "all" ? t("table.all", {}, "All") : format.number(option)
137
139
  }, option))
138
140
  })]
139
141
  });
@@ -146,6 +148,7 @@ function PerPageSelect({ table, pagination }) {
146
148
  */
147
149
  function AppendingPagination({ table, pagination }) {
148
150
  const t = useT();
151
+ const format = useFormatter();
149
152
  const sentinel = useRef(null);
150
153
  const [loading, setLoading] = useState(false);
151
154
  const [failed, setFailed] = useState(false);
@@ -212,9 +215,9 @@ function AppendingPagination({ table, pagination }) {
212
215
  children: [/* @__PURE__ */ jsxs("div", {
213
216
  className: "text-muted-foreground flex items-center gap-3 text-sm",
214
217
  children: [/* @__PURE__ */ jsx("span", { children: t("table.showing_range", {
215
- first: pagination.from,
216
- last: pagination.to
217
- }, `Showing ${pagination.from}–${pagination.to}`) }), /* @__PURE__ */ jsx(PerPageSelect, {
218
+ first: format.number(pagination.from),
219
+ last: format.number(pagination.to)
220
+ }, "Showing :first–:last") }), /* @__PURE__ */ jsx(PerPageSelect, {
218
221
  table,
219
222
  pagination
220
223
  })]