@alfakit/react 0.1.2 → 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 (171) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/components/actions/action-modals.js +4 -0
  3. package/dist/components/actions/action-modals.js.map +1 -1
  4. package/dist/components/ai/copilot.d.ts +3 -1
  5. package/dist/components/ai/copilot.d.ts.map +1 -1
  6. package/dist/components/ai/copilot.js +4 -1
  7. package/dist/components/ai/copilot.js.map +1 -1
  8. package/dist/components/cms/live-preview.js +3 -2
  9. package/dist/components/cms/live-preview.js.map +1 -1
  10. package/dist/components/cms/page.js +1 -1
  11. package/dist/components/fields/builder.js +15 -6
  12. package/dist/components/fields/builder.js.map +1 -1
  13. package/dist/components/fields/image-editor-dialog.js +4 -2
  14. package/dist/components/fields/image-editor-dialog.js.map +1 -1
  15. package/dist/components/fields/item-actions.js +10 -10
  16. package/dist/components/fields/item-actions.js.map +1 -1
  17. package/dist/components/fields/key-value.d.ts.map +1 -1
  18. package/dist/components/fields/key-value.js +3 -3
  19. package/dist/components/fields/key-value.js.map +1 -1
  20. package/dist/components/fields/modal-table-select.js +6 -5
  21. package/dist/components/fields/modal-table-select.js.map +1 -1
  22. package/dist/components/fields/repeater.js +2 -2
  23. package/dist/components/fields/repeater.js.map +1 -1
  24. package/dist/components/fields/rich-editor.js +2 -1
  25. package/dist/components/fields/rich-editor.js.map +1 -1
  26. package/dist/components/form/form-block.js +1 -1
  27. package/dist/components/form/form-block.js.map +1 -1
  28. package/dist/components/form/form-context.js +2 -2
  29. package/dist/components/form/form-context.js.map +1 -1
  30. package/dist/components/kanban/kanban.js +4 -3
  31. package/dist/components/kanban/kanban.js.map +1 -1
  32. package/dist/components/layout/section.js +2 -2
  33. package/dist/components/layout/section.js.map +1 -1
  34. package/dist/components/panel/app-sidebar.d.ts +2 -3
  35. package/dist/components/panel/app-sidebar.d.ts.map +1 -1
  36. package/dist/components/panel/app-sidebar.js +1 -24
  37. package/dist/components/panel/app-sidebar.js.map +1 -1
  38. package/dist/components/panel/brand.d.ts +10 -0
  39. package/dist/components/panel/brand.d.ts.map +1 -0
  40. package/dist/components/panel/brand.js +37 -0
  41. package/dist/components/panel/brand.js.map +1 -0
  42. package/dist/components/panel/index.d.ts +2 -1
  43. package/dist/components/panel/topbar.js +1 -1
  44. package/dist/components/realtime/live-records-pill.d.ts.map +1 -1
  45. package/dist/components/realtime/live-records-pill.js +6 -3
  46. package/dist/components/realtime/live-records-pill.js.map +1 -1
  47. package/dist/components/table/cells.d.ts +6 -0
  48. package/dist/components/table/cells.d.ts.map +1 -1
  49. package/dist/components/table/cells.js +6 -2
  50. package/dist/components/table/cells.js.map +1 -1
  51. package/dist/components/table/column-manager.js +8 -7
  52. package/dist/components/table/column-manager.js.map +1 -1
  53. package/dist/components/table/content-layout.js +2 -1
  54. package/dist/components/table/content-layout.js.map +1 -1
  55. package/dist/components/table/pagination.js +16 -13
  56. package/dist/components/table/pagination.js.map +1 -1
  57. package/dist/components/table/table-block.js +14 -4
  58. package/dist/components/table/table-block.js.map +1 -1
  59. package/dist/components/ui/dialog.d.ts.map +1 -1
  60. package/dist/components/ui/dialog.js +3 -1
  61. package/dist/components/ui/dialog.js.map +1 -1
  62. package/dist/components/ui/popover.d.ts.map +1 -1
  63. package/dist/components/ui/popover.js +3 -1
  64. package/dist/components/ui/popover.js.map +1 -1
  65. package/dist/components/ui/sheet.d.ts.map +1 -1
  66. package/dist/components/ui/sheet.js +3 -1
  67. package/dist/components/ui/sheet.js.map +1 -1
  68. package/dist/components/ui/tooltip.js +3 -1
  69. package/dist/components/ui/tooltip.js.map +1 -1
  70. package/dist/context.d.ts +5 -0
  71. package/dist/context.d.ts.map +1 -1
  72. package/dist/context.js +5 -1
  73. package/dist/context.js.map +1 -1
  74. package/dist/create-alfakit.d.ts.map +1 -1
  75. package/dist/create-alfakit.js +8 -5
  76. package/dist/create-alfakit.js.map +1 -1
  77. package/dist/eject-manifest.json +16 -3
  78. package/dist/index.d.ts +6 -3
  79. package/dist/index.js +24 -21
  80. package/dist/layouts/app-layout.d.ts.map +1 -1
  81. package/dist/layouts/app-layout.js +2 -29
  82. package/dist/layouts/app-layout.js.map +1 -1
  83. package/dist/layouts/auth-layout.js +2 -2
  84. package/dist/layouts/auth-layout.js.map +1 -1
  85. package/dist/layouts/fullscreen-layout.js +1 -1
  86. package/dist/layouts/fullscreen-layout.js.map +1 -1
  87. package/dist/layouts/lazy-layouts.js +15 -0
  88. package/dist/layouts/lazy-layouts.js.map +1 -0
  89. package/dist/layouts/max-widths.js +34 -0
  90. package/dist/layouts/max-widths.js.map +1 -0
  91. package/dist/layouts/panel-layouts.d.ts +10 -0
  92. package/dist/layouts/panel-layouts.d.ts.map +1 -0
  93. package/dist/layouts/panel-layouts.js +20 -0
  94. package/dist/layouts/panel-layouts.js.map +1 -0
  95. package/dist/layouts/top-nav-layout.js +2 -2
  96. package/dist/layouts/top-nav-layout.js.map +1 -1
  97. package/dist/pages/page.d.ts.map +1 -1
  98. package/dist/pages/page.js +12 -7
  99. package/dist/pages/page.js.map +1 -1
  100. package/dist/standalone/alfakit-component.js +11 -6
  101. package/dist/standalone/alfakit-component.js.map +1 -1
  102. package/dist/standalone.css +7 -0
  103. package/dist/starter-kit/dashboard-widgets.d.ts +33 -0
  104. package/dist/starter-kit/dashboard-widgets.d.ts.map +1 -0
  105. package/dist/starter-kit/dashboard-widgets.js +53 -0
  106. package/dist/starter-kit/dashboard-widgets.js.map +1 -0
  107. package/dist/starter-kit/impersonation-banner.js +34 -0
  108. package/dist/starter-kit/impersonation-banner.js.map +1 -0
  109. package/dist/starter-kit/index.d.ts +3 -2
  110. package/dist/starter-kit/index.js +3 -2
  111. package/dist/starter-kit/starter-kit.d.ts +6 -0
  112. package/dist/starter-kit/starter-kit.d.ts.map +1 -1
  113. package/dist/starter-kit/starter-kit.js +18 -7
  114. package/dist/starter-kit/starter-kit.js.map +1 -1
  115. package/dist/starter-kit/widgets-loaded.js +20 -4
  116. package/dist/starter-kit/widgets-loaded.js.map +1 -1
  117. package/dist/starter-kit/widgets-triggers.js +34 -3
  118. package/dist/starter-kit/widgets-triggers.js.map +1 -1
  119. package/dist/starter-kit/widgets.d.ts +13 -5
  120. package/dist/starter-kit/widgets.d.ts.map +1 -1
  121. package/dist/starter-kit/widgets.js +56 -18
  122. package/dist/starter-kit/widgets.js.map +1 -1
  123. package/dist/styles.css +15 -2
  124. package/dist/themes.css +6 -1
  125. package/package.json +2 -2
  126. package/src/components/actions/action-modals.tsx +10 -0
  127. package/src/components/ai/copilot.tsx +14 -1
  128. package/src/components/cms/live-preview.tsx +5 -2
  129. package/src/components/fields/builder.tsx +14 -5
  130. package/src/components/fields/image-editor-dialog.tsx +7 -2
  131. package/src/components/fields/item-actions.tsx +32 -9
  132. package/src/components/fields/key-value.tsx +3 -2
  133. package/src/components/fields/modal-table-select.tsx +8 -3
  134. package/src/components/fields/repeater.tsx +2 -3
  135. package/src/components/fields/rich-editor.tsx +3 -0
  136. package/src/components/form/form-block.tsx +2 -1
  137. package/src/components/form/form-context.tsx +2 -2
  138. package/src/components/kanban/kanban.tsx +16 -3
  139. package/src/components/layout/section.tsx +2 -2
  140. package/src/components/panel/app-sidebar.tsx +2 -38
  141. package/src/components/panel/brand.tsx +46 -0
  142. package/src/components/realtime/live-records-pill.tsx +4 -3
  143. package/src/components/table/cells.tsx +9 -2
  144. package/src/components/table/column-manager.tsx +12 -10
  145. package/src/components/table/content-layout.tsx +5 -1
  146. package/src/components/table/pagination.tsx +16 -9
  147. package/src/components/table/table-block.tsx +25 -12
  148. package/src/components/ui/dialog.tsx +5 -1
  149. package/src/components/ui/popover.tsx +5 -1
  150. package/src/components/ui/sheet.tsx +5 -1
  151. package/src/components/ui/tooltip.tsx +5 -1
  152. package/src/context.tsx +10 -0
  153. package/src/create-alfakit.tsx +11 -2
  154. package/src/index.ts +2 -0
  155. package/src/layouts/app-layout.tsx +4 -28
  156. package/src/layouts/auth-layout.tsx +2 -2
  157. package/src/layouts/fullscreen-layout.tsx +1 -1
  158. package/src/layouts/lazy-layouts.ts +14 -0
  159. package/src/layouts/max-widths.ts +29 -0
  160. package/src/layouts/panel-layouts.ts +17 -0
  161. package/src/layouts/top-nav-layout.tsx +2 -2
  162. package/src/pages/page.tsx +21 -12
  163. package/src/standalone/alfakit-component.tsx +18 -7
  164. package/src/starter-kit/dashboard-widgets.tsx +78 -0
  165. package/src/starter-kit/impersonation-banner.tsx +48 -0
  166. package/src/starter-kit/index.ts +2 -0
  167. package/src/starter-kit/starter-kit.tsx +31 -4
  168. package/src/starter-kit/widgets-loaded.tsx +22 -0
  169. package/src/starter-kit/widgets-triggers.tsx +36 -1
  170. package/src/starter-kit/widgets.tsx +95 -20
  171. package/src/styles.css +15 -2
@@ -1 +1 @@
1
- {"version":3,"file":"kanban.js","names":[],"sources":["../../../src/components/kanban/kanban.tsx"],"sourcesContent":["import type {\n KanbanCardSchema,\n KanbanColumnSchema,\n KanbanEnvironment,\n KanbanLaneSchema,\n KanbanSchema,\n KanbanWidgetSchema,\n LocaleFormatter,\n} from '@alfakit/core'\nimport {\n KanbanController,\n attachKanbanPointer,\n clientErrorNotification,\n createKanbanFiltersStore,\n kanbanActiveFilters,\n kanbanCardsIn,\n kanbanInitials,\n kanbanWipState,\n} from '@alfakit/core'\nimport { router } from '@inertiajs/react'\nimport {\n CalendarIcon,\n ChevronRightIcon,\n ChevronsLeftRightIcon,\n ChevronsRightLeftIcon,\n FilterIcon,\n PlusIcon,\n SearchIcon,\n} from 'lucide-react'\nimport { Fragment, useEffect, useId, useRef, useState, type KeyboardEvent } from 'react'\nimport { useActionRunner, useDirection, useFormatter, usePanel, useT } from '../../context'\nimport { useStore } from '../../hooks/use-store'\nimport { badgeColorClasses, colorClass, cssColor } from '../../lib/colors'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport { usePageActionContext } from '../actions/action-context'\nimport { ActionList } from '../actions/action-list'\nimport { FormProvider } from '../form/form-context'\nimport { showToast } from '../notifications/flash-toasts'\nimport { SchemaRenderer } from '../schema/schema-renderer'\nimport { Avatar, AvatarFallback, AvatarImage } from '../ui/avatar'\nimport { Badge } from '../ui/badge'\nimport { Button } from '../ui/button'\nimport { Card, CardTitle } from '../ui/card'\nimport { Input } from '../ui/input'\nimport { Popover, PopoverContent, PopoverTrigger } from '../ui/popover'\nimport { Spinner } from '../ui/spinner'\n\ntype Translate = ReturnType<typeof useT>\n\n/**\n * The board of a `KanbanPage` (schema component `kanban`) or a `KanbanWidget`\n * (alfasix/alfakit-kanban). Cards move by dragging (mouse, pen, touch) or with the\n * keyboard, and every move is saved in one request.\n */\nexport function Kanban({\n component,\n widget,\n}: {\n component?: KanbanSchema\n widget?: KanbanWidgetSchema\n}) {\n const board = component ?? widget?.kanban\n\n return board ? <KanbanBoard key={board.actionComponent} board={board} /> : null\n}\n\nfunction KanbanBoard({ board }: { board: KanbanSchema }) {\n const runner = useActionRunner()\n const page = usePageActionContext()\n const panel = usePanel()\n const t = useT()\n const direction = useDirection()\n const formatter = useFormatter()\n const labelId = useId()\n const instructionsId = useId()\n const environment = (): KanbanEnvironment => ({\n runner,\n token: page.token,\n t,\n notify: (notifications) => notifications.forEach((notification) => showToast(notification)),\n error: (message) => showToast(clientErrorNotification('kanban', message)),\n visit: (url) => router.visit(url),\n })\n // One controller per board (the parent keys this view by its action component).\n const [controller] = useState(() => new KanbanController(board, environment()))\n const [filters] = useState(() =>\n createKanbanFiltersStore(board, page.token, panel.endpoints.schemaOptions),\n )\n const root = useRef<HTMLDivElement>(null)\n const cards = useRef(new Map<string, HTMLElement>())\n const [focused, setFocused] = useState<string | null>(null)\n\n useEffect(() => {\n controller.setEnvironment(environment())\n })\n\n const first = useRef(true)\n\n useEffect(() => {\n if (first.current) {\n first.current = false\n\n return\n }\n\n controller.setBoard(board)\n }, [controller, board])\n\n useEffect(\n () => (root.current ? attachKanbanPointer(root.current, controller) : undefined),\n [controller],\n )\n useEffect(() => controller.startPolling(), [controller])\n useEffect(\n () => () => {\n controller.destroy()\n filters?.destroy()\n },\n [controller, filters],\n )\n\n const state = useStore(controller.store)\n const schema = controller.schema\n const lanes = controller.lanes()\n const keys = state.columns.flatMap((column) => column.cards.map((card) => card.key))\n const current = focused !== null && keys.includes(focused) ? focused : (keys[0] ?? null)\n\n const focus = (key: string | undefined) => {\n if (!key) return\n setFocused(key)\n requestAnimationFrame(() => cards.current.get(key)?.focus())\n }\n\n // A card picked up with the keyboard moves to another list: keep the focus on it.\n const picked = state.picked\n\n useEffect(() => {\n if (picked?.via === 'keyboard') {\n const element = cards.current.get(picked.key)\n\n if (element && document.activeElement !== element) element.focus()\n }\n }, [picked])\n\n const onKeyDown = (key: string) => (event: KeyboardEvent<HTMLElement>) => {\n if (event.target !== event.currentTarget) return\n\n const result = controller.handleKey(key, event, direction)\n\n if (!result.handled) return\n\n event.preventDefault()\n\n if (result.open) controller.open(key)\n else focus(result.focus)\n }\n\n const template = state.columns\n .map((column) => (state.collapsed.has(column.key) ? '3.25rem' : 'minmax(16rem, 20rem)'))\n .join(' ')\n\n return (\n <Card\n ref={root}\n role=\"region\"\n aria-labelledby={labelId}\n className=\"gap-3 py-4\"\n data-slot=\"kanban\"\n >\n <div className=\"flex flex-wrap items-center gap-2 px-4\" data-slot=\"kanban-toolbar\">\n {schema.heading ? (\n <CardTitle id={labelId} className=\"text-base\">\n {schema.heading}\n </CardTitle>\n ) : (\n <span id={labelId} className=\"sr-only\">\n {t('kanban.label', {}, 'Kanban board')}\n </span>\n )}\n <div className=\"ms-auto flex w-full flex-wrap items-center gap-2 sm:w-auto\">\n {state.loading && (\n <Spinner className=\"size-4\" aria-label={t('kanban.loading', {}, 'Loading board')} />\n )}\n {schema.searchable && (\n <KanbanSearch controller={controller} search={state.search} t={t} />\n )}\n {filters && <KanbanFilters controller={controller} store={filters} t={t} />}\n </div>\n </div>\n <p id={instructionsId} className=\"sr-only\">\n {t(\n 'kanban.instructions',\n {},\n 'Press Space to pick up a card. While it is picked up, use the arrow keys to move it, Space to drop it and Escape to cancel.',\n )}\n </p>\n <div\n className=\"relative overflow-x-auto overscroll-x-contain px-4 pb-2\"\n data-slot=\"kanban-scroller\"\n >\n <div\n className=\"grid w-max min-w-full snap-x gap-3\"\n style={{ gridTemplateColumns: template }}\n >\n {state.columns.map((column) => (\n <ColumnHeader\n key={column.key}\n column={column}\n id={`${labelId}-column-${column.key}`}\n collapsed={state.collapsed.has(column.key)}\n creatable={Boolean(column.creatable && schema.createAction)}\n filtered={state.search !== '' || kanbanActiveFilters(state.filters) > 0}\n onToggle={() => controller.toggleColumn(column.key)}\n onCreate={() => controller.create(column.key)}\n t={t}\n />\n ))}\n {lanes.map((lane) => {\n const laneId = lane ? `${labelId}-lane-${lane.key}` : undefined\n const collapsedLane = lane !== null && state.collapsedLanes.has(lane.key)\n\n return (\n <Fragment key={lane?.key ?? '__board'}>\n {lane && (\n <LaneHeader\n lane={lane}\n id={laneId!}\n count={state.columns.reduce(\n (sum, column) => sum + kanbanCardsIn(column, lane.key).length,\n 0,\n )}\n collapsed={collapsedLane}\n onToggle={() => controller.toggleLane(lane.key)}\n t={t}\n />\n )}\n {!collapsedLane &&\n state.columns.map((column) => {\n const collapsed = state.collapsed.has(column.key)\n const items = kanbanCardsIn(column, lane?.key ?? null)\n const hidden = lane === null ? column.total - column.cards.length : 0\n\n return (\n <ul\n key={column.key}\n role=\"list\"\n aria-labelledby={[`${labelId}-column-${column.key}`, laneId]\n .filter(Boolean)\n .join(' ')}\n data-slot=\"kanban-dropzone\"\n data-column={column.key}\n data-lane={lane?.key}\n data-refused={\n state.picked && state.refused?.column === column.key ? '' : undefined\n }\n className={cn(\n 'bg-muted/40 flex min-h-24 flex-col gap-2 rounded-lg p-2',\n lane === null && 'max-h-[70vh] overflow-y-auto',\n )}\n >\n {!collapsed &&\n items.map((card) => (\n <KanbanCard\n key={card.key}\n card={card}\n board={schema}\n token={page.token}\n current={current === card.key}\n picked={state.picked?.key === card.key ? state.picked.via : undefined}\n saving={state.saving.has(card.key)}\n describedBy={instructionsId}\n formatter={formatter}\n t={t}\n setRef={(element) => {\n if (element) cards.current.set(card.key, element)\n else cards.current.delete(card.key)\n }}\n onFocus={() => setFocused(card.key)}\n onKeyDown={onKeyDown(card.key)}\n onOpen={() => controller.open(card.key)}\n />\n ))}\n {!collapsed && items.length === 0 && (\n <li\n className=\"text-muted-foreground rounded-md border border-dashed px-2 py-6 text-center text-xs\"\n data-slot=\"kanban-empty\"\n >\n {state.search !== '' || kanbanActiveFilters(state.filters) > 0\n ? t('kanban.no_results', {}, 'No cards match')\n : (column.emptyState ?? t('kanban.empty', {}, 'No cards'))}\n </li>\n )}\n {!collapsed && hidden > 0 && (\n <li className=\"text-muted-foreground px-2 text-center text-xs\">\n {t('kanban.more_cards', { count: hidden }, '+:count more')}\n </li>\n )}\n </ul>\n )\n })}\n </Fragment>\n )\n })}\n </div>\n </div>\n <div className=\"sr-only\" role=\"status\" aria-live=\"polite\">\n {state.announcement}\n </div>\n </Card>\n )\n}\n\nfunction KanbanSearch({\n controller,\n search,\n t,\n}: {\n controller: KanbanController\n search: string\n t: Translate\n}) {\n const [value, setValue] = useState(search)\n const [synced, setSynced] = useState(search)\n\n if (synced !== search) {\n setSynced(search)\n setValue(search)\n }\n\n return (\n <div className=\"relative w-full sm:w-64\">\n <SearchIcon\n className=\"text-muted-foreground pointer-events-none absolute start-2.5 top-1/2 size-4 -translate-y-1/2\"\n aria-hidden=\"true\"\n />\n <Input\n type=\"search\"\n value={value}\n className=\"h-8 ps-8\"\n placeholder={t('kanban.search_placeholder', {}, 'Search…')}\n aria-label={t('kanban.search', {}, 'Search cards')}\n onChange={(event) => {\n setValue(event.target.value)\n controller.setSearch(event.target.value)\n }}\n />\n </div>\n )\n}\n\nfunction KanbanFilters({\n controller,\n store,\n t,\n}: {\n controller: KanbanController\n store: NonNullable<ReturnType<typeof createKanbanFiltersStore>>\n t: Translate\n}) {\n const form = useStore(store.store)\n const [initial] = useState(() => ({\n components: store.state.components,\n state: store.state.values,\n columns: store.state.columns,\n }))\n const active = kanbanActiveFilters(form.values)\n\n useEffect(() => {\n if (form.dirty.size > 0) controller.setFilters(form.values)\n }, [controller, form.values, form.dirty])\n\n return (\n <Popover>\n <PopoverTrigger asChild>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" data-slot=\"kanban-filters\">\n <FilterIcon aria-hidden=\"true\" />\n {t('kanban.filters', {}, 'Filters')}\n {active > 0 && <Badge className=\"h-5 min-w-5 px-1\">{active}</Badge>}\n </Button>\n </PopoverTrigger>\n <PopoverContent align=\"end\" className=\"w-80 sm:w-96\">\n <FormProvider store={store}>\n <div className=\"flex flex-col gap-4\">\n <SchemaRenderer components={form.components} columns={form.columns} className=\"gap-4\" />\n {active > 0 && (\n <div className=\"flex justify-end\">\n <Button\n type=\"button\"\n variant=\"link\"\n size=\"sm\"\n onClick={() => {\n store.fill(initial)\n controller.setFilters(null, 0)\n }}\n >\n {t('kanban.reset_filters', {}, 'Reset')}\n </Button>\n </div>\n )}\n </div>\n </FormProvider>\n </PopoverContent>\n </Popover>\n )\n}\n\nfunction ColumnHeader({\n column,\n id,\n collapsed,\n creatable,\n filtered,\n onToggle,\n onCreate,\n t,\n}: {\n column: KanbanColumnSchema\n id: string\n collapsed: boolean\n creatable: boolean\n filtered: boolean\n onToggle: () => void\n onCreate: () => void\n t: Translate\n}) {\n const wip = kanbanWipState(column)\n const shown =\n column.wipLimit !== undefined ? column.count : filtered ? column.total : column.count\n const countLabel =\n column.wipLimit !== undefined\n ? t('kanban.wip', { count: column.count, limit: column.wipLimit }, ':count of :limit')\n : filtered && column.total !== column.count\n ? t(\n 'kanban.count_filtered',\n { shown: column.total, count: column.count },\n ':shown of :count cards',\n )\n : t('kanban.count', { count: column.count }, ':count cards')\n const style = column.color ? { borderTopColor: cssColor(column.color) } : undefined\n const toggleLabel = collapsed\n ? t('kanban.expand', { column: column.label }, 'Expand :column')\n : t('kanban.collapse', { column: column.label }, 'Collapse :column')\n\n if (collapsed) {\n return (\n <div\n className=\"bg-muted/60 flex snap-start flex-col items-center gap-2 rounded-lg border border-t-4 px-1 py-2\"\n style={style}\n data-slot=\"kanban-column-header\"\n data-column={column.key}\n data-collapsed=\"\"\n data-wip={wip ?? undefined}\n >\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n aria-label={toggleLabel}\n aria-expanded={false}\n onClick={onToggle}\n >\n <ChevronsLeftRightIcon aria-hidden=\"true\" />\n </Button>\n <span className=\"text-muted-foreground text-xs tabular-nums\" title={countLabel}>\n {shown}\n </span>\n <h3 id={id} className=\"text-sm font-medium [writing-mode:vertical-rl]\">\n {column.label}\n </h3>\n </div>\n )\n }\n\n return (\n <div\n className=\"bg-muted/60 flex snap-start flex-col gap-1 rounded-lg border border-t-4 px-3 py-2\"\n style={style}\n data-slot=\"kanban-column-header\"\n data-column={column.key}\n data-wip={wip ?? undefined}\n >\n <div className=\"flex items-center gap-2\">\n {column.icon && <Icon name={column.icon} className=\"text-muted-foreground size-4\" />}\n <h3 id={id} className=\"min-w-0 truncate text-sm font-semibold\">\n {column.label}\n </h3>\n <Badge\n variant=\"secondary\"\n className={cn(\n 'h-5 px-1.5 tabular-nums',\n wip === 'over' && 'bg-destructive/15 text-destructive',\n wip === 'full' && 'bg-warning/15 text-warning',\n )}\n title={countLabel}\n >\n <span aria-hidden=\"true\">\n {column.wipLimit !== undefined ? `${column.count}/${column.wipLimit}` : shown}\n </span>\n <span className=\"sr-only\">{countLabel}</span>\n </Badge>\n <div className=\"ms-auto flex items-center\">\n {creatable && (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n aria-label={t('kanban.add_card', { column: column.label }, 'Add a card to :column')}\n title={t('kanban.add_card', { column: column.label }, 'Add a card to :column')}\n onClick={onCreate}\n >\n <PlusIcon aria-hidden=\"true\" />\n </Button>\n )}\n {column.collapsible && (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n aria-label={toggleLabel}\n title={toggleLabel}\n aria-expanded={true}\n onClick={onToggle}\n >\n <ChevronsRightLeftIcon aria-hidden=\"true\" />\n </Button>\n )}\n </div>\n </div>\n {column.description && (\n <p className=\"text-muted-foreground line-clamp-2 text-xs\">{column.description}</p>\n )}\n {wip === 'over' && (\n <p className=\"text-destructive text-xs\">\n {t('kanban.wip_over', { limit: column.wipLimit ?? 0 }, 'Over the limit of :limit cards')}\n </p>\n )}\n {wip === 'full' && column.wipStrict && (\n <p className=\"text-muted-foreground text-xs\">\n {t('kanban.wip_full', {}, 'This column is full')}\n </p>\n )}\n </div>\n )\n}\n\nfunction LaneHeader({\n lane,\n id,\n count,\n collapsed,\n onToggle,\n t,\n}: {\n lane: KanbanLaneSchema\n id: string\n count: number\n collapsed: boolean\n onToggle: () => void\n t: Translate\n}) {\n return (\n <div\n className=\"flex items-center gap-2 pt-2\"\n style={{ gridColumn: '1 / -1' }}\n data-slot=\"kanban-lane\"\n data-lane={lane.key}\n >\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n aria-expanded={!collapsed}\n aria-label={\n collapsed\n ? t('kanban.expand_lane', { lane: lane.label }, 'Expand row :lane')\n : t('kanban.collapse_lane', { lane: lane.label }, 'Collapse row :lane')\n }\n onClick={onToggle}\n >\n <ChevronRightIcon\n className={cn(\n 'transition-transform rtl:rotate-180',\n !collapsed && 'rotate-90 rtl:rotate-90',\n )}\n aria-hidden=\"true\"\n />\n </Button>\n {lane.avatar ? (\n <Avatar className=\"size-6\">\n <AvatarImage src={lane.avatar} alt=\"\" />\n <AvatarFallback>{kanbanInitials(lane.label)}</AvatarFallback>\n </Avatar>\n ) : (\n lane.icon && <Icon name={lane.icon} className=\"text-muted-foreground size-4\" />\n )}\n <span id={id} className=\"text-sm font-semibold\">\n {lane.label}\n </span>\n <Badge variant=\"secondary\" className=\"h-5 px-1.5 tabular-nums\">\n {count}\n </Badge>\n </div>\n )\n}\n\nfunction KanbanCard({\n card,\n board,\n token,\n current,\n picked,\n saving,\n describedBy,\n formatter,\n t,\n setRef,\n onFocus,\n onKeyDown,\n onOpen,\n}: {\n card: KanbanCardSchema\n board: KanbanSchema\n token: string\n current: boolean\n picked: 'keyboard' | 'pointer' | undefined\n saving: boolean\n describedBy: string\n formatter: LocaleFormatter\n t: Translate\n setRef: (element: HTMLElement | null) => void\n onFocus: () => void\n onKeyDown: (event: KeyboardEvent<HTMLElement>) => void\n onOpen: () => void\n}) {\n const titleId = useId()\n const opens = card.clickable !== false && Boolean(card.url || board.cardAction)\n const assignees = card.assignees ?? []\n const shownAssignees = assignees.slice(0, 3)\n\n return (\n <li\n className=\"relative\"\n data-slot=\"kanban-card\"\n data-key={card.key}\n data-movable={board.movable && card.movable !== false ? undefined : 'false'}\n data-picked={picked}\n data-saving={saving ? '' : undefined}\n >\n <div\n ref={setRef}\n role=\"button\"\n tabIndex={current ? 0 : -1}\n aria-labelledby={titleId}\n aria-describedby={describedBy}\n aria-disabled={opens ? undefined : true}\n data-slot=\"kanban-card-body\"\n className={cn(\n 'bg-card text-card-foreground focus-visible:ring-ring/50 flex touch-manipulation flex-col gap-2 overflow-hidden rounded-lg border p-3 text-start shadow-xs outline-none select-none focus-visible:ring-[3px]',\n opens && 'hover:border-ring/60 cursor-pointer',\n card.color && 'border-s-4',\n )}\n style={card.color ? { borderInlineStartColor: cssColor(card.color) } : undefined}\n onFocus={(event) => event.target === event.currentTarget && onFocus()}\n onKeyDown={onKeyDown}\n onClick={() => opens && onOpen()}\n >\n {card.coverImage && (\n <img\n src={card.coverImage}\n alt={card.coverImageAlt ?? ''}\n loading=\"lazy\"\n draggable={false}\n className=\"-mx-3 -mt-3 h-32 w-[calc(100%+1.5rem)] max-w-none object-cover\"\n />\n )}\n <span\n id={titleId}\n className={cn('text-sm leading-snug font-medium', card.actions && 'pe-7')}\n >\n {card.title}\n </span>\n {card.description && (\n <p className=\"text-muted-foreground line-clamp-3 text-xs\">{card.description}</p>\n )}\n {card.badges && card.badges.length > 0 && (\n <div className=\"flex flex-wrap gap-1\">\n {card.badges.map((badge, index) => (\n <Badge\n key={index}\n variant=\"outline\"\n title={badge.tooltip}\n className={colorClass(badgeColorClasses, badge.color, 'gray')}\n >\n {badge.icon && <Icon name={badge.icon} />}\n {badge.label}\n </Badge>\n ))}\n </div>\n )}\n {card.schema && card.schema.length > 0 && (\n <SchemaRenderer components={card.schema} className=\"gap-2 text-xs\" />\n )}\n {card.progress !== undefined && (\n <div\n role=\"progressbar\"\n aria-valuemin={0}\n aria-valuemax={100}\n aria-valuenow={Math.round(card.progress)}\n aria-label={t(\n 'kanban.progress',\n { percent: formatter.percent(card.progress / 100) },\n ':percent complete',\n )}\n className=\"bg-muted h-1.5 overflow-hidden rounded-full\"\n >\n <div\n className=\"bg-primary h-full rounded-full\"\n style={{ width: `${card.progress}%` }}\n />\n </div>\n )}\n {(card.dueDate || assignees.length > 0) && (\n <div className=\"flex items-center gap-2 text-xs\">\n {card.dueDate && (\n <span\n className={cn(\n 'inline-flex items-center gap-1',\n card.overdue ? 'text-destructive font-medium' : 'text-muted-foreground',\n )}\n >\n <CalendarIcon className=\"size-3.5\" aria-hidden=\"true\" />\n <span className=\"sr-only\">\n {t('kanban.due', { date: formatter.date(card.dueDate) }, 'Due :date')}\n </span>\n <time dateTime={card.dueDate} aria-hidden=\"true\">\n {formatter.date(card.dueDate)}\n </time>\n {card.overdue && (\n <span className=\"sr-only\">{t('kanban.overdue', {}, 'Overdue')}</span>\n )}\n </span>\n )}\n {assignees.length > 0 && (\n <div className=\"ms-auto flex items-center\">\n <span className=\"sr-only\">\n {t(\n 'kanban.assignees',\n { names: formatter.list(assignees.map((assignee) => assignee.name)) },\n 'Assigned to :names',\n )}\n </span>\n <div className=\"flex -space-x-1.5 rtl:space-x-reverse\" aria-hidden=\"true\">\n {shownAssignees.map((assignee, index) => (\n <Avatar key={index} className=\"ring-card size-6 ring-2\" title={assignee.name}>\n {assignee.avatar && <AvatarImage src={assignee.avatar} alt=\"\" />}\n <AvatarFallback className=\"text-[0.625rem]\">\n {kanbanInitials(assignee.name)}\n </AvatarFallback>\n </Avatar>\n ))}\n {assignees.length > shownAssignees.length && (\n <span className=\"bg-muted ring-card flex size-6 items-center justify-center rounded-full text-[0.625rem] font-medium ring-2\">\n {t(\n 'kanban.more_assignees',\n { count: assignees.length - shownAssignees.length },\n '+:count',\n )}\n </span>\n )}\n </div>\n </div>\n )}\n </div>\n )}\n </div>\n {card.actions && card.actions.length > 0 && (\n <div className=\"absolute end-1.5 top-1.5\" data-kanban-no-drag=\"\">\n <ActionList\n actions={card.actions}\n context={{ token, component: board.actionComponent, record: card.key }}\n size=\"xs\"\n />\n </div>\n )}\n </li>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuDA,SAAgB,OAAO,EACrB,WACA,UAIC;CACD,MAAM,QAAQ,aAAa,QAAQ;CAEnC,OAAO,QAAQ,oBAAC,aAAD,EAAgD,MAAQ,GAAtC,MAAM,eAAgC,IAAI;AAC7E;AAEA,SAAS,YAAY,EAAE,SAAkC;CACvD,MAAM,SAAS,gBAAgB;CAC/B,MAAM,OAAO,qBAAqB;CAClC,MAAM,QAAQ,SAAS;CACvB,MAAM,IAAI,KAAK;CACf,MAAM,YAAY,aAAa;CAC/B,MAAM,YAAY,aAAa;CAC/B,MAAM,UAAU,MAAM;CACtB,MAAM,iBAAiB,MAAM;CAC7B,MAAM,qBAAwC;EAC5C;EACA,OAAO,KAAK;EACZ;EACA,SAAS,kBAAkB,cAAc,SAAS,iBAAiB,UAAU,YAAY,CAAC;EAC1F,QAAQ,YAAY,UAAU,wBAAwB,UAAU,OAAO,CAAC;EACxE,QAAQ,QAAQ,OAAO,MAAM,GAAG;CAClC;CAEA,MAAM,CAAC,cAAc,eAAe,IAAI,iBAAiB,OAAO,YAAY,CAAC,CAAC;CAC9E,MAAM,CAAC,WAAW,eAChB,yBAAyB,OAAO,KAAK,OAAO,MAAM,UAAU,aAAa,CAC3E;CACA,MAAM,OAAO,OAAuB,IAAI;CACxC,MAAM,QAAQ,uBAAO,IAAI,IAAyB,CAAC;CACnD,MAAM,CAAC,SAAS,cAAc,SAAwB,IAAI;CAE1D,gBAAgB;EACd,WAAW,eAAe,YAAY,CAAC;CACzC,CAAC;CAED,MAAM,QAAQ,OAAO,IAAI;CAEzB,gBAAgB;EACd,IAAI,MAAM,SAAS;GACjB,MAAM,UAAU;GAEhB;EACF;EAEA,WAAW,SAAS,KAAK;CAC3B,GAAG,CAAC,YAAY,KAAK,CAAC;CAEtB,gBACS,KAAK,UAAU,oBAAoB,KAAK,SAAS,UAAU,IAAI,KAAA,GACtE,CAAC,UAAU,CACb;CACA,gBAAgB,WAAW,aAAa,GAAG,CAAC,UAAU,CAAC;CACvD,sBACc;EACV,WAAW,QAAQ;EACnB,SAAS,QAAQ;CACnB,GACA,CAAC,YAAY,OAAO,CACtB;CAEA,MAAM,QAAQ,SAAS,WAAW,KAAK;CACvC,MAAM,SAAS,WAAW;CAC1B,MAAM,QAAQ,WAAW,MAAM;CAC/B,MAAM,OAAO,MAAM,QAAQ,SAAS,WAAW,OAAO,MAAM,KAAK,SAAS,KAAK,GAAG,CAAC;CACnF,MAAM,UAAU,YAAY,QAAQ,KAAK,SAAS,OAAO,IAAI,UAAW,KAAK,MAAM;CAEnF,MAAM,SAAS,QAA4B;EACzC,IAAI,CAAC,KAAK;EACV,WAAW,GAAG;EACd,4BAA4B,MAAM,QAAQ,IAAI,GAAG,CAAC,EAAE,MAAM,CAAC;CAC7D;CAGA,MAAM,SAAS,MAAM;CAErB,gBAAgB;EACd,IAAI,QAAQ,QAAQ,YAAY;GAC9B,MAAM,UAAU,MAAM,QAAQ,IAAI,OAAO,GAAG;GAE5C,IAAI,WAAW,SAAS,kBAAkB,SAAS,QAAQ,MAAM;EACnE;CACF,GAAG,CAAC,MAAM,CAAC;CAEX,MAAM,aAAa,SAAiB,UAAsC;EACxE,IAAI,MAAM,WAAW,MAAM,eAAe;EAE1C,MAAM,SAAS,WAAW,UAAU,KAAK,OAAO,SAAS;EAEzD,IAAI,CAAC,OAAO,SAAS;EAErB,MAAM,eAAe;EAErB,IAAI,OAAO,MAAM,WAAW,KAAK,GAAG;OAC/B,MAAM,OAAO,KAAK;CACzB;CAEA,MAAM,WAAW,MAAM,QACpB,KAAK,WAAY,MAAM,UAAU,IAAI,OAAO,GAAG,IAAI,YAAY,sBAAuB,CAAC,CACvF,KAAK,GAAG;CAEX,OACE,qBAAC,MAAD;EACE,KAAK;EACL,MAAK;EACL,mBAAiB;EACjB,WAAU;EACV,aAAU;EALZ,UAAA;GAOE,qBAAC,OAAD;IAAK,WAAU;IAAyC,aAAU;IAAlE,UAAA,CACG,OAAO,UACN,oBAAC,WAAD;KAAW,IAAI;KAAS,WAAU;KAC/B,UAAA,OAAO;IACC,CAAA,IAEX,oBAAC,QAAD;KAAM,IAAI;KAAS,WAAU;KAC1B,UAAA,EAAE,gBAAgB,CAAC,GAAG,cAAc;IACjC,CAAA,GAER,qBAAC,OAAD;KAAK,WAAU;KAAf,UAAA;MACG,MAAM,WACL,oBAAC,SAAD;OAAS,WAAU;OAAS,cAAY,EAAE,kBAAkB,CAAC,GAAG,eAAe;MAAI,CAAA;MAEpF,OAAO,cACN,oBAAC,cAAD;OAA0B;OAAY,QAAQ,MAAM;OAAW;MAAI,CAAA;MAEpE,WAAW,oBAAC,eAAD;OAA2B;OAAY,OAAO;OAAY;MAAI,CAAA;KACvE;IACF,CAAA,CAAA;;GACL,oBAAC,KAAD;IAAG,IAAI;IAAgB,WAAU;IAC9B,UAAA,EACC,uBACA,CAAC,GACD,6HACF;GACC,CAAA;GACH,oBAAC,OAAD;IACE,WAAU;IACV,aAAU;IAEV,UAAA,qBAAC,OAAD;KACE,WAAU;KACV,OAAO,EAAE,qBAAqB,SAAS;KAFzC,UAAA,CAIG,MAAM,QAAQ,KAAK,WAClB,oBAAC,cAAD;MAEU;MACR,IAAI,GAAG,QAAQ,UAAU,OAAO;MAChC,WAAW,MAAM,UAAU,IAAI,OAAO,GAAG;MACzC,WAAW,QAAQ,OAAO,aAAa,OAAO,YAAY;MAC1D,UAAU,MAAM,WAAW,MAAM,oBAAoB,MAAM,OAAO,IAAI;MACtE,gBAAgB,WAAW,aAAa,OAAO,GAAG;MAClD,gBAAgB,WAAW,OAAO,OAAO,GAAG;MACzC;KACJ,GATM,OAAO,GASb,CACF,GACA,MAAM,KAAK,SAAS;MACnB,MAAM,SAAS,OAAO,GAAG,QAAQ,QAAQ,KAAK,QAAQ,KAAA;MACtD,MAAM,gBAAgB,SAAS,QAAQ,MAAM,eAAe,IAAI,KAAK,GAAG;MAExE,OACE,qBAAC,UAAD,EAAA,UAAA,CACG,QACC,oBAAC,YAAD;OACQ;OACN,IAAI;OACJ,OAAO,MAAM,QAAQ,QAClB,KAAK,WAAW,MAAM,cAAc,QAAQ,KAAK,GAAG,CAAC,CAAC,QACvD,CACF;OACA,WAAW;OACX,gBAAgB,WAAW,WAAW,KAAK,GAAG;OAC3C;MACJ,CAAA,GAEF,CAAC,iBACA,MAAM,QAAQ,KAAK,WAAW;OAC5B,MAAM,YAAY,MAAM,UAAU,IAAI,OAAO,GAAG;OAChD,MAAM,QAAQ,cAAc,QAAQ,MAAM,OAAO,IAAI;OACrD,MAAM,SAAS,SAAS,OAAO,OAAO,QAAQ,OAAO,MAAM,SAAS;OAEpE,OACE,qBAAC,MAAD;QAEE,MAAK;QACL,mBAAiB,CAAC,GAAG,QAAQ,UAAU,OAAO,OAAO,MAAM,CAAC,CACzD,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;QACX,aAAU;QACV,eAAa,OAAO;QACpB,aAAW,MAAM;QACjB,gBACE,MAAM,UAAU,MAAM,SAAS,WAAW,OAAO,MAAM,KAAK,KAAA;QAE9D,WAAW,GACT,2DACA,SAAS,QAAQ,8BACnB;QAfF,UAAA;SAiBG,CAAC,aACA,MAAM,KAAK,SACT,oBAAC,YAAD;UAEQ;UACN,OAAO;UACP,OAAO,KAAK;UACZ,SAAS,YAAY,KAAK;UAC1B,QAAQ,MAAM,QAAQ,QAAQ,KAAK,MAAM,MAAM,OAAO,MAAM,KAAA;UAC5D,QAAQ,MAAM,OAAO,IAAI,KAAK,GAAG;UACjC,aAAa;UACF;UACR;UACH,SAAS,YAAY;WACnB,IAAI,SAAS,MAAM,QAAQ,IAAI,KAAK,KAAK,OAAO;gBAC3C,MAAM,QAAQ,OAAO,KAAK,GAAG;UACpC;UACA,eAAe,WAAW,KAAK,GAAG;UAClC,WAAW,UAAU,KAAK,GAAG;UAC7B,cAAc,WAAW,KAAK,KAAK,GAAG;SACvC,GAjBM,KAAK,GAiBX,CACF;SACF,CAAC,aAAa,MAAM,WAAW,KAC9B,oBAAC,MAAD;UACE,WAAU;UACV,aAAU;UAET,UAAA,MAAM,WAAW,MAAM,oBAAoB,MAAM,OAAO,IAAI,IACzD,EAAE,qBAAqB,CAAC,GAAG,gBAAgB,IAC1C,OAAO,cAAc,EAAE,gBAAgB,CAAC,GAAG,UAAU;SACxD,CAAA;SAEL,CAAC,aAAa,SAAS,KACtB,oBAAC,MAAD;UAAI,WAAU;UACX,UAAA,EAAE,qBAAqB,EAAE,OAAO,OAAO,GAAG,cAAc;SACvD,CAAA;QAEJ;OArDG,GAAA,OAAO,GAqDV;MAER,CAAC,CACK,EAAA,GA9EK,MAAM,OAAO,SA8ElB;KAEd,CAAC,CACE;;GACF,CAAA;GACL,oBAAC,OAAD;IAAK,WAAU;IAAU,MAAK;IAAS,aAAU;IAC9C,UAAA,MAAM;GACJ,CAAA;EACD;;AAEV;AAEA,SAAS,aAAa,EACpB,YACA,QACA,KAKC;CACD,MAAM,CAAC,OAAO,YAAY,SAAS,MAAM;CACzC,MAAM,CAAC,QAAQ,aAAa,SAAS,MAAM;CAE3C,IAAI,WAAW,QAAQ;EACrB,UAAU,MAAM;EAChB,SAAS,MAAM;CACjB;CAEA,OACE,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA,CACE,oBAAC,YAAD;GACE,WAAU;GACV,eAAY;EACb,CAAA,GACD,oBAAC,OAAD;GACE,MAAK;GACE;GACP,WAAU;GACV,aAAa,EAAE,6BAA6B,CAAC,GAAG,SAAS;GACzD,cAAY,EAAE,iBAAiB,CAAC,GAAG,cAAc;GACjD,WAAW,UAAU;IACnB,SAAS,MAAM,OAAO,KAAK;IAC3B,WAAW,UAAU,MAAM,OAAO,KAAK;GACzC;EACD,CAAA,CACE;;AAET;AAEA,SAAS,cAAc,EACrB,YACA,OACA,KAKC;CACD,MAAM,OAAO,SAAS,MAAM,KAAK;CACjC,MAAM,CAAC,WAAW,gBAAgB;EAChC,YAAY,MAAM,MAAM;EACxB,OAAO,MAAM,MAAM;EACnB,SAAS,MAAM,MAAM;CACvB,EAAE;CACF,MAAM,SAAS,oBAAoB,KAAK,MAAM;CAE9C,gBAAgB;EACd,IAAI,KAAK,MAAM,OAAO,GAAG,WAAW,WAAW,KAAK,MAAM;CAC5D,GAAG;EAAC;EAAY,KAAK;EAAQ,KAAK;CAAK,CAAC;CAExC,OACE,qBAAC,SAAD,EAAA,UAAA,CACE,oBAAC,gBAAD;EAAgB,SAAA;EACd,UAAA,qBAAC,QAAD;GAAQ,MAAK;GAAS,SAAQ;GAAU,MAAK;GAAK,aAAU;GAA5D,UAAA;IACE,oBAAC,YAAD,EAAY,eAAY,OAAQ,CAAA;IAC/B,EAAE,kBAAkB,CAAC,GAAG,SAAS;IACjC,SAAS,KAAK,oBAAC,OAAD;KAAO,WAAU;KAAoB,UAAA;IAAc,CAAA;GAC5D;;CACM,CAAA,GAChB,oBAAC,gBAAD;EAAgB,OAAM;EAAM,WAAU;EACpC,UAAA,oBAAC,cAAD;GAAqB;GACnB,UAAA,qBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,oBAAC,gBAAD;KAAgB,YAAY,KAAK;KAAY,SAAS,KAAK;KAAS,WAAU;IAAS,CAAA,GACtF,SAAS,KACR,oBAAC,OAAD;KAAK,WAAU;KACb,UAAA,oBAAC,QAAD;MACE,MAAK;MACL,SAAQ;MACR,MAAK;MACL,eAAe;OACb,MAAM,KAAK,OAAO;OAClB,WAAW,WAAW,MAAM,CAAC;MAC/B;MAEC,UAAA,EAAE,wBAAwB,CAAC,GAAG,OAAO;KAChC,CAAA;IACL,CAAA,CAEJ;;EACO,CAAA;CACA,CAAA,CACT,EAAA,CAAA;AAEb;AAEA,SAAS,aAAa,EACpB,QACA,IACA,WACA,WACA,UACA,UACA,UACA,KAUC;CACD,MAAM,MAAM,eAAe,MAAM;CACjC,MAAM,QACJ,OAAO,aAAa,KAAA,IAAY,OAAO,QAAQ,WAAW,OAAO,QAAQ,OAAO;CAClF,MAAM,aACJ,OAAO,aAAa,KAAA,IAChB,EAAE,cAAc;EAAE,OAAO,OAAO;EAAO,OAAO,OAAO;CAAS,GAAG,kBAAkB,IACnF,YAAY,OAAO,UAAU,OAAO,QAClC,EACE,yBACA;EAAE,OAAO,OAAO;EAAO,OAAO,OAAO;CAAM,GAC3C,wBACF,IACA,EAAE,gBAAgB,EAAE,OAAO,OAAO,MAAM,GAAG,cAAc;CACjE,MAAM,QAAQ,OAAO,QAAQ,EAAE,gBAAgB,SAAS,OAAO,KAAK,EAAE,IAAI,KAAA;CAC1E,MAAM,cAAc,YAChB,EAAE,iBAAiB,EAAE,QAAQ,OAAO,MAAM,GAAG,gBAAgB,IAC7D,EAAE,mBAAmB,EAAE,QAAQ,OAAO,MAAM,GAAG,kBAAkB;CAErE,IAAI,WACF,OACE,qBAAC,OAAD;EACE,WAAU;EACH;EACP,aAAU;EACV,eAAa,OAAO;EACpB,kBAAe;EACf,YAAU,OAAO,KAAA;EANnB,UAAA;GAQE,oBAAC,QAAD;IACE,MAAK;IACL,SAAQ;IACR,MAAK;IACL,cAAY;IACZ,iBAAe;IACf,SAAS;IAET,UAAA,oBAAC,uBAAD,EAAuB,eAAY,OAAQ,CAAA;GACrC,CAAA;GACR,oBAAC,QAAD;IAAM,WAAU;IAA6C,OAAO;IACjE,UAAA;GACG,CAAA;GACN,oBAAC,MAAD;IAAQ;IAAI,WAAU;IACnB,UAAA,OAAO;GACN,CAAA;EACD;;CAIT,OACE,qBAAC,OAAD;EACE,WAAU;EACH;EACP,aAAU;EACV,eAAa,OAAO;EACpB,YAAU,OAAO,KAAA;EALnB,UAAA;GAOE,qBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KACG,OAAO,QAAQ,oBAAC,MAAD;MAAM,MAAM,OAAO;MAAM,WAAU;KAAgC,CAAA;KACnF,oBAAC,MAAD;MAAQ;MAAI,WAAU;MACnB,UAAA,OAAO;KACN,CAAA;KACJ,qBAAC,OAAD;MACE,SAAQ;MACR,WAAW,GACT,2BACA,QAAQ,UAAU,sCAClB,QAAQ,UAAU,4BACpB;MACA,OAAO;MAPT,UAAA,CASE,oBAAC,QAAD;OAAM,eAAY;OACf,UAAA,OAAO,aAAa,KAAA,IAAY,GAAG,OAAO,MAAM,GAAG,OAAO,aAAa;MACpE,CAAA,GACN,oBAAC,QAAD;OAAM,WAAU;OAAW,UAAA;MAAiB,CAAA,CACvC;;KACP,qBAAC,OAAD;MAAK,WAAU;MAAf,UAAA,CACG,aACC,oBAAC,QAAD;OACE,MAAK;OACL,SAAQ;OACR,MAAK;OACL,cAAY,EAAE,mBAAmB,EAAE,QAAQ,OAAO,MAAM,GAAG,uBAAuB;OAClF,OAAO,EAAE,mBAAmB,EAAE,QAAQ,OAAO,MAAM,GAAG,uBAAuB;OAC7E,SAAS;OAET,UAAA,oBAAC,UAAD,EAAU,eAAY,OAAQ,CAAA;MACxB,CAAA,GAET,OAAO,eACN,oBAAC,QAAD;OACE,MAAK;OACL,SAAQ;OACR,MAAK;OACL,cAAY;OACZ,OAAO;OACP,iBAAe;OACf,SAAS;OAET,UAAA,oBAAC,uBAAD,EAAuB,eAAY,OAAQ,CAAA;MACrC,CAAA,CAEP;;IACF;;GACJ,OAAO,eACN,oBAAC,KAAD;IAAG,WAAU;IAA8C,UAAA,OAAO;GAAe,CAAA;GAElF,QAAQ,UACP,oBAAC,KAAD;IAAG,WAAU;IACV,UAAA,EAAE,mBAAmB,EAAE,OAAO,OAAO,YAAY,EAAE,GAAG,gCAAgC;GACtF,CAAA;GAEJ,QAAQ,UAAU,OAAO,aACxB,oBAAC,KAAD;IAAG,WAAU;IACV,UAAA,EAAE,mBAAmB,CAAC,GAAG,qBAAqB;GAC9C,CAAA;EAEF;;AAET;AAEA,SAAS,WAAW,EAClB,MACA,IACA,OACA,WACA,UACA,KAQC;CACD,OACE,qBAAC,OAAD;EACE,WAAU;EACV,OAAO,EAAE,YAAY,SAAS;EAC9B,aAAU;EACV,aAAW,KAAK;EAJlB,UAAA;GAME,oBAAC,QAAD;IACE,MAAK;IACL,SAAQ;IACR,MAAK;IACL,iBAAe,CAAC;IAChB,cACE,YACI,EAAE,sBAAsB,EAAE,MAAM,KAAK,MAAM,GAAG,kBAAkB,IAChE,EAAE,wBAAwB,EAAE,MAAM,KAAK,MAAM,GAAG,oBAAoB;IAE1E,SAAS;IAET,UAAA,oBAAC,kBAAD;KACE,WAAW,GACT,uCACA,CAAC,aAAa,yBAChB;KACA,eAAY;IACb,CAAA;GACK,CAAA;GACP,KAAK,SACJ,qBAAC,QAAD;IAAQ,WAAU;IAAlB,UAAA,CACE,oBAAC,aAAD;KAAa,KAAK,KAAK;KAAQ,KAAI;IAAI,CAAA,GACvC,oBAAC,gBAAD,EAAA,UAAiB,eAAe,KAAK,KAAK,EAAkB,CAAA,CACtD;GAER,CAAA,IAAA,KAAK,QAAQ,oBAAC,MAAD;IAAM,MAAM,KAAK;IAAM,WAAU;GAAgC,CAAA;GAEhF,oBAAC,QAAD;IAAU;IAAI,WAAU;IACrB,UAAA,KAAK;GACF,CAAA;GACN,oBAAC,OAAD;IAAO,SAAQ;IAAY,WAAU;IAClC,UAAA;GACI,CAAA;EACJ;;AAET;AAEA,SAAS,WAAW,EAClB,MACA,OACA,OACA,SACA,QACA,QACA,aACA,WACA,GACA,QACA,SACA,WACA,UAeC;CACD,MAAM,UAAU,MAAM;CACtB,MAAM,QAAQ,KAAK,cAAc,SAAS,QAAQ,KAAK,OAAO,MAAM,UAAU;CAC9E,MAAM,YAAY,KAAK,aAAa,CAAC;CACrC,MAAM,iBAAiB,UAAU,MAAM,GAAG,CAAC;CAE3C,OACE,qBAAC,MAAD;EACE,WAAU;EACV,aAAU;EACV,YAAU,KAAK;EACf,gBAAc,MAAM,WAAW,KAAK,YAAY,QAAQ,KAAA,IAAY;EACpE,eAAa;EACb,eAAa,SAAS,KAAK,KAAA;EAN7B,UAAA,CAQE,qBAAC,OAAD;GACE,KAAK;GACL,MAAK;GACL,UAAU,UAAU,IAAI;GACxB,mBAAiB;GACjB,oBAAkB;GAClB,iBAAe,QAAQ,KAAA,IAAY;GACnC,aAAU;GACV,WAAW,GACT,+MACA,SAAS,uCACT,KAAK,SAAS,YAChB;GACA,OAAO,KAAK,QAAQ,EAAE,wBAAwB,SAAS,KAAK,KAAK,EAAE,IAAI,KAAA;GACvE,UAAU,UAAU,MAAM,WAAW,MAAM,iBAAiB,QAAQ;GACzD;GACX,eAAe,SAAS,OAAO;GAhBjC,UAAA;IAkBG,KAAK,cACJ,oBAAC,OAAD;KACE,KAAK,KAAK;KACV,KAAK,KAAK,iBAAiB;KAC3B,SAAQ;KACR,WAAW;KACX,WAAU;IACX,CAAA;IAEH,oBAAC,QAAD;KACE,IAAI;KACJ,WAAW,GAAG,oCAAoC,KAAK,WAAW,MAAM;KAEvE,UAAA,KAAK;IACF,CAAA;IACL,KAAK,eACJ,oBAAC,KAAD;KAAG,WAAU;KAA8C,UAAA,KAAK;IAAe,CAAA;IAEhF,KAAK,UAAU,KAAK,OAAO,SAAS,KACnC,oBAAC,OAAD;KAAK,WAAU;KACZ,UAAA,KAAK,OAAO,KAAK,OAAO,UACvB,qBAAC,OAAD;MAEE,SAAQ;MACR,OAAO,MAAM;MACb,WAAW,WAAW,mBAAmB,MAAM,OAAO,MAAM;MAJ9D,UAAA,CAMG,MAAM,QAAQ,oBAAC,MAAD,EAAM,MAAM,MAAM,KAAO,CAAA,GACvC,MAAM,KACF;KAPA,GAAA,KAOA,CACR;IACE,CAAA;IAEN,KAAK,UAAU,KAAK,OAAO,SAAS,KACnC,oBAAC,gBAAD;KAAgB,YAAY,KAAK;KAAQ,WAAU;IAAiB,CAAA;IAErE,KAAK,aAAa,KAAA,KACjB,oBAAC,OAAD;KACE,MAAK;KACL,iBAAe;KACf,iBAAe;KACf,iBAAe,KAAK,MAAM,KAAK,QAAQ;KACvC,cAAY,EACV,mBACA,EAAE,SAAS,UAAU,QAAQ,KAAK,WAAW,GAAG,EAAE,GAClD,mBACF;KACA,WAAU;KAEV,UAAA,oBAAC,OAAD;MACE,WAAU;MACV,OAAO,EAAE,OAAO,GAAG,KAAK,SAAS,GAAG;KACrC,CAAA;IACE,CAAA;KAEL,KAAK,WAAW,UAAU,SAAS,MACnC,qBAAC,OAAD;KAAK,WAAU;KAAf,UAAA,CACG,KAAK,WACJ,qBAAC,QAAD;MACE,WAAW,GACT,kCACA,KAAK,UAAU,iCAAiC,uBAClD;MAJF,UAAA;OAME,oBAAC,cAAD;QAAc,WAAU;QAAW,eAAY;OAAQ,CAAA;OACvD,oBAAC,QAAD;QAAM,WAAU;QACb,UAAA,EAAE,cAAc,EAAE,MAAM,UAAU,KAAK,KAAK,OAAO,EAAE,GAAG,WAAW;OAChE,CAAA;OACN,oBAAC,QAAD;QAAM,UAAU,KAAK;QAAS,eAAY;QACvC,UAAA,UAAU,KAAK,KAAK,OAAO;OACxB,CAAA;OACL,KAAK,WACJ,oBAAC,QAAD;QAAM,WAAU;QAAW,UAAA,EAAE,kBAAkB,CAAC,GAAG,SAAS;OAAQ,CAAA;MAElE;KAEP,CAAA,GAAA,UAAU,SAAS,KAClB,qBAAC,OAAD;MAAK,WAAU;MAAf,UAAA,CACE,oBAAC,QAAD;OAAM,WAAU;OACb,UAAA,EACC,oBACA,EAAE,OAAO,UAAU,KAAK,UAAU,KAAK,aAAa,SAAS,IAAI,CAAC,EAAE,GACpE,oBACF;MACI,CAAA,GACN,qBAAC,OAAD;OAAK,WAAU;OAAwC,eAAY;OAAnE,UAAA,CACG,eAAe,KAAK,UAAU,UAC7B,qBAAC,QAAD;QAAoB,WAAU;QAA0B,OAAO,SAAS;QAAxE,UAAA,CACG,SAAS,UAAU,oBAAC,aAAD;SAAa,KAAK,SAAS;SAAQ,KAAI;QAAI,CAAA,GAC/D,oBAAC,gBAAD;SAAgB,WAAU;SACvB,UAAA,eAAe,SAAS,IAAI;QACf,CAAA,CACV;OALK,GAAA,KAKL,CACT,GACA,UAAU,SAAS,eAAe,UACjC,oBAAC,QAAD;QAAM,WAAU;QACb,UAAA,EACC,yBACA,EAAE,OAAO,UAAU,SAAS,eAAe,OAAO,GAClD,SACF;OACI,CAAA,CAEL;MACF,CAAA,CAAA;KAEJ,CAAA,CAAA;;GAEJ;EACJ,CAAA,GAAA,KAAK,WAAW,KAAK,QAAQ,SAAS,KACrC,oBAAC,OAAD;GAAK,WAAU;GAA2B,uBAAoB;GAC5D,UAAA,oBAAC,YAAD;IACE,SAAS,KAAK;IACd,SAAS;KAAE;KAAO,WAAW,MAAM;KAAiB,QAAQ,KAAK;IAAI;IACrE,MAAK;GACN,CAAA;EACE,CAAA,CAEL;;AAER"}
1
+ {"version":3,"file":"kanban.js","names":[],"sources":["../../../src/components/kanban/kanban.tsx"],"sourcesContent":["import type {\n KanbanCardSchema,\n KanbanColumnSchema,\n KanbanEnvironment,\n KanbanLaneSchema,\n KanbanSchema,\n KanbanWidgetSchema,\n LocaleFormatter,\n} from '@alfakit/core'\nimport {\n KanbanController,\n attachKanbanPointer,\n clientErrorNotification,\n createKanbanFiltersStore,\n kanbanActiveFilters,\n kanbanCardsIn,\n kanbanInitials,\n kanbanWipState,\n} from '@alfakit/core'\nimport { router } from '@inertiajs/react'\nimport {\n CalendarIcon,\n ChevronRightIcon,\n ChevronsLeftRightIcon,\n ChevronsRightLeftIcon,\n FilterIcon,\n PlusIcon,\n SearchIcon,\n} from 'lucide-react'\nimport { Fragment, useEffect, useId, useRef, useState, type KeyboardEvent } from 'react'\nimport {\n useActionRunner,\n useChoice,\n useDirection,\n useFormatter,\n usePanel,\n useT,\n} from '../../context'\nimport { useStore } from '../../hooks/use-store'\nimport { badgeColorClasses, colorClass, cssColor } from '../../lib/colors'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport { usePageActionContext } from '../actions/action-context'\nimport { ActionList } from '../actions/action-list'\nimport { FormProvider } from '../form/form-context'\nimport { showToast } from '../notifications/flash-toasts'\nimport { SchemaRenderer } from '../schema/schema-renderer'\nimport { Avatar, AvatarFallback, AvatarImage } from '../ui/avatar'\nimport { Badge } from '../ui/badge'\nimport { Button } from '../ui/button'\nimport { Card, CardTitle } from '../ui/card'\nimport { Input } from '../ui/input'\nimport { Popover, PopoverContent, PopoverTrigger } from '../ui/popover'\nimport { Spinner } from '../ui/spinner'\n\ntype Translate = ReturnType<typeof useT>\n\n/**\n * The board of a `KanbanPage` (schema component `kanban`) or a `KanbanWidget`\n * (alfasix/alfakit-kanban). Cards move by dragging (mouse, pen, touch) or with the\n * keyboard, and every move is saved in one request.\n */\nexport function Kanban({\n component,\n widget,\n}: {\n component?: KanbanSchema\n widget?: KanbanWidgetSchema\n}) {\n const board = component ?? widget?.kanban\n\n return board ? <KanbanBoard key={board.actionComponent} board={board} /> : null\n}\n\nfunction KanbanBoard({ board }: { board: KanbanSchema }) {\n const runner = useActionRunner()\n const page = usePageActionContext()\n const panel = usePanel()\n const t = useT()\n const direction = useDirection()\n const formatter = useFormatter()\n const labelId = useId()\n const instructionsId = useId()\n const environment = (): KanbanEnvironment => ({\n runner,\n token: page.token,\n t,\n notify: (notifications) => notifications.forEach((notification) => showToast(notification)),\n error: (message) => showToast(clientErrorNotification('kanban', message)),\n visit: (url) => router.visit(url),\n })\n // One controller per board (the parent keys this view by its action component).\n const [controller] = useState(() => new KanbanController(board, environment()))\n const [filters] = useState(() =>\n createKanbanFiltersStore(board, page.token, panel.endpoints.schemaOptions),\n )\n const root = useRef<HTMLDivElement>(null)\n const cards = useRef(new Map<string, HTMLElement>())\n const [focused, setFocused] = useState<string | null>(null)\n\n useEffect(() => {\n controller.setEnvironment(environment())\n })\n\n const first = useRef(true)\n\n useEffect(() => {\n if (first.current) {\n first.current = false\n\n return\n }\n\n controller.setBoard(board)\n }, [controller, board])\n\n useEffect(\n () => (root.current ? attachKanbanPointer(root.current, controller) : undefined),\n [controller],\n )\n useEffect(() => controller.startPolling(), [controller])\n useEffect(\n () => () => {\n controller.destroy()\n filters?.destroy()\n },\n [controller, filters],\n )\n\n const state = useStore(controller.store)\n const schema = controller.schema\n const lanes = controller.lanes()\n const keys = state.columns.flatMap((column) => column.cards.map((card) => card.key))\n const current = focused !== null && keys.includes(focused) ? focused : (keys[0] ?? null)\n\n const focus = (key: string | undefined) => {\n if (!key) return\n setFocused(key)\n requestAnimationFrame(() => cards.current.get(key)?.focus())\n }\n\n // A card picked up with the keyboard moves to another list: keep the focus on it.\n const picked = state.picked\n\n useEffect(() => {\n if (picked?.via === 'keyboard') {\n const element = cards.current.get(picked.key)\n\n if (element && document.activeElement !== element) element.focus()\n }\n }, [picked])\n\n const onKeyDown = (key: string) => (event: KeyboardEvent<HTMLElement>) => {\n if (event.target !== event.currentTarget) return\n\n const result = controller.handleKey(key, event, direction)\n\n if (!result.handled) return\n\n event.preventDefault()\n\n if (result.open) controller.open(key)\n else focus(result.focus)\n }\n\n const template = state.columns\n .map((column) => (state.collapsed.has(column.key) ? '3.25rem' : 'minmax(16rem, 20rem)'))\n .join(' ')\n\n return (\n <Card\n ref={root}\n role=\"region\"\n aria-labelledby={labelId}\n className=\"gap-3 py-4\"\n data-slot=\"kanban\"\n >\n <div className=\"flex flex-wrap items-center gap-2 px-4\" data-slot=\"kanban-toolbar\">\n {schema.heading ? (\n <CardTitle id={labelId} className=\"text-base\">\n {schema.heading}\n </CardTitle>\n ) : (\n <span id={labelId} className=\"sr-only\">\n {t('kanban.label', {}, 'Kanban board')}\n </span>\n )}\n <div className=\"ms-auto flex w-full flex-wrap items-center gap-2 sm:w-auto\">\n {state.loading && (\n <Spinner className=\"size-4\" aria-label={t('kanban.loading', {}, 'Loading board')} />\n )}\n {schema.searchable && (\n <KanbanSearch controller={controller} search={state.search} t={t} />\n )}\n {filters && <KanbanFilters controller={controller} store={filters} t={t} />}\n </div>\n </div>\n <p id={instructionsId} className=\"sr-only\">\n {t(\n 'kanban.instructions',\n {},\n 'Press Space to pick up a card. While it is picked up, use the arrow keys to move it, Space to drop it and Escape to cancel.',\n )}\n </p>\n <div\n className=\"relative overflow-x-auto overscroll-x-contain px-4 pb-2\"\n data-slot=\"kanban-scroller\"\n >\n <div\n className=\"grid w-max min-w-full snap-x gap-3\"\n style={{ gridTemplateColumns: template }}\n >\n {state.columns.map((column) => (\n <ColumnHeader\n key={column.key}\n column={column}\n id={`${labelId}-column-${column.key}`}\n collapsed={state.collapsed.has(column.key)}\n creatable={Boolean(column.creatable && schema.createAction)}\n filtered={state.search !== '' || kanbanActiveFilters(state.filters) > 0}\n onToggle={() => controller.toggleColumn(column.key)}\n onCreate={() => controller.create(column.key)}\n t={t}\n />\n ))}\n {lanes.map((lane) => {\n const laneId = lane ? `${labelId}-lane-${lane.key}` : undefined\n const collapsedLane = lane !== null && state.collapsedLanes.has(lane.key)\n\n return (\n <Fragment key={lane?.key ?? '__board'}>\n {lane && (\n <LaneHeader\n lane={lane}\n id={laneId!}\n count={state.columns.reduce(\n (sum, column) => sum + kanbanCardsIn(column, lane.key).length,\n 0,\n )}\n collapsed={collapsedLane}\n onToggle={() => controller.toggleLane(lane.key)}\n t={t}\n />\n )}\n {!collapsedLane &&\n state.columns.map((column) => {\n const collapsed = state.collapsed.has(column.key)\n const items = kanbanCardsIn(column, lane?.key ?? null)\n const hidden = lane === null ? column.total - column.cards.length : 0\n\n return (\n <ul\n key={column.key}\n role=\"list\"\n aria-labelledby={[`${labelId}-column-${column.key}`, laneId]\n .filter(Boolean)\n .join(' ')}\n data-slot=\"kanban-dropzone\"\n data-column={column.key}\n data-lane={lane?.key}\n data-refused={\n state.picked && state.refused?.column === column.key ? '' : undefined\n }\n className={cn(\n 'bg-muted/40 flex min-h-24 flex-col gap-2 rounded-lg p-2',\n lane === null && 'max-h-[70vh] overflow-y-auto',\n )}\n >\n {!collapsed &&\n items.map((card) => (\n <KanbanCard\n key={card.key}\n card={card}\n board={schema}\n token={page.token}\n current={current === card.key}\n picked={state.picked?.key === card.key ? state.picked.via : undefined}\n saving={state.saving.has(card.key)}\n describedBy={instructionsId}\n formatter={formatter}\n t={t}\n setRef={(element) => {\n if (element) cards.current.set(card.key, element)\n else cards.current.delete(card.key)\n }}\n onFocus={() => setFocused(card.key)}\n onKeyDown={onKeyDown(card.key)}\n onOpen={() => controller.open(card.key)}\n />\n ))}\n {!collapsed && items.length === 0 && (\n <li\n className=\"text-muted-foreground rounded-md border border-dashed px-2 py-6 text-center text-xs\"\n data-slot=\"kanban-empty\"\n >\n {state.search !== '' || kanbanActiveFilters(state.filters) > 0\n ? t('kanban.no_results', {}, 'No cards match')\n : (column.emptyState ?? t('kanban.empty', {}, 'No cards'))}\n </li>\n )}\n {!collapsed && hidden > 0 && (\n <li className=\"text-muted-foreground px-2 text-center text-xs\">\n {t('kanban.more_cards', { count: hidden }, '+:count more')}\n </li>\n )}\n </ul>\n )\n })}\n </Fragment>\n )\n })}\n </div>\n </div>\n <div className=\"sr-only\" role=\"status\" aria-live=\"polite\">\n {state.announcement}\n </div>\n </Card>\n )\n}\n\nfunction KanbanSearch({\n controller,\n search,\n t,\n}: {\n controller: KanbanController\n search: string\n t: Translate\n}) {\n const [value, setValue] = useState(search)\n const [synced, setSynced] = useState(search)\n\n if (synced !== search) {\n setSynced(search)\n setValue(search)\n }\n\n return (\n <div className=\"relative w-full sm:w-64\">\n <SearchIcon\n className=\"text-muted-foreground pointer-events-none absolute start-2.5 top-1/2 size-4 -translate-y-1/2\"\n aria-hidden=\"true\"\n />\n <Input\n type=\"search\"\n value={value}\n className=\"h-8 ps-8\"\n placeholder={t('kanban.search_placeholder', {}, 'Search…')}\n aria-label={t('kanban.search', {}, 'Search cards')}\n onChange={(event) => {\n setValue(event.target.value)\n controller.setSearch(event.target.value)\n }}\n />\n </div>\n )\n}\n\nfunction KanbanFilters({\n controller,\n store,\n t,\n}: {\n controller: KanbanController\n store: NonNullable<ReturnType<typeof createKanbanFiltersStore>>\n t: Translate\n}) {\n const form = useStore(store.store)\n const [initial] = useState(() => ({\n components: store.state.components,\n state: store.state.values,\n columns: store.state.columns,\n }))\n const active = kanbanActiveFilters(form.values)\n\n useEffect(() => {\n if (form.dirty.size > 0) controller.setFilters(form.values)\n }, [controller, form.values, form.dirty])\n\n return (\n <Popover>\n <PopoverTrigger asChild>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" data-slot=\"kanban-filters\">\n <FilterIcon aria-hidden=\"true\" />\n {t('kanban.filters', {}, 'Filters')}\n {active > 0 && <Badge className=\"h-5 min-w-5 px-1\">{active}</Badge>}\n </Button>\n </PopoverTrigger>\n <PopoverContent align=\"end\" className=\"w-80 sm:w-96\">\n <FormProvider store={store}>\n <div className=\"flex flex-col gap-4\">\n <SchemaRenderer components={form.components} columns={form.columns} className=\"gap-4\" />\n {active > 0 && (\n <div className=\"flex justify-end\">\n <Button\n type=\"button\"\n variant=\"link\"\n size=\"sm\"\n onClick={() => {\n store.fill(initial)\n controller.setFilters(null, 0)\n }}\n >\n {t('kanban.reset_filters', {}, 'Reset')}\n </Button>\n </div>\n )}\n </div>\n </FormProvider>\n </PopoverContent>\n </Popover>\n )\n}\n\nfunction ColumnHeader({\n column,\n id,\n collapsed,\n creatable,\n filtered,\n onToggle,\n onCreate,\n t,\n}: {\n column: KanbanColumnSchema\n id: string\n collapsed: boolean\n creatable: boolean\n filtered: boolean\n onToggle: () => void\n onCreate: () => void\n t: Translate\n}) {\n const choice = useChoice()\n const wip = kanbanWipState(column)\n const shown =\n column.wipLimit !== undefined ? column.count : filtered ? column.total : column.count\n const countLabel =\n column.wipLimit !== undefined\n ? t('kanban.wip', { count: column.count, limit: column.wipLimit }, ':count of :limit')\n : filtered && column.total !== column.count\n ? t(\n 'kanban.count_filtered',\n { shown: column.total, count: column.count },\n ':shown of :count cards',\n )\n : choice('kanban.count', column.count, {}, '{1} :count card|[0,*] :count cards')\n const style = column.color ? { borderTopColor: cssColor(column.color) } : undefined\n const toggleLabel = collapsed\n ? t('kanban.expand', { column: column.label }, 'Expand :column')\n : t('kanban.collapse', { column: column.label }, 'Collapse :column')\n\n if (collapsed) {\n return (\n <div\n className=\"bg-muted/60 flex snap-start flex-col items-center gap-2 rounded-lg border border-t-4 px-1 py-2\"\n style={style}\n data-slot=\"kanban-column-header\"\n data-column={column.key}\n data-collapsed=\"\"\n data-wip={wip ?? undefined}\n >\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n aria-label={toggleLabel}\n aria-expanded={false}\n onClick={onToggle}\n >\n <ChevronsLeftRightIcon aria-hidden=\"true\" />\n </Button>\n <span className=\"text-muted-foreground text-xs tabular-nums\" title={countLabel}>\n {shown}\n </span>\n <h3 id={id} className=\"text-sm font-medium [writing-mode:vertical-rl]\">\n {column.label}\n </h3>\n </div>\n )\n }\n\n return (\n <div\n className=\"bg-muted/60 flex snap-start flex-col gap-1 rounded-lg border border-t-4 px-3 py-2\"\n style={style}\n data-slot=\"kanban-column-header\"\n data-column={column.key}\n data-wip={wip ?? undefined}\n >\n <div className=\"flex items-center gap-2\">\n {column.icon && <Icon name={column.icon} className=\"text-muted-foreground size-4\" />}\n <h3 id={id} className=\"min-w-0 truncate text-sm font-semibold\">\n {column.label}\n </h3>\n <Badge\n variant=\"secondary\"\n className={cn(\n 'h-5 px-1.5 tabular-nums',\n wip === 'over' && 'bg-destructive/15 text-destructive',\n wip === 'full' && 'bg-warning/15 text-warning',\n )}\n title={countLabel}\n >\n <span aria-hidden=\"true\">\n {column.wipLimit !== undefined ? `${column.count}/${column.wipLimit}` : shown}\n </span>\n <span className=\"sr-only\">{countLabel}</span>\n </Badge>\n <div className=\"ms-auto flex items-center\">\n {creatable && (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n aria-label={t('kanban.add_card', { column: column.label }, 'Add a card to :column')}\n title={t('kanban.add_card', { column: column.label }, 'Add a card to :column')}\n onClick={onCreate}\n >\n <PlusIcon aria-hidden=\"true\" />\n </Button>\n )}\n {column.collapsible && (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n aria-label={toggleLabel}\n title={toggleLabel}\n aria-expanded={true}\n onClick={onToggle}\n >\n <ChevronsRightLeftIcon aria-hidden=\"true\" />\n </Button>\n )}\n </div>\n </div>\n {column.description && (\n <p className=\"text-muted-foreground line-clamp-2 text-xs\">{column.description}</p>\n )}\n {wip === 'over' && (\n <p className=\"text-destructive text-xs\">\n {choice(\n 'kanban.wip_over',\n column.wipLimit ?? 0,\n { limit: column.wipLimit ?? 0 },\n '{1} Over the limit of :limit card|[0,*] Over the limit of :limit cards',\n )}\n </p>\n )}\n {wip === 'full' && column.wipStrict && (\n <p className=\"text-muted-foreground text-xs\">\n {t('kanban.wip_full', {}, 'This column is full')}\n </p>\n )}\n </div>\n )\n}\n\nfunction LaneHeader({\n lane,\n id,\n count,\n collapsed,\n onToggle,\n t,\n}: {\n lane: KanbanLaneSchema\n id: string\n count: number\n collapsed: boolean\n onToggle: () => void\n t: Translate\n}) {\n return (\n <div\n className=\"flex items-center gap-2 pt-2\"\n style={{ gridColumn: '1 / -1' }}\n data-slot=\"kanban-lane\"\n data-lane={lane.key}\n >\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n aria-expanded={!collapsed}\n aria-label={\n collapsed\n ? t('kanban.expand_lane', { lane: lane.label }, 'Expand row :lane')\n : t('kanban.collapse_lane', { lane: lane.label }, 'Collapse row :lane')\n }\n onClick={onToggle}\n >\n <ChevronRightIcon\n className={cn(\n 'transition-transform rtl:rotate-180',\n !collapsed && 'rotate-90 rtl:rotate-90',\n )}\n aria-hidden=\"true\"\n />\n </Button>\n {lane.avatar ? (\n <Avatar className=\"size-6\">\n <AvatarImage src={lane.avatar} alt=\"\" />\n <AvatarFallback>{kanbanInitials(lane.label)}</AvatarFallback>\n </Avatar>\n ) : (\n lane.icon && <Icon name={lane.icon} className=\"text-muted-foreground size-4\" />\n )}\n <span id={id} className=\"text-sm font-semibold\">\n {lane.label}\n </span>\n <Badge variant=\"secondary\" className=\"h-5 px-1.5 tabular-nums\">\n {count}\n </Badge>\n </div>\n )\n}\n\nfunction KanbanCard({\n card,\n board,\n token,\n current,\n picked,\n saving,\n describedBy,\n formatter,\n t,\n setRef,\n onFocus,\n onKeyDown,\n onOpen,\n}: {\n card: KanbanCardSchema\n board: KanbanSchema\n token: string\n current: boolean\n picked: 'keyboard' | 'pointer' | undefined\n saving: boolean\n describedBy: string\n formatter: LocaleFormatter\n t: Translate\n setRef: (element: HTMLElement | null) => void\n onFocus: () => void\n onKeyDown: (event: KeyboardEvent<HTMLElement>) => void\n onOpen: () => void\n}) {\n const titleId = useId()\n const opens = card.clickable !== false && Boolean(card.url || board.cardAction)\n const assignees = card.assignees ?? []\n const shownAssignees = assignees.slice(0, 3)\n\n return (\n <li\n className=\"relative\"\n data-slot=\"kanban-card\"\n data-key={card.key}\n data-movable={board.movable && card.movable !== false ? undefined : 'false'}\n data-picked={picked}\n data-saving={saving ? '' : undefined}\n >\n <div\n ref={setRef}\n role=\"button\"\n tabIndex={current ? 0 : -1}\n aria-labelledby={titleId}\n aria-describedby={describedBy}\n aria-disabled={opens ? undefined : true}\n data-slot=\"kanban-card-body\"\n className={cn(\n 'bg-card text-card-foreground focus-visible:ring-ring/50 flex touch-manipulation flex-col gap-2 overflow-hidden rounded-lg border p-3 text-start shadow-xs outline-none select-none focus-visible:ring-[3px]',\n opens && 'hover:border-ring/60 cursor-pointer',\n card.color && 'border-s-4',\n )}\n style={card.color ? { borderInlineStartColor: cssColor(card.color) } : undefined}\n onFocus={(event) => event.target === event.currentTarget && onFocus()}\n onKeyDown={onKeyDown}\n onClick={() => opens && onOpen()}\n >\n {card.coverImage && (\n <img\n src={card.coverImage}\n alt={card.coverImageAlt ?? ''}\n loading=\"lazy\"\n draggable={false}\n className=\"-mx-3 -mt-3 h-32 w-[calc(100%+1.5rem)] max-w-none object-cover\"\n />\n )}\n <span\n id={titleId}\n className={cn('text-sm leading-snug font-medium', card.actions && 'pe-7')}\n >\n {card.title}\n </span>\n {card.description && (\n <p className=\"text-muted-foreground line-clamp-3 text-xs\">{card.description}</p>\n )}\n {card.badges && card.badges.length > 0 && (\n <div className=\"flex flex-wrap gap-1\">\n {card.badges.map((badge, index) => (\n <Badge\n key={index}\n variant=\"outline\"\n title={badge.tooltip}\n className={colorClass(badgeColorClasses, badge.color, 'gray')}\n >\n {badge.icon && <Icon name={badge.icon} />}\n {badge.label}\n </Badge>\n ))}\n </div>\n )}\n {card.schema && card.schema.length > 0 && (\n <SchemaRenderer components={card.schema} className=\"gap-2 text-xs\" />\n )}\n {card.progress !== undefined && (\n <div\n role=\"progressbar\"\n aria-valuemin={0}\n aria-valuemax={100}\n aria-valuenow={Math.round(card.progress)}\n aria-label={t(\n 'kanban.progress',\n { percent: formatter.percent(card.progress / 100) },\n ':percent complete',\n )}\n className=\"bg-muted h-1.5 overflow-hidden rounded-full\"\n >\n <div\n className=\"bg-primary h-full rounded-full\"\n style={{ width: `${card.progress}%` }}\n />\n </div>\n )}\n {(card.dueDate || assignees.length > 0) && (\n <div className=\"flex items-center gap-2 text-xs\">\n {card.dueDate && (\n <span\n className={cn(\n 'inline-flex items-center gap-1',\n card.overdue ? 'text-destructive font-medium' : 'text-muted-foreground',\n )}\n >\n <CalendarIcon className=\"size-3.5\" aria-hidden=\"true\" />\n <span className=\"sr-only\">\n {t('kanban.due', { date: formatter.date(card.dueDate) }, 'Due :date')}\n </span>\n <time dateTime={card.dueDate} aria-hidden=\"true\">\n {formatter.date(card.dueDate)}\n </time>\n {card.overdue && (\n <span className=\"sr-only\">{t('kanban.overdue', {}, 'Overdue')}</span>\n )}\n </span>\n )}\n {assignees.length > 0 && (\n <div className=\"ms-auto flex items-center\">\n <span className=\"sr-only\">\n {t(\n 'kanban.assignees',\n { names: formatter.list(assignees.map((assignee) => assignee.name)) },\n 'Assigned to :names',\n )}\n </span>\n <div className=\"flex -space-x-1.5 rtl:space-x-reverse\" aria-hidden=\"true\">\n {shownAssignees.map((assignee, index) => (\n <Avatar key={index} className=\"ring-card size-6 ring-2\" title={assignee.name}>\n {assignee.avatar && <AvatarImage src={assignee.avatar} alt=\"\" />}\n <AvatarFallback className=\"text-[0.625rem]\">\n {kanbanInitials(assignee.name)}\n </AvatarFallback>\n </Avatar>\n ))}\n {assignees.length > shownAssignees.length && (\n <span className=\"bg-muted ring-card flex size-6 items-center justify-center rounded-full text-[0.625rem] font-medium ring-2\">\n {t(\n 'kanban.more_assignees',\n { count: assignees.length - shownAssignees.length },\n '+:count',\n )}\n </span>\n )}\n </div>\n </div>\n )}\n </div>\n )}\n </div>\n {card.actions && card.actions.length > 0 && (\n <div className=\"absolute end-1.5 top-1.5\" data-kanban-no-drag=\"\">\n <ActionList\n actions={card.actions}\n context={{ token, component: board.actionComponent, record: card.key }}\n size=\"xs\"\n />\n </div>\n )}\n </li>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8DA,SAAgB,OAAO,EACrB,WACA,UAIC;CACD,MAAM,QAAQ,aAAa,QAAQ;CAEnC,OAAO,QAAQ,oBAAC,aAAD,EAAgD,MAAQ,GAAtC,MAAM,eAAgC,IAAI;AAC7E;AAEA,SAAS,YAAY,EAAE,SAAkC;CACvD,MAAM,SAAS,gBAAgB;CAC/B,MAAM,OAAO,qBAAqB;CAClC,MAAM,QAAQ,SAAS;CACvB,MAAM,IAAI,KAAK;CACf,MAAM,YAAY,aAAa;CAC/B,MAAM,YAAY,aAAa;CAC/B,MAAM,UAAU,MAAM;CACtB,MAAM,iBAAiB,MAAM;CAC7B,MAAM,qBAAwC;EAC5C;EACA,OAAO,KAAK;EACZ;EACA,SAAS,kBAAkB,cAAc,SAAS,iBAAiB,UAAU,YAAY,CAAC;EAC1F,QAAQ,YAAY,UAAU,wBAAwB,UAAU,OAAO,CAAC;EACxE,QAAQ,QAAQ,OAAO,MAAM,GAAG;CAClC;CAEA,MAAM,CAAC,cAAc,eAAe,IAAI,iBAAiB,OAAO,YAAY,CAAC,CAAC;CAC9E,MAAM,CAAC,WAAW,eAChB,yBAAyB,OAAO,KAAK,OAAO,MAAM,UAAU,aAAa,CAC3E;CACA,MAAM,OAAO,OAAuB,IAAI;CACxC,MAAM,QAAQ,uBAAO,IAAI,IAAyB,CAAC;CACnD,MAAM,CAAC,SAAS,cAAc,SAAwB,IAAI;CAE1D,gBAAgB;EACd,WAAW,eAAe,YAAY,CAAC;CACzC,CAAC;CAED,MAAM,QAAQ,OAAO,IAAI;CAEzB,gBAAgB;EACd,IAAI,MAAM,SAAS;GACjB,MAAM,UAAU;GAEhB;EACF;EAEA,WAAW,SAAS,KAAK;CAC3B,GAAG,CAAC,YAAY,KAAK,CAAC;CAEtB,gBACS,KAAK,UAAU,oBAAoB,KAAK,SAAS,UAAU,IAAI,KAAA,GACtE,CAAC,UAAU,CACb;CACA,gBAAgB,WAAW,aAAa,GAAG,CAAC,UAAU,CAAC;CACvD,sBACc;EACV,WAAW,QAAQ;EACnB,SAAS,QAAQ;CACnB,GACA,CAAC,YAAY,OAAO,CACtB;CAEA,MAAM,QAAQ,SAAS,WAAW,KAAK;CACvC,MAAM,SAAS,WAAW;CAC1B,MAAM,QAAQ,WAAW,MAAM;CAC/B,MAAM,OAAO,MAAM,QAAQ,SAAS,WAAW,OAAO,MAAM,KAAK,SAAS,KAAK,GAAG,CAAC;CACnF,MAAM,UAAU,YAAY,QAAQ,KAAK,SAAS,OAAO,IAAI,UAAW,KAAK,MAAM;CAEnF,MAAM,SAAS,QAA4B;EACzC,IAAI,CAAC,KAAK;EACV,WAAW,GAAG;EACd,4BAA4B,MAAM,QAAQ,IAAI,GAAG,CAAC,EAAE,MAAM,CAAC;CAC7D;CAGA,MAAM,SAAS,MAAM;CAErB,gBAAgB;EACd,IAAI,QAAQ,QAAQ,YAAY;GAC9B,MAAM,UAAU,MAAM,QAAQ,IAAI,OAAO,GAAG;GAE5C,IAAI,WAAW,SAAS,kBAAkB,SAAS,QAAQ,MAAM;EACnE;CACF,GAAG,CAAC,MAAM,CAAC;CAEX,MAAM,aAAa,SAAiB,UAAsC;EACxE,IAAI,MAAM,WAAW,MAAM,eAAe;EAE1C,MAAM,SAAS,WAAW,UAAU,KAAK,OAAO,SAAS;EAEzD,IAAI,CAAC,OAAO,SAAS;EAErB,MAAM,eAAe;EAErB,IAAI,OAAO,MAAM,WAAW,KAAK,GAAG;OAC/B,MAAM,OAAO,KAAK;CACzB;CAEA,MAAM,WAAW,MAAM,QACpB,KAAK,WAAY,MAAM,UAAU,IAAI,OAAO,GAAG,IAAI,YAAY,sBAAuB,CAAC,CACvF,KAAK,GAAG;CAEX,OACE,qBAAC,MAAD;EACE,KAAK;EACL,MAAK;EACL,mBAAiB;EACjB,WAAU;EACV,aAAU;EALZ,UAAA;GAOE,qBAAC,OAAD;IAAK,WAAU;IAAyC,aAAU;IAAlE,UAAA,CACG,OAAO,UACN,oBAAC,WAAD;KAAW,IAAI;KAAS,WAAU;KAC/B,UAAA,OAAO;IACC,CAAA,IAEX,oBAAC,QAAD;KAAM,IAAI;KAAS,WAAU;KAC1B,UAAA,EAAE,gBAAgB,CAAC,GAAG,cAAc;IACjC,CAAA,GAER,qBAAC,OAAD;KAAK,WAAU;KAAf,UAAA;MACG,MAAM,WACL,oBAAC,SAAD;OAAS,WAAU;OAAS,cAAY,EAAE,kBAAkB,CAAC,GAAG,eAAe;MAAI,CAAA;MAEpF,OAAO,cACN,oBAAC,cAAD;OAA0B;OAAY,QAAQ,MAAM;OAAW;MAAI,CAAA;MAEpE,WAAW,oBAAC,eAAD;OAA2B;OAAY,OAAO;OAAY;MAAI,CAAA;KACvE;IACF,CAAA,CAAA;;GACL,oBAAC,KAAD;IAAG,IAAI;IAAgB,WAAU;IAC9B,UAAA,EACC,uBACA,CAAC,GACD,6HACF;GACC,CAAA;GACH,oBAAC,OAAD;IACE,WAAU;IACV,aAAU;IAEV,UAAA,qBAAC,OAAD;KACE,WAAU;KACV,OAAO,EAAE,qBAAqB,SAAS;KAFzC,UAAA,CAIG,MAAM,QAAQ,KAAK,WAClB,oBAAC,cAAD;MAEU;MACR,IAAI,GAAG,QAAQ,UAAU,OAAO;MAChC,WAAW,MAAM,UAAU,IAAI,OAAO,GAAG;MACzC,WAAW,QAAQ,OAAO,aAAa,OAAO,YAAY;MAC1D,UAAU,MAAM,WAAW,MAAM,oBAAoB,MAAM,OAAO,IAAI;MACtE,gBAAgB,WAAW,aAAa,OAAO,GAAG;MAClD,gBAAgB,WAAW,OAAO,OAAO,GAAG;MACzC;KACJ,GATM,OAAO,GASb,CACF,GACA,MAAM,KAAK,SAAS;MACnB,MAAM,SAAS,OAAO,GAAG,QAAQ,QAAQ,KAAK,QAAQ,KAAA;MACtD,MAAM,gBAAgB,SAAS,QAAQ,MAAM,eAAe,IAAI,KAAK,GAAG;MAExE,OACE,qBAAC,UAAD,EAAA,UAAA,CACG,QACC,oBAAC,YAAD;OACQ;OACN,IAAI;OACJ,OAAO,MAAM,QAAQ,QAClB,KAAK,WAAW,MAAM,cAAc,QAAQ,KAAK,GAAG,CAAC,CAAC,QACvD,CACF;OACA,WAAW;OACX,gBAAgB,WAAW,WAAW,KAAK,GAAG;OAC3C;MACJ,CAAA,GAEF,CAAC,iBACA,MAAM,QAAQ,KAAK,WAAW;OAC5B,MAAM,YAAY,MAAM,UAAU,IAAI,OAAO,GAAG;OAChD,MAAM,QAAQ,cAAc,QAAQ,MAAM,OAAO,IAAI;OACrD,MAAM,SAAS,SAAS,OAAO,OAAO,QAAQ,OAAO,MAAM,SAAS;OAEpE,OACE,qBAAC,MAAD;QAEE,MAAK;QACL,mBAAiB,CAAC,GAAG,QAAQ,UAAU,OAAO,OAAO,MAAM,CAAC,CACzD,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;QACX,aAAU;QACV,eAAa,OAAO;QACpB,aAAW,MAAM;QACjB,gBACE,MAAM,UAAU,MAAM,SAAS,WAAW,OAAO,MAAM,KAAK,KAAA;QAE9D,WAAW,GACT,2DACA,SAAS,QAAQ,8BACnB;QAfF,UAAA;SAiBG,CAAC,aACA,MAAM,KAAK,SACT,oBAAC,YAAD;UAEQ;UACN,OAAO;UACP,OAAO,KAAK;UACZ,SAAS,YAAY,KAAK;UAC1B,QAAQ,MAAM,QAAQ,QAAQ,KAAK,MAAM,MAAM,OAAO,MAAM,KAAA;UAC5D,QAAQ,MAAM,OAAO,IAAI,KAAK,GAAG;UACjC,aAAa;UACF;UACR;UACH,SAAS,YAAY;WACnB,IAAI,SAAS,MAAM,QAAQ,IAAI,KAAK,KAAK,OAAO;gBAC3C,MAAM,QAAQ,OAAO,KAAK,GAAG;UACpC;UACA,eAAe,WAAW,KAAK,GAAG;UAClC,WAAW,UAAU,KAAK,GAAG;UAC7B,cAAc,WAAW,KAAK,KAAK,GAAG;SACvC,GAjBM,KAAK,GAiBX,CACF;SACF,CAAC,aAAa,MAAM,WAAW,KAC9B,oBAAC,MAAD;UACE,WAAU;UACV,aAAU;UAET,UAAA,MAAM,WAAW,MAAM,oBAAoB,MAAM,OAAO,IAAI,IACzD,EAAE,qBAAqB,CAAC,GAAG,gBAAgB,IAC1C,OAAO,cAAc,EAAE,gBAAgB,CAAC,GAAG,UAAU;SACxD,CAAA;SAEL,CAAC,aAAa,SAAS,KACtB,oBAAC,MAAD;UAAI,WAAU;UACX,UAAA,EAAE,qBAAqB,EAAE,OAAO,OAAO,GAAG,cAAc;SACvD,CAAA;QAEJ;OArDG,GAAA,OAAO,GAqDV;MAER,CAAC,CACK,EAAA,GA9EK,MAAM,OAAO,SA8ElB;KAEd,CAAC,CACE;;GACF,CAAA;GACL,oBAAC,OAAD;IAAK,WAAU;IAAU,MAAK;IAAS,aAAU;IAC9C,UAAA,MAAM;GACJ,CAAA;EACD;;AAEV;AAEA,SAAS,aAAa,EACpB,YACA,QACA,KAKC;CACD,MAAM,CAAC,OAAO,YAAY,SAAS,MAAM;CACzC,MAAM,CAAC,QAAQ,aAAa,SAAS,MAAM;CAE3C,IAAI,WAAW,QAAQ;EACrB,UAAU,MAAM;EAChB,SAAS,MAAM;CACjB;CAEA,OACE,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA,CACE,oBAAC,YAAD;GACE,WAAU;GACV,eAAY;EACb,CAAA,GACD,oBAAC,OAAD;GACE,MAAK;GACE;GACP,WAAU;GACV,aAAa,EAAE,6BAA6B,CAAC,GAAG,SAAS;GACzD,cAAY,EAAE,iBAAiB,CAAC,GAAG,cAAc;GACjD,WAAW,UAAU;IACnB,SAAS,MAAM,OAAO,KAAK;IAC3B,WAAW,UAAU,MAAM,OAAO,KAAK;GACzC;EACD,CAAA,CACE;;AAET;AAEA,SAAS,cAAc,EACrB,YACA,OACA,KAKC;CACD,MAAM,OAAO,SAAS,MAAM,KAAK;CACjC,MAAM,CAAC,WAAW,gBAAgB;EAChC,YAAY,MAAM,MAAM;EACxB,OAAO,MAAM,MAAM;EACnB,SAAS,MAAM,MAAM;CACvB,EAAE;CACF,MAAM,SAAS,oBAAoB,KAAK,MAAM;CAE9C,gBAAgB;EACd,IAAI,KAAK,MAAM,OAAO,GAAG,WAAW,WAAW,KAAK,MAAM;CAC5D,GAAG;EAAC;EAAY,KAAK;EAAQ,KAAK;CAAK,CAAC;CAExC,OACE,qBAAC,SAAD,EAAA,UAAA,CACE,oBAAC,gBAAD;EAAgB,SAAA;EACd,UAAA,qBAAC,QAAD;GAAQ,MAAK;GAAS,SAAQ;GAAU,MAAK;GAAK,aAAU;GAA5D,UAAA;IACE,oBAAC,YAAD,EAAY,eAAY,OAAQ,CAAA;IAC/B,EAAE,kBAAkB,CAAC,GAAG,SAAS;IACjC,SAAS,KAAK,oBAAC,OAAD;KAAO,WAAU;KAAoB,UAAA;IAAc,CAAA;GAC5D;;CACM,CAAA,GAChB,oBAAC,gBAAD;EAAgB,OAAM;EAAM,WAAU;EACpC,UAAA,oBAAC,cAAD;GAAqB;GACnB,UAAA,qBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,oBAAC,gBAAD;KAAgB,YAAY,KAAK;KAAY,SAAS,KAAK;KAAS,WAAU;IAAS,CAAA,GACtF,SAAS,KACR,oBAAC,OAAD;KAAK,WAAU;KACb,UAAA,oBAAC,QAAD;MACE,MAAK;MACL,SAAQ;MACR,MAAK;MACL,eAAe;OACb,MAAM,KAAK,OAAO;OAClB,WAAW,WAAW,MAAM,CAAC;MAC/B;MAEC,UAAA,EAAE,wBAAwB,CAAC,GAAG,OAAO;KAChC,CAAA;IACL,CAAA,CAEJ;;EACO,CAAA;CACA,CAAA,CACT,EAAA,CAAA;AAEb;AAEA,SAAS,aAAa,EACpB,QACA,IACA,WACA,WACA,UACA,UACA,UACA,KAUC;CACD,MAAM,SAAS,UAAU;CACzB,MAAM,MAAM,eAAe,MAAM;CACjC,MAAM,QACJ,OAAO,aAAa,KAAA,IAAY,OAAO,QAAQ,WAAW,OAAO,QAAQ,OAAO;CAClF,MAAM,aACJ,OAAO,aAAa,KAAA,IAChB,EAAE,cAAc;EAAE,OAAO,OAAO;EAAO,OAAO,OAAO;CAAS,GAAG,kBAAkB,IACnF,YAAY,OAAO,UAAU,OAAO,QAClC,EACE,yBACA;EAAE,OAAO,OAAO;EAAO,OAAO,OAAO;CAAM,GAC3C,wBACF,IACA,OAAO,gBAAgB,OAAO,OAAO,CAAC,GAAG,oCAAoC;CACrF,MAAM,QAAQ,OAAO,QAAQ,EAAE,gBAAgB,SAAS,OAAO,KAAK,EAAE,IAAI,KAAA;CAC1E,MAAM,cAAc,YAChB,EAAE,iBAAiB,EAAE,QAAQ,OAAO,MAAM,GAAG,gBAAgB,IAC7D,EAAE,mBAAmB,EAAE,QAAQ,OAAO,MAAM,GAAG,kBAAkB;CAErE,IAAI,WACF,OACE,qBAAC,OAAD;EACE,WAAU;EACH;EACP,aAAU;EACV,eAAa,OAAO;EACpB,kBAAe;EACf,YAAU,OAAO,KAAA;EANnB,UAAA;GAQE,oBAAC,QAAD;IACE,MAAK;IACL,SAAQ;IACR,MAAK;IACL,cAAY;IACZ,iBAAe;IACf,SAAS;IAET,UAAA,oBAAC,uBAAD,EAAuB,eAAY,OAAQ,CAAA;GACrC,CAAA;GACR,oBAAC,QAAD;IAAM,WAAU;IAA6C,OAAO;IACjE,UAAA;GACG,CAAA;GACN,oBAAC,MAAD;IAAQ;IAAI,WAAU;IACnB,UAAA,OAAO;GACN,CAAA;EACD;;CAIT,OACE,qBAAC,OAAD;EACE,WAAU;EACH;EACP,aAAU;EACV,eAAa,OAAO;EACpB,YAAU,OAAO,KAAA;EALnB,UAAA;GAOE,qBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KACG,OAAO,QAAQ,oBAAC,MAAD;MAAM,MAAM,OAAO;MAAM,WAAU;KAAgC,CAAA;KACnF,oBAAC,MAAD;MAAQ;MAAI,WAAU;MACnB,UAAA,OAAO;KACN,CAAA;KACJ,qBAAC,OAAD;MACE,SAAQ;MACR,WAAW,GACT,2BACA,QAAQ,UAAU,sCAClB,QAAQ,UAAU,4BACpB;MACA,OAAO;MAPT,UAAA,CASE,oBAAC,QAAD;OAAM,eAAY;OACf,UAAA,OAAO,aAAa,KAAA,IAAY,GAAG,OAAO,MAAM,GAAG,OAAO,aAAa;MACpE,CAAA,GACN,oBAAC,QAAD;OAAM,WAAU;OAAW,UAAA;MAAiB,CAAA,CACvC;;KACP,qBAAC,OAAD;MAAK,WAAU;MAAf,UAAA,CACG,aACC,oBAAC,QAAD;OACE,MAAK;OACL,SAAQ;OACR,MAAK;OACL,cAAY,EAAE,mBAAmB,EAAE,QAAQ,OAAO,MAAM,GAAG,uBAAuB;OAClF,OAAO,EAAE,mBAAmB,EAAE,QAAQ,OAAO,MAAM,GAAG,uBAAuB;OAC7E,SAAS;OAET,UAAA,oBAAC,UAAD,EAAU,eAAY,OAAQ,CAAA;MACxB,CAAA,GAET,OAAO,eACN,oBAAC,QAAD;OACE,MAAK;OACL,SAAQ;OACR,MAAK;OACL,cAAY;OACZ,OAAO;OACP,iBAAe;OACf,SAAS;OAET,UAAA,oBAAC,uBAAD,EAAuB,eAAY,OAAQ,CAAA;MACrC,CAAA,CAEP;;IACF;;GACJ,OAAO,eACN,oBAAC,KAAD;IAAG,WAAU;IAA8C,UAAA,OAAO;GAAe,CAAA;GAElF,QAAQ,UACP,oBAAC,KAAD;IAAG,WAAU;IACV,UAAA,OACC,mBACA,OAAO,YAAY,GACnB,EAAE,OAAO,OAAO,YAAY,EAAE,GAC9B,wEACF;GACC,CAAA;GAEJ,QAAQ,UAAU,OAAO,aACxB,oBAAC,KAAD;IAAG,WAAU;IACV,UAAA,EAAE,mBAAmB,CAAC,GAAG,qBAAqB;GAC9C,CAAA;EAEF;;AAET;AAEA,SAAS,WAAW,EAClB,MACA,IACA,OACA,WACA,UACA,KAQC;CACD,OACE,qBAAC,OAAD;EACE,WAAU;EACV,OAAO,EAAE,YAAY,SAAS;EAC9B,aAAU;EACV,aAAW,KAAK;EAJlB,UAAA;GAME,oBAAC,QAAD;IACE,MAAK;IACL,SAAQ;IACR,MAAK;IACL,iBAAe,CAAC;IAChB,cACE,YACI,EAAE,sBAAsB,EAAE,MAAM,KAAK,MAAM,GAAG,kBAAkB,IAChE,EAAE,wBAAwB,EAAE,MAAM,KAAK,MAAM,GAAG,oBAAoB;IAE1E,SAAS;IAET,UAAA,oBAAC,kBAAD;KACE,WAAW,GACT,uCACA,CAAC,aAAa,yBAChB;KACA,eAAY;IACb,CAAA;GACK,CAAA;GACP,KAAK,SACJ,qBAAC,QAAD;IAAQ,WAAU;IAAlB,UAAA,CACE,oBAAC,aAAD;KAAa,KAAK,KAAK;KAAQ,KAAI;IAAI,CAAA,GACvC,oBAAC,gBAAD,EAAA,UAAiB,eAAe,KAAK,KAAK,EAAkB,CAAA,CACtD;GAER,CAAA,IAAA,KAAK,QAAQ,oBAAC,MAAD;IAAM,MAAM,KAAK;IAAM,WAAU;GAAgC,CAAA;GAEhF,oBAAC,QAAD;IAAU;IAAI,WAAU;IACrB,UAAA,KAAK;GACF,CAAA;GACN,oBAAC,OAAD;IAAO,SAAQ;IAAY,WAAU;IAClC,UAAA;GACI,CAAA;EACJ;;AAET;AAEA,SAAS,WAAW,EAClB,MACA,OACA,OACA,SACA,QACA,QACA,aACA,WACA,GACA,QACA,SACA,WACA,UAeC;CACD,MAAM,UAAU,MAAM;CACtB,MAAM,QAAQ,KAAK,cAAc,SAAS,QAAQ,KAAK,OAAO,MAAM,UAAU;CAC9E,MAAM,YAAY,KAAK,aAAa,CAAC;CACrC,MAAM,iBAAiB,UAAU,MAAM,GAAG,CAAC;CAE3C,OACE,qBAAC,MAAD;EACE,WAAU;EACV,aAAU;EACV,YAAU,KAAK;EACf,gBAAc,MAAM,WAAW,KAAK,YAAY,QAAQ,KAAA,IAAY;EACpE,eAAa;EACb,eAAa,SAAS,KAAK,KAAA;EAN7B,UAAA,CAQE,qBAAC,OAAD;GACE,KAAK;GACL,MAAK;GACL,UAAU,UAAU,IAAI;GACxB,mBAAiB;GACjB,oBAAkB;GAClB,iBAAe,QAAQ,KAAA,IAAY;GACnC,aAAU;GACV,WAAW,GACT,+MACA,SAAS,uCACT,KAAK,SAAS,YAChB;GACA,OAAO,KAAK,QAAQ,EAAE,wBAAwB,SAAS,KAAK,KAAK,EAAE,IAAI,KAAA;GACvE,UAAU,UAAU,MAAM,WAAW,MAAM,iBAAiB,QAAQ;GACzD;GACX,eAAe,SAAS,OAAO;GAhBjC,UAAA;IAkBG,KAAK,cACJ,oBAAC,OAAD;KACE,KAAK,KAAK;KACV,KAAK,KAAK,iBAAiB;KAC3B,SAAQ;KACR,WAAW;KACX,WAAU;IACX,CAAA;IAEH,oBAAC,QAAD;KACE,IAAI;KACJ,WAAW,GAAG,oCAAoC,KAAK,WAAW,MAAM;KAEvE,UAAA,KAAK;IACF,CAAA;IACL,KAAK,eACJ,oBAAC,KAAD;KAAG,WAAU;KAA8C,UAAA,KAAK;IAAe,CAAA;IAEhF,KAAK,UAAU,KAAK,OAAO,SAAS,KACnC,oBAAC,OAAD;KAAK,WAAU;KACZ,UAAA,KAAK,OAAO,KAAK,OAAO,UACvB,qBAAC,OAAD;MAEE,SAAQ;MACR,OAAO,MAAM;MACb,WAAW,WAAW,mBAAmB,MAAM,OAAO,MAAM;MAJ9D,UAAA,CAMG,MAAM,QAAQ,oBAAC,MAAD,EAAM,MAAM,MAAM,KAAO,CAAA,GACvC,MAAM,KACF;KAPA,GAAA,KAOA,CACR;IACE,CAAA;IAEN,KAAK,UAAU,KAAK,OAAO,SAAS,KACnC,oBAAC,gBAAD;KAAgB,YAAY,KAAK;KAAQ,WAAU;IAAiB,CAAA;IAErE,KAAK,aAAa,KAAA,KACjB,oBAAC,OAAD;KACE,MAAK;KACL,iBAAe;KACf,iBAAe;KACf,iBAAe,KAAK,MAAM,KAAK,QAAQ;KACvC,cAAY,EACV,mBACA,EAAE,SAAS,UAAU,QAAQ,KAAK,WAAW,GAAG,EAAE,GAClD,mBACF;KACA,WAAU;KAEV,UAAA,oBAAC,OAAD;MACE,WAAU;MACV,OAAO,EAAE,OAAO,GAAG,KAAK,SAAS,GAAG;KACrC,CAAA;IACE,CAAA;KAEL,KAAK,WAAW,UAAU,SAAS,MACnC,qBAAC,OAAD;KAAK,WAAU;KAAf,UAAA,CACG,KAAK,WACJ,qBAAC,QAAD;MACE,WAAW,GACT,kCACA,KAAK,UAAU,iCAAiC,uBAClD;MAJF,UAAA;OAME,oBAAC,cAAD;QAAc,WAAU;QAAW,eAAY;OAAQ,CAAA;OACvD,oBAAC,QAAD;QAAM,WAAU;QACb,UAAA,EAAE,cAAc,EAAE,MAAM,UAAU,KAAK,KAAK,OAAO,EAAE,GAAG,WAAW;OAChE,CAAA;OACN,oBAAC,QAAD;QAAM,UAAU,KAAK;QAAS,eAAY;QACvC,UAAA,UAAU,KAAK,KAAK,OAAO;OACxB,CAAA;OACL,KAAK,WACJ,oBAAC,QAAD;QAAM,WAAU;QAAW,UAAA,EAAE,kBAAkB,CAAC,GAAG,SAAS;OAAQ,CAAA;MAElE;KAEP,CAAA,GAAA,UAAU,SAAS,KAClB,qBAAC,OAAD;MAAK,WAAU;MAAf,UAAA,CACE,oBAAC,QAAD;OAAM,WAAU;OACb,UAAA,EACC,oBACA,EAAE,OAAO,UAAU,KAAK,UAAU,KAAK,aAAa,SAAS,IAAI,CAAC,EAAE,GACpE,oBACF;MACI,CAAA,GACN,qBAAC,OAAD;OAAK,WAAU;OAAwC,eAAY;OAAnE,UAAA,CACG,eAAe,KAAK,UAAU,UAC7B,qBAAC,QAAD;QAAoB,WAAU;QAA0B,OAAO,SAAS;QAAxE,UAAA,CACG,SAAS,UAAU,oBAAC,aAAD;SAAa,KAAK,SAAS;SAAQ,KAAI;QAAI,CAAA,GAC/D,oBAAC,gBAAD;SAAgB,WAAU;SACvB,UAAA,eAAe,SAAS,IAAI;QACf,CAAA,CACV;OALK,GAAA,KAKL,CACT,GACA,UAAU,SAAS,eAAe,UACjC,oBAAC,QAAD;QAAM,WAAU;QACb,UAAA,EACC,yBACA,EAAE,OAAO,UAAU,SAAS,eAAe,OAAO,GAClD,SACF;OACI,CAAA,CAEL;MACF,CAAA,CAAA;KAEJ,CAAA,CAAA;;GAEJ;EACJ,CAAA,GAAA,KAAK,WAAW,KAAK,QAAQ,SAAS,KACrC,oBAAC,OAAD;GAAK,WAAU;GAA2B,uBAAoB;GAC5D,UAAA,oBAAC,YAAD;IACE,SAAS,KAAK;IACd,SAAS;KAAE;KAAO,WAAW,MAAM;KAAiB,QAAQ,KAAK;IAAI;IACrE,MAAK;GACN,CAAA;EACE,CAAA,CAEL;;AAER"}
@@ -49,8 +49,8 @@ function SectionComponent({ component }) {
49
49
  }),
50
50
  /* @__PURE__ */ jsxs("div", {
51
51
  className: "min-w-0 flex-1 basis-48",
52
- children: [component.heading && createElement(headingTag(component.headingLevel), { className: "text-base leading-6 font-semibold" }, component.heading), component.description && /* @__PURE__ */ jsx("p", {
53
- className: "text-muted-foreground mt-1 text-sm",
52
+ children: [component.heading && createElement(headingTag(component.headingLevel), { className: "text-base leading-6 font-semibold break-words" }, component.heading), component.description && /* @__PURE__ */ jsx("p", {
53
+ className: "text-muted-foreground mt-1 text-sm break-words",
54
54
  children: component.description
55
55
  })]
56
56
  }),
@@ -1 +1 @@
1
- {"version":3,"file":"section.js","names":[],"sources":["../../../src/components/layout/section.tsx"],"sourcesContent":["import type { SectionSchema } from '@alfakit/core'\nimport {\n actionsAlignmentClass,\n headingTag,\n readPersisted,\n schemaGapClass,\n writePersisted,\n} from '@alfakit/core'\nimport { ChevronDownIcon } from 'lucide-react'\nimport { createElement, useState } from 'react'\nimport { useT } from '../../context'\nimport { useHydrated } from '../../hooks/use-hydrated'\nimport { extraProps } from '../../lib/attributes'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport { usePageActionContext } from '../actions/action-context'\nimport { ActionList } from '../actions/action-list'\nimport { useOptionalFormStore } from '../form/form-context'\nimport { useFieldActionContext } from '../schema/field-actions'\nimport { SchemaRenderer } from '../schema/schema-renderer'\nimport { Button } from '../ui/button'\nimport { Collapsible, CollapsibleContent, CollapsibleTrigger } from '../ui/collapsible'\nimport { DeferredSchema } from './deferred'\nimport { MixedContent } from './mixed-content'\n\nexport function SectionComponent({ component }: { component: SectionSchema }) {\n const t = useT()\n const [choice, setChoice] = useState<boolean | null>(null)\n // Inside a form the section's actions run as field actions, so `$get` / `$set` work.\n const form = useOptionalFormStore()\n const pageContext = usePageActionContext()\n const fieldContext = useFieldActionContext(component)\n const context = form ? fieldContext : pageContext\n const persistKey = component.persistCollapsed\n const hydrated = useHydrated()\n // Read only after hydration, so the server render and hydration use the schema's default.\n const stored = hydrated && persistKey ? readPersisted(persistKey) : null\n const open = choice ?? (stored !== null ? stored !== 'collapsed' : !component.collapsed)\n const hasHeader =\n component.heading ||\n component.description ||\n component.icon ||\n component.headerActions?.length ||\n component.afterHeader?.length\n\n const setOpen = (next: boolean) => {\n setChoice(next)\n\n if (persistKey) writePersisted(persistKey, next ? 'expanded' : 'collapsed')\n }\n\n const content = (\n <DeferredSchema component={component}>\n {(loaded) => (\n <SchemaRenderer\n components={loaded.schema ?? []}\n columns={loaded.columns}\n className={schemaGapClass(loaded)}\n />\n )}\n </DeferredSchema>\n )\n\n const header = hasHeader ? (\n <div\n className={cn(\n 'flex flex-wrap items-start gap-3',\n component.aside ? 'lg:col-span-1' : 'border-b px-6 py-4',\n component.compact && !component.aside && 'px-4 py-3',\n )}\n >\n {component.icon && (\n <Icon name={component.icon} className=\"text-muted-foreground mt-0.5 size-5\" />\n )}\n <div className=\"min-w-0 flex-1 basis-48\">\n {component.heading &&\n createElement(\n headingTag(component.headingLevel),\n { className: 'text-base leading-6 font-semibold' },\n component.heading,\n )}\n {component.description && (\n <p className=\"text-muted-foreground mt-1 text-sm\">{component.description}</p>\n )}\n </div>\n {component.headerActions && component.headerActions.length > 0 && (\n <ActionList actions={component.headerActions} context={context} size=\"sm\" />\n )}\n <MixedContent items={component.afterHeader} name=\"section-after-header\" />\n {component.collapsible && (\n <CollapsibleTrigger asChild>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-label={t('toggle_section', {}, 'Toggle section')}\n >\n <Icon\n name=\"alfakit::schemas.section.collapse-button\"\n fallback={ChevronDownIcon}\n className={cn('transition-transform', open && 'rotate-180')}\n />\n </Button>\n </CollapsibleTrigger>\n )}\n </div>\n ) : null\n\n const hasFooterActions = Boolean(component.footerActions?.length)\n const footer =\n hasFooterActions || component.footer?.length ? (\n <div\n data-slot=\"section-footer\"\n className={cn(\n 'flex flex-wrap items-center gap-3 border-t px-6 py-4',\n component.compact && 'px-4 py-3',\n )}\n >\n {hasFooterActions && (\n <ActionList\n actions={component.footerActions ?? []}\n context={context}\n className={actionsAlignmentClass(component.footerActionsAlignment) || undefined}\n />\n )}\n <MixedContent items={component.footer} name=\"section-footer-content\" />\n </div>\n ) : null\n\n if (component.aside) {\n return (\n <Collapsible open={!component.collapsible || open} onOpenChange={setOpen} asChild>\n <section\n data-slot=\"section\"\n {...extraProps(component.extraAttributes, 'grid gap-6 lg:grid-cols-3')}\n >\n {header}\n <CollapsibleContent asChild>\n <div\n data-surface=\"section\"\n className={cn(\n 'bg-card rounded-xl border shadow-xs lg:col-span-2',\n component.secondary && 'bg-muted/40',\n )}\n >\n <div className={cn('p-6', component.compact && 'p-4')}>{content}</div>\n {footer}\n </div>\n </CollapsibleContent>\n </section>\n </Collapsible>\n )\n }\n\n return (\n <Collapsible open={!component.collapsible || open} onOpenChange={setOpen} asChild>\n <section\n data-slot=\"section\"\n data-surface=\"section\"\n {...extraProps(\n component.extraAttributes,\n cn('bg-card rounded-xl border shadow-xs', component.secondary && 'bg-muted/40'),\n )}\n >\n {header}\n <CollapsibleContent>\n <div className={cn('p-6', component.compact && 'p-4')}>{content}</div>\n {footer}\n </CollapsibleContent>\n </section>\n </Collapsible>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"section.js","names":[],"sources":["../../../src/components/layout/section.tsx"],"sourcesContent":["import type { SectionSchema } from '@alfakit/core'\nimport {\n actionsAlignmentClass,\n headingTag,\n readPersisted,\n schemaGapClass,\n writePersisted,\n} from '@alfakit/core'\nimport { ChevronDownIcon } from 'lucide-react'\nimport { createElement, useState } from 'react'\nimport { useT } from '../../context'\nimport { useHydrated } from '../../hooks/use-hydrated'\nimport { extraProps } from '../../lib/attributes'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport { usePageActionContext } from '../actions/action-context'\nimport { ActionList } from '../actions/action-list'\nimport { useOptionalFormStore } from '../form/form-context'\nimport { useFieldActionContext } from '../schema/field-actions'\nimport { SchemaRenderer } from '../schema/schema-renderer'\nimport { Button } from '../ui/button'\nimport { Collapsible, CollapsibleContent, CollapsibleTrigger } from '../ui/collapsible'\nimport { DeferredSchema } from './deferred'\nimport { MixedContent } from './mixed-content'\n\nexport function SectionComponent({ component }: { component: SectionSchema }) {\n const t = useT()\n const [choice, setChoice] = useState<boolean | null>(null)\n // Inside a form the section's actions run as field actions, so `$get` / `$set` work.\n const form = useOptionalFormStore()\n const pageContext = usePageActionContext()\n const fieldContext = useFieldActionContext(component)\n const context = form ? fieldContext : pageContext\n const persistKey = component.persistCollapsed\n const hydrated = useHydrated()\n // Read only after hydration, so the server render and hydration use the schema's default.\n const stored = hydrated && persistKey ? readPersisted(persistKey) : null\n const open = choice ?? (stored !== null ? stored !== 'collapsed' : !component.collapsed)\n const hasHeader =\n component.heading ||\n component.description ||\n component.icon ||\n component.headerActions?.length ||\n component.afterHeader?.length\n\n const setOpen = (next: boolean) => {\n setChoice(next)\n\n if (persistKey) writePersisted(persistKey, next ? 'expanded' : 'collapsed')\n }\n\n const content = (\n <DeferredSchema component={component}>\n {(loaded) => (\n <SchemaRenderer\n components={loaded.schema ?? []}\n columns={loaded.columns}\n className={schemaGapClass(loaded)}\n />\n )}\n </DeferredSchema>\n )\n\n const header = hasHeader ? (\n <div\n className={cn(\n 'flex flex-wrap items-start gap-3',\n component.aside ? 'lg:col-span-1' : 'border-b px-6 py-4',\n component.compact && !component.aside && 'px-4 py-3',\n )}\n >\n {component.icon && (\n <Icon name={component.icon} className=\"text-muted-foreground mt-0.5 size-5\" />\n )}\n <div className=\"min-w-0 flex-1 basis-48\">\n {component.heading &&\n createElement(\n headingTag(component.headingLevel),\n { className: 'text-base leading-6 font-semibold break-words' },\n component.heading,\n )}\n {component.description && (\n <p className=\"text-muted-foreground mt-1 text-sm break-words\">{component.description}</p>\n )}\n </div>\n {component.headerActions && component.headerActions.length > 0 && (\n <ActionList actions={component.headerActions} context={context} size=\"sm\" />\n )}\n <MixedContent items={component.afterHeader} name=\"section-after-header\" />\n {component.collapsible && (\n <CollapsibleTrigger asChild>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-label={t('toggle_section', {}, 'Toggle section')}\n >\n <Icon\n name=\"alfakit::schemas.section.collapse-button\"\n fallback={ChevronDownIcon}\n className={cn('transition-transform', open && 'rotate-180')}\n />\n </Button>\n </CollapsibleTrigger>\n )}\n </div>\n ) : null\n\n const hasFooterActions = Boolean(component.footerActions?.length)\n const footer =\n hasFooterActions || component.footer?.length ? (\n <div\n data-slot=\"section-footer\"\n className={cn(\n 'flex flex-wrap items-center gap-3 border-t px-6 py-4',\n component.compact && 'px-4 py-3',\n )}\n >\n {hasFooterActions && (\n <ActionList\n actions={component.footerActions ?? []}\n context={context}\n className={actionsAlignmentClass(component.footerActionsAlignment) || undefined}\n />\n )}\n <MixedContent items={component.footer} name=\"section-footer-content\" />\n </div>\n ) : null\n\n if (component.aside) {\n return (\n <Collapsible open={!component.collapsible || open} onOpenChange={setOpen} asChild>\n <section\n data-slot=\"section\"\n {...extraProps(component.extraAttributes, 'grid gap-6 lg:grid-cols-3')}\n >\n {header}\n <CollapsibleContent asChild>\n <div\n data-surface=\"section\"\n className={cn(\n 'bg-card rounded-xl border shadow-xs lg:col-span-2',\n component.secondary && 'bg-muted/40',\n )}\n >\n <div className={cn('p-6', component.compact && 'p-4')}>{content}</div>\n {footer}\n </div>\n </CollapsibleContent>\n </section>\n </Collapsible>\n )\n }\n\n return (\n <Collapsible open={!component.collapsible || open} onOpenChange={setOpen} asChild>\n <section\n data-slot=\"section\"\n data-surface=\"section\"\n {...extraProps(\n component.extraAttributes,\n cn('bg-card rounded-xl border shadow-xs', component.secondary && 'bg-muted/40'),\n )}\n >\n {header}\n <CollapsibleContent>\n <div className={cn('p-6', component.compact && 'p-4')}>{content}</div>\n {footer}\n </CollapsibleContent>\n </section>\n </Collapsible>\n )\n}\n"],"mappings":"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"}
@@ -1,7 +1,6 @@
1
+ import { Brand } from "./brand.js";
1
2
  //#region src/components/panel/app-sidebar.d.ts
2
- export declare function Brand({ className }: {
3
- className?: string;
4
- }): import("react").JSX.Element;
5
3
  export declare function AppSidebar(): import("react").JSX.Element;
6
4
  //#endregion
5
+ export { Brand };
7
6
  //# sourceMappingURL=app-sidebar.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"app-sidebar.d.ts","names":[],"sources":["../../../src/components/panel/app-sidebar.tsx"],"mappings":";wBAiDgB,QAAQ;EAAe;oBAAoB,IAAA;wBAmT3C,8BAAU,IAAA"}
1
+ {"version":3,"file":"app-sidebar.d.ts","names":[],"sources":["../../../src/components/panel/app-sidebar.tsx"],"mappings":";;wBAgUgB,8BAAU,IAAA"}
@@ -11,6 +11,7 @@ import { NavLabel } from "./nav-label.js";
11
11
  import { NewTabHint } from "../../lib/new-tab-hint.js";
12
12
  import { NotificationsMenu } from "../notifications/notifications-menu.js";
13
13
  import { Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarRail } from "../ui/sidebar.js";
14
+ import { Brand } from "./brand.js";
14
15
  import { GlobalSearch } from "./global-search.js";
15
16
  import { TenantMenu } from "./tenant-menu.js";
16
17
  import { UserMenu } from "./user-menu.js";
@@ -19,30 +20,6 @@ import { Link } from "@inertiajs/react";
19
20
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
20
21
  import { ChevronRightIcon } from "lucide-react";
21
22
  //#region src/components/panel/app-sidebar.tsx
22
- function Brand({ className }) {
23
- const panel = usePanel();
24
- return /* @__PURE__ */ jsx(Link, {
25
- href: panel.url ?? "/",
26
- className: cn("flex items-center gap-2 overflow-hidden", className),
27
- children: panel.brandLogo ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("img", {
28
- src: panel.brandLogo,
29
- alt: panel.brandName,
30
- style: { height: panel.brandLogoHeight ?? "1.75rem" },
31
- className: cn("max-w-full object-contain", panel.darkModeBrandLogo && "dark:hidden")
32
- }), panel.darkModeBrandLogo && /* @__PURE__ */ jsx("img", {
33
- src: panel.darkModeBrandLogo,
34
- alt: panel.brandName,
35
- style: { height: panel.brandLogoHeight ?? "1.75rem" },
36
- className: "hidden max-w-full object-contain dark:block"
37
- })] }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
38
- className: "bg-primary text-primary-foreground flex size-8 shrink-0 items-center justify-center rounded-lg text-sm font-bold",
39
- children: panel.brandName.charAt(0)
40
- }), /* @__PURE__ */ jsx("span", {
41
- className: "truncate text-sm font-semibold group-data-[collapsible=icon]:hidden",
42
- children: panel.brandName
43
- })] })
44
- });
45
- }
46
23
  function NavBadge({ item }) {
47
24
  const t = useT();
48
25
  if (item.badgePending) return /* @__PURE__ */ jsx("span", {
@@ -1 +1 @@
1
- {"version":3,"file":"app-sidebar.js","names":[],"sources":["../../../src/components/panel/app-sidebar.tsx"],"sourcesContent":["import {\n PREFETCH_CACHE_FOR,\n flattenNavigationItems,\n hasActiveNavigationItem,\n navigationItemText,\n type NavigationGroupSchema,\n type NavigationItemSchema,\n} from '@alfakit/core'\nimport { Link } from '@inertiajs/react'\nimport { ChevronRightIcon } from 'lucide-react'\nimport type { ComponentProps, ReactNode } from 'react'\nimport { useDirection, usePanel, useT } from '../../context'\nimport { extraProps } from '../../lib/attributes'\nimport { badgeColorClasses, colorClass } from '../../lib/colors'\nimport { Icon } from '../../lib/icons'\nimport { NewTabHint } from '../../lib/new-tab-hint'\nimport { cn } from '../../lib/utils'\nimport { NotificationsMenu } from '../notifications/notifications-menu'\nimport { Badge } from '../ui/badge'\nimport { Collapsible, CollapsibleContent, CollapsibleTrigger } from '../ui/collapsible'\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuTrigger,\n} from '../ui/dropdown-menu'\nimport {\n Sidebar,\n SidebarContent,\n SidebarFooter,\n SidebarGroup,\n SidebarGroupContent,\n SidebarGroupLabel,\n SidebarHeader,\n SidebarMenu,\n SidebarMenuButton,\n SidebarMenuItem,\n SidebarMenuSub,\n SidebarMenuSubButton,\n SidebarMenuSubItem,\n SidebarRail,\n} from '../ui/sidebar'\nimport { GlobalSearch } from './global-search'\nimport { NavLabel } from './nav-label'\nimport { Slot } from './slot'\nimport { TenantMenu } from './tenant-menu'\nimport { UserMenu } from './user-menu'\n\nexport function Brand({ className }: { className?: string }) {\n const panel = usePanel()\n\n return (\n <Link\n href={panel.url ?? '/'}\n className={cn('flex items-center gap-2 overflow-hidden', className)}\n >\n {panel.brandLogo ? (\n <>\n <img\n src={panel.brandLogo}\n alt={panel.brandName}\n style={{ height: panel.brandLogoHeight ?? '1.75rem' }}\n className={cn('max-w-full object-contain', panel.darkModeBrandLogo && 'dark:hidden')}\n />\n {panel.darkModeBrandLogo && (\n <img\n src={panel.darkModeBrandLogo}\n alt={panel.brandName}\n style={{ height: panel.brandLogoHeight ?? '1.75rem' }}\n className=\"hidden max-w-full object-contain dark:block\"\n />\n )}\n </>\n ) : (\n <>\n <span className=\"bg-primary text-primary-foreground flex size-8 shrink-0 items-center justify-center rounded-lg text-sm font-bold\">\n {panel.brandName.charAt(0)}\n </span>\n <span className=\"truncate text-sm font-semibold group-data-[collapsible=icon]:hidden\">\n {panel.brandName}\n </span>\n </>\n )}\n </Link>\n )\n}\n\nfunction NavBadge({ item }: { item: NavigationItemSchema }) {\n const t = useT()\n\n // `deferNavigationBadges()`: a placeholder until the deferred badges arrive.\n if (item.badgePending) {\n return (\n <span\n data-slot=\"badge\"\n aria-busy=\"true\"\n aria-label={t('loading', {}, 'Loading')}\n className=\"bg-muted-foreground/20 ms-auto inline-block h-4 w-5 animate-pulse rounded-md\"\n />\n )\n }\n\n if (item.badge === undefined || item.badge === null) return null\n\n return (\n <Badge\n variant=\"outline\"\n className={cn('ms-auto px-1.5 py-0', colorClass(badgeColorClasses, item.badgeColor, 'gray'))}\n title={item.badgeTooltip}\n >\n {item.badge}\n </Badge>\n )\n}\n\n/**\n * A navigation link: an Inertia link, or a plain anchor for `openUrlInNewTab()`. Used as an\n * `asChild` target, so it must pass on the classes, data attributes and handlers it receives.\n */\nfunction NavLink({\n item,\n children,\n ...props\n}: { item: NavigationItemSchema; children: ReactNode } & Omit<\n ComponentProps<'a'>,\n 'href' | 'children'\n>) {\n // `NavigationItem::extraAttributes()`; `class` is merged with the link's own.\n const attributes = {\n ...props,\n ...extraProps(item.extraAttributes, props.className),\n } as ComponentProps<'a'>\n\n return item.openInNewTab ? (\n <a {...attributes} href={item.url} target=\"_blank\" rel=\"noopener noreferrer\">\n {children}\n <NewTabHint />\n </a>\n ) : (\n // Slot passes DOM props; Inertia's Link redefines a few event names, so pass them through untyped.\n <Link\n {...(attributes as Record<string, unknown>)}\n href={item.url ?? '#'}\n prefetch\n cacheFor={PREFETCH_CACHE_FOR}\n >\n {children}\n </Link>\n )\n}\n\n/** Child items (any depth) with their own badges, new-tab links and nested children. */\nfunction NavSubItem({ item }: { item: NavigationItemSchema }) {\n if (item.children && item.children.length > 0) {\n return (\n <SidebarMenuSubItem>\n <Collapsible defaultOpen={item.active} className=\"group/nav-sub\">\n <CollapsibleTrigger asChild>\n <SidebarMenuSubButton asChild isActive={item.active}>\n <button type=\"button\" {...extraProps(item.extraAttributes, 'w-full')}>\n {item.icon && <Icon name={item.icon} />}\n <NavLabel item={item} />\n <NavBadge item={item} />\n <ChevronRightIcon className=\"ms-auto transition-transform duration-200 group-data-[state=open]/nav-sub:rotate-90 rtl:rotate-180 rtl:group-data-[state=open]/nav-sub:rotate-90\" />\n </button>\n </SidebarMenuSubButton>\n </CollapsibleTrigger>\n <CollapsibleContent>\n <SidebarMenuSub>\n {item.children.map((child) => (\n <NavSubItem key={child.label} item={child} />\n ))}\n </SidebarMenuSub>\n </CollapsibleContent>\n </Collapsible>\n </SidebarMenuSubItem>\n )\n }\n\n return (\n <SidebarMenuSubItem>\n <SidebarMenuSubButton asChild isActive={item.active}>\n <NavLink item={item}>\n {item.icon && <Icon name={item.icon} />}\n <NavLabel item={item} />\n <NavBadge item={item} />\n </NavLink>\n </SidebarMenuSubButton>\n </SidebarMenuSubItem>\n )\n}\n\nfunction NavItem({ item }: { item: NavigationItemSchema }) {\n if (item.children && item.children.length > 0) {\n return (\n <Collapsible asChild defaultOpen={item.active} className=\"group/collapsible\">\n <SidebarMenuItem>\n <CollapsibleTrigger asChild>\n <SidebarMenuButton\n tooltip={navigationItemText(item)}\n isActive={item.active}\n {...extraProps(item.extraAttributes)}\n >\n {item.icon && <Icon name={item.icon} />}\n <NavLabel item={item} />\n <NavBadge item={item} />\n <ChevronRightIcon className=\"ms-auto transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90 rtl:rotate-180 rtl:group-data-[state=open]/collapsible:rotate-90\" />\n </SidebarMenuButton>\n </CollapsibleTrigger>\n <CollapsibleContent>\n <SidebarMenuSub>\n {item.children.map((child) => (\n <NavSubItem key={child.label} item={child} />\n ))}\n </SidebarMenuSub>\n </CollapsibleContent>\n </SidebarMenuItem>\n </Collapsible>\n )\n }\n\n return (\n <SidebarMenuItem>\n <SidebarMenuButton asChild isActive={item.active} tooltip={navigationItemText(item)}>\n <NavLink item={item}>\n {item.icon && <Icon name={item.icon} />}\n <NavLabel item={item} />\n <NavBadge item={item} />\n </NavLink>\n </SidebarMenuButton>\n </SidebarMenuItem>\n )\n}\n\n/** A group's items in its flyout menu, children indented under their parent. */\nfunction FlyoutItems({ items }: { items: NavigationItemSchema[] }) {\n return flattenNavigationItems(items).map(({ item, depth }, index) => (\n <DropdownMenuItem\n key={`${depth}-${item.label}-${index}`}\n asChild\n data-active={item.active ? 'true' : undefined}\n >\n <NavLink\n item={item}\n aria-current={item.active ? 'page' : undefined}\n className={cn(\n 'data-[active=true]:bg-accent data-[active=true]:font-medium',\n depth === 1 && 'ps-6',\n depth > 1 && 'ps-9',\n )}\n >\n {item.icon && <Icon name={item.icon} />}\n <NavLabel item={item} className=\"truncate\" />\n <NavBadge item={item} />\n </NavLink>\n </DropdownMenuItem>\n ))\n}\n\n/**\n * In the icon-only (collapsed) sidebar, a group with an icon is one button that opens its\n * items in a flyout menu, like Filament. Hidden while the sidebar is expanded.\n */\nfunction NavGroupFlyout({ group }: { group: NavigationGroupSchema }) {\n const direction = useDirection()\n const active = hasActiveNavigationItem(group.items)\n\n return (\n <SidebarMenu className=\"hidden group-data-[collapsible=icon]:flex\" data-nav-flyout=\"\">\n <SidebarMenuItem>\n <DropdownMenu dir={direction}>\n <DropdownMenuTrigger asChild>\n <SidebarMenuButton isActive={active}>\n <Icon name={group.icon!} />\n <span>{group.label}</span>\n </SidebarMenuButton>\n </DropdownMenuTrigger>\n <DropdownMenuContent\n side={direction === 'rtl' ? 'left' : 'right'}\n align=\"start\"\n className=\"min-w-56\"\n >\n <DropdownMenuLabel>{group.label}</DropdownMenuLabel>\n <FlyoutItems items={group.items} />\n </DropdownMenuContent>\n </DropdownMenu>\n </SidebarMenuItem>\n </SidebarMenu>\n )\n}\n\nfunction NavGroup({ group }: { group: NavigationGroupSchema }) {\n // `NavigationGroup::extraSidebarAttributes()`; `class` is merged with the group's own.\n const attributes = extraProps(group.extraSidebarAttributes)\n // A labelled group with an icon collapses into a flyout in the icon-only sidebar.\n const flyout = Boolean(group.label && group.icon)\n const content = (\n <SidebarGroupContent className={cn(flyout && 'group-data-[collapsible=icon]:hidden')}>\n <SidebarMenu>\n {group.items.map((item) => (\n <NavItem key={item.label} item={item} />\n ))}\n </SidebarMenu>\n </SidebarGroupContent>\n )\n const flyoutMenu = flyout ? <NavGroupFlyout group={group} /> : null\n\n if (!group.label) {\n return <SidebarGroup {...attributes}>{content}</SidebarGroup>\n }\n\n if (!group.collapsible) {\n return (\n <SidebarGroup {...attributes}>\n <SidebarGroupLabel>\n {group.icon && <Icon name={group.icon} className=\"me-1.5\" />}\n {group.label}\n </SidebarGroupLabel>\n {content}\n {flyoutMenu}\n </SidebarGroup>\n )\n }\n\n return (\n <Collapsible\n defaultOpen={!group.collapsed || group.items.some((item) => item.active)}\n className=\"group/nav-group\"\n >\n <SidebarGroup {...attributes}>\n <CollapsibleTrigger asChild>\n <SidebarGroupLabel\n asChild\n className=\"hover:bg-sidebar-accent w-full cursor-pointer justify-between\"\n >\n <button type=\"button\">\n <span className=\"flex items-center gap-1.5\">\n {group.icon && <Icon name={group.icon} />}\n {group.label}\n </span>\n <Icon\n name=\"alfakit::panels.sidebar.group.collapse-button\"\n fallback={ChevronRightIcon}\n className=\"size-3.5 transition-transform group-data-[state=open]/nav-group:rotate-90 rtl:rotate-180 rtl:group-data-[state=open]/nav-group:rotate-90\"\n />\n </button>\n </SidebarGroupLabel>\n </CollapsibleTrigger>\n <CollapsibleContent>{content}</CollapsibleContent>\n {flyoutMenu}\n </SidebarGroup>\n </Collapsible>\n )\n}\n\nexport function AppSidebar() {\n const panel = usePanel()\n const direction = useDirection()\n const t = useT()\n\n return (\n <Sidebar\n side={direction === 'rtl' ? 'right' : 'left'}\n collapsible={\n panel.theme?.design?.layout === 'rail'\n ? 'icon'\n : panel.sidebarFullyCollapsibleOnDesktop\n ? 'offcanvas'\n : panel.sidebarCollapsibleOnDesktop\n ? 'icon'\n : 'none'\n }\n variant={panel.theme?.sidebar === 'flush' ? 'sidebar' : (panel.theme?.sidebar ?? 'inset')}\n >\n <SidebarHeader>\n <Slot name=\"sidebar.start\" />\n <Slot name=\"sidebar.logo.before\" />\n <SidebarMenu>\n <SidebarMenuItem>\n {panel.tenancy?.current ? (\n <>\n <Slot name=\"tenant-menu.before\" />\n <TenantMenu />\n <Slot name=\"tenant-menu.after\" />\n </>\n ) : (\n <SidebarMenuButton size=\"lg\" asChild>\n <div>\n <Brand />\n </div>\n </SidebarMenuButton>\n )}\n </SidebarMenuItem>\n </SidebarMenu>\n <Slot name=\"sidebar.logo.after\" />\n {/* `databaseNotifications(position: 'sidebar')` or `topbar(false)`. */}\n {panel.databaseNotifications?.position === 'sidebar' && (\n <SidebarMenu>\n <SidebarMenuItem>\n <NotificationsMenu variant=\"sidebar\" />\n </SidebarMenuItem>\n </SidebarMenu>\n )}\n {/* `globalSearch(position: GlobalSearchPosition::Sidebar)` or `topbar(false)`. */}\n {panel.globalSearch?.position === 'sidebar' && (\n <SidebarMenu>\n <SidebarMenuItem>\n <GlobalSearch variant=\"sidebar\" />\n </SidebarMenuItem>\n </SidebarMenu>\n )}\n <Slot name=\"sidebar.header\" />\n </SidebarHeader>\n <SidebarContent>\n <Slot name=\"sidebar.nav.start\" />\n <nav aria-label={t('sidebar', {}, 'Sidebar')} className=\"contents\">\n {panel.navigation.map((group, index) => (\n <NavGroup key={group.label ?? `group-${index}`} group={group} />\n ))}\n </nav>\n <Slot name=\"sidebar.nav.end\" />\n </SidebarContent>\n <SidebarFooter>\n <Slot name=\"sidebar.footer\" />\n {/* `userMenu(position: UserMenuPosition::Topbar)` shows it in the top bar instead. */}\n {panel.userMenu?.position !== 'topbar' && (\n <SidebarMenu>\n <SidebarMenuItem>\n <UserMenu />\n </SidebarMenuItem>\n </SidebarMenu>\n )}\n <Slot name=\"sidebar.end\" />\n </SidebarFooter>\n <SidebarRail />\n </Sidebar>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"app-sidebar.js","names":[],"sources":["../../../src/components/panel/app-sidebar.tsx"],"sourcesContent":["import {\n PREFETCH_CACHE_FOR,\n flattenNavigationItems,\n hasActiveNavigationItem,\n navigationItemText,\n type NavigationGroupSchema,\n type NavigationItemSchema,\n} from '@alfakit/core'\nimport { Link } from '@inertiajs/react'\nimport { ChevronRightIcon } from 'lucide-react'\nimport type { ComponentProps, ReactNode } from 'react'\nimport { useDirection, usePanel, useT } from '../../context'\nimport { extraProps } from '../../lib/attributes'\nimport { badgeColorClasses, colorClass } from '../../lib/colors'\nimport { Icon } from '../../lib/icons'\nimport { NewTabHint } from '../../lib/new-tab-hint'\nimport { cn } from '../../lib/utils'\nimport { NotificationsMenu } from '../notifications/notifications-menu'\nimport { Badge } from '../ui/badge'\nimport { Collapsible, CollapsibleContent, CollapsibleTrigger } from '../ui/collapsible'\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuTrigger,\n} from '../ui/dropdown-menu'\nimport {\n Sidebar,\n SidebarContent,\n SidebarFooter,\n SidebarGroup,\n SidebarGroupContent,\n SidebarGroupLabel,\n SidebarHeader,\n SidebarMenu,\n SidebarMenuButton,\n SidebarMenuItem,\n SidebarMenuSub,\n SidebarMenuSubButton,\n SidebarMenuSubItem,\n SidebarRail,\n} from '../ui/sidebar'\nimport { Brand } from './brand'\nimport { GlobalSearch } from './global-search'\nimport { NavLabel } from './nav-label'\nimport { Slot } from './slot'\nimport { TenantMenu } from './tenant-menu'\nimport { UserMenu } from './user-menu'\n\nexport { Brand } from './brand'\n\nfunction NavBadge({ item }: { item: NavigationItemSchema }) {\n const t = useT()\n\n // `deferNavigationBadges()`: a placeholder until the deferred badges arrive.\n if (item.badgePending) {\n return (\n <span\n data-slot=\"badge\"\n aria-busy=\"true\"\n aria-label={t('loading', {}, 'Loading')}\n className=\"bg-muted-foreground/20 ms-auto inline-block h-4 w-5 animate-pulse rounded-md\"\n />\n )\n }\n\n if (item.badge === undefined || item.badge === null) return null\n\n return (\n <Badge\n variant=\"outline\"\n className={cn('ms-auto px-1.5 py-0', colorClass(badgeColorClasses, item.badgeColor, 'gray'))}\n title={item.badgeTooltip}\n >\n {item.badge}\n </Badge>\n )\n}\n\n/**\n * A navigation link: an Inertia link, or a plain anchor for `openUrlInNewTab()`. Used as an\n * `asChild` target, so it must pass on the classes, data attributes and handlers it receives.\n */\nfunction NavLink({\n item,\n children,\n ...props\n}: { item: NavigationItemSchema; children: ReactNode } & Omit<\n ComponentProps<'a'>,\n 'href' | 'children'\n>) {\n // `NavigationItem::extraAttributes()`; `class` is merged with the link's own.\n const attributes = {\n ...props,\n ...extraProps(item.extraAttributes, props.className),\n } as ComponentProps<'a'>\n\n return item.openInNewTab ? (\n <a {...attributes} href={item.url} target=\"_blank\" rel=\"noopener noreferrer\">\n {children}\n <NewTabHint />\n </a>\n ) : (\n // Slot passes DOM props; Inertia's Link redefines a few event names, so pass them through untyped.\n <Link\n {...(attributes as Record<string, unknown>)}\n href={item.url ?? '#'}\n prefetch\n cacheFor={PREFETCH_CACHE_FOR}\n >\n {children}\n </Link>\n )\n}\n\n/** Child items (any depth) with their own badges, new-tab links and nested children. */\nfunction NavSubItem({ item }: { item: NavigationItemSchema }) {\n if (item.children && item.children.length > 0) {\n return (\n <SidebarMenuSubItem>\n <Collapsible defaultOpen={item.active} className=\"group/nav-sub\">\n <CollapsibleTrigger asChild>\n <SidebarMenuSubButton asChild isActive={item.active}>\n <button type=\"button\" {...extraProps(item.extraAttributes, 'w-full')}>\n {item.icon && <Icon name={item.icon} />}\n <NavLabel item={item} />\n <NavBadge item={item} />\n <ChevronRightIcon className=\"ms-auto transition-transform duration-200 group-data-[state=open]/nav-sub:rotate-90 rtl:rotate-180 rtl:group-data-[state=open]/nav-sub:rotate-90\" />\n </button>\n </SidebarMenuSubButton>\n </CollapsibleTrigger>\n <CollapsibleContent>\n <SidebarMenuSub>\n {item.children.map((child) => (\n <NavSubItem key={child.label} item={child} />\n ))}\n </SidebarMenuSub>\n </CollapsibleContent>\n </Collapsible>\n </SidebarMenuSubItem>\n )\n }\n\n return (\n <SidebarMenuSubItem>\n <SidebarMenuSubButton asChild isActive={item.active}>\n <NavLink item={item}>\n {item.icon && <Icon name={item.icon} />}\n <NavLabel item={item} />\n <NavBadge item={item} />\n </NavLink>\n </SidebarMenuSubButton>\n </SidebarMenuSubItem>\n )\n}\n\nfunction NavItem({ item }: { item: NavigationItemSchema }) {\n if (item.children && item.children.length > 0) {\n return (\n <Collapsible asChild defaultOpen={item.active} className=\"group/collapsible\">\n <SidebarMenuItem>\n <CollapsibleTrigger asChild>\n <SidebarMenuButton\n tooltip={navigationItemText(item)}\n isActive={item.active}\n {...extraProps(item.extraAttributes)}\n >\n {item.icon && <Icon name={item.icon} />}\n <NavLabel item={item} />\n <NavBadge item={item} />\n <ChevronRightIcon className=\"ms-auto transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90 rtl:rotate-180 rtl:group-data-[state=open]/collapsible:rotate-90\" />\n </SidebarMenuButton>\n </CollapsibleTrigger>\n <CollapsibleContent>\n <SidebarMenuSub>\n {item.children.map((child) => (\n <NavSubItem key={child.label} item={child} />\n ))}\n </SidebarMenuSub>\n </CollapsibleContent>\n </SidebarMenuItem>\n </Collapsible>\n )\n }\n\n return (\n <SidebarMenuItem>\n <SidebarMenuButton asChild isActive={item.active} tooltip={navigationItemText(item)}>\n <NavLink item={item}>\n {item.icon && <Icon name={item.icon} />}\n <NavLabel item={item} />\n <NavBadge item={item} />\n </NavLink>\n </SidebarMenuButton>\n </SidebarMenuItem>\n )\n}\n\n/** A group's items in its flyout menu, children indented under their parent. */\nfunction FlyoutItems({ items }: { items: NavigationItemSchema[] }) {\n return flattenNavigationItems(items).map(({ item, depth }, index) => (\n <DropdownMenuItem\n key={`${depth}-${item.label}-${index}`}\n asChild\n data-active={item.active ? 'true' : undefined}\n >\n <NavLink\n item={item}\n aria-current={item.active ? 'page' : undefined}\n className={cn(\n 'data-[active=true]:bg-accent data-[active=true]:font-medium',\n depth === 1 && 'ps-6',\n depth > 1 && 'ps-9',\n )}\n >\n {item.icon && <Icon name={item.icon} />}\n <NavLabel item={item} className=\"truncate\" />\n <NavBadge item={item} />\n </NavLink>\n </DropdownMenuItem>\n ))\n}\n\n/**\n * In the icon-only (collapsed) sidebar, a group with an icon is one button that opens its\n * items in a flyout menu, like Filament. Hidden while the sidebar is expanded.\n */\nfunction NavGroupFlyout({ group }: { group: NavigationGroupSchema }) {\n const direction = useDirection()\n const active = hasActiveNavigationItem(group.items)\n\n return (\n <SidebarMenu className=\"hidden group-data-[collapsible=icon]:flex\" data-nav-flyout=\"\">\n <SidebarMenuItem>\n <DropdownMenu dir={direction}>\n <DropdownMenuTrigger asChild>\n <SidebarMenuButton isActive={active}>\n <Icon name={group.icon!} />\n <span>{group.label}</span>\n </SidebarMenuButton>\n </DropdownMenuTrigger>\n <DropdownMenuContent\n side={direction === 'rtl' ? 'left' : 'right'}\n align=\"start\"\n className=\"min-w-56\"\n >\n <DropdownMenuLabel>{group.label}</DropdownMenuLabel>\n <FlyoutItems items={group.items} />\n </DropdownMenuContent>\n </DropdownMenu>\n </SidebarMenuItem>\n </SidebarMenu>\n )\n}\n\nfunction NavGroup({ group }: { group: NavigationGroupSchema }) {\n // `NavigationGroup::extraSidebarAttributes()`; `class` is merged with the group's own.\n const attributes = extraProps(group.extraSidebarAttributes)\n // A labelled group with an icon collapses into a flyout in the icon-only sidebar.\n const flyout = Boolean(group.label && group.icon)\n const content = (\n <SidebarGroupContent className={cn(flyout && 'group-data-[collapsible=icon]:hidden')}>\n <SidebarMenu>\n {group.items.map((item) => (\n <NavItem key={item.label} item={item} />\n ))}\n </SidebarMenu>\n </SidebarGroupContent>\n )\n const flyoutMenu = flyout ? <NavGroupFlyout group={group} /> : null\n\n if (!group.label) {\n return <SidebarGroup {...attributes}>{content}</SidebarGroup>\n }\n\n if (!group.collapsible) {\n return (\n <SidebarGroup {...attributes}>\n <SidebarGroupLabel>\n {group.icon && <Icon name={group.icon} className=\"me-1.5\" />}\n {group.label}\n </SidebarGroupLabel>\n {content}\n {flyoutMenu}\n </SidebarGroup>\n )\n }\n\n return (\n <Collapsible\n defaultOpen={!group.collapsed || group.items.some((item) => item.active)}\n className=\"group/nav-group\"\n >\n <SidebarGroup {...attributes}>\n <CollapsibleTrigger asChild>\n <SidebarGroupLabel\n asChild\n className=\"hover:bg-sidebar-accent w-full cursor-pointer justify-between\"\n >\n <button type=\"button\">\n <span className=\"flex items-center gap-1.5\">\n {group.icon && <Icon name={group.icon} />}\n {group.label}\n </span>\n <Icon\n name=\"alfakit::panels.sidebar.group.collapse-button\"\n fallback={ChevronRightIcon}\n className=\"size-3.5 transition-transform group-data-[state=open]/nav-group:rotate-90 rtl:rotate-180 rtl:group-data-[state=open]/nav-group:rotate-90\"\n />\n </button>\n </SidebarGroupLabel>\n </CollapsibleTrigger>\n <CollapsibleContent>{content}</CollapsibleContent>\n {flyoutMenu}\n </SidebarGroup>\n </Collapsible>\n )\n}\n\nexport function AppSidebar() {\n const panel = usePanel()\n const direction = useDirection()\n const t = useT()\n\n return (\n <Sidebar\n side={direction === 'rtl' ? 'right' : 'left'}\n collapsible={\n panel.theme?.design?.layout === 'rail'\n ? 'icon'\n : panel.sidebarFullyCollapsibleOnDesktop\n ? 'offcanvas'\n : panel.sidebarCollapsibleOnDesktop\n ? 'icon'\n : 'none'\n }\n variant={panel.theme?.sidebar === 'flush' ? 'sidebar' : (panel.theme?.sidebar ?? 'inset')}\n >\n <SidebarHeader>\n <Slot name=\"sidebar.start\" />\n <Slot name=\"sidebar.logo.before\" />\n <SidebarMenu>\n <SidebarMenuItem>\n {panel.tenancy?.current ? (\n <>\n <Slot name=\"tenant-menu.before\" />\n <TenantMenu />\n <Slot name=\"tenant-menu.after\" />\n </>\n ) : (\n <SidebarMenuButton size=\"lg\" asChild>\n <div>\n <Brand />\n </div>\n </SidebarMenuButton>\n )}\n </SidebarMenuItem>\n </SidebarMenu>\n <Slot name=\"sidebar.logo.after\" />\n {/* `databaseNotifications(position: 'sidebar')` or `topbar(false)`. */}\n {panel.databaseNotifications?.position === 'sidebar' && (\n <SidebarMenu>\n <SidebarMenuItem>\n <NotificationsMenu variant=\"sidebar\" />\n </SidebarMenuItem>\n </SidebarMenu>\n )}\n {/* `globalSearch(position: GlobalSearchPosition::Sidebar)` or `topbar(false)`. */}\n {panel.globalSearch?.position === 'sidebar' && (\n <SidebarMenu>\n <SidebarMenuItem>\n <GlobalSearch variant=\"sidebar\" />\n </SidebarMenuItem>\n </SidebarMenu>\n )}\n <Slot name=\"sidebar.header\" />\n </SidebarHeader>\n <SidebarContent>\n <Slot name=\"sidebar.nav.start\" />\n <nav aria-label={t('sidebar', {}, 'Sidebar')} className=\"contents\">\n {panel.navigation.map((group, index) => (\n <NavGroup key={group.label ?? `group-${index}`} group={group} />\n ))}\n </nav>\n <Slot name=\"sidebar.nav.end\" />\n </SidebarContent>\n <SidebarFooter>\n <Slot name=\"sidebar.footer\" />\n {/* `userMenu(position: UserMenuPosition::Topbar)` shows it in the top bar instead. */}\n {panel.userMenu?.position !== 'topbar' && (\n <SidebarMenu>\n <SidebarMenuItem>\n <UserMenu />\n </SidebarMenuItem>\n </SidebarMenu>\n )}\n <Slot name=\"sidebar.end\" />\n </SidebarFooter>\n <SidebarRail />\n </Sidebar>\n )\n}\n"],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ //#region src/components/panel/brand.d.ts
2
+ /**
3
+ * The panel's logo (or initial) and name, linking to the panel home. Its own module, so the
4
+ * auth layout doesn't import the sidebar.
5
+ */
6
+ export declare function Brand({ className }: {
7
+ className?: string;
8
+ }): import("react").JSX.Element;
9
+ //#endregion
10
+ //# sourceMappingURL=brand.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"brand.d.ts","names":[],"sources":["../../../src/components/panel/brand.tsx"],"mappings":";;;;;wBAQgB,QAAQ;EAAe;oBAAoB,IAAA"}
@@ -0,0 +1,37 @@
1
+ import { usePanel } from "../../context.js";
2
+ import { cn } from "../../lib/utils.js";
3
+ import { Link } from "@inertiajs/react";
4
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
+ //#region src/components/panel/brand.tsx
6
+ /**
7
+ * The panel's logo (or initial) and name, linking to the panel home. Its own module, so the
8
+ * auth layout doesn't import the sidebar.
9
+ */
10
+ function Brand({ className }) {
11
+ const panel = usePanel();
12
+ return /* @__PURE__ */ jsx(Link, {
13
+ href: panel.url ?? "/",
14
+ className: cn("flex items-center gap-2 overflow-hidden", className),
15
+ children: panel.brandLogo ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("img", {
16
+ src: panel.brandLogo,
17
+ alt: panel.brandName,
18
+ style: { height: panel.brandLogoHeight ?? "1.75rem" },
19
+ className: cn("max-w-full object-contain", panel.darkModeBrandLogo && "dark:hidden")
20
+ }), panel.darkModeBrandLogo && /* @__PURE__ */ jsx("img", {
21
+ src: panel.darkModeBrandLogo,
22
+ alt: panel.brandName,
23
+ style: { height: panel.brandLogoHeight ?? "1.75rem" },
24
+ className: "hidden max-w-full object-contain dark:block"
25
+ })] }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
26
+ className: "bg-primary text-primary-foreground flex size-8 shrink-0 items-center justify-center rounded-lg text-sm font-bold",
27
+ children: panel.brandName.charAt(0)
28
+ }), /* @__PURE__ */ jsx("span", {
29
+ className: "truncate text-sm font-semibold group-data-[collapsible=icon]:hidden",
30
+ children: panel.brandName
31
+ })] })
32
+ });
33
+ }
34
+ //#endregion
35
+ export { Brand };
36
+
37
+ //# sourceMappingURL=brand.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"brand.js","names":[],"sources":["../../../src/components/panel/brand.tsx"],"sourcesContent":["import { Link } from '@inertiajs/react'\nimport { usePanel } from '../../context'\nimport { cn } from '../../lib/utils'\n\n/**\n * The panel's logo (or initial) and name, linking to the panel home. Its own module, so the\n * auth layout doesn't import the sidebar.\n */\nexport function Brand({ className }: { className?: string }) {\n const panel = usePanel()\n\n return (\n <Link\n href={panel.url ?? '/'}\n className={cn('flex items-center gap-2 overflow-hidden', className)}\n >\n {panel.brandLogo ? (\n <>\n <img\n src={panel.brandLogo}\n alt={panel.brandName}\n style={{ height: panel.brandLogoHeight ?? '1.75rem' }}\n className={cn('max-w-full object-contain', panel.darkModeBrandLogo && 'dark:hidden')}\n />\n {panel.darkModeBrandLogo && (\n <img\n src={panel.darkModeBrandLogo}\n alt={panel.brandName}\n style={{ height: panel.brandLogoHeight ?? '1.75rem' }}\n className=\"hidden max-w-full object-contain dark:block\"\n />\n )}\n </>\n ) : (\n <>\n <span className=\"bg-primary text-primary-foreground flex size-8 shrink-0 items-center justify-center rounded-lg text-sm font-bold\">\n {panel.brandName.charAt(0)}\n </span>\n <span className=\"truncate text-sm font-semibold group-data-[collapsible=icon]:hidden\">\n {panel.brandName}\n </span>\n </>\n )}\n </Link>\n )\n}\n"],"mappings":";;;;;;;;;AAQA,SAAgB,MAAM,EAAE,aAAqC;CAC3D,MAAM,QAAQ,SAAS;CAEvB,OACE,oBAAC,MAAD;EACE,MAAM,MAAM,OAAO;EACnB,WAAW,GAAG,2CAA2C,SAAS;EAEjE,UAAA,MAAM,YACL,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,OAAD;GACE,KAAK,MAAM;GACX,KAAK,MAAM;GACX,OAAO,EAAE,QAAQ,MAAM,mBAAmB,UAAU;GACpD,WAAW,GAAG,6BAA6B,MAAM,qBAAqB,aAAa;EACpF,CAAA,GACA,MAAM,qBACL,oBAAC,OAAD;GACE,KAAK,MAAM;GACX,KAAK,MAAM;GACX,OAAO,EAAE,QAAQ,MAAM,mBAAmB,UAAU;GACpD,WAAU;EACX,CAAA,CAEH,EAAA,CAAA,IAEF,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,QAAD;GAAM,WAAU;GACb,UAAA,MAAM,UAAU,OAAO,CAAC;EACrB,CAAA,GACN,oBAAC,QAAD;GAAM,WAAU;GACb,UAAA,MAAM;EACH,CAAA,CACN,EAAA,CAAA;CAEA,CAAA;AAEV"}
@@ -1,4 +1,5 @@
1
- import { AppSidebar, Brand } from "./app-sidebar.js";
1
+ import { Brand } from "./brand.js";
2
+ import { AppSidebar } from "./app-sidebar.js";
2
3
  import { BottomNav } from "./bottom-nav.js";
3
4
  import { DebugPanelSlot } from "./debug-panel-slot.js";
4
5
  import { DebugPanel, DebugTreeNode } from "./debug-panel.js";
@@ -1,12 +1,12 @@
1
1
  import { usePanel, useT } from "../../context.js";
2
2
  import { Slot } from "./slot.js";
3
+ import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator } from "../ui/breadcrumb.js";
3
4
  import { NotificationsMenu } from "../notifications/notifications-menu.js";
4
5
  import { Separator } from "../ui/separator.js";
5
6
  import { SidebarTrigger } from "../ui/sidebar.js";
6
7
  import { GlobalSearch } from "./global-search.js";
7
8
  import { TopbarLocaleSwitcher } from "./locale-switcher.js";
8
9
  import { UserMenu } from "./user-menu.js";
9
- import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator } from "../ui/breadcrumb.js";
10
10
  import { DebugPanelSlot } from "./debug-panel-slot.js";
11
11
  import { ThemeToggle } from "./theme-toggle.js";
12
12
  import { Link } from "@inertiajs/react";
@@ -1 +1 @@
1
- {"version":3,"file":"live-records-pill.d.ts","names":[],"sources":["../../../src/components/realtime/live-records-pill.tsx"],"mappings":";;;;;;;wBAYgB,eACd,MAAM,+BACN,gBACA;EAAW;EAAmB,UAAU;IAAgB,MAAM;;IAC7D;;wBAwBa,kBAAkB;EAAU,MAAM;oBAAa,IAAA"}
1
+ {"version":3,"file":"live-records-pill.d.ts","names":[],"sources":["../../../src/components/realtime/live-records-pill.tsx"],"mappings":";;;;;;;wBAYgB,eACd,MAAM,+BACN,gBACA;EAAW;EAAmB,UAAU;IAAgB,MAAM;;IAC7D;;wBAyBa,kBAAkB;EAAU,MAAM;oBAAa,IAAA"}
@@ -1,4 +1,4 @@
1
- import { useChoice, usePollComponent } from "../../context.js";
1
+ import { useChoice, usePollComponent, useRefreshComponents } from "../../context.js";
2
2
  import { Button } from "../ui/button.js";
3
3
  import { useStore } from "../../hooks/use-store.js";
4
4
  import { LiveUpdates, shownRecordKeys } from "@alfakit/core";
@@ -13,6 +13,7 @@ import { ArrowUpIcon } from "lucide-react";
13
13
  */
14
14
  function useLiveUpdates(live, target, options = {}) {
15
15
  const poll = usePollComponent();
16
+ const refresh = useRefreshComponents();
16
17
  const key = live ? JSON.stringify(live) : "";
17
18
  const polling = options.polling;
18
19
  const records = options.records;
@@ -20,12 +21,14 @@ function useLiveUpdates(live, target, options = {}) {
20
21
  live,
21
22
  target,
22
23
  polling,
23
- poll
24
+ poll,
25
+ refresh
24
26
  }) : null, [
25
27
  key,
26
28
  target,
27
29
  polling,
28
- poll
30
+ poll,
31
+ refresh
29
32
  ]);
30
33
  useEffect(() => {
31
34
  controller?.setShownKeys(records === void 0 ? null : shownRecordKeys(records));
@@ -1 +1 @@
1
- {"version":3,"file":"live-records-pill.js","names":[],"sources":["../../../src/components/realtime/live-records-pill.tsx"],"sourcesContent":["import { LiveUpdates, shownRecordKeys, type LiveUpdatesSchema, type RecordKey } from '@alfakit/core'\nimport { ArrowUpIcon } from 'lucide-react'\nimport { useEffect, useMemo } from 'react'\nimport { useChoice, usePollComponent } from '../../context'\nimport { useStore } from '../../hooks/use-store'\nimport { Button } from '../ui/button'\n\n/**\n * Follow `live()` updates of a table or widget: refresh it in place when its records\n * change, polling instead without Echo. Returns the controller (its store counts created\n * records for `<LiveRecordsPill>`), or null without `live()`.\n */\nexport function useLiveUpdates(\n live: LiveUpdatesSchema | undefined,\n target: string,\n options: { polling?: boolean; records?: ReadonlyArray<{ key?: RecordKey }> | null } = {},\n): LiveUpdates | null {\n const poll = usePollComponent()\n const key = live ? JSON.stringify(live) : ''\n const polling = options.polling\n const records = options.records\n\n const controller = useMemo(\n () => (live ? new LiveUpdates({ live, target, polling, poll }) : null),\n // `live` is compared by value (`key`): a reload brings a new object with the same settings.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [key, target, polling, poll],\n )\n\n // Updates of records on other pages don't refresh the table.\n useEffect(() => {\n controller?.setShownKeys(records === undefined ? null : shownRecordKeys(records))\n }, [controller, records])\n\n useEffect(() => controller?.start(), [controller])\n\n return controller\n}\n\n/** \"3 new records — show\": created records the table doesn't show yet. */\nexport function LiveRecordsPill({ live }: { live: LiveUpdates }) {\n const choice = useChoice()\n const { pending } = useStore(live.store)\n\n return (\n <div data-slot=\"live-records\" aria-live=\"polite\" className=\"flex justify-center\">\n {pending > 0 && (\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"secondary\"\n className=\"rounded-full shadow-sm\"\n onClick={() => void live.showPending()}\n >\n <ArrowUpIcon aria-hidden=\"true\" />\n {choice(\n 'realtime.new_records',\n pending,\n {},\n '{1} :count new record — show|[2,*] :count new records — show',\n )}\n </Button>\n )}\n </div>\n )\n}\n"],"mappings":";;;;;;;;;;;;;AAYA,SAAgB,eACd,MACA,QACA,UAAsF,CAAC,GACnE;CACpB,MAAM,OAAO,iBAAiB;CAC9B,MAAM,MAAM,OAAO,KAAK,UAAU,IAAI,IAAI;CAC1C,MAAM,UAAU,QAAQ;CACxB,MAAM,UAAU,QAAQ;CAExB,MAAM,aAAa,cACV,OAAO,IAAI,YAAY;EAAE;EAAM;EAAQ;EAAS;CAAK,CAAC,IAAI,MAGjE;EAAC;EAAK;EAAQ;EAAS;CAAI,CAC7B;CAGA,gBAAgB;EACd,YAAY,aAAa,YAAY,KAAA,IAAY,OAAO,gBAAgB,OAAO,CAAC;CAClF,GAAG,CAAC,YAAY,OAAO,CAAC;CAExB,gBAAgB,YAAY,MAAM,GAAG,CAAC,UAAU,CAAC;CAEjD,OAAO;AACT;;AAGA,SAAgB,gBAAgB,EAAE,QAA+B;CAC/D,MAAM,SAAS,UAAU;CACzB,MAAM,EAAE,YAAY,SAAS,KAAK,KAAK;CAEvC,OACE,oBAAC,OAAD;EAAK,aAAU;EAAe,aAAU;EAAS,WAAU;EACxD,UAAA,UAAU,KACT,qBAAC,QAAD;GACE,MAAK;GACL,MAAK;GACL,SAAQ;GACR,WAAU;GACV,eAAe,KAAK,KAAK,YAAY;GALvC,UAAA,CAOE,oBAAC,aAAD,EAAa,eAAY,OAAQ,CAAA,GAChC,OACC,wBACA,SACA,CAAC,GACD,8DACF,CACM;;CAEP,CAAA;AAET"}
1
+ {"version":3,"file":"live-records-pill.js","names":[],"sources":["../../../src/components/realtime/live-records-pill.tsx"],"sourcesContent":["import { LiveUpdates, shownRecordKeys, type LiveUpdatesSchema, type RecordKey } from '@alfakit/core'\nimport { ArrowUpIcon } from 'lucide-react'\nimport { useEffect, useMemo } from 'react'\nimport { useChoice, usePollComponent, useRefreshComponents } from '../../context'\nimport { useStore } from '../../hooks/use-store'\nimport { Button } from '../ui/button'\n\n/**\n * Follow `live()` updates of a table or widget: refresh it in place when its records\n * change, polling instead without Echo. Returns the controller (its store counts created\n * records for `<LiveRecordsPill>`), or null without `live()`.\n */\nexport function useLiveUpdates(\n live: LiveUpdatesSchema | undefined,\n target: string,\n options: { polling?: boolean; records?: ReadonlyArray<{ key?: RecordKey }> | null } = {},\n): LiveUpdates | null {\n const poll = usePollComponent()\n const refresh = useRefreshComponents()\n const key = live ? JSON.stringify(live) : ''\n const polling = options.polling\n const records = options.records\n\n const controller = useMemo(\n () => (live ? new LiveUpdates({ live, target, polling, poll, refresh }) : null),\n // `live` is compared by value (`key`): a reload brings a new object with the same settings.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [key, target, polling, poll, refresh],\n )\n\n // Updates of records on other pages don't refresh the table.\n useEffect(() => {\n controller?.setShownKeys(records === undefined ? null : shownRecordKeys(records))\n }, [controller, records])\n\n useEffect(() => controller?.start(), [controller])\n\n return controller\n}\n\n/** \"3 new records — show\": created records the table doesn't show yet. */\nexport function LiveRecordsPill({ live }: { live: LiveUpdates }) {\n const choice = useChoice()\n const { pending } = useStore(live.store)\n\n return (\n <div data-slot=\"live-records\" aria-live=\"polite\" className=\"flex justify-center\">\n {pending > 0 && (\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"secondary\"\n className=\"rounded-full shadow-sm\"\n onClick={() => void live.showPending()}\n >\n <ArrowUpIcon aria-hidden=\"true\" />\n {choice(\n 'realtime.new_records',\n pending,\n {},\n '{1} :count new record — show|[2,*] :count new records — show',\n )}\n </Button>\n )}\n </div>\n )\n}\n"],"mappings":";;;;;;;;;;;;;AAYA,SAAgB,eACd,MACA,QACA,UAAsF,CAAC,GACnE;CACpB,MAAM,OAAO,iBAAiB;CAC9B,MAAM,UAAU,qBAAqB;CACrC,MAAM,MAAM,OAAO,KAAK,UAAU,IAAI,IAAI;CAC1C,MAAM,UAAU,QAAQ;CACxB,MAAM,UAAU,QAAQ;CAExB,MAAM,aAAa,cACV,OAAO,IAAI,YAAY;EAAE;EAAM;EAAQ;EAAS;EAAM;CAAQ,CAAC,IAAI,MAG1E;EAAC;EAAK;EAAQ;EAAS;EAAM;CAAO,CACtC;CAGA,gBAAgB;EACd,YAAY,aAAa,YAAY,KAAA,IAAY,OAAO,gBAAgB,OAAO,CAAC;CAClF,GAAG,CAAC,YAAY,OAAO,CAAC;CAExB,gBAAgB,YAAY,MAAM,GAAG,CAAC,UAAU,CAAC;CAEjD,OAAO;AACT;;AAGA,SAAgB,gBAAgB,EAAE,QAA+B;CAC/D,MAAM,SAAS,UAAU;CACzB,MAAM,EAAE,YAAY,SAAS,KAAK,KAAK;CAEvC,OACE,oBAAC,OAAD;EAAK,aAAU;EAAe,aAAU;EAAS,WAAU;EACxD,UAAA,UAAU,KACT,qBAAC,QAAD;GACE,MAAK;GACL,MAAK;GACL,SAAQ;GACR,WAAU;GACV,eAAe,KAAK,KAAK,YAAY;GALvC,UAAA,CAOE,oBAAC,aAAD,EAAa,eAAY,OAAQ,CAAA,GAChC,OACC,wBACA,SACA,CAAC,GACD,8DACF,CACM;;CAEP,CAAA;AAET"}
@@ -6,6 +6,12 @@ export interface CellProps {
6
6
  recordKey: RecordKey;
7
7
  token: string;
8
8
  component: string;
9
+ /**
10
+ * Set when this renderer was picked from the registry (`column:<type>`): it then renders
11
+ * the built-in cell instead of looking itself up again, so an ejected `TableCellContent`
12
+ * registered for a column type doesn't render itself forever.
13
+ */
14
+ fromRegistry?: boolean;
9
15
  }
10
16
  export declare function TableCellContent(props: CellProps): import("react").JSX.Element;
11
17
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"cells.d.ts","names":[],"sources":["../../../src/components/table/cells.tsx"],"mappings":";;iBAwDiB;EACf,QAAQ;EACR,MAAM;EACN,WAAW;EACX;EACA;;wBAGc,iBAAiB,OAAO,4BAAS,IAAA"}
1
+ {"version":3,"file":"cells.d.ts","names":[],"sources":["../../../src/components/table/cells.tsx"],"mappings":";;iBAwDiB;EACf,QAAQ;EACR,MAAM;EACN,WAAW;EACX;EACA;;;;;;EAMA;;wBAGc,iBAAiB,OAAO,4BAAS,IAAA"}