@alfakit/react 0.1.9 → 0.1.11

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 (107) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/components/actions/action-button.js +13 -1
  3. package/dist/components/actions/action-button.js.map +1 -1
  4. package/dist/components/dev-tools/dev-tools-inspector.js +3 -3
  5. package/dist/components/dev-tools/dev-tools-inspector.js.map +1 -1
  6. package/dist/components/fields/checkbox-list.js +2 -2
  7. package/dist/components/fields/checkbox-list.js.map +1 -1
  8. package/dist/components/fields/money-input.d.ts +5 -0
  9. package/dist/components/fields/money-input.d.ts.map +1 -1
  10. package/dist/components/fields/money-input.js +2 -5
  11. package/dist/components/fields/money-input.js.map +1 -1
  12. package/dist/components/fields/rich-editor-extensions.js +14 -4
  13. package/dist/components/fields/rich-editor-extensions.js.map +1 -1
  14. package/dist/components/file-manager/file-manager.js +2 -0
  15. package/dist/components/file-manager/file-manager.js.map +1 -1
  16. package/dist/components/layout/elements.d.ts.map +1 -1
  17. package/dist/components/layout/elements.js +16 -5
  18. package/dist/components/layout/elements.js.map +1 -1
  19. package/dist/components/layout/mixed-content.d.ts +6 -4
  20. package/dist/components/layout/mixed-content.d.ts.map +1 -1
  21. package/dist/components/layout/mixed-content.js +6 -4
  22. package/dist/components/layout/mixed-content.js.map +1 -1
  23. package/dist/components/layout/section.js +4 -2
  24. package/dist/components/layout/section.js.map +1 -1
  25. package/dist/components/notifications/notifications-menu.d.ts.map +1 -1
  26. package/dist/components/notifications/notifications-menu.js +45 -17
  27. package/dist/components/notifications/notifications-menu.js.map +1 -1
  28. package/dist/components/panel/lazy-placeholder.d.ts +1 -0
  29. package/dist/components/panel/lazy-placeholder.d.ts.map +1 -1
  30. package/dist/components/panel/lazy-placeholder.js +38 -4
  31. package/dist/components/panel/lazy-placeholder.js.map +1 -1
  32. package/dist/components/panel/shortcuts-overlay.js +13 -10
  33. package/dist/components/panel/shortcuts-overlay.js.map +1 -1
  34. package/dist/components/table/cells.js +1 -1
  35. package/dist/components/table/cells.js.map +1 -1
  36. package/dist/components/table/column-manager.js +4 -4
  37. package/dist/components/table/column-manager.js.map +1 -1
  38. package/dist/components/table/spreadsheet.js +8 -1
  39. package/dist/components/table/spreadsheet.js.map +1 -1
  40. package/dist/components/translation-manager/translation-manager.js +1 -1
  41. package/dist/components/translation-manager/translation-manager.js.map +1 -1
  42. package/dist/components/ui/calendar.d.ts.map +1 -1
  43. package/dist/components/ui/calendar.js +7 -0
  44. package/dist/components/ui/calendar.js.map +1 -1
  45. package/dist/components/widgets/dashboard-customizer.js +2 -2
  46. package/dist/components/widgets/dashboard-customizer.js.map +1 -1
  47. package/dist/components/widgets/stats-overview.js +3 -3
  48. package/dist/components/widgets/stats-overview.js.map +1 -1
  49. package/dist/components/widgets/widgets-block.js +2 -2
  50. package/dist/components/widgets/widgets-block.js.map +1 -1
  51. package/dist/create-alfakit.d.ts.map +1 -1
  52. package/dist/create-alfakit.js +3 -2
  53. package/dist/create-alfakit.js.map +1 -1
  54. package/dist/eject-manifest.json +4 -2
  55. package/dist/index.d.ts +2 -2
  56. package/dist/index.js +2 -2
  57. package/dist/pages/page.d.ts.map +1 -1
  58. package/dist/pages/page.js +4 -7
  59. package/dist/pages/page.js.map +1 -1
  60. package/dist/standalone/alfakit-component.d.ts +0 -10
  61. package/dist/standalone/alfakit-component.d.ts.map +1 -1
  62. package/dist/standalone/alfakit-component.js +5 -4
  63. package/dist/standalone/alfakit-component.js.map +1 -1
  64. package/dist/standalone/runtime.js +2 -1
  65. package/dist/standalone/runtime.js.map +1 -1
  66. package/dist/standalone.css +23 -1
  67. package/dist/starter-kit/index.d.ts +2 -2
  68. package/dist/starter-kit/index.js +2 -2
  69. package/dist/starter-kit/navigation.d.ts +6 -1
  70. package/dist/starter-kit/navigation.d.ts.map +1 -1
  71. package/dist/starter-kit/navigation.js +3 -2
  72. package/dist/starter-kit/navigation.js.map +1 -1
  73. package/dist/starter-kit/starter-kit.d.ts +9 -0
  74. package/dist/starter-kit/starter-kit.d.ts.map +1 -1
  75. package/dist/starter-kit/starter-kit.js +22 -3
  76. package/dist/starter-kit/starter-kit.js.map +1 -1
  77. package/dist/styles.css +2 -1
  78. package/dist/themes.css +4 -0
  79. package/package.json +2 -2
  80. package/src/components/actions/action-button.tsx +15 -1
  81. package/src/components/dev-tools/dev-tools-inspector.tsx +7 -2
  82. package/src/components/fields/checkbox-list.tsx +2 -2
  83. package/src/components/fields/money-input.tsx +3 -14
  84. package/src/components/fields/rich-editor-extensions.tsx +24 -2
  85. package/src/components/file-manager/file-manager.tsx +3 -1
  86. package/src/components/layout/elements.tsx +27 -4
  87. package/src/components/layout/mixed-content.tsx +8 -4
  88. package/src/components/layout/section.tsx +2 -2
  89. package/src/components/notifications/notifications-menu.tsx +42 -1
  90. package/src/components/panel/lazy-placeholder.tsx +41 -1
  91. package/src/components/panel/shortcuts-overlay.tsx +29 -24
  92. package/src/components/table/cells.tsx +3 -1
  93. package/src/components/table/column-manager.tsx +6 -4
  94. package/src/components/table/spreadsheet.tsx +18 -7
  95. package/src/components/translation-manager/translation-manager.tsx +1 -1
  96. package/src/components/ui/calendar.tsx +8 -0
  97. package/src/components/widgets/dashboard-customizer.tsx +2 -2
  98. package/src/components/widgets/stats-overview.tsx +6 -3
  99. package/src/components/widgets/widgets-block.tsx +2 -2
  100. package/src/create-alfakit.tsx +9 -1
  101. package/src/pages/page.tsx +7 -3
  102. package/src/standalone/alfakit-component.tsx +9 -4
  103. package/src/standalone/runtime.ts +3 -0
  104. package/src/starter-kit/index.ts +1 -0
  105. package/src/starter-kit/navigation.ts +12 -1
  106. package/src/starter-kit/starter-kit.tsx +25 -2
  107. package/src/styles.css +2 -1
@@ -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 * 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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"}
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 // Without `alt()` the first image is named after the column, so a record link that\n // wraps it has a name (W-V4-20).\n alt={cell.alt ?? (index === 0 ? (column.label ?? '') : '')}\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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"}
@@ -56,11 +56,11 @@ function ColumnManager({ table, token, component }) {
56
56
  if (deferred) setDraft(next);
57
57
  else visitTable(table.identifier, { columns: next }, ["page"]);
58
58
  };
59
- const save = async (order) => {
59
+ const save = async (order, options = {}) => {
60
60
  if (!panel.endpoints.tableColumns) return false;
61
61
  setSaving(true);
62
62
  try {
63
- await saveColumnOrder(panel.endpoints.tableColumns, token, component, order);
63
+ await saveColumnOrder(panel.endpoints.tableColumns, token, component, order, options);
64
64
  return true;
65
65
  } catch (error) {
66
66
  showToast({
@@ -107,13 +107,13 @@ function ColumnManager({ table, token, component }) {
107
107
  setOrderDraft(null);
108
108
  setAnnouncement("");
109
109
  setOpen(false);
110
- if (orderDraft && orderChanged) await save(orderDraft);
110
+ if (orderDraft && orderChanged) await save(orderDraft, { reload: !columns });
111
111
  if (columns) visitTable(table.identifier, { columns }, ["page"]);
112
112
  };
113
113
  const reset = async () => {
114
114
  if (reorderable) {
115
115
  setOrderDraft(null);
116
- await save([]);
116
+ await save([], { reload: !toggleable });
117
117
  }
118
118
  if (toggleable) {
119
119
  setDraft(null);
@@ -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 // 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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"}
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[], options: { reload?: boolean } = {}): 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, options)\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 // The visibility visit renders the new order too: no second reload racing it.\n if (orderDraft && orderChanged) await save(orderDraft, { reload: !columns })\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 // The visibility visit below renders the defined order too.\n await save([], { reload: !toggleable })\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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"}
@@ -376,7 +376,14 @@ function Spreadsheet({ table, token, component, onClose }) {
376
376
  children: /* @__PURE__ */ jsxs(DialogContent, {
377
377
  className: "sm:max-w-lg",
378
378
  children: [
379
- /* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsx(DialogTitle, { children: t("table.spreadsheet.paste_title", {}, "Paste cells") }), /* @__PURE__ */ jsxs(DialogDescription, { children: [choice("table.spreadsheet.paste_summary", preview?.plan.changes.length ?? 0, {}, ":count cell will change|:count cells will change"), (preview?.plan.skipped ?? 0) > 0 && ` ${choice("table.spreadsheet.paste_skipped", preview?.plan.skipped ?? 0, {}, ":count read-only cell is skipped|:count read-only cells are skipped")}`] })] }),
379
+ /* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsx(DialogTitle, { children: t("table.spreadsheet.paste_title", {}, "Paste cells") }), /* @__PURE__ */ jsxs(DialogDescription, { children: [/* @__PURE__ */ jsx("span", {
380
+ className: "block",
381
+ children: choice("table.spreadsheet.paste_summary", preview?.plan.changes.length ?? 0, {}, ":count cell will change|:count cells will change")
382
+ }), (preview?.plan.skipped ?? 0) > 0 && /* @__PURE__ */ jsx("span", {
383
+ className: "block",
384
+ "data-slot": "spreadsheet-paste-skipped",
385
+ children: choice("table.spreadsheet.paste_skipped", preview?.plan.skipped ?? 0, {}, ":count read-only cell is skipped|:count read-only cells are skipped")
386
+ })] })] }),
380
387
  /* @__PURE__ */ jsxs("div", {
381
388
  "data-slot": "spreadsheet-paste",
382
389
  className: "flex flex-col gap-3",
@@ -1 +1 @@
1
- {"version":3,"file":"spreadsheet.js","names":[],"sources":["../../../src/components/table/spreadsheet.tsx"],"sourcesContent":["import type {\n PastePlan,\n SpreadsheetAnnouncement,\n SpreadsheetSaveResult,\n TableSchema,\n} from '@alfakit/core'\nimport {\n SPREADSHEET_CLASSES,\n SPREADSHEET_ISSUE_MESSAGES,\n SpreadsheetGrid,\n VIRTUAL_ESTIMATES,\n inertiaReload,\n saveSpreadsheetChanges,\n spreadsheetAnnouncement,\n spreadsheetAria,\n spreadsheetCellClass,\n spreadsheetCellId,\n spreadsheetColumns,\n spreadsheetRows,\n spreadsheetSelectionSize,\n virtualizeOptions,\n} from '@alfakit/core'\nimport { CheckIcon } from 'lucide-react'\nimport {\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type ClipboardEvent,\n type KeyboardEvent,\n} from 'react'\nimport { useChoice, useDirection, usePanel, useT } from '../../context'\nimport { useStore } from '../../hooks/use-store'\nimport { useVirtualList } from '../../hooks/use-virtual-list'\nimport { showToast } from '../notifications/flash-toasts'\nimport { VirtualSpacerRow } from '../schema/virtual-spacer'\nimport { Button } from '../ui/button'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '../ui/dialog'\nimport { Spinner } from '../ui/spinner'\n\nexport interface SpreadsheetProps {\n table: TableSchema\n token: string\n component: string\n /** Leave spreadsheet mode. */\n onClose: () => void\n}\n\ninterface PastePreview {\n plan: PastePlan\n errors: SpreadsheetSaveResult['errors']\n validating: boolean\n}\n\n/**\n * Spreadsheet mode of a `Table::spreadsheet()` table (loaded on first use): a keyboard\n * grid over the page's records. Edits stay local (highlighted) until \"Save\" sends them in\n * one request; the server validates each cell with its column's rules and the record's\n * `update` policy, and its errors show on the cells.\n */\nexport function Spreadsheet({ table, token, component, onClose }: SpreadsheetProps) {\n const t = useT()\n const choice = useChoice()\n const direction = useDirection()\n const panel = usePanel()\n const baseId = useId()\n const columns = useMemo(() => spreadsheetColumns(table), [table])\n const rows = useMemo(\n () => spreadsheetRows(table.records ?? [], columns),\n [table.records, columns],\n )\n const [grid] = useState(() => new SpreadsheetGrid(rows, columns))\n const state = useStore(grid.store)\n const [announcement, setAnnouncement] = useState('')\n const [preview, setPreview] = useState<PastePreview | null>(null)\n const gridRef = useRef<HTMLTableElement | null>(null)\n const endpoint = panel.endpoints.tableCells\n\n // A reload (save, live update, polling) brings new records; edits of rows still on the\n // page are kept.\n useEffect(() => grid.setData(rows, columns), [grid, rows, columns])\n\n const {\n list,\n range,\n indexes,\n attach,\n item: attachRow,\n } = useVirtualList(rows.length, virtualizeOptions(table.virtualize, VIRTUAL_ESTIMATES.row))\n\n const announce = (message: SpreadsheetAnnouncement | null) => {\n if (message) setAnnouncement(choice(message.key, message.count, {}, message.fallback))\n }\n\n // Keep focus on the active cell (roving tabindex), scrolling a virtualised row into view.\n useEffect(() => {\n if (state.editing) return\n\n const root = gridRef.current\n\n if (!root || !root.contains(document.activeElement)) return\n\n const { row, col } = state.active\n const cell = document.getElementById(spreadsheetCellId(baseId, row, col))\n\n if (cell) {\n cell.focus({ preventScroll: false })\n cell.scrollIntoView?.({ block: 'nearest', inline: 'nearest' })\n } else {\n list.scrollToIndex(row)\n }\n }, [state.active, state.editing, baseId, list])\n\n const save = async () => {\n const changes = grid.changes()\n\n if (!endpoint || changes.length === 0 || state.saving) return\n\n grid.setSaving(true)\n\n try {\n const result = await saveSpreadsheetChanges(endpoint, token, component, changes)\n\n grid.applySaveResult(result)\n\n if (result.saved.length > 0) {\n announce(spreadsheetAnnouncement('saved', result.saved.length))\n inertiaReload()\n }\n\n if (result.errors.length > 0) {\n announce(spreadsheetAnnouncement('failed', result.errors.length))\n }\n } catch (error) {\n showToast({\n id: 'alfakit-spreadsheet-failed',\n title: t('table.spreadsheet.request_failed', {}, \"Couldn't save the changes\"),\n body: error instanceof Error ? error.message : String(error),\n status: 'danger',\n format: 'alfakit',\n })\n } finally {\n grid.setSaving(false)\n }\n }\n\n const undoSave = async () => {\n const changes = grid.undoSaveChanges()\n\n if (!endpoint || changes.length === 0) return\n\n grid.setSaving(true)\n\n try {\n const result = await saveSpreadsheetChanges(endpoint, token, component, changes)\n\n grid.applySaveResult(result)\n announce(spreadsheetAnnouncement('undo', result.saved.length))\n\n if (result.saved.length > 0) inertiaReload()\n } finally {\n grid.setSaving(false)\n }\n }\n\n const close = () => {\n if (\n grid.dirtyCount > 0 &&\n !window.confirm(t('table.spreadsheet.discard_confirm', {}, 'Discard your unsaved changes?'))\n ) {\n return\n }\n\n grid.discard()\n onClose()\n }\n\n const onKeyDown = (event: KeyboardEvent<HTMLTableElement>) => {\n const result = grid.handleKey(event, direction)\n\n if (result === 'ignored') return\n\n event.preventDefault()\n\n if (result === 'save') {\n void save()\n } else if (result === 'undo') {\n announce(spreadsheetAnnouncement('undo', grid.undo()))\n } else if (result === 'fill' || result === 'clear') {\n announce(spreadsheetAnnouncement(result, grid.lastApplied))\n }\n\n if (result === 'commit' || result === 'cancel' || result === 'toggle') {\n // Back from the editor to the cell.\n requestAnimationFrame(() =>\n document\n .getElementById(spreadsheetCellId(baseId, grid.state.active.row, grid.state.active.col))\n ?.focus(),\n )\n }\n }\n\n const onCopy = (event: ClipboardEvent<HTMLTableElement>) => {\n if (grid.state.editing) return\n\n event.preventDefault()\n event.clipboardData.setData('text/plain', grid.copyText())\n announce(spreadsheetAnnouncement('copy', spreadsheetSelectionSize(grid.bounds())))\n }\n\n const onPaste = (event: ClipboardEvent<HTMLTableElement>) => {\n if (grid.state.editing) return\n\n event.preventDefault()\n\n const plan = grid.planPaste(event.clipboardData.getData('text/plain'))\n\n if (plan.changes.length === 0 && plan.issues.length === 0) return\n\n setPreview({ plan, errors: [], validating: Boolean(endpoint && plan.changes.length > 0) })\n\n if (!endpoint || plan.changes.length === 0) return\n\n // Validate the pasted values on the server before they are applied.\n void saveSpreadsheetChanges(\n endpoint,\n token,\n component,\n plan.changes.map((change) => {\n const record = grid.getRows()[change.row]\n const column = grid.getColumns()[change.col]\n\n return { record: record?.key ?? '', column: column?.name ?? '', state: change.value }\n }),\n { dryRun: true },\n )\n .then((result) =>\n setPreview(\n (current) => current && { ...current, errors: result.errors, validating: false },\n ),\n )\n .catch(() => setPreview((current) => current && { ...current, validating: false }))\n }\n\n const applyPaste = () => {\n if (!preview) return\n\n const count = grid.apply(preview.plan.changes)\n\n if (preview.errors.length > 0) grid.setErrors(preview.errors)\n\n announce(spreadsheetAnnouncement('paste', count))\n setPreview(null)\n }\n\n const issueText = (issue: PastePlan['issues'][number]) => {\n const message = SPREADSHEET_ISSUE_MESSAGES[issue.reason]\n\n return t(\n message.key,\n { text: issue.text, column: columns[issue.col]?.label ?? '', row: issue.row + 1 },\n message.fallback,\n )\n }\n\n const errorList = grid.errorCells()\n\n const helpId = `${baseId}-help`\n\n return (\n <div data-slot=\"spreadsheet\" className=\"flex flex-col gap-3\">\n <div data-slot=\"spreadsheet-toolbar\" className=\"flex flex-wrap items-center gap-2\">\n <Button\n type=\"button\"\n size=\"sm\"\n disabled={grid.dirtyCount === 0 || state.saving}\n onClick={() => void save()}\n >\n {state.saving && <Spinner />}\n {t('table.spreadsheet.save', {}, 'Save changes')}\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n disabled={!grid.canUndo || state.saving}\n onClick={() => announce(spreadsheetAnnouncement('undo', grid.undo()))}\n >\n {t('table.spreadsheet.undo', {}, 'Undo')}\n </Button>\n {grid.canUndoSave && (\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n disabled={state.saving}\n onClick={() => void undoSave()}\n >\n {t('table.spreadsheet.undo_save', {}, 'Undo last save')}\n </Button>\n )}\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n disabled={grid.dirtyCount === 0 || state.saving}\n onClick={() => grid.discard()}\n >\n {t('table.spreadsheet.discard', {}, 'Discard')}\n </Button>\n <span className=\"text-muted-foreground text-sm\" aria-live=\"polite\">\n {grid.dirtyCount > 0 &&\n choice(\n 'table.spreadsheet.unsaved',\n grid.dirtyCount,\n {},\n ':count unsaved change|:count unsaved changes',\n )}\n {grid.errorCount > 0 && (\n <span className=\"text-destructive ms-2\">\n {choice(\n 'table.spreadsheet.errors',\n grid.errorCount,\n {},\n ':count error|:count errors',\n )}\n </span>\n )}\n </span>\n <span className=\"flex-1\" />\n <Button type=\"button\" size=\"sm\" variant=\"outline\" onClick={close}>\n {t('table.spreadsheet.close', {}, 'Done')}\n </Button>\n </div>\n <p id={helpId} className=\"sr-only\">\n {t(\n 'table.spreadsheet.help',\n {},\n 'Arrow keys move between cells. Enter or F2 edits a cell, Escape cancels, Tab moves to the next cell. Ctrl+C copies, Ctrl+V pastes, Ctrl+D fills down, Ctrl+Z undoes and Ctrl+S saves.',\n )}\n </p>\n <div data-surface=\"table\" className={SPREADSHEET_CLASSES.root} style={{ maxHeight: '70vh' }}>\n <table\n ref={gridRef}\n role=\"grid\"\n aria-label={table.heading ?? t('table.spreadsheet.label', {}, 'Spreadsheet')}\n aria-describedby={helpId}\n aria-rowcount={rows.length + 1}\n aria-colcount={columns.length}\n aria-multiselectable=\"true\"\n aria-busy={state.saving || undefined}\n data-slot=\"spreadsheet-grid\"\n className={SPREADSHEET_CLASSES.table}\n onKeyDown={onKeyDown}\n onCopy={onCopy}\n onPaste={onPaste}\n >\n <thead>\n <tr aria-rowindex={1}>\n {columns.map((column, col) => (\n <th\n key={column.name}\n role=\"columnheader\"\n scope=\"col\"\n aria-colindex={col + 1}\n className={SPREADSHEET_CLASSES.header}\n >\n {column.label}\n </th>\n ))}\n </tr>\n </thead>\n <tbody ref={attach}>\n <VirtualSpacerRow height={range.before} colSpan={columns.length} />\n {indexes.map((row) => {\n const record = rows[row]\n\n if (!record) return null\n\n return (\n <tr\n key={String(record.key)}\n ref={attachRow}\n data-index={row}\n aria-rowindex={row + 2}\n >\n {columns.map((column, col) => {\n const active = grid.isActive(row, col)\n const editing =\n state.editing && state.editing.row === row && state.editing.col === col\n const errors = grid.errorsAt(row, col)\n const value = grid.value(row, col)\n const editable = grid.isEditable(row, col)\n\n return (\n <td\n key={column.name}\n id={spreadsheetCellId(baseId, row, col)}\n role=\"gridcell\"\n {...spreadsheetAria(row, col)}\n tabIndex={active ? 0 : -1}\n aria-selected={grid.isSelected(row, col)}\n aria-readonly={!editable || undefined}\n aria-invalid={errors.length > 0 || undefined}\n title={errors.join(' ') || undefined}\n data-slot=\"spreadsheet-cell\"\n data-dirty={grid.isDirty(row, col) || undefined}\n data-active={active || undefined}\n className={spreadsheetCellClass(grid, row, col)}\n onMouseDown={(event) => {\n if (editing) return\n\n grid.moveTo(row, col, event.shiftKey)\n }}\n onDoubleClick={() => grid.beginEdit()}\n >\n {editing && column.kind === 'select' ? (\n <select\n autoFocus\n className={SPREADSHEET_CLASSES.editor}\n aria-label={column.label}\n value={\n state.editing?.value === null || state.editing?.value === undefined\n ? ''\n : String(state.editing.value)\n }\n onChange={(event) => {\n grid.updateDraft(event.target.value)\n grid.commitEdit()\n document.getElementById(spreadsheetCellId(baseId, row, col))?.focus()\n }}\n onBlur={() => grid.cancelEdit()}\n >\n <option value=\"\">{t('table.spreadsheet.no_value', {}, '—')}</option>\n {column.options?.map((option) => (\n <option\n key={option.value}\n value={option.value}\n disabled={option.disabled}\n >\n {option.label.replace(/<[^>]*>/g, '')}\n </option>\n ))}\n </select>\n ) : editing ? (\n <input\n autoFocus\n type={column.kind === 'number' ? 'text' : (column.inputType ?? 'text')}\n inputMode={column.kind === 'number' ? 'decimal' : undefined}\n className={SPREADSHEET_CLASSES.editor}\n aria-label={column.label}\n value={\n state.editing?.value === null || state.editing?.value === undefined\n ? ''\n : String(state.editing.value)\n }\n onChange={(event) => grid.updateDraft(event.target.value)}\n onBlur={() => grid.commitEdit()}\n />\n ) : column.kind === 'boolean' ? (\n <span className=\"inline-flex items-center gap-1\">\n <span\n aria-hidden=\"true\"\n className=\"border-input data-[checked=true]:bg-primary data-[checked=true]:text-primary-foreground inline-flex size-4 items-center justify-center rounded-[4px] border\"\n data-checked={Boolean(value)}\n >\n {Boolean(value) && <CheckIcon className=\"size-3\" />}\n </span>\n <span className=\"sr-only\">\n {value\n ? t('table.spreadsheet.yes', {}, 'Yes')\n : t('table.spreadsheet.no', {}, 'No')}\n </span>\n </span>\n ) : (\n grid.text(row, col)\n )}\n {errors.length > 0 && <span className=\"sr-only\">{errors.join(' ')}</span>}\n </td>\n )\n })}\n </tr>\n )\n })}\n <VirtualSpacerRow height={range.after} colSpan={columns.length} />\n </tbody>\n </table>\n {rows.length === 0 && (\n <p className=\"text-muted-foreground p-6 text-center text-sm\">\n {t('table.spreadsheet.empty', {}, 'No records to edit.')}\n </p>\n )}\n </div>\n {errorList.length > 0 && (\n <ul data-slot=\"spreadsheet-errors\" className=\"text-destructive flex flex-col gap-1 text-sm\">\n {errorList.map((error) => (\n <li key={error.key}>\n <button\n type=\"button\"\n className=\"text-start hover:underline\"\n onClick={() => {\n grid.moveTo(error.row, error.col)\n document.getElementById(spreadsheetCellId(baseId, error.row, error.col))?.focus()\n }}\n >\n {t(\n 'table.spreadsheet.cell_error',\n {\n row: error.row + 1,\n column: columns[error.col]?.label ?? '',\n message: error.messages.join(' '),\n },\n 'Row :row, :column: :message',\n )}\n </button>\n </li>\n ))}\n </ul>\n )}\n <span\n aria-live=\"polite\"\n aria-atomic=\"true\"\n className=\"sr-only\"\n data-slot=\"spreadsheet-announcement\"\n >\n {announcement}\n </span>\n\n <Dialog open={preview !== null} onOpenChange={(open) => !open && setPreview(null)}>\n <DialogContent className=\"sm:max-w-lg\">\n <DialogHeader>\n <DialogTitle>{t('table.spreadsheet.paste_title', {}, 'Paste cells')}</DialogTitle>\n <DialogDescription>\n {choice(\n 'table.spreadsheet.paste_summary',\n preview?.plan.changes.length ?? 0,\n {},\n ':count cell will change|:count cells will change',\n )}\n {(preview?.plan.skipped ?? 0) > 0 &&\n ` ${choice('table.spreadsheet.paste_skipped', preview?.plan.skipped ?? 0, {}, ':count read-only cell is skipped|:count read-only cells are skipped')}`}\n </DialogDescription>\n </DialogHeader>\n <div data-slot=\"spreadsheet-paste\" className=\"flex flex-col gap-3\">\n {preview?.validating && (\n <p className=\"text-muted-foreground flex items-center gap-2 text-sm\">\n <Spinner />\n {t('table.spreadsheet.paste_validating', {}, 'Checking the values…')}\n </p>\n )}\n {preview && (preview.plan.issues.length > 0 || preview.errors.length > 0) && (\n <ul className=\"text-destructive flex max-h-48 flex-col gap-1 overflow-auto text-sm\">\n {preview.plan.issues.map((issue) => (\n <li key={`issue-${issue.row}-${issue.col}`}>{issueText(issue)}</li>\n ))}\n {preview.errors.map((error) => {\n const position = grid.position(error.record, error.column)\n const column = columns.find((item) => item.name === error.column)\n const row = position?.row ?? -1\n\n return (\n <li key={`error-${String(error.record)}-${error.column}`}>\n {t(\n 'table.spreadsheet.cell_error',\n {\n row: row + 1,\n column: column?.label ?? error.column,\n message: error.messages.join(' '),\n },\n 'Row :row, :column: :message',\n )}\n </li>\n )\n })}\n </ul>\n )}\n </div>\n <DialogFooter>\n <Button type=\"button\" variant=\"outline\" onClick={() => setPreview(null)}>\n {t('cancel', {}, 'Cancel')}\n </Button>\n <Button\n type=\"button\"\n disabled={!preview || preview.plan.changes.length === 0}\n onClick={applyPaste}\n >\n {t('table.spreadsheet.paste_apply', {}, 'Apply')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </div>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"spreadsheet.js","names":[],"sources":["../../../src/components/table/spreadsheet.tsx"],"sourcesContent":["import type {\n PastePlan,\n SpreadsheetAnnouncement,\n SpreadsheetSaveResult,\n TableSchema,\n} from '@alfakit/core'\nimport {\n SPREADSHEET_CLASSES,\n SPREADSHEET_ISSUE_MESSAGES,\n SpreadsheetGrid,\n VIRTUAL_ESTIMATES,\n inertiaReload,\n saveSpreadsheetChanges,\n spreadsheetAnnouncement,\n spreadsheetAria,\n spreadsheetCellClass,\n spreadsheetCellId,\n spreadsheetColumns,\n spreadsheetRows,\n spreadsheetSelectionSize,\n virtualizeOptions,\n} from '@alfakit/core'\nimport { CheckIcon } from 'lucide-react'\nimport {\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type ClipboardEvent,\n type KeyboardEvent,\n} from 'react'\nimport { useChoice, useDirection, usePanel, useT } from '../../context'\nimport { useStore } from '../../hooks/use-store'\nimport { useVirtualList } from '../../hooks/use-virtual-list'\nimport { showToast } from '../notifications/flash-toasts'\nimport { VirtualSpacerRow } from '../schema/virtual-spacer'\nimport { Button } from '../ui/button'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '../ui/dialog'\nimport { Spinner } from '../ui/spinner'\n\nexport interface SpreadsheetProps {\n table: TableSchema\n token: string\n component: string\n /** Leave spreadsheet mode. */\n onClose: () => void\n}\n\ninterface PastePreview {\n plan: PastePlan\n errors: SpreadsheetSaveResult['errors']\n validating: boolean\n}\n\n/**\n * Spreadsheet mode of a `Table::spreadsheet()` table (loaded on first use): a keyboard\n * grid over the page's records. Edits stay local (highlighted) until \"Save\" sends them in\n * one request; the server validates each cell with its column's rules and the record's\n * `update` policy, and its errors show on the cells.\n */\nexport function Spreadsheet({ table, token, component, onClose }: SpreadsheetProps) {\n const t = useT()\n const choice = useChoice()\n const direction = useDirection()\n const panel = usePanel()\n const baseId = useId()\n const columns = useMemo(() => spreadsheetColumns(table), [table])\n const rows = useMemo(\n () => spreadsheetRows(table.records ?? [], columns),\n [table.records, columns],\n )\n const [grid] = useState(() => new SpreadsheetGrid(rows, columns))\n const state = useStore(grid.store)\n const [announcement, setAnnouncement] = useState('')\n const [preview, setPreview] = useState<PastePreview | null>(null)\n const gridRef = useRef<HTMLTableElement | null>(null)\n const endpoint = panel.endpoints.tableCells\n\n // A reload (save, live update, polling) brings new records; edits of rows still on the\n // page are kept.\n useEffect(() => grid.setData(rows, columns), [grid, rows, columns])\n\n const {\n list,\n range,\n indexes,\n attach,\n item: attachRow,\n } = useVirtualList(rows.length, virtualizeOptions(table.virtualize, VIRTUAL_ESTIMATES.row))\n\n const announce = (message: SpreadsheetAnnouncement | null) => {\n if (message) setAnnouncement(choice(message.key, message.count, {}, message.fallback))\n }\n\n // Keep focus on the active cell (roving tabindex), scrolling a virtualised row into view.\n useEffect(() => {\n if (state.editing) return\n\n const root = gridRef.current\n\n if (!root || !root.contains(document.activeElement)) return\n\n const { row, col } = state.active\n const cell = document.getElementById(spreadsheetCellId(baseId, row, col))\n\n if (cell) {\n cell.focus({ preventScroll: false })\n cell.scrollIntoView?.({ block: 'nearest', inline: 'nearest' })\n } else {\n list.scrollToIndex(row)\n }\n }, [state.active, state.editing, baseId, list])\n\n const save = async () => {\n const changes = grid.changes()\n\n if (!endpoint || changes.length === 0 || state.saving) return\n\n grid.setSaving(true)\n\n try {\n const result = await saveSpreadsheetChanges(endpoint, token, component, changes)\n\n grid.applySaveResult(result)\n\n if (result.saved.length > 0) {\n announce(spreadsheetAnnouncement('saved', result.saved.length))\n inertiaReload()\n }\n\n if (result.errors.length > 0) {\n announce(spreadsheetAnnouncement('failed', result.errors.length))\n }\n } catch (error) {\n showToast({\n id: 'alfakit-spreadsheet-failed',\n title: t('table.spreadsheet.request_failed', {}, \"Couldn't save the changes\"),\n body: error instanceof Error ? error.message : String(error),\n status: 'danger',\n format: 'alfakit',\n })\n } finally {\n grid.setSaving(false)\n }\n }\n\n const undoSave = async () => {\n const changes = grid.undoSaveChanges()\n\n if (!endpoint || changes.length === 0) return\n\n grid.setSaving(true)\n\n try {\n const result = await saveSpreadsheetChanges(endpoint, token, component, changes)\n\n grid.applySaveResult(result)\n announce(spreadsheetAnnouncement('undo', result.saved.length))\n\n if (result.saved.length > 0) inertiaReload()\n } finally {\n grid.setSaving(false)\n }\n }\n\n const close = () => {\n if (\n grid.dirtyCount > 0 &&\n !window.confirm(t('table.spreadsheet.discard_confirm', {}, 'Discard your unsaved changes?'))\n ) {\n return\n }\n\n grid.discard()\n onClose()\n }\n\n const onKeyDown = (event: KeyboardEvent<HTMLTableElement>) => {\n const result = grid.handleKey(event, direction)\n\n if (result === 'ignored') return\n\n event.preventDefault()\n\n if (result === 'save') {\n void save()\n } else if (result === 'undo') {\n announce(spreadsheetAnnouncement('undo', grid.undo()))\n } else if (result === 'fill' || result === 'clear') {\n announce(spreadsheetAnnouncement(result, grid.lastApplied))\n }\n\n if (result === 'commit' || result === 'cancel' || result === 'toggle') {\n // Back from the editor to the cell.\n requestAnimationFrame(() =>\n document\n .getElementById(spreadsheetCellId(baseId, grid.state.active.row, grid.state.active.col))\n ?.focus(),\n )\n }\n }\n\n const onCopy = (event: ClipboardEvent<HTMLTableElement>) => {\n if (grid.state.editing) return\n\n event.preventDefault()\n event.clipboardData.setData('text/plain', grid.copyText())\n announce(spreadsheetAnnouncement('copy', spreadsheetSelectionSize(grid.bounds())))\n }\n\n const onPaste = (event: ClipboardEvent<HTMLTableElement>) => {\n if (grid.state.editing) return\n\n event.preventDefault()\n\n const plan = grid.planPaste(event.clipboardData.getData('text/plain'))\n\n if (plan.changes.length === 0 && plan.issues.length === 0) return\n\n setPreview({ plan, errors: [], validating: Boolean(endpoint && plan.changes.length > 0) })\n\n if (!endpoint || plan.changes.length === 0) return\n\n // Validate the pasted values on the server before they are applied.\n void saveSpreadsheetChanges(\n endpoint,\n token,\n component,\n plan.changes.map((change) => {\n const record = grid.getRows()[change.row]\n const column = grid.getColumns()[change.col]\n\n return { record: record?.key ?? '', column: column?.name ?? '', state: change.value }\n }),\n { dryRun: true },\n )\n .then((result) =>\n setPreview(\n (current) => current && { ...current, errors: result.errors, validating: false },\n ),\n )\n .catch(() => setPreview((current) => current && { ...current, validating: false }))\n }\n\n const applyPaste = () => {\n if (!preview) return\n\n const count = grid.apply(preview.plan.changes)\n\n if (preview.errors.length > 0) grid.setErrors(preview.errors)\n\n announce(spreadsheetAnnouncement('paste', count))\n setPreview(null)\n }\n\n const issueText = (issue: PastePlan['issues'][number]) => {\n const message = SPREADSHEET_ISSUE_MESSAGES[issue.reason]\n\n return t(\n message.key,\n { text: issue.text, column: columns[issue.col]?.label ?? '', row: issue.row + 1 },\n message.fallback,\n )\n }\n\n const errorList = grid.errorCells()\n\n const helpId = `${baseId}-help`\n\n return (\n <div data-slot=\"spreadsheet\" className=\"flex flex-col gap-3\">\n <div data-slot=\"spreadsheet-toolbar\" className=\"flex flex-wrap items-center gap-2\">\n <Button\n type=\"button\"\n size=\"sm\"\n disabled={grid.dirtyCount === 0 || state.saving}\n onClick={() => void save()}\n >\n {state.saving && <Spinner />}\n {t('table.spreadsheet.save', {}, 'Save changes')}\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n disabled={!grid.canUndo || state.saving}\n onClick={() => announce(spreadsheetAnnouncement('undo', grid.undo()))}\n >\n {t('table.spreadsheet.undo', {}, 'Undo')}\n </Button>\n {grid.canUndoSave && (\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n disabled={state.saving}\n onClick={() => void undoSave()}\n >\n {t('table.spreadsheet.undo_save', {}, 'Undo last save')}\n </Button>\n )}\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n disabled={grid.dirtyCount === 0 || state.saving}\n onClick={() => grid.discard()}\n >\n {t('table.spreadsheet.discard', {}, 'Discard')}\n </Button>\n <span className=\"text-muted-foreground text-sm\" aria-live=\"polite\">\n {grid.dirtyCount > 0 &&\n choice(\n 'table.spreadsheet.unsaved',\n grid.dirtyCount,\n {},\n ':count unsaved change|:count unsaved changes',\n )}\n {grid.errorCount > 0 && (\n <span className=\"text-destructive ms-2\">\n {choice(\n 'table.spreadsheet.errors',\n grid.errorCount,\n {},\n ':count error|:count errors',\n )}\n </span>\n )}\n </span>\n <span className=\"flex-1\" />\n <Button type=\"button\" size=\"sm\" variant=\"outline\" onClick={close}>\n {t('table.spreadsheet.close', {}, 'Done')}\n </Button>\n </div>\n <p id={helpId} className=\"sr-only\">\n {t(\n 'table.spreadsheet.help',\n {},\n 'Arrow keys move between cells. Enter or F2 edits a cell, Escape cancels, Tab moves to the next cell. Ctrl+C copies, Ctrl+V pastes, Ctrl+D fills down, Ctrl+Z undoes and Ctrl+S saves.',\n )}\n </p>\n <div data-surface=\"table\" className={SPREADSHEET_CLASSES.root} style={{ maxHeight: '70vh' }}>\n <table\n ref={gridRef}\n role=\"grid\"\n aria-label={table.heading ?? t('table.spreadsheet.label', {}, 'Spreadsheet')}\n aria-describedby={helpId}\n aria-rowcount={rows.length + 1}\n aria-colcount={columns.length}\n aria-multiselectable=\"true\"\n aria-busy={state.saving || undefined}\n data-slot=\"spreadsheet-grid\"\n className={SPREADSHEET_CLASSES.table}\n onKeyDown={onKeyDown}\n onCopy={onCopy}\n onPaste={onPaste}\n >\n <thead>\n <tr aria-rowindex={1}>\n {columns.map((column, col) => (\n <th\n key={column.name}\n role=\"columnheader\"\n scope=\"col\"\n aria-colindex={col + 1}\n className={SPREADSHEET_CLASSES.header}\n >\n {column.label}\n </th>\n ))}\n </tr>\n </thead>\n <tbody ref={attach}>\n <VirtualSpacerRow height={range.before} colSpan={columns.length} />\n {indexes.map((row) => {\n const record = rows[row]\n\n if (!record) return null\n\n return (\n <tr\n key={String(record.key)}\n ref={attachRow}\n data-index={row}\n aria-rowindex={row + 2}\n >\n {columns.map((column, col) => {\n const active = grid.isActive(row, col)\n const editing =\n state.editing && state.editing.row === row && state.editing.col === col\n const errors = grid.errorsAt(row, col)\n const value = grid.value(row, col)\n const editable = grid.isEditable(row, col)\n\n return (\n <td\n key={column.name}\n id={spreadsheetCellId(baseId, row, col)}\n role=\"gridcell\"\n {...spreadsheetAria(row, col)}\n tabIndex={active ? 0 : -1}\n aria-selected={grid.isSelected(row, col)}\n aria-readonly={!editable || undefined}\n aria-invalid={errors.length > 0 || undefined}\n title={errors.join(' ') || undefined}\n data-slot=\"spreadsheet-cell\"\n data-dirty={grid.isDirty(row, col) || undefined}\n data-active={active || undefined}\n className={spreadsheetCellClass(grid, row, col)}\n onMouseDown={(event) => {\n if (editing) return\n\n grid.moveTo(row, col, event.shiftKey)\n }}\n onDoubleClick={() => grid.beginEdit()}\n >\n {editing && column.kind === 'select' ? (\n <select\n autoFocus\n className={SPREADSHEET_CLASSES.editor}\n aria-label={column.label}\n value={\n state.editing?.value === null || state.editing?.value === undefined\n ? ''\n : String(state.editing.value)\n }\n onChange={(event) => {\n grid.updateDraft(event.target.value)\n grid.commitEdit()\n document.getElementById(spreadsheetCellId(baseId, row, col))?.focus()\n }}\n onBlur={() => grid.cancelEdit()}\n >\n <option value=\"\">{t('table.spreadsheet.no_value', {}, '—')}</option>\n {column.options?.map((option) => (\n <option\n key={option.value}\n value={option.value}\n disabled={option.disabled}\n >\n {option.label.replace(/<[^>]*>/g, '')}\n </option>\n ))}\n </select>\n ) : editing ? (\n <input\n autoFocus\n type={column.kind === 'number' ? 'text' : (column.inputType ?? 'text')}\n inputMode={column.kind === 'number' ? 'decimal' : undefined}\n className={SPREADSHEET_CLASSES.editor}\n aria-label={column.label}\n value={\n state.editing?.value === null || state.editing?.value === undefined\n ? ''\n : String(state.editing.value)\n }\n onChange={(event) => grid.updateDraft(event.target.value)}\n onBlur={() => grid.commitEdit()}\n />\n ) : column.kind === 'boolean' ? (\n <span className=\"inline-flex items-center gap-1\">\n <span\n aria-hidden=\"true\"\n className=\"border-input data-[checked=true]:bg-primary data-[checked=true]:text-primary-foreground inline-flex size-4 items-center justify-center rounded-[4px] border\"\n data-checked={Boolean(value)}\n >\n {Boolean(value) && <CheckIcon className=\"size-3\" />}\n </span>\n <span className=\"sr-only\">\n {value\n ? t('table.spreadsheet.yes', {}, 'Yes')\n : t('table.spreadsheet.no', {}, 'No')}\n </span>\n </span>\n ) : (\n grid.text(row, col)\n )}\n {errors.length > 0 && <span className=\"sr-only\">{errors.join(' ')}</span>}\n </td>\n )\n })}\n </tr>\n )\n })}\n <VirtualSpacerRow height={range.after} colSpan={columns.length} />\n </tbody>\n </table>\n {rows.length === 0 && (\n <p className=\"text-muted-foreground p-6 text-center text-sm\">\n {t('table.spreadsheet.empty', {}, 'No records to edit.')}\n </p>\n )}\n </div>\n {errorList.length > 0 && (\n <ul data-slot=\"spreadsheet-errors\" className=\"text-destructive flex flex-col gap-1 text-sm\">\n {errorList.map((error) => (\n <li key={error.key}>\n <button\n type=\"button\"\n className=\"text-start hover:underline\"\n onClick={() => {\n grid.moveTo(error.row, error.col)\n document.getElementById(spreadsheetCellId(baseId, error.row, error.col))?.focus()\n }}\n >\n {t(\n 'table.spreadsheet.cell_error',\n {\n row: error.row + 1,\n column: columns[error.col]?.label ?? '',\n message: error.messages.join(' '),\n },\n 'Row :row, :column: :message',\n )}\n </button>\n </li>\n ))}\n </ul>\n )}\n <span\n aria-live=\"polite\"\n aria-atomic=\"true\"\n className=\"sr-only\"\n data-slot=\"spreadsheet-announcement\"\n >\n {announcement}\n </span>\n\n <Dialog open={preview !== null} onOpenChange={(open) => !open && setPreview(null)}>\n <DialogContent className=\"sm:max-w-lg\">\n <DialogHeader>\n <DialogTitle>{t('table.spreadsheet.paste_title', {}, 'Paste cells')}</DialogTitle>\n <DialogDescription>\n {/* One line per count: translations can't join two sentences. */}\n <span className=\"block\">\n {choice(\n 'table.spreadsheet.paste_summary',\n preview?.plan.changes.length ?? 0,\n {},\n ':count cell will change|:count cells will change',\n )}\n </span>\n {(preview?.plan.skipped ?? 0) > 0 && (\n <span className=\"block\" data-slot=\"spreadsheet-paste-skipped\">\n {choice(\n 'table.spreadsheet.paste_skipped',\n preview?.plan.skipped ?? 0,\n {},\n ':count read-only cell is skipped|:count read-only cells are skipped',\n )}\n </span>\n )}\n </DialogDescription>\n </DialogHeader>\n <div data-slot=\"spreadsheet-paste\" className=\"flex flex-col gap-3\">\n {preview?.validating && (\n <p className=\"text-muted-foreground flex items-center gap-2 text-sm\">\n <Spinner />\n {t('table.spreadsheet.paste_validating', {}, 'Checking the values…')}\n </p>\n )}\n {preview && (preview.plan.issues.length > 0 || preview.errors.length > 0) && (\n <ul className=\"text-destructive flex max-h-48 flex-col gap-1 overflow-auto text-sm\">\n {preview.plan.issues.map((issue) => (\n <li key={`issue-${issue.row}-${issue.col}`}>{issueText(issue)}</li>\n ))}\n {preview.errors.map((error) => {\n const position = grid.position(error.record, error.column)\n const column = columns.find((item) => item.name === error.column)\n const row = position?.row ?? -1\n\n return (\n <li key={`error-${String(error.record)}-${error.column}`}>\n {t(\n 'table.spreadsheet.cell_error',\n {\n row: row + 1,\n column: column?.label ?? error.column,\n message: error.messages.join(' '),\n },\n 'Row :row, :column: :message',\n )}\n </li>\n )\n })}\n </ul>\n )}\n </div>\n <DialogFooter>\n <Button type=\"button\" variant=\"outline\" onClick={() => setPreview(null)}>\n {t('cancel', {}, 'Cancel')}\n </Button>\n <Button\n type=\"button\"\n disabled={!preview || preview.plan.changes.length === 0}\n onClick={applyPaste}\n >\n {t('table.spreadsheet.paste_apply', {}, 'Apply')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </div>\n )\n}\n"],"mappings":"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"}
@@ -288,7 +288,7 @@ function TranslationManagerView({ schema }) {
288
288
  className: "bg-muted/50",
289
289
  children: /* @__PURE__ */ jsxs("tr", { children: [/* @__PURE__ */ jsx("th", {
290
290
  scope: "col",
291
- className: "bg-muted sticky start-0 z-10 min-w-56 border-b px-3 py-2 text-start font-medium",
291
+ className: "bg-card sticky start-0 z-10 min-w-56 border-b [background-image:linear-gradient(var(--muted),var(--muted))] px-3 py-2 text-start font-medium",
292
292
  children: t("translation-manager.key", {}, "Key")
293
293
  }), locales.map((locale) => /* @__PURE__ */ jsx("th", {
294
294
  scope: "col",