@alfadocs/ui-kit-debug 1.7.0 → 1.8.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 (234) hide show
  1. package/dist/_chunks/{anamnesis-summary-rows-F-cCmFAn.js → anamnesis-summary-rows-d44s_whc.js} +2 -2
  2. package/dist/_chunks/{anamnesis-summary-rows-F-cCmFAn.js.map → anamnesis-summary-rows-d44s_whc.js.map} +1 -1
  3. package/dist/_chunks/{antenatal-schedule-timeline-BjlF2rTz.js → antenatal-schedule-timeline-B1k8QkA6.js} +3 -3
  4. package/dist/_chunks/{antenatal-schedule-timeline-BjlF2rTz.js.map → antenatal-schedule-timeline-B1k8QkA6.js.map} +1 -1
  5. package/dist/_chunks/{appointment-card-BhcPJpXh.js → appointment-card-Dzr3GeVz.js} +73 -90
  6. package/dist/_chunks/appointment-card-Dzr3GeVz.js.map +1 -0
  7. package/dist/_chunks/{appointment-timeline-CMPvzlGZ.js → appointment-timeline-0mwtpErq.js} +3 -3
  8. package/dist/_chunks/{appointment-timeline-CMPvzlGZ.js.map → appointment-timeline-0mwtpErq.js.map} +1 -1
  9. package/dist/_chunks/{appointment-tray-3c_FLxXJ.js → appointment-tray-4FUu_5NX.js} +2 -2
  10. package/dist/_chunks/{appointment-tray-3c_FLxXJ.js.map → appointment-tray-4FUu_5NX.js.map} +1 -1
  11. package/dist/_chunks/armchair-BaLDW6Hz.js +23 -0
  12. package/dist/_chunks/armchair-BaLDW6Hz.js.map +1 -0
  13. package/dist/_chunks/{booking-CQMJUFG-.js → booking-DHkKcUIl.js} +4 -4
  14. package/dist/_chunks/{booking-CQMJUFG-.js.map → booking-DHkKcUIl.js.map} +1 -1
  15. package/dist/_chunks/{calendar-4dXTvsCz.js → calendar-B4Gnyu1C.js} +553 -437
  16. package/dist/_chunks/calendar-B4Gnyu1C.js.map +1 -0
  17. package/dist/_chunks/calendar-event-card-Bjdbik8G.js +425 -0
  18. package/dist/_chunks/calendar-event-card-Bjdbik8G.js.map +1 -0
  19. package/dist/_chunks/{care-plan-card-DQjVRDxO.js → care-plan-card-aDN4oem9.js} +3 -3
  20. package/dist/_chunks/{care-plan-card-DQjVRDxO.js.map → care-plan-card-aDN4oem9.js.map} +1 -1
  21. package/dist/_chunks/{care-plan-entry-card-CMpoeNkb.js → care-plan-entry-card-BEhANdBE.js} +2 -2
  22. package/dist/_chunks/{care-plan-entry-card-CMpoeNkb.js.map → care-plan-entry-card-BEhANdBE.js.map} +1 -1
  23. package/dist/_chunks/{care-plan-header-CxYoq23f.js → care-plan-header-CkpPyQqG.js} +2 -2
  24. package/dist/_chunks/{care-plan-header-CxYoq23f.js.map → care-plan-header-CkpPyQqG.js.map} +1 -1
  25. package/dist/_chunks/{color-picker-D-tUwxxT.js → color-picker-oZ6zYks8.js} +164 -151
  26. package/dist/_chunks/color-picker-oZ6zYks8.js.map +1 -0
  27. package/dist/_chunks/control-room-rail-Cj2iX9h_.js +337 -0
  28. package/dist/_chunks/control-room-rail-Cj2iX9h_.js.map +1 -0
  29. package/dist/_chunks/{cycle-calculator-DzgO1vzP.js → cycle-calculator-DmtYGhqq.js} +3 -3
  30. package/dist/_chunks/{cycle-calculator-DzgO1vzP.js.map → cycle-calculator-DmtYGhqq.js.map} +1 -1
  31. package/dist/_chunks/{date-picker-Bp64zk2p.js → date-picker-CepI_oI2.js} +77 -74
  32. package/dist/_chunks/date-picker-CepI_oI2.js.map +1 -0
  33. package/dist/_chunks/{date-picker-variants-pKAJfnWr.js → date-picker-variants-DfuooXEK.js} +7 -2
  34. package/dist/_chunks/{date-picker-variants-pKAJfnWr.js.map → date-picker-variants-DfuooXEK.js.map} +1 -1
  35. package/dist/_chunks/{date-range-picker-CDrZ8Zh0.js → date-range-picker-BD8P_rJq.js} +46 -45
  36. package/dist/_chunks/{date-range-picker-CDrZ8Zh0.js.map → date-range-picker-BD8P_rJq.js.map} +1 -1
  37. package/dist/_chunks/{date-time-picker-DVETwpzc.js → date-time-picker-3I2vVKGV.js} +2 -2
  38. package/dist/_chunks/{date-time-picker-DVETwpzc.js.map → date-time-picker-3I2vVKGV.js.map} +1 -1
  39. package/dist/_chunks/{due-date-calculator-wK8Tajzz.js → due-date-calculator-BF_Ikofx.js} +4 -4
  40. package/dist/_chunks/{due-date-calculator-wK8Tajzz.js.map → due-date-calculator-BF_Ikofx.js.map} +1 -1
  41. package/dist/_chunks/{entity-card-9_62gY7l.js → entity-card-DmrgYSEX.js} +4 -4
  42. package/dist/_chunks/{entity-card-9_62gY7l.js.map → entity-card-DmrgYSEX.js.map} +1 -1
  43. package/dist/_chunks/{gestational-age-calculator-C_uDAeP_.js → gestational-age-calculator-CxZelpu2.js} +5 -5
  44. package/dist/_chunks/{gestational-age-calculator-C_uDAeP_.js.map → gestational-age-calculator-CxZelpu2.js.map} +1 -1
  45. package/dist/_chunks/{hcg-doubling-BaXkJhT-.js → hcg-doubling-CpU7H5rQ.js} +3 -3
  46. package/dist/_chunks/{hcg-doubling-BaXkJhT-.js.map → hcg-doubling-CpU7H5rQ.js.map} +1 -1
  47. package/dist/_chunks/{link-cell-renderer-DH4JYpKU.js → link-cell-renderer-BZQtsuFz.js} +2 -2
  48. package/dist/_chunks/{link-cell-renderer-DH4JYpKU.js.map → link-cell-renderer-BZQtsuFz.js.map} +1 -1
  49. package/dist/_chunks/{notes-panel-DlnENphf.js → notes-panel-e9cJWVRg.js} +2 -2
  50. package/dist/_chunks/{notes-panel-DlnENphf.js.map → notes-panel-e9cJWVRg.js.map} +1 -1
  51. package/dist/_chunks/{operator-hero-CCDnIa1S.js → operator-hero-BnFv-Uef.js} +2 -2
  52. package/dist/_chunks/{operator-hero-CCDnIa1S.js.map → operator-hero-BnFv-Uef.js.map} +1 -1
  53. package/dist/_chunks/{parse-JqixfsU0.js → parse-MN9bGkrY.js} +2 -2
  54. package/dist/_chunks/{parse-JqixfsU0.js.map → parse-MN9bGkrY.js.map} +1 -1
  55. package/dist/_chunks/{patient-details-qnsqYBGQ.js → patient-details-xrqe13az.js} +160 -159
  56. package/dist/_chunks/patient-details-xrqe13az.js.map +1 -0
  57. package/dist/_chunks/{patient-table-DwshfVsQ.js → patient-table-BqYomX50.js} +2 -2
  58. package/dist/_chunks/{patient-table-DwshfVsQ.js.map → patient-table-BqYomX50.js.map} +1 -1
  59. package/dist/_chunks/{payment-automation-upsell-BBIG7NFL.js → payment-automation-upsell-DwQW2fRp.js} +52 -63
  60. package/dist/_chunks/payment-automation-upsell-DwQW2fRp.js.map +1 -0
  61. package/dist/_chunks/{payment-request-card-BjjBMdsp.js → payment-request-card-YVCcCZ25.js} +2 -2
  62. package/dist/_chunks/{payment-request-card-BjjBMdsp.js.map → payment-request-card-YVCcCZ25.js.map} +1 -1
  63. package/dist/_chunks/{pregnancy-dating-BVS_9YU2.js → pregnancy-dating-DtToyMyc.js} +5 -5
  64. package/dist/_chunks/{pregnancy-dating-BVS_9YU2.js.map → pregnancy-dating-DtToyMyc.js.map} +1 -1
  65. package/dist/_chunks/{radiograph-panel.agent-CiHwgISa.js → radiograph-panel.agent-C3trfWqB.js} +3 -3
  66. package/dist/_chunks/{radiograph-panel.agent-CiHwgISa.js.map → radiograph-panel.agent-C3trfWqB.js.map} +1 -1
  67. package/dist/_chunks/repeat-CvQa5rZt.js +17 -0
  68. package/dist/_chunks/repeat-CvQa5rZt.js.map +1 -0
  69. package/dist/_chunks/resource-chip-DYTG0IQQ.js +83 -0
  70. package/dist/_chunks/resource-chip-DYTG0IQQ.js.map +1 -0
  71. package/dist/_chunks/{rich-text-editor-DARnq_6N.js → rich-text-editor-BDfFtK4H.js} +2 -2
  72. package/dist/_chunks/{rich-text-editor-DARnq_6N.js.map → rich-text-editor-BDfFtK4H.js.map} +1 -1
  73. package/dist/_chunks/subDays-BLl3y3pd.js +8 -0
  74. package/dist/_chunks/{subDays-CAUv47M1.js.map → subDays-BLl3y3pd.js.map} +1 -1
  75. package/dist/agent-catalog.json +2 -2
  76. package/dist/components/_shared/date-picker-variants.d.ts.map +1 -1
  77. package/dist/components/appointment-card/index.js +2 -2
  78. package/dist/components/appointment-timeline/index.js +1 -1
  79. package/dist/components/booking/index.js +1 -1
  80. package/dist/components/calendar/calendar.agent.d.ts.map +1 -1
  81. package/dist/components/calendar/calendar.d.ts +138 -12
  82. package/dist/components/calendar/calendar.d.ts.map +1 -1
  83. package/dist/components/calendar/index.js +1 -1
  84. package/dist/components/calendar-event-card/calendar-event-card.d.ts +48 -11
  85. package/dist/components/calendar-event-card/calendar-event-card.d.ts.map +1 -1
  86. package/dist/components/calendar-event-card/index.js +1 -1
  87. package/dist/components/care-plan-card/index.js +1 -1
  88. package/dist/components/care-plan-entry-card/index.js +1 -1
  89. package/dist/components/care-plan-header/index.js +1 -1
  90. package/dist/components/color-picker/index.d.ts +1 -1
  91. package/dist/components/color-picker/index.d.ts.map +1 -1
  92. package/dist/components/color-picker/index.js +4 -3
  93. package/dist/components/color-picker/palettes.d.ts +10 -0
  94. package/dist/components/color-picker/palettes.d.ts.map +1 -1
  95. package/dist/components/control-room-rail/control-room-rail.d.ts +9 -0
  96. package/dist/components/control-room-rail/control-room-rail.d.ts.map +1 -1
  97. package/dist/components/control-room-rail/index.js +1 -1
  98. package/dist/components/cycle-calculator/index.js +1 -1
  99. package/dist/components/data-table/index.js +1 -1
  100. package/dist/components/date-picker/date-picker.d.ts +11 -0
  101. package/dist/components/date-picker/date-picker.d.ts.map +1 -1
  102. package/dist/components/date-picker/index.js +1 -1
  103. package/dist/components/date-range-picker/date-range-picker.d.ts.map +1 -1
  104. package/dist/components/date-range-picker/index.js +1 -1
  105. package/dist/components/date-time-picker/index.js +1 -1
  106. package/dist/components/due-date-calculator/index.js +2 -2
  107. package/dist/components/gestational-age-calculator/index.js +1 -1
  108. package/dist/components/hcg-doubling/index.js +1 -1
  109. package/dist/components/index.d.ts +1 -0
  110. package/dist/components/index.d.ts.map +1 -1
  111. package/dist/components/notes-panel/index.js +1 -1
  112. package/dist/components/operator-hero/index.js +1 -1
  113. package/dist/components/patient-details/index.js +1 -1
  114. package/dist/components/patient-details/patient-details.d.ts +8 -0
  115. package/dist/components/patient-details/patient-details.d.ts.map +1 -1
  116. package/dist/components/patient-table/index.js +1 -1
  117. package/dist/components/payment-card/index.js +1 -1
  118. package/dist/components/pregnancy-dating/index.js +1 -1
  119. package/dist/components/radiograph-panel/index.js +1 -1
  120. package/dist/components/resource-chip/index.d.ts +3 -0
  121. package/dist/components/resource-chip/index.d.ts.map +1 -0
  122. package/dist/components/resource-chip/index.js +5 -0
  123. package/dist/components/resource-chip/index.js.map +1 -0
  124. package/dist/components/resource-chip/resource-chip.d.ts +26 -0
  125. package/dist/components/resource-chip/resource-chip.d.ts.map +1 -0
  126. package/dist/components/rich-text-editor/index.js +1 -1
  127. package/dist/host-compat.css +7 -1
  128. package/dist/i18n/locales/ar.d.ts +4 -0
  129. package/dist/i18n/locales/ar.d.ts.map +1 -1
  130. package/dist/i18n/locales/ar.js +4 -0
  131. package/dist/i18n/locales/ar.js.map +1 -1
  132. package/dist/i18n/locales/de.d.ts +4 -0
  133. package/dist/i18n/locales/de.d.ts.map +1 -1
  134. package/dist/i18n/locales/de.js +4 -0
  135. package/dist/i18n/locales/de.js.map +1 -1
  136. package/dist/i18n/locales/el.d.ts +4 -0
  137. package/dist/i18n/locales/el.d.ts.map +1 -1
  138. package/dist/i18n/locales/el.js +4 -0
  139. package/dist/i18n/locales/el.js.map +1 -1
  140. package/dist/i18n/locales/en.d.ts +4 -0
  141. package/dist/i18n/locales/en.d.ts.map +1 -1
  142. package/dist/i18n/locales/en.js +4 -0
  143. package/dist/i18n/locales/en.js.map +1 -1
  144. package/dist/i18n/locales/es.d.ts +4 -0
  145. package/dist/i18n/locales/es.d.ts.map +1 -1
  146. package/dist/i18n/locales/es.js +4 -0
  147. package/dist/i18n/locales/es.js.map +1 -1
  148. package/dist/i18n/locales/fr.d.ts +4 -0
  149. package/dist/i18n/locales/fr.d.ts.map +1 -1
  150. package/dist/i18n/locales/fr.js +4 -0
  151. package/dist/i18n/locales/fr.js.map +1 -1
  152. package/dist/i18n/locales/hi.d.ts +4 -0
  153. package/dist/i18n/locales/hi.d.ts.map +1 -1
  154. package/dist/i18n/locales/hi.js +4 -0
  155. package/dist/i18n/locales/hi.js.map +1 -1
  156. package/dist/i18n/locales/it.d.ts +4 -0
  157. package/dist/i18n/locales/it.d.ts.map +1 -1
  158. package/dist/i18n/locales/it.js +4 -0
  159. package/dist/i18n/locales/it.js.map +1 -1
  160. package/dist/i18n/locales/ja.d.ts +4 -0
  161. package/dist/i18n/locales/ja.d.ts.map +1 -1
  162. package/dist/i18n/locales/ja.js +4 -0
  163. package/dist/i18n/locales/ja.js.map +1 -1
  164. package/dist/i18n/locales/nl.d.ts +4 -0
  165. package/dist/i18n/locales/nl.d.ts.map +1 -1
  166. package/dist/i18n/locales/nl.js +4 -0
  167. package/dist/i18n/locales/nl.js.map +1 -1
  168. package/dist/i18n/locales/pl.d.ts +4 -0
  169. package/dist/i18n/locales/pl.d.ts.map +1 -1
  170. package/dist/i18n/locales/pl.js +4 -0
  171. package/dist/i18n/locales/pl.js.map +1 -1
  172. package/dist/i18n/locales/pt.d.ts +4 -0
  173. package/dist/i18n/locales/pt.d.ts.map +1 -1
  174. package/dist/i18n/locales/pt.js +4 -0
  175. package/dist/i18n/locales/pt.js.map +1 -1
  176. package/dist/i18n/locales/ro.d.ts +4 -0
  177. package/dist/i18n/locales/ro.d.ts.map +1 -1
  178. package/dist/i18n/locales/ro.js +4 -0
  179. package/dist/i18n/locales/ro.js.map +1 -1
  180. package/dist/i18n/locales/ru.d.ts +4 -0
  181. package/dist/i18n/locales/ru.d.ts.map +1 -1
  182. package/dist/i18n/locales/ru.js +4 -0
  183. package/dist/i18n/locales/ru.js.map +1 -1
  184. package/dist/i18n/locales/sq.d.ts +4 -0
  185. package/dist/i18n/locales/sq.d.ts.map +1 -1
  186. package/dist/i18n/locales/sq.js +4 -0
  187. package/dist/i18n/locales/sq.js.map +1 -1
  188. package/dist/i18n/locales/sv.d.ts +4 -0
  189. package/dist/i18n/locales/sv.d.ts.map +1 -1
  190. package/dist/i18n/locales/sv.js +4 -0
  191. package/dist/i18n/locales/sv.js.map +1 -1
  192. package/dist/i18n/locales/tr.d.ts +4 -0
  193. package/dist/i18n/locales/tr.d.ts.map +1 -1
  194. package/dist/i18n/locales/tr.js +4 -0
  195. package/dist/i18n/locales/tr.js.map +1 -1
  196. package/dist/i18n/locales/zh.d.ts +4 -0
  197. package/dist/i18n/locales/zh.d.ts.map +1 -1
  198. package/dist/i18n/locales/zh.js +4 -0
  199. package/dist/i18n/locales/zh.js.map +1 -1
  200. package/dist/index.js +961 -958
  201. package/dist/index.js.map +1 -1
  202. package/dist/locales/ar.json +4 -0
  203. package/dist/locales/de.json +4 -0
  204. package/dist/locales/el.json +4 -0
  205. package/dist/locales/en.json +4 -0
  206. package/dist/locales/es.json +4 -0
  207. package/dist/locales/fr.json +4 -0
  208. package/dist/locales/hi.json +4 -0
  209. package/dist/locales/it.json +4 -0
  210. package/dist/locales/ja.json +4 -0
  211. package/dist/locales/nl.json +4 -0
  212. package/dist/locales/pl.json +4 -0
  213. package/dist/locales/pt.json +4 -0
  214. package/dist/locales/ro.json +4 -0
  215. package/dist/locales/ru.json +4 -0
  216. package/dist/locales/sq.json +4 -0
  217. package/dist/locales/sv.json +4 -0
  218. package/dist/locales/tr.json +4 -0
  219. package/dist/locales/zh.json +4 -0
  220. package/dist/patterns/anamnesis/index.js +1 -1
  221. package/dist/patterns/payment-automation-upsell/index.js +1 -1
  222. package/dist/tokens.css +40 -24
  223. package/package.json +5 -1
  224. package/dist/_chunks/appointment-card-BhcPJpXh.js.map +0 -1
  225. package/dist/_chunks/calendar-4dXTvsCz.js.map +0 -1
  226. package/dist/_chunks/calendar-event-card-C6qGtywL.js +0 -257
  227. package/dist/_chunks/calendar-event-card-C6qGtywL.js.map +0 -1
  228. package/dist/_chunks/color-picker-D-tUwxxT.js.map +0 -1
  229. package/dist/_chunks/control-room-rail-IH1eBjrK.js +0 -333
  230. package/dist/_chunks/control-room-rail-IH1eBjrK.js.map +0 -1
  231. package/dist/_chunks/date-picker-Bp64zk2p.js.map +0 -1
  232. package/dist/_chunks/patient-details-qnsqYBGQ.js.map +0 -1
  233. package/dist/_chunks/payment-automation-upsell-BBIG7NFL.js.map +0 -1
  234. package/dist/_chunks/subDays-CAUv47M1.js +0 -8
@@ -0,0 +1 @@
1
+ {"version":3,"file":"color-picker-oZ6zYks8.js","sources":["../../src/components/color-picker/color-picker.agent.ts","../../src/components/color-picker/color-utils.ts","../../src/components/color-picker/palettes.ts","../../src/components/color-picker/color-picker.tsx"],"sourcesContent":["/* -------------------------------------------------------------------- */\n/* Agent adapter — ColorPicker. */\n/* */\n/* See `src/docs/26-agent-readiness.mdx` for the contract. */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\nimport type { ColorPickerHandle } from './color-picker';\n\nexport const colorPickerAgent: AgentAdapter<ColorPickerHandle> = {\n id: 'color-picker',\n capabilities: ['set_value'],\n state: {\n value: {\n type: 'string',\n descriptionKey: 'ui.agent.colorPicker.state.value',\n description: 'Currently picked colour as a hex string (e.g. \"#3b82f6\").',\n read: (handle) => handle.getValue(),\n },\n },\n actions: {\n set_value: {\n safety: 'write',\n argsType: '{ hex: string }',\n argsSchema: {\n type: 'object',\n properties: {\n hex: {\n type: 'string',\n description: 'Hex colour string, e.g. \"#3b82f6\".',\n },\n },\n required: ['hex'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.colorPicker.actions.setValue',\n description: 'Set the picked colour from a hex string.',\n examples: [{ args: { hex: '#3b82f6' }, note: 'Set to brand blue.' }],\n invoke: (handle, args: { hex: string }) => {\n handle.setValue(args.hex);\n },\n },\n },\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'color-picker',\n description:\n 'Marks the ColorPicker wrapper (inline) or trigger (popover variant).',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description: 'Sourced from the id prop.',\n },\n },\n};\n","/**\n * Pure colour-conversion utilities for the ColorPicker component.\n *\n * This is the ONLY file where hex/rgb literals are permitted (for conversion\n * math). The component file (`color-picker.tsx`) must not contain hex/rgb\n * literals — it references `var(--…)` tokens for its own UI.\n */\n\nexport interface HSLA {\n h: number; // 0–360\n s: number; // 0–100\n l: number; // 0–100\n a: number; // 0–1\n}\n\n/* ------------------------------------------------------------------ */\n/* Hex ↔ HSL */\n/* ------------------------------------------------------------------ */\n\n/** Parse a hex string (#rgb, #rrggbb, #rrggbbaa) into HSLA. */\nexport function hexToHsl(hex: string): HSLA {\n let h = hex.startsWith('#') ? hex.slice(1) : hex;\n\n // Expand shorthand (#rgb → #rrggbb, #rgba → #rrggbbaa)\n if (h.length === 3 || h.length === 4) {\n h = h\n .split('')\n .map((c) => c + c)\n .join('');\n }\n\n const r = parseInt(h.slice(0, 2), 16) / 255;\n const g = parseInt(h.slice(2, 4), 16) / 255;\n const b = parseInt(h.slice(4, 6), 16) / 255;\n const a = h.length === 8 ? parseInt(h.slice(6, 8), 16) / 255 : 1;\n\n return rgbToHsl(r, g, b, a);\n}\n\n/** Convert normalised RGB (0–1) + alpha to HSLA. */\nfunction rgbToHsl(r: number, g: number, b: number, a: number): HSLA {\n const max = Math.max(r, g, b);\n const min = Math.min(r, g, b);\n const l = (max + min) / 2;\n let hue = 0;\n let sat = 0;\n\n if (max !== min) {\n const d = max - min;\n sat = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n\n if (max === r) {\n hue = ((g - b) / d + (g < b ? 6 : 0)) / 6;\n } else if (max === g) {\n hue = ((b - r) / d + 2) / 6;\n } else {\n hue = ((r - g) / d + 4) / 6;\n }\n }\n\n return {\n h: Math.round(hue * 360),\n s: Math.round(sat * 100),\n l: Math.round(l * 100),\n a: Math.round(a * 100) / 100,\n };\n}\n\n/** Convert HSLA to a hex string (#rrggbb or #rrggbbaa when a < 1). */\nexport function hslToHex(hsl: HSLA): string {\n const { r, g, b } = hslToRgbComponents(hsl);\n const toHex = (n: number) =>\n Math.round(n * 255)\n .toString(16)\n .padStart(2, '0');\n\n const base = `#${toHex(r)}${toHex(g)}${toHex(b)}`;\n if (hsl.a < 1) {\n return `${base}${toHex(hsl.a)}`;\n }\n return base;\n}\n\n/** Convert HSLA to an rgba() string. */\nexport function hslToRgba(hsl: HSLA): string {\n const { r, g, b } = hslToRgbComponents(hsl);\n const ri = Math.round(r * 255);\n const gi = Math.round(g * 255);\n const bi = Math.round(b * 255);\n\n if (hsl.a < 1) {\n return `rgba(${ri}, ${gi}, ${bi}, ${hsl.a})`;\n }\n return `rgba(${ri}, ${gi}, ${bi}, 1)`;\n}\n\n/** Internal: convert HSLA to normalised RGB components (0–1). */\nfunction hslToRgbComponents(hsl: HSLA): {\n r: number;\n g: number;\n b: number;\n} {\n const h = hsl.h / 360;\n const s = hsl.s / 100;\n const l = hsl.l / 100;\n\n if (s === 0) {\n return { r: l, g: l, b: l };\n }\n\n const q = l < 0.5 ? l * (1 + s) : l + s - l * s;\n const p = 2 * l - q;\n\n return {\n r: hueToRgb(p, q, h + 1 / 3),\n g: hueToRgb(p, q, h),\n b: hueToRgb(p, q, h - 1 / 3),\n };\n}\n\nfunction hueToRgb(p: number, q: number, t: number): number {\n let tt = t;\n if (tt < 0) tt += 1;\n if (tt > 1) tt -= 1;\n if (tt < 1 / 6) return p + (q - p) * 6 * tt;\n if (tt < 1 / 2) return q;\n if (tt < 2 / 3) return p + (q - p) * (2 / 3 - tt) * 6;\n return p;\n}\n\n/* ------------------------------------------------------------------ */\n/* Format / Parse */\n/* ------------------------------------------------------------------ */\n\n/** Format an HSLA value to the specified output format. */\nexport function formatOutput(\n hsl: HSLA,\n format: 'hex' | 'hsl' | 'rgba',\n): string {\n switch (format) {\n case 'hex':\n return hslToHex(hsl);\n case 'hsl':\n if (hsl.a < 1) {\n return `hsla(${hsl.h}, ${hsl.s}%, ${hsl.l}%, ${hsl.a})`;\n }\n return `hsl(${hsl.h}, ${hsl.s}%, ${hsl.l}%)`;\n case 'rgba':\n return hslToRgba(hsl);\n }\n}\n\n/** Parse any supported colour string into HSLA. Returns null on failure. */\nexport function parseInput(value: string): HSLA | null {\n const trimmed = value.trim();\n if (!trimmed) return null;\n\n // Hex: #rgb, #rrggbb, #rrggbbaa\n if (trimmed.startsWith('#')) {\n const body = trimmed.slice(1);\n if (!/^[0-9a-fA-F]{3,8}$/.test(body)) return null;\n if (![3, 4, 6, 8].includes(body.length)) return null;\n return hexToHsl(trimmed);\n }\n\n // hsla(h, s%, l%, a) or hsl(h, s%, l%)\n const hslaMatch = trimmed.match(\n /^hsla?\\(\\s*([\\d.]+)\\s*[,/]\\s*([\\d.]+)%?\\s*[,/]\\s*([\\d.]+)%?\\s*(?:[,/]\\s*([\\d.]+))?\\s*\\)$/,\n );\n if (hslaMatch) {\n return {\n h: Math.round(parseFloat(hslaMatch[1])) % 360,\n s: Math.round(parseFloat(hslaMatch[2])),\n l: Math.round(parseFloat(hslaMatch[3])),\n a: hslaMatch[4] !== undefined ? parseFloat(hslaMatch[4]) : 1,\n };\n }\n\n // rgba(r, g, b, a) or rgb(r, g, b)\n const rgbaMatch = trimmed.match(\n /^rgba?\\(\\s*([\\d.]+)\\s*[,/]\\s*([\\d.]+)\\s*[,/]\\s*([\\d.]+)\\s*(?:[,/]\\s*([\\d.]+))?\\s*\\)$/,\n );\n if (rgbaMatch) {\n const r = parseFloat(rgbaMatch[1]) / 255;\n const g = parseFloat(rgbaMatch[2]) / 255;\n const b = parseFloat(rgbaMatch[3]) / 255;\n const a = rgbaMatch[4] !== undefined ? parseFloat(rgbaMatch[4]) : 1;\n return rgbToHsl(r, g, b, a);\n }\n\n return null;\n}\n\n/* ------------------------------------------------------------------ */\n/* Contrast — WCAG 2.x relative luminance */\n/* ------------------------------------------------------------------ */\n\n/** Relative luminance per WCAG 2.x (0 = black, 1 = white). */\nexport function relativeLuminance(hsl: HSLA): number {\n const { r, g, b } = hslToRgbComponents(hsl);\n const linearise = (c: number) =>\n c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);\n return 0.2126 * linearise(r) + 0.7152 * linearise(g) + 0.0722 * linearise(b);\n}\n\n/** WCAG 2.x contrast ratio between two colours. */\nexport function contrastRatio(fg: HSLA, bg: HSLA): number {\n const lum1 = relativeLuminance(fg);\n const lum2 = relativeLuminance(bg);\n const lighter = Math.max(lum1, lum2);\n const darker = Math.min(lum1, lum2);\n return Math.round(((lighter + 0.05) / (darker + 0.05)) * 100) / 100;\n}\n\n/** Meets WCAG AA for normal text (≥ 4.5:1). */\nexport function meetsAA(ratio: number): boolean {\n return ratio >= 4.5;\n}\n\n/** Meets WCAG AAA for normal text (≥ 7:1). */\nexport function meetsAAA(ratio: number): boolean {\n return ratio >= 7;\n}\n","export interface PaletteSwatch {\n name: string;\n hex: string;\n /** Recommended text colour for contrast. */\n textColor?: '#000000' | '#ffffff';\n}\n\n/**\n * Material Design appointment colours — mirrors the platform's `DoctorColor`\n * entity. Pink 500 is first because it's the default appointment colour;\n * remaining dark (white-text) colours follow alphabetically, then light\n * (black-text) colours alphabetically.\n */\nexport const APPOINTMENT_PALETTE: PaletteSwatch[] = [\n { name: 'Pink 500', hex: '#e91e63', textColor: '#ffffff' },\n { name: 'Black', hex: '#000000', textColor: '#ffffff' },\n { name: 'Blue 500', hex: '#2196f3', textColor: '#ffffff' },\n { name: 'Blue 900', hex: '#0d47a1', textColor: '#ffffff' },\n { name: 'Blue Grey 500', hex: '#607d8b', textColor: '#ffffff' },\n { name: 'Blue Grey 800', hex: '#37474f', textColor: '#ffffff' },\n { name: 'Brown 500', hex: '#795548', textColor: '#ffffff' },\n { name: 'Deep Orange 500', hex: '#ff5722', textColor: '#ffffff' },\n { name: 'Deep Purple 500', hex: '#673ab7', textColor: '#ffffff' },\n { name: 'Green 500', hex: '#4caf50', textColor: '#ffffff' },\n { name: 'Green 900', hex: '#1b5e20', textColor: '#ffffff' },\n { name: 'Indigo 500', hex: '#3f51b5', textColor: '#ffffff' },\n { name: 'Indigo 900', hex: '#1a237e', textColor: '#ffffff' },\n { name: 'Pink 900', hex: '#880e4f', textColor: '#ffffff' },\n { name: 'Purple 500', hex: '#9c27b0', textColor: '#ffffff' },\n { name: 'Purple 900', hex: '#4a148c', textColor: '#ffffff' },\n { name: 'Red 500', hex: '#f44336', textColor: '#ffffff' },\n { name: 'Red 900', hex: '#b71c1c', textColor: '#ffffff' },\n { name: 'Teal 500', hex: '#009688', textColor: '#ffffff' },\n { name: 'Teal 900', hex: '#004d40', textColor: '#ffffff' },\n { name: 'Amber 500', hex: '#ffc107', textColor: '#000000' },\n { name: 'Cyan 500', hex: '#00bcd4', textColor: '#000000' },\n { name: 'Grey 500', hex: '#9e9e9e', textColor: '#000000' },\n { name: 'Light Blue 500', hex: '#03a9f4', textColor: '#000000' },\n { name: 'Light Green 500', hex: '#8bc34a', textColor: '#000000' },\n { name: 'Lime 500', hex: '#cddc39', textColor: '#000000' },\n { name: 'Orange 500', hex: '#ff9800', textColor: '#000000' },\n { name: 'Orange 900', hex: '#e65100', textColor: '#000000' },\n { name: 'White', hex: '#ffffff', textColor: '#000000' },\n { name: 'Yellow 500', hex: '#ffeb3b', textColor: '#000000' },\n];\n\n/** Alfadocs brand palette — the six brand families × 3 shades (300/500/700). */\nexport const BRAND_PALETTE: PaletteSwatch[] = [\n { name: 'Blue 300', hex: '#70738c' },\n { name: 'Blue 500', hex: '#292e53' },\n { name: 'Blue 700', hex: '#1d213b' },\n { name: 'Violet 300', hex: '#9995ee' },\n { name: 'Violet 500', hex: '#6761e5' },\n { name: 'Violet 700', hex: '#4945a3' },\n { name: 'Purple 300', hex: '#ccaafa' },\n { name: 'Purple 500', hex: '#b380f8' },\n { name: 'Purple 700', hex: '#7f5bb0' },\n { name: 'Magenta 300', hex: '#ea7ffc' },\n { name: 'Magenta 500', hex: '#e040fb' },\n { name: 'Magenta 700', hex: '#9f2db2' },\n { name: 'Fuchsia 300', hex: '#fa76fc' },\n { name: 'Fuchsia 500', hex: '#f732fb' },\n { name: 'Fuchsia 700', hex: '#af24b2' },\n { name: 'Grey 300', hex: '#f9f6f3' },\n { name: 'Grey 500', hex: '#f6f1ed' },\n { name: 'Grey 700', hex: '#afaba8' },\n];\n\n/**\n * Google Calendar event colours — the platform's DEFAULT appointment\n * palette (practice DoctorColor sets mirror Google Calendar so synced\n * events keep their colours; the event `colorId` set is capped at 11 —\n * the 24 \"label\" colours exist only in Google's Labels API).\n * `textColor` is deliberately omitted: solid-scheme consumers get the\n * event card's auto-derived ink (provably WCAG AA for any opaque hex),\n * and the tinted scheme paints text on theme tokens regardless.\n */\nexport const GOOGLE_CALENDAR_PALETTE: PaletteSwatch[] = [\n { name: 'Tomato', hex: '#d50000' },\n { name: 'Flamingo', hex: '#e67c73' },\n { name: 'Tangerine', hex: '#f4511e' },\n { name: 'Banana', hex: '#f6bf26' },\n { name: 'Sage', hex: '#33b679' },\n { name: 'Basil', hex: '#0b8043' },\n { name: 'Peacock', hex: '#039be5' },\n { name: 'Blueberry', hex: '#3f51b5' },\n { name: 'Lavender', hex: '#7986cb' },\n { name: 'Grape', hex: '#8e24aa' },\n { name: 'Graphite', hex: '#616161' },\n];\n","import {\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type KeyboardEvent,\n} from 'react';\nimport * as Popover from '@radix-ui/react-popover';\nimport { cva } from 'class-variance-authority';\nimport { Check, X } from 'lucide-react';\nimport { useTranslation } from 'react-i18next';\nimport { useFormField } from '../form-field/form-field-context';\nimport { Slider } from '../slider/slider';\nimport { useAgentRegistration } from '../../agent';\nimport { colorPickerAgent } from './color-picker.agent';\n\n/** Agent-readiness curated handle for ColorPicker. */\nexport interface ColorPickerHandle {\n getValue: () => string;\n setValue: (hex: string) => void;\n}\nimport {\n contrastRatio,\n formatOutput,\n hslToHex,\n meetsAA,\n meetsAAA,\n parseInput,\n type HSLA,\n} from './color-utils';\nimport { APPOINTMENT_PALETTE, type PaletteSwatch } from './palettes';\n\nconst COLS = 6;\n\nconst triggerVariants = cva(\n [\n 'ds:inline-flex ds:items-center ds:w-full',\n 'ds:rounded-[var(--radius-sm)] ds:border ds:border-[color:var(--border)] ds:bg-[var(--background)] ds:text-[var(--foreground)]',\n 'ds:transition-colors ds:duration-[var(--animation-duration)] ds:motion-reduce:transition-none',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[color:var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:disabled:cursor-not-allowed ds:disabled:opacity-50',\n ].join(' '),\n {\n variants: {\n size: {\n sm: 'ds:h-8 ds:text-[length:var(--font-size-sm)] ds:ps-3 ds:pe-3',\n md: 'ds:h-[var(--min-target-size)] ds:text-[length:var(--font-size-base)] ds:ps-3 ds:pe-3',\n lg: 'ds:h-12 ds:text-[length:var(--font-size-lg)] ds:ps-4 ds:pe-4',\n },\n },\n defaultVariants: { size: 'md' },\n },\n);\n\nconst swatchVariants = cva(\n [\n 'ds:relative ds:rounded-[var(--radius-sm)] ds:border-2 ds:cursor-pointer',\n 'ds:transition-[transform,box-shadow] ds:duration-[var(--animation-duration)] ds:motion-reduce:transition-none',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[color:var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:hover:scale-110',\n // The swatch background is the user-picked colour — set as a CSS custom\n // property via inline `style` per 23-constraints §Runtime-computed\n // dimensions (CSS custom property setter; the bg rule lives on the class).\n 'ds:bg-[var(--swatch-bg)]',\n ].join(' '),\n {\n variants: {\n selected: {\n true: 'ds:border-[var(--primary)] ds:shadow-[var(--shadow-md)]',\n false: 'ds:border-transparent',\n },\n // Swatch footprint. md/lg honour --min-target-size (44/48px) for touch.\n // sm is a denser 28px swatch for toolbar/inline use — comfortably above\n // the WCAG 2.5.8 (AA) 24px minimum, with the grid gap providing spacing.\n // sm intentionally does NOT take the accessible-theme --min-target-size\n // bump (48px) — a dense colour grid is opt-in and the full roving-tabindex\n // keyboard path is the mitigation for the sub-AAA pointer target.\n size: {\n // sm = 28px: clears WCAG 2.5.8 (AA, 24px) but intentionally opts out of\n // the accessible-theme 48px min-target bump — a conscious, signed-off\n // trade-off (dense opt-in grid; keyboard roving-tabindex is the mitigation).\n sm: 'ds:min-w-7 ds:min-h-7',\n md: 'ds:min-w-[var(--min-target-size)] ds:min-h-[var(--min-target-size)]',\n lg: 'ds:min-w-[var(--min-target-size)] ds:min-h-[var(--min-target-size)]',\n },\n },\n defaultVariants: { selected: false, size: 'md' },\n },\n);\n\nconst PANEL_CLASSES = [\n 'ds:flex ds:flex-col ds:gap-[var(--spacing-md)]',\n 'ds:rounded-[var(--radius-md)] ds:bg-[var(--background)] ds:text-[var(--foreground)]',\n 'ds:p-[var(--spacing-md)]',\n].join(' ');\n\n// Checkerboard under the opacity track — static geometry, so expressed as\n// Tailwind arbitrary values rather than inline `style`. `grey-700` comes\n// from the closed palette so the tile colour still tracks the token ramp.\nconst OPACITY_CHECKER_CLASSES = [\n 'ds:bg-[image:repeating-conic-gradient(var(--color-grey-700)_0%_25%,transparent_0%_50%)]',\n 'ds:bg-[size:8px_8px]',\n].join(' ');\n\nconst PANEL_COMPACT_CLASSES = [\n 'ds:rounded-[var(--radius-md)] ds:bg-[var(--background)] ds:text-[var(--foreground)]',\n 'ds:p-[var(--spacing-sm)]',\n].join(' ');\n\n// Tighter padding for the dense (sm) swatch-only panel — toolbar/inline use.\nconst PANEL_COMPACT_SM_CLASSES = [\n 'ds:rounded-[var(--radius-md)] ds:bg-[var(--background)] ds:text-[var(--foreground)]',\n 'ds:p-[var(--spacing-xs)]',\n].join(' ');\n\nconst POPOVER_CONTENT_CLASSES = [\n 'ds:z-[var(--z-popover)] ds:rounded-[var(--radius-md)]',\n 'ds:border ds:border-[color:var(--border)] ds:bg-[var(--background)] ds:shadow-[var(--shadow-lg)]',\n 'ds:w-72',\n 'ds:data-[state=open]:animate-in ds:data-[state=open]:fade-in-0 ds:data-[state=open]:zoom-in-95',\n 'ds:data-[state=closed]:animate-out ds:data-[state=closed]:fade-out-0 ds:data-[state=closed]:zoom-out-95',\n 'ds:data-[side=bottom]:slide-in-from-top-2 ds:data-[side=top]:slide-in-from-bottom-2',\n 'ds:data-[side=left]:slide-in-from-right-2 ds:data-[side=right]:slide-in-from-left-2',\n].join(' ');\n\nconst HEX_INPUT_CLASSES = [\n 'ds:w-full ds:rounded-[var(--radius-sm)] ds:border ds:bg-[var(--background)] ds:text-[var(--foreground)]',\n 'ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-sm)] ds:py-[var(--spacing-xs)] ds:text-[length:var(--font-size-sm)]',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[color:var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:disabled:cursor-not-allowed ds:disabled:opacity-50',\n 'ds:transition-colors ds:duration-[var(--animation-duration)] ds:motion-reduce:transition-none',\n].join(' ');\n\n// Makes the Slider track/range transparent so the gradient behind shows through\nconst TRANSPARENT_SLIDER =\n 'ds:[&>span:first-child]:bg-transparent ds:[&>span:first-child>span]:bg-transparent';\n\nexport interface ColorPickerProps {\n value?: string;\n defaultValue?: string;\n onChange?: (value: string) => void;\n format?: 'hex' | 'hsl' | 'rgba';\n allowOpacity?: boolean;\n palette?: (string | PaletteSwatch)[];\n against?: string;\n size?: 'sm' | 'md' | 'lg';\n disabled?: boolean;\n variant?: 'inline' | 'popover';\n /** Show only the swatch grid without sliders, hex input, or contrast readout */\n compact?: boolean;\n className?: string;\n}\n\nexport const ColorPicker = forwardRef<HTMLDivElement, ColorPickerProps>(\n (props, ref) => {\n const {\n value,\n defaultValue,\n onChange,\n format = 'hex',\n allowOpacity = false,\n palette,\n against,\n size = 'md',\n disabled = false,\n variant = 'inline',\n compact = true,\n className,\n } = props;\n\n const { t } = useTranslation();\n const ctx = useFormField();\n const generatedId = useId();\n const pickerId = ctx.id || generatedId;\n const effectiveDisabled = ctx.disabled || disabled;\n\n const isControlled = value !== undefined;\n const [internalHsl, setInternalHsl] = useState<HSLA>(() => {\n const initial = value ?? defaultValue;\n if (initial) {\n const parsed = parseInput(initial);\n if (parsed) return parsed;\n }\n return { h: 0, s: 100, l: 50, a: 1 };\n });\n\n const currentHsl: HSLA = useMemo(() => {\n if (isControlled && value) {\n const parsed = parseInput(value);\n if (parsed) return parsed;\n }\n return internalHsl;\n }, [isControlled, value, internalHsl]);\n\n const emitChange = useCallback(\n (hsl: HSLA) => {\n const finalHsl = allowOpacity ? hsl : { ...hsl, a: 1 };\n if (!isControlled) setInternalHsl(finalHsl);\n onChange?.(formatOutput(finalHsl, format));\n },\n [allowOpacity, format, isControlled, onChange],\n );\n\n const [hexInput, setHexInput] = useState(() => hslToHex(currentHsl));\n const [hexError, setHexError] = useState(false);\n const revertTimerRef = useRef<ReturnType<typeof setTimeout>>(undefined);\n const currentHslRef = useRef(currentHsl);\n currentHslRef.current = currentHsl;\n\n useEffect(() => {\n setHexInput(hslToHex(currentHsl));\n setHexError(false);\n if (revertTimerRef.current !== undefined) {\n clearTimeout(revertTimerRef.current);\n revertTimerRef.current = undefined;\n }\n }, [currentHsl]);\n\n useEffect(() => {\n return () => {\n if (revertTimerRef.current !== undefined) {\n clearTimeout(revertTimerRef.current);\n }\n };\n }, []);\n\n const handleHexBlur = () => {\n const parsed = parseInput(hexInput);\n if (parsed) {\n setHexError(false);\n emitChange(parsed);\n } else {\n setHexError(true);\n revertTimerRef.current = setTimeout(() => {\n revertTimerRef.current = undefined;\n setHexError(false);\n setHexInput(hslToHex(currentHslRef.current));\n }, 800);\n }\n };\n\n const swatches: PaletteSwatch[] = useMemo(() => {\n if (!palette) return APPOINTMENT_PALETTE;\n return palette.map((item) =>\n typeof item === 'string'\n ? { name: item.toUpperCase(), hex: item }\n : item,\n );\n }, [palette]);\n\n const currentHex = hslToHex(currentHsl);\n // Normalise palette entries through parseInput so swatches declared as\n // rgb()/hsl()/shorthand hex still match — raw `s.hex` comparison misses\n // any non-literal-hex representation.\n const swatchCanonicalHexes = useMemo(\n () =>\n swatches.map((s) => {\n const parsed = parseInput(s.hex);\n return parsed ? hslToHex(parsed).toLowerCase() : null;\n }),\n [swatches],\n );\n const selectedSwatchIndex = swatchCanonicalHexes.findIndex(\n (hex) => hex !== null && hex === currentHex.toLowerCase(),\n );\n\n const gridRef = useRef<HTMLDivElement>(null);\n const [focusedIndex, setFocusedIndex] = useState(\n selectedSwatchIndex >= 0 ? selectedSwatchIndex : 0,\n );\n\n const focusSwatch = (index: number) => {\n const cells =\n gridRef.current?.querySelectorAll<HTMLElement>('[role=\"gridcell\"]');\n if (cells?.[index]) {\n cells[index].focus();\n setFocusedIndex(index);\n }\n };\n\n const handleGridKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n if (effectiveDisabled) return;\n const total = swatches.length;\n let next = focusedIndex;\n\n // The grid (grid-cols-6) mirrors under dir=\"rtl\", so the physical\n // ArrowRight/ArrowLeft keys must map to the inverse logical delta to keep\n // keyboard navigation following the visual reading order. Resolve the\n // effective direction from the element's computed style.\n const isRtl =\n typeof window !== 'undefined' && gridRef.current\n ? window.getComputedStyle(gridRef.current).direction === 'rtl'\n : false;\n const forward = isRtl ? -1 : 1;\n\n switch (event.key) {\n case 'ArrowRight':\n next = (focusedIndex + forward + total) % total;\n break;\n case 'ArrowLeft':\n next = (focusedIndex - forward + total) % total;\n break;\n case 'ArrowDown':\n next = Math.min(focusedIndex + COLS, total - 1);\n break;\n case 'ArrowUp':\n next = Math.max(focusedIndex - COLS, 0);\n break;\n case 'Home':\n next = Math.floor(focusedIndex / COLS) * COLS;\n break;\n case 'End':\n next = Math.min(\n Math.floor(focusedIndex / COLS) * COLS + COLS - 1,\n total - 1,\n );\n break;\n case 'PageUp':\n next = focusedIndex % COLS;\n break;\n case 'PageDown': {\n const lastRowStart = Math.floor((total - 1) / COLS) * COLS;\n next = Math.min(lastRowStart + (focusedIndex % COLS), total - 1);\n break;\n }\n case 'Enter':\n case ' ': {\n event.preventDefault();\n const parsed = parseInput(swatches[focusedIndex].hex);\n if (parsed) emitChange(parsed);\n return;\n }\n default:\n return;\n }\n\n event.preventDefault();\n focusSwatch(next);\n };\n\n const [open, setOpen] = useState(false);\n\n const agentHandle = useMemo<ColorPickerHandle>(\n () => ({\n getValue: () => hslToHex(currentHslRef.current),\n setValue: (hex) => {\n const parsed = parseInput(hex);\n if (parsed) emitChange(parsed);\n },\n }),\n [emitChange],\n );\n useAgentRegistration(colorPickerAgent, agentHandle, pickerId);\n\n const contrastInfo = useMemo(() => {\n if (!against) return null;\n const bgHsl = parseInput(against);\n if (!bgHsl) return null;\n const ratio = contrastRatio(currentHsl, bgHsl);\n return { ratio, aa: meetsAA(ratio), aaa: meetsAAA(ratio) };\n }, [against, currentHsl]);\n\n const swatchGrid = (\n // eslint-disable-next-line jsx-a11y/interactive-supports-focus -- inner gridcells are individually focusable via roving tabindex\n <div\n ref={gridRef}\n role=\"grid\"\n aria-label={t('inputs.colorPicker.paletteLabel', 'Colour palette')}\n onKeyDown={handleGridKeyDown}\n className=\"ds:grid ds:grid-cols-6 ds:gap-[var(--spacing-xs)]\"\n >\n {swatches.map((_swatch, i) => {\n const rowStart = Math.floor(i / COLS) * COLS;\n const isFirstInRow = i === rowStart;\n return isFirstInRow ? (\n <div key={i} role=\"row\" className=\"ds:contents\">\n {swatches.slice(rowStart, rowStart + COLS).map((s, j) => {\n const idx = rowStart + j;\n const sel = idx === selectedSwatchIndex;\n return (\n // eslint-disable-next-line jsx-a11y/click-events-have-key-events -- parent grid handles keyboard navigation via onKeyDown\n <div\n key={s.hex}\n role=\"gridcell\"\n aria-selected={sel}\n aria-label={t('inputs.colorPicker.swatchLabel', {\n name: s.name,\n hex: s.hex,\n })}\n tabIndex={idx === focusedIndex ? 0 : -1}\n onClick={() => {\n if (effectiveDisabled) return;\n const parsed = parseInput(s.hex);\n if (parsed) emitChange(parsed);\n setFocusedIndex(idx);\n }}\n className={swatchVariants({ selected: sel, size })}\n // eslint-disable-next-line react/forbid-dom-props -- user-picked swatch hex injected via --swatch-bg CSS variable\n style={{ ['--swatch-bg' as string]: s.hex }}\n >\n {sel ? (\n <Check\n aria-hidden=\"true\"\n className=\"ds:absolute ds:inset-0 ds:m-auto ds:size-4 ds:text-[var(--background)] ds:mix-blend-difference\"\n />\n ) : null}\n </div>\n );\n })}\n </div>\n ) : null;\n })}\n </div>\n );\n\n const fullControls = compact ? null : (\n <>\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <label\n htmlFor={`${pickerId}-hex`}\n className=\"ds:text-[length:var(--font-size-xs)] ds:text-[var(--muted-foreground)]\"\n >\n {t('inputs.colorPicker.hex', 'Hex')}\n </label>\n <bdi dir=\"ltr\">\n <input\n id={`${pickerId}-hex`}\n type=\"text\"\n value={hexInput}\n disabled={effectiveDisabled}\n onChange={(e) => setHexInput(e.target.value)}\n onBlur={handleHexBlur}\n className={`${HEX_INPUT_CLASSES} ${hexError ? 'ds:border-[var(--destructive)]' : 'ds:border-[color:var(--border)]'}`}\n />\n </bdi>\n </div>\n\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n <SliderWithGradient\n label={t('inputs.colorPicker.hue', 'Hue')}\n gradient=\"linear-gradient(to right, hsl(0,100%,50%), hsl(60,100%,50%), hsl(120,100%,50%), hsl(180,100%,50%), hsl(240,100%,50%), hsl(300,100%,50%), hsl(360,100%,50%))\"\n min={0}\n max={360}\n value={currentHsl.h}\n onChange={(h) => emitChange({ ...currentHsl, h })}\n formatValue={(v) => `H ${v}°`}\n disabled={effectiveDisabled}\n />\n <SliderWithGradient\n label={t('inputs.colorPicker.saturation', 'Saturation')}\n gradient={`linear-gradient(to right, hsl(${currentHsl.h},0%,${currentHsl.l}%), hsl(${currentHsl.h},100%,${currentHsl.l}%))`}\n min={0}\n max={100}\n value={currentHsl.s}\n onChange={(s) => emitChange({ ...currentHsl, s })}\n formatValue={(v) => `S ${v}%`}\n disabled={effectiveDisabled}\n />\n <SliderWithGradient\n label={t('inputs.colorPicker.lightness', 'Lightness')}\n gradient={`linear-gradient(to right, hsl(${currentHsl.h},${currentHsl.s}%,0%), hsl(${currentHsl.h},${currentHsl.s}%,50%), hsl(${currentHsl.h},${currentHsl.s}%,100%))`}\n min={0}\n max={100}\n value={currentHsl.l}\n onChange={(l) => emitChange({ ...currentHsl, l })}\n formatValue={(v) => `L ${v}%`}\n disabled={effectiveDisabled}\n />\n {allowOpacity ? (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <label className=\"ds:text-[length:var(--font-size-xs)] ds:text-[var(--muted-foreground)]\">\n {t('inputs.colorPicker.opacity', 'Opacity')}\n </label>\n <div className=\"ds:relative\">\n <div\n className={`ds:absolute ds:inset-0 ds:rounded-[var(--radius-full)] ds:pointer-events-none ${OPACITY_CHECKER_CLASSES}`}\n aria-hidden=\"true\"\n />\n <div\n className=\"ds:absolute ds:inset-0 ds:rounded-[var(--radius-full)] ds:pointer-events-none ds:bg-[image:var(--opacity-gradient)]\"\n // eslint-disable-next-line react/forbid-dom-props -- opacity-track gradient derived from live HSL, no token equivalent\n style={{\n ['--opacity-gradient' as string]: `linear-gradient(to right, hsla(${currentHsl.h},${currentHsl.s}%,${currentHsl.l}%,0), hsl(${currentHsl.h},${currentHsl.s}%,${currentHsl.l}%))`,\n }}\n aria-hidden=\"true\"\n />\n <Slider\n min={0}\n max={100}\n step={1}\n value={[Math.round(currentHsl.a * 100)]}\n onValueChange={([v]) =>\n emitChange({ ...currentHsl, a: v / 100 })\n }\n aria-label={t('inputs.colorPicker.opacity', 'Opacity')}\n formatValue={(v) => `${v}%`}\n disabled={effectiveDisabled}\n className={TRANSPARENT_SLIDER}\n />\n </div>\n </div>\n ) : null}\n </div>\n\n {contrastInfo ? (\n <div\n className=\"ds:flex ds:items-center ds:gap-[var(--spacing-sm)] ds:text-[length:var(--font-size-sm)]\"\n role=\"status\"\n aria-live=\"polite\"\n >\n <span className=\"ds:tabular-nums\">\n {t('inputs.colorPicker.contrastRatio', {\n ratio: contrastInfo.ratio.toFixed(1),\n })}\n </span>\n <ContrastBadge level=\"AA\" passes={contrastInfo.aa} t={t} />\n <ContrastBadge level=\"AAA\" passes={contrastInfo.aaa} t={t} />\n </div>\n ) : null}\n\n <div className=\"ds:flex ds:items-center ds:gap-[var(--spacing-sm)]\">\n <div\n className=\"ds:size-8 ds:rounded-[var(--radius-sm)] ds:border ds:border-[color:var(--border)] ds:bg-[var(--swatch-bg)]\"\n // eslint-disable-next-line react/forbid-dom-props -- live picked colour injected via --swatch-bg CSS variable\n style={{ ['--swatch-bg' as string]: hslToHex(currentHsl) }}\n aria-hidden=\"true\"\n />\n <span className=\"ds:text-[length:var(--font-size-sm)] ds:text-[var(--muted-foreground)] ds:tabular-nums\">\n {formatOutput(currentHsl, format)}\n </span>\n </div>\n </>\n );\n\n const panelContent = (\n <div\n className={\n compact\n ? size === 'sm'\n ? PANEL_COMPACT_SM_CLASSES\n : PANEL_COMPACT_CLASSES\n : PANEL_CLASSES\n }\n >\n {swatchGrid}\n {fullControls}\n </div>\n );\n\n if (variant === 'inline') {\n return (\n <div\n ref={ref}\n id={pickerId}\n className={className}\n aria-describedby={ctx.describedBy || undefined}\n aria-invalid={ctx.invalid || undefined}\n aria-disabled={effectiveDisabled || undefined}\n data-component=\"color-picker\"\n data-component-id={pickerId}\n data-testid=\"color-picker\"\n >\n {panelContent}\n </div>\n );\n }\n\n return (\n <Popover.Root open={open} onOpenChange={setOpen}>\n <Popover.Trigger asChild disabled={effectiveDisabled}>\n {/* eslint-disable-next-line jsx-a11y/role-supports-aria-props -- FormField propagates invalid state to its trigger; users rely on this for validation announcements */}\n <button\n ref={ref as React.Ref<HTMLButtonElement>}\n type=\"button\"\n id={pickerId}\n aria-describedby={ctx.describedBy || undefined}\n aria-invalid={ctx.invalid || undefined}\n // In compact mode the trigger only renders the swatch (which is\n // aria-hidden). Provide a fallback name so the button is named\n // for AT regardless of variant. The current value is announced\n // separately via the hex/HSL output inside the popover.\n aria-label={\n compact\n ? t('inputs.colorPicker.triggerLabel', 'Choose colour')\n : undefined\n }\n className={triggerVariants({ size, className })}\n data-component=\"color-picker\"\n data-component-id={pickerId}\n data-testid=\"color-picker-trigger\"\n >\n <span\n className={`ds:inline-block ds:size-5 ds:rounded-[var(--radius-sm)] ds:border ds:border-[color:var(--border)] ds:shrink-0 ds:bg-[var(--swatch-bg)]${compact ? '' : ' ds:me-[var(--spacing-sm)]'}`}\n aria-hidden=\"true\"\n // eslint-disable-next-line react/forbid-dom-props -- trigger preview swatch shows current picked colour via --swatch-bg\n style={{ ['--swatch-bg' as string]: hslToHex(currentHsl) }}\n />\n {compact ? null : (\n <span className=\"ds:text-start ds:truncate ds:tabular-nums\">\n {formatOutput(currentHsl, format)}\n </span>\n )}\n </button>\n </Popover.Trigger>\n <Popover.Portal>\n <Popover.Content\n sideOffset={4}\n align=\"start\"\n className={POPOVER_CONTENT_CLASSES}\n >\n {panelContent}\n </Popover.Content>\n </Popover.Portal>\n </Popover.Root>\n );\n },\n);\n\nColorPicker.displayName = 'ColorPicker';\n\nfunction ContrastBadge({\n level,\n passes,\n t,\n}: {\n level: string;\n passes: boolean;\n t: (key: string, fallback: string) => string;\n}) {\n return (\n <span className=\"ds:inline-flex ds:items-center ds:gap-[var(--spacing-xs)]\">\n <abbr\n title={`Web Content Accessibility Guidelines Level ${level}`}\n className=\"ds:no-underline ds:font-medium\"\n >\n {level}\n </abbr>\n {passes ? (\n <Check\n aria-hidden=\"true\"\n className=\"ds:size-4 ds:text-[var(--success)]\"\n />\n ) : (\n <X\n aria-hidden=\"true\"\n className=\"ds:size-4 ds:text-[var(--destructive)]\"\n />\n )}\n <span className=\"ds:sr-only\">\n {passes\n ? t('inputs.colorPicker.contrastPass', 'Pass')\n : t('inputs.colorPicker.contrastFail', 'Fail')}\n </span>\n </span>\n );\n}\n\nfunction SliderWithGradient({\n label,\n gradient,\n min,\n max,\n value,\n onChange,\n formatValue,\n disabled,\n}: {\n label: string;\n gradient: string;\n min: number;\n max: number;\n value: number;\n onChange: (v: number) => void;\n formatValue: (v: number) => string;\n disabled: boolean;\n}) {\n return (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <label className=\"ds:text-[length:var(--font-size-xs)] ds:text-[var(--muted-foreground)]\">\n {label}\n </label>\n <div className=\"ds:relative\">\n <div\n className=\"ds:absolute ds:inset-0 ds:rounded-[var(--radius-full)] ds:pointer-events-none ds:bg-[image:var(--slider-gradient)]\"\n // eslint-disable-next-line react/forbid-dom-props -- hue/saturation/lightness gradient derived from live HSL, no token equivalent\n style={{ ['--slider-gradient' as string]: gradient }}\n aria-hidden=\"true\"\n />\n <Slider\n min={min}\n max={max}\n step={1}\n value={[value]}\n onValueChange={([v]) => onChange(v)}\n aria-label={label}\n formatValue={formatValue}\n disabled={disabled}\n className={TRANSPARENT_SLIDER}\n />\n </div>\n </div>\n );\n}\n"],"names":["colorPickerAgent","handle","args","hexToHsl","hex","h","g","b","a","rgbToHsl","r","max","min","l","hue","sat","d","hslToHex","hsl","hslToRgbComponents","toHex","n","base","hslToRgba","ri","gi","bi","s","q","p","hueToRgb","t","tt","formatOutput","format","parseInput","value","trimmed","body","hslaMatch","rgbaMatch","relativeLuminance","linearise","c","contrastRatio","fg","bg","lum1","lum2","lighter","darker","meetsAA","ratio","meetsAAA","APPOINTMENT_PALETTE","BRAND_PALETTE","GOOGLE_CALENDAR_PALETTE","COLS","triggerVariants","cva","swatchVariants","PANEL_CLASSES","OPACITY_CHECKER_CLASSES","PANEL_COMPACT_CLASSES","PANEL_COMPACT_SM_CLASSES","POPOVER_CONTENT_CLASSES","HEX_INPUT_CLASSES","TRANSPARENT_SLIDER","ColorPicker","forwardRef","props","ref","defaultValue","onChange","allowOpacity","palette","against","size","disabled","variant","compact","className","useTranslation","ctx","useFormField","generatedId","useId","pickerId","effectiveDisabled","isControlled","internalHsl","setInternalHsl","useState","initial","parsed","currentHsl","useMemo","emitChange","useCallback","finalHsl","hexInput","setHexInput","hexError","setHexError","revertTimerRef","useRef","currentHslRef","useEffect","handleHexBlur","swatches","item","currentHex","selectedSwatchIndex","gridRef","focusedIndex","setFocusedIndex","focusSwatch","index","cells","_a","handleGridKeyDown","event","total","next","forward","lastRowStart","open","setOpen","agentHandle","useAgentRegistration","contrastInfo","bgHsl","swatchGrid","jsx","_swatch","rowStart","j","idx","sel","Check","fullControls","jsxs","Fragment","e","SliderWithGradient","v","Slider","ContrastBadge","panelContent","Popover","level","passes","X","label","gradient","formatValue"],"mappings":"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"}
@@ -0,0 +1,337 @@
1
+ import { jsx as h, jsxs as D, Fragment as lo } from "react/jsx-runtime";
2
+ import { useState as _, useCallback as g, useMemo as T, useRef as B, useContext as H, useId as io, useEffect as ao, createContext as co, forwardRef as uo } from "react";
3
+ import { useTranslation as po } from "react-i18next";
4
+ import { I as G } from "./icon-button-DA2CAGHZ.js";
5
+ import { a as fo } from "./panel-header-D313n_9-.js";
6
+ import { T as mo } from "./tool-rail-CHyUmulN.js";
7
+ import { u as go } from "./use-persistent-state-nZwZAnE9.js";
8
+ import { S as Ro } from "./star-Bf9L2Uot.js";
9
+ import { X as vo } from "./x-B5YnXwCz.js";
10
+ const ho = {
11
+ id: "control-room-rail",
12
+ capabilities: ["open", "close", "select_single"],
13
+ state: {
14
+ activeToolId: {
15
+ type: "string | null",
16
+ descriptionKey: "ui.toolRail.agent.state.activeToolId",
17
+ description: "Id of the tool whose panel is currently open, or null when the rail is collapsed to its strip. No panel content is ever exposed.",
18
+ read: (t) => t.getActiveToolId()
19
+ }
20
+ },
21
+ actions: {
22
+ open: {
23
+ // Pure ephemeral panel state (open) — no data loss, no external effect.
24
+ safety: "read",
25
+ argsType: "{ id: string }",
26
+ argsSchema: {
27
+ type: "object",
28
+ properties: { id: { type: "string" } },
29
+ required: ["id"]
30
+ },
31
+ idempotent: !0,
32
+ descriptionKey: "ui.toolRail.agent.actions.open",
33
+ description: "Open the given tool's panel.",
34
+ examples: [{ args: { id: "inbox" }, note: "Open the inbox tool panel." }],
35
+ invoke: (t, n) => {
36
+ t.open(n.id);
37
+ }
38
+ },
39
+ close: {
40
+ safety: "read",
41
+ idempotent: !0,
42
+ descriptionKey: "ui.toolRail.agent.actions.close",
43
+ description: "Collapse the rail to its strip (no active tool).",
44
+ invoke: (t) => {
45
+ t.close();
46
+ }
47
+ },
48
+ select_tool: {
49
+ safety: "read",
50
+ argsType: "{ id: string | null }",
51
+ argsSchema: {
52
+ type: "object",
53
+ properties: { id: { type: ["string", "null"] } },
54
+ required: ["id"]
55
+ },
56
+ idempotent: !0,
57
+ descriptionKey: "ui.toolRail.agent.actions.selectTool",
58
+ description: "Set the active tool by id (opens its panel), or pass null to collapse.",
59
+ invoke: (t, n) => {
60
+ t.setActiveTool(n.id);
61
+ }
62
+ }
63
+ },
64
+ domHooks: {
65
+ root: {
66
+ attr: "data-component",
67
+ value: "control-room-rail",
68
+ description: "Marks the ControlRoomRail wrapper."
69
+ },
70
+ instanceId: {
71
+ attr: "data-component-id",
72
+ sourceProp: "id",
73
+ description: "Sourced from the id prop. Required to address a specific rail from the agent."
74
+ },
75
+ item: {
76
+ attr: "data-tool-id",
77
+ description: "Stable tool id emitted on each strip IconButton. The active icon also carries data-active set to its id."
78
+ }
79
+ }
80
+ }, S = co(null);
81
+ function jo({
82
+ globalTools: t = [],
83
+ children: n
84
+ }) {
85
+ const [u, s] = _(
86
+ () => /* @__PURE__ */ new Map()
87
+ ), p = g(
88
+ (i, l) => {
89
+ s((a) => {
90
+ const M = new Map(a);
91
+ return M.set(i, l), M;
92
+ });
93
+ },
94
+ []
95
+ ), P = g((i) => {
96
+ s((l) => {
97
+ if (!l.has(i)) return l;
98
+ const a = new Map(l);
99
+ return a.delete(i), a;
100
+ });
101
+ }, []), f = T(
102
+ () => Array.from(u.values()).flat(),
103
+ [u]
104
+ ), v = B(null), k = g((i) => {
105
+ v.current = i;
106
+ }, []), m = g((i) => {
107
+ var l;
108
+ (l = v.current) == null || l.setActiveTool(i);
109
+ }, []), b = g(() => {
110
+ var i;
111
+ (i = v.current) == null || i.setActiveTool(null);
112
+ }, []), y = T(
113
+ () => ({
114
+ globalTools: t,
115
+ contextualTools: f,
116
+ registerContextualTools: p,
117
+ unregisterContextualTools: P,
118
+ registerRail: k,
119
+ openTool: m,
120
+ closeTool: b
121
+ }),
122
+ [
123
+ t,
124
+ f,
125
+ p,
126
+ P,
127
+ k,
128
+ m,
129
+ b
130
+ ]
131
+ );
132
+ return /* @__PURE__ */ h(S.Provider, { value: y, children: n });
133
+ }
134
+ function Ho(t) {
135
+ const n = H(S), u = n == null ? void 0 : n.registerContextualTools, s = n == null ? void 0 : n.unregisterContextualTools, p = io();
136
+ ao(() => {
137
+ if (!(!u || !s))
138
+ return u(p, t), () => s(p);
139
+ }, [u, s, p, t]);
140
+ }
141
+ function To() {
142
+ const t = H(S);
143
+ return T(() => {
144
+ if (!t) return [];
145
+ const n = t.contextualTools.map((s) => ({
146
+ ...s,
147
+ scope: "contextual"
148
+ })), u = t.globalTools.map((s) => ({
149
+ ...s,
150
+ scope: "global"
151
+ }));
152
+ return [...n, ...u];
153
+ }, [t]);
154
+ }
155
+ function Ko() {
156
+ const t = H(S), n = g(() => {
157
+ }, []);
158
+ return {
159
+ openTool: (t == null ? void 0 : t.openTool) ?? n,
160
+ closeTool: (t == null ? void 0 : t.closeTool) ?? n
161
+ };
162
+ }
163
+ function yo() {
164
+ const t = H(S), n = g((u) => {
165
+ }, []);
166
+ return (t == null ? void 0 : t.registerRail) ?? n;
167
+ }
168
+ const qo = uo(function({
169
+ tools: n,
170
+ railLabel: u,
171
+ reorderable: s = !0,
172
+ favoriteIds: p,
173
+ defaultFavoriteIds: P,
174
+ pinnedFavoriteIds: f,
175
+ onFavoriteIdsChange: v,
176
+ persistFavoritesKey: k = "ui.controlRoom.favorites",
177
+ activeToolId: m,
178
+ defaultActiveToolId: b = null,
179
+ onActiveToolChange: y,
180
+ ...i
181
+ }, l) {
182
+ const { t: a } = po(), [M, J] = _(
183
+ m ?? b ?? null
184
+ ), L = m !== void 0 ? m : M, Q = g(
185
+ (o) => {
186
+ m === void 0 && J(o), y == null || y(o);
187
+ },
188
+ [m, y]
189
+ ), U = To(), C = n ?? U, K = p !== void 0, [W, Y] = go(
190
+ k,
191
+ () => P ?? C.filter((o) => o.scope === "global").map((o) => o.id),
192
+ { disabled: K }
193
+ ), q = K ? p : W, A = T(() => f != null && f.length ? [
194
+ ...f,
195
+ ...q.filter((o) => !f.includes(o))
196
+ ] : q, [f, q]), d = T(() => {
197
+ const o = /* @__PURE__ */ new Map();
198
+ for (const r of C) o.set(r.id, r);
199
+ return o;
200
+ }, [C]), w = T(
201
+ () => new Set(A.filter((o) => d.has(o))),
202
+ [A, d]
203
+ ), O = (o) => {
204
+ const r = o(A.filter((e) => d.has(e)));
205
+ K || Y((e) => o(e.filter((c) => d.has(c)))), v == null || v(r);
206
+ }, E = T(() => {
207
+ if (!s) return C;
208
+ const o = A.filter((e) => d.has(e)).map((e) => ({
209
+ ...d.get(e),
210
+ scope: "global",
211
+ reorderable: !0
212
+ })), r = C.filter((e) => !w.has(e.id)).map((e) => ({
213
+ ...e,
214
+ scope: "contextual",
215
+ reorderable: !0
216
+ }));
217
+ return [...o, ...r];
218
+ }, [s, C, A, d, w]), [Z, F] = _(""), z = B(!1), I = (o, r) => {
219
+ const e = r ? a("controlRoom.pinnedAnnounce", {
220
+ tool: o,
221
+ defaultValue: "Pinned {{tool}} to favourites"
222
+ }) : a("controlRoom.unpinnedAnnounce", {
223
+ tool: o,
224
+ defaultValue: "Removed {{tool}} from favourites"
225
+ });
226
+ z.current = !z.current, F(z.current ? e : `${e}​`);
227
+ }, oo = (o) => {
228
+ var r;
229
+ I(((r = d.get(o)) == null ? void 0 : r.label) ?? o, !w.has(o)), O(
230
+ (e) => e.includes(o) ? e.filter((c) => c !== o) : [...e, o]
231
+ );
232
+ }, to = (o, r) => {
233
+ var c;
234
+ const e = (c = E[o]) == null ? void 0 : c.id;
235
+ e !== void 0 && O((x) => {
236
+ const V = x.filter((R) => d.has(R)), j = V.length;
237
+ if (o < j) {
238
+ if (r >= j) return V.filter((so) => so !== e);
239
+ const R = V.slice();
240
+ return R.splice(o, 1), R.splice(r, 0, e), R;
241
+ }
242
+ if (r <= j) {
243
+ const R = V.slice();
244
+ return R.splice(Math.min(r, j), 0, e), R;
245
+ }
246
+ return x;
247
+ });
248
+ }, eo = ({
249
+ tool: o,
250
+ from: r,
251
+ to: e
252
+ }) => {
253
+ const c = w.size, x = r < c;
254
+ return x && e >= c ? a("controlRoom.unpinnedAnnounce", {
255
+ tool: o.label,
256
+ defaultValue: "Removed {{tool}} from favourites"
257
+ }) : !x && e <= c ? a("controlRoom.pinnedAnnounce", {
258
+ tool: o.label,
259
+ defaultValue: "Pinned {{tool}} to favourites"
260
+ }) : x && e < c ? a("controlRoom.reorderAnnounce", {
261
+ tool: o.label,
262
+ to: e + 1,
263
+ total: c,
264
+ defaultValue: "{{tool}} moved to position {{to}} of {{total}}"
265
+ }) : "";
266
+ }, X = B(null), $ = yo(), no = g(
267
+ (o) => {
268
+ X.current = o, $(o), typeof l == "function" ? l(o) : l && (l.current = o);
269
+ },
270
+ [$, l]
271
+ ), N = L != null ? d.get(L) ?? null : null, ro = N ? /* @__PURE__ */ D(lo, { children: [
272
+ s ? (() => {
273
+ const o = w.has(N.id);
274
+ return /* @__PURE__ */ h(
275
+ G,
276
+ {
277
+ icon: /* @__PURE__ */ h(
278
+ Ro,
279
+ {
280
+ "aria-hidden": "true",
281
+ fill: o ? "currentColor" : "none",
282
+ className: o ? "ds:text-[color:var(--accent)]" : void 0
283
+ }
284
+ ),
285
+ intent: "ghost",
286
+ size: "sm",
287
+ "aria-pressed": o,
288
+ "aria-label": a("controlRoom.favorite", {
289
+ defaultValue: "Favourite"
290
+ }),
291
+ onClick: () => oo(N.id)
292
+ }
293
+ );
294
+ })() : null,
295
+ /* @__PURE__ */ h(
296
+ G,
297
+ {
298
+ icon: /* @__PURE__ */ h(vo, { "aria-hidden": "true" }),
299
+ intent: "ghost",
300
+ size: "sm",
301
+ "aria-label": a("controlRoom.close", { defaultValue: "Close" }),
302
+ onClick: () => {
303
+ var o;
304
+ return (o = X.current) == null ? void 0 : o.close();
305
+ }
306
+ }
307
+ )
308
+ ] }) : null;
309
+ return /* @__PURE__ */ D(fo, { actions: ro, children: [
310
+ /* @__PURE__ */ h(
311
+ mo,
312
+ {
313
+ ref: no,
314
+ dataComponent: "control-room-rail",
315
+ agentAdapter: ho,
316
+ tools: E,
317
+ activeToolId: m,
318
+ defaultActiveToolId: b,
319
+ onActiveToolChange: Q,
320
+ railLabel: u ?? a("controlRoom.railLabel", { defaultValue: "Control room" }),
321
+ onReorder: s ? to : void 0,
322
+ formatReorderAnnouncement: s ? eo : void 0,
323
+ ...i
324
+ }
325
+ ),
326
+ s ? /* @__PURE__ */ h("span", { role: "status", "aria-live": "polite", className: "ds:sr-only", children: Z }) : null
327
+ ] });
328
+ });
329
+ export {
330
+ jo as C,
331
+ qo as a,
332
+ To as b,
333
+ ho as c,
334
+ Ho as d,
335
+ Ko as u
336
+ };
337
+ //# sourceMappingURL=control-room-rail-Cj2iX9h_.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"control-room-rail-Cj2iX9h_.js","sources":["../../src/components/control-room-rail/control-room-rail.agent.ts","../../src/components/control-room-rail/control-room-context.tsx","../../src/components/control-room-rail/control-room-rail.tsx"],"sourcesContent":["/* -------------------------------------------------------------------- */\n/* Agent adapter — ControlRoomRail. */\n/* */\n/* The product surface built on ToolRail: the docked \"Control Room\". */\n/* It claims its OWN agent identity ('control-room-rail') so an agent and */\n/* the DOM / cascade boundary can tell the Control Room apart from a bare */\n/* ToolRail. Generic rail surface only: open / close a tool's panel and */\n/* read which tool is active. State is strictly the active tool id — never */\n/* any tool's panel CONTENT (which may carry PHI). */\n/* */\n/* The descriptionKeys deliberately REUSE the existing */\n/* `ui.toolRail.agent.*` translations — no new i18n keys are coined this */\n/* pass. */\n/* */\n/* NOTE: pin / unpin / reorder favourites are intentionally NOT yet an */\n/* agent capability. Exposing them is a deferred follow-up: it needs a */\n/* closed-vocabulary capability addition (DS-maintainer approval per */\n/* src/docs/26-agent-readiness.mdx) plus its own 18-locale descriptionKeys */\n/* — neither of which this pass introduces. */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\nimport type { ControlRoomRailHandle } from './control-room-rail';\n\nexport const controlRoomRailAgent: AgentAdapter<ControlRoomRailHandle> = {\n id: 'control-room-rail',\n capabilities: ['open', 'close', 'select_single'],\n state: {\n activeToolId: {\n type: 'string | null',\n descriptionKey: 'ui.toolRail.agent.state.activeToolId',\n description:\n 'Id of the tool whose panel is currently open, or null when the rail is collapsed to its strip. No panel content is ever exposed.',\n read: (handle) => handle.getActiveToolId(),\n },\n },\n actions: {\n open: {\n // Pure ephemeral panel state (open) — no data loss, no external effect.\n safety: 'read',\n argsType: '{ id: string }',\n argsSchema: {\n type: 'object',\n properties: { id: { type: 'string' } },\n required: ['id'],\n },\n idempotent: true,\n descriptionKey: 'ui.toolRail.agent.actions.open',\n description: \"Open the given tool's panel.\",\n examples: [{ args: { id: 'inbox' }, note: 'Open the inbox tool panel.' }],\n invoke: (handle, args: { id: string }) => {\n handle.open(args.id);\n },\n },\n close: {\n safety: 'read',\n idempotent: true,\n descriptionKey: 'ui.toolRail.agent.actions.close',\n description: 'Collapse the rail to its strip (no active tool).',\n invoke: (handle) => {\n handle.close();\n },\n },\n select_tool: {\n safety: 'read',\n argsType: '{ id: string | null }',\n argsSchema: {\n type: 'object',\n properties: { id: { type: ['string', 'null'] } },\n required: ['id'],\n },\n idempotent: true,\n descriptionKey: 'ui.toolRail.agent.actions.selectTool',\n description:\n 'Set the active tool by id (opens its panel), or pass null to collapse.',\n invoke: (handle, args: { id: string | null }) => {\n handle.setActiveTool(args.id);\n },\n },\n },\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'control-room-rail',\n description: 'Marks the ControlRoomRail wrapper.',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description:\n 'Sourced from the id prop. Required to address a specific rail from the agent.',\n },\n item: {\n attr: 'data-tool-id',\n description:\n 'Stable tool id emitted on each strip IconButton. The active icon also carries data-active set to its id.',\n },\n },\n};\n","import {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from 'react';\nimport type { ToolRailHandle, ToolRailTool } from '../tool-rail';\n\n/* ------------------------------------------------------------------ */\n/* Control Room context — the scope mechanism */\n/* */\n/* The DS provides the plumbing; the CONSUMER declares scope by which */\n/* API it reaches for: */\n/* - <ControlRoomProvider globalTools={…}> → `global` tools, set */\n/* once at the app shell, persist across navigation. */\n/* - useControlRoomTools([…]) → `contextual` tools, */\n/* registered per-page, swap with the open entity. */\n/* `<ControlRoomRail>` reads the merged set; `global` tools seed the */\n/* default favourites (pinned on top), `contextual` tools fall below */\n/* the divider. The rail renders the divider between the two groups. */\n/* ------------------------------------------------------------------ */\n\ninterface ControlRoomContextValue {\n globalTools: ToolRailTool[];\n contextualTools: ToolRailTool[];\n registerContextualTools: (id: string, tools: ToolRailTool[]) => void;\n unregisterContextualTools: (id: string) => void;\n // The rail registers its imperative handle here so pages can drive it\n // (e.g. open the X-ray panel when a tooth is clicked). Null until mounted.\n registerRail: (handle: ToolRailHandle | null) => void;\n openTool: (id: string) => void;\n closeTool: () => void;\n}\n\nconst ControlRoomContext = createContext<ControlRoomContextValue | null>(null);\n\nexport interface ControlRoomProviderProps {\n /**\n * Tools valid in every context (Alia, Inbox). Set once at the app shell —\n * they pin to the rail's far end and persist across navigation. Memoise\n * this array so it doesn't re-register every render.\n */\n globalTools?: ToolRailTool[];\n children: ReactNode;\n}\n\n/**\n * Holds the Control Room's global tools and the registry of per-context\n * contextual tools. Mount once at the app shell, inside the frame that also\n * renders `<ControlRoomRail>`.\n */\nexport function ControlRoomProvider({\n globalTools = [],\n children,\n}: ControlRoomProviderProps) {\n // id → that registration's contextual tools. Multiple concurrent\n // registrations merge in insertion order (rare, but composes cleanly).\n const [registry, setRegistry] = useState<Map<string, ToolRailTool[]>>(\n () => new Map(),\n );\n\n const registerContextualTools = useCallback(\n (id: string, tools: ToolRailTool[]) => {\n setRegistry((prev) => {\n const next = new Map(prev);\n next.set(id, tools);\n return next;\n });\n },\n [],\n );\n\n const unregisterContextualTools = useCallback((id: string) => {\n setRegistry((prev) => {\n if (!prev.has(id)) return prev;\n const next = new Map(prev);\n next.delete(id);\n return next;\n });\n }, []);\n\n const contextualTools = useMemo(\n () => Array.from(registry.values()).flat(),\n [registry],\n );\n\n // The rail's imperative handle, registered by <ControlRoomRail> on mount.\n // openTool/closeTool drive it so a page can open a panel (e.g. the X-ray\n // viewer when a tooth is clicked) without holding a ref to the rail itself.\n const railHandleRef = useRef<ToolRailHandle | null>(null);\n const registerRail = useCallback((handle: ToolRailHandle | null) => {\n railHandleRef.current = handle;\n }, []);\n const openTool = useCallback((id: string) => {\n railHandleRef.current?.setActiveTool(id);\n }, []);\n const closeTool = useCallback(() => {\n railHandleRef.current?.setActiveTool(null);\n }, []);\n\n const value = useMemo<ControlRoomContextValue>(\n () => ({\n globalTools,\n contextualTools,\n registerContextualTools,\n unregisterContextualTools,\n registerRail,\n openTool,\n closeTool,\n }),\n [\n globalTools,\n contextualTools,\n registerContextualTools,\n unregisterContextualTools,\n registerRail,\n openTool,\n closeTool,\n ],\n );\n\n return (\n <ControlRoomContext.Provider value={value}>\n {children}\n </ControlRoomContext.Provider>\n );\n}\n\n/**\n * Register this context's **contextual** tools (Notes, Appointments, the entity\n * summary). They sit below the favourites divider and unregister automatically\n * when the calling component unmounts (i.e. when you leave the context).\n *\n * Pass a **stable / memoised** array — like `useEffect` deps, a fresh array\n * every render re-registers every render. Wrap it in `useMemo`.\n *\n * No-op when rendered outside a `<ControlRoomProvider>`.\n */\nexport function useControlRoomTools(tools: ToolRailTool[]): void {\n const ctx = useContext(ControlRoomContext);\n // Depend on the STABLE register/unregister callbacks, never the whole\n // context value: the value object changes every time the registry updates\n // (which this very effect triggers), so depending on `ctx` would re-register\n // on every change — an infinite loop. The callbacks are `useCallback([])`.\n const register = ctx?.registerContextualTools;\n const unregister = ctx?.unregisterContextualTools;\n const id = useId();\n useEffect(() => {\n if (!register || !unregister) return undefined;\n register(id, tools);\n return () => unregister(id);\n }, [register, unregister, id, tools]);\n}\n\n/**\n * The merged tool set the rail consumes: contextual tools (auto-tagged\n * `scope: 'contextual'`) then globals (`scope: 'global'`). Scope is assigned\n * here by which API registered the tool — `global` seeds the Control Room's\n * default favourites (pinned on top); `contextual` falls below the divider.\n * `ControlRoomRail` re-groups by favourite membership for the final order.\n * Returns `[]` outside a provider.\n */\nexport function useControlRoomMergedTools(): ToolRailTool[] {\n const ctx = useContext(ControlRoomContext);\n return useMemo(() => {\n if (!ctx) return [];\n const contextual = ctx.contextualTools.map((tool) => ({\n ...tool,\n scope: 'contextual' as const,\n }));\n const global = ctx.globalTools.map((tool) => ({\n ...tool,\n scope: 'global' as const,\n }));\n return [...contextual, ...global];\n }, [ctx]);\n}\n\n/**\n * Imperative actions to drive the rail from a page: open a tool's panel (e.g.\n * the X-ray viewer when a tooth is clicked) or collapse it. No-ops outside a\n * `<ControlRoomProvider>`. The functions are stable across renders.\n */\nexport function useControlRoomActions(): {\n openTool: (id: string) => void;\n closeTool: () => void;\n} {\n const ctx = useContext(ControlRoomContext);\n const noop = useCallback(() => {}, []);\n return {\n openTool: ctx?.openTool ?? noop,\n closeTool: ctx?.closeTool ?? noop,\n };\n}\n\n/**\n * Internal: the rail registers its imperative handle with the provider so\n * `useControlRoomActions().openTool` can drive it. Returns the stable\n * `registerRail` callback (or a no-op outside a provider).\n */\nexport function useControlRoomRailRegister(): (\n handle: ToolRailHandle | null,\n) => void {\n const ctx = useContext(ControlRoomContext);\n const noop = useCallback((_handle: ToolRailHandle | null) => {}, []);\n return ctx?.registerRail ?? noop;\n}\n","import {\n forwardRef,\n useCallback,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { Star, X } from 'lucide-react';\nimport { IconButton } from '../button/icon-button';\nimport { PanelHeaderActionsProvider } from '../panel-header/panel-header';\nimport {\n ToolRail,\n type ToolRailHandle,\n type ToolRailProps,\n type ToolRailTool,\n} from '../tool-rail';\nimport { usePersistentState } from '../../hooks/use-persistent-state';\nimport { controlRoomRailAgent } from './control-room-rail.agent';\nimport {\n useControlRoomMergedTools,\n useControlRoomRailRegister,\n} from './control-room-context';\n\n/* ------------------------------------------------------------------ */\n/* ControlRoomRail — the unified, contextual workspace rail. */\n/* */\n/* The docked right-hand \"Control Room\": the single home for the */\n/* assistant, inbox, notes, appointments and entity summaries */\n/* alongside the main work surface. One panel open at a time, */\n/* non-modal. */\n/* */\n/* It layers a FAVOURITES model over the proven ToolRail (its prior */\n/* name): favourited tools form a pinned group at the TOP of the strip */\n/* above a divider, then everything else below. The default favourites */\n/* are the host's `global` tools (Alia, Inbox) — so the rail opens with */\n/* notifications + Alia on top, the Control Room's default arrangement. */\n/* */\n/* Favouriting is DRAG-FIRST, no per-icon star: drag a tool up across */\n/* the divider to pin it (and drop it where you want in the order), */\n/* drag a favourite back down to unpin. The keyboard equivalent is */\n/* `Alt`+Arrow (crossing the divider pins / unpins, announced). The */\n/* non-drag pointer path — and the discoverable entry point — is an */\n/* add / remove control in each open tool's panel header. */\n/* */\n/* ToolRail stays favourite-agnostic: this layer maps favourite */\n/* membership onto the rail's generic `scope` grouping + (whole-strip) */\n/* `reorderable` run, reads cross-divider moves as pin / unpin, and */\n/* injects the favourite + close controls into the active panel's */\n/* PanelHeader via <PanelHeaderActionsProvider> (no separate header */\n/* row — the controls live inline-end of the panel's title row). */\n/* ------------------------------------------------------------------ */\n\n/** A Control Room tool — the rail tool descriptor, `scope`-aware. */\nexport type ControlRoomTool = ToolRailTool;\n\n/** Imperative handle — open / collapse a tool panel without the DOM. */\nexport type ControlRoomRailHandle = ToolRailHandle;\n\nexport interface ControlRoomRailProps extends Omit<\n ToolRailProps,\n | 'tools'\n | 'onReorder'\n | 'formatReorderAnnouncement'\n | 'renderToolAffordance'\n | 'renderPanelHeader'\n> {\n /**\n * Explicit tool set. Omit to read the merged global + contextual tools from\n * the nearest `<ControlRoomProvider>` (+ `useControlRoomTools`).\n */\n tools?: ControlRoomTool[];\n /**\n * Enable the favourites model: a pinned top group, drag / `Alt`+Arrow\n * reordering, and the panel-header add / remove control. Default `true`. Set\n * `false` for the legacy flat strip (tools render in the order / `scope` you\n * pass, no drag, no panel-header control).\n */\n reorderable?: boolean;\n /**\n * Controlled favourite tool ids, in pinned order. When set, the rail does not\n * persist — the host owns the value and is notified via `onFavoriteIdsChange`.\n */\n favoriteIds?: string[];\n /**\n * HARD-PINNED favourite ids — always rendered at the very START of the\n * pinned group, ahead of (and deduped from) user favourites, in both\n * controlled and uncontrolled modes. Immune to unpin: removing one via\n * the panel-header control or a drag is a no-op (it re-pins on the next\n * render). For tools the product wants permanently one glance away —\n * e.g. notifications at the top of the strip.\n */\n pinnedFavoriteIds?: string[];\n /**\n * Uncontrolled initial favourites. Defaults to the ids of the tools the host\n * marked `scope: 'global'` (Alia, Inbox) — pinning them on top by default.\n */\n defaultFavoriteIds?: string[];\n /** Fires with the next favourites order whenever the user pins / reorders. */\n onFavoriteIdsChange?: (next: string[]) => void;\n /** localStorage key for the uncontrolled favourites. */\n persistFavoritesKey?: string;\n}\n\nexport const ControlRoomRail = forwardRef<\n ControlRoomRailHandle,\n ControlRoomRailProps\n>(function ControlRoomRail(\n {\n tools,\n railLabel,\n reorderable = true,\n favoriteIds,\n defaultFavoriteIds,\n pinnedFavoriteIds,\n onFavoriteIdsChange,\n persistFavoritesKey = 'ui.controlRoom.favorites',\n activeToolId,\n defaultActiveToolId = null,\n onActiveToolChange,\n ...rest\n },\n ref,\n) {\n const { t } = useTranslation();\n\n // Mirror the active tool id so the rail can build the panel-header controls\n // (favourite + close) for whichever tool is open. Controlled hosts own the\n // value via `activeToolId`; otherwise we seed from `defaultActiveToolId` and\n // track subsequent changes through the intercepted `onActiveToolChange`.\n const [activeTracked, setActiveTracked] = useState<string | null>(\n activeToolId ?? defaultActiveToolId ?? null,\n );\n const activeId = activeToolId !== undefined ? activeToolId : activeTracked;\n const handleActiveToolChange = useCallback(\n (id: string | null) => {\n if (activeToolId === undefined) setActiveTracked(id);\n onActiveToolChange?.(id);\n },\n [activeToolId, onActiveToolChange],\n );\n // Provider-driven tools when none are passed explicitly. Calling the hook\n // unconditionally is safe — it returns [] outside a provider.\n const merged = useControlRoomMergedTools();\n const resolved = tools ?? merged;\n\n const isControlled = favoriteIds !== undefined;\n // Uncontrolled favourites persist to localStorage; the lazy initial seeds\n // from the host's `global` tools on first mount only (later tool changes\n // don't re-seed — favourites are user-owned once set). When controlled, the\n // hook is disabled so it never reads or writes storage.\n const [storedFavorites, setStoredFavorites] = usePersistentState<string[]>(\n persistFavoritesKey,\n () =>\n defaultFavoriteIds ??\n resolved.filter((tl) => tl.scope === 'global').map((tl) => tl.id),\n { disabled: isControlled },\n );\n const userFavorites = isControlled ? favoriteIds : storedFavorites;\n /* Hard-pinned ids lead the group every render — user favourites follow,\n deduped. Because the merge happens HERE (not in storage), an unpin\n write simply has no effect on a pinned id. */\n const favorites = useMemo(() => {\n if (!pinnedFavoriteIds?.length) return userFavorites;\n return [\n ...pinnedFavoriteIds,\n ...userFavorites.filter((id) => !pinnedFavoriteIds.includes(id)),\n ];\n }, [pinnedFavoriteIds, userFavorites]);\n\n const byId = useMemo(() => {\n const map = new Map<string, ControlRoomTool>();\n for (const tl of resolved) map.set(tl.id, tl);\n return map;\n }, [resolved]);\n\n // Favourites filtered to currently-present tools — stale ids are ignored\n // (and dropped on the next write).\n const favoriteSet = useMemo(\n () => new Set(favorites.filter((id) => byId.has(id))),\n [favorites, byId],\n );\n\n const updateFavorites = (updater: (prev: string[]) => string[]) => {\n // `updater` must be pure — it is invoked twice (once to compute the\n // reported `next`, once inside the functional setState below).\n const next = updater(favorites.filter((id) => byId.has(id)));\n // Persist via a functional update so rapid pin/reorder events compose\n // (mirrors the Sidebar's useFavorites); controlled hosts own the value.\n if (!isControlled)\n setStoredFavorites((prev) => updater(prev.filter((id) => byId.has(id))));\n onFavoriteIdsChange?.(next);\n };\n\n // Re-group into the pinned run (favourites order, tagged so ToolRail draws\n // the divider) followed by the rest. EVERY tool is `reorderable` so the rail's\n // reorder run spans the whole strip — that's what lets a drag / Alt+Arrow\n // cross the divider; `handleReorder` reads the crossing as pin / unpin.\n const railTools = useMemo<ControlRoomTool[]>(() => {\n if (!reorderable) return resolved;\n const favTools = favorites\n .filter((id) => byId.has(id))\n .map((id) => ({\n ...(byId.get(id) as ControlRoomTool),\n scope: 'global' as const,\n reorderable: true,\n }));\n const rest = resolved\n .filter((tl) => !favoriteSet.has(tl.id))\n .map((tl) => ({\n ...tl,\n scope: 'contextual' as const,\n reorderable: true,\n }));\n return [...favTools, ...rest];\n }, [reorderable, resolved, favorites, byId, favoriteSet]);\n\n // The drag / Alt+Arrow path announces through the rail's own reorder live\n // region; the panel-header button toggles outside it, so it needs its own\n // polite announcement. The zero-width-space toggle forces a re-announce of an\n // identical message (e.g. pin → unpin → pin the same tool).\n const [pinMessage, setPinMessage] = useState('');\n const pinAnnounceToggle = useRef(false);\n const announcePinChange = (label: string, willPin: boolean) => {\n const text = willPin\n ? t('controlRoom.pinnedAnnounce', {\n tool: label,\n defaultValue: 'Pinned {{tool}} to favourites',\n })\n : t('controlRoom.unpinnedAnnounce', {\n tool: label,\n defaultValue: 'Removed {{tool}} from favourites',\n });\n pinAnnounceToggle.current = !pinAnnounceToggle.current;\n setPinMessage(pinAnnounceToggle.current ? text : `${text}\\u200B`);\n };\n\n const togglePin = (id: string) => {\n announcePinChange(byId.get(id)?.label ?? id, !favoriteSet.has(id));\n updateFavorites((prev) =>\n prev.includes(id) ? prev.filter((p) => p !== id) : [...prev, id],\n );\n };\n\n // The rail fires `onReorder` with indices into `railTools` (favourites first,\n // then the rest). The divider sits at `favCount`, so the index either side of\n // it tells us whether a move is a reorder, a pin, an unpin, or a no-op.\n const handleReorder = (from: number, to: number) => {\n const movedId = railTools[from]?.id;\n if (movedId === undefined) return;\n updateFavorites((prev) => {\n const present = prev.filter((id) => byId.has(id));\n const favCount = present.length;\n const wasFav = from < favCount;\n if (wasFav) {\n // Dropped below the divider → unpin.\n if (to >= favCount) return present.filter((id) => id !== movedId);\n // Reorder within favourites (full-strip index == favourites index).\n const next = present.slice();\n next.splice(from, 1);\n next.splice(to, 0, movedId);\n return next;\n }\n // A contextual tool dropped onto / above the divider → pin at that slot.\n if (to <= favCount) {\n const next = present.slice();\n next.splice(Math.min(to, favCount), 0, movedId);\n return next;\n }\n // Contextual → contextual: that group is host-ordered, so nothing to do.\n return prev;\n });\n };\n\n // Membership-aware live-region phrasing for the rail's reorder announcer.\n const formatReorderAnnouncement = ({\n tool,\n from,\n to,\n }: {\n tool: ControlRoomTool;\n from: number;\n to: number;\n }): string => {\n const favCount = favoriteSet.size;\n const wasFav = from < favCount;\n if (wasFav && to >= favCount)\n return t('controlRoom.unpinnedAnnounce', {\n tool: tool.label,\n defaultValue: 'Removed {{tool}} from favourites',\n });\n if (!wasFav && to <= favCount)\n return t('controlRoom.pinnedAnnounce', {\n tool: tool.label,\n defaultValue: 'Pinned {{tool}} to favourites',\n });\n if (wasFav && to < favCount)\n return t('controlRoom.reorderAnnounce', {\n tool: tool.label,\n to: to + 1,\n total: favCount,\n defaultValue: '{{tool}} moved to position {{to}} of {{total}}',\n });\n // Contextual → contextual is a no-op; stay silent.\n return '';\n };\n\n // Register the rail's imperative handle with the provider (so a page's\n // useControlRoomActions().openTool can drive it) AND forward it to the\n // consumer's ref. A callback ref does both; no-op without a provider. We also\n // stash it locally so the injected close control can collapse the panel.\n const railHandleRef = useRef<ToolRailHandle | null>(null);\n const registerRail = useControlRoomRailRegister();\n const setRefs = useCallback(\n (handle: ToolRailHandle | null) => {\n railHandleRef.current = handle;\n registerRail(handle);\n if (typeof ref === 'function') ref(handle);\n else if (ref) ref.current = handle;\n },\n [registerRail, ref],\n );\n\n // The active tool's panel-header controls, injected into its PanelHeader's\n // action cluster (inline-end of the title row) via context — no separate\n // header row. When a tool is open: an icon-only favourite toggle (only when\n // reorderable; pressed state via aria-pressed + the filled star) followed by\n // a close control that collapses the panel. Nothing injected when collapsed\n // or where the panel renders no PanelHeader.\n const activeTool = activeId != null ? (byId.get(activeId) ?? null) : null;\n const injectedActions: ReactNode = activeTool ? (\n <>\n {reorderable\n ? (() => {\n const pinned = favoriteSet.has(activeTool.id);\n return (\n <IconButton\n icon={\n <Star\n aria-hidden=\"true\"\n fill={pinned ? 'currentColor' : 'none'}\n className={\n pinned ? 'ds:text-[color:var(--accent)]' : undefined\n }\n />\n }\n intent=\"ghost\"\n size=\"sm\"\n aria-pressed={pinned}\n aria-label={t('controlRoom.favorite', {\n defaultValue: 'Favourite',\n })}\n onClick={() => togglePin(activeTool.id)}\n />\n );\n })()\n : null}\n <IconButton\n icon={<X aria-hidden=\"true\" />}\n intent=\"ghost\"\n size=\"sm\"\n aria-label={t('controlRoom.close', { defaultValue: 'Close' })}\n onClick={() => railHandleRef.current?.close()}\n />\n </>\n ) : null;\n return (\n <PanelHeaderActionsProvider actions={injectedActions}>\n <ToolRail\n ref={setRefs}\n dataComponent=\"control-room-rail\"\n agentAdapter={controlRoomRailAgent}\n tools={railTools}\n activeToolId={activeToolId}\n defaultActiveToolId={defaultActiveToolId}\n onActiveToolChange={handleActiveToolChange}\n railLabel={\n railLabel ??\n t('controlRoom.railLabel', { defaultValue: 'Control room' })\n }\n onReorder={reorderable ? handleReorder : undefined}\n formatReorderAnnouncement={\n reorderable ? formatReorderAnnouncement : undefined\n }\n {...rest}\n />\n {/* Polite announcement for the panel-header pin / unpin button (the\n drag / Alt+Arrow path announces via the rail's own reorder region). */}\n {reorderable ? (\n <span role=\"status\" aria-live=\"polite\" className=\"ds:sr-only\">\n {pinMessage}\n </span>\n ) : null}\n </PanelHeaderActionsProvider>\n );\n});\n"],"names":["controlRoomRailAgent","handle","args","ControlRoomContext","createContext","ControlRoomProvider","globalTools","children","registry","setRegistry","useState","registerContextualTools","useCallback","id","tools","prev","next","unregisterContextualTools","contextualTools","useMemo","railHandleRef","useRef","registerRail","openTool","_a","closeTool","value","jsx","useControlRoomTools","ctx","useContext","register","unregister","useId","useEffect","useControlRoomMergedTools","contextual","tool","global","useControlRoomActions","noop","useControlRoomRailRegister","_handle","ControlRoomRail","forwardRef","railLabel","reorderable","favoriteIds","defaultFavoriteIds","pinnedFavoriteIds","onFavoriteIdsChange","persistFavoritesKey","activeToolId","defaultActiveToolId","onActiveToolChange","rest","ref","t","useTranslation","activeTracked","setActiveTracked","activeId","handleActiveToolChange","merged","resolved","isControlled","storedFavorites","setStoredFavorites","usePersistentState","tl","userFavorites","favorites","byId","map","favoriteSet","updateFavorites","updater","railTools","favTools","pinMessage","setPinMessage","pinAnnounceToggle","announcePinChange","label","willPin","text","togglePin","p","handleReorder","from","to","movedId","present","favCount","formatReorderAnnouncement","wasFav","setRefs","activeTool","injectedActions","jsxs","Fragment","pinned","IconButton","Star","X","PanelHeaderActionsProvider","ToolRail"],"mappings":"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"}
@@ -4,12 +4,12 @@ import { c as q } from "./index-D2ZczOXr.js";
4
4
  import { useTranslation as z } from "react-i18next";
5
5
  import { u as B } from "./registry-DvAUVLHh.js";
6
6
  import { F as S } from "./form-field-CahJzTxp.js";
7
- import { D as Y } from "./date-picker-Bp64zk2p.js";
7
+ import { D as Y } from "./date-picker-CepI_oI2.js";
8
8
  import { N as H } from "./number-input-Cgu2TtA8.js";
9
9
  import { C as M } from "./card-DPmk26CL.js";
10
10
  import { B as T } from "./badge-sTusUqZD.js";
11
11
  import { I as U } from "./insert-result-LCNTskNJ.js";
12
- import { a as m, c as V } from "./date-picker-variants-pKAJfnWr.js";
12
+ import { a as m, c as V } from "./date-picker-variants-DfuooXEK.js";
13
13
  import { C as J } from "./check-DrFSN__t.js";
14
14
  import { H as Q } from "./heart--qCA4ffe.js";
15
15
  import { c as X } from "./createLucideIcon-DhHxpK9K.js";
@@ -422,4 +422,4 @@ export {
422
422
  ie as L,
423
423
  se as p
424
424
  };
425
- //# sourceMappingURL=cycle-calculator-DzgO1vzP.js.map
425
+ //# sourceMappingURL=cycle-calculator-DmtYGhqq.js.map