@alfakit/react 0.1.1 → 0.1.6

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 (219) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/components/actions/action-button.d.ts.map +1 -1
  3. package/dist/components/actions/action-button.js +5 -4
  4. package/dist/components/actions/action-button.js.map +1 -1
  5. package/dist/components/actions/action-modals.d.ts.map +1 -1
  6. package/dist/components/actions/action-modals.js +6 -5
  7. package/dist/components/actions/action-modals.js.map +1 -1
  8. package/dist/components/ai/copilot.d.ts +3 -1
  9. package/dist/components/ai/copilot.d.ts.map +1 -1
  10. package/dist/components/ai/copilot.js +4 -1
  11. package/dist/components/ai/copilot.js.map +1 -1
  12. package/dist/components/cms/live-preview.js +3 -2
  13. package/dist/components/cms/live-preview.js.map +1 -1
  14. package/dist/components/cms/page.js +1 -1
  15. package/dist/components/fields/builder.js +15 -6
  16. package/dist/components/fields/builder.js.map +1 -1
  17. package/dist/components/fields/color-picker.js +1 -0
  18. package/dist/components/fields/color-picker.js.map +1 -1
  19. package/dist/components/fields/file-upload.js +11 -10
  20. package/dist/components/fields/file-upload.js.map +1 -1
  21. package/dist/components/fields/image-editor-dialog.js +4 -2
  22. package/dist/components/fields/image-editor-dialog.js.map +1 -1
  23. package/dist/components/fields/item-actions.js +10 -10
  24. package/dist/components/fields/item-actions.js.map +1 -1
  25. package/dist/components/fields/key-value.d.ts.map +1 -1
  26. package/dist/components/fields/key-value.js +3 -3
  27. package/dist/components/fields/key-value.js.map +1 -1
  28. package/dist/components/fields/modal-table-select.js +6 -5
  29. package/dist/components/fields/modal-table-select.js.map +1 -1
  30. package/dist/components/fields/one-time-code-input.js +1 -1
  31. package/dist/components/fields/one-time-code-input.js.map +1 -1
  32. package/dist/components/fields/repeater-table.js +12 -1
  33. package/dist/components/fields/repeater-table.js.map +1 -1
  34. package/dist/components/fields/repeater.js +2 -2
  35. package/dist/components/fields/repeater.js.map +1 -1
  36. package/dist/components/fields/rich-editor.js +2 -1
  37. package/dist/components/fields/rich-editor.js.map +1 -1
  38. package/dist/components/fields/select.js +3 -3
  39. package/dist/components/fields/select.js.map +1 -1
  40. package/dist/components/file-manager/file-manager.js +1 -1
  41. package/dist/components/file-manager/file-manager.js.map +1 -1
  42. package/dist/components/form/form-block.d.ts.map +1 -1
  43. package/dist/components/form/form-block.js +14 -2
  44. package/dist/components/form/form-block.js.map +1 -1
  45. package/dist/components/form/form-context.js +7 -3
  46. package/dist/components/form/form-context.js.map +1 -1
  47. package/dist/components/kanban/kanban.js +4 -3
  48. package/dist/components/kanban/kanban.js.map +1 -1
  49. package/dist/components/layout/fused-group.js +1 -0
  50. package/dist/components/layout/fused-group.js.map +1 -1
  51. package/dist/components/layout/section.js +2 -2
  52. package/dist/components/layout/section.js.map +1 -1
  53. package/dist/components/layout/tabs.d.ts.map +1 -1
  54. package/dist/components/layout/tabs.js +54 -15
  55. package/dist/components/layout/tabs.js.map +1 -1
  56. package/dist/components/panel/app-sidebar.d.ts +2 -3
  57. package/dist/components/panel/app-sidebar.d.ts.map +1 -1
  58. package/dist/components/panel/app-sidebar.js +1 -24
  59. package/dist/components/panel/app-sidebar.js.map +1 -1
  60. package/dist/components/panel/brand.d.ts +10 -0
  61. package/dist/components/panel/brand.d.ts.map +1 -0
  62. package/dist/components/panel/brand.js +37 -0
  63. package/dist/components/panel/brand.js.map +1 -0
  64. package/dist/components/panel/global-search.js +1 -0
  65. package/dist/components/panel/global-search.js.map +1 -1
  66. package/dist/components/panel/index.d.ts +2 -1
  67. package/dist/components/panel/shortcut-keys.js +1 -0
  68. package/dist/components/panel/shortcut-keys.js.map +1 -1
  69. package/dist/components/panel/tenant-menu.js +2 -2
  70. package/dist/components/panel/tenant-menu.js.map +1 -1
  71. package/dist/components/panel/topbar.js +1 -1
  72. package/dist/components/realtime/live-records-pill.d.ts.map +1 -1
  73. package/dist/components/realtime/live-records-pill.js +6 -3
  74. package/dist/components/realtime/live-records-pill.js.map +1 -1
  75. package/dist/components/table/cells.d.ts +6 -0
  76. package/dist/components/table/cells.d.ts.map +1 -1
  77. package/dist/components/table/cells.js +15 -3
  78. package/dist/components/table/cells.js.map +1 -1
  79. package/dist/components/table/column-manager.js +8 -7
  80. package/dist/components/table/column-manager.js.map +1 -1
  81. package/dist/components/table/content-layout.js +2 -1
  82. package/dist/components/table/content-layout.js.map +1 -1
  83. package/dist/components/table/grouping.js +11 -1
  84. package/dist/components/table/grouping.js.map +1 -1
  85. package/dist/components/table/pagination.js +16 -13
  86. package/dist/components/table/pagination.js.map +1 -1
  87. package/dist/components/table/table-block.js +14 -4
  88. package/dist/components/table/table-block.js.map +1 -1
  89. package/dist/components/ui/dialog.d.ts.map +1 -1
  90. package/dist/components/ui/dialog.js +3 -1
  91. package/dist/components/ui/dialog.js.map +1 -1
  92. package/dist/components/ui/popover.d.ts.map +1 -1
  93. package/dist/components/ui/popover.js +3 -1
  94. package/dist/components/ui/popover.js.map +1 -1
  95. package/dist/components/ui/sheet.d.ts.map +1 -1
  96. package/dist/components/ui/sheet.js +3 -1
  97. package/dist/components/ui/sheet.js.map +1 -1
  98. package/dist/components/ui/tooltip.js +3 -1
  99. package/dist/components/ui/tooltip.js.map +1 -1
  100. package/dist/components.css +347 -0
  101. package/dist/context.d.ts +5 -0
  102. package/dist/context.d.ts.map +1 -1
  103. package/dist/context.js +5 -1
  104. package/dist/context.js.map +1 -1
  105. package/dist/create-alfakit.d.ts.map +1 -1
  106. package/dist/create-alfakit.js +8 -5
  107. package/dist/create-alfakit.js.map +1 -1
  108. package/dist/eject-manifest.json +16 -3
  109. package/dist/index.d.ts +6 -3
  110. package/dist/index.js +24 -21
  111. package/dist/layouts/app-layout.d.ts.map +1 -1
  112. package/dist/layouts/app-layout.js +2 -29
  113. package/dist/layouts/app-layout.js.map +1 -1
  114. package/dist/layouts/auth-layout.js +2 -2
  115. package/dist/layouts/auth-layout.js.map +1 -1
  116. package/dist/layouts/fullscreen-layout.js +1 -1
  117. package/dist/layouts/fullscreen-layout.js.map +1 -1
  118. package/dist/layouts/lazy-layouts.js +15 -0
  119. package/dist/layouts/lazy-layouts.js.map +1 -0
  120. package/dist/layouts/max-widths.js +34 -0
  121. package/dist/layouts/max-widths.js.map +1 -0
  122. package/dist/layouts/panel-layouts.d.ts +10 -0
  123. package/dist/layouts/panel-layouts.d.ts.map +1 -0
  124. package/dist/layouts/panel-layouts.js +20 -0
  125. package/dist/layouts/panel-layouts.js.map +1 -0
  126. package/dist/layouts/top-nav-layout.js +2 -2
  127. package/dist/layouts/top-nav-layout.js.map +1 -1
  128. package/dist/pages/page.d.ts.map +1 -1
  129. package/dist/pages/page.js +12 -7
  130. package/dist/pages/page.js.map +1 -1
  131. package/dist/standalone/alfakit-component.js +11 -6
  132. package/dist/standalone/alfakit-component.js.map +1 -1
  133. package/dist/standalone/alfakit-toaster.d.ts.map +1 -1
  134. package/dist/standalone/alfakit-toaster.js +8 -1
  135. package/dist/standalone/alfakit-toaster.js.map +1 -1
  136. package/dist/standalone.css +54 -0
  137. package/dist/starter-kit/dashboard-widgets.d.ts +33 -0
  138. package/dist/starter-kit/dashboard-widgets.d.ts.map +1 -0
  139. package/dist/starter-kit/dashboard-widgets.js +53 -0
  140. package/dist/starter-kit/dashboard-widgets.js.map +1 -0
  141. package/dist/starter-kit/impersonation-banner.js +34 -0
  142. package/dist/starter-kit/impersonation-banner.js.map +1 -0
  143. package/dist/starter-kit/index.d.ts +3 -2
  144. package/dist/starter-kit/index.js +3 -2
  145. package/dist/starter-kit/starter-kit.d.ts +6 -0
  146. package/dist/starter-kit/starter-kit.d.ts.map +1 -1
  147. package/dist/starter-kit/starter-kit.js +18 -7
  148. package/dist/starter-kit/starter-kit.js.map +1 -1
  149. package/dist/starter-kit/widgets-loaded.js +21 -5
  150. package/dist/starter-kit/widgets-loaded.js.map +1 -1
  151. package/dist/starter-kit/widgets-triggers.js +35 -3
  152. package/dist/starter-kit/widgets-triggers.js.map +1 -1
  153. package/dist/starter-kit/widgets.d.ts +13 -5
  154. package/dist/starter-kit/widgets.d.ts.map +1 -1
  155. package/dist/starter-kit/widgets.js +56 -18
  156. package/dist/starter-kit/widgets.js.map +1 -1
  157. package/dist/styles.css +15 -2
  158. package/dist/themes.css +8 -335
  159. package/package.json +2 -2
  160. package/src/components/actions/action-button.tsx +7 -4
  161. package/src/components/actions/action-modals.tsx +13 -1
  162. package/src/components/ai/copilot.tsx +14 -1
  163. package/src/components/cms/live-preview.tsx +5 -2
  164. package/src/components/fields/builder.tsx +14 -5
  165. package/src/components/fields/color-picker.tsx +1 -0
  166. package/src/components/fields/file-upload.tsx +21 -10
  167. package/src/components/fields/image-editor-dialog.tsx +7 -2
  168. package/src/components/fields/item-actions.tsx +32 -9
  169. package/src/components/fields/key-value.tsx +3 -2
  170. package/src/components/fields/modal-table-select.tsx +8 -3
  171. package/src/components/fields/one-time-code-input.tsx +1 -1
  172. package/src/components/fields/repeater-table.tsx +12 -1
  173. package/src/components/fields/repeater.tsx +2 -3
  174. package/src/components/fields/rich-editor.tsx +3 -0
  175. package/src/components/fields/select.tsx +7 -3
  176. package/src/components/file-manager/file-manager.tsx +1 -1
  177. package/src/components/form/form-block.tsx +26 -1
  178. package/src/components/form/form-context.tsx +3 -6
  179. package/src/components/kanban/kanban.tsx +16 -3
  180. package/src/components/layout/fused-group.tsx +5 -1
  181. package/src/components/layout/section.tsx +2 -2
  182. package/src/components/layout/tabs.tsx +72 -17
  183. package/src/components/panel/app-sidebar.tsx +2 -38
  184. package/src/components/panel/brand.tsx +46 -0
  185. package/src/components/panel/global-search.tsx +1 -1
  186. package/src/components/panel/shortcut-keys.tsx +4 -1
  187. package/src/components/panel/tenant-menu.tsx +2 -2
  188. package/src/components/realtime/live-records-pill.tsx +4 -3
  189. package/src/components/table/cells.tsx +27 -5
  190. package/src/components/table/column-manager.tsx +12 -10
  191. package/src/components/table/content-layout.tsx +5 -1
  192. package/src/components/table/grouping.tsx +15 -1
  193. package/src/components/table/pagination.tsx +16 -9
  194. package/src/components/table/table-block.tsx +25 -12
  195. package/src/components/ui/dialog.tsx +5 -1
  196. package/src/components/ui/popover.tsx +5 -1
  197. package/src/components/ui/sheet.tsx +5 -1
  198. package/src/components/ui/tooltip.tsx +5 -1
  199. package/src/context.tsx +10 -0
  200. package/src/create-alfakit.tsx +11 -2
  201. package/src/index.ts +2 -0
  202. package/src/layouts/app-layout.tsx +4 -28
  203. package/src/layouts/auth-layout.tsx +2 -2
  204. package/src/layouts/fullscreen-layout.tsx +1 -1
  205. package/src/layouts/lazy-layouts.ts +14 -0
  206. package/src/layouts/max-widths.ts +29 -0
  207. package/src/layouts/panel-layouts.ts +17 -0
  208. package/src/layouts/top-nav-layout.tsx +2 -2
  209. package/src/pages/page.tsx +21 -12
  210. package/src/standalone/alfakit-component.tsx +18 -7
  211. package/src/standalone/alfakit-toaster.tsx +21 -2
  212. package/src/starter-kit/dashboard-widgets.tsx +78 -0
  213. package/src/starter-kit/impersonation-banner.tsx +48 -0
  214. package/src/starter-kit/index.ts +2 -0
  215. package/src/starter-kit/starter-kit.tsx +31 -4
  216. package/src/starter-kit/widgets-loaded.tsx +23 -1
  217. package/src/starter-kit/widgets-triggers.tsx +37 -2
  218. package/src/starter-kit/widgets.tsx +95 -20
  219. package/src/styles.css +15 -2
@@ -1 +1 @@
1
- {"version":3,"file":"repeater.js","names":[],"sources":["../../../src/components/fields/repeater.tsx"],"sourcesContent":["import type { RepeaterSchema, SchemaComponent } from '@alfakit/core'\nimport {\n VIRTUAL_ESTIMATES,\n appendRepeaterItem,\n cloneIndexedState,\n cloneRepeaterItem,\n columnSpanClasses,\n fieldIds,\n gridColumnsClasses,\n isDeferredPlaceholder,\n moveIndexedState,\n moveRepeaterItem,\n removeIndexedState,\n removeRepeaterItem,\n reorderedItemKeys,\n replacePlaceholder,\n virtualizeOptions,\n} from '@alfakit/core'\nimport { useState } from 'react'\nimport { useFormatter } from '../../context'\nimport { useScrollToErroredItem, useVirtualList } from '../../hooks/use-virtual-list'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport { useField } from '../form/form-context'\nimport { DeferredSchema } from '../layout/deferred'\nimport { useFieldActionContext } from '../schema/field-actions'\nimport { FieldWrapper } from '../schema/field-wrapper'\nimport { SchemaRenderer } from '../schema/schema-renderer'\nimport { Collapsible, CollapsibleContent } from '../ui/collapsible'\nimport {\n AddActionRow,\n CollapseAllActions,\n ItemActionButton,\n ItemHeaderActions,\n useItemActionFallbacks,\n useItemActions,\n useItemMoves,\n useRunItemAction,\n} from './item-actions'\nimport { RepeaterTable } from './repeater-table'\n\n/**\n * Items use the per-index schema from the server when available (so closures see item\n * state) and fall back to the template for freshly added items.\n */\n/**\n * `deferLoading()`: a skeleton until the field scrolls into view, then the field with its\n * items (loaded from the server).\n */\nexport function RepeaterField({ component }: { component: RepeaterSchema }) {\n if (!isDeferredPlaceholder(component)) return <RepeaterFieldContent component={component} />\n\n return (\n <DeferredSchema component={component}>\n {(loaded) => <RepeaterFieldContent component={loaded} />}\n </DeferredSchema>\n )\n}\n\nfunction RepeaterFieldContent({ component }: { component: RepeaterSchema }) {\n const formatter = useFormatter()\n const { value, setValue, error, id, disabled, readOnly, aria } = useField<unknown[] | null>(\n component,\n )\n const context = useFieldActionContext(component)\n const runItemAction = useRunItemAction(context)\n const fallbacks = useItemActionFallbacks(component.addActionLabel)\n const resolve = useItemActions(component, fallbacks)\n // Read-only shows the items but hides add, delete, clone and reorder controls.\n const locked = disabled || readOnly\n const items = value ?? []\n const [collapsed, setCollapsed] = useState<Record<number, boolean>>({})\n const [dragIndex, setDragIndex] = useState<number | null>(null)\n // Long lists render only the visible items (plus a few around them); a multi-column\n // `grid()` is windowed by whole rows, counting its columns from the rendered grid.\n const virtual = useVirtualList(\n items.length,\n virtualizeOptions(\n component.virtualize,\n VIRTUAL_ESTIMATES.item,\n 12,\n component.grid ? 'auto' : 1,\n ),\n )\n const { range, indexes, style, attach, item } = virtual\n useScrollToErroredItem(virtual.list, range.active, component.statePath)\n\n // Collapsed flags are keyed by index, so they move with their item.\n const moveItem = (from: number, to: number) => {\n setValue(moveRepeaterItem(items, from, to))\n setCollapsed((state) => moveIndexedState(state, from, to))\n }\n const removeItem = (index: number) => {\n setValue(removeRepeaterItem(items, index))\n setCollapsed((state) => removeIndexedState(state, index))\n }\n const cloneItem = (index: number) => {\n setValue(cloneRepeaterItem(items, index))\n setCollapsed((state) => cloneIndexedState(state, index))\n }\n // Move buttons: announced, one at a time, focus kept on the moved item.\n const {\n moveWithButton,\n region: moveRegion,\n containerRef: moveContainerRef,\n } = useItemMoves(value, moveItem, (index) => component.items[index]?.label, items.length)\n // A drop runs the reorder action: in the browser, or on the server when customised.\n const dropItem = (from: number, to: number) =>\n runItemAction(resolve('reorder'), { items: reorderedItemKeys(items.length, from, to) }, () =>\n moveItem(from, to),\n )\n const setAllCollapsed = (value: boolean) =>\n setCollapsed(Object.fromEntries(items.map((_, index) => [index, value])))\n const addItem = () =>\n setValue(\n appendRepeaterItem(\n items,\n component.simple\n ? ({ [Object.keys(component.templateState)[0] ?? 'value']: null } as Record<\n string,\n unknown\n >)\n : component.templateState,\n ),\n )\n\n const schemaFor = (index: number): SchemaComponent[] =>\n component.items[index]?.schema ??\n replacePlaceholder(component.template, '__INDEX__', String(index))\n\n const canAdd =\n component.addable &&\n !locked &&\n (component.maxItems == null || items.length < component.maxItems)\n const canDelete =\n component.deletable &&\n !locked &&\n (component.minItems == null || items.length > component.minItems)\n const draggable =\n component.reorderable &&\n component.reorderableWithDragAndDrop !== false &&\n !locked &&\n resolve('reorder') !== null\n const buttons = component.reorderable && component.reorderableWithButtons !== false && !locked\n\n return (\n <FieldWrapper field={component} htmlFor={id} error={error}>\n <div ref={moveContainerRef} className=\"flex flex-col gap-3\">\n {moveRegion}\n {component.table?.length && !component.simple ? (\n <RepeaterTable\n id={id}\n columns={component.table}\n compact={component.compact}\n count={items.length}\n prefixFor={(index) => `${component.statePath}.${index}.`}\n schemaFor={schemaFor}\n labelledBy={component.label ? fieldIds(id).label : undefined}\n describedBy={aria['aria-describedby']}\n reorderable={buttons}\n cloneable={Boolean(component.cloneable) && canAdd}\n deletable={canDelete}\n onMove={moveItem}\n onClone={cloneItem}\n onRemove={removeItem}\n virtual={virtual}\n context={context}\n resolve={(name, index) => resolve(name, component.items[index])}\n extraActionsFor={(index) => component.items[index]?.actions}\n />\n ) : (\n <>\n {component.collapsible && !component.simple && items.length > 0 && (\n <CollapseAllActions\n context={context}\n resolve={(name) => resolve(name)}\n onCollapseAll={() => setAllCollapsed(true)}\n onExpandAll={() => setAllCollapsed(false)}\n />\n )}\n <ul\n id={id}\n aria-labelledby={component.label ? fieldIds(id).label : undefined}\n aria-describedby={aria['aria-describedby']}\n ref={attach}\n style={style}\n className={cn('grid gap-3', component.grid && gridColumnsClasses(component.grid))}\n >\n {indexes.map((index) => {\n const isCollapsed = collapsed[index] ?? component.collapsed ?? false\n const label = component.items[index]?.label ?? null\n const serverItem = component.items[index]\n\n return (\n <li\n key={index}\n ref={item}\n data-index={index}\n aria-setsize={range.active ? items.length : undefined}\n aria-posinset={range.active ? index + 1 : undefined}\n draggable={draggable}\n onDragStart={() => setDragIndex(index)}\n onDragOver={(event) => draggable && event.preventDefault()}\n onDrop={() => {\n if (dragIndex !== null && dragIndex !== index) dropItem(dragIndex, index)\n setDragIndex(null)\n }}\n onDragEnd={() => setDragIndex(null)}\n className={cn(\n 'bg-card min-w-0 rounded-lg border shadow-xs',\n dragIndex === index && 'opacity-50',\n component.simple && 'border-0 shadow-none',\n )}\n >\n <Collapsible open={!isCollapsed}>\n {!component.simple && (\n <div\n className=\"flex flex-wrap items-center gap-1 border-b px-2 py-1.5\"\n data-slot=\"item-header\"\n >\n {draggable && (\n <span\n className=\"text-muted-foreground cursor-grab\"\n title={resolve('reorder', serverItem)?.label ?? undefined}\n aria-hidden=\"true\"\n >\n <Icon\n name={resolve('reorder', serverItem)?.icon ?? 'grip-vertical'}\n />\n </span>\n )}\n {component.itemNumbers && (\n <span className=\"text-muted-foreground text-xs tabular-nums\">\n {formatter.number(index + 1)}\n </span>\n )}\n {label && (\n <span dir=\"auto\" className=\"min-w-0 truncate text-sm font-medium\">\n {label}\n </span>\n )}\n <span className=\"flex-1\" />\n <ItemHeaderActions\n context={context}\n itemKey={String(index)}\n index={index}\n count={items.length}\n resolve={(name) => resolve(name, serverItem)}\n extraActions={locked ? undefined : serverItem?.actions}\n buttons={buttons}\n canClone={Boolean(component.cloneable) && canAdd}\n canDelete={canDelete}\n collapsible={Boolean(component.collapsible)}\n collapsed={isCollapsed}\n onMove={moveWithButton}\n onClone={() => cloneItem(index)}\n onDelete={() => removeItem(index)}\n onToggle={() =>\n setCollapsed((state) => ({ ...state, [index]: !isCollapsed }))\n }\n />\n </div>\n )}\n <CollapsibleContent>\n <div className={cn('flex gap-2', component.simple ? 'items-start' : 'p-4')}>\n <div className=\"flex-1\">\n <SchemaRenderer\n components={schemaFor(index)}\n columns={\n component.simple\n ? { default: 1 }\n : (component.columns ?? { default: 1, lg: 2 })\n }\n className={cn(\n component.simple && 'gap-0',\n '[&_[data-slot=field]_[data-slot=label]]:hidden',\n !component.simple && '[&_[data-slot=field]_[data-slot=label]]:flex',\n )}\n />\n </div>\n {component.simple && canDelete && (\n <ItemActionButton\n action={resolve('delete', serverItem)}\n context={context}\n args={{ item: String(index) }}\n size=\"default\"\n className=\"text-muted-foreground\"\n onClient={() => removeItem(index)}\n />\n )}\n </div>\n </CollapsibleContent>\n </Collapsible>\n </li>\n )\n })}\n </ul>\n </>\n )}\n {canAdd && (\n <AddActionRow alignment={component.addActionAlignment}>\n <ItemActionButton\n action={resolve('add')}\n context={context}\n size=\"sm\"\n onClient={addItem}\n />\n </AddActionRow>\n )}\n </div>\n </FieldWrapper>\n )\n}\n\nexport function columnSpanOf(component: SchemaComponent): string {\n return columnSpanClasses(component.columnSpan)\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"repeater.js","names":[],"sources":["../../../src/components/fields/repeater.tsx"],"sourcesContent":["import type { RepeaterSchema, SchemaComponent } from '@alfakit/core'\nimport {\n VIRTUAL_ESTIMATES,\n appendRepeaterItem,\n cloneIndexedState,\n cloneRepeaterItem,\n columnSpanClasses,\n fieldIds,\n gridColumnsClasses,\n isDeferredPlaceholder,\n moveIndexedState,\n moveRepeaterItem,\n removeIndexedState,\n removeRepeaterItem,\n reorderedItemKeys,\n templateForIndex,\n virtualizeOptions,\n} from '@alfakit/core'\nimport { useState } from 'react'\nimport { useFormatter } from '../../context'\nimport { useScrollToErroredItem, useVirtualList } from '../../hooks/use-virtual-list'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport { useField } from '../form/form-context'\nimport { DeferredSchema } from '../layout/deferred'\nimport { useFieldActionContext } from '../schema/field-actions'\nimport { FieldWrapper } from '../schema/field-wrapper'\nimport { SchemaRenderer } from '../schema/schema-renderer'\nimport { Collapsible, CollapsibleContent } from '../ui/collapsible'\nimport {\n AddActionRow,\n CollapseAllActions,\n ItemActionButton,\n ItemHeaderActions,\n useItemActionFallbacks,\n useItemActions,\n useItemMoves,\n useRunItemAction,\n} from './item-actions'\nimport { RepeaterTable } from './repeater-table'\n\n/**\n * Items use the per-index schema from the server when available (so closures see item\n * state) and fall back to the template for freshly added items.\n */\n/**\n * `deferLoading()`: a skeleton until the field scrolls into view, then the field with its\n * items (loaded from the server).\n */\nexport function RepeaterField({ component }: { component: RepeaterSchema }) {\n if (!isDeferredPlaceholder(component)) return <RepeaterFieldContent component={component} />\n\n return (\n <DeferredSchema component={component}>\n {(loaded) => <RepeaterFieldContent component={loaded} />}\n </DeferredSchema>\n )\n}\n\nfunction RepeaterFieldContent({ component }: { component: RepeaterSchema }) {\n const formatter = useFormatter()\n const { value, setValue, error, id, disabled, readOnly, aria } = useField<unknown[] | null>(\n component,\n )\n const context = useFieldActionContext(component)\n const runItemAction = useRunItemAction(context)\n const fallbacks = useItemActionFallbacks(component.addActionLabel)\n const resolve = useItemActions(component, fallbacks)\n // Read-only shows the items but hides add, delete, clone and reorder controls.\n const locked = disabled || readOnly\n const items = value ?? []\n const [collapsed, setCollapsed] = useState<Record<number, boolean>>({})\n const [dragIndex, setDragIndex] = useState<number | null>(null)\n // Long lists render only the visible items (plus a few around them); a multi-column\n // `grid()` is windowed by whole rows, counting its columns from the rendered grid.\n const virtual = useVirtualList(\n items.length,\n virtualizeOptions(\n component.virtualize,\n VIRTUAL_ESTIMATES.item,\n 12,\n component.grid ? 'auto' : 1,\n ),\n )\n const { range, indexes, style, attach, item } = virtual\n useScrollToErroredItem(virtual.list, range.active, component.statePath)\n\n // Collapsed flags are keyed by index, so they move with their item.\n const moveItem = (from: number, to: number) => {\n setValue(moveRepeaterItem(items, from, to))\n setCollapsed((state) => moveIndexedState(state, from, to))\n }\n const removeItem = (index: number) => {\n setValue(removeRepeaterItem(items, index))\n setCollapsed((state) => removeIndexedState(state, index))\n }\n const cloneItem = (index: number) => {\n setValue(cloneRepeaterItem(items, index))\n setCollapsed((state) => cloneIndexedState(state, index))\n }\n // Move buttons: announced, one at a time, focus kept on the moved item.\n const {\n moveWithButton,\n region: moveRegion,\n containerRef: moveContainerRef,\n } = useItemMoves(value, moveItem, (index) => component.items[index]?.label, items.length)\n // A drop runs the reorder action: in the browser, or on the server when customised.\n const dropItem = (from: number, to: number) =>\n runItemAction(resolve('reorder'), { items: reorderedItemKeys(items.length, from, to) }, () =>\n moveItem(from, to),\n )\n const setAllCollapsed = (value: boolean) =>\n setCollapsed(Object.fromEntries(items.map((_, index) => [index, value])))\n const addItem = () =>\n setValue(\n appendRepeaterItem(\n items,\n component.simple\n ? ({ [Object.keys(component.templateState)[0] ?? 'value']: null } as Record<\n string,\n unknown\n >)\n : component.templateState,\n ),\n )\n\n const schemaFor = (index: number): SchemaComponent[] =>\n component.items[index]?.schema ?? templateForIndex(component.template, index)\n\n const canAdd =\n component.addable &&\n !locked &&\n (component.maxItems == null || items.length < component.maxItems)\n const canDelete =\n component.deletable &&\n !locked &&\n (component.minItems == null || items.length > component.minItems)\n const draggable =\n component.reorderable &&\n component.reorderableWithDragAndDrop !== false &&\n !locked &&\n resolve('reorder') !== null\n const buttons = component.reorderable && component.reorderableWithButtons !== false && !locked\n\n return (\n <FieldWrapper field={component} htmlFor={id} error={error}>\n <div ref={moveContainerRef} className=\"flex flex-col gap-3\">\n {moveRegion}\n {component.table?.length && !component.simple ? (\n <RepeaterTable\n id={id}\n columns={component.table}\n compact={component.compact}\n count={items.length}\n prefixFor={(index) => `${component.statePath}.${index}.`}\n schemaFor={schemaFor}\n labelledBy={component.label ? fieldIds(id).label : undefined}\n describedBy={aria['aria-describedby']}\n reorderable={buttons}\n cloneable={Boolean(component.cloneable) && canAdd}\n deletable={canDelete}\n onMove={moveItem}\n onClone={cloneItem}\n onRemove={removeItem}\n virtual={virtual}\n context={context}\n resolve={(name, index) => resolve(name, component.items[index])}\n extraActionsFor={(index) => component.items[index]?.actions}\n />\n ) : (\n <>\n {component.collapsible && !component.simple && items.length > 0 && (\n <CollapseAllActions\n context={context}\n resolve={(name) => resolve(name)}\n onCollapseAll={() => setAllCollapsed(true)}\n onExpandAll={() => setAllCollapsed(false)}\n />\n )}\n <ul\n id={id}\n aria-labelledby={component.label ? fieldIds(id).label : undefined}\n aria-describedby={aria['aria-describedby']}\n ref={attach}\n style={style}\n className={cn('grid gap-3', component.grid && gridColumnsClasses(component.grid))}\n >\n {indexes.map((index) => {\n const isCollapsed = collapsed[index] ?? component.collapsed ?? false\n const label = component.items[index]?.label ?? null\n const serverItem = component.items[index]\n\n return (\n <li\n key={index}\n ref={item}\n data-index={index}\n aria-setsize={range.active ? items.length : undefined}\n aria-posinset={range.active ? index + 1 : undefined}\n draggable={draggable}\n onDragStart={() => setDragIndex(index)}\n onDragOver={(event) => draggable && event.preventDefault()}\n onDrop={() => {\n if (dragIndex !== null && dragIndex !== index) dropItem(dragIndex, index)\n setDragIndex(null)\n }}\n onDragEnd={() => setDragIndex(null)}\n className={cn(\n 'bg-card min-w-0 rounded-lg border shadow-xs',\n dragIndex === index && 'opacity-50',\n component.simple && 'border-0 shadow-none',\n )}\n >\n <Collapsible open={!isCollapsed}>\n {!component.simple && (\n <div\n className=\"flex flex-wrap items-center gap-1 border-b px-2 py-1.5\"\n data-slot=\"item-header\"\n >\n {draggable && (\n <span\n className=\"text-muted-foreground cursor-grab\"\n title={resolve('reorder', serverItem)?.label ?? undefined}\n aria-hidden=\"true\"\n >\n <Icon\n name={resolve('reorder', serverItem)?.icon ?? 'grip-vertical'}\n />\n </span>\n )}\n {component.itemNumbers && (\n <span className=\"text-muted-foreground text-xs tabular-nums\">\n {formatter.number(index + 1)}\n </span>\n )}\n {label && (\n <span dir=\"auto\" className=\"min-w-0 truncate text-sm font-medium\">\n {label}\n </span>\n )}\n <span className=\"flex-1\" />\n <ItemHeaderActions\n context={context}\n itemKey={String(index)}\n index={index}\n count={items.length}\n resolve={(name) => resolve(name, serverItem)}\n extraActions={locked ? undefined : serverItem?.actions}\n buttons={buttons}\n canClone={Boolean(component.cloneable) && canAdd}\n canDelete={canDelete}\n collapsible={Boolean(component.collapsible)}\n collapsed={isCollapsed}\n onMove={moveWithButton}\n onClone={() => cloneItem(index)}\n onDelete={() => removeItem(index)}\n onToggle={() =>\n setCollapsed((state) => ({ ...state, [index]: !isCollapsed }))\n }\n />\n </div>\n )}\n <CollapsibleContent>\n <div className={cn('flex gap-2', component.simple ? 'items-start' : 'p-4')}>\n <div className=\"flex-1\">\n <SchemaRenderer\n components={schemaFor(index)}\n columns={\n component.simple\n ? { default: 1 }\n : (component.columns ?? { default: 1, lg: 2 })\n }\n className={cn(\n component.simple && 'gap-0',\n '[&_[data-slot=field]_[data-slot=label]]:hidden',\n !component.simple && '[&_[data-slot=field]_[data-slot=label]]:flex',\n )}\n />\n </div>\n {component.simple && canDelete && (\n <ItemActionButton\n action={resolve('delete', serverItem)}\n context={context}\n args={{ item: String(index) }}\n size=\"default\"\n className=\"text-muted-foreground\"\n onClient={() => removeItem(index)}\n />\n )}\n </div>\n </CollapsibleContent>\n </Collapsible>\n </li>\n )\n })}\n </ul>\n </>\n )}\n {canAdd && (\n <AddActionRow alignment={component.addActionAlignment}>\n <ItemActionButton\n action={resolve('add')}\n context={context}\n size=\"sm\"\n onClient={addItem}\n />\n </AddActionRow>\n )}\n </div>\n </FieldWrapper>\n )\n}\n\nexport function columnSpanOf(component: SchemaComponent): string {\n return columnSpanClasses(component.columnSpan)\n}\n"],"mappings":"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"}
@@ -7,7 +7,7 @@ import { Skeleton } from "../ui/skeleton.js";
7
7
  import { FieldWrapper } from "../schema/field-wrapper.js";
8
8
  import { Separator } from "../ui/separator.js";
9
9
  import { ExtensionToolbarButton, RichEditorSidePanel, SuggestionPopup, ToolbarGroupButton, stickyStyle, useRichEditorExtensions } from "./rich-editor-extensions.js";
10
- import { EditorAttachments, TABLE_TOOLBAR_BUTTONS, allToolbarButtons, attachToolbarKeyboard, commandLabel, detailsNodeConfigs, fieldIds, fileAttachmentError, floatingToolbarStyle, focusToolbar, gridNodeConfigs, highlightMarkConfig, htmlToMarkdown, isToolbarGroup, isToolbarShortcut, leadExtensionConfig, linkExtensionOptions, loadRichEditorExtensions, panelUploadOptions, resizableImageAttributes, resizableImageOptions, resolveFloatingToolbar, resolveStickyOffset, setTextColor, showsTableToolbar, smallMarkConfig, subscriptMarkConfig, superscriptMarkConfig, textAlignExtensionConfig, textColorMarkConfig, toEditorDocument, toolbarButtonLabel, toolbarCommands, toolbarPanel, uploadTemporaryFile } from "@alfakit/core";
10
+ import { EditorAttachments, TABLE_TOOLBAR_BUTTONS, allToolbarButtons, attachToolbarKeyboard, commandLabel, detailsNodeConfigs, documentNonce, fieldIds, fileAttachmentError, floatingToolbarStyle, focusToolbar, gridNodeConfigs, highlightMarkConfig, htmlToMarkdown, isToolbarGroup, isToolbarShortcut, leadExtensionConfig, linkExtensionOptions, loadRichEditorExtensions, panelUploadOptions, resizableImageAttributes, resizableImageOptions, resolveFloatingToolbar, resolveStickyOffset, setTextColor, showsTableToolbar, smallMarkConfig, subscriptMarkConfig, superscriptMarkConfig, textAlignExtensionConfig, textColorMarkConfig, toEditorDocument, toolbarButtonLabel, toolbarCommands, toolbarPanel, uploadTemporaryFile } from "@alfakit/core";
11
11
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
12
12
  import { jsx, jsxs } from "react/jsx-runtime";
13
13
  import { ALargeSmallIcon, BaselineIcon, BetweenHorizontalEndIcon, BetweenHorizontalStartIcon, BetweenVerticalEndIcon, BetweenVerticalStartIcon, BoldIcon, CodeIcon, Columns2Icon, Columns3Icon, EraserIcon, Grid2x2XIcon, Heading1Icon, Heading2Icon, Heading3Icon, Heading4Icon, Heading5Icon, Heading6Icon, HighlighterIcon, ImageIcon, ItalicIcon, LinkIcon, ListCollapseIcon, ListIcon, ListOrderedIcon, Minus, PanelTopIcon, PilcrowIcon, QuoteIcon, RedoIcon, RemoveFormattingIcon, Rows3Icon, SquareCodeIcon, SquareXIcon, StrikethroughIcon, SubscriptIcon, SuperscriptIcon, TableCellsMergeIcon, TableCellsSplitIcon, TableIcon, TablePropertiesIcon, TextAlignCenterIcon, TextAlignEndIcon, TextAlignJustifyIcon, TextAlignStartIcon, TypeIcon, UnderlineIcon, UndoIcon } from "lucide-react";
@@ -227,6 +227,7 @@ function RichEditorInput({ component, plugins }) {
227
227
  };
228
228
  useEffect(() => () => attachments.destroy(), [attachments]);
229
229
  const editor = useEditor({
230
+ injectNonce: documentNonce(),
230
231
  extensions: [
231
232
  StarterKit.configure({ link: false }),
232
233
  Link.configure(linkExtensionOptions(component.linkProtocols)),
@@ -1 +1 @@
1
- {"version":3,"file":"rich-editor.js","names":[],"sources":["../../../src/components/fields/rich-editor.tsx"],"sourcesContent":["import type {\n LoadedRichEditorExtensions,\n RichEditorPanel,\n RichEditorSchema,\n ToolCommandContext,\n} from '@alfakit/core'\nimport {\n allToolbarButtons,\n attachToolbarKeyboard,\n commandLabel,\n detailsNodeConfigs,\n EditorAttachments,\n fieldIds,\n fileAttachmentError,\n floatingToolbarStyle,\n focusToolbar,\n gridNodeConfigs,\n highlightMarkConfig,\n htmlToMarkdown,\n isToolbarGroup,\n isToolbarShortcut,\n leadExtensionConfig,\n linkExtensionOptions,\n loadRichEditorExtensions,\n panelUploadOptions,\n resizableImageAttributes,\n resizableImageOptions,\n resolveFloatingToolbar,\n resolveStickyOffset,\n setTextColor,\n showsTableToolbar,\n smallMarkConfig,\n subscriptMarkConfig,\n superscriptMarkConfig,\n TABLE_TOOLBAR_BUTTONS,\n textAlignExtensionConfig,\n textColorMarkConfig,\n toEditorDocument,\n toolbarButtonLabel,\n toolbarCommands,\n toolbarPanel,\n uploadTemporaryFile,\n} from '@alfakit/core'\nimport Image from '@tiptap/extension-image'\nimport Link from '@tiptap/extension-link'\nimport Placeholder from '@tiptap/extension-placeholder'\nimport { TableKit } from '@tiptap/extension-table'\nimport {\n EditorContent,\n Extension,\n Mark,\n Node,\n useEditor,\n type Editor,\n type Extensions,\n} from '@tiptap/react'\nimport StarterKit from '@tiptap/starter-kit'\nimport {\n ALargeSmallIcon,\n BaselineIcon,\n BetweenHorizontalEndIcon,\n BetweenHorizontalStartIcon,\n BetweenVerticalEndIcon,\n BetweenVerticalStartIcon,\n BoldIcon,\n CodeIcon,\n Columns2Icon,\n Columns3Icon,\n EraserIcon,\n Grid2x2XIcon,\n Heading1Icon,\n Heading2Icon,\n Heading3Icon,\n Heading4Icon,\n Heading5Icon,\n Heading6Icon,\n HighlighterIcon,\n ImageIcon,\n ItalicIcon,\n LinkIcon,\n ListCollapseIcon,\n ListIcon,\n ListOrderedIcon,\n Minus,\n PanelTopIcon,\n PilcrowIcon,\n QuoteIcon,\n RedoIcon,\n RemoveFormattingIcon,\n Rows3Icon,\n SquareCodeIcon,\n SquareXIcon,\n StrikethroughIcon,\n SubscriptIcon,\n SuperscriptIcon,\n TableCellsMergeIcon,\n TableCellsSplitIcon,\n TableIcon,\n TablePropertiesIcon,\n TextAlignCenterIcon,\n TextAlignEndIcon,\n TextAlignJustifyIcon,\n TextAlignStartIcon,\n TypeIcon,\n UnderlineIcon,\n UndoIcon,\n} from 'lucide-react'\nimport { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from 'react'\nimport { useActionRunner, usePanel, useT } from '../../context'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport { useField } from '../form/form-context'\nimport { FieldWrapper } from '../schema/field-wrapper'\nimport { Button } from '../ui/button'\nimport { Separator } from '../ui/separator'\nimport { Skeleton } from '../ui/skeleton'\nimport {\n ExtensionToolbarButton,\n RichEditorSidePanel,\n stickyStyle,\n SuggestionPopup,\n ToolbarGroupButton,\n useRichEditorExtensions,\n} from './rich-editor-extensions'\n\ntype MarkConfig = Parameters<typeof Mark.create>[0]\ntype NodeConfig = Parameters<typeof Node.create>[0]\ntype ExtensionConfig = Parameters<typeof Extension.create>[0]\n\n/** Toolbar button icons; what each button does lives in `@alfakit/core` (`TOOLBAR_COMMANDS`). */\nconst ICONS: Record<string, ReactNode> = {\n bold: <BoldIcon />,\n italic: <ItalicIcon />,\n underline: <UnderlineIcon />,\n strike: <StrikethroughIcon />,\n subscript: <SubscriptIcon />,\n superscript: <SuperscriptIcon />,\n code: <CodeIcon />,\n highlight: <HighlighterIcon />,\n textColor: <BaselineIcon />,\n link: <LinkIcon />,\n h1: <Heading1Icon />,\n h2: <Heading2Icon />,\n h3: <Heading3Icon />,\n h4: <Heading4Icon />,\n h5: <Heading5Icon />,\n h6: <Heading6Icon />,\n paragraph: <TypeIcon />,\n heading: <Heading2Icon />,\n // Alignment and column icons point at a side: mirror them right to left.\n alignStart: <TextAlignStartIcon className=\"rtl:-scale-x-100\" />,\n alignCenter: <TextAlignCenterIcon />,\n alignEnd: <TextAlignEndIcon className=\"rtl:-scale-x-100\" />,\n alignJustify: <TextAlignJustifyIcon />,\n blockquote: <QuoteIcon />,\n codeBlock: <SquareCodeIcon />,\n bulletList: <ListIcon />,\n orderedList: <ListOrderedIcon />,\n horizontalRule: <Minus />,\n details: <ListCollapseIcon />,\n lead: <PilcrowIcon />,\n small: <ALargeSmallIcon />,\n grid: <Columns2Icon />,\n gridAddColumnBefore: <BetweenVerticalStartIcon className=\"rtl:-scale-x-100\" />,\n gridAddColumnAfter: <BetweenVerticalEndIcon className=\"rtl:-scale-x-100\" />,\n gridDeleteColumn: <Columns3Icon />,\n gridDelete: <SquareXIcon />,\n table: <TableIcon />,\n tableAddColumnBefore: <BetweenVerticalStartIcon className=\"rtl:-scale-x-100\" />,\n tableAddColumnAfter: <BetweenVerticalEndIcon className=\"rtl:-scale-x-100\" />,\n tableDeleteColumn: <Columns3Icon />,\n tableAddRowBefore: <BetweenHorizontalStartIcon />,\n tableAddRowAfter: <BetweenHorizontalEndIcon />,\n tableDeleteRow: <Rows3Icon />,\n tableMergeCells: <TableCellsMergeIcon />,\n tableSplitCell: <TableCellsSplitIcon />,\n tableToggleHeaderRow: <PanelTopIcon />,\n tableToggleHeaderCell: <TablePropertiesIcon />,\n tableDelete: <Grid2x2XIcon />,\n clearFormatting: <RemoveFormattingIcon />,\n attachFiles: <ImageIcon />,\n undo: <UndoIcon />,\n redo: <RedoIcon />,\n}\n\n/**\n * Resize handles of `resizableImages()` (Tiptap's node view adds bare `data-resize-handle`\n * elements): round dots on the corners, shown on hover and while the image is selected.\n */\nconst RESIZE_HANDLE_CLASSES =\n '[&_[data-resize-handle]]:z-10 [&_[data-resize-handle]]:size-3 [&_[data-resize-handle]]:rounded-full [&_[data-resize-handle]]:border-2 [&_[data-resize-handle]]:border-background [&_[data-resize-handle]]:bg-primary [&_[data-resize-handle]]:opacity-0 [&_[data-resize-container]:hover_[data-resize-handle]]:opacity-100 [&_.ProseMirror-selectednode_[data-resize-handle]]:opacity-100 [&_[data-resize-handle=bottom-right]]:cursor-nwse-resize [&_[data-resize-handle=top-left]]:cursor-nwse-resize [&_[data-resize-handle=bottom-left]]:cursor-nesw-resize [&_[data-resize-handle=top-right]]:cursor-nesw-resize'\n\n/** The image extension, with drag handles for `resizableImages()`. */\nexport function imageExtension(resizable: boolean) {\n if (!resizable) return Image\n\n return Image.extend({\n addAttributes() {\n return resizableImageAttributes(this.parent?.() ?? {})\n },\n }).configure(resizableImageOptions())\n}\n\n/** Extensions for the extra toolbar buttons (only those the toolbar uses are loaded). */\nexport function toolbarExtensions(buttons: string[], markdown: boolean): Extensions {\n const has = (...names: string[]) => names.some((name) => buttons.includes(name))\n const extensions: Extensions = []\n\n if (has('table')) extensions.push(TableKit.configure({ table: { resizable: false } }))\n // Markdown has no syntax for these.\n if (markdown) return extensions\n\n if (has('highlight')) extensions.push(Mark.create(highlightMarkConfig() as MarkConfig))\n if (has('subscript')) extensions.push(Mark.create(subscriptMarkConfig() as MarkConfig))\n if (has('superscript')) extensions.push(Mark.create(superscriptMarkConfig() as MarkConfig))\n if (has('textColor')) extensions.push(Mark.create(textColorMarkConfig() as MarkConfig))\n if (has('alignStart', 'alignCenter', 'alignEnd', 'alignJustify')) {\n extensions.push(Extension.create(textAlignExtensionConfig() as ExtensionConfig))\n }\n if (has('details')) {\n extensions.push(...detailsNodeConfigs().map((config) => Node.create(config as NodeConfig)))\n }\n if (has('small')) extensions.push(Mark.create(smallMarkConfig() as MarkConfig))\n if (has('lead')) extensions.push(Extension.create(leadExtensionConfig() as ExtensionConfig))\n if (has('grid', 'gridDelete', 'gridAddColumnBefore', 'gridAddColumnAfter', 'gridDeleteColumn')) {\n extensions.push(...gridNodeConfigs().map((config) => Node.create(config as NodeConfig)))\n }\n\n return extensions\n}\n\nconst NO_EXTENSIONS: LoadedRichEditorExtensions = { extensions: [], commands: {} }\n\n/**\n * The rich and Markdown editors. Plugin extensions (`RichEditor::plugins()`) load before\n * the editor is created, since Tiptap extensions can't be added afterwards.\n */\nexport function RichEditorField({ component }: { component: RichEditorSchema }) {\n const keys = component.type === 'MarkdownEditor' ? [] : (component.extensions ?? [])\n const signature = keys.join('|')\n const [loaded, setLoaded] = useState<{\n signature: string\n value: LoadedRichEditorExtensions\n } | null>(() => (keys.length === 0 ? { signature, value: NO_EXTENSIONS } : null))\n\n useEffect(() => {\n if (loaded?.signature === signature) return\n\n let cancelled = false\n\n void loadRichEditorExtensions(signature === '' ? [] : signature.split('|')).then((value) => {\n if (!cancelled) setLoaded({ signature, value })\n })\n\n return () => {\n cancelled = true\n }\n }, [signature, loaded?.signature])\n\n if (loaded?.signature !== signature) {\n return <RichEditorLoading component={component} />\n }\n\n return <RichEditorInput key={signature} component={component} plugins={loaded.value} />\n}\n\nfunction RichEditorLoading({ component }: { component: RichEditorSchema }) {\n const { id, error } = useField<unknown>(component)\n\n return (\n <FieldWrapper field={component} htmlFor={id} error={error}>\n <Skeleton className=\"h-40 w-full\" aria-hidden=\"true\" />\n </FieldWrapper>\n )\n}\n\nfunction RichEditorInput({\n component,\n plugins,\n}: {\n component: RichEditorSchema\n plugins: LoadedRichEditorExtensions\n}) {\n const t = useT()\n const panel = usePanel()\n const runner = useActionRunner()\n const { value, setValue, blur, error, id, disabled, readOnly, aria } =\n useField<unknown>(component)\n const fileInput = useRef<HTMLInputElement>(null)\n // ProseMirror reads its DOM attributes on every view update; the ref keeps them current.\n const ariaRef = useRef(aria)\n const isMarkdown = component.type === 'MarkdownEditor'\n // Uploaded images preview from a local URL but are stored by their `tmp:` key.\n const [attachments] = useState(() => new EditorAttachments())\n const editable = !disabled && !readOnly\n const isJson = Boolean(component.json) && !isMarkdown\n // The editor's live instance, for the custom block node views and suggestions.\n const editorRef = useRef<Editor | null>(null)\n const richExtensions = useRichEditorExtensions(component, editorRef)\n // The open toolbar panel (the text colour palette).\n const [openPanel, setOpenPanel] = useState<'textColor' | null>(null)\n // The open side panel (custom blocks or merge tags).\n const [sidePanel, setSidePanel] = useState<RichEditorPanel | null>(() => {\n const initial = component.activePanel ?? null\n\n if (initial === 'customBlocks') return component.customBlocks?.length ? initial : null\n if (initial === 'mergeTags') return component.mergeTags?.length ? initial : null\n\n return null\n })\n const [attachmentError, setAttachmentError] = useState<string | null>(null)\n // Re-render on selection changes so active states and the table row follow the cursor.\n const [, setSelectionTick] = useState(0)\n const sticky = Boolean(component.stickyToolbar || component.stickyPanels)\n const contextRef = useRef(richExtensions.context)\n // Keyboard access to the toolbars (roving tabindex, arrows, Escape, Alt+F10).\n const toolbarElements = useRef<Record<'main' | 'table' | 'floating', HTMLElement | null>>({\n main: null,\n table: null,\n floating: null,\n })\n const toolbars = useCallback(\n () => [\n toolbarElements.current.floating,\n toolbarElements.current.main,\n toolbarElements.current.table,\n ],\n [],\n )\n const attachKeyboard = useCallback(\n (slot: 'main' | 'table' | 'floating', element: HTMLElement | null) => {\n toolbarElements.current[slot] = element\n\n if (!element) return\n\n const detach = attachToolbarKeyboard(element, {\n onEscape: () => editorRef.current?.commands.focus(),\n toolbars,\n })\n\n return () => {\n detach()\n if (toolbarElements.current[slot] === element) toolbarElements.current[slot] = null\n }\n },\n [toolbars],\n )\n const mainToolbarRef = useCallback(\n (element: HTMLElement | null) => attachKeyboard('main', element),\n [attachKeyboard],\n )\n const tableToolbarRef = useCallback(\n (element: HTMLElement | null) => attachKeyboard('table', element),\n [attachKeyboard],\n )\n const floatingToolbarRef = useCallback(\n (element: HTMLElement | null) => attachKeyboard('floating', element),\n [attachKeyboard],\n )\n\n useEffect(() => {\n contextRef.current = richExtensions.context\n })\n\n // How plugin tools open their editor action. The refs are read when a tool runs (on\n // click), never during render.\n const [toolContext] = useState<ToolCommandContext>(() => ({\n runAction: (tool, args) =>\n tool.action\n ? runner.runField(tool.action, { ...contextRef.current, arguments: args })\n : Promise.resolve(undefined),\n editor: () => editorRef.current,\n }))\n\n // Built-in buttons, plugin tools and commands of plugin JavaScript extensions.\n const commands = useMemo(\n () => toolbarCommands(component.editorTools, toolContext, plugins.commands),\n [component.editorTools, plugins.commands, toolContext],\n )\n\n // Field state ↔ editor content: HTML, Markdown (loaded from the server's HTML) or a\n // Tiptap JSON document. `tmp:` upload keys become local preview URLs and back.\n const stateToContent = (): string | Record<string, unknown> => {\n if (isJson) {\n const document = toEditorDocument(value)\n\n return document ? JSON.parse(attachments.toEditor(JSON.stringify(document))) : ''\n }\n\n const markdownHtml = typeof component.html === 'string' ? component.html : null\n\n return attachments.toEditor(((isMarkdown ? markdownHtml : value) as string | null) ?? '')\n }\n const editorToState = (instance: Editor): unknown => {\n if (instance.isEmpty) return null\n if (isJson) return JSON.parse(attachments.toState(JSON.stringify(instance.getJSON())))\n\n const html = instance.getHTML()\n\n return attachments.toState(isMarkdown ? htmlToMarkdown(html) : html)\n }\n\n useEffect(() => () => attachments.destroy(), [attachments])\n\n const editor = useEditor({\n extensions: [\n StarterKit.configure({ link: false }),\n Link.configure(linkExtensionOptions(component.linkProtocols)),\n imageExtension(Boolean(component.resizableImages) && !isMarkdown),\n Placeholder.configure({ placeholder: component.placeholder ?? '' }),\n ...toolbarExtensions(allToolbarButtons(component), isMarkdown),\n ...(isMarkdown ? [] : richExtensions.extensions),\n ...(isMarkdown ? [] : (plugins.extensions as Extensions)),\n ],\n // Markdown is loaded from the server's HTML rendering of it, never parsed as HTML.\n content: stateToContent(),\n editable,\n editorProps: {\n // The mention / merge tag popup takes the arrow, Enter, Tab and Escape keys.\n handleKeyDown: (_view, event) => {\n // Alt+F10: into the floating toolbar, else the main one.\n if (isToolbarShortcut(event)) {\n return focusToolbar(toolbars())\n }\n\n return editorRef.current\n ? richExtensions.suggestions.handleKeyDown(event, editorRef.current)\n : false\n },\n attributes: () => ({\n class: cn(\n 'alfakit-prose min-h-32 px-3 py-2 text-sm outline-none',\n component.resizableImages && RESIZE_HANDLE_CLASSES,\n ),\n // Runtime sizes cannot be Tailwind classes (they would never be generated).\n ...(component.minHeight ? { style: `min-height: ${component.minHeight}px` } : {}),\n id,\n // Each paragraph follows its own script, so Arabic and English mix correctly.\n dir: 'auto',\n role: 'textbox',\n 'aria-multiline': 'true',\n ...(component.label ? { 'aria-labelledby': fieldIds(id).label } : {}),\n ...Object.fromEntries(\n Object.entries(ariaRef.current).map(([name, attribute]) => [name, String(attribute)]),\n ),\n }),\n },\n onUpdate: ({ editor: instance }) => {\n setValue(editorToState(instance))\n },\n onTransaction: ({ editor: instance }) => {\n richExtensions.suggestions.update(instance)\n setSelectionTick((tick) => tick + 1)\n },\n onBlur: () => {\n richExtensions.suggestions.close()\n blur()\n },\n })\n\n useEffect(() => {\n editorRef.current = editor\n }, [editor])\n\n // Keep editor in sync when the server refreshes the state.\n useEffect(() => {\n // Tiptap may replace the instance on mount (e.g. when the editor loads lazily); the\n // replaced one has no schema left, and the new one starts from the current value.\n if (!editor?.schema) return\n\n const current = editorToState(editor)\n const same = isJson\n ? JSON.stringify(toEditorDocument(value)) === JSON.stringify(current)\n : (value ?? '') === (current ?? '')\n\n if (!same) {\n editor.commands.setContent(stateToContent(), { emitUpdate: false })\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [value])\n\n useEffect(() => {\n editor?.setEditable(editable)\n }, [editor, editable])\n\n // Re-apply the editable element's attributes when the error or description changes.\n useEffect(() => {\n ariaRef.current = aria\n\n if (editor && !editor.isDestroyed) {\n editor.view.setProps({})\n }\n }, [editor, aria])\n\n // Measured in the browser once the editor exists (the toolbar only renders then).\n const stickyTop = useMemo(\n () => (sticky && editor ? resolveStickyOffset(component.stickyOffset) : null),\n [sticky, editor, component.stickyOffset],\n )\n\n // A floating toolbar follows its selection while the page scrolls.\n const hasFloatingToolbars = Boolean(component.floatingToolbars)\n\n useEffect(() => {\n if (!hasFloatingToolbars) return\n\n const onScroll = () => setSelectionTick((tick) => tick + 1)\n\n window.addEventListener('scroll', onScroll, { capture: true, passive: true })\n\n return () => window.removeEventListener('scroll', onScroll, { capture: true })\n }, [hasFloatingToolbars])\n\n const pickImage = () => fileInput.current?.click()\n\n const uploadImage = async (file: File) => {\n if (!panel.endpoints.upload || !editor) return\n\n // The server checks again when the form is saved.\n const problem = fileAttachmentError(file, component.fileAttachments)\n\n if (problem) {\n setAttachmentError(\n problem === 'too_large'\n ? t('form.file_too_large', {}, 'This file is too large.')\n : t('form.file_invalid_type', {}, 'This file type is not allowed.'),\n )\n\n return\n }\n\n setAttachmentError(null)\n\n let response: { key: string }\n\n try {\n // Large attachments go in resumable chunks.\n response = await uploadTemporaryFile(\n panel.endpoints.upload,\n file,\n panelUploadOptions(panel, component.fileAttachments.uploadPolicy),\n )\n } catch (error) {\n setAttachmentError(\n (error as { errors?: Record<string, string[]> }).errors?.file?.[0] ??\n t('form.upload_failed', {}, 'The file could not be uploaded.'),\n )\n\n return\n }\n\n const src = attachments.add(response.key, file)\n\n editor.chain().focus().setImage({ src, alt: file.name }).run()\n }\n\n const translate = (key: string, fallback: string) => t(key, {}, fallback)\n\n const iconFor = (name: string): ReactNode => {\n if (ICONS[name]) return ICONS[name]\n\n const tool = component.editorTools?.find((candidate) => candidate.name === name)\n\n return tool?.icon ? (\n <Icon name={tool.icon} />\n ) : (\n <span className=\"text-xs\">{commandLabel(name, commands, translate)}</span>\n )\n }\n\n const runCommand = (name: string) => {\n const button = commands[name]\n\n if (!button || !editor) return\n\n button.run(editor, {\n // Messages arrive translated (`form.link_prompt`, `editor.grid_columns`).\n prompt: (message) => window.prompt(message),\n pickImage,\n togglePanel: (target) => setOpenPanel((current) => (current === target ? null : target)),\n t: translate,\n })\n }\n\n const renderButton = (name: string) => {\n const button = commands[name]\n\n if (!button || !editor) return null\n\n const label = commandLabel(name, commands, translate)\n const active = button.active?.(editor) || (name === 'textColor' && openPanel === name)\n\n return (\n <Button\n key={name}\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-label={label}\n title={label}\n aria-pressed={button.active || name === 'textColor' ? Boolean(active) : undefined}\n disabled={!editable}\n className={cn(active && 'bg-accent text-accent-foreground')}\n onMouseDown={(event) => event.preventDefault()}\n onClick={() => runCommand(name)}\n >\n {iconFor(name)}\n </Button>\n )\n }\n\n /** A toolbar entry: separator, group dropdown, panel toggle or button. */\n const renderEntry = (name: string, index: number) => {\n if (!editor) return null\n\n if (name === '|') {\n return <Separator key={`sep-${index}`} orientation=\"vertical\" className=\"mx-1 h-5\" />\n }\n\n if (isToolbarGroup(name)) {\n const group = component.toolbarButtonGroups?.[name]\n\n return group ? (\n <ToolbarGroupButton\n key={name}\n group={group}\n editor={editor}\n editable={editable}\n commands={commands}\n icons={iconFor}\n translate={translate}\n onRun={runCommand}\n />\n ) : null\n }\n\n const target = toolbarPanel(name)\n\n if (target) {\n return (\n <ExtensionToolbarButton\n key={name}\n name={target}\n component={component}\n editable={editable}\n open={sidePanel === target}\n onToggle={() => setSidePanel((current) => (current === target ? null : target))}\n />\n )\n }\n\n return renderButton(name)\n }\n\n const floating = editable ? resolveFloatingToolbar(editor, component.floatingToolbars) : null\n // A `table` floating toolbar replaces the table row of buttons.\n const tableRow =\n editor &&\n editable &&\n !component.floatingToolbars?.table &&\n showsTableToolbar(allToolbarButtons(component), editor)\n\n return (\n <FieldWrapper field={component} htmlFor={id} error={error}>\n <div\n className={cn(\n 'border-input dark:bg-input/30 focus-within:border-ring focus-within:ring-ring/50 rounded-md border shadow-xs focus-within:ring-[3px]',\n error && 'border-destructive',\n disabled && 'opacity-60',\n )}\n >\n {component.toolbarButtons.length > 0 && editor && (\n <div\n ref={mainToolbarRef}\n role=\"toolbar\"\n aria-label={t('editor.toolbar', {}, 'Formatting')}\n aria-keyshortcuts=\"Alt+F10\"\n data-slot=\"rich-editor-toolbar\"\n className={cn(\n 'flex flex-wrap items-center gap-0.5 border-b p-1',\n component.stickyToolbar && 'bg-background sticky z-10 rounded-t-md',\n )}\n // The offset is a runtime value: no Tailwind class can hold it.\n style={component.stickyToolbar ? stickyStyle(stickyTop ?? '0px') : undefined}\n >\n {component.toolbarButtons.map(renderEntry)}\n </div>\n )}\n {editor && openPanel === 'textColor' && (\n <div\n role=\"group\"\n aria-label={toolbarButtonLabel('textColor', translate)}\n className=\"flex flex-wrap items-center gap-1 border-b p-1\"\n data-slot=\"rich-editor-text-colors\"\n >\n {(component.textColors ?? []).map((color) => (\n <button\n key={color.value}\n type=\"button\"\n title={color.label}\n aria-label={color.label}\n aria-pressed={editor.getAttributes('textColor').color === color.value}\n className=\"focus-visible:ring-ring/50 size-6 rounded-full border shadow-xs outline-none focus-visible:ring-[3px] aria-pressed:ring-2\"\n // Palette colours are runtime values: no Tailwind class can hold them.\n style={{ backgroundColor: color.value }}\n onMouseDown={(event) => event.preventDefault()}\n onClick={() => {\n setTextColor(editor, color.value)\n setOpenPanel(null)\n }}\n />\n ))}\n {component.customTextColors && (\n <input\n type=\"color\"\n aria-label={t('editor.custom_color', {}, 'Custom color')}\n title={t('editor.custom_color', {}, 'Custom color')}\n className=\"size-6 cursor-pointer rounded border bg-transparent p-0\"\n onChange={(event) => setTextColor(editor, event.target.value)}\n />\n )}\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-label={t('editor.remove_color', {}, 'Remove color')}\n title={t('editor.remove_color', {}, 'Remove color')}\n onMouseDown={(event) => event.preventDefault()}\n onClick={() => {\n setTextColor(editor, null)\n setOpenPanel(null)\n }}\n >\n <EraserIcon />\n </Button>\n </div>\n )}\n {tableRow && (\n <div\n ref={tableToolbarRef}\n role=\"toolbar\"\n aria-label={toolbarButtonLabel('table', translate)}\n className=\"flex flex-wrap items-center gap-0.5 border-b p-1\"\n data-slot=\"rich-editor-table-toolbar\"\n >\n {TABLE_TOOLBAR_BUTTONS.map((name) => renderButton(name))}\n </div>\n )}\n <div className=\"@container\">\n <div className=\"flex flex-col-reverse @2xl:flex-row\">\n <EditorContent\n editor={editor}\n className=\"min-w-0 flex-1\"\n style={\n component.maxHeight\n ? { maxHeight: component.maxHeight, overflowY: 'auto' }\n : undefined\n }\n />\n {editor && sidePanel && (\n <RichEditorSidePanel\n panel={sidePanel}\n component={component}\n editable={editable}\n sticky={component.stickyPanels ? (stickyTop ?? '0px') : null}\n onInsertBlock={(blockId) => void richExtensions.insertBlock(blockId)}\n onInsertMergeTag={(tagId) =>\n editor\n .chain()\n .focus()\n .insertContent({ type: 'mergeTag', attrs: { id: tagId } })\n .run()\n }\n onClose={() => setSidePanel(null)}\n />\n )}\n </div>\n </div>\n {editor && floating && floating.buttons.length > 0 && (\n <div\n ref={floatingToolbarRef}\n role=\"toolbar\"\n aria-label={t('editor.floating_toolbar', {}, 'Selection formatting')}\n data-slot=\"rich-editor-floating-toolbar\"\n data-node={floating.node}\n className=\"bg-popover text-popover-foreground fixed z-50 flex items-center gap-0.5 rounded-md border p-1 shadow-md\"\n // Runtime coordinates cannot be Tailwind classes.\n style={floatingToolbarStyle(floating.coords)}\n >\n {floating.buttons.map(renderEntry)}\n </div>\n )}\n <SuggestionPopup\n suggestions={richExtensions.suggestions}\n editor={editor}\n id={`${id}-suggestions`}\n />\n {attachmentError && (\n <p role=\"alert\" className=\"text-destructive px-3 pb-2 text-xs\">\n {attachmentError}\n </p>\n )}\n <input\n ref={fileInput}\n type=\"file\"\n accept={(component.fileAttachments.acceptedFileTypes ?? ['image/*']).join(',')}\n className=\"sr-only\"\n tabIndex={-1}\n aria-hidden=\"true\"\n onChange={(event) => event.target.files?.[0] && void uploadImage(event.target.files[0])}\n />\n </div>\n </FieldWrapper>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"rich-editor.js","names":[],"sources":["../../../src/components/fields/rich-editor.tsx"],"sourcesContent":["import type {\n LoadedRichEditorExtensions,\n RichEditorPanel,\n RichEditorSchema,\n ToolCommandContext,\n} from '@alfakit/core'\nimport {\n allToolbarButtons,\n attachToolbarKeyboard,\n commandLabel,\n detailsNodeConfigs,\n documentNonce,\n EditorAttachments,\n fieldIds,\n fileAttachmentError,\n floatingToolbarStyle,\n focusToolbar,\n gridNodeConfigs,\n highlightMarkConfig,\n htmlToMarkdown,\n isToolbarGroup,\n isToolbarShortcut,\n leadExtensionConfig,\n linkExtensionOptions,\n loadRichEditorExtensions,\n panelUploadOptions,\n resizableImageAttributes,\n resizableImageOptions,\n resolveFloatingToolbar,\n resolveStickyOffset,\n setTextColor,\n showsTableToolbar,\n smallMarkConfig,\n subscriptMarkConfig,\n superscriptMarkConfig,\n TABLE_TOOLBAR_BUTTONS,\n textAlignExtensionConfig,\n textColorMarkConfig,\n toEditorDocument,\n toolbarButtonLabel,\n toolbarCommands,\n toolbarPanel,\n uploadTemporaryFile,\n} from '@alfakit/core'\nimport Image from '@tiptap/extension-image'\nimport Link from '@tiptap/extension-link'\nimport Placeholder from '@tiptap/extension-placeholder'\nimport { TableKit } from '@tiptap/extension-table'\nimport {\n EditorContent,\n Extension,\n Mark,\n Node,\n useEditor,\n type Editor,\n type Extensions,\n} from '@tiptap/react'\nimport StarterKit from '@tiptap/starter-kit'\nimport {\n ALargeSmallIcon,\n BaselineIcon,\n BetweenHorizontalEndIcon,\n BetweenHorizontalStartIcon,\n BetweenVerticalEndIcon,\n BetweenVerticalStartIcon,\n BoldIcon,\n CodeIcon,\n Columns2Icon,\n Columns3Icon,\n EraserIcon,\n Grid2x2XIcon,\n Heading1Icon,\n Heading2Icon,\n Heading3Icon,\n Heading4Icon,\n Heading5Icon,\n Heading6Icon,\n HighlighterIcon,\n ImageIcon,\n ItalicIcon,\n LinkIcon,\n ListCollapseIcon,\n ListIcon,\n ListOrderedIcon,\n Minus,\n PanelTopIcon,\n PilcrowIcon,\n QuoteIcon,\n RedoIcon,\n RemoveFormattingIcon,\n Rows3Icon,\n SquareCodeIcon,\n SquareXIcon,\n StrikethroughIcon,\n SubscriptIcon,\n SuperscriptIcon,\n TableCellsMergeIcon,\n TableCellsSplitIcon,\n TableIcon,\n TablePropertiesIcon,\n TextAlignCenterIcon,\n TextAlignEndIcon,\n TextAlignJustifyIcon,\n TextAlignStartIcon,\n TypeIcon,\n UnderlineIcon,\n UndoIcon,\n} from 'lucide-react'\nimport { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from 'react'\nimport { useActionRunner, usePanel, useT } from '../../context'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport { useField } from '../form/form-context'\nimport { FieldWrapper } from '../schema/field-wrapper'\nimport { Button } from '../ui/button'\nimport { Separator } from '../ui/separator'\nimport { Skeleton } from '../ui/skeleton'\nimport {\n ExtensionToolbarButton,\n RichEditorSidePanel,\n stickyStyle,\n SuggestionPopup,\n ToolbarGroupButton,\n useRichEditorExtensions,\n} from './rich-editor-extensions'\n\ntype MarkConfig = Parameters<typeof Mark.create>[0]\ntype NodeConfig = Parameters<typeof Node.create>[0]\ntype ExtensionConfig = Parameters<typeof Extension.create>[0]\n\n/** Toolbar button icons; what each button does lives in `@alfakit/core` (`TOOLBAR_COMMANDS`). */\nconst ICONS: Record<string, ReactNode> = {\n bold: <BoldIcon />,\n italic: <ItalicIcon />,\n underline: <UnderlineIcon />,\n strike: <StrikethroughIcon />,\n subscript: <SubscriptIcon />,\n superscript: <SuperscriptIcon />,\n code: <CodeIcon />,\n highlight: <HighlighterIcon />,\n textColor: <BaselineIcon />,\n link: <LinkIcon />,\n h1: <Heading1Icon />,\n h2: <Heading2Icon />,\n h3: <Heading3Icon />,\n h4: <Heading4Icon />,\n h5: <Heading5Icon />,\n h6: <Heading6Icon />,\n paragraph: <TypeIcon />,\n heading: <Heading2Icon />,\n // Alignment and column icons point at a side: mirror them right to left.\n alignStart: <TextAlignStartIcon className=\"rtl:-scale-x-100\" />,\n alignCenter: <TextAlignCenterIcon />,\n alignEnd: <TextAlignEndIcon className=\"rtl:-scale-x-100\" />,\n alignJustify: <TextAlignJustifyIcon />,\n blockquote: <QuoteIcon />,\n codeBlock: <SquareCodeIcon />,\n bulletList: <ListIcon />,\n orderedList: <ListOrderedIcon />,\n horizontalRule: <Minus />,\n details: <ListCollapseIcon />,\n lead: <PilcrowIcon />,\n small: <ALargeSmallIcon />,\n grid: <Columns2Icon />,\n gridAddColumnBefore: <BetweenVerticalStartIcon className=\"rtl:-scale-x-100\" />,\n gridAddColumnAfter: <BetweenVerticalEndIcon className=\"rtl:-scale-x-100\" />,\n gridDeleteColumn: <Columns3Icon />,\n gridDelete: <SquareXIcon />,\n table: <TableIcon />,\n tableAddColumnBefore: <BetweenVerticalStartIcon className=\"rtl:-scale-x-100\" />,\n tableAddColumnAfter: <BetweenVerticalEndIcon className=\"rtl:-scale-x-100\" />,\n tableDeleteColumn: <Columns3Icon />,\n tableAddRowBefore: <BetweenHorizontalStartIcon />,\n tableAddRowAfter: <BetweenHorizontalEndIcon />,\n tableDeleteRow: <Rows3Icon />,\n tableMergeCells: <TableCellsMergeIcon />,\n tableSplitCell: <TableCellsSplitIcon />,\n tableToggleHeaderRow: <PanelTopIcon />,\n tableToggleHeaderCell: <TablePropertiesIcon />,\n tableDelete: <Grid2x2XIcon />,\n clearFormatting: <RemoveFormattingIcon />,\n attachFiles: <ImageIcon />,\n undo: <UndoIcon />,\n redo: <RedoIcon />,\n}\n\n/**\n * Resize handles of `resizableImages()` (Tiptap's node view adds bare `data-resize-handle`\n * elements): round dots on the corners, shown on hover and while the image is selected.\n */\nconst RESIZE_HANDLE_CLASSES =\n '[&_[data-resize-handle]]:z-10 [&_[data-resize-handle]]:size-3 [&_[data-resize-handle]]:rounded-full [&_[data-resize-handle]]:border-2 [&_[data-resize-handle]]:border-background [&_[data-resize-handle]]:bg-primary [&_[data-resize-handle]]:opacity-0 [&_[data-resize-container]:hover_[data-resize-handle]]:opacity-100 [&_.ProseMirror-selectednode_[data-resize-handle]]:opacity-100 [&_[data-resize-handle=bottom-right]]:cursor-nwse-resize [&_[data-resize-handle=top-left]]:cursor-nwse-resize [&_[data-resize-handle=bottom-left]]:cursor-nesw-resize [&_[data-resize-handle=top-right]]:cursor-nesw-resize'\n\n/** The image extension, with drag handles for `resizableImages()`. */\nexport function imageExtension(resizable: boolean) {\n if (!resizable) return Image\n\n return Image.extend({\n addAttributes() {\n return resizableImageAttributes(this.parent?.() ?? {})\n },\n }).configure(resizableImageOptions())\n}\n\n/** Extensions for the extra toolbar buttons (only those the toolbar uses are loaded). */\nexport function toolbarExtensions(buttons: string[], markdown: boolean): Extensions {\n const has = (...names: string[]) => names.some((name) => buttons.includes(name))\n const extensions: Extensions = []\n\n if (has('table')) extensions.push(TableKit.configure({ table: { resizable: false } }))\n // Markdown has no syntax for these.\n if (markdown) return extensions\n\n if (has('highlight')) extensions.push(Mark.create(highlightMarkConfig() as MarkConfig))\n if (has('subscript')) extensions.push(Mark.create(subscriptMarkConfig() as MarkConfig))\n if (has('superscript')) extensions.push(Mark.create(superscriptMarkConfig() as MarkConfig))\n if (has('textColor')) extensions.push(Mark.create(textColorMarkConfig() as MarkConfig))\n if (has('alignStart', 'alignCenter', 'alignEnd', 'alignJustify')) {\n extensions.push(Extension.create(textAlignExtensionConfig() as ExtensionConfig))\n }\n if (has('details')) {\n extensions.push(...detailsNodeConfigs().map((config) => Node.create(config as NodeConfig)))\n }\n if (has('small')) extensions.push(Mark.create(smallMarkConfig() as MarkConfig))\n if (has('lead')) extensions.push(Extension.create(leadExtensionConfig() as ExtensionConfig))\n if (has('grid', 'gridDelete', 'gridAddColumnBefore', 'gridAddColumnAfter', 'gridDeleteColumn')) {\n extensions.push(...gridNodeConfigs().map((config) => Node.create(config as NodeConfig)))\n }\n\n return extensions\n}\n\nconst NO_EXTENSIONS: LoadedRichEditorExtensions = { extensions: [], commands: {} }\n\n/**\n * The rich and Markdown editors. Plugin extensions (`RichEditor::plugins()`) load before\n * the editor is created, since Tiptap extensions can't be added afterwards.\n */\nexport function RichEditorField({ component }: { component: RichEditorSchema }) {\n const keys = component.type === 'MarkdownEditor' ? [] : (component.extensions ?? [])\n const signature = keys.join('|')\n const [loaded, setLoaded] = useState<{\n signature: string\n value: LoadedRichEditorExtensions\n } | null>(() => (keys.length === 0 ? { signature, value: NO_EXTENSIONS } : null))\n\n useEffect(() => {\n if (loaded?.signature === signature) return\n\n let cancelled = false\n\n void loadRichEditorExtensions(signature === '' ? [] : signature.split('|')).then((value) => {\n if (!cancelled) setLoaded({ signature, value })\n })\n\n return () => {\n cancelled = true\n }\n }, [signature, loaded?.signature])\n\n if (loaded?.signature !== signature) {\n return <RichEditorLoading component={component} />\n }\n\n return <RichEditorInput key={signature} component={component} plugins={loaded.value} />\n}\n\nfunction RichEditorLoading({ component }: { component: RichEditorSchema }) {\n const { id, error } = useField<unknown>(component)\n\n return (\n <FieldWrapper field={component} htmlFor={id} error={error}>\n <Skeleton className=\"h-40 w-full\" aria-hidden=\"true\" />\n </FieldWrapper>\n )\n}\n\nfunction RichEditorInput({\n component,\n plugins,\n}: {\n component: RichEditorSchema\n plugins: LoadedRichEditorExtensions\n}) {\n const t = useT()\n const panel = usePanel()\n const runner = useActionRunner()\n const { value, setValue, blur, error, id, disabled, readOnly, aria } =\n useField<unknown>(component)\n const fileInput = useRef<HTMLInputElement>(null)\n // ProseMirror reads its DOM attributes on every view update; the ref keeps them current.\n const ariaRef = useRef(aria)\n const isMarkdown = component.type === 'MarkdownEditor'\n // Uploaded images preview from a local URL but are stored by their `tmp:` key.\n const [attachments] = useState(() => new EditorAttachments())\n const editable = !disabled && !readOnly\n const isJson = Boolean(component.json) && !isMarkdown\n // The editor's live instance, for the custom block node views and suggestions.\n const editorRef = useRef<Editor | null>(null)\n const richExtensions = useRichEditorExtensions(component, editorRef)\n // The open toolbar panel (the text colour palette).\n const [openPanel, setOpenPanel] = useState<'textColor' | null>(null)\n // The open side panel (custom blocks or merge tags).\n const [sidePanel, setSidePanel] = useState<RichEditorPanel | null>(() => {\n const initial = component.activePanel ?? null\n\n if (initial === 'customBlocks') return component.customBlocks?.length ? initial : null\n if (initial === 'mergeTags') return component.mergeTags?.length ? initial : null\n\n return null\n })\n const [attachmentError, setAttachmentError] = useState<string | null>(null)\n // Re-render on selection changes so active states and the table row follow the cursor.\n const [, setSelectionTick] = useState(0)\n const sticky = Boolean(component.stickyToolbar || component.stickyPanels)\n const contextRef = useRef(richExtensions.context)\n // Keyboard access to the toolbars (roving tabindex, arrows, Escape, Alt+F10).\n const toolbarElements = useRef<Record<'main' | 'table' | 'floating', HTMLElement | null>>({\n main: null,\n table: null,\n floating: null,\n })\n const toolbars = useCallback(\n () => [\n toolbarElements.current.floating,\n toolbarElements.current.main,\n toolbarElements.current.table,\n ],\n [],\n )\n const attachKeyboard = useCallback(\n (slot: 'main' | 'table' | 'floating', element: HTMLElement | null) => {\n toolbarElements.current[slot] = element\n\n if (!element) return\n\n const detach = attachToolbarKeyboard(element, {\n onEscape: () => editorRef.current?.commands.focus(),\n toolbars,\n })\n\n return () => {\n detach()\n if (toolbarElements.current[slot] === element) toolbarElements.current[slot] = null\n }\n },\n [toolbars],\n )\n const mainToolbarRef = useCallback(\n (element: HTMLElement | null) => attachKeyboard('main', element),\n [attachKeyboard],\n )\n const tableToolbarRef = useCallback(\n (element: HTMLElement | null) => attachKeyboard('table', element),\n [attachKeyboard],\n )\n const floatingToolbarRef = useCallback(\n (element: HTMLElement | null) => attachKeyboard('floating', element),\n [attachKeyboard],\n )\n\n useEffect(() => {\n contextRef.current = richExtensions.context\n })\n\n // How plugin tools open their editor action. The refs are read when a tool runs (on\n // click), never during render.\n const [toolContext] = useState<ToolCommandContext>(() => ({\n runAction: (tool, args) =>\n tool.action\n ? runner.runField(tool.action, { ...contextRef.current, arguments: args })\n : Promise.resolve(undefined),\n editor: () => editorRef.current,\n }))\n\n // Built-in buttons, plugin tools and commands of plugin JavaScript extensions.\n const commands = useMemo(\n () => toolbarCommands(component.editorTools, toolContext, plugins.commands),\n [component.editorTools, plugins.commands, toolContext],\n )\n\n // Field state ↔ editor content: HTML, Markdown (loaded from the server's HTML) or a\n // Tiptap JSON document. `tmp:` upload keys become local preview URLs and back.\n const stateToContent = (): string | Record<string, unknown> => {\n if (isJson) {\n const document = toEditorDocument(value)\n\n return document ? JSON.parse(attachments.toEditor(JSON.stringify(document))) : ''\n }\n\n const markdownHtml = typeof component.html === 'string' ? component.html : null\n\n return attachments.toEditor(((isMarkdown ? markdownHtml : value) as string | null) ?? '')\n }\n const editorToState = (instance: Editor): unknown => {\n if (instance.isEmpty) return null\n if (isJson) return JSON.parse(attachments.toState(JSON.stringify(instance.getJSON())))\n\n const html = instance.getHTML()\n\n return attachments.toState(isMarkdown ? htmlToMarkdown(html) : html)\n }\n\n useEffect(() => () => attachments.destroy(), [attachments])\n\n const editor = useEditor({\n // TipTap injects its base CSS; with the page's CSP nonce a nonce-based policy allows it.\n injectNonce: documentNonce(),\n extensions: [\n StarterKit.configure({ link: false }),\n Link.configure(linkExtensionOptions(component.linkProtocols)),\n imageExtension(Boolean(component.resizableImages) && !isMarkdown),\n Placeholder.configure({ placeholder: component.placeholder ?? '' }),\n ...toolbarExtensions(allToolbarButtons(component), isMarkdown),\n ...(isMarkdown ? [] : richExtensions.extensions),\n ...(isMarkdown ? [] : (plugins.extensions as Extensions)),\n ],\n // Markdown is loaded from the server's HTML rendering of it, never parsed as HTML.\n content: stateToContent(),\n editable,\n editorProps: {\n // The mention / merge tag popup takes the arrow, Enter, Tab and Escape keys.\n handleKeyDown: (_view, event) => {\n // Alt+F10: into the floating toolbar, else the main one.\n if (isToolbarShortcut(event)) {\n return focusToolbar(toolbars())\n }\n\n return editorRef.current\n ? richExtensions.suggestions.handleKeyDown(event, editorRef.current)\n : false\n },\n attributes: () => ({\n class: cn(\n 'alfakit-prose min-h-32 px-3 py-2 text-sm outline-none',\n component.resizableImages && RESIZE_HANDLE_CLASSES,\n ),\n // Runtime sizes cannot be Tailwind classes (they would never be generated).\n ...(component.minHeight ? { style: `min-height: ${component.minHeight}px` } : {}),\n id,\n // Each paragraph follows its own script, so Arabic and English mix correctly.\n dir: 'auto',\n role: 'textbox',\n 'aria-multiline': 'true',\n ...(component.label ? { 'aria-labelledby': fieldIds(id).label } : {}),\n ...Object.fromEntries(\n Object.entries(ariaRef.current).map(([name, attribute]) => [name, String(attribute)]),\n ),\n }),\n },\n onUpdate: ({ editor: instance }) => {\n setValue(editorToState(instance))\n },\n onTransaction: ({ editor: instance }) => {\n richExtensions.suggestions.update(instance)\n setSelectionTick((tick) => tick + 1)\n },\n onBlur: () => {\n richExtensions.suggestions.close()\n blur()\n },\n })\n\n useEffect(() => {\n editorRef.current = editor\n }, [editor])\n\n // Keep editor in sync when the server refreshes the state.\n useEffect(() => {\n // Tiptap may replace the instance on mount (e.g. when the editor loads lazily); the\n // replaced one has no schema left, and the new one starts from the current value.\n if (!editor?.schema) return\n\n const current = editorToState(editor)\n const same = isJson\n ? JSON.stringify(toEditorDocument(value)) === JSON.stringify(current)\n : (value ?? '') === (current ?? '')\n\n if (!same) {\n editor.commands.setContent(stateToContent(), { emitUpdate: false })\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [value])\n\n useEffect(() => {\n editor?.setEditable(editable)\n }, [editor, editable])\n\n // Re-apply the editable element's attributes when the error or description changes.\n useEffect(() => {\n ariaRef.current = aria\n\n if (editor && !editor.isDestroyed) {\n editor.view.setProps({})\n }\n }, [editor, aria])\n\n // Measured in the browser once the editor exists (the toolbar only renders then).\n const stickyTop = useMemo(\n () => (sticky && editor ? resolveStickyOffset(component.stickyOffset) : null),\n [sticky, editor, component.stickyOffset],\n )\n\n // A floating toolbar follows its selection while the page scrolls.\n const hasFloatingToolbars = Boolean(component.floatingToolbars)\n\n useEffect(() => {\n if (!hasFloatingToolbars) return\n\n const onScroll = () => setSelectionTick((tick) => tick + 1)\n\n window.addEventListener('scroll', onScroll, { capture: true, passive: true })\n\n return () => window.removeEventListener('scroll', onScroll, { capture: true })\n }, [hasFloatingToolbars])\n\n const pickImage = () => fileInput.current?.click()\n\n const uploadImage = async (file: File) => {\n if (!panel.endpoints.upload || !editor) return\n\n // The server checks again when the form is saved.\n const problem = fileAttachmentError(file, component.fileAttachments)\n\n if (problem) {\n setAttachmentError(\n problem === 'too_large'\n ? t('form.file_too_large', {}, 'This file is too large.')\n : t('form.file_invalid_type', {}, 'This file type is not allowed.'),\n )\n\n return\n }\n\n setAttachmentError(null)\n\n let response: { key: string }\n\n try {\n // Large attachments go in resumable chunks.\n response = await uploadTemporaryFile(\n panel.endpoints.upload,\n file,\n panelUploadOptions(panel, component.fileAttachments.uploadPolicy),\n )\n } catch (error) {\n setAttachmentError(\n (error as { errors?: Record<string, string[]> }).errors?.file?.[0] ??\n t('form.upload_failed', {}, 'The file could not be uploaded.'),\n )\n\n return\n }\n\n const src = attachments.add(response.key, file)\n\n editor.chain().focus().setImage({ src, alt: file.name }).run()\n }\n\n const translate = (key: string, fallback: string) => t(key, {}, fallback)\n\n const iconFor = (name: string): ReactNode => {\n if (ICONS[name]) return ICONS[name]\n\n const tool = component.editorTools?.find((candidate) => candidate.name === name)\n\n return tool?.icon ? (\n <Icon name={tool.icon} />\n ) : (\n <span className=\"text-xs\">{commandLabel(name, commands, translate)}</span>\n )\n }\n\n const runCommand = (name: string) => {\n const button = commands[name]\n\n if (!button || !editor) return\n\n button.run(editor, {\n // Messages arrive translated (`form.link_prompt`, `editor.grid_columns`).\n prompt: (message) => window.prompt(message),\n pickImage,\n togglePanel: (target) => setOpenPanel((current) => (current === target ? null : target)),\n t: translate,\n })\n }\n\n const renderButton = (name: string) => {\n const button = commands[name]\n\n if (!button || !editor) return null\n\n const label = commandLabel(name, commands, translate)\n const active = button.active?.(editor) || (name === 'textColor' && openPanel === name)\n\n return (\n <Button\n key={name}\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-label={label}\n title={label}\n aria-pressed={button.active || name === 'textColor' ? Boolean(active) : undefined}\n disabled={!editable}\n className={cn(active && 'bg-accent text-accent-foreground')}\n onMouseDown={(event) => event.preventDefault()}\n onClick={() => runCommand(name)}\n >\n {iconFor(name)}\n </Button>\n )\n }\n\n /** A toolbar entry: separator, group dropdown, panel toggle or button. */\n const renderEntry = (name: string, index: number) => {\n if (!editor) return null\n\n if (name === '|') {\n return <Separator key={`sep-${index}`} orientation=\"vertical\" className=\"mx-1 h-5\" />\n }\n\n if (isToolbarGroup(name)) {\n const group = component.toolbarButtonGroups?.[name]\n\n return group ? (\n <ToolbarGroupButton\n key={name}\n group={group}\n editor={editor}\n editable={editable}\n commands={commands}\n icons={iconFor}\n translate={translate}\n onRun={runCommand}\n />\n ) : null\n }\n\n const target = toolbarPanel(name)\n\n if (target) {\n return (\n <ExtensionToolbarButton\n key={name}\n name={target}\n component={component}\n editable={editable}\n open={sidePanel === target}\n onToggle={() => setSidePanel((current) => (current === target ? null : target))}\n />\n )\n }\n\n return renderButton(name)\n }\n\n const floating = editable ? resolveFloatingToolbar(editor, component.floatingToolbars) : null\n // A `table` floating toolbar replaces the table row of buttons.\n const tableRow =\n editor &&\n editable &&\n !component.floatingToolbars?.table &&\n showsTableToolbar(allToolbarButtons(component), editor)\n\n return (\n <FieldWrapper field={component} htmlFor={id} error={error}>\n <div\n className={cn(\n 'border-input dark:bg-input/30 focus-within:border-ring focus-within:ring-ring/50 rounded-md border shadow-xs focus-within:ring-[3px]',\n error && 'border-destructive',\n disabled && 'opacity-60',\n )}\n >\n {component.toolbarButtons.length > 0 && editor && (\n <div\n ref={mainToolbarRef}\n role=\"toolbar\"\n aria-label={t('editor.toolbar', {}, 'Formatting')}\n aria-keyshortcuts=\"Alt+F10\"\n data-slot=\"rich-editor-toolbar\"\n className={cn(\n 'flex flex-wrap items-center gap-0.5 border-b p-1',\n component.stickyToolbar && 'bg-background sticky z-10 rounded-t-md',\n )}\n // The offset is a runtime value: no Tailwind class can hold it.\n style={component.stickyToolbar ? stickyStyle(stickyTop ?? '0px') : undefined}\n >\n {component.toolbarButtons.map(renderEntry)}\n </div>\n )}\n {editor && openPanel === 'textColor' && (\n <div\n role=\"group\"\n aria-label={toolbarButtonLabel('textColor', translate)}\n className=\"flex flex-wrap items-center gap-1 border-b p-1\"\n data-slot=\"rich-editor-text-colors\"\n >\n {(component.textColors ?? []).map((color) => (\n <button\n key={color.value}\n type=\"button\"\n title={color.label}\n aria-label={color.label}\n aria-pressed={editor.getAttributes('textColor').color === color.value}\n className=\"focus-visible:ring-ring/50 size-6 rounded-full border shadow-xs outline-none focus-visible:ring-[3px] aria-pressed:ring-2\"\n // Palette colours are runtime values: no Tailwind class can hold them.\n style={{ backgroundColor: color.value }}\n onMouseDown={(event) => event.preventDefault()}\n onClick={() => {\n setTextColor(editor, color.value)\n setOpenPanel(null)\n }}\n />\n ))}\n {component.customTextColors && (\n <input\n type=\"color\"\n aria-label={t('editor.custom_color', {}, 'Custom color')}\n title={t('editor.custom_color', {}, 'Custom color')}\n className=\"size-6 cursor-pointer rounded border bg-transparent p-0\"\n onChange={(event) => setTextColor(editor, event.target.value)}\n />\n )}\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-label={t('editor.remove_color', {}, 'Remove color')}\n title={t('editor.remove_color', {}, 'Remove color')}\n onMouseDown={(event) => event.preventDefault()}\n onClick={() => {\n setTextColor(editor, null)\n setOpenPanel(null)\n }}\n >\n <EraserIcon />\n </Button>\n </div>\n )}\n {tableRow && (\n <div\n ref={tableToolbarRef}\n role=\"toolbar\"\n aria-label={toolbarButtonLabel('table', translate)}\n className=\"flex flex-wrap items-center gap-0.5 border-b p-1\"\n data-slot=\"rich-editor-table-toolbar\"\n >\n {TABLE_TOOLBAR_BUTTONS.map((name) => renderButton(name))}\n </div>\n )}\n <div className=\"@container\">\n <div className=\"flex flex-col-reverse @2xl:flex-row\">\n <EditorContent\n editor={editor}\n className=\"min-w-0 flex-1\"\n style={\n component.maxHeight\n ? { maxHeight: component.maxHeight, overflowY: 'auto' }\n : undefined\n }\n />\n {editor && sidePanel && (\n <RichEditorSidePanel\n panel={sidePanel}\n component={component}\n editable={editable}\n sticky={component.stickyPanels ? (stickyTop ?? '0px') : null}\n onInsertBlock={(blockId) => void richExtensions.insertBlock(blockId)}\n onInsertMergeTag={(tagId) =>\n editor\n .chain()\n .focus()\n .insertContent({ type: 'mergeTag', attrs: { id: tagId } })\n .run()\n }\n onClose={() => setSidePanel(null)}\n />\n )}\n </div>\n </div>\n {editor && floating && floating.buttons.length > 0 && (\n <div\n ref={floatingToolbarRef}\n role=\"toolbar\"\n aria-label={t('editor.floating_toolbar', {}, 'Selection formatting')}\n data-slot=\"rich-editor-floating-toolbar\"\n data-node={floating.node}\n className=\"bg-popover text-popover-foreground fixed z-50 flex items-center gap-0.5 rounded-md border p-1 shadow-md\"\n // Runtime coordinates cannot be Tailwind classes.\n style={floatingToolbarStyle(floating.coords)}\n >\n {floating.buttons.map(renderEntry)}\n </div>\n )}\n <SuggestionPopup\n suggestions={richExtensions.suggestions}\n editor={editor}\n id={`${id}-suggestions`}\n />\n {attachmentError && (\n <p role=\"alert\" className=\"text-destructive px-3 pb-2 text-xs\">\n {attachmentError}\n </p>\n )}\n <input\n ref={fileInput}\n type=\"file\"\n accept={(component.fileAttachments.acceptedFileTypes ?? ['image/*']).join(',')}\n className=\"sr-only\"\n tabIndex={-1}\n aria-hidden=\"true\"\n onChange={(event) => event.target.files?.[0] && void uploadImage(event.target.files[0])}\n />\n </div>\n </FieldWrapper>\n )\n}\n"],"mappings":"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"}
@@ -47,7 +47,7 @@ function SelectField({ component }) {
47
47
  className: "border-input dark:bg-input/30 focus-visible:ring-ring/50 h-9 w-full rounded-md border bg-transparent px-3 text-sm shadow-xs outline-none focus-visible:ring-[3px]",
48
48
  children: [component.selectablePlaceholder && /* @__PURE__ */ jsx("option", {
49
49
  value: "",
50
- children: component.placeholder ?? ""
50
+ children: component.placeholder ?? t("select_option", {}, "Select an option")
51
51
  }), component.options.map((option) => isOptionGroup(option) ? /* @__PURE__ */ jsx("optgroup", {
52
52
  label: option.label,
53
53
  children: option.options.map((item) => /* @__PURE__ */ jsx("option", {
@@ -79,7 +79,7 @@ function SelectField({ component }) {
79
79
  ...aria,
80
80
  "aria-readonly": readOnly || void 0,
81
81
  className: "w-full",
82
- children: /* @__PURE__ */ jsx(SelectValue, { placeholder: component.placeholder ?? "" })
82
+ children: /* @__PURE__ */ jsx(SelectValue, { placeholder: component.placeholder ?? t("select_option", {}, "Select an option") })
83
83
  }), /* @__PURE__ */ jsxs(SelectContent, { children: [
84
84
  component.selectablePlaceholder && value !== null && value !== void 0 && value !== "" && /* @__PURE__ */ jsx(SelectItem, {
85
85
  value: "__none__",
@@ -280,7 +280,7 @@ function ComboboxSelect({ component, value, setValue, id, disabled, readOnly, er
280
280
  disabled: disabled || readOnly,
281
281
  className: cn("h-auto min-h-9 w-full justify-between px-3 py-1.5 font-normal hover:bg-transparent", error && "border-destructive"),
282
282
  children: [/* @__PURE__ */ jsxs("span", {
283
- className: "flex flex-1 flex-wrap items-center gap-1 text-start",
283
+ className: "flex min-w-0 flex-1 flex-wrap items-center gap-1 text-start",
284
284
  children: [
285
285
  selected.length === 0 && /* @__PURE__ */ jsx("span", {
286
286
  className: "text-muted-foreground",
@@ -1 +1 @@
1
- {"version":3,"file":"select.js","names":[],"sources":["../../../src/components/fields/select.tsx"],"sourcesContent":["import type { FieldAriaAttributes, Option, OptionOrGroup, SelectSchema } from '@alfakit/core'\nimport { htmlLabelToText, isOptionGroup, moveListItem, reorderOffset } from '@alfakit/core'\nimport { CheckIcon, ChevronsUpDownIcon, GripVerticalIcon, XIcon } from 'lucide-react'\nimport { useEffect, useMemo, useRef, useState, type KeyboardEvent, type ReactNode } from 'react'\nimport { useDirection, useT } from '../../context'\nimport { textColorClasses } from '../../lib/colors'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport { useField, useFormStore } from '../form/form-context'\nimport { FieldWrapper } from '../schema/field-wrapper'\nimport { Badge } from '../ui/badge'\nimport { Button } from '../ui/button'\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n} from '../ui/command'\nimport { Popover, PopoverContent, PopoverTrigger } from '../ui/popover'\nimport {\n Select,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectLabel,\n SelectTrigger,\n SelectValue,\n} from '../ui/select'\nimport { Spinner } from '../ui/spinner'\n\nfunction flatten(options: OptionOrGroup[]): Option[] {\n return options.flatMap((option) => (isOptionGroup(option) ? option.options : [option]))\n}\n\n/** Text of an option label for places that can't show markup (`allowHtml()` labels). */\nfunction plainLabel(component: SelectSchema, label: string): string {\n return component.allowHtml ? htmlLabelToText(label) : label\n}\n\nexport function SelectField({ component }: { component: SelectSchema }) {\n const t = useT()\n const noOptions = component.noOptionsMessage ?? t('form.no_options', {}, 'No options available.')\n const { value, setValue, blur, error, id, disabled, readOnly, aria } = useField<\n string | number | Array<string | number> | null\n >(component)\n // Selects have no native read-only mode: lock the control and announce it as read-only.\n const locked = disabled || readOnly\n\n if (component.native && !component.multiple && !component.searchable) {\n return (\n <FieldWrapper field={component} htmlFor={id} error={error}>\n <SelectAffixes component={component} error={error}>\n <select\n id={id}\n name={component.name}\n value={value === null || value === undefined ? '' : String(value)}\n onChange={(event) => setValue(event.target.value === '' ? null : event.target.value)}\n onBlur={blur}\n disabled={locked}\n required={component.required}\n {...aria}\n aria-readonly={readOnly || undefined}\n className=\"border-input dark:bg-input/30 focus-visible:ring-ring/50 h-9 w-full rounded-md border bg-transparent px-3 text-sm shadow-xs outline-none focus-visible:ring-[3px]\"\n >\n {component.selectablePlaceholder && (\n <option value=\"\">{component.placeholder ?? ''}</option>\n )}\n {component.options.map((option) =>\n isOptionGroup(option) ? (\n <optgroup key={option.label} label={option.label}>\n {option.options.map((item) => (\n <option key={item.value} value={item.value} disabled={item.disabled}>\n {plainLabel(component, item.label)}\n </option>\n ))}\n </optgroup>\n ) : (\n <option key={option.value} value={option.value} disabled={option.disabled}>\n {plainLabel(component, option.label)}\n </option>\n ),\n )}\n </select>\n </SelectAffixes>\n </FieldWrapper>\n )\n }\n\n if (!component.multiple && !component.searchable) {\n return (\n <FieldWrapper field={component} htmlFor={id} error={error}>\n <SelectAffixes component={component} error={error}>\n <Select\n value={value === null || value === undefined ? '' : String(value)}\n onValueChange={(next) => setValue(next === '__none__' ? null : next)}\n disabled={locked}\n >\n <SelectTrigger\n id={id}\n {...aria}\n aria-readonly={readOnly || undefined}\n className=\"w-full\"\n >\n <SelectValue placeholder={component.placeholder ?? ''} />\n </SelectTrigger>\n <SelectContent>\n {component.selectablePlaceholder &&\n value !== null &&\n value !== undefined &&\n value !== '' && (\n <SelectItem value=\"__none__\" className=\"text-muted-foreground\">\n {component.placeholder ?? '—'}\n </SelectItem>\n )}\n {component.options.map((option) =>\n isOptionGroup(option) ? (\n <SelectGroup key={option.label}>\n <SelectLabel>{option.label}</SelectLabel>\n {option.options.map((item) => (\n <SelectItem key={item.value} value={item.value} disabled={item.disabled}>\n <OptionLabel option={item} component={component} />\n </SelectItem>\n ))}\n </SelectGroup>\n ) : (\n <SelectItem key={option.value} value={option.value} disabled={option.disabled}>\n <OptionLabel option={option} component={component} />\n </SelectItem>\n ),\n )}\n {component.options.length === 0 && (\n <div data-slot=\"select-empty\" className=\"text-muted-foreground px-2 py-1.5 text-sm\">\n {noOptions}\n </div>\n )}\n </SelectContent>\n </Select>\n </SelectAffixes>\n </FieldWrapper>\n )\n }\n\n return (\n <FieldWrapper field={component} htmlFor={id} error={error}>\n <SelectAffixes component={component} error={error}>\n <ComboboxSelect\n component={component}\n value={value}\n setValue={setValue}\n id={id}\n disabled={disabled}\n readOnly={readOnly}\n error={error}\n aria={aria}\n />\n </SelectAffixes>\n </FieldWrapper>\n )\n}\n\n/** Prefix/suffix text and icons around any of the select variants. */\nfunction SelectAffixes({\n component,\n error,\n children,\n}: {\n component: SelectSchema\n error?: string\n children: ReactNode\n}) {\n const hasPrefix = Boolean(component.prefix || component.prefixIcon)\n const hasSuffix = Boolean(component.suffix || component.suffixIcon)\n\n if (!hasPrefix && !hasSuffix) {\n return children\n }\n\n return (\n <div\n data-slot=\"input-group\"\n className={cn(\n 'border-input dark:bg-input/30 has-[:focus-visible]:border-ring has-[:focus-visible]:ring-ring/50 flex min-h-9 w-full items-stretch overflow-hidden rounded-md border shadow-xs has-[:focus-visible]:ring-[3px]',\n error && 'border-destructive',\n )}\n >\n {hasPrefix && (\n <span className=\"text-muted-foreground bg-muted/50 flex items-center gap-1 border-e px-3 text-sm whitespace-nowrap\">\n <Icon\n name={component.prefixIcon}\n className={component.prefixIconColor && textColorClasses[component.prefixIconColor]}\n />\n {component.prefix}\n </span>\n )}\n <div className=\"min-w-0 flex-1 *:h-full *:w-full *:rounded-none *:border-0 *:bg-transparent *:shadow-none *:focus-visible:ring-0 dark:*:bg-transparent\">\n {children}\n </div>\n {hasSuffix && (\n <span className=\"text-muted-foreground bg-muted/50 flex items-center gap-1 border-s px-3 text-sm whitespace-nowrap\">\n {component.suffix}\n <Icon\n name={component.suffixIcon}\n className={component.suffixIconColor && textColorClasses[component.suffixIconColor]}\n />\n </span>\n )}\n </div>\n )\n}\n\nfunction OptionLabel({ option, component }: { option: Option; component: SelectSchema }) {\n const wrap = component.wrapOptionLabels !== false\n\n return (\n <span className={cn('flex min-w-0 items-center gap-2', !wrap && 'max-w-full')}>\n {option.icon && <Icon name={option.icon} />}\n {component.allowHtml ? (\n <span\n data-slot=\"option-label\"\n className={cn(wrap ? 'break-words' : 'truncate')}\n dangerouslySetInnerHTML={{ __html: option.label }}\n />\n ) : (\n <span data-slot=\"option-label\" className={cn(wrap ? 'break-words' : 'truncate')}>\n {option.label}\n </span>\n )}\n {option.description && (\n <span className=\"text-muted-foreground text-xs\">{option.description}</span>\n )}\n </span>\n )\n}\n\ninterface ComboboxProps {\n component: SelectSchema\n value: string | number | Array<string | number> | null | undefined\n setValue: (value: string | number | Array<string | number> | null) => void\n id: string\n disabled: boolean\n readOnly: boolean\n error?: string\n aria: FieldAriaAttributes\n}\n\nfunction ComboboxSelect({\n component,\n value,\n setValue,\n id,\n disabled,\n readOnly,\n error,\n aria,\n}: ComboboxProps) {\n const t = useT()\n const store = useFormStore()\n const [open, setOpen] = useState(false)\n const [search, setSearch] = useState('')\n const [loading, setLoading] = useState(false)\n const [remoteOptions, setRemoteOptions] = useState<Option[] | null>(null)\n const [labels, setLabels] = useState<Record<string, string>>(component.selectedLabels ?? {})\n const requestIdRef = useRef(0)\n // Values whose labels were already requested: the server may not know a value (deleted\n // record, stale state), so asking again on every render would loop forever.\n const requestedLabelsRef = useRef(new Set<string>())\n\n // Labels the server sends with a refresh win (e.g. after the edit option modal renamed\n // the selected record).\n const knownLabels = useMemo(\n () => ({ ...labels, ...component.selectedLabels }),\n [labels, component.selectedLabels],\n )\n\n const selected = useMemo<string[]>(\n () =>\n Array.isArray(value)\n ? value.map(String)\n : value === null || value === undefined || value === ''\n ? []\n : [String(value)],\n [value],\n )\n const staticOptions = useMemo(() => flatten(component.options), [component.options])\n const options = remoteOptions ?? staticOptions\n const isRemote = Boolean(component.searchable)\n\n // Debounced remote search: every keystroke restarts the timer and invalidates in-flight requests.\n useEffect(() => {\n if (!open || !isRemote) {\n return\n }\n\n const timer = setTimeout(() => {\n const current = ++requestIdRef.current\n setLoading(true)\n\n void store\n .searchOptions(component.statePath, search)\n .then((results) => {\n if (current === requestIdRef.current) {\n setRemoteOptions(results)\n }\n })\n .finally(() => {\n if (current === requestIdRef.current) {\n setLoading(false)\n }\n })\n }, component.searchDebounce ?? 300)\n\n return () => clearTimeout(timer)\n }, [open, search, isRemote, store, component.statePath, component.searchDebounce])\n\n // Resolve labels for values we have not seen yet (e.g. after a server refresh).\n useEffect(() => {\n if (!isRemote) {\n return\n }\n\n const missing = selected.filter(\n (key) =>\n !knownLabels[key] &&\n !requestedLabelsRef.current.has(key) &&\n !staticOptions.some((option) => option.value === key),\n )\n\n if (missing.length === 0) {\n return\n }\n\n for (const key of missing) {\n requestedLabelsRef.current.add(key)\n }\n\n void store\n .optionLabels(component.statePath, missing)\n .then((resolved) => setLabels((current) => ({ ...current, ...resolved })))\n }, [selected, knownLabels, staticOptions, isRemote, store, component.statePath])\n\n const labelFor = (key: string) =>\n knownLabels[key] ??\n options.find((option) => option.value === key)?.label ??\n staticOptions.find((option) => option.value === key)?.label ??\n key\n\n const toggle = (key: string, label: string) => {\n setLabels((current) => ({ ...current, [key]: label }))\n\n if (component.multiple) {\n const next = selected.includes(key)\n ? selected.filter((item) => item !== key)\n : [...selected, key]\n\n if (component.maxItems && next.length > component.maxItems) {\n return\n }\n\n // `minItems()`: the last required selections cannot be removed.\n if (component.minItems && next.length < selected.length && next.length < component.minItems) {\n return\n }\n\n setValue(next)\n } else {\n setValue(selected.includes(key) && component.selectablePlaceholder ? null : key)\n setOpen(false)\n }\n }\n\n const canRemove = !component.minItems || selected.length > component.minItems\n // `reorderable()`: chosen options are listed under the trigger, where they can be dragged\n // or moved with Alt + arrow keys (chips inside the trigger button can't hold controls).\n const reorderable = Boolean(component.multiple && component.reorderable)\n\n const filtered = isRemote\n ? options\n : options.filter((option) =>\n plainLabel(component, option.label).toLowerCase().includes(search.toLowerCase()),\n )\n // Nothing to choose from at all (not a search without matches).\n const isEmpty = search === '' && options.length === 0\n\n const popover = (\n <Popover\n open={open}\n onOpenChange={(next) => {\n setOpen(next)\n\n if (!next) {\n setSearch('')\n store.blur(component.statePath)\n }\n }}\n >\n <PopoverTrigger asChild>\n <Button\n id={id}\n type=\"button\"\n variant=\"outline\"\n data-input=\"\"\n role=\"combobox\"\n aria-expanded={open}\n {...aria}\n aria-readonly={readOnly || undefined}\n disabled={disabled || readOnly}\n className={cn(\n 'h-auto min-h-9 w-full justify-between px-3 py-1.5 font-normal hover:bg-transparent',\n error && 'border-destructive',\n )}\n >\n <span className=\"flex flex-1 flex-wrap items-center gap-1 text-start\">\n {selected.length === 0 && (\n <span className=\"text-muted-foreground\">\n {component.placeholder ?? t('select_option', {}, 'Select an option')}\n </span>\n )}\n {component.multiple && reorderable && selected.length > 0 && (\n <span className=\"text-muted-foreground\">\n {component.placeholder ?? t('select_option', {}, 'Select an option')}\n </span>\n )}\n {component.multiple\n ? !reorderable &&\n selected.map((key) => (\n <Badge key={key} variant=\"secondary\" className=\"gap-1 pe-1\">\n <SelectedLabel component={component} label={labelFor(key)} />\n {!readOnly && !disabled && canRemove && (\n <span\n role=\"button\"\n tabIndex={-1}\n aria-label={t('remove', {}, 'Remove')}\n className=\"hover:bg-foreground/10 rounded-sm\"\n onClick={(event) => {\n event.stopPropagation()\n setValue(selected.filter((item) => item !== key))\n }}\n >\n <XIcon className=\"size-3\" />\n </span>\n )}\n </Badge>\n ))\n : selected[0] !== undefined && (\n <SelectedLabel\n component={component}\n label={labelFor(selected[0])}\n className=\"truncate\"\n />\n )}\n </span>\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-(--radix-popover-trigger-width) p-0\" align=\"start\">\n <Command shouldFilter={false}>\n <CommandInput\n placeholder={\n component.searchPrompt ?? t('form.search_placeholder', {}, 'Type to search…')\n }\n value={search}\n onValueChange={setSearch}\n />\n <CommandList>\n {loading && filtered.length === 0 ? (\n <div\n data-slot=\"select-loading\"\n className=\"text-muted-foreground flex items-center justify-center gap-2 py-6 text-sm\"\n >\n <Spinner />{' '}\n {search !== ''\n ? (component.searchingMessage ?? t('form.searching', {}, 'Searching…'))\n : (component.loadingMessage ?? t('loading', {}, 'Loading…'))}\n </div>\n ) : (\n <CommandEmpty>\n {isEmpty\n ? (component.noOptionsMessage ??\n t('form.no_options', {}, 'No options available.'))\n : (component.noSearchResultsMessage ?? t('no_results', {}, 'No results.'))}\n </CommandEmpty>\n )}\n <CommandGroup>\n {filtered.map((option) => {\n const isSelected = selected.includes(option.value)\n\n return (\n <CommandItem\n key={option.value}\n value={option.value}\n disabled={option.disabled}\n onSelect={() => toggle(option.value, option.label)}\n >\n <CheckIcon className={cn('size-4', isSelected ? 'opacity-100' : 'opacity-0')} />\n <OptionLabel option={option} component={component} />\n </CommandItem>\n )\n })}\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n )\n\n if (!reorderable) {\n return popover\n }\n\n return (\n <>\n {popover}\n <ReorderableSelection\n id={id}\n values={Array.isArray(value) ? value : []}\n labelFor={(key) => plainLabel(component, labelFor(key))}\n locked={disabled || readOnly}\n canRemove={canRemove}\n onChange={setValue}\n />\n </>\n )\n}\n\n/** The chosen options of a `reorderable()` multi-select, in order. */\nfunction ReorderableSelection({\n id,\n values,\n labelFor,\n locked,\n canRemove,\n onChange,\n}: {\n id: string\n values: Array<string | number>\n labelFor: (key: string) => string\n locked: boolean\n canRemove: boolean\n onChange: (values: Array<string | number>) => void\n}) {\n const t = useT()\n const direction = useDirection()\n const listRef = useRef<HTMLUListElement>(null)\n const focusIndex = useRef<number | null>(null)\n const [dragIndex, setDragIndex] = useState<number | null>(null)\n const [announcement, setAnnouncement] = useState('')\n\n useEffect(() => {\n if (focusIndex.current === null) {\n return\n }\n\n listRef.current\n ?.querySelectorAll<HTMLElement>('[data-select-chip]')\n [focusIndex.current]?.focus()\n focusIndex.current = null\n }, [values])\n\n if (values.length === 0) {\n return null\n }\n\n const move = (from: number, to: number) => {\n if (to < 0 || to >= values.length) {\n return\n }\n\n onChange(moveListItem(values, from, to))\n focusIndex.current = to\n setAnnouncement(\n t(\n 'form.option_moved',\n { option: labelFor(String(values[from])), position: to + 1, total: values.length },\n ':option moved to position :position of :total',\n ),\n )\n }\n\n const onKeyDown = (event: KeyboardEvent<HTMLElement>, index: number) => {\n const offset = reorderOffset(event, 'horizontal', direction)\n\n if (locked || offset === null) {\n return\n }\n\n event.preventDefault()\n move(index, index + offset)\n }\n\n return (\n <>\n <ul ref={listRef} data-slot=\"select-reorder-list\" className=\"mt-2 flex flex-wrap gap-1.5\">\n {values.map((item, index) => {\n const key = String(item)\n const label = labelFor(key)\n\n return (\n <li\n key={key}\n data-select-chip=\"\"\n tabIndex={locked ? undefined : 0}\n aria-describedby={locked ? undefined : `${id}-reorder-hint`}\n draggable={!locked}\n onKeyDown={(event) => onKeyDown(event, index)}\n onDragStart={() => setDragIndex(index)}\n onDragOver={(event) => !locked && event.preventDefault()}\n onDrop={() => {\n if (dragIndex !== null && dragIndex !== index) move(dragIndex, index)\n setDragIndex(null)\n }}\n onDragEnd={() => setDragIndex(null)}\n className={cn(\n 'bg-secondary text-secondary-foreground focus-visible:ring-ring/50 inline-flex items-center gap-1 rounded-md border px-1.5 py-0.5 text-xs font-medium outline-none focus-visible:ring-[3px]',\n !locked && 'cursor-grab',\n dragIndex === index && 'opacity-50',\n )}\n >\n {!locked && <GripVerticalIcon aria-hidden className=\"text-muted-foreground size-3\" />}\n <span>{label}</span>\n {!locked && canRemove && (\n <button\n type=\"button\"\n aria-label={t('form.remove_tag', { tag: label }, 'Remove :tag')}\n className=\"hover:bg-foreground/10 rounded-sm\"\n onClick={() => onChange(values.filter((_, i) => i !== index))}\n >\n <XIcon className=\"size-3\" />\n </button>\n )}\n </li>\n )\n })}\n </ul>\n {!locked && (\n <span id={`${id}-reorder-hint`} className=\"sr-only\">\n {t('form.reorder_options_hint', {}, 'Press Alt with an arrow key to move this option.')}\n </span>\n )}\n <span aria-live=\"polite\" aria-atomic=\"true\" className=\"sr-only\">\n {announcement}\n </span>\n </>\n )\n}\n\n/** A selected value's label in the trigger (HTML with `allowHtml()`). */\nfunction SelectedLabel({\n component,\n label,\n className,\n}: {\n component: SelectSchema\n label: string\n className?: string\n}) {\n return component.allowHtml ? (\n <span className={className} dangerouslySetInnerHTML={{ __html: label }} />\n ) : (\n <span className={className}>{label}</span>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"select.js","names":[],"sources":["../../../src/components/fields/select.tsx"],"sourcesContent":["import type { FieldAriaAttributes, Option, OptionOrGroup, SelectSchema } from '@alfakit/core'\nimport { htmlLabelToText, isOptionGroup, moveListItem, reorderOffset } from '@alfakit/core'\nimport { CheckIcon, ChevronsUpDownIcon, GripVerticalIcon, XIcon } from 'lucide-react'\nimport { useEffect, useMemo, useRef, useState, type KeyboardEvent, type ReactNode } from 'react'\nimport { useDirection, useT } from '../../context'\nimport { textColorClasses } from '../../lib/colors'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport { useField, useFormStore } from '../form/form-context'\nimport { FieldWrapper } from '../schema/field-wrapper'\nimport { Badge } from '../ui/badge'\nimport { Button } from '../ui/button'\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n} from '../ui/command'\nimport { Popover, PopoverContent, PopoverTrigger } from '../ui/popover'\nimport {\n Select,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectLabel,\n SelectTrigger,\n SelectValue,\n} from '../ui/select'\nimport { Spinner } from '../ui/spinner'\n\nfunction flatten(options: OptionOrGroup[]): Option[] {\n return options.flatMap((option) => (isOptionGroup(option) ? option.options : [option]))\n}\n\n/** Text of an option label for places that can't show markup (`allowHtml()` labels). */\nfunction plainLabel(component: SelectSchema, label: string): string {\n return component.allowHtml ? htmlLabelToText(label) : label\n}\n\nexport function SelectField({ component }: { component: SelectSchema }) {\n const t = useT()\n const noOptions = component.noOptionsMessage ?? t('form.no_options', {}, 'No options available.')\n const { value, setValue, blur, error, id, disabled, readOnly, aria } = useField<\n string | number | Array<string | number> | null\n >(component)\n // Selects have no native read-only mode: lock the control and announce it as read-only.\n const locked = disabled || readOnly\n\n if (component.native && !component.multiple && !component.searchable) {\n return (\n <FieldWrapper field={component} htmlFor={id} error={error}>\n <SelectAffixes component={component} error={error}>\n <select\n id={id}\n name={component.name}\n value={value === null || value === undefined ? '' : String(value)}\n onChange={(event) => setValue(event.target.value === '' ? null : event.target.value)}\n onBlur={blur}\n disabled={locked}\n required={component.required}\n {...aria}\n aria-readonly={readOnly || undefined}\n className=\"border-input dark:bg-input/30 focus-visible:ring-ring/50 h-9 w-full rounded-md border bg-transparent px-3 text-sm shadow-xs outline-none focus-visible:ring-[3px]\"\n >\n {component.selectablePlaceholder && (\n <option value=\"\">\n {component.placeholder ?? t('select_option', {}, 'Select an option')}\n </option>\n )}\n {component.options.map((option) =>\n isOptionGroup(option) ? (\n <optgroup key={option.label} label={option.label}>\n {option.options.map((item) => (\n <option key={item.value} value={item.value} disabled={item.disabled}>\n {plainLabel(component, item.label)}\n </option>\n ))}\n </optgroup>\n ) : (\n <option key={option.value} value={option.value} disabled={option.disabled}>\n {plainLabel(component, option.label)}\n </option>\n ),\n )}\n </select>\n </SelectAffixes>\n </FieldWrapper>\n )\n }\n\n if (!component.multiple && !component.searchable) {\n return (\n <FieldWrapper field={component} htmlFor={id} error={error}>\n <SelectAffixes component={component} error={error}>\n <Select\n value={value === null || value === undefined ? '' : String(value)}\n onValueChange={(next) => setValue(next === '__none__' ? null : next)}\n disabled={locked}\n >\n <SelectTrigger\n id={id}\n {...aria}\n aria-readonly={readOnly || undefined}\n className=\"w-full\"\n >\n <SelectValue\n placeholder={component.placeholder ?? t('select_option', {}, 'Select an option')}\n />\n </SelectTrigger>\n <SelectContent>\n {component.selectablePlaceholder &&\n value !== null &&\n value !== undefined &&\n value !== '' && (\n <SelectItem value=\"__none__\" className=\"text-muted-foreground\">\n {component.placeholder ?? '—'}\n </SelectItem>\n )}\n {component.options.map((option) =>\n isOptionGroup(option) ? (\n <SelectGroup key={option.label}>\n <SelectLabel>{option.label}</SelectLabel>\n {option.options.map((item) => (\n <SelectItem key={item.value} value={item.value} disabled={item.disabled}>\n <OptionLabel option={item} component={component} />\n </SelectItem>\n ))}\n </SelectGroup>\n ) : (\n <SelectItem key={option.value} value={option.value} disabled={option.disabled}>\n <OptionLabel option={option} component={component} />\n </SelectItem>\n ),\n )}\n {component.options.length === 0 && (\n <div data-slot=\"select-empty\" className=\"text-muted-foreground px-2 py-1.5 text-sm\">\n {noOptions}\n </div>\n )}\n </SelectContent>\n </Select>\n </SelectAffixes>\n </FieldWrapper>\n )\n }\n\n return (\n <FieldWrapper field={component} htmlFor={id} error={error}>\n <SelectAffixes component={component} error={error}>\n <ComboboxSelect\n component={component}\n value={value}\n setValue={setValue}\n id={id}\n disabled={disabled}\n readOnly={readOnly}\n error={error}\n aria={aria}\n />\n </SelectAffixes>\n </FieldWrapper>\n )\n}\n\n/** Prefix/suffix text and icons around any of the select variants. */\nfunction SelectAffixes({\n component,\n error,\n children,\n}: {\n component: SelectSchema\n error?: string\n children: ReactNode\n}) {\n const hasPrefix = Boolean(component.prefix || component.prefixIcon)\n const hasSuffix = Boolean(component.suffix || component.suffixIcon)\n\n if (!hasPrefix && !hasSuffix) {\n return children\n }\n\n return (\n <div\n data-slot=\"input-group\"\n className={cn(\n 'border-input dark:bg-input/30 has-[:focus-visible]:border-ring has-[:focus-visible]:ring-ring/50 flex min-h-9 w-full items-stretch overflow-hidden rounded-md border shadow-xs has-[:focus-visible]:ring-[3px]',\n error && 'border-destructive',\n )}\n >\n {hasPrefix && (\n <span className=\"text-muted-foreground bg-muted/50 flex items-center gap-1 border-e px-3 text-sm whitespace-nowrap\">\n <Icon\n name={component.prefixIcon}\n className={component.prefixIconColor && textColorClasses[component.prefixIconColor]}\n />\n {component.prefix}\n </span>\n )}\n <div className=\"min-w-0 flex-1 *:h-full *:w-full *:rounded-none *:border-0 *:bg-transparent *:shadow-none *:focus-visible:ring-0 dark:*:bg-transparent\">\n {children}\n </div>\n {hasSuffix && (\n <span className=\"text-muted-foreground bg-muted/50 flex items-center gap-1 border-s px-3 text-sm whitespace-nowrap\">\n {component.suffix}\n <Icon\n name={component.suffixIcon}\n className={component.suffixIconColor && textColorClasses[component.suffixIconColor]}\n />\n </span>\n )}\n </div>\n )\n}\n\nfunction OptionLabel({ option, component }: { option: Option; component: SelectSchema }) {\n const wrap = component.wrapOptionLabels !== false\n\n return (\n <span className={cn('flex min-w-0 items-center gap-2', !wrap && 'max-w-full')}>\n {option.icon && <Icon name={option.icon} />}\n {component.allowHtml ? (\n <span\n data-slot=\"option-label\"\n className={cn(wrap ? 'break-words' : 'truncate')}\n dangerouslySetInnerHTML={{ __html: option.label }}\n />\n ) : (\n <span data-slot=\"option-label\" className={cn(wrap ? 'break-words' : 'truncate')}>\n {option.label}\n </span>\n )}\n {option.description && (\n <span className=\"text-muted-foreground text-xs\">{option.description}</span>\n )}\n </span>\n )\n}\n\ninterface ComboboxProps {\n component: SelectSchema\n value: string | number | Array<string | number> | null | undefined\n setValue: (value: string | number | Array<string | number> | null) => void\n id: string\n disabled: boolean\n readOnly: boolean\n error?: string\n aria: FieldAriaAttributes\n}\n\nfunction ComboboxSelect({\n component,\n value,\n setValue,\n id,\n disabled,\n readOnly,\n error,\n aria,\n}: ComboboxProps) {\n const t = useT()\n const store = useFormStore()\n const [open, setOpen] = useState(false)\n const [search, setSearch] = useState('')\n const [loading, setLoading] = useState(false)\n const [remoteOptions, setRemoteOptions] = useState<Option[] | null>(null)\n const [labels, setLabels] = useState<Record<string, string>>(component.selectedLabels ?? {})\n const requestIdRef = useRef(0)\n // Values whose labels were already requested: the server may not know a value (deleted\n // record, stale state), so asking again on every render would loop forever.\n const requestedLabelsRef = useRef(new Set<string>())\n\n // Labels the server sends with a refresh win (e.g. after the edit option modal renamed\n // the selected record).\n const knownLabels = useMemo(\n () => ({ ...labels, ...component.selectedLabels }),\n [labels, component.selectedLabels],\n )\n\n const selected = useMemo<string[]>(\n () =>\n Array.isArray(value)\n ? value.map(String)\n : value === null || value === undefined || value === ''\n ? []\n : [String(value)],\n [value],\n )\n const staticOptions = useMemo(() => flatten(component.options), [component.options])\n const options = remoteOptions ?? staticOptions\n const isRemote = Boolean(component.searchable)\n\n // Debounced remote search: every keystroke restarts the timer and invalidates in-flight requests.\n useEffect(() => {\n if (!open || !isRemote) {\n return\n }\n\n const timer = setTimeout(() => {\n const current = ++requestIdRef.current\n setLoading(true)\n\n void store\n .searchOptions(component.statePath, search)\n .then((results) => {\n if (current === requestIdRef.current) {\n setRemoteOptions(results)\n }\n })\n .finally(() => {\n if (current === requestIdRef.current) {\n setLoading(false)\n }\n })\n }, component.searchDebounce ?? 300)\n\n return () => clearTimeout(timer)\n }, [open, search, isRemote, store, component.statePath, component.searchDebounce])\n\n // Resolve labels for values we have not seen yet (e.g. after a server refresh).\n useEffect(() => {\n if (!isRemote) {\n return\n }\n\n const missing = selected.filter(\n (key) =>\n !knownLabels[key] &&\n !requestedLabelsRef.current.has(key) &&\n !staticOptions.some((option) => option.value === key),\n )\n\n if (missing.length === 0) {\n return\n }\n\n for (const key of missing) {\n requestedLabelsRef.current.add(key)\n }\n\n void store\n .optionLabels(component.statePath, missing)\n .then((resolved) => setLabels((current) => ({ ...current, ...resolved })))\n }, [selected, knownLabels, staticOptions, isRemote, store, component.statePath])\n\n const labelFor = (key: string) =>\n knownLabels[key] ??\n options.find((option) => option.value === key)?.label ??\n staticOptions.find((option) => option.value === key)?.label ??\n key\n\n const toggle = (key: string, label: string) => {\n setLabels((current) => ({ ...current, [key]: label }))\n\n if (component.multiple) {\n const next = selected.includes(key)\n ? selected.filter((item) => item !== key)\n : [...selected, key]\n\n if (component.maxItems && next.length > component.maxItems) {\n return\n }\n\n // `minItems()`: the last required selections cannot be removed.\n if (component.minItems && next.length < selected.length && next.length < component.minItems) {\n return\n }\n\n setValue(next)\n } else {\n setValue(selected.includes(key) && component.selectablePlaceholder ? null : key)\n setOpen(false)\n }\n }\n\n const canRemove = !component.minItems || selected.length > component.minItems\n // `reorderable()`: chosen options are listed under the trigger, where they can be dragged\n // or moved with Alt + arrow keys (chips inside the trigger button can't hold controls).\n const reorderable = Boolean(component.multiple && component.reorderable)\n\n const filtered = isRemote\n ? options\n : options.filter((option) =>\n plainLabel(component, option.label).toLowerCase().includes(search.toLowerCase()),\n )\n // Nothing to choose from at all (not a search without matches).\n const isEmpty = search === '' && options.length === 0\n\n const popover = (\n <Popover\n open={open}\n onOpenChange={(next) => {\n setOpen(next)\n\n if (!next) {\n setSearch('')\n store.blur(component.statePath)\n }\n }}\n >\n <PopoverTrigger asChild>\n <Button\n id={id}\n type=\"button\"\n variant=\"outline\"\n data-input=\"\"\n role=\"combobox\"\n aria-expanded={open}\n {...aria}\n aria-readonly={readOnly || undefined}\n disabled={disabled || readOnly}\n className={cn(\n 'h-auto min-h-9 w-full justify-between px-3 py-1.5 font-normal hover:bg-transparent',\n error && 'border-destructive',\n )}\n >\n <span className=\"flex min-w-0 flex-1 flex-wrap items-center gap-1 text-start\">\n {selected.length === 0 && (\n <span className=\"text-muted-foreground\">\n {component.placeholder ?? t('select_option', {}, 'Select an option')}\n </span>\n )}\n {component.multiple && reorderable && selected.length > 0 && (\n <span className=\"text-muted-foreground\">\n {component.placeholder ?? t('select_option', {}, 'Select an option')}\n </span>\n )}\n {component.multiple\n ? !reorderable &&\n selected.map((key) => (\n <Badge key={key} variant=\"secondary\" className=\"gap-1 pe-1\">\n <SelectedLabel component={component} label={labelFor(key)} />\n {!readOnly && !disabled && canRemove && (\n <span\n role=\"button\"\n tabIndex={-1}\n aria-label={t('remove', {}, 'Remove')}\n className=\"hover:bg-foreground/10 rounded-sm\"\n onClick={(event) => {\n event.stopPropagation()\n setValue(selected.filter((item) => item !== key))\n }}\n >\n <XIcon className=\"size-3\" />\n </span>\n )}\n </Badge>\n ))\n : selected[0] !== undefined && (\n <SelectedLabel\n component={component}\n label={labelFor(selected[0])}\n className=\"truncate\"\n />\n )}\n </span>\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-(--radix-popover-trigger-width) p-0\" align=\"start\">\n <Command shouldFilter={false}>\n <CommandInput\n placeholder={\n component.searchPrompt ?? t('form.search_placeholder', {}, 'Type to search…')\n }\n value={search}\n onValueChange={setSearch}\n />\n <CommandList>\n {loading && filtered.length === 0 ? (\n <div\n data-slot=\"select-loading\"\n className=\"text-muted-foreground flex items-center justify-center gap-2 py-6 text-sm\"\n >\n <Spinner />{' '}\n {search !== ''\n ? (component.searchingMessage ?? t('form.searching', {}, 'Searching…'))\n : (component.loadingMessage ?? t('loading', {}, 'Loading…'))}\n </div>\n ) : (\n <CommandEmpty>\n {isEmpty\n ? (component.noOptionsMessage ??\n t('form.no_options', {}, 'No options available.'))\n : (component.noSearchResultsMessage ?? t('no_results', {}, 'No results.'))}\n </CommandEmpty>\n )}\n <CommandGroup>\n {filtered.map((option) => {\n const isSelected = selected.includes(option.value)\n\n return (\n <CommandItem\n key={option.value}\n value={option.value}\n disabled={option.disabled}\n onSelect={() => toggle(option.value, option.label)}\n >\n <CheckIcon className={cn('size-4', isSelected ? 'opacity-100' : 'opacity-0')} />\n <OptionLabel option={option} component={component} />\n </CommandItem>\n )\n })}\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n )\n\n if (!reorderable) {\n return popover\n }\n\n return (\n <>\n {popover}\n <ReorderableSelection\n id={id}\n values={Array.isArray(value) ? value : []}\n labelFor={(key) => plainLabel(component, labelFor(key))}\n locked={disabled || readOnly}\n canRemove={canRemove}\n onChange={setValue}\n />\n </>\n )\n}\n\n/** The chosen options of a `reorderable()` multi-select, in order. */\nfunction ReorderableSelection({\n id,\n values,\n labelFor,\n locked,\n canRemove,\n onChange,\n}: {\n id: string\n values: Array<string | number>\n labelFor: (key: string) => string\n locked: boolean\n canRemove: boolean\n onChange: (values: Array<string | number>) => void\n}) {\n const t = useT()\n const direction = useDirection()\n const listRef = useRef<HTMLUListElement>(null)\n const focusIndex = useRef<number | null>(null)\n const [dragIndex, setDragIndex] = useState<number | null>(null)\n const [announcement, setAnnouncement] = useState('')\n\n useEffect(() => {\n if (focusIndex.current === null) {\n return\n }\n\n listRef.current\n ?.querySelectorAll<HTMLElement>('[data-select-chip]')\n [focusIndex.current]?.focus()\n focusIndex.current = null\n }, [values])\n\n if (values.length === 0) {\n return null\n }\n\n const move = (from: number, to: number) => {\n if (to < 0 || to >= values.length) {\n return\n }\n\n onChange(moveListItem(values, from, to))\n focusIndex.current = to\n setAnnouncement(\n t(\n 'form.option_moved',\n { option: labelFor(String(values[from])), position: to + 1, total: values.length },\n ':option moved to position :position of :total',\n ),\n )\n }\n\n const onKeyDown = (event: KeyboardEvent<HTMLElement>, index: number) => {\n const offset = reorderOffset(event, 'horizontal', direction)\n\n if (locked || offset === null) {\n return\n }\n\n event.preventDefault()\n move(index, index + offset)\n }\n\n return (\n <>\n <ul ref={listRef} data-slot=\"select-reorder-list\" className=\"mt-2 flex flex-wrap gap-1.5\">\n {values.map((item, index) => {\n const key = String(item)\n const label = labelFor(key)\n\n return (\n <li\n key={key}\n data-select-chip=\"\"\n tabIndex={locked ? undefined : 0}\n aria-describedby={locked ? undefined : `${id}-reorder-hint`}\n draggable={!locked}\n onKeyDown={(event) => onKeyDown(event, index)}\n onDragStart={() => setDragIndex(index)}\n onDragOver={(event) => !locked && event.preventDefault()}\n onDrop={() => {\n if (dragIndex !== null && dragIndex !== index) move(dragIndex, index)\n setDragIndex(null)\n }}\n onDragEnd={() => setDragIndex(null)}\n className={cn(\n 'bg-secondary text-secondary-foreground focus-visible:ring-ring/50 inline-flex items-center gap-1 rounded-md border px-1.5 py-0.5 text-xs font-medium outline-none focus-visible:ring-[3px]',\n !locked && 'cursor-grab',\n dragIndex === index && 'opacity-50',\n )}\n >\n {!locked && <GripVerticalIcon aria-hidden className=\"text-muted-foreground size-3\" />}\n <span>{label}</span>\n {!locked && canRemove && (\n <button\n type=\"button\"\n aria-label={t('form.remove_tag', { tag: label }, 'Remove :tag')}\n className=\"hover:bg-foreground/10 rounded-sm\"\n onClick={() => onChange(values.filter((_, i) => i !== index))}\n >\n <XIcon className=\"size-3\" />\n </button>\n )}\n </li>\n )\n })}\n </ul>\n {!locked && (\n <span id={`${id}-reorder-hint`} className=\"sr-only\">\n {t('form.reorder_options_hint', {}, 'Press Alt with an arrow key to move this option.')}\n </span>\n )}\n <span aria-live=\"polite\" aria-atomic=\"true\" className=\"sr-only\">\n {announcement}\n </span>\n </>\n )\n}\n\n/** A selected value's label in the trigger (HTML with `allowHtml()`). */\nfunction SelectedLabel({\n component,\n label,\n className,\n}: {\n component: SelectSchema\n label: string\n className?: string\n}) {\n return component.allowHtml ? (\n <span className={className} dangerouslySetInnerHTML={{ __html: label }} />\n ) : (\n <span className={className}>{label}</span>\n )\n}\n"],"mappings":"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"}
@@ -207,7 +207,7 @@ function FileManagerView({ schema, onChoose, onCancel }) {
207
207
  }),
208
208
  /* @__PURE__ */ jsx("nav", {
209
209
  "aria-label": tt("breadcrumb", {}, "Folder path"),
210
- className: "min-w-0 flex-1",
210
+ className: "min-w-0 flex-[1_1_12rem]",
211
211
  "data-slot": "file-manager-breadcrumb",
212
212
  children: /* @__PURE__ */ jsxs("ol", {
213
213
  className: "flex min-w-0 flex-wrap items-center gap-1 text-sm",