@alfadocs/ui-kit-debug 0.82.0 → 0.84.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. package/dist/_chunks/{actions-cell-renderer-DLrcSTK_.js → actions-cell-renderer-DaL80uqL.js} +2 -2
  2. package/dist/_chunks/{actions-cell-renderer-DLrcSTK_.js.map → actions-cell-renderer-DaL80uqL.js.map} +1 -1
  3. package/dist/_chunks/chart-GFLv4cXm.js +609 -0
  4. package/dist/_chunks/chart-GFLv4cXm.js.map +1 -0
  5. package/dist/_chunks/dashboard-grid-D2dm0IRN.js +691 -0
  6. package/dist/_chunks/dashboard-grid-D2dm0IRN.js.map +1 -0
  7. package/dist/_chunks/{editable-currency-cell-renderer-GwfA9tTR.js → editable-currency-cell-renderer-Dus_sBvX.js} +2 -2
  8. package/dist/_chunks/{editable-currency-cell-renderer-GwfA9tTR.js.map → editable-currency-cell-renderer-Dus_sBvX.js.map} +1 -1
  9. package/dist/_chunks/{face-scheme-C0rk21gg.js → face-scheme-CjQAHvSP.js} +2 -2
  10. package/dist/_chunks/{face-scheme-C0rk21gg.js.map → face-scheme-CjQAHvSP.js.map} +1 -1
  11. package/dist/_chunks/{file-manager-DfTG7bxx.js → file-manager-DLJlinIO.js} +3 -3
  12. package/dist/_chunks/{file-manager-DfTG7bxx.js.map → file-manager-DLJlinIO.js.map} +1 -1
  13. package/dist/_chunks/{header-settings-DMfdx0Vq.js → header-settings-CLwFqMHI.js} +2 -2
  14. package/dist/_chunks/{header-settings-DMfdx0Vq.js.map → header-settings-CLwFqMHI.js.map} +1 -1
  15. package/dist/_chunks/{icon-button-group-C_lqXTAj.js → icon-button-group-BLHPN6jg.js} +178 -163
  16. package/dist/_chunks/icon-button-group-BLHPN6jg.js.map +1 -0
  17. package/dist/_chunks/{marketplace-app-shell-Bxq1PYAj.js → marketplace-app-shell-Br2yebEK.js} +2 -2
  18. package/dist/_chunks/{marketplace-app-shell-Bxq1PYAj.js.map → marketplace-app-shell-Br2yebEK.js.map} +1 -1
  19. package/dist/_chunks/{patient-table-DweKjiXg.js → patient-table-BHzmUbzu.js} +2 -2
  20. package/dist/_chunks/{patient-table-DweKjiXg.js.map → patient-table-BHzmUbzu.js.map} +1 -1
  21. package/dist/_chunks/{theme-toggle-BJCz_UOi.js → theme-toggle-B4mOrQX1.js} +2 -2
  22. package/dist/_chunks/{theme-toggle-BJCz_UOi.js.map → theme-toggle-B4mOrQX1.js.map} +1 -1
  23. package/dist/_chunks/widget-picker-DEmTVuFL.js +193 -0
  24. package/dist/_chunks/widget-picker-DEmTVuFL.js.map +1 -0
  25. package/dist/agent-catalog.json +238 -4
  26. package/dist/agent-i18n/en.json +27 -1
  27. package/dist/components/chart/chart.agent.d.ts.map +1 -1
  28. package/dist/components/chart/chart.d.ts +36 -1
  29. package/dist/components/chart/chart.d.ts.map +1 -1
  30. package/dist/components/chart/index.js +1 -1
  31. package/dist/components/dashboard-grid/dashboard-grid-engine.d.ts +37 -0
  32. package/dist/components/dashboard-grid/dashboard-grid-engine.d.ts.map +1 -0
  33. package/dist/components/dashboard-grid/dashboard-grid.agent.d.ts +4 -0
  34. package/dist/components/dashboard-grid/dashboard-grid.agent.d.ts.map +1 -0
  35. package/dist/components/dashboard-grid/dashboard-grid.d.ts +74 -0
  36. package/dist/components/dashboard-grid/dashboard-grid.d.ts.map +1 -0
  37. package/dist/components/dashboard-grid/index.d.ts +3 -0
  38. package/dist/components/dashboard-grid/index.d.ts.map +1 -0
  39. package/dist/components/dashboard-grid/index.js +6 -0
  40. package/dist/components/dashboard-grid/index.js.map +1 -0
  41. package/dist/components/data-table/index.js +2 -2
  42. package/dist/components/face-scheme/index.js +1 -1
  43. package/dist/components/file-manager/index.js +1 -1
  44. package/dist/components/header-settings/index.js +1 -1
  45. package/dist/components/icon-button-group/icon-button-group.d.ts.map +1 -1
  46. package/dist/components/icon-button-group/index.js +1 -1
  47. package/dist/components/index.d.ts +2 -0
  48. package/dist/components/index.d.ts.map +1 -1
  49. package/dist/components/patient-table/index.js +1 -1
  50. package/dist/components/theme-toggle/index.js +1 -1
  51. package/dist/components/widget-picker/index.d.ts +3 -0
  52. package/dist/components/widget-picker/index.d.ts.map +1 -0
  53. package/dist/components/widget-picker/index.js +6 -0
  54. package/dist/components/widget-picker/index.js.map +1 -0
  55. package/dist/components/widget-picker/widget-picker.agent.d.ts +4 -0
  56. package/dist/components/widget-picker/widget-picker.agent.d.ts.map +1 -0
  57. package/dist/components/widget-picker/widget-picker.d.ts +49 -0
  58. package/dist/components/widget-picker/widget-picker.d.ts.map +1 -0
  59. package/dist/i18n/locales/ar.d.ts +29 -0
  60. package/dist/i18n/locales/ar.d.ts.map +1 -1
  61. package/dist/i18n/locales/ar.js +29 -0
  62. package/dist/i18n/locales/ar.js.map +1 -1
  63. package/dist/i18n/locales/de.d.ts +29 -0
  64. package/dist/i18n/locales/de.d.ts.map +1 -1
  65. package/dist/i18n/locales/de.js +29 -0
  66. package/dist/i18n/locales/de.js.map +1 -1
  67. package/dist/i18n/locales/el.d.ts +29 -0
  68. package/dist/i18n/locales/el.d.ts.map +1 -1
  69. package/dist/i18n/locales/el.js +29 -0
  70. package/dist/i18n/locales/el.js.map +1 -1
  71. package/dist/i18n/locales/en.d.ts +29 -0
  72. package/dist/i18n/locales/en.d.ts.map +1 -1
  73. package/dist/i18n/locales/en.js +29 -0
  74. package/dist/i18n/locales/en.js.map +1 -1
  75. package/dist/i18n/locales/es.d.ts +29 -0
  76. package/dist/i18n/locales/es.d.ts.map +1 -1
  77. package/dist/i18n/locales/es.js +29 -0
  78. package/dist/i18n/locales/es.js.map +1 -1
  79. package/dist/i18n/locales/fr.d.ts +29 -0
  80. package/dist/i18n/locales/fr.d.ts.map +1 -1
  81. package/dist/i18n/locales/fr.js +29 -0
  82. package/dist/i18n/locales/fr.js.map +1 -1
  83. package/dist/i18n/locales/hi.d.ts +29 -0
  84. package/dist/i18n/locales/hi.d.ts.map +1 -1
  85. package/dist/i18n/locales/hi.js +29 -0
  86. package/dist/i18n/locales/hi.js.map +1 -1
  87. package/dist/i18n/locales/it.d.ts +29 -0
  88. package/dist/i18n/locales/it.d.ts.map +1 -1
  89. package/dist/i18n/locales/it.js +29 -0
  90. package/dist/i18n/locales/it.js.map +1 -1
  91. package/dist/i18n/locales/ja.d.ts +29 -0
  92. package/dist/i18n/locales/ja.d.ts.map +1 -1
  93. package/dist/i18n/locales/ja.js +29 -0
  94. package/dist/i18n/locales/ja.js.map +1 -1
  95. package/dist/i18n/locales/nl.d.ts +29 -0
  96. package/dist/i18n/locales/nl.d.ts.map +1 -1
  97. package/dist/i18n/locales/nl.js +29 -0
  98. package/dist/i18n/locales/nl.js.map +1 -1
  99. package/dist/i18n/locales/pl.d.ts +29 -0
  100. package/dist/i18n/locales/pl.d.ts.map +1 -1
  101. package/dist/i18n/locales/pl.js +29 -0
  102. package/dist/i18n/locales/pl.js.map +1 -1
  103. package/dist/i18n/locales/pt.d.ts +29 -0
  104. package/dist/i18n/locales/pt.d.ts.map +1 -1
  105. package/dist/i18n/locales/pt.js +29 -0
  106. package/dist/i18n/locales/pt.js.map +1 -1
  107. package/dist/i18n/locales/ro.d.ts +29 -0
  108. package/dist/i18n/locales/ro.d.ts.map +1 -1
  109. package/dist/i18n/locales/ro.js +29 -0
  110. package/dist/i18n/locales/ro.js.map +1 -1
  111. package/dist/i18n/locales/ru.d.ts +29 -0
  112. package/dist/i18n/locales/ru.d.ts.map +1 -1
  113. package/dist/i18n/locales/ru.js +29 -0
  114. package/dist/i18n/locales/ru.js.map +1 -1
  115. package/dist/i18n/locales/sq.d.ts +29 -0
  116. package/dist/i18n/locales/sq.d.ts.map +1 -1
  117. package/dist/i18n/locales/sq.js +29 -0
  118. package/dist/i18n/locales/sq.js.map +1 -1
  119. package/dist/i18n/locales/sv.d.ts +29 -0
  120. package/dist/i18n/locales/sv.d.ts.map +1 -1
  121. package/dist/i18n/locales/sv.js +29 -0
  122. package/dist/i18n/locales/sv.js.map +1 -1
  123. package/dist/i18n/locales/tr.d.ts +29 -0
  124. package/dist/i18n/locales/tr.d.ts.map +1 -1
  125. package/dist/i18n/locales/tr.js +29 -0
  126. package/dist/i18n/locales/tr.js.map +1 -1
  127. package/dist/i18n/locales/zh.d.ts +29 -0
  128. package/dist/i18n/locales/zh.d.ts.map +1 -1
  129. package/dist/i18n/locales/zh.js +29 -0
  130. package/dist/i18n/locales/zh.js.map +1 -1
  131. package/dist/index.js +82 -76
  132. package/dist/index.js.map +1 -1
  133. package/dist/locales/ar.json +29 -0
  134. package/dist/locales/de.json +29 -0
  135. package/dist/locales/el.json +29 -0
  136. package/dist/locales/en.json +29 -0
  137. package/dist/locales/es.json +29 -0
  138. package/dist/locales/fr.json +29 -0
  139. package/dist/locales/hi.json +29 -0
  140. package/dist/locales/it.json +29 -0
  141. package/dist/locales/ja.json +29 -0
  142. package/dist/locales/nl.json +29 -0
  143. package/dist/locales/pl.json +29 -0
  144. package/dist/locales/pt.json +29 -0
  145. package/dist/locales/ro.json +29 -0
  146. package/dist/locales/ru.json +29 -0
  147. package/dist/locales/sq.json +29 -0
  148. package/dist/locales/sv.json +29 -0
  149. package/dist/locales/tr.json +29 -0
  150. package/dist/locales/zh.json +29 -0
  151. package/dist/patterns/marketplace-app-shell/index.js +1 -1
  152. package/dist/tokens.css +1 -1
  153. package/package.json +9 -1
  154. package/dist/_chunks/chart-CpkpA74k.js +0 -374
  155. package/dist/_chunks/chart-CpkpA74k.js.map +0 -1
  156. package/dist/_chunks/icon-button-group-C_lqXTAj.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard-grid-D2dm0IRN.js","sources":["../../node_modules/lucide-react/dist/esm/icons/move-diagonal-2.mjs","../../src/components/dashboard-grid/dashboard-grid.agent.ts","../../src/components/dashboard-grid/dashboard-grid-engine.ts","../../src/components/dashboard-grid/dashboard-grid.tsx"],"sourcesContent":["/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M19 13v6h-6\", key: \"1hxl6d\" }],\n [\"path\", { d: \"M5 11V5h6\", key: \"12e2xe\" }],\n [\"path\", { d: \"m5 5 14 14\", key: \"11anup\" }]\n];\nconst MoveDiagonal2 = createLucideIcon(\"move-diagonal-2\", __iconNode);\n\nexport { __iconNode, MoveDiagonal2 as default };\n//# sourceMappingURL=move-diagonal-2.mjs.map\n","import type { AgentAdapter } from '../../agent/types';\nimport type { DashboardGridHandle } from './dashboard-grid';\n\nexport const dashboardGridAgent: AgentAdapter<DashboardGridHandle> = {\n id: 'dashboard-grid',\n // The board's whole purpose is in-place rearrangement of its widgets.\n capabilities: ['edit_inline'],\n state: {\n layout: {\n type: '{ id: string, x: number, y: number, w: number, h: number }[]',\n descriptionKey: 'ui.agent.dashboardGrid.state.layout',\n description:\n 'Current widget geometry in cell units — ids and rectangles only, no widget content.',\n read: (handle) => handle.getGridState().layout,\n },\n cols: {\n type: 'number',\n descriptionKey: 'ui.agent.dashboardGrid.state.cols',\n description: 'Logical column count of the board.',\n read: (handle) => handle.getGridState().cols,\n },\n editing: {\n type: 'boolean',\n descriptionKey: 'ui.agent.dashboardGrid.state.editing',\n description:\n 'Whether edit mode is on. Move/resize actions are refused while it is off — the host app owns the toggle.',\n read: (handle) => handle.getGridState().editing,\n },\n },\n actions: {\n move_widget: {\n // Rearranging the board mutates user configuration — a write,\n // reversible by moving back.\n safety: 'write',\n argsType: 'id, x, y',\n argsSchema: {\n type: 'object',\n properties: {\n id: { type: 'string', description: 'Widget id (see layout state).' },\n x: {\n type: 'integer',\n minimum: 0,\n description: '0-based logical column.',\n },\n y: { type: 'integer', minimum: 0, description: '0-based row.' },\n },\n required: ['id', 'x', 'y'],\n },\n returns: 'boolean (accepted)',\n returnsSchema: {\n type: 'boolean',\n description:\n 'True when applied; false when edit mode is off or the id is unknown.',\n },\n idempotent: true,\n descriptionKey: 'ui.agent.dashboardGrid.actions.moveWidget',\n description:\n 'Move a widget to a cell. Out-of-bounds targets are clamped; colliding widgets are pushed down and the layout re-compacts. Refused while edit mode is off.',\n invoke: (handle, args: { id: string; x: number; y: number }) =>\n handle.moveWidgetTo(args.id, args.x, args.y),\n },\n resize_widget: {\n safety: 'write',\n argsType: 'id, w, h',\n argsSchema: {\n type: 'object',\n properties: {\n id: { type: 'string', description: 'Widget id (see layout state).' },\n w: {\n type: 'integer',\n minimum: 1,\n description: 'Column span (≥ 1).',\n },\n h: { type: 'integer', minimum: 1, description: 'Row span (≥ 1).' },\n },\n required: ['id', 'w', 'h'],\n },\n returns: 'boolean (accepted)',\n returnsSchema: {\n type: 'boolean',\n description:\n 'True when applied; false when edit mode is off or the id is unknown.',\n },\n idempotent: true,\n descriptionKey: 'ui.agent.dashboardGrid.actions.resizeWidget',\n description:\n 'Resize a widget to a span. Clamped to the grid and the widget’s min/max; colliding widgets are pushed down. Refused while edit mode is off.',\n invoke: (handle, args: { id: string; w: number; h: number }) =>\n handle.resizeWidgetTo(args.id, args.w, args.h),\n },\n },\n domHooks: {\n root: { attr: 'data-component', value: 'dashboard-grid' },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description: 'Sourced from the id prop.',\n },\n item: {\n attr: 'data-widget-id',\n description: 'Each widget wrapper carries its layout id.',\n },\n },\n};\n","/* ------------------------------------------------------------------ */\n/* DashboardGrid engine — pure layout math, no DOM. */\n/* */\n/* The grid is a column-count × unbounded-rows plane. Every widget is */\n/* an axis-aligned rectangle in cell units: `x` is the 0-based LOGICAL */\n/* column (inline-start based — CSS Grid flips it visually in RTL), */\n/* `y` the 0-based row, `w`/`h` the spans. All functions are pure and */\n/* return new arrays; the component layer owns state and DOM. */\n/* ------------------------------------------------------------------ */\n\nexport interface DashboardWidgetLayout {\n id: string;\n /** 0-based logical column of the inline-start edge. */\n x: number;\n /** 0-based row of the block-start edge. */\n y: number;\n /** Column span (≥ 1). */\n w: number;\n /** Row span (≥ 1). */\n h: number;\n minW?: number;\n minH?: number;\n maxW?: number;\n maxH?: number;\n}\n\nexport function collides(\n a: DashboardWidgetLayout,\n b: DashboardWidgetLayout,\n): boolean {\n return (\n a.x < b.x + b.w && b.x < a.x + a.w && a.y < b.y + b.h && b.y < a.y + a.h\n );\n}\n\n/** Clamp a rect to the grid bounds and its own min/max constraints. */\nexport function clampRect(\n item: DashboardWidgetLayout,\n cols: number,\n): DashboardWidgetLayout {\n const minW = Math.max(1, item.minW ?? 1);\n const minH = Math.max(1, item.minH ?? 1);\n const maxW = Math.min(cols, item.maxW ?? cols);\n const maxH = item.maxH ?? Number.POSITIVE_INFINITY;\n const w = Math.min(Math.max(item.w, minW), maxW);\n const h = Math.min(Math.max(item.h, minH), maxH);\n const x = Math.min(Math.max(0, item.x), cols - w);\n const y = Math.max(0, item.y);\n return { ...item, x, y, w, h };\n}\n\n/**\n * Resolve overlaps and apply upward gravity. The `activeId` rect (the one\n * being dragged/resized) keeps its exact position; every other widget is\n * pushed down out of collisions, then pulled up as far as gravity allows.\n * Deterministic: non-active widgets settle in reading order (y, then x).\n */\nexport function normalise(\n layout: DashboardWidgetLayout[],\n cols: number,\n activeId?: string,\n): DashboardWidgetLayout[] {\n const items = layout.map((item) => clampRect(item, cols));\n const order = [...items].sort((a, b) => {\n if (a.id === activeId) return -1;\n if (b.id === activeId) return 1;\n return a.y - b.y || a.x - b.x;\n });\n const placed: DashboardWidgetLayout[] = [];\n const active = activeId\n ? items.find((item) => item.id === activeId)\n : undefined;\n for (const item of order) {\n if (item.id !== activeId) {\n // Swap-up: when the ACTIVE rect has moved onto this item, prefer\n // lifting the displaced item ABOVE the active rect (into the space\n // the active vacated) over pushing it down. Without this, moving a\n // widget downward past a same-column neighbour is impossible — the\n // neighbour keeps fleeing ahead and the drop compaction reverts the\n // whole gesture.\n if (active && collides(active, item)) {\n const above = { ...item, y: Math.max(0, active.y - item.h) };\n if (\n !collides(active, above) &&\n !placed.some((p) => p.id !== activeId && collides(p, above))\n ) {\n item.y = above.y;\n }\n }\n while (placed.some((p) => collides(p, item))) {\n item.y += 1;\n }\n while (item.y > 0) {\n const test = { ...item, y: item.y - 1 };\n if (placed.some((p) => collides(p, test))) break;\n item.y -= 1;\n }\n }\n placed.push(item);\n }\n // Preserve the caller's array order (children order), only geometry moved.\n const byId = new Map(placed.map((p) => [p.id, p]));\n return layout.map((item) => byId.get(item.id) as DashboardWidgetLayout);\n}\n\n/** Move a widget to a target cell, resolving collisions around it. */\nexport function moveItem(\n layout: DashboardWidgetLayout[],\n id: string,\n x: number,\n y: number,\n cols: number,\n): DashboardWidgetLayout[] {\n const next = layout.map((item) =>\n item.id === id ? clampRect({ ...item, x, y }, cols) : item,\n );\n return normalise(next, cols, id);\n}\n\n/** Resize a widget to a target span, resolving collisions around it. */\nexport function resizeItem(\n layout: DashboardWidgetLayout[],\n id: string,\n w: number,\n h: number,\n cols: number,\n): DashboardWidgetLayout[] {\n const next = layout.map((item) =>\n item.id === id\n ? // Resizing never moves the widget: the width clamps to the space\n // between its position and the grid edge (clampRect would slide it).\n // minW wins over the edge clamp so clampRect cannot re-raise w and\n // slide x as a side effect.\n clampRect(\n {\n ...item,\n w: Math.max(item.minW ?? 1, Math.min(w, cols - item.x)),\n h,\n },\n cols,\n )\n : item,\n );\n return normalise(next, cols, id);\n}\n\n/** First free slot (reading order) that fits a `w`×`h` rect. */\nexport function firstFit(\n layout: DashboardWidgetLayout[],\n cols: number,\n w: number,\n h: number,\n): { x: number; y: number } {\n const width = Math.min(Math.max(1, w), cols);\n const maxY = layout.reduce((m, item) => Math.max(m, item.y + item.h), 0);\n for (let y = 0; y <= maxY; y += 1) {\n for (let x = 0; x <= cols - width; x += 1) {\n const candidate: DashboardWidgetLayout = {\n id: '__candidate__',\n x,\n y,\n w: width,\n h,\n };\n if (!layout.some((item) => collides(item, candidate))) {\n return { x, y };\n }\n }\n }\n return { x: 0, y: maxY };\n}\n\n/** Total rows the layout occupies (for sizing the add tile / container). */\nexport function rowCount(layout: DashboardWidgetLayout[]): number {\n return layout.reduce((m, item) => Math.max(m, item.y + item.h), 0);\n}\n","/* ------------------------------------------------------------------ */\n/* DashboardGrid — user-configurable widget board. */\n/* */\n/* A CSS-Grid plane (N logical columns × unbounded rows) whose child */\n/* `DashboardGrid.Widget`s can be moved, resized, removed, and added */\n/* while `editing` is on. Layout state is `{id,x,y,w,h}[]` in cell */\n/* units — controlled via `layout`/`onLayoutChange` or uncontrolled */\n/* via `defaultLayout`. The collision/gravity engine lives in */\n/* `dashboard-grid-engine.ts` (pure, unit-tested). */\n/* */\n/* - Coordinates reach CSS through custom properties set with */\n/* `style.setProperty` — the sanctioned escape hatch for runtime */\n/* values (23-constraints §4; same pattern as `progress`). */\n/* - RTL is free: CSS Grid columns are logical, so column 1 sits at */\n/* the inline-start in both directions. Arrow keys are dir-aware. */\n/* - Move/resize are keyboard-first: each handle is a button — Enter/ */\n/* Space grabs, arrows step one cell, Enter drops, Escape cancels — */\n/* with a polite live region announcing every step. */\n/* ------------------------------------------------------------------ */\n\nimport {\n Children,\n Fragment,\n createContext,\n forwardRef,\n isValidElement,\n useCallback,\n useContext,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n type KeyboardEvent as ReactKeyboardEvent,\n type PointerEvent as ReactPointerEvent,\n type ReactElement,\n type ReactNode,\n} from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { GripVertical, MoveDiagonal2, Plus, X } from 'lucide-react';\nimport { IconButton } from '../button/icon-button';\nimport { useIsomorphicLayoutEffect } from '../../hooks/use-isomorphic-layout-effect';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { dashboardGridAgent } from './dashboard-grid.agent';\nimport {\n clampRect,\n firstFit,\n moveItem,\n normalise,\n resizeItem,\n rowCount,\n type DashboardWidgetLayout,\n} from './dashboard-grid-engine';\n\nexport type { DashboardWidgetLayout } from './dashboard-grid-engine';\n\n/* ------------------------------------------------------------------ */\n/* CVA */\n/* ------------------------------------------------------------------ */\n\nconst dashboardGridVariants = cva(\n [\n 'ds:grid ds:w-full',\n 'ds:gap-[var(--spacing-md)]',\n 'ds:[grid-template-columns:repeat(var(--dg-cols),minmax(0,1fr))]',\n 'ds:[grid-auto-rows:var(--dg-row)]',\n // Edit-mode surface: tint the whole plane, draw faint cell lines, and\n // reserve spare rows (--dg-min-block) so the AVAILABLE space reads at\n // a glance instead of the board ending at the last occupied row.\n 'ds:data-[editing=true]:rounded-[var(--radius-lg)] ds:data-[editing=true]:bg-muted/10',\n 'ds:data-[editing=true]:[background-image:var(--dg-grid-lines)]',\n 'ds:data-[editing=true]:min-h-[var(--dg-min-block)]',\n ].join(' '),\n { variants: {}, defaultVariants: {} },\n);\n\nconst widgetVariants = cva(\n [\n 'ds:relative ds:flex ds:min-h-0 ds:min-w-0 ds:flex-col ds:overflow-hidden',\n // Mirror of Card variant=\"elevated\" so widgets read as kit cards.\n 'ds:rounded-[var(--radius-lg)] ds:bg-[var(--card)] ds:text-[var(--card-foreground)]',\n 'ds:border ds:border-[color:var(--card-border)] ds:shadow-[var(--shadow-card)] ds:[.theme-accessible_&]:border-2',\n 'ds:[grid-column-start:var(--dg-x)] ds:[grid-column-end:span_var(--dg-w)]',\n 'ds:[grid-row-start:var(--dg-y)] ds:[grid-row-end:span_var(--dg-h)]',\n // Grabbed feedback (keyboard or pointer drag in flight).\n 'ds:data-[grabbed=true]:ring-[length:var(--focus-ring-width)] ds:data-[grabbed=true]:ring-ring ds:data-[grabbed=true]:z-10',\n ].join(' '),\n { variants: {}, defaultVariants: {} },\n);\n\n/* ------------------------------------------------------------------ */\n/* Public types */\n/* ------------------------------------------------------------------ */\n\nexport interface DashboardGridProps extends VariantProps<\n typeof dashboardGridVariants\n> {\n /** Accessible name for the board region. Required. */\n 'aria-label': string;\n /** Opaque instance id — emitted as `data-component-id` for the agent registry. */\n id?: string;\n /** Logical column count. Defaults to 12. */\n cols?: number;\n /** Row height in px (one `h` unit). Defaults to 96. */\n rowHeight?: number;\n /** Controlled layout. Entries are matched to widgets by `id`. */\n layout?: DashboardWidgetLayout[];\n /** Uncontrolled initial layout. */\n defaultLayout?: DashboardWidgetLayout[];\n /**\n * Fired after every committed change — move, resize, remove pruning, and\n * the auto-placement of widgets that had no layout entry. Persist this.\n */\n onLayoutChange?: (next: DashboardWidgetLayout[]) => void;\n /** Edit mode: shows move/resize/remove chrome and the add tile. */\n editing?: boolean;\n /**\n * Called when the user activates a widget's remove button. The kit\n * commits the entry removal (one `onLayoutChange`) and manages focus;\n * the consumer unmounts the child. Omit to hide the remove button.\n */\n onRemoveWidget?: (id: string) => void;\n /**\n * Called when the user activates the add tile (rendered in edit mode\n * only when this is provided). The consumer appends a new\n * `DashboardGrid.Widget`; it is auto-placed first-fit and reported via\n * `onLayoutChange`.\n */\n onRequestAdd?: () => void;\n /** `DashboardGrid.Widget` children. */\n children: ReactNode;\n className?: string;\n}\n\nexport interface DashboardGridHandle {\n /** Move a widget to a cell. False when not editing or id unknown. */\n moveWidgetTo: (id: string, x: number, y: number) => boolean;\n /** Resize a widget to a span. False when not editing or id unknown. */\n resizeWidgetTo: (id: string, w: number, h: number) => boolean;\n /** Current geometry + mode. */\n getGridState: () => {\n cols: number;\n editing: boolean;\n layout: DashboardWidgetLayout[];\n };\n}\n\nexport interface DashboardGridWidgetProps {\n /** Stable widget id — matches a `layout` entry. */\n id: string;\n /** Visible widget title (consumer-translated). */\n title: string;\n /** Cell span used when the widget has no layout entry yet. */\n defaultW?: number;\n defaultH?: number;\n /** Extra header actions (view mode and edit mode). */\n actionsSlot?: ReactNode;\n children?: ReactNode;\n}\n\n/* ------------------------------------------------------------------ */\n/* Context */\n/* ------------------------------------------------------------------ */\n\ninterface GrabState {\n kind: 'move' | 'resize';\n id: string;\n via: 'pointer' | 'keyboard';\n}\n\ninterface DashboardGridContextValue {\n editing: boolean;\n layoutById: Map<string, DashboardWidgetLayout>;\n grab: GrabState | null;\n canRemove: boolean;\n requestRemove: (id: string) => void;\n startKeyboardGrab: (kind: 'move' | 'resize', id: string) => void;\n keyboardStep: (\n event: ReactKeyboardEvent<HTMLButtonElement>,\n id: string,\n ) => void;\n startPointerGrab: (\n kind: 'move' | 'resize',\n id: string,\n event: ReactPointerEvent<HTMLButtonElement>,\n ) => void;\n}\n\nconst DashboardGridContext = createContext<DashboardGridContextValue | null>(\n null,\n);\n\n/** Walk widget children, descending into fragments (a common JSX shape). */\nfunction forEachWidgetChild(\n children: ReactNode,\n fn: (child: ReactElement<DashboardGridWidgetProps>) => void,\n): void {\n Children.forEach(children, (child) => {\n if (!isValidElement(child)) return;\n if (child.type === Fragment) {\n forEachWidgetChild(\n (child.props as { children?: ReactNode }).children,\n fn,\n );\n return;\n }\n fn(child as ReactElement<DashboardGridWidgetProps>);\n });\n}\n\n/* ------------------------------------------------------------------ */\n/* Widget */\n/* ------------------------------------------------------------------ */\n\nfunction DashboardGridWidget({\n id,\n title,\n actionsSlot,\n children,\n}: DashboardGridWidgetProps) {\n const { t } = useTranslation();\n const ctx = useContext(DashboardGridContext);\n const wrapperRef = useRef<HTMLDivElement>(null);\n\n if (import.meta.env.DEV && !ctx) {\n console.warn(\n 'DashboardGrid.Widget: must be rendered inside a <DashboardGrid>.',\n );\n }\n\n const entry = ctx?.layoutById.get(id);\n\n // Sanctioned escape hatch for runtime-computed values (23-constraints §4):\n // cell coordinates land on CSS custom properties via style.setProperty.\n useIsomorphicLayoutEffect(() => {\n const node = wrapperRef.current;\n if (!node || !entry) return;\n node.style.setProperty('--dg-x', String(entry.x + 1));\n node.style.setProperty('--dg-y', String(entry.y + 1));\n node.style.setProperty('--dg-w', String(entry.w));\n node.style.setProperty('--dg-h', String(entry.h));\n }, [entry?.x, entry?.y, entry?.w, entry?.h, entry]);\n\n if (!ctx || !entry) return null;\n\n const grabbed = ctx.grab?.id === id;\n const editing = ctx.editing;\n\n return (\n <div\n ref={wrapperRef}\n role=\"listitem\"\n aria-label={title}\n data-component=\"dashboard-grid-widget\"\n data-widget-id={id}\n data-grabbed={grabbed || undefined}\n className={widgetVariants()}\n >\n <div className=\"ds:flex ds:items-center ds:gap-[var(--spacing-xs)] ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-sm)] ds:pt-[var(--spacing-sm)]\">\n {editing ? (\n <IconButton\n size=\"sm\"\n intent=\"outline\"\n type=\"button\"\n icon={<GripVertical />}\n aria-label={t('dashboardGrid.move', { title })}\n aria-pressed={grabbed && ctx.grab?.kind === 'move'}\n className=\"ds:cursor-grab ds:touch-none ds:bg-[var(--card)]\"\n onPointerDown={(event) => ctx.startPointerGrab('move', id, event)}\n onKeyDown={(event) => ctx.keyboardStep(event, id)}\n onClick={() => ctx.startKeyboardGrab('move', id)}\n />\n ) : null}\n <span className=\"ds:min-w-0 ds:flex-1 ds:truncate ds:text-sm ds:font-medium\">\n {title}\n </span>\n {actionsSlot}\n {editing && ctx.canRemove ? (\n <IconButton\n size=\"sm\"\n intent=\"outline\"\n type=\"button\"\n icon={<X />}\n className=\"ds:bg-[var(--card)]\"\n aria-label={t('dashboardGrid.remove', { title })}\n onClick={() => ctx.requestRemove(id)}\n />\n ) : null}\n </div>\n <div className=\"ds:min-h-0 ds:flex-1 ds:overflow-hidden ds:ps-[var(--spacing-md)] ds:pe-[var(--spacing-md)] ds:pb-[var(--spacing-md)] ds:pt-[var(--spacing-xs)]\">\n {children}\n </div>\n {editing ? (\n <span className=\"ds:absolute ds:bottom-[var(--spacing-sm)] ds:end-[var(--spacing-sm)]\">\n <IconButton\n size=\"sm\"\n intent=\"outline\"\n type=\"button\"\n icon={<MoveDiagonal2 />}\n flipIconInRtl\n aria-label={t('dashboardGrid.resize', { title })}\n aria-pressed={grabbed && ctx.grab?.kind === 'resize'}\n className=\"ds:touch-none ds:bg-[var(--card)]\"\n onPointerDown={(event) => ctx.startPointerGrab('resize', id, event)}\n onKeyDown={(event) => ctx.keyboardStep(event, id)}\n onClick={() => ctx.startKeyboardGrab('resize', id)}\n />\n </span>\n ) : null}\n </div>\n );\n}\nDashboardGridWidget.displayName = 'DashboardGrid.Widget';\n\n/* ------------------------------------------------------------------ */\n/* DashboardGrid */\n/* ------------------------------------------------------------------ */\n\ninterface PointerDragState {\n kind: 'move' | 'resize';\n id: string;\n pointerId: number;\n startClientX: number;\n startClientY: number;\n origin: DashboardWidgetLayout;\n colStride: number;\n rowStride: number;\n isRtl: boolean;\n}\n\nconst DashboardGridRoot = forwardRef<DashboardGridHandle, DashboardGridProps>(\n (\n {\n 'aria-label': ariaLabel,\n id,\n cols = 12,\n rowHeight = 96,\n layout: layoutProp,\n defaultLayout,\n onLayoutChange,\n editing = false,\n onRemoveWidget,\n onRequestAdd,\n children,\n className,\n },\n ref,\n ) => {\n const { t } = useTranslation();\n const gridRef = useRef<HTMLDivElement>(null);\n\n if (import.meta.env.DEV && !ariaLabel) {\n console.warn(\n 'DashboardGrid: `aria-label` is required for accessibility.',\n );\n }\n\n /* ---- child ids in render order --------------------------------- */\n /* Fragments are flattened: `<>{widgets}</>` is a normal consumer */\n /* shape and must contribute its widgets, not an id-less wrapper. */\n const childIds = useMemo(() => {\n const ids: string[] = [];\n forEachWidgetChild(children, (child) => {\n if (child.props.id) ids.push(child.props.id);\n });\n return ids;\n }, [children]);\n const childMeta = useMemo(() => {\n const meta = new Map<string, { defaultW: number; defaultH: number }>();\n forEachWidgetChild(children, (child) => {\n if (child.props.id) {\n meta.set(child.props.id, {\n defaultW: child.props.defaultW ?? 4,\n defaultH: child.props.defaultH ?? 2,\n });\n }\n });\n return meta;\n }, [children]);\n\n /* ---- controlled / uncontrolled layout -------------------------- */\n const [internalLayout, setInternalLayout] = useState<\n DashboardWidgetLayout[]\n >(() => defaultLayout ?? []);\n const committed = layoutProp ?? internalLayout;\n\n const commit = useCallback(\n (next: DashboardWidgetLayout[]) => {\n if (layoutProp === undefined) setInternalLayout(next);\n onLayoutChange?.(next);\n },\n [layoutProp, onLayoutChange],\n );\n\n /* ---- resolve: bounds-clamp + auto-place missing children -------- */\n /* Entries whose widget is absent are KEPT, not pruned: widgets may */\n /* mount late (lazy chunks, permission gates) and pruning would */\n /* destroy their saved geometry — they simply don't render until the */\n /* child appears. Removal goes through the remove flow, which commits */\n /* the entry removal explicitly. */\n const { resolved, autoPlaced } = useMemo(() => {\n const clamped = committed.map((entry) => clampRect(entry, cols));\n const missing = childIds.filter(\n (cid) => !clamped.some((entry) => entry.id === cid),\n );\n if (missing.length === 0) {\n return { resolved: clamped, autoPlaced: false };\n }\n const placed = [...clamped];\n for (const cid of missing) {\n const meta = childMeta.get(cid) ?? { defaultW: 4, defaultH: 2 };\n const w = Math.min(meta.defaultW, cols);\n const spot = firstFit(placed, cols, w, meta.defaultH);\n placed.push({ id: cid, x: spot.x, y: spot.y, w, h: meta.defaultH });\n }\n return { resolved: normalise(placed, cols), autoPlaced: true };\n }, [committed, childIds, childMeta, cols]);\n\n // Report auto-placement exactly once per divergence so the consumer can\n // persist the new entries. Bounds-clamping is render-only and never\n // reported — a controlled layout is not rewritten uninvited.\n const reportedRef = useRef('');\n useEffect(() => {\n if (!autoPlaced) return;\n const signature = resolved\n .map(\n (entry) => `${entry.id}:${entry.x},${entry.y},${entry.w},${entry.h}`,\n )\n .join('|');\n if (reportedRef.current !== signature) {\n reportedRef.current = signature;\n commit(resolved);\n }\n }, [autoPlaced, resolved, commit]);\n\n /* ---- drag / grab state ----------------------------------------- */\n /* Live values mirror into refs so event handlers stay PURE: no state */\n /* updater performs side effects (StrictMode double-invokes them and */\n /* render-phase commits would set consumer state during render), and */\n /* the stable callbacks read current values without dependency churn. */\n const [draft, setDraft] = useState<DashboardWidgetLayout[] | null>(null);\n const [grab, setGrab] = useState<GrabState | null>(null);\n const [announcement, setAnnouncement] = useState('');\n const draftRef = useRef<DashboardWidgetLayout[] | null>(null);\n const grabRef = useRef<\n (GrabState & { baseLayout: DashboardWidgetLayout[] }) | null\n >(null);\n const pointerDragRef = useRef<PointerDragState | null>(null);\n // A pointer interaction always ends with a trailing `click` on the\n // handle — preventDefault on pointerdown does NOT suppress it, and\n // pointer capture retargets it to the handle. This flag turns that\n // click into a no-op instead of a phantom keyboard grab.\n const suppressClickRef = useRef(false);\n const colsRef = useRef(cols);\n colsRef.current = cols;\n const resolvedRef = useRef(resolved);\n resolvedRef.current = resolved;\n\n const applyDraft = useCallback((next: DashboardWidgetLayout[] | null) => {\n draftRef.current = next;\n setDraft(next);\n }, []);\n\n const beginGrab = useCallback(\n (\n kind: 'move' | 'resize',\n widgetId: string,\n via: 'pointer' | 'keyboard',\n ) => {\n const state: GrabState = { kind, id: widgetId, via };\n // The grab-time layout is the collision base for EVERY step of this\n // grab: resolving against the mutating draft makes displaced\n // neighbours flee ahead of repeated steps (down-reorder becomes\n // unreachable); resolving against the frozen base keeps targeting\n // stateless and lets the engine's swap-up work.\n grabRef.current = { ...state, baseLayout: resolvedRef.current };\n setGrab(state);\n applyDraft(resolvedRef.current);\n },\n [applyDraft],\n );\n\n const active = draft ?? resolved;\n const layoutById = useMemo(\n () => new Map(active.map((entry) => [entry.id, entry])),\n [active],\n );\n\n const announceEntry = useCallback(\n (kind: 'move' | 'resize', entry: DashboardWidgetLayout) => {\n setAnnouncement(\n kind === 'move'\n ? t('dashboardGrid.movedTo', { col: entry.x + 1, row: entry.y + 1 })\n : t('dashboardGrid.resizedTo', { cols: entry.w, rows: entry.h }),\n );\n },\n [t],\n );\n\n const endGrab = useCallback(\n (commitDraft: boolean) => {\n const current = draftRef.current;\n const grabbed = grabRef.current;\n grabRef.current = null;\n pointerDragRef.current = null;\n setGrab(null);\n applyDraft(null);\n if (!commitDraft || !current || !grabbed) {\n setAnnouncement(t('dashboardGrid.cancelled'));\n return;\n }\n // Committing compacts the WHOLE board — the dropped widget joins\n // the gravity pass, so a saved dashboard never keeps stray gaps.\n // A release that changed nothing commits nothing: a plain press on\n // a handle must never rewrite the persisted layout.\n const final = normalise(current, colsRef.current);\n const signatureOf = (layout: DashboardWidgetLayout[]): string =>\n layout.map((e) => `${e.id}:${e.x},${e.y},${e.w},${e.h}`).join('|');\n if (signatureOf(final) === signatureOf(resolvedRef.current)) {\n setAnnouncement(t('dashboardGrid.cancelled'));\n return;\n }\n commit(final);\n // Announce where the widget actually SETTLED — compaction can move\n // it past the last previewed cell, and a screen-reader user must\n // not be left with a stale mental model.\n const landed = final.find((entry) => entry.id === grabbed.id);\n setAnnouncement(\n landed\n ? t('dashboardGrid.droppedAt', {\n col: landed.x + 1,\n row: landed.y + 1,\n })\n : t('dashboardGrid.cancelled'),\n );\n },\n [applyDraft, commit, t],\n );\n\n /* ---- keyboard grab --------------------------------------------- */\n const startKeyboardGrab = useCallback(\n (kind: 'move' | 'resize', widgetId: string) => {\n if (!editing) return;\n // The click that terminates a pointer interaction is not a request\n // for a keyboard grab.\n if (suppressClickRef.current) {\n suppressClickRef.current = false;\n return;\n }\n const current = grabRef.current;\n if (current?.via === 'pointer') return;\n if (current && current.id === widgetId && current.kind === kind) {\n // Second Enter/Space (button click) drops.\n endGrab(true);\n return;\n }\n beginGrab(kind, widgetId, 'keyboard');\n setAnnouncement(\n kind === 'move'\n ? t('dashboardGrid.grabbed')\n : t('dashboardGrid.resizeGrabbed'),\n );\n },\n [editing, beginGrab, endGrab, t],\n );\n\n const keyboardStep = useCallback(\n (event: ReactKeyboardEvent<HTMLButtonElement>, widgetId: string) => {\n const grabbed = grabRef.current;\n if (!grabbed || grabbed.id !== widgetId || grabbed.via !== 'keyboard') {\n return;\n }\n if (event.key === 'Escape') {\n event.preventDefault();\n endGrab(false);\n return;\n }\n const arrows = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'];\n if (!arrows.includes(event.key)) return;\n event.preventDefault();\n const isRtl =\n typeof window !== 'undefined' && gridRef.current\n ? window.getComputedStyle(gridRef.current).direction === 'rtl'\n : false;\n // Visual left/right → logical inline delta (flips in RTL).\n const inlineDelta =\n event.key === 'ArrowRight'\n ? isRtl\n ? -1\n : 1\n : event.key === 'ArrowLeft'\n ? isRtl\n ? 1\n : -1\n : 0;\n const blockDelta =\n event.key === 'ArrowDown' ? 1 : event.key === 'ArrowUp' ? -1 : 0;\n // Target accumulates through the draft; collisions resolve against\n // the frozen grab-time base (see beginGrab).\n const currentDraft = draftRef.current ?? grabbed.baseLayout;\n const entry = currentDraft.find((item) => item.id === widgetId);\n if (!entry) return;\n const next =\n grabbed.kind === 'move'\n ? moveItem(\n grabbed.baseLayout,\n widgetId,\n entry.x + inlineDelta,\n entry.y + blockDelta,\n cols,\n )\n : resizeItem(\n grabbed.baseLayout,\n widgetId,\n entry.w + inlineDelta,\n entry.h + blockDelta,\n cols,\n );\n applyDraft(next);\n const moved = next.find((item) => item.id === widgetId);\n if (moved) announceEntry(grabbed.kind, moved);\n },\n [cols, endGrab, applyDraft, announceEntry],\n );\n\n /* ---- pointer drag ---------------------------------------------- */\n const startPointerGrab = useCallback(\n (\n kind: 'move' | 'resize',\n widgetId: string,\n event: ReactPointerEvent<HTMLButtonElement>,\n ) => {\n if (!editing) return;\n // Any grab in flight wins: a keyboard grab must not be hijacked,\n // and a second concurrent pointer (multi-touch) must not reset an\n // active drag.\n if (grabRef.current) return;\n const gridNode = gridRef.current;\n const entry = resolvedRef.current.find((item) => item.id === widgetId);\n if (!gridNode || !entry) return;\n event.preventDefault();\n // preventDefault suppressed the browser's mousedown-focus — restore\n // it explicitly so the focusout/Escape cancel paths stay reachable\n // and the handle shows its focus ring during the drag.\n event.currentTarget.focus?.();\n const rect = gridNode.getBoundingClientRect();\n // A 0-width container (hidden tab, jsdom) has no usable cell metric —\n // pointer dragging is meaningless there; keyboard still works.\n if (rect.width <= 0) return;\n const styles = window.getComputedStyle(gridNode);\n const gap = Number.parseFloat(styles.columnGap) || 0;\n const rowGap = Number.parseFloat(styles.rowGap) || 0;\n const colWidth = (rect.width - gap * (cols - 1)) / cols;\n pointerDragRef.current = {\n kind,\n id: widgetId,\n pointerId: event.pointerId,\n startClientX: event.clientX,\n startClientY: event.clientY,\n origin: entry,\n colStride: colWidth + gap,\n rowStride: rowHeight + rowGap,\n isRtl: styles.direction === 'rtl',\n };\n try {\n event.currentTarget.setPointerCapture?.(event.pointerId);\n } catch {\n // Synthetic pointer events (tests) have no active pointer to\n // capture; the window-level listeners track the drag regardless.\n }\n beginGrab(kind, widgetId, 'pointer');\n },\n [editing, cols, rowHeight, beginGrab],\n );\n\n // Pointer move/up/cancel are window-level while a drag is in flight so\n // the drag survives the pointer leaving the handle's hit area.\n useEffect(() => {\n if (!grab || grab.via !== 'pointer') return undefined;\n const onMove = (event: PointerEvent) => {\n const dragState = pointerDragRef.current;\n const grabbed = grabRef.current;\n if (!dragState || !grabbed || event.pointerId !== dragState.pointerId)\n return;\n const dxPx = event.clientX - dragState.startClientX;\n const dyPx = event.clientY - dragState.startClientY;\n // Visual px → logical cells: a rightward drag decreases the logical\n // column in RTL.\n const inlineCells =\n Math.round(dxPx / dragState.colStride) * (dragState.isRtl ? -1 : 1);\n const blockCells = Math.round(dyPx / dragState.rowStride);\n // Origin-absolute targeting against the frozen grab base — every\n // event re-derives the whole draft, nothing accumulates.\n const next =\n dragState.kind === 'move'\n ? moveItem(\n grabbed.baseLayout,\n dragState.id,\n dragState.origin.x + inlineCells,\n dragState.origin.y + blockCells,\n colsRef.current,\n )\n : resizeItem(\n grabbed.baseLayout,\n dragState.id,\n dragState.origin.w + inlineCells,\n dragState.origin.h + blockCells,\n colsRef.current,\n );\n applyDraft(next);\n };\n const onUp = (event: PointerEvent) => {\n const dragState = pointerDragRef.current;\n if (!dragState || event.pointerId !== dragState.pointerId) return;\n suppressClickRef.current = true;\n endGrab(true);\n };\n const onCancel = (event: PointerEvent) => {\n const dragState = pointerDragRef.current;\n if (!dragState || event.pointerId !== dragState.pointerId) return;\n suppressClickRef.current = true;\n endGrab(false);\n };\n window.addEventListener('pointermove', onMove);\n window.addEventListener('pointerup', onUp);\n window.addEventListener('pointercancel', onCancel);\n return () => {\n window.removeEventListener('pointermove', onMove);\n window.removeEventListener('pointerup', onUp);\n window.removeEventListener('pointercancel', onCancel);\n };\n }, [grab, endGrab, applyDraft]);\n\n // Escape cancels ANY in-flight grab wherever focus currently is (APG:\n // the cancel key must work for the whole operation, not only while the\n // grabbed handle keeps focus).\n useEffect(() => {\n if (!grab) return undefined;\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') endGrab(false);\n };\n window.addEventListener('keydown', onKeyDown);\n return () => window.removeEventListener('keydown', onKeyDown);\n }, [grab, endGrab]);\n\n // A keyboard grab that loses focus is cancelled (never leave the board\n // in a half-grabbed state).\n useEffect(() => {\n if (!grab || grab.via !== 'keyboard') return undefined;\n const onFocusOut = (event: FocusEvent) => {\n const next = event.relatedTarget as Node | null;\n if (!next || !gridRef.current?.contains(next)) endGrab(false);\n };\n const node = gridRef.current;\n node?.addEventListener('focusout', onFocusOut);\n return () => node?.removeEventListener('focusout', onFocusOut);\n }, [grab, endGrab]);\n\n /* ---- container CSS vars ---------------------------------------- */\n useIsomorphicLayoutEffect(() => {\n const node = gridRef.current;\n if (!node) return;\n node.style.setProperty('--dg-cols', String(cols));\n node.style.setProperty('--dg-row', `${rowHeight}px`);\n }, [cols, rowHeight]);\n\n // Edit-mode surface metrics. The cell-line gradients and the spare-row\n // min height depend on runtime values (cols, rowHeight, occupied rows),\n // so they flow through custom properties like the coordinates do.\n const visibleRows = rowCount(active);\n useIsomorphicLayoutEffect(() => {\n const node = gridRef.current;\n if (!node) return;\n node.style.setProperty(\n '--dg-grid-lines',\n `repeating-linear-gradient(to right, color-mix(in srgb, var(--border) 50%, transparent) 0 1px, transparent 1px calc((100% + var(--spacing-md)) / ${cols})), ` +\n `repeating-linear-gradient(to bottom, color-mix(in srgb, var(--border) 50%, transparent) 0 1px, transparent 1px calc(${rowHeight}px + var(--spacing-md)))`,\n );\n node.style.setProperty(\n '--dg-min-block',\n `calc(${visibleRows + 2} * (${rowHeight}px + var(--spacing-md)) - var(--spacing-md))`,\n );\n }, [cols, rowHeight, visibleRows]);\n\n /* ---- add tile placement ---------------------------------------- */\n const addTileRef = useRef<HTMLDivElement>(null);\n const showAddTile = editing && Boolean(onRequestAdd);\n const addSpot = useMemo(\n () => (showAddTile ? firstFit(active, cols, 2, 2) : null),\n [showAddTile, active, cols],\n );\n useIsomorphicLayoutEffect(() => {\n const node = addTileRef.current;\n if (!node || !addSpot) return;\n node.style.setProperty('--dg-x', String(addSpot.x + 1));\n node.style.setProperty('--dg-y', String(addSpot.y + 1));\n node.style.setProperty('--dg-w', '2');\n node.style.setProperty('--dg-h', '2');\n }, [addSpot]);\n\n /* ---- remove flow ------------------------------------------------ */\n const requestRemove = useCallback(\n (widgetId: string) => {\n // The kit owns the entry removal (single commit) and the focus\n // recovery — the consumer only unmounts the child. Without this a\n // keyboard user's focus falls to <body> when the button unmounts.\n commit(\n normalise(\n resolvedRef.current.filter((entry) => entry.id !== widgetId),\n colsRef.current,\n ),\n );\n setAnnouncement(t('dashboardGrid.removed'));\n onRemoveWidget?.(widgetId);\n requestAnimationFrame(() => {\n const root = gridRef.current;\n if (!root) return;\n const nextFocus = root.querySelector<HTMLButtonElement>('button');\n if (nextFocus) nextFocus.focus();\n else root.focus();\n });\n },\n [commit, onRemoveWidget, t],\n );\n\n /* ---- imperative handle / agent --------------------------------- */\n const agentHandle = useMemo<DashboardGridHandle>(\n () => ({\n moveWidgetTo(widgetId, x, y) {\n if (!editing) return false;\n if (!Number.isFinite(x) || !Number.isFinite(y)) return false;\n if (!resolved.some((item) => item.id === widgetId)) return false;\n // Round: fractional cells produce invalid grid-column values.\n commit(\n normalise(\n moveItem(resolved, widgetId, Math.round(x), Math.round(y), cols),\n cols,\n ),\n );\n return true;\n },\n resizeWidgetTo(widgetId, w, h) {\n if (!editing) return false;\n if (!Number.isFinite(w) || !Number.isFinite(h)) return false;\n if (!resolved.some((item) => item.id === widgetId)) return false;\n commit(\n normalise(\n resizeItem(\n resolved,\n widgetId,\n Math.round(w),\n Math.round(h),\n cols,\n ),\n cols,\n ),\n );\n return true;\n },\n getGridState() {\n return {\n cols,\n editing,\n layout: resolved.map((item) => ({ ...item })),\n };\n },\n }),\n [editing, resolved, cols, commit],\n );\n useImperativeHandle(ref, () => agentHandle, [agentHandle]);\n useAgentRegistration(dashboardGridAgent, agentHandle, id);\n\n const contextValue = useMemo<DashboardGridContextValue>(\n () => ({\n editing,\n layoutById,\n grab,\n canRemove: Boolean(onRemoveWidget),\n requestRemove,\n startKeyboardGrab,\n keyboardStep,\n startPointerGrab,\n }),\n [\n editing,\n layoutById,\n grab,\n onRemoveWidget,\n requestRemove,\n startKeyboardGrab,\n keyboardStep,\n startPointerGrab,\n ],\n );\n\n return (\n <div\n data-component=\"dashboard-grid\"\n data-component-id={id}\n data-editing={editing || undefined}\n className={`ds:block ds:w-full ${className ?? ''}`.trim()}\n >\n <div role=\"status\" aria-live=\"polite\" className=\"ds:sr-only\">\n {announcement}\n </div>\n <div\n ref={gridRef}\n role=\"list\"\n aria-label={ariaLabel}\n tabIndex={-1}\n data-editing={editing || undefined}\n className={dashboardGridVariants()}\n >\n <DashboardGridContext.Provider value={contextValue}>\n {children}\n </DashboardGridContext.Provider>\n {showAddTile ? (\n // role=\"list\" allows only listitem children — the tile wrapper\n // carries the grid placement, the button fills it.\n <div\n ref={addTileRef}\n role=\"listitem\"\n className={[\n 'ds:flex',\n 'ds:[grid-column-start:var(--dg-x)] ds:[grid-column-end:span_var(--dg-w)]',\n 'ds:[grid-row-start:var(--dg-y)] ds:[grid-row-end:span_var(--dg-h)]',\n ].join(' ')}\n >\n <button\n type=\"button\"\n onClick={onRequestAdd}\n className={[\n 'ds:flex ds:flex-1 ds:items-center ds:justify-center ds:gap-[var(--spacing-xs)]',\n 'ds:rounded-[var(--radius-lg)] ds:border ds:border-dashed ds:border-border',\n 'ds:text-sm ds:text-muted-foreground ds:transition-colors',\n 'ds:hover:bg-muted/10 ds:hover:text-foreground',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid ds:focus-visible:outline-ring',\n ].join(' ')}\n >\n <Plus aria-hidden=\"true\" className=\"ds:size-4\" />\n {t('dashboardGrid.add')}\n </button>\n </div>\n ) : null}\n </div>\n </div>\n );\n },\n);\nDashboardGridRoot.displayName = 'DashboardGrid';\n\nexport const DashboardGrid = Object.assign(DashboardGridRoot, {\n Widget: DashboardGridWidget,\n});\n"],"names":["__iconNode","MoveDiagonal2","createLucideIcon","dashboardGridAgent","handle","args","collides","a","b","clampRect","item","cols","minW","minH","maxW","maxH","w","h","x","y","normalise","layout","activeId","items","order","placed","active","above","p","test","byId","moveItem","id","next","resizeItem","firstFit","width","maxY","m","candidate","rowCount","dashboardGridVariants","cva","widgetVariants","DashboardGridContext","createContext","forEachWidgetChild","children","fn","Children","child","isValidElement","Fragment","DashboardGridWidget","title","actionsSlot","t","useTranslation","ctx","useContext","wrapperRef","useRef","entry","useIsomorphicLayoutEffect","node","grabbed","_a","editing","jsxs","jsx","IconButton","GripVertical","_b","event","X","_c","DashboardGridRoot","forwardRef","ariaLabel","rowHeight","layoutProp","defaultLayout","onLayoutChange","onRemoveWidget","onRequestAdd","className","ref","gridRef","childIds","useMemo","ids","childMeta","meta","internalLayout","setInternalLayout","useState","committed","commit","useCallback","resolved","autoPlaced","clamped","missing","cid","spot","reportedRef","useEffect","signature","draft","setDraft","grab","setGrab","announcement","setAnnouncement","draftRef","grabRef","pointerDragRef","suppressClickRef","colsRef","resolvedRef","applyDraft","beginGrab","kind","widgetId","via","state","layoutById","announceEntry","endGrab","commitDraft","current","final","signatureOf","e","landed","startKeyboardGrab","keyboardStep","isRtl","inlineDelta","blockDelta","moved","startPointerGrab","gridNode","rect","styles","gap","rowGap","colWidth","_d","onMove","dragState","dxPx","dyPx","inlineCells","blockCells","onUp","onCancel","onKeyDown","onFocusOut","visibleRows","addTileRef","showAddTile","addSpot","requestRemove","root","nextFocus","agentHandle","useImperativeHandle","useAgentRegistration","contextValue","Plus","DashboardGrid"],"mappings":"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","x_google_ignoreList":[0]}
@@ -3,7 +3,7 @@ import { jsx as l, jsxs as L } from "react/jsx-runtime";
3
3
  import { T as V } from "./tag-3wgkwwDB.js";
4
4
  import { useTranslation as x } from "react-i18next";
5
5
  import { I as z } from "./icon-button-C_kbcd7I.js";
6
- import { I as $ } from "./icon-button-group-C_lqXTAj.js";
6
+ import { I as $ } from "./icon-button-group-BLHPN6jg.js";
7
7
  import { c as D } from "./createLucideIcon-DhHxpK9K.js";
8
8
  import { S as H } from "./square-check-big-dj0o8yA3.js";
9
9
  import { S as q } from "./square-DASBRZ0U.js";
@@ -407,4 +407,4 @@ export {
407
407
  ve as r,
408
408
  be as u
409
409
  };
410
- //# sourceMappingURL=editable-currency-cell-renderer-GwfA9tTR.js.map
410
+ //# sourceMappingURL=editable-currency-cell-renderer-Dus_sBvX.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"editable-currency-cell-renderer-GwfA9tTR.js","sources":["../../node_modules/lucide-react/dist/esm/icons/arrow-down.mjs","../../node_modules/lucide-react/dist/esm/icons/arrow-up.mjs","../../src/components/data-table/hooks/use-total-row.ts","../../src/components/data-table/cell-renderers/tooth-cell-renderer.tsx","../../src/components/data-table/cell-renderers/reorder-cell-renderer.tsx","../../src/components/data-table/cell-renderers/toggle-cell-renderer.tsx","../../src/components/data-table/cell-renderers/color-dot-cell-renderer.tsx","../../src/components/data-table/cell-renderers/balance-cell-renderer.tsx","../../src/components/data-table/cell-renderers/editable-text-cell-renderer.tsx","../../src/components/data-table/cell-renderers/editable-currency-cell-renderer.tsx"],"sourcesContent":["/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M12 5v14\", key: \"s699le\" }],\n [\"path\", { d: \"m19 12-7 7-7-7\", key: \"1idqje\" }]\n];\nconst ArrowDown = createLucideIcon(\"arrow-down\", __iconNode);\n\nexport { __iconNode, ArrowDown as default };\n//# sourceMappingURL=arrow-down.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"m5 12 7-7 7 7\", key: \"hav0vg\" }],\n [\"path\", { d: \"M12 19V5\", key: \"x0mq9r\" }]\n];\nconst ArrowUp = createLucideIcon(\"arrow-up\", __iconNode);\n\nexport { __iconNode, ArrowUp as default };\n//# sourceMappingURL=arrow-up.mjs.map\n","import { useMemo } from 'react';\n\n/**\n * Compute a pinned total row from a dataset and a list of numeric fields.\n *\n * The returned object is structurally a `TData` with non-summed fields left\n * `undefined` — plug it into `pinnedBottomRowData={[totalRow]}`. Cell renderers\n * in the non-summed columns receive `undefined`, so they should render nothing\n * (all of the DS cell renderers short-circuit on `null`/`undefined`).\n *\n * Pass an optional `labelField` + `labelValue` to show a static caption such\n * as \"Total\" in the first column of the pinned row.\n */\nexport function useTotalRow<TData>(\n rowData: TData[] | undefined,\n sumFields: Array<keyof TData & string>,\n options?: {\n labelField?: keyof TData & string;\n labelValue?: string;\n },\n): TData {\n return useMemo(() => {\n const row: Record<string, unknown> = {};\n\n for (const field of sumFields) {\n let total = 0;\n for (const r of rowData ?? []) {\n const raw = (r as Record<string, unknown>)[field];\n const n = typeof raw === 'number' ? raw : Number(raw);\n if (Number.isFinite(n)) total += n;\n }\n row[field] = total;\n }\n\n if (options?.labelField && options.labelValue !== undefined) {\n row[options.labelField] = options.labelValue;\n }\n\n return row as TData;\n }, [rowData, sumFields, options?.labelField, options?.labelValue]);\n}\n","import type { CustomCellRendererProps } from 'ag-grid-react';\nimport { Tag } from '../../tag/tag';\n\n// Tooth glyph — lucide ships no dental icon, so this is a small inline tooth\n// (a crown narrowing to two roots) tinted with `currentColor`, so it inherits\n// the Tag's text colour. Decorative; the FDI numbers are the accessible label.\nfunction ToothIcon() {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={1.75}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n className=\"ds:size-3.5\"\n >\n <path d=\"M12 5.5c-1.074 -1.426 -2.45 -2.2 -4 -2c-2.5 .323 -3.7 2.5 -3.5 5c.1 1.5 .5 3 .5 4.5c0 1.5 .5 3.5 1 5c.3 .9 .5 2 1.5 2s1.3 -1.5 1.5 -2.5c.2 -1 .5 -2 1.5 -2s1.3 1 1.5 2c.2 1 .5 2.5 1.5 2.5s1.2 -1.1 1.5 -2c.5 -1.5 1 -3.5 1 -5c0 -1.5 .4 -3 .5 -4.5c.2 -2.5 -1 -4.677 -3.5 -5c-1.55 -.2 -2.926 .574 -4 2z\" />\n </svg>\n );\n}\n\nexport interface ToothCellRendererParams {\n /** Max inline size of the chip before its label truncates (with a tooltip). */\n maxInlineSize?: string;\n}\n\n/**\n * Renders an array of tooth ids (FDI notation) as a single outlined Tag — the\n * teeth comma-separated and prefixed with a tooth glyph, so dentition reads at\n * a glance instead of as bare numbers.\n */\nexport function ToothCellRenderer(\n props: CustomCellRendererProps<unknown, string[]> & ToothCellRendererParams,\n) {\n const { value, maxInlineSize = '8rem' } = props;\n if (!Array.isArray(value) || value.length === 0) return null;\n\n return (\n <Tag\n label={value.join(', ')}\n size=\"sm\"\n fill=\"outline\"\n leading={<ToothIcon />}\n maxInlineSize={maxInlineSize}\n />\n );\n}\n","import type { CustomCellRendererProps } from 'ag-grid-react';\nimport { useTranslation } from 'react-i18next';\nimport { ArrowUp, ArrowDown } from 'lucide-react';\nimport { IconButton } from '../../button/icon-button';\nimport { IconButtonGroup } from '../../icon-button-group';\n\n/**\n * Keyboard-accessible row-reorder cell. AG Grid's native row dragging is\n * mouse/touch only; this renderer adds move-up / move-down buttons so the order\n * is reachable by keyboard too (the missing accessible half of the\n * \"drag-sortable column\" primitive). The consumer owns `rowData` order and\n * reorders it in `onMove` — the same controlled contract as the editable cells.\n */\nexport interface ReorderCellRendererParams<TData = unknown> {\n /** Move the row one step in the given direction (consumer reorders rowData). */\n onMove: (data: TData, direction: 'up' | 'down') => void;\n /** Accessible name for the move-up button (defaults to a kit string). */\n moveUpLabel?: string;\n /** Accessible name for the move-down button (defaults to a kit string). */\n moveDownLabel?: string;\n /** Button intent (default `ghost`). */\n intent?: 'ghost' | 'outline';\n /** Render the two buttons as a connected `IconButtonGroup` (default true). */\n group?: boolean;\n /**\n * Disable move-up on the first displayed row and move-down on the last\n * (default true). Turn off when the grid is filtered/sorted and the ends are\n * not meaningful.\n */\n disableAtEnds?: boolean;\n}\n\n/**\n * Pixel width a reorder column needs for the two `sm` IconButtons (32px each)\n * plus the data-table cell's inline padding so the controls never clip. Mirrors\n * {@link actionsColumnWidth}.\n */\nexport function reorderColumnWidth(): number {\n const SM_BUTTON = 32;\n const CELL_INSET = 26;\n return SM_BUTTON * 2 + CELL_INSET;\n}\n\nexport function ReorderCellRenderer<TData = unknown>(\n props: CustomCellRendererProps<TData> & ReorderCellRendererParams<TData>,\n) {\n const {\n data,\n node,\n api,\n onMove,\n moveUpLabel,\n moveDownLabel,\n intent = 'ghost',\n group = true,\n disableAtEnds = true,\n } = props;\n const { t } = useTranslation();\n if (!data) return null;\n\n const rowIndex = node.rowIndex ?? -1;\n const lastIndex = api.getDisplayedRowCount() - 1;\n const atFirst = disableAtEnds && rowIndex <= 0;\n const atLast = disableAtEnds && rowIndex >= lastIndex;\n\n const upLabel = moveUpLabel ?? t('dataTable.moveUp', 'Move up');\n const downLabel = moveDownLabel ?? t('dataTable.moveDown', 'Move down');\n\n // An ARRAY of IconButtons (not a Fragment): IconButtonGroup inspects its\n // direct children and rejects anything that isn't a DS IconButton.\n const buttons = [\n <IconButton\n key=\"up\"\n size=\"sm\"\n intent={intent}\n icon={<ArrowUp aria-hidden className=\"ds:size-4\" />}\n tooltip={upLabel}\n aria-label={upLabel}\n disabled={atFirst}\n onClick={(event) => {\n event.stopPropagation();\n onMove(data, 'up');\n }}\n />,\n <IconButton\n key=\"down\"\n size=\"sm\"\n intent={intent}\n icon={<ArrowDown aria-hidden className=\"ds:size-4\" />}\n tooltip={downLabel}\n aria-label={downLabel}\n disabled={atLast}\n onClick={(event) => {\n event.stopPropagation();\n onMove(data, 'down');\n }}\n />,\n ];\n\n return group ? (\n <IconButtonGroup\n aria-label={t('dataTable.reorder', 'Reorder row')}\n size=\"sm\"\n >\n {buttons}\n </IconButtonGroup>\n ) : (\n <span className=\"ds:inline-flex ds:items-center ds:gap-[var(--spacing-xs)]\">\n {buttons}\n </span>\n );\n}\n","import { useState, type ReactNode } from 'react';\nimport type { CustomCellRendererProps } from 'ag-grid-react';\nimport { CheckSquare, Square } from 'lucide-react';\nimport { useTranslation } from 'react-i18next';\n\nexport interface ToggleCellRendererParams<TData = unknown> {\n /**\n * Fires with the row and the new target value. May return a `Promise` —\n * if it rejects, the consumer is expected to revert the underlying value\n * and flash the row with `data-table-row-error` (return that row class\n * from `getRowClass`). Use `onError` below to be notified inside this\n * renderer.\n */\n onToggle: (data: TData, newValue: boolean) => void | Promise<void>;\n /**\n * Optional reject hook. Fires when the `onToggle` promise rejects, with\n * the row and the error. The button auto-disables during the in-flight\n * promise and re-enables on either settle.\n */\n onError?: (data: TData, error: unknown) => void;\n /** Icon shown when the current value is truthy. */\n trueIcon?: ReactNode;\n /** Icon shown when the current value is falsy. */\n falseIcon?: ReactNode;\n /** Extra classes applied to the \"on\" icon — defaults to success token. */\n trueClass?: string;\n /** Extra classes applied to the \"off\" icon. */\n falseClass?: string;\n /** Accessible label. Falls back to the default on/off announcements. */\n label?: string;\n}\n\nexport function ToggleCellRenderer<TData = unknown>(\n props: CustomCellRendererProps<TData, boolean> &\n ToggleCellRendererParams<TData>,\n) {\n const {\n value,\n data,\n onToggle,\n onError,\n trueIcon,\n falseIcon,\n trueClass = 'ds:text-[color:var(--success)]',\n falseClass = 'ds:text-[color:var(--muted-foreground)]',\n label,\n } = props;\n const { t } = useTranslation();\n const [pending, setPending] = useState(false);\n if (!data) return null;\n\n const isOn = Boolean(value);\n const icon = isOn\n ? (trueIcon ?? <CheckSquare aria-hidden className=\"ds:size-4\" />)\n : (falseIcon ?? <Square aria-hidden className=\"ds:size-4\" />);\n const stateClass = isOn ? trueClass : falseClass;\n const resolvedLabel =\n label ?? (isOn ? t('inputs.switch.on') : t('inputs.switch.off'));\n\n async function handleClick(event: React.MouseEvent) {\n event.stopPropagation();\n if (pending || !data) return;\n const next = !isOn;\n const result = onToggle(data, next);\n if (result && typeof (result as Promise<void>).then === 'function') {\n setPending(true);\n try {\n await result;\n } catch (err) {\n onError?.(data, err);\n } finally {\n setPending(false);\n }\n }\n }\n\n return (\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={isOn}\n aria-busy={pending}\n aria-label={resolvedLabel}\n disabled={pending}\n onClick={handleClick}\n className={[\n 'ds:inline-flex ds:items-center ds:justify-center',\n 'ds:min-h-[var(--min-target-size)] ds:min-w-[var(--min-target-size)]',\n 'ds:appearance-none ds:bg-transparent ds:p-[var(--spacing-xs)]',\n 'ds:rounded-[var(--radius-sm)]',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)]',\n 'ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[color:var(--ring)]',\n 'ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:disabled:opacity-50',\n stateClass,\n ].join(' ')}\n >\n {icon}\n </button>\n );\n}\n","import { useRef } from 'react';\nimport type { CustomCellRendererProps } from 'ag-grid-react';\nimport { useIsomorphicLayoutEffect } from '../../../hooks/use-isomorphic-layout-effect';\n\nexport interface ColorDotCellRendererParams {\n /** Field name on the row whose value holds the hex color. */\n colorField: string;\n /** Visual size of the dot. */\n size?: 'sm' | 'md' | 'lg';\n /** Optional label shown next to the dot. */\n labelField?: string;\n}\n\nconst SIZE_CLASS: Record<\n NonNullable<ColorDotCellRendererParams['size']>,\n string\n> = {\n sm: 'ds:size-[var(--icon-size-sm)]',\n md: 'ds:size-[var(--icon-size-md)]',\n lg: 'ds:size-[var(--icon-size-lg)]',\n};\n\nfunction readField(row: unknown, field: string): string | undefined {\n if (!row || typeof row !== 'object') return undefined;\n const value = (row as Record<string, unknown>)[field];\n return typeof value === 'string' ? value : undefined;\n}\n\n// Only accept trusted CSS color forms. Anything outside this allow-list\n// (including smuggled `url()` or extra declarations) is dropped so the\n// CSS custom-property writer can't be used to inject styles.\nconst HEX_RE = /^#(?:[0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i;\nconst RGB_RE = /^rgba?\\(\\s*[\\d.\\s,%/]+\\)$/i;\nconst HSL_RE = /^hsla?\\(\\s*[\\d.\\s,%/]+\\)$/i;\nconst CSS_VAR_RE = /^var\\(--[a-z0-9-]+(?:,\\s*[^)]+)?\\)$/i;\n\nfunction sanitizeColor(raw: string | undefined): string | undefined {\n if (!raw) return undefined;\n const v = raw.trim();\n if (\n HEX_RE.test(v) ||\n RGB_RE.test(v) ||\n HSL_RE.test(v) ||\n CSS_VAR_RE.test(v)\n ) {\n return v;\n }\n return undefined;\n}\n\nexport function ColorDotCellRenderer<TData = unknown>(\n props: CustomCellRendererProps<TData> & ColorDotCellRendererParams,\n) {\n const { data, colorField, size = 'md', labelField } = props;\n const dotRef = useRef<HTMLSpanElement | null>(null);\n const rawColor = data ? readField(data, colorField) : undefined;\n const color = sanitizeColor(rawColor);\n const label = data && labelField ? readField(data, labelField) : undefined;\n\n // Apply the dynamic color via a CSS custom property on the element.\n // Keeps hex/rgb literals out of JSX (constraint #2 and #4). The data\n // itself drives the color — constraints only forbid hardcoded colors\n // in component source, not in consumer row data.\n useIsomorphicLayoutEffect(() => {\n const el = dotRef.current;\n if (!el) return;\n if (color) {\n el.style.setProperty('--data-table-dot-color', color);\n } else {\n el.style.removeProperty('--data-table-dot-color');\n }\n }, [color]);\n\n if (!color) return null;\n\n return (\n <span className=\"ds:inline-flex ds:items-center ds:gap-[var(--spacing-sm)]\">\n <span\n ref={dotRef}\n aria-hidden=\"true\"\n className={[\n 'ds:inline-block ds:shrink-0 ds:rounded-[var(--radius-full)]',\n 'ds:bg-[var(--data-table-dot-color)]',\n 'ds:border ds:border-[color:var(--border)]',\n SIZE_CLASS[size],\n ].join(' ')}\n />\n {label ? <span>{label}</span> : null}\n </span>\n );\n}\n","import type { ColDef } from 'ag-grid-community';\nimport type { CustomCellRendererProps } from 'ag-grid-react';\nimport { useTranslation } from 'react-i18next';\n\nexport interface BalanceLine {\n /** User-visible label for this line. */\n label: string;\n /** Field name on the row whose numeric value is rendered. */\n valueField: string;\n /** `'currency'` renders via Intl, `'percent'` appends `%`, `'number'` raw. Default `'number'`. */\n format?: 'currency' | 'percent' | 'number';\n}\n\nexport interface BalanceCellRendererParams {\n lines: BalanceLine[];\n /** ISO 4217 code, used by `currency`-formatted lines. Default `'EUR'`. */\n currency?: string;\n /** Apply destructive color to negative values. */\n highlightNegative?: boolean;\n}\n\nfunction readNumber(row: unknown, field: string): number | null {\n if (!row || typeof row !== 'object') return null;\n const raw = (row as Record<string, unknown>)[field];\n const n = typeof raw === 'number' ? raw : Number(raw);\n return Number.isFinite(n) ? n : null;\n}\n\n/**\n * Renders a compact set of label / value pairs inside a single AG Grid cell.\n *\n * Layout is **horizontal** with middle-dot separators so the cell fits\n * inside the default AG Grid row height without spilling into the row\n * below. Use the SALDI / Listini patterns (Totale · Incassato · Da Incassare)\n * as the canonical example.\n *\n * If a consumer's content wraps (long localized labels, narrow columns)\n * they can opt into row auto-growth by spreading\n * {@link balanceCellRendererColDefDefaults} onto the column definition.\n */\nexport function BalanceCellRenderer<TData = unknown>(\n props: CustomCellRendererProps<TData> & BalanceCellRendererParams,\n) {\n const { data, lines, currency = 'EUR', highlightNegative } = props;\n const { i18n } = useTranslation();\n if (!data) return null;\n\n const locale = i18n.language || 'en';\n\n const formatLine = (\n line: BalanceLine,\n ): { label: string; formatted: string; negative: boolean } | null => {\n const n = readNumber(data, line.valueField);\n if (n === null) return null;\n\n let formatted: string;\n switch (line.format ?? 'number') {\n case 'currency':\n formatted = new Intl.NumberFormat(locale, {\n style: 'currency',\n currency,\n }).format(n);\n break;\n case 'percent':\n formatted = new Intl.NumberFormat(locale, {\n style: 'percent',\n maximumFractionDigits: 1,\n }).format(n / 100);\n break;\n default:\n formatted = new Intl.NumberFormat(locale).format(n);\n }\n\n return {\n label: line.label,\n formatted,\n negative: Boolean(highlightNegative) && n < 0,\n };\n };\n\n const rendered = lines\n .map(formatLine)\n .filter(\n (x): x is { label: string; formatted: string; negative: boolean } =>\n x !== null,\n );\n if (rendered.length === 0) return null;\n\n return (\n <div\n className={[\n 'ds:flex',\n 'ds:flex-wrap',\n 'ds:items-center',\n 'ds:gap-x-[var(--spacing-sm)]',\n 'ds:gap-y-0',\n 'type-meta',\n 'ds:leading-tight',\n ].join(' ')}\n >\n {rendered.map((item, idx) => (\n <span\n key={`${item.label}-${idx}`}\n className=\"ds:inline-flex ds:items-baseline ds:gap-x-[var(--spacing-xs)]\"\n >\n {idx > 0 ? (\n <span\n aria-hidden=\"true\"\n className=\"ds:me-[var(--spacing-xs)] ds:text-[color:var(--muted-foreground)]\"\n >\n ·\n </span>\n ) : null}\n <span className=\"ds:text-[color:var(--muted-foreground)]\">\n {item.label}\n </span>\n <span\n className={[\n 'ds:tabular-nums',\n 'ds:font-medium',\n item.negative ? 'ds:text-[color:var(--destructive)]' : '',\n ]\n .filter(Boolean)\n .join(' ')}\n >\n {item.formatted}\n </span>\n </span>\n ))}\n </div>\n );\n}\n\n/**\n * Column-definition defaults consumers can spread onto a `ColDef` when they\n * want the renderer's wrapped / multi-line behaviour to grow the row.\n *\n * The default compact horizontal layout is engineered to fit the standard\n * AG Grid row height, so this opt-in is only needed when a long label set\n * wraps across two or more lines and the consumer would rather grow the\n * row than wrap silently.\n *\n * AG Grid does NOT auto-grow row height to fit a tall cell unless\n * `autoHeight` and `wrapText` are set on the colDef itself — a cell\n * renderer can't impose that from inside.\n *\n * @example\n * ```ts\n * {\n * headerName: 'Saldi',\n * cellRenderer: BalanceCellRenderer,\n * cellRendererParams: { lines, currency: 'EUR' },\n * ...balanceCellRendererColDefDefaults,\n * }\n * ```\n */\nexport const balanceCellRendererColDefDefaults: Readonly<\n Pick<ColDef, 'autoHeight' | 'wrapText'>\n> = {\n autoHeight: true,\n wrapText: true,\n};\n","import { useEffect, useRef, useState } from 'react';\nimport type { CustomCellEditorProps } from 'ag-grid-react';\nimport {\n INPUT_SURFACE_CHROME,\n INPUT_SURFACE_HEIGHT,\n INPUT_SURFACE_PADDING_X,\n INPUT_SURFACE_TEXT,\n} from '../../_shared/input-surface';\n\n/**\n * Inline text editor that visually matches `<TextInput size=\"sm\">`. Use as\n * `cellEditor` on a colDef with `editable: true`. The cell renderer (default\n * or custom) takes over again once editing stops.\n *\n * AG Grid commits on Enter or Tab or blur; cancels on Escape. The consumer\n * receives the committed value via `onCellValueChanged`.\n */\nexport function EditableTextCellRenderer<TData = unknown>(\n props: CustomCellEditorProps<TData, string>,\n) {\n const { initialValue, onValueChange, stopEditing, column } = props;\n const [value, setValue] = useState<string>(initialValue ?? '');\n const inputRef = useRef<HTMLInputElement | null>(null);\n\n // Focus + select on mount so typing replaces the current value.\n useEffect(() => {\n const el = inputRef.current;\n if (!el) return;\n el.focus();\n el.select();\n }, []);\n\n // The current value is pushed to AG Grid via `onValueChange` on every\n // keystroke — AG Grid commits the most recent value when editing stops.\n // No `useGridCellEditor` hook needed for that contract.\n\n // Thread the column header into the input's accessible name so screen\n // readers announce \"Edit text, {column}\" instead of an unlabelled input.\n // AG Grid doesn't auto-wire the column header to cell editors.\n const headerName =\n (column?.getColDef?.()?.headerName as string | undefined) ?? undefined;\n\n return (\n <input\n ref={inputRef}\n type=\"text\"\n value={value}\n aria-label={headerName}\n onChange={(e) => {\n const next = e.target.value;\n setValue(next);\n onValueChange(next);\n }}\n onKeyDown={(e) => {\n // Escape cancels, Enter/Tab commit — AG Grid handles both, but we\n // explicitly stop editing on Enter so the consumer sees the commit\n // immediately rather than waiting for the next focus blur.\n if (e.key === 'Enter') {\n e.preventDefault();\n stopEditing();\n }\n }}\n className={[\n 'ds:block ds:w-full ds:appearance-none',\n // Input surface chrome: rounded border + bg + focus halo.\n INPUT_SURFACE_CHROME,\n // Use the `md` height (`--min-target-size`) so the input\n // auto-lifts to 48px under `.theme-accessible` to satisfy\n // WCAG 2.5.5 target size.\n INPUT_SURFACE_HEIGHT.md,\n INPUT_SURFACE_TEXT.sm,\n INPUT_SURFACE_PADDING_X.sm,\n ].join(' ')}\n />\n );\n}\n","import { useEffect, useRef, useState } from 'react';\nimport type { CustomCellEditorProps } from 'ag-grid-react';\nimport { useTranslation } from 'react-i18next';\nimport {\n INPUT_SURFACE_CHROME,\n INPUT_SURFACE_HEIGHT,\n INPUT_SURFACE_PADDING_X,\n INPUT_SURFACE_TEXT,\n} from '../../_shared/input-surface';\n\nexport interface EditableCurrencyCellEditorParams {\n /** ISO 4217 currency code (e.g. `EUR`, `USD`). Defaults to `EUR`. */\n currency?: string;\n /** Decimal places allowed in the editor. Defaults to 2 (cents precision). */\n decimals?: number;\n /** Minimum allowed value — values below this are clamped on commit. */\n min?: number;\n /** Maximum allowed value — values above this are clamped on commit. */\n max?: number;\n}\n\n/**\n * Inline numeric editor that visually matches `<TextInput size=\"sm\">`. Use as\n * `cellEditor` on a colDef with `editable: true`. The display formatting is\n * still the renderer's job — once editing stops, the cell hands back to\n * `CurrencyCellRenderer` (or whichever renderer the colDef declares).\n *\n * Stores a Number, not a string, so consumers receive `row.amount = 12.5`\n * not `\"12.5\"`. Strips locale separators on each change so commas/dots in\n * any language convert to a clean numeric value.\n */\nexport function EditableCurrencyCellRenderer<TData = unknown>(\n props: CustomCellEditorProps<TData, number> &\n EditableCurrencyCellEditorParams,\n) {\n const {\n initialValue,\n onValueChange,\n stopEditing,\n column,\n decimals = 2,\n min,\n max,\n } = props;\n const { i18n } = useTranslation();\n const inputRef = useRef<HTMLInputElement | null>(null);\n // Thread the column header into the input's accessible name — see\n // editable-text-cell-renderer.tsx for the rationale.\n const headerName =\n (column?.getColDef?.()?.headerName as string | undefined) ?? undefined;\n\n // Local string state so the user can type intermediate values like \"12.\"\n // before the trailing zero arrives. We commit a Number to AG Grid on each\n // change for consumers that watch row state live; the final commit fires\n // when editing stops.\n const [draft, setDraft] = useState<string>(() => {\n if (initialValue == null || Number.isNaN(initialValue)) return '';\n return String(initialValue);\n });\n\n useEffect(() => {\n const el = inputRef.current;\n if (!el) return;\n el.focus();\n el.select();\n }, []);\n\n function parseDraft(input: string): number | null {\n if (input.trim().length === 0) return null;\n // Accept either the user's locale decimal separator or a `.`. Strip\n // grouping characters (locale thousands separators, plus spaces).\n const lang = i18n.language || 'en';\n const partsFmt = new Intl.NumberFormat(lang).formatToParts(12345.6);\n const groupChar = partsFmt.find((p) => p.type === 'group')?.value ?? '';\n const decimalChar =\n partsFmt.find((p) => p.type === 'decimal')?.value ?? '.';\n const cleaned = input\n .replace(new RegExp(`\\\\${groupChar}`, 'g'), '')\n .replace(decimalChar, '.')\n .replace(/[^\\d.-]/g, '');\n const n = Number(cleaned);\n return Number.isFinite(n) ? n : null;\n }\n\n function commit(input: string) {\n const parsed = parseDraft(input);\n if (parsed == null) {\n onValueChange(null);\n return;\n }\n // Clamp first, then round to the declared precision so we never\n // persist floating-point dust from string parsing.\n let clamped = parsed;\n if (typeof min === 'number') clamped = Math.max(min, clamped);\n if (typeof max === 'number') clamped = Math.min(max, clamped);\n const factor = 10 ** decimals;\n onValueChange(Math.round(clamped * factor) / factor);\n }\n\n return (\n <input\n ref={inputRef}\n type=\"text\"\n // Inputmode hints mobile keyboards to show the decimal pad instead\n // of the full keyboard. type=\"number\" would also work but spinners\n // and locale parsing are inconsistent across browsers.\n inputMode=\"decimal\"\n value={draft}\n aria-label={headerName}\n onChange={(e) => {\n const next = e.target.value;\n setDraft(next);\n commit(next);\n }}\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n stopEditing();\n }\n // Escape — AG Grid cancels by default; the editor doesn't need\n // explicit handling beyond what AG Grid wires automatically.\n }}\n className={[\n 'ds:block ds:w-full ds:appearance-none ds:text-end ds:tabular-nums',\n INPUT_SURFACE_CHROME,\n // Use `md` height — see editable-text-cell-renderer for rationale.\n INPUT_SURFACE_HEIGHT.md,\n INPUT_SURFACE_TEXT.sm,\n INPUT_SURFACE_PADDING_X.sm,\n ].join(' ')}\n />\n );\n}\n"],"names":["__iconNode","ArrowDown","createLucideIcon","ArrowUp","useTotalRow","rowData","sumFields","options","useMemo","row","field","total","r","raw","n","ToothIcon","jsx","ToothCellRenderer","props","value","maxInlineSize","Tag","reorderColumnWidth","ReorderCellRenderer","data","node","api","onMove","moveUpLabel","moveDownLabel","intent","group","disableAtEnds","t","useTranslation","rowIndex","lastIndex","atFirst","atLast","upLabel","downLabel","buttons","IconButton","event","IconButtonGroup","ToggleCellRenderer","onToggle","onError","trueIcon","falseIcon","trueClass","falseClass","label","pending","setPending","useState","isOn","icon","CheckSquare","Square","stateClass","resolvedLabel","handleClick","result","err","SIZE_CLASS","readField","HEX_RE","RGB_RE","HSL_RE","CSS_VAR_RE","sanitizeColor","v","ColorDotCellRenderer","colorField","size","labelField","dotRef","useRef","rawColor","color","useIsomorphicLayoutEffect","el","jsxs","readNumber","BalanceCellRenderer","lines","currency","highlightNegative","i18n","locale","formatLine","line","formatted","rendered","x","item","idx","EditableTextCellRenderer","initialValue","onValueChange","stopEditing","column","setValue","inputRef","useEffect","headerName","_b","_a","e","next","INPUT_SURFACE_CHROME","INPUT_SURFACE_HEIGHT","INPUT_SURFACE_TEXT","INPUT_SURFACE_PADDING_X","EditableCurrencyCellRenderer","decimals","min","max","draft","setDraft","parseDraft","input","lang","partsFmt","groupChar","p","decimalChar","cleaned","commit","parsed","clamped","factor"],"mappings":";;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA,MAAMA,IAAa;AAAA,EACjB,CAAC,QAAQ,EAAE,GAAG,YAAY,KAAK,SAAQ,CAAE;AAAA,EACzC,CAAC,QAAQ,EAAE,GAAG,kBAAkB,KAAK,SAAQ,CAAE;AACjD,GACMC,IAAYC,EAAiB,cAAcF,CAAU;ACb3D;AAAA;AAAA;AAAA;AAAA;AAAA;AASA,MAAMA,IAAa;AAAA,EACjB,CAAC,QAAQ,EAAE,GAAG,iBAAiB,KAAK,SAAQ,CAAE;AAAA,EAC9C,CAAC,QAAQ,EAAE,GAAG,YAAY,KAAK,SAAQ,CAAE;AAC3C,GACMG,IAAUD,EAAiB,YAAYF,CAAU;ACAhD,SAASI,GACdC,GACAC,GACAC,GAIO;AACP,SAAOC,EAAQ,MAAM;AACnB,UAAMC,IAA+B,CAAA;AAErC,eAAWC,KAASJ,GAAW;AAC7B,UAAIK,IAAQ;AACZ,iBAAWC,KAAKP,KAAW,IAAI;AAC7B,cAAMQ,IAAOD,EAA8BF,CAAK,GAC1CI,IAAI,OAAOD,KAAQ,WAAWA,IAAM,OAAOA,CAAG;AACpD,QAAI,OAAO,SAASC,CAAC,MAAGH,KAASG;AAAA,MACnC;AACA,MAAAL,EAAIC,CAAK,IAAIC;AAAA,IACf;AAEA,WAAIJ,KAAA,QAAAA,EAAS,cAAcA,EAAQ,eAAe,WAChDE,EAAIF,EAAQ,UAAU,IAAIA,EAAQ,aAG7BE;AAAA,EACT,GAAG,CAACJ,GAASC,GAAWC,KAAA,gBAAAA,EAAS,YAAYA,KAAA,gBAAAA,EAAS,UAAU,CAAC;AACnE;AClCA,SAASQ,IAAY;AACnB,SACE,gBAAAC;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,QAAO;AAAA,MACP,aAAa;AAAA,MACb,eAAc;AAAA,MACd,gBAAe;AAAA,MACf,eAAY;AAAA,MACZ,WAAU;AAAA,MAEV,UAAA,gBAAAA,EAAC,QAAA,EAAK,GAAE,4SAAA,CAA4S;AAAA,IAAA;AAAA,EAAA;AAG1T;AAYO,SAASC,GACdC,GACA;AACA,QAAM,EAAE,OAAAC,GAAO,eAAAC,IAAgB,OAAA,IAAWF;AAC1C,SAAI,CAAC,MAAM,QAAQC,CAAK,KAAKA,EAAM,WAAW,IAAU,OAGtD,gBAAAH;AAAA,IAACK;AAAA,IAAA;AAAA,MACC,OAAOF,EAAM,KAAK,IAAI;AAAA,MACtB,MAAK;AAAA,MACL,MAAK;AAAA,MACL,2BAAUJ,GAAA,EAAU;AAAA,MACpB,eAAAK;AAAA,IAAA;AAAA,EAAA;AAGN;ACXO,SAASE,KAA6B;AAG3C,SAAO;AACT;AAEO,SAASC,GACdL,GACA;AACA,QAAM;AAAA,IACJ,MAAAM;AAAA,IACA,MAAAC;AAAA,IACA,KAAAC;AAAA,IACA,QAAAC;AAAA,IACA,aAAAC;AAAA,IACA,eAAAC;AAAA,IACA,QAAAC,IAAS;AAAA,IACT,OAAAC,IAAQ;AAAA,IACR,eAAAC,IAAgB;AAAA,EAAA,IACdd,GACE,EAAE,GAAAe,EAAA,IAAMC,EAAA;AACd,MAAI,CAACV,EAAM,QAAO;AAElB,QAAMW,IAAWV,EAAK,YAAY,IAC5BW,IAAYV,EAAI,qBAAA,IAAyB,GACzCW,IAAUL,KAAiBG,KAAY,GACvCG,IAASN,KAAiBG,KAAYC,GAEtCG,IAAUX,KAAeK,EAAE,oBAAoB,SAAS,GACxDO,IAAYX,KAAiBI,EAAE,sBAAsB,WAAW,GAIhEQ,IAAU;AAAA,IACd,gBAAAzB;AAAA,MAAC0B;AAAA,MAAA;AAAA,QAEC,MAAK;AAAA,QACL,QAAAZ;AAAA,QACA,MAAM,gBAAAd,EAACb,GAAA,EAAQ,eAAW,IAAC,WAAU,aAAY;AAAA,QACjD,SAASoC;AAAA,QACT,cAAYA;AAAA,QACZ,UAAUF;AAAA,QACV,SAAS,CAACM,MAAU;AAClB,UAAAA,EAAM,gBAAA,GACNhB,EAAOH,GAAM,IAAI;AAAA,QACnB;AAAA,MAAA;AAAA,MAVI;AAAA,IAAA;AAAA,IAYN,gBAAAR;AAAA,MAAC0B;AAAA,MAAA;AAAA,QAEC,MAAK;AAAA,QACL,QAAAZ;AAAA,QACA,MAAM,gBAAAd,EAACf,GAAA,EAAU,eAAW,IAAC,WAAU,aAAY;AAAA,QACnD,SAASuC;AAAA,QACT,cAAYA;AAAA,QACZ,UAAUF;AAAA,QACV,SAAS,CAACK,MAAU;AAClB,UAAAA,EAAM,gBAAA,GACNhB,EAAOH,GAAM,MAAM;AAAA,QACrB;AAAA,MAAA;AAAA,MAVI;AAAA,IAAA;AAAA,EAWN;AAGF,SAAOO,IACL,gBAAAf;AAAA,IAAC4B;AAAA,IAAA;AAAA,MACC,cAAYX,EAAE,qBAAqB,aAAa;AAAA,MAChD,MAAK;AAAA,MAEJ,UAAAQ;AAAA,IAAA;AAAA,EAAA,IAGH,gBAAAzB,EAAC,QAAA,EAAK,WAAU,6DACb,UAAAyB,GACH;AAEJ;AC/EO,SAASI,GACd3B,GAEA;AACA,QAAM;AAAA,IACJ,OAAAC;AAAA,IACA,MAAAK;AAAA,IACA,UAAAsB;AAAA,IACA,SAAAC;AAAA,IACA,UAAAC;AAAA,IACA,WAAAC;AAAA,IACA,WAAAC,IAAY;AAAA,IACZ,YAAAC,IAAa;AAAA,IACb,OAAAC;AAAA,EAAA,IACElC,GACE,EAAE,GAAAe,EAAA,IAAMC,EAAA,GACR,CAACmB,GAASC,CAAU,IAAIC,EAAS,EAAK;AAC5C,MAAI,CAAC/B,EAAM,QAAO;AAElB,QAAMgC,IAAO,EAAQrC,GACfsC,IAAOD,IACRR,KAAY,gBAAAhC,EAAC0C,GAAA,EAAY,eAAW,IAAC,WAAU,YAAA,CAAY,IAC3DT,KAAa,gBAAAjC,EAAC2C,GAAA,EAAO,eAAW,IAAC,WAAU,aAAY,GACtDC,IAAaJ,IAAON,IAAYC,GAChCU,IACJT,KAAiBnB,EAAPuB,IAAS,qBAAwB,mBAAN;AAEvC,iBAAeM,EAAYnB,GAAyB;AAElD,QADAA,EAAM,gBAAA,GACFU,KAAW,CAAC7B,EAAM;AAEtB,UAAMuC,IAASjB,EAAStB,GADX,CAACgC,CACoB;AAClC,QAAIO,KAAU,OAAQA,EAAyB,QAAS,YAAY;AAClE,MAAAT,EAAW,EAAI;AACf,UAAI;AACF,cAAMS;AAAA,MACR,SAASC,GAAK;AACZ,QAAAjB,KAAA,QAAAA,EAAUvB,GAAMwC;AAAA,MAClB,UAAA;AACE,QAAAV,EAAW,EAAK;AAAA,MAClB;AAAA,IACF;AAAA,EACF;AAEA,SACE,gBAAAtC;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAK;AAAA,MACL,MAAK;AAAA,MACL,gBAAcwC;AAAA,MACd,aAAWH;AAAA,MACX,cAAYQ;AAAA,MACZ,UAAUR;AAAA,MACV,SAASS;AAAA,MACT,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACAF;AAAA,MAAA,EACA,KAAK,GAAG;AAAA,MAET,UAAAH;AAAA,IAAA;AAAA,EAAA;AAGP;ACxFA,MAAMQ,IAGF;AAAA,EACF,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAEA,SAASC,EAAUzD,GAAcC,GAAmC;AAClE,MAAI,CAACD,KAAO,OAAOA,KAAQ,SAAU;AACrC,QAAMU,IAASV,EAAgCC,CAAK;AACpD,SAAO,OAAOS,KAAU,WAAWA,IAAQ;AAC7C;AAKA,MAAMgD,IAAS,iDACTC,IAAS,8BACTC,KAAS,8BACTC,KAAa;AAEnB,SAASC,GAAc1D,GAA6C;AAClE,MAAI,CAACA,EAAK;AACV,QAAM2D,IAAI3D,EAAI,KAAA;AACd,MACEsD,EAAO,KAAKK,CAAC,KACbJ,EAAO,KAAKI,CAAC,KACbH,GAAO,KAAKG,CAAC,KACbF,GAAW,KAAKE,CAAC;AAEjB,WAAOA;AAGX;AAEO,SAASC,GACdvD,GACA;AACA,QAAM,EAAE,MAAAM,GAAM,YAAAkD,GAAY,MAAAC,IAAO,MAAM,YAAAC,MAAe1D,GAChD2D,IAASC,EAA+B,IAAI,GAC5CC,IAAWvD,IAAO0C,EAAU1C,GAAMkD,CAAU,IAAI,QAChDM,IAAQT,GAAcQ,CAAQ,GAC9B3B,IAAQ5B,KAAQoD,IAAaV,EAAU1C,GAAMoD,CAAU,IAAI;AAgBjE,SAVAK,EAA0B,MAAM;AAC9B,UAAMC,IAAKL,EAAO;AAClB,IAAKK,MACDF,IACFE,EAAG,MAAM,YAAY,0BAA0BF,CAAK,IAEpDE,EAAG,MAAM,eAAe,wBAAwB;AAAA,EAEpD,GAAG,CAACF,CAAK,CAAC,GAELA,IAGH,gBAAAG,EAAC,QAAA,EAAK,WAAU,6DACd,UAAA;AAAA,IAAA,gBAAAnE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,KAAK6D;AAAA,QACL,eAAY;AAAA,QACZ,WAAW;AAAA,UACT;AAAA,UACA;AAAA,UACA;AAAA,UACAZ,EAAWU,CAAI;AAAA,QAAA,EACf,KAAK,GAAG;AAAA,MAAA;AAAA,IAAA;AAAA,IAEXvB,IAAQ,gBAAApC,EAAC,QAAA,EAAM,UAAAoC,EAAA,CAAM,IAAU;AAAA,EAAA,GAClC,IAfiB;AAiBrB;ACrEA,SAASgC,GAAW3E,GAAcC,GAA8B;AAC9D,MAAI,CAACD,KAAO,OAAOA,KAAQ,SAAU,QAAO;AAC5C,QAAMI,IAAOJ,EAAgCC,CAAK,GAC5CI,IAAI,OAAOD,KAAQ,WAAWA,IAAM,OAAOA,CAAG;AACpD,SAAO,OAAO,SAASC,CAAC,IAAIA,IAAI;AAClC;AAcO,SAASuE,GACdnE,GACA;AACA,QAAM,EAAE,MAAAM,GAAM,OAAA8D,GAAO,UAAAC,IAAW,OAAO,mBAAAC,MAAsBtE,GACvD,EAAE,MAAAuE,EAAA,IAASvD,EAAA;AACjB,MAAI,CAACV,EAAM,QAAO;AAElB,QAAMkE,IAASD,EAAK,YAAY,MAE1BE,IAAa,CACjBC,MACmE;AACnE,UAAM9E,IAAIsE,GAAW5D,GAAMoE,EAAK,UAAU;AAC1C,QAAI9E,MAAM,KAAM,QAAO;AAEvB,QAAI+E;AACJ,YAAQD,EAAK,UAAU,UAAA;AAAA,MACrB,KAAK;AACH,QAAAC,IAAY,IAAI,KAAK,aAAaH,GAAQ;AAAA,UACxC,OAAO;AAAA,UACP,UAAAH;AAAA,QAAA,CACD,EAAE,OAAOzE,CAAC;AACX;AAAA,MACF,KAAK;AACH,QAAA+E,IAAY,IAAI,KAAK,aAAaH,GAAQ;AAAA,UACxC,OAAO;AAAA,UACP,uBAAuB;AAAA,QAAA,CACxB,EAAE,OAAO5E,IAAI,GAAG;AACjB;AAAA,MACF;AACE,QAAA+E,IAAY,IAAI,KAAK,aAAaH,CAAM,EAAE,OAAO5E,CAAC;AAAA,IAAA;AAGtD,WAAO;AAAA,MACL,OAAO8E,EAAK;AAAA,MACZ,WAAAC;AAAA,MACA,UAAU,EAAQL,KAAsB1E,IAAI;AAAA,IAAA;AAAA,EAEhD,GAEMgF,IAAWR,EACd,IAAIK,CAAU,EACd;AAAA,IACC,CAACI,MACCA,MAAM;AAAA,EAAA;AAEZ,SAAID,EAAS,WAAW,IAAU,OAGhC,gBAAA9E;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MAAA,EACA,KAAK,GAAG;AAAA,MAET,UAAA8E,EAAS,IAAI,CAACE,GAAMC,MACnB,gBAAAd;AAAA,QAAC;AAAA,QAAA;AAAA,UAEC,WAAU;AAAA,UAET,UAAA;AAAA,YAAAc,IAAM,IACL,gBAAAjF;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,eAAY;AAAA,gBACZ,WAAU;AAAA,gBACX,UAAA;AAAA,cAAA;AAAA,YAAA,IAGC;AAAA,YACJ,gBAAAA,EAAC,QAAA,EAAK,WAAU,2CACb,YAAK,OACR;AAAA,YACA,gBAAAA;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,WAAW;AAAA,kBACT;AAAA,kBACA;AAAA,kBACAgF,EAAK,WAAW,uCAAuC;AAAA,gBAAA,EAEtD,OAAO,OAAO,EACd,KAAK,GAAG;AAAA,gBAEV,UAAAA,EAAK;AAAA,cAAA;AAAA,YAAA;AAAA,UACR;AAAA,QAAA;AAAA,QAxBK,GAAGA,EAAK,KAAK,IAAIC,CAAG;AAAA,MAAA,CA0B5B;AAAA,IAAA;AAAA,EAAA;AAGP;AClHO,SAASC,GACdhF,GACA;;AACA,QAAM,EAAE,cAAAiF,GAAc,eAAAC,GAAe,aAAAC,GAAa,QAAAC,MAAWpF,GACvD,CAACC,GAAOoF,CAAQ,IAAIhD,EAAiB4C,KAAgB,EAAE,GACvDK,IAAW1B,EAAgC,IAAI;AAGrD,EAAA2B,EAAU,MAAM;AACd,UAAMvB,IAAKsB,EAAS;AACpB,IAAKtB,MACLA,EAAG,MAAA,GACHA,EAAG,OAAA;AAAA,EACL,GAAG,CAAA,CAAE;AASL,QAAMwB,MACHC,KAAAC,IAAAN,KAAA,gBAAAA,EAAQ,cAAR,gBAAAM,EAAA,KAAAN,OAAA,gBAAAK,EAAuB,eAAqC;AAE/D,SACE,gBAAA3F;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,KAAKwF;AAAA,MACL,MAAK;AAAA,MACL,OAAArF;AAAA,MACA,cAAYuF;AAAA,MACZ,UAAU,CAACG,MAAM;AACf,cAAMC,IAAOD,EAAE,OAAO;AACtB,QAAAN,EAASO,CAAI,GACbV,EAAcU,CAAI;AAAA,MACpB;AAAA,MACA,WAAW,CAACD,MAAM;AAIhB,QAAIA,EAAE,QAAQ,YACZA,EAAE,eAAA,GACFR,EAAA;AAAA,MAEJ;AAAA,MACA,WAAW;AAAA,QACT;AAAA;AAAA,QAEAU;AAAA;AAAA;AAAA;AAAA,QAIAC,EAAqB;AAAA,QACrBC,EAAmB;AAAA,QACnBC,EAAwB;AAAA,MAAA,EACxB,KAAK,GAAG;AAAA,IAAA;AAAA,EAAA;AAGhB;AC5CO,SAASC,GACdjG,GAEA;;AACA,QAAM;AAAA,IACJ,cAAAiF;AAAA,IACA,eAAAC;AAAA,IACA,aAAAC;AAAA,IACA,QAAAC;AAAA,IACA,UAAAc,IAAW;AAAA,IACX,KAAAC;AAAA,IACA,KAAAC;AAAA,EAAA,IACEpG,GACE,EAAE,MAAAuE,EAAA,IAASvD,EAAA,GACXsE,IAAW1B,EAAgC,IAAI,GAG/C4B,MACHC,KAAAC,IAAAN,KAAA,gBAAAA,EAAQ,cAAR,gBAAAM,EAAA,KAAAN,OAAA,gBAAAK,EAAuB,eAAqC,QAMzD,CAACY,GAAOC,CAAQ,IAAIjE,EAAiB,MACrC4C,KAAgB,QAAQ,OAAO,MAAMA,CAAY,IAAU,KACxD,OAAOA,CAAY,CAC3B;AAED,EAAAM,EAAU,MAAM;AACd,UAAMvB,IAAKsB,EAAS;AACpB,IAAKtB,MACLA,EAAG,MAAA,GACHA,EAAG,OAAA;AAAA,EACL,GAAG,CAAA,CAAE;AAEL,WAASuC,EAAWC,GAA8B;;AAChD,QAAIA,EAAM,KAAA,EAAO,WAAW,EAAG,QAAO;AAGtC,UAAMC,IAAOlC,EAAK,YAAY,MACxBmC,IAAW,IAAI,KAAK,aAAaD,CAAI,EAAE,cAAc,OAAO,GAC5DE,MAAYjB,IAAAgB,EAAS,KAAK,CAACE,MAAMA,EAAE,SAAS,OAAO,MAAvC,gBAAAlB,EAA0C,UAAS,IAC/DmB,MACJpB,IAAAiB,EAAS,KAAK,CAACE,MAAMA,EAAE,SAAS,SAAS,MAAzC,gBAAAnB,EAA4C,UAAS,KACjDqB,IAAUN,EACb,QAAQ,IAAI,OAAO,KAAKG,CAAS,IAAI,GAAG,GAAG,EAAE,EAC7C,QAAQE,GAAa,GAAG,EACxB,QAAQ,YAAY,EAAE,GACnBjH,IAAI,OAAOkH,CAAO;AACxB,WAAO,OAAO,SAASlH,CAAC,IAAIA,IAAI;AAAA,EAClC;AAEA,WAASmH,EAAOP,GAAe;AAC7B,UAAMQ,IAAST,EAAWC,CAAK;AAC/B,QAAIQ,KAAU,MAAM;AAClB,MAAA9B,EAAc,IAAI;AAClB;AAAA,IACF;AAGA,QAAI+B,IAAUD;AACd,IAAI,OAAOb,KAAQ,iBAAoB,KAAK,IAAIA,GAAKc,CAAO,IACxD,OAAOb,KAAQ,iBAAoB,KAAK,IAAIA,GAAKa,CAAO;AAC5D,UAAMC,IAAS,MAAMhB;AACrB,IAAAhB,EAAc,KAAK,MAAM+B,IAAUC,CAAM,IAAIA,CAAM;AAAA,EACrD;AAEA,SACE,gBAAApH;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,KAAKwF;AAAA,MACL,MAAK;AAAA,MAIL,WAAU;AAAA,MACV,OAAOe;AAAA,MACP,cAAYb;AAAA,MACZ,UAAU,CAACG,MAAM;AACf,cAAMC,IAAOD,EAAE,OAAO;AACtB,QAAAW,EAASV,CAAI,GACbmB,EAAOnB,CAAI;AAAA,MACb;AAAA,MACA,WAAW,CAACD,MAAM;AAChB,QAAIA,EAAE,QAAQ,YACZA,EAAE,eAAA,GACFR,EAAA;AAAA,MAIJ;AAAA,MACA,WAAW;AAAA,QACT;AAAA,QACAU;AAAA;AAAA,QAEAC,EAAqB;AAAA,QACrBC,EAAmB;AAAA,QACnBC,EAAwB;AAAA,MAAA,EACxB,KAAK,GAAG;AAAA,IAAA;AAAA,EAAA;AAGhB;","x_google_ignoreList":[0,1]}
1
+ {"version":3,"file":"editable-currency-cell-renderer-Dus_sBvX.js","sources":["../../node_modules/lucide-react/dist/esm/icons/arrow-down.mjs","../../node_modules/lucide-react/dist/esm/icons/arrow-up.mjs","../../src/components/data-table/hooks/use-total-row.ts","../../src/components/data-table/cell-renderers/tooth-cell-renderer.tsx","../../src/components/data-table/cell-renderers/reorder-cell-renderer.tsx","../../src/components/data-table/cell-renderers/toggle-cell-renderer.tsx","../../src/components/data-table/cell-renderers/color-dot-cell-renderer.tsx","../../src/components/data-table/cell-renderers/balance-cell-renderer.tsx","../../src/components/data-table/cell-renderers/editable-text-cell-renderer.tsx","../../src/components/data-table/cell-renderers/editable-currency-cell-renderer.tsx"],"sourcesContent":["/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M12 5v14\", key: \"s699le\" }],\n [\"path\", { d: \"m19 12-7 7-7-7\", key: \"1idqje\" }]\n];\nconst ArrowDown = createLucideIcon(\"arrow-down\", __iconNode);\n\nexport { __iconNode, ArrowDown as default };\n//# sourceMappingURL=arrow-down.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"m5 12 7-7 7 7\", key: \"hav0vg\" }],\n [\"path\", { d: \"M12 19V5\", key: \"x0mq9r\" }]\n];\nconst ArrowUp = createLucideIcon(\"arrow-up\", __iconNode);\n\nexport { __iconNode, ArrowUp as default };\n//# sourceMappingURL=arrow-up.mjs.map\n","import { useMemo } from 'react';\n\n/**\n * Compute a pinned total row from a dataset and a list of numeric fields.\n *\n * The returned object is structurally a `TData` with non-summed fields left\n * `undefined` — plug it into `pinnedBottomRowData={[totalRow]}`. Cell renderers\n * in the non-summed columns receive `undefined`, so they should render nothing\n * (all of the DS cell renderers short-circuit on `null`/`undefined`).\n *\n * Pass an optional `labelField` + `labelValue` to show a static caption such\n * as \"Total\" in the first column of the pinned row.\n */\nexport function useTotalRow<TData>(\n rowData: TData[] | undefined,\n sumFields: Array<keyof TData & string>,\n options?: {\n labelField?: keyof TData & string;\n labelValue?: string;\n },\n): TData {\n return useMemo(() => {\n const row: Record<string, unknown> = {};\n\n for (const field of sumFields) {\n let total = 0;\n for (const r of rowData ?? []) {\n const raw = (r as Record<string, unknown>)[field];\n const n = typeof raw === 'number' ? raw : Number(raw);\n if (Number.isFinite(n)) total += n;\n }\n row[field] = total;\n }\n\n if (options?.labelField && options.labelValue !== undefined) {\n row[options.labelField] = options.labelValue;\n }\n\n return row as TData;\n }, [rowData, sumFields, options?.labelField, options?.labelValue]);\n}\n","import type { CustomCellRendererProps } from 'ag-grid-react';\nimport { Tag } from '../../tag/tag';\n\n// Tooth glyph — lucide ships no dental icon, so this is a small inline tooth\n// (a crown narrowing to two roots) tinted with `currentColor`, so it inherits\n// the Tag's text colour. Decorative; the FDI numbers are the accessible label.\nfunction ToothIcon() {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={1.75}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n className=\"ds:size-3.5\"\n >\n <path d=\"M12 5.5c-1.074 -1.426 -2.45 -2.2 -4 -2c-2.5 .323 -3.7 2.5 -3.5 5c.1 1.5 .5 3 .5 4.5c0 1.5 .5 3.5 1 5c.3 .9 .5 2 1.5 2s1.3 -1.5 1.5 -2.5c.2 -1 .5 -2 1.5 -2s1.3 1 1.5 2c.2 1 .5 2.5 1.5 2.5s1.2 -1.1 1.5 -2c.5 -1.5 1 -3.5 1 -5c0 -1.5 .4 -3 .5 -4.5c.2 -2.5 -1 -4.677 -3.5 -5c-1.55 -.2 -2.926 .574 -4 2z\" />\n </svg>\n );\n}\n\nexport interface ToothCellRendererParams {\n /** Max inline size of the chip before its label truncates (with a tooltip). */\n maxInlineSize?: string;\n}\n\n/**\n * Renders an array of tooth ids (FDI notation) as a single outlined Tag — the\n * teeth comma-separated and prefixed with a tooth glyph, so dentition reads at\n * a glance instead of as bare numbers.\n */\nexport function ToothCellRenderer(\n props: CustomCellRendererProps<unknown, string[]> & ToothCellRendererParams,\n) {\n const { value, maxInlineSize = '8rem' } = props;\n if (!Array.isArray(value) || value.length === 0) return null;\n\n return (\n <Tag\n label={value.join(', ')}\n size=\"sm\"\n fill=\"outline\"\n leading={<ToothIcon />}\n maxInlineSize={maxInlineSize}\n />\n );\n}\n","import type { CustomCellRendererProps } from 'ag-grid-react';\nimport { useTranslation } from 'react-i18next';\nimport { ArrowUp, ArrowDown } from 'lucide-react';\nimport { IconButton } from '../../button/icon-button';\nimport { IconButtonGroup } from '../../icon-button-group';\n\n/**\n * Keyboard-accessible row-reorder cell. AG Grid's native row dragging is\n * mouse/touch only; this renderer adds move-up / move-down buttons so the order\n * is reachable by keyboard too (the missing accessible half of the\n * \"drag-sortable column\" primitive). The consumer owns `rowData` order and\n * reorders it in `onMove` — the same controlled contract as the editable cells.\n */\nexport interface ReorderCellRendererParams<TData = unknown> {\n /** Move the row one step in the given direction (consumer reorders rowData). */\n onMove: (data: TData, direction: 'up' | 'down') => void;\n /** Accessible name for the move-up button (defaults to a kit string). */\n moveUpLabel?: string;\n /** Accessible name for the move-down button (defaults to a kit string). */\n moveDownLabel?: string;\n /** Button intent (default `ghost`). */\n intent?: 'ghost' | 'outline';\n /** Render the two buttons as a connected `IconButtonGroup` (default true). */\n group?: boolean;\n /**\n * Disable move-up on the first displayed row and move-down on the last\n * (default true). Turn off when the grid is filtered/sorted and the ends are\n * not meaningful.\n */\n disableAtEnds?: boolean;\n}\n\n/**\n * Pixel width a reorder column needs for the two `sm` IconButtons (32px each)\n * plus the data-table cell's inline padding so the controls never clip. Mirrors\n * {@link actionsColumnWidth}.\n */\nexport function reorderColumnWidth(): number {\n const SM_BUTTON = 32;\n const CELL_INSET = 26;\n return SM_BUTTON * 2 + CELL_INSET;\n}\n\nexport function ReorderCellRenderer<TData = unknown>(\n props: CustomCellRendererProps<TData> & ReorderCellRendererParams<TData>,\n) {\n const {\n data,\n node,\n api,\n onMove,\n moveUpLabel,\n moveDownLabel,\n intent = 'ghost',\n group = true,\n disableAtEnds = true,\n } = props;\n const { t } = useTranslation();\n if (!data) return null;\n\n const rowIndex = node.rowIndex ?? -1;\n const lastIndex = api.getDisplayedRowCount() - 1;\n const atFirst = disableAtEnds && rowIndex <= 0;\n const atLast = disableAtEnds && rowIndex >= lastIndex;\n\n const upLabel = moveUpLabel ?? t('dataTable.moveUp', 'Move up');\n const downLabel = moveDownLabel ?? t('dataTable.moveDown', 'Move down');\n\n // An ARRAY of IconButtons (not a Fragment): IconButtonGroup inspects its\n // direct children and rejects anything that isn't a DS IconButton.\n const buttons = [\n <IconButton\n key=\"up\"\n size=\"sm\"\n intent={intent}\n icon={<ArrowUp aria-hidden className=\"ds:size-4\" />}\n tooltip={upLabel}\n aria-label={upLabel}\n disabled={atFirst}\n onClick={(event) => {\n event.stopPropagation();\n onMove(data, 'up');\n }}\n />,\n <IconButton\n key=\"down\"\n size=\"sm\"\n intent={intent}\n icon={<ArrowDown aria-hidden className=\"ds:size-4\" />}\n tooltip={downLabel}\n aria-label={downLabel}\n disabled={atLast}\n onClick={(event) => {\n event.stopPropagation();\n onMove(data, 'down');\n }}\n />,\n ];\n\n return group ? (\n <IconButtonGroup\n aria-label={t('dataTable.reorder', 'Reorder row')}\n size=\"sm\"\n >\n {buttons}\n </IconButtonGroup>\n ) : (\n <span className=\"ds:inline-flex ds:items-center ds:gap-[var(--spacing-xs)]\">\n {buttons}\n </span>\n );\n}\n","import { useState, type ReactNode } from 'react';\nimport type { CustomCellRendererProps } from 'ag-grid-react';\nimport { CheckSquare, Square } from 'lucide-react';\nimport { useTranslation } from 'react-i18next';\n\nexport interface ToggleCellRendererParams<TData = unknown> {\n /**\n * Fires with the row and the new target value. May return a `Promise` —\n * if it rejects, the consumer is expected to revert the underlying value\n * and flash the row with `data-table-row-error` (return that row class\n * from `getRowClass`). Use `onError` below to be notified inside this\n * renderer.\n */\n onToggle: (data: TData, newValue: boolean) => void | Promise<void>;\n /**\n * Optional reject hook. Fires when the `onToggle` promise rejects, with\n * the row and the error. The button auto-disables during the in-flight\n * promise and re-enables on either settle.\n */\n onError?: (data: TData, error: unknown) => void;\n /** Icon shown when the current value is truthy. */\n trueIcon?: ReactNode;\n /** Icon shown when the current value is falsy. */\n falseIcon?: ReactNode;\n /** Extra classes applied to the \"on\" icon — defaults to success token. */\n trueClass?: string;\n /** Extra classes applied to the \"off\" icon. */\n falseClass?: string;\n /** Accessible label. Falls back to the default on/off announcements. */\n label?: string;\n}\n\nexport function ToggleCellRenderer<TData = unknown>(\n props: CustomCellRendererProps<TData, boolean> &\n ToggleCellRendererParams<TData>,\n) {\n const {\n value,\n data,\n onToggle,\n onError,\n trueIcon,\n falseIcon,\n trueClass = 'ds:text-[color:var(--success)]',\n falseClass = 'ds:text-[color:var(--muted-foreground)]',\n label,\n } = props;\n const { t } = useTranslation();\n const [pending, setPending] = useState(false);\n if (!data) return null;\n\n const isOn = Boolean(value);\n const icon = isOn\n ? (trueIcon ?? <CheckSquare aria-hidden className=\"ds:size-4\" />)\n : (falseIcon ?? <Square aria-hidden className=\"ds:size-4\" />);\n const stateClass = isOn ? trueClass : falseClass;\n const resolvedLabel =\n label ?? (isOn ? t('inputs.switch.on') : t('inputs.switch.off'));\n\n async function handleClick(event: React.MouseEvent) {\n event.stopPropagation();\n if (pending || !data) return;\n const next = !isOn;\n const result = onToggle(data, next);\n if (result && typeof (result as Promise<void>).then === 'function') {\n setPending(true);\n try {\n await result;\n } catch (err) {\n onError?.(data, err);\n } finally {\n setPending(false);\n }\n }\n }\n\n return (\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={isOn}\n aria-busy={pending}\n aria-label={resolvedLabel}\n disabled={pending}\n onClick={handleClick}\n className={[\n 'ds:inline-flex ds:items-center ds:justify-center',\n 'ds:min-h-[var(--min-target-size)] ds:min-w-[var(--min-target-size)]',\n 'ds:appearance-none ds:bg-transparent ds:p-[var(--spacing-xs)]',\n 'ds:rounded-[var(--radius-sm)]',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)]',\n 'ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[color:var(--ring)]',\n 'ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:disabled:opacity-50',\n stateClass,\n ].join(' ')}\n >\n {icon}\n </button>\n );\n}\n","import { useRef } from 'react';\nimport type { CustomCellRendererProps } from 'ag-grid-react';\nimport { useIsomorphicLayoutEffect } from '../../../hooks/use-isomorphic-layout-effect';\n\nexport interface ColorDotCellRendererParams {\n /** Field name on the row whose value holds the hex color. */\n colorField: string;\n /** Visual size of the dot. */\n size?: 'sm' | 'md' | 'lg';\n /** Optional label shown next to the dot. */\n labelField?: string;\n}\n\nconst SIZE_CLASS: Record<\n NonNullable<ColorDotCellRendererParams['size']>,\n string\n> = {\n sm: 'ds:size-[var(--icon-size-sm)]',\n md: 'ds:size-[var(--icon-size-md)]',\n lg: 'ds:size-[var(--icon-size-lg)]',\n};\n\nfunction readField(row: unknown, field: string): string | undefined {\n if (!row || typeof row !== 'object') return undefined;\n const value = (row as Record<string, unknown>)[field];\n return typeof value === 'string' ? value : undefined;\n}\n\n// Only accept trusted CSS color forms. Anything outside this allow-list\n// (including smuggled `url()` or extra declarations) is dropped so the\n// CSS custom-property writer can't be used to inject styles.\nconst HEX_RE = /^#(?:[0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i;\nconst RGB_RE = /^rgba?\\(\\s*[\\d.\\s,%/]+\\)$/i;\nconst HSL_RE = /^hsla?\\(\\s*[\\d.\\s,%/]+\\)$/i;\nconst CSS_VAR_RE = /^var\\(--[a-z0-9-]+(?:,\\s*[^)]+)?\\)$/i;\n\nfunction sanitizeColor(raw: string | undefined): string | undefined {\n if (!raw) return undefined;\n const v = raw.trim();\n if (\n HEX_RE.test(v) ||\n RGB_RE.test(v) ||\n HSL_RE.test(v) ||\n CSS_VAR_RE.test(v)\n ) {\n return v;\n }\n return undefined;\n}\n\nexport function ColorDotCellRenderer<TData = unknown>(\n props: CustomCellRendererProps<TData> & ColorDotCellRendererParams,\n) {\n const { data, colorField, size = 'md', labelField } = props;\n const dotRef = useRef<HTMLSpanElement | null>(null);\n const rawColor = data ? readField(data, colorField) : undefined;\n const color = sanitizeColor(rawColor);\n const label = data && labelField ? readField(data, labelField) : undefined;\n\n // Apply the dynamic color via a CSS custom property on the element.\n // Keeps hex/rgb literals out of JSX (constraint #2 and #4). The data\n // itself drives the color — constraints only forbid hardcoded colors\n // in component source, not in consumer row data.\n useIsomorphicLayoutEffect(() => {\n const el = dotRef.current;\n if (!el) return;\n if (color) {\n el.style.setProperty('--data-table-dot-color', color);\n } else {\n el.style.removeProperty('--data-table-dot-color');\n }\n }, [color]);\n\n if (!color) return null;\n\n return (\n <span className=\"ds:inline-flex ds:items-center ds:gap-[var(--spacing-sm)]\">\n <span\n ref={dotRef}\n aria-hidden=\"true\"\n className={[\n 'ds:inline-block ds:shrink-0 ds:rounded-[var(--radius-full)]',\n 'ds:bg-[var(--data-table-dot-color)]',\n 'ds:border ds:border-[color:var(--border)]',\n SIZE_CLASS[size],\n ].join(' ')}\n />\n {label ? <span>{label}</span> : null}\n </span>\n );\n}\n","import type { ColDef } from 'ag-grid-community';\nimport type { CustomCellRendererProps } from 'ag-grid-react';\nimport { useTranslation } from 'react-i18next';\n\nexport interface BalanceLine {\n /** User-visible label for this line. */\n label: string;\n /** Field name on the row whose numeric value is rendered. */\n valueField: string;\n /** `'currency'` renders via Intl, `'percent'` appends `%`, `'number'` raw. Default `'number'`. */\n format?: 'currency' | 'percent' | 'number';\n}\n\nexport interface BalanceCellRendererParams {\n lines: BalanceLine[];\n /** ISO 4217 code, used by `currency`-formatted lines. Default `'EUR'`. */\n currency?: string;\n /** Apply destructive color to negative values. */\n highlightNegative?: boolean;\n}\n\nfunction readNumber(row: unknown, field: string): number | null {\n if (!row || typeof row !== 'object') return null;\n const raw = (row as Record<string, unknown>)[field];\n const n = typeof raw === 'number' ? raw : Number(raw);\n return Number.isFinite(n) ? n : null;\n}\n\n/**\n * Renders a compact set of label / value pairs inside a single AG Grid cell.\n *\n * Layout is **horizontal** with middle-dot separators so the cell fits\n * inside the default AG Grid row height without spilling into the row\n * below. Use the SALDI / Listini patterns (Totale · Incassato · Da Incassare)\n * as the canonical example.\n *\n * If a consumer's content wraps (long localized labels, narrow columns)\n * they can opt into row auto-growth by spreading\n * {@link balanceCellRendererColDefDefaults} onto the column definition.\n */\nexport function BalanceCellRenderer<TData = unknown>(\n props: CustomCellRendererProps<TData> & BalanceCellRendererParams,\n) {\n const { data, lines, currency = 'EUR', highlightNegative } = props;\n const { i18n } = useTranslation();\n if (!data) return null;\n\n const locale = i18n.language || 'en';\n\n const formatLine = (\n line: BalanceLine,\n ): { label: string; formatted: string; negative: boolean } | null => {\n const n = readNumber(data, line.valueField);\n if (n === null) return null;\n\n let formatted: string;\n switch (line.format ?? 'number') {\n case 'currency':\n formatted = new Intl.NumberFormat(locale, {\n style: 'currency',\n currency,\n }).format(n);\n break;\n case 'percent':\n formatted = new Intl.NumberFormat(locale, {\n style: 'percent',\n maximumFractionDigits: 1,\n }).format(n / 100);\n break;\n default:\n formatted = new Intl.NumberFormat(locale).format(n);\n }\n\n return {\n label: line.label,\n formatted,\n negative: Boolean(highlightNegative) && n < 0,\n };\n };\n\n const rendered = lines\n .map(formatLine)\n .filter(\n (x): x is { label: string; formatted: string; negative: boolean } =>\n x !== null,\n );\n if (rendered.length === 0) return null;\n\n return (\n <div\n className={[\n 'ds:flex',\n 'ds:flex-wrap',\n 'ds:items-center',\n 'ds:gap-x-[var(--spacing-sm)]',\n 'ds:gap-y-0',\n 'type-meta',\n 'ds:leading-tight',\n ].join(' ')}\n >\n {rendered.map((item, idx) => (\n <span\n key={`${item.label}-${idx}`}\n className=\"ds:inline-flex ds:items-baseline ds:gap-x-[var(--spacing-xs)]\"\n >\n {idx > 0 ? (\n <span\n aria-hidden=\"true\"\n className=\"ds:me-[var(--spacing-xs)] ds:text-[color:var(--muted-foreground)]\"\n >\n ·\n </span>\n ) : null}\n <span className=\"ds:text-[color:var(--muted-foreground)]\">\n {item.label}\n </span>\n <span\n className={[\n 'ds:tabular-nums',\n 'ds:font-medium',\n item.negative ? 'ds:text-[color:var(--destructive)]' : '',\n ]\n .filter(Boolean)\n .join(' ')}\n >\n {item.formatted}\n </span>\n </span>\n ))}\n </div>\n );\n}\n\n/**\n * Column-definition defaults consumers can spread onto a `ColDef` when they\n * want the renderer's wrapped / multi-line behaviour to grow the row.\n *\n * The default compact horizontal layout is engineered to fit the standard\n * AG Grid row height, so this opt-in is only needed when a long label set\n * wraps across two or more lines and the consumer would rather grow the\n * row than wrap silently.\n *\n * AG Grid does NOT auto-grow row height to fit a tall cell unless\n * `autoHeight` and `wrapText` are set on the colDef itself — a cell\n * renderer can't impose that from inside.\n *\n * @example\n * ```ts\n * {\n * headerName: 'Saldi',\n * cellRenderer: BalanceCellRenderer,\n * cellRendererParams: { lines, currency: 'EUR' },\n * ...balanceCellRendererColDefDefaults,\n * }\n * ```\n */\nexport const balanceCellRendererColDefDefaults: Readonly<\n Pick<ColDef, 'autoHeight' | 'wrapText'>\n> = {\n autoHeight: true,\n wrapText: true,\n};\n","import { useEffect, useRef, useState } from 'react';\nimport type { CustomCellEditorProps } from 'ag-grid-react';\nimport {\n INPUT_SURFACE_CHROME,\n INPUT_SURFACE_HEIGHT,\n INPUT_SURFACE_PADDING_X,\n INPUT_SURFACE_TEXT,\n} from '../../_shared/input-surface';\n\n/**\n * Inline text editor that visually matches `<TextInput size=\"sm\">`. Use as\n * `cellEditor` on a colDef with `editable: true`. The cell renderer (default\n * or custom) takes over again once editing stops.\n *\n * AG Grid commits on Enter or Tab or blur; cancels on Escape. The consumer\n * receives the committed value via `onCellValueChanged`.\n */\nexport function EditableTextCellRenderer<TData = unknown>(\n props: CustomCellEditorProps<TData, string>,\n) {\n const { initialValue, onValueChange, stopEditing, column } = props;\n const [value, setValue] = useState<string>(initialValue ?? '');\n const inputRef = useRef<HTMLInputElement | null>(null);\n\n // Focus + select on mount so typing replaces the current value.\n useEffect(() => {\n const el = inputRef.current;\n if (!el) return;\n el.focus();\n el.select();\n }, []);\n\n // The current value is pushed to AG Grid via `onValueChange` on every\n // keystroke — AG Grid commits the most recent value when editing stops.\n // No `useGridCellEditor` hook needed for that contract.\n\n // Thread the column header into the input's accessible name so screen\n // readers announce \"Edit text, {column}\" instead of an unlabelled input.\n // AG Grid doesn't auto-wire the column header to cell editors.\n const headerName =\n (column?.getColDef?.()?.headerName as string | undefined) ?? undefined;\n\n return (\n <input\n ref={inputRef}\n type=\"text\"\n value={value}\n aria-label={headerName}\n onChange={(e) => {\n const next = e.target.value;\n setValue(next);\n onValueChange(next);\n }}\n onKeyDown={(e) => {\n // Escape cancels, Enter/Tab commit — AG Grid handles both, but we\n // explicitly stop editing on Enter so the consumer sees the commit\n // immediately rather than waiting for the next focus blur.\n if (e.key === 'Enter') {\n e.preventDefault();\n stopEditing();\n }\n }}\n className={[\n 'ds:block ds:w-full ds:appearance-none',\n // Input surface chrome: rounded border + bg + focus halo.\n INPUT_SURFACE_CHROME,\n // Use the `md` height (`--min-target-size`) so the input\n // auto-lifts to 48px under `.theme-accessible` to satisfy\n // WCAG 2.5.5 target size.\n INPUT_SURFACE_HEIGHT.md,\n INPUT_SURFACE_TEXT.sm,\n INPUT_SURFACE_PADDING_X.sm,\n ].join(' ')}\n />\n );\n}\n","import { useEffect, useRef, useState } from 'react';\nimport type { CustomCellEditorProps } from 'ag-grid-react';\nimport { useTranslation } from 'react-i18next';\nimport {\n INPUT_SURFACE_CHROME,\n INPUT_SURFACE_HEIGHT,\n INPUT_SURFACE_PADDING_X,\n INPUT_SURFACE_TEXT,\n} from '../../_shared/input-surface';\n\nexport interface EditableCurrencyCellEditorParams {\n /** ISO 4217 currency code (e.g. `EUR`, `USD`). Defaults to `EUR`. */\n currency?: string;\n /** Decimal places allowed in the editor. Defaults to 2 (cents precision). */\n decimals?: number;\n /** Minimum allowed value — values below this are clamped on commit. */\n min?: number;\n /** Maximum allowed value — values above this are clamped on commit. */\n max?: number;\n}\n\n/**\n * Inline numeric editor that visually matches `<TextInput size=\"sm\">`. Use as\n * `cellEditor` on a colDef with `editable: true`. The display formatting is\n * still the renderer's job — once editing stops, the cell hands back to\n * `CurrencyCellRenderer` (or whichever renderer the colDef declares).\n *\n * Stores a Number, not a string, so consumers receive `row.amount = 12.5`\n * not `\"12.5\"`. Strips locale separators on each change so commas/dots in\n * any language convert to a clean numeric value.\n */\nexport function EditableCurrencyCellRenderer<TData = unknown>(\n props: CustomCellEditorProps<TData, number> &\n EditableCurrencyCellEditorParams,\n) {\n const {\n initialValue,\n onValueChange,\n stopEditing,\n column,\n decimals = 2,\n min,\n max,\n } = props;\n const { i18n } = useTranslation();\n const inputRef = useRef<HTMLInputElement | null>(null);\n // Thread the column header into the input's accessible name — see\n // editable-text-cell-renderer.tsx for the rationale.\n const headerName =\n (column?.getColDef?.()?.headerName as string | undefined) ?? undefined;\n\n // Local string state so the user can type intermediate values like \"12.\"\n // before the trailing zero arrives. We commit a Number to AG Grid on each\n // change for consumers that watch row state live; the final commit fires\n // when editing stops.\n const [draft, setDraft] = useState<string>(() => {\n if (initialValue == null || Number.isNaN(initialValue)) return '';\n return String(initialValue);\n });\n\n useEffect(() => {\n const el = inputRef.current;\n if (!el) return;\n el.focus();\n el.select();\n }, []);\n\n function parseDraft(input: string): number | null {\n if (input.trim().length === 0) return null;\n // Accept either the user's locale decimal separator or a `.`. Strip\n // grouping characters (locale thousands separators, plus spaces).\n const lang = i18n.language || 'en';\n const partsFmt = new Intl.NumberFormat(lang).formatToParts(12345.6);\n const groupChar = partsFmt.find((p) => p.type === 'group')?.value ?? '';\n const decimalChar =\n partsFmt.find((p) => p.type === 'decimal')?.value ?? '.';\n const cleaned = input\n .replace(new RegExp(`\\\\${groupChar}`, 'g'), '')\n .replace(decimalChar, '.')\n .replace(/[^\\d.-]/g, '');\n const n = Number(cleaned);\n return Number.isFinite(n) ? n : null;\n }\n\n function commit(input: string) {\n const parsed = parseDraft(input);\n if (parsed == null) {\n onValueChange(null);\n return;\n }\n // Clamp first, then round to the declared precision so we never\n // persist floating-point dust from string parsing.\n let clamped = parsed;\n if (typeof min === 'number') clamped = Math.max(min, clamped);\n if (typeof max === 'number') clamped = Math.min(max, clamped);\n const factor = 10 ** decimals;\n onValueChange(Math.round(clamped * factor) / factor);\n }\n\n return (\n <input\n ref={inputRef}\n type=\"text\"\n // Inputmode hints mobile keyboards to show the decimal pad instead\n // of the full keyboard. type=\"number\" would also work but spinners\n // and locale parsing are inconsistent across browsers.\n inputMode=\"decimal\"\n value={draft}\n aria-label={headerName}\n onChange={(e) => {\n const next = e.target.value;\n setDraft(next);\n commit(next);\n }}\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n stopEditing();\n }\n // Escape — AG Grid cancels by default; the editor doesn't need\n // explicit handling beyond what AG Grid wires automatically.\n }}\n className={[\n 'ds:block ds:w-full ds:appearance-none ds:text-end ds:tabular-nums',\n INPUT_SURFACE_CHROME,\n // Use `md` height — see editable-text-cell-renderer for rationale.\n INPUT_SURFACE_HEIGHT.md,\n INPUT_SURFACE_TEXT.sm,\n INPUT_SURFACE_PADDING_X.sm,\n ].join(' ')}\n />\n );\n}\n"],"names":["__iconNode","ArrowDown","createLucideIcon","ArrowUp","useTotalRow","rowData","sumFields","options","useMemo","row","field","total","r","raw","n","ToothIcon","jsx","ToothCellRenderer","props","value","maxInlineSize","Tag","reorderColumnWidth","ReorderCellRenderer","data","node","api","onMove","moveUpLabel","moveDownLabel","intent","group","disableAtEnds","t","useTranslation","rowIndex","lastIndex","atFirst","atLast","upLabel","downLabel","buttons","IconButton","event","IconButtonGroup","ToggleCellRenderer","onToggle","onError","trueIcon","falseIcon","trueClass","falseClass","label","pending","setPending","useState","isOn","icon","CheckSquare","Square","stateClass","resolvedLabel","handleClick","result","err","SIZE_CLASS","readField","HEX_RE","RGB_RE","HSL_RE","CSS_VAR_RE","sanitizeColor","v","ColorDotCellRenderer","colorField","size","labelField","dotRef","useRef","rawColor","color","useIsomorphicLayoutEffect","el","jsxs","readNumber","BalanceCellRenderer","lines","currency","highlightNegative","i18n","locale","formatLine","line","formatted","rendered","x","item","idx","EditableTextCellRenderer","initialValue","onValueChange","stopEditing","column","setValue","inputRef","useEffect","headerName","_b","_a","e","next","INPUT_SURFACE_CHROME","INPUT_SURFACE_HEIGHT","INPUT_SURFACE_TEXT","INPUT_SURFACE_PADDING_X","EditableCurrencyCellRenderer","decimals","min","max","draft","setDraft","parseDraft","input","lang","partsFmt","groupChar","p","decimalChar","cleaned","commit","parsed","clamped","factor"],"mappings":"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","x_google_ignoreList":[0,1]}
@@ -9,7 +9,7 @@ import { B as P } from "./button-CPGiR_bH.js";
9
9
  import { I as Ze } from "./icon-button-C_kbcd7I.js";
10
10
  import { B as es } from "./button-group-DzV5wgnx.js";
11
11
  import { C as ts } from "./combobox-DiMLItyu.js";
12
- import { I as vn } from "./icon-button-group-C_lqXTAj.js";
12
+ import { I as vn } from "./icon-button-group-BLHPN6jg.js";
13
13
  import { T as Ar } from "./text-input-CUvCb6ST.js";
14
14
  import { C as Oe } from "./card-DPmk26CL.js";
15
15
  import { S as Tt } from "./separator-CYU_bGFn.js";
@@ -3143,4 +3143,4 @@ export {
3143
3143
  Nn as t,
3144
3144
  Kr as u
3145
3145
  };
3146
- //# sourceMappingURL=face-scheme-C0rk21gg.js.map
3146
+ //# sourceMappingURL=face-scheme-CjQAHvSP.js.map