@entifix/react-controls 0.18.2 → 0.20.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 (328) hide show
  1. package/README.md +13 -5
  2. package/dist/i18n/catalog/en.d.ts.map +1 -1
  3. package/dist/i18n/catalog/en.js +68 -10
  4. package/dist/i18n/catalog/en.js.map +1 -1
  5. package/dist/i18n/catalog/es.d.ts +76 -5
  6. package/dist/i18n/catalog/es.d.ts.map +1 -1
  7. package/dist/i18n/catalog/es.js +74 -10
  8. package/dist/i18n/catalog/es.js.map +1 -1
  9. package/dist/i18n/catalog/index.d.ts +126 -10
  10. package/dist/i18n/catalog/index.d.ts.map +1 -1
  11. package/dist/i18n/entity-labels.d.ts +14 -0
  12. package/dist/i18n/entity-labels.d.ts.map +1 -1
  13. package/dist/i18n/entity-labels.js +15 -0
  14. package/dist/i18n/entity-labels.js.map +1 -1
  15. package/dist/i18n/i18n-context.js +2 -2
  16. package/dist/i18n/i18n-context.js.map +1 -1
  17. package/dist/index.d.ts +13 -2
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +13 -2
  20. package/dist/index.js.map +1 -1
  21. package/dist/primitives.d.ts +7 -1
  22. package/dist/primitives.d.ts.map +1 -1
  23. package/dist/primitives.js +7 -1
  24. package/dist/primitives.js.map +1 -1
  25. package/dist/theme/index.d.ts +1 -0
  26. package/dist/theme/index.d.ts.map +1 -1
  27. package/dist/theme/index.js +1 -0
  28. package/dist/theme/index.js.map +1 -1
  29. package/dist/theme/theme-context.d.ts +35 -7
  30. package/dist/theme/theme-context.d.ts.map +1 -1
  31. package/dist/theme/theme-context.js +109 -21
  32. package/dist/theme/theme-context.js.map +1 -1
  33. package/dist/theme/theme-cookie.d.ts +9 -0
  34. package/dist/theme/theme-cookie.d.ts.map +1 -0
  35. package/dist/theme/theme-cookie.js +8 -0
  36. package/dist/theme/theme-cookie.js.map +1 -0
  37. package/dist/theme/theme-script.d.ts +8 -5
  38. package/dist/theme/theme-script.d.ts.map +1 -1
  39. package/dist/theme/theme-script.js +24 -10
  40. package/dist/theme/theme-script.js.map +1 -1
  41. package/dist/theme/types.d.ts +19 -3
  42. package/dist/theme/types.d.ts.map +1 -1
  43. package/dist/theme/types.js.map +1 -1
  44. package/dist/ui/actions/action-surfaces.d.ts +1 -1
  45. package/dist/ui/actions/action-surfaces.js +1 -1
  46. package/dist/ui/actions/action-surfaces.js.map +1 -1
  47. package/dist/ui/actions/error-actions.d.ts +32 -0
  48. package/dist/ui/actions/error-actions.d.ts.map +1 -0
  49. package/dist/ui/actions/error-actions.js +40 -0
  50. package/dist/ui/actions/error-actions.js.map +1 -0
  51. package/dist/ui/actions/index.d.ts +2 -0
  52. package/dist/ui/actions/index.d.ts.map +1 -1
  53. package/dist/ui/actions/index.js +2 -0
  54. package/dist/ui/actions/index.js.map +1 -1
  55. package/dist/ui/actions/shortcut.d.ts +13 -0
  56. package/dist/ui/actions/shortcut.d.ts.map +1 -0
  57. package/dist/ui/actions/shortcut.js +18 -0
  58. package/dist/ui/actions/shortcut.js.map +1 -0
  59. package/dist/ui/actions/use-verb-invoker.d.ts +50 -0
  60. package/dist/ui/actions/use-verb-invoker.d.ts.map +1 -0
  61. package/dist/ui/actions/use-verb-invoker.js +93 -0
  62. package/dist/ui/actions/use-verb-invoker.js.map +1 -0
  63. package/dist/ui/atoms/alert/alert-dismiss.d.ts +9 -0
  64. package/dist/ui/atoms/alert/alert-dismiss.d.ts.map +1 -0
  65. package/dist/ui/atoms/alert/alert-dismiss.js +28 -0
  66. package/dist/ui/atoms/alert/alert-dismiss.js.map +1 -0
  67. package/dist/ui/atoms/alert/alert.d.ts +24 -0
  68. package/dist/ui/atoms/alert/alert.d.ts.map +1 -0
  69. package/dist/ui/atoms/alert/alert.js +50 -0
  70. package/dist/ui/atoms/alert/alert.js.map +1 -0
  71. package/dist/ui/atoms/alert/index.d.ts +3 -0
  72. package/dist/ui/atoms/alert/index.d.ts.map +1 -0
  73. package/dist/ui/atoms/alert/index.js +4 -0
  74. package/dist/ui/atoms/alert/index.js.map +1 -0
  75. package/dist/ui/atoms/alert/tone.d.ts +8 -0
  76. package/dist/ui/atoms/alert/tone.d.ts.map +1 -0
  77. package/dist/ui/atoms/alert/tone.js +11 -0
  78. package/dist/ui/atoms/alert/tone.js.map +1 -0
  79. package/dist/ui/atoms/button/button-recipe.js +1 -1
  80. package/dist/ui/atoms/button/button-recipe.js.map +1 -1
  81. package/dist/ui/atoms/button/index.d.ts +1 -0
  82. package/dist/ui/atoms/button/index.d.ts.map +1 -1
  83. package/dist/ui/atoms/button/index.js +1 -0
  84. package/dist/ui/atoms/button/index.js.map +1 -1
  85. package/dist/ui/atoms/button/submit-button.d.ts +13 -0
  86. package/dist/ui/atoms/button/submit-button.d.ts.map +1 -0
  87. package/dist/ui/atoms/button/submit-button.js +29 -0
  88. package/dist/ui/atoms/button/submit-button.js.map +1 -0
  89. package/dist/ui/atoms/cell-value/cell-value.d.ts +6 -1
  90. package/dist/ui/atoms/cell-value/cell-value.d.ts.map +1 -1
  91. package/dist/ui/atoms/cell-value/cell-value.js +48 -16
  92. package/dist/ui/atoms/cell-value/cell-value.js.map +1 -1
  93. package/dist/ui/atoms/field/checkbox.d.ts.map +1 -1
  94. package/dist/ui/atoms/field/checkbox.js +21 -1
  95. package/dist/ui/atoms/field/checkbox.js.map +1 -1
  96. package/dist/ui/atoms/field/field.js +1 -1
  97. package/dist/ui/atoms/field/field.js.map +1 -1
  98. package/dist/ui/atoms/field-control/field-control.d.ts +7 -1
  99. package/dist/ui/atoms/field-control/field-control.d.ts.map +1 -1
  100. package/dist/ui/atoms/field-control/field-control.js +25 -3
  101. package/dist/ui/atoms/field-control/field-control.js.map +1 -1
  102. package/dist/ui/atoms/money/index.d.ts +4 -0
  103. package/dist/ui/atoms/money/index.d.ts.map +1 -0
  104. package/dist/ui/atoms/money/index.js +5 -0
  105. package/dist/ui/atoms/money/index.js.map +1 -0
  106. package/dist/ui/atoms/money/money-input.d.ts +19 -0
  107. package/dist/ui/atoms/money/money-input.d.ts.map +1 -0
  108. package/dist/ui/atoms/money/money-input.js +75 -0
  109. package/dist/ui/atoms/money/money-input.js.map +1 -0
  110. package/dist/ui/atoms/money/money-math.d.ts +21 -0
  111. package/dist/ui/atoms/money/money-math.d.ts.map +1 -0
  112. package/dist/ui/atoms/money/money-math.js +36 -0
  113. package/dist/ui/atoms/money/money-math.js.map +1 -0
  114. package/dist/ui/atoms/money/money.d.ts +19 -0
  115. package/dist/ui/atoms/money/money.d.ts.map +1 -0
  116. package/dist/ui/atoms/money/money.js +26 -0
  117. package/dist/ui/atoms/money/money.js.map +1 -0
  118. package/dist/ui/atoms/number-input/index.d.ts +3 -0
  119. package/dist/ui/atoms/number-input/index.d.ts.map +1 -0
  120. package/dist/ui/atoms/number-input/index.js +4 -0
  121. package/dist/ui/atoms/number-input/index.js.map +1 -0
  122. package/dist/ui/atoms/number-input/number-input.d.ts +10 -0
  123. package/dist/ui/atoms/number-input/number-input.d.ts.map +1 -0
  124. package/dist/ui/atoms/number-input/number-input.js +23 -0
  125. package/dist/ui/atoms/number-input/number-input.js.map +1 -0
  126. package/dist/ui/atoms/number-input/quantity-input.d.ts +29 -0
  127. package/dist/ui/atoms/number-input/quantity-input.d.ts.map +1 -0
  128. package/dist/ui/atoms/number-input/quantity-input.js +100 -0
  129. package/dist/ui/atoms/number-input/quantity-input.js.map +1 -0
  130. package/dist/ui/atoms/skeleton/skeleton.js +1 -1
  131. package/dist/ui/atoms/skeleton/skeleton.js.map +1 -1
  132. package/dist/ui/atoms/status-tag/index.d.ts +2 -0
  133. package/dist/ui/atoms/status-tag/index.d.ts.map +1 -0
  134. package/dist/ui/atoms/status-tag/index.js +3 -0
  135. package/dist/ui/atoms/status-tag/index.js.map +1 -0
  136. package/dist/ui/atoms/status-tag/status-tag.d.ts +17 -0
  137. package/dist/ui/atoms/status-tag/status-tag.d.ts.map +1 -0
  138. package/dist/ui/atoms/status-tag/status-tag.js +37 -0
  139. package/dist/ui/atoms/status-tag/status-tag.js.map +1 -0
  140. package/dist/ui/atoms/switch/switch.d.ts.map +1 -1
  141. package/dist/ui/atoms/switch/switch.js +6 -3
  142. package/dist/ui/atoms/switch/switch.js.map +1 -1
  143. package/dist/ui/atoms/table/table.d.ts +12 -3
  144. package/dist/ui/atoms/table/table.d.ts.map +1 -1
  145. package/dist/ui/atoms/table/table.js +59 -10
  146. package/dist/ui/atoms/table/table.js.map +1 -1
  147. package/dist/ui/atoms/text/text.d.ts +2 -2
  148. package/dist/ui/atoms/text/text.d.ts.map +1 -1
  149. package/dist/ui/atoms/text/text.js.map +1 -1
  150. package/dist/ui/molecules/action-bar/action-bar.d.ts +76 -0
  151. package/dist/ui/molecules/action-bar/action-bar.d.ts.map +1 -0
  152. package/dist/ui/molecules/action-bar/action-bar.js +218 -0
  153. package/dist/ui/molecules/action-bar/action-bar.js.map +1 -0
  154. package/dist/ui/molecules/action-bar/index.d.ts +2 -0
  155. package/dist/ui/molecules/action-bar/index.d.ts.map +1 -0
  156. package/dist/ui/molecules/action-bar/index.js +3 -0
  157. package/dist/ui/molecules/action-bar/index.js.map +1 -0
  158. package/dist/ui/molecules/breadcrumbs/breadcrumbs.d.ts +11 -2
  159. package/dist/ui/molecules/breadcrumbs/breadcrumbs.d.ts.map +1 -1
  160. package/dist/ui/molecules/breadcrumbs/breadcrumbs.js +9 -7
  161. package/dist/ui/molecules/breadcrumbs/breadcrumbs.js.map +1 -1
  162. package/dist/ui/molecules/bulk-action-bar/bulk-action-bar.d.ts.map +1 -1
  163. package/dist/ui/molecules/bulk-action-bar/bulk-action-bar.js +8 -10
  164. package/dist/ui/molecules/bulk-action-bar/bulk-action-bar.js.map +1 -1
  165. package/dist/ui/molecules/bulk-result/bulk-result.d.ts +3 -3
  166. package/dist/ui/molecules/bulk-result/bulk-result.js +4 -4
  167. package/dist/ui/molecules/bulk-result/bulk-result.js.map +1 -1
  168. package/dist/ui/molecules/column-settings/column-settings.js +1 -1
  169. package/dist/ui/molecules/column-settings/column-settings.js.map +1 -1
  170. package/dist/ui/molecules/confirm-dialog/confirm-dialog.d.ts +24 -9
  171. package/dist/ui/molecules/confirm-dialog/confirm-dialog.d.ts.map +1 -1
  172. package/dist/ui/molecules/confirm-dialog/confirm-dialog.js +38 -13
  173. package/dist/ui/molecules/confirm-dialog/confirm-dialog.js.map +1 -1
  174. package/dist/ui/molecules/description-list/description-list.d.ts +17 -0
  175. package/dist/ui/molecules/description-list/description-list.d.ts.map +1 -0
  176. package/dist/ui/molecules/description-list/description-list.js +36 -0
  177. package/dist/ui/molecules/description-list/description-list.js.map +1 -0
  178. package/dist/ui/molecules/description-list/index.d.ts +2 -0
  179. package/dist/ui/molecules/description-list/index.d.ts.map +1 -0
  180. package/dist/ui/molecules/description-list/index.js +3 -0
  181. package/dist/ui/molecules/description-list/index.js.map +1 -0
  182. package/dist/ui/molecules/drawer/drawer.js +3 -3
  183. package/dist/ui/molecules/drawer/drawer.js.map +1 -1
  184. package/dist/ui/molecules/empty-state/empty-state.d.ts +15 -0
  185. package/dist/ui/molecules/empty-state/empty-state.d.ts.map +1 -0
  186. package/dist/ui/molecules/empty-state/empty-state.js +29 -0
  187. package/dist/ui/molecules/empty-state/empty-state.js.map +1 -0
  188. package/dist/ui/molecules/empty-state/index.d.ts +2 -0
  189. package/dist/ui/molecules/empty-state/index.d.ts.map +1 -0
  190. package/dist/ui/molecules/empty-state/index.js +3 -0
  191. package/dist/ui/molecules/empty-state/index.js.map +1 -0
  192. package/dist/ui/molecules/entity-link-input/entity-link-input.d.ts.map +1 -1
  193. package/dist/ui/molecules/entity-link-input/entity-link-input.js +7 -4
  194. package/dist/ui/molecules/entity-link-input/entity-link-input.js.map +1 -1
  195. package/dist/ui/molecules/entity-link-picker/entity-link-picker.js +2 -2
  196. package/dist/ui/molecules/entity-link-picker/entity-link-picker.js.map +1 -1
  197. package/dist/ui/molecules/entity-record-card/entity-record-card.d.ts +33 -20
  198. package/dist/ui/molecules/entity-record-card/entity-record-card.d.ts.map +1 -1
  199. package/dist/ui/molecules/entity-record-card/entity-record-card.js +53 -20
  200. package/dist/ui/molecules/entity-record-card/entity-record-card.js.map +1 -1
  201. package/dist/ui/molecules/filter-builder/filter-builder.d.ts +8 -2
  202. package/dist/ui/molecules/filter-builder/filter-builder.d.ts.map +1 -1
  203. package/dist/ui/molecules/filter-builder/filter-builder.js +14 -5
  204. package/dist/ui/molecules/filter-builder/filter-builder.js.map +1 -1
  205. package/dist/ui/molecules/filter-chips/filter-chips.d.ts +16 -0
  206. package/dist/ui/molecules/filter-chips/filter-chips.d.ts.map +1 -0
  207. package/dist/ui/molecules/filter-chips/filter-chips.js +73 -0
  208. package/dist/ui/molecules/filter-chips/filter-chips.js.map +1 -0
  209. package/dist/ui/molecules/filter-chips/index.d.ts +2 -0
  210. package/dist/ui/molecules/filter-chips/index.d.ts.map +1 -0
  211. package/dist/ui/molecules/filter-chips/index.js +3 -0
  212. package/dist/ui/molecules/filter-chips/index.js.map +1 -0
  213. package/dist/ui/molecules/media-gallery/index.d.ts +2 -0
  214. package/dist/ui/molecules/media-gallery/index.d.ts.map +1 -0
  215. package/dist/ui/molecules/media-gallery/index.js +3 -0
  216. package/dist/ui/molecules/media-gallery/index.js.map +1 -0
  217. package/dist/ui/molecules/media-gallery/media-gallery.d.ts +31 -0
  218. package/dist/ui/molecules/media-gallery/media-gallery.d.ts.map +1 -0
  219. package/dist/ui/molecules/media-gallery/media-gallery.js +64 -0
  220. package/dist/ui/molecules/media-gallery/media-gallery.js.map +1 -0
  221. package/dist/ui/molecules/menu/menu.d.ts +11 -1
  222. package/dist/ui/molecules/menu/menu.d.ts.map +1 -1
  223. package/dist/ui/molecules/menu/menu.js +68 -6
  224. package/dist/ui/molecules/menu/menu.js.map +1 -1
  225. package/dist/ui/molecules/nav-menu/nav-menu.js +4 -4
  226. package/dist/ui/molecules/nav-menu/nav-menu.js.map +1 -1
  227. package/dist/ui/molecules/pagination/pagination.d.ts +5 -0
  228. package/dist/ui/molecules/pagination/pagination.d.ts.map +1 -1
  229. package/dist/ui/molecules/pagination/pagination.js +35 -18
  230. package/dist/ui/molecules/pagination/pagination.js.map +1 -1
  231. package/dist/ui/molecules/region-state/index.d.ts +2 -0
  232. package/dist/ui/molecules/region-state/index.d.ts.map +1 -0
  233. package/dist/ui/molecules/region-state/index.js +3 -0
  234. package/dist/ui/molecules/region-state/index.js.map +1 -0
  235. package/dist/ui/molecules/region-state/region-state.d.ts +42 -0
  236. package/dist/ui/molecules/region-state/region-state.d.ts.map +1 -0
  237. package/dist/ui/molecules/region-state/region-state.js +83 -0
  238. package/dist/ui/molecules/region-state/region-state.js.map +1 -0
  239. package/dist/ui/molecules/segmented-nav/segment-classes.d.ts +3 -3
  240. package/dist/ui/molecules/segmented-nav/segment-classes.d.ts.map +1 -1
  241. package/dist/ui/molecules/segmented-nav/segment-classes.js +2 -2
  242. package/dist/ui/molecules/segmented-nav/segment-classes.js.map +1 -1
  243. package/dist/ui/molecules/segmented-nav/segmented-nav.d.ts +14 -4
  244. package/dist/ui/molecules/segmented-nav/segmented-nav.d.ts.map +1 -1
  245. package/dist/ui/molecules/segmented-nav/segmented-nav.js +6 -5
  246. package/dist/ui/molecules/segmented-nav/segmented-nav.js.map +1 -1
  247. package/dist/ui/molecules/split-view/split-view.js +3 -3
  248. package/dist/ui/molecules/split-view/split-view.js.map +1 -1
  249. package/dist/ui/molecules/tab-strip/tab-strip.d.ts +51 -12
  250. package/dist/ui/molecules/tab-strip/tab-strip.d.ts.map +1 -1
  251. package/dist/ui/molecules/tab-strip/tab-strip.js +125 -34
  252. package/dist/ui/molecules/tab-strip/tab-strip.js.map +1 -1
  253. package/dist/ui/molecules/table-toolbar/table-toolbar.d.ts +3 -1
  254. package/dist/ui/molecules/table-toolbar/table-toolbar.d.ts.map +1 -1
  255. package/dist/ui/molecules/table-toolbar/table-toolbar.js +3 -2
  256. package/dist/ui/molecules/table-toolbar/table-toolbar.js.map +1 -1
  257. package/dist/ui/molecules/toast-region/toast-region.d.ts +63 -19
  258. package/dist/ui/molecules/toast-region/toast-region.d.ts.map +1 -1
  259. package/dist/ui/molecules/toast-region/toast-region.js +129 -42
  260. package/dist/ui/molecules/toast-region/toast-region.js.map +1 -1
  261. package/dist/ui/organisms/command-palette/command-palette.d.ts.map +1 -1
  262. package/dist/ui/organisms/command-palette/command-palette.js +25 -18
  263. package/dist/ui/organisms/command-palette/command-palette.js.map +1 -1
  264. package/dist/ui/organisms/entity-detail-grid/entity-detail-grid.d.ts.map +1 -1
  265. package/dist/ui/organisms/entity-detail-grid/entity-detail-grid.js +8 -3
  266. package/dist/ui/organisms/entity-detail-grid/entity-detail-grid.js.map +1 -1
  267. package/dist/ui/organisms/entity-form/entity-form.d.ts +1 -1
  268. package/dist/ui/organisms/entity-form/entity-form.d.ts.map +1 -1
  269. package/dist/ui/organisms/entity-form/entity-form.js +325 -215
  270. package/dist/ui/organisms/entity-form/entity-form.js.map +1 -1
  271. package/dist/ui/organisms/entity-form/entity-form.types.d.ts +8 -0
  272. package/dist/ui/organisms/entity-form/entity-form.types.d.ts.map +1 -1
  273. package/dist/ui/organisms/entity-form/entity-form.types.js.map +1 -1
  274. package/dist/ui/organisms/entity-table/entity-table.d.ts +1 -1
  275. package/dist/ui/organisms/entity-table/entity-table.d.ts.map +1 -1
  276. package/dist/ui/organisms/entity-table/entity-table.js +334 -198
  277. package/dist/ui/organisms/entity-table/entity-table.js.map +1 -1
  278. package/dist/ui/organisms/entity-table/entity-table.types.d.ts +19 -4
  279. package/dist/ui/organisms/entity-table/entity-table.types.d.ts.map +1 -1
  280. package/dist/ui/organisms/entity-table/entity-table.types.js.map +1 -1
  281. package/dist/ui/organisms/entity-table/header-sort.d.ts +18 -0
  282. package/dist/ui/organisms/entity-table/header-sort.d.ts.map +1 -0
  283. package/dist/ui/organisms/entity-table/header-sort.js +54 -0
  284. package/dist/ui/organisms/entity-table/header-sort.js.map +1 -0
  285. package/dist/ui/organisms/entity-table/pivot.d.ts +25 -0
  286. package/dist/ui/organisms/entity-table/pivot.d.ts.map +1 -0
  287. package/dist/ui/organisms/entity-table/pivot.js +106 -0
  288. package/dist/ui/organisms/entity-table/pivot.js.map +1 -0
  289. package/dist/ui/organisms/entity-table/use-result-announcement.d.ts +13 -0
  290. package/dist/ui/organisms/entity-table/use-result-announcement.d.ts.map +1 -0
  291. package/dist/ui/organisms/entity-table/use-result-announcement.js +31 -0
  292. package/dist/ui/organisms/entity-table/use-result-announcement.js.map +1 -0
  293. package/dist/ui/organisms/top-bar/live-indicator.d.ts +11 -0
  294. package/dist/ui/organisms/top-bar/live-indicator.d.ts.map +1 -0
  295. package/dist/ui/organisms/top-bar/live-indicator.js +46 -0
  296. package/dist/ui/organisms/top-bar/live-indicator.js.map +1 -0
  297. package/dist/ui/organisms/top-bar/top-bar.d.ts +11 -2
  298. package/dist/ui/organisms/top-bar/top-bar.d.ts.map +1 -1
  299. package/dist/ui/organisms/top-bar/top-bar.js +14 -5
  300. package/dist/ui/organisms/top-bar/top-bar.js.map +1 -1
  301. package/dist/ui/organisms/wizard/wizard.d.ts +1 -1
  302. package/dist/ui/organisms/wizard/wizard.d.ts.map +1 -1
  303. package/dist/ui/organisms/wizard/wizard.js +7 -1
  304. package/dist/ui/organisms/wizard/wizard.js.map +1 -1
  305. package/dist/ui/organisms/wizard/wizard.types.d.ts +8 -0
  306. package/dist/ui/organisms/wizard/wizard.types.d.ts.map +1 -1
  307. package/dist/ui/organisms/wizard/wizard.types.js.map +1 -1
  308. package/dist/ui/utils/live-updates.d.ts +24 -0
  309. package/dist/ui/utils/live-updates.d.ts.map +1 -0
  310. package/dist/ui/utils/live-updates.js +20 -0
  311. package/dist/ui/utils/live-updates.js.map +1 -0
  312. package/dist/ui/utils/use-focus-on-arrival.d.ts +14 -0
  313. package/dist/ui/utils/use-focus-on-arrival.d.ts.map +1 -0
  314. package/dist/ui/utils/use-focus-on-arrival.js +42 -0
  315. package/dist/ui/utils/use-focus-on-arrival.js.map +1 -0
  316. package/dist/ui/utils/use-hotkey.d.ts +44 -25
  317. package/dist/ui/utils/use-hotkey.d.ts.map +1 -1
  318. package/dist/ui/utils/use-hotkey.js +80 -48
  319. package/dist/ui/utils/use-hotkey.js.map +1 -1
  320. package/package.json +5 -5
  321. package/dist/ui/molecules/split-button/index.d.ts +0 -2
  322. package/dist/ui/molecules/split-button/index.d.ts.map +0 -1
  323. package/dist/ui/molecules/split-button/index.js +0 -3
  324. package/dist/ui/molecules/split-button/index.js.map +0 -1
  325. package/dist/ui/molecules/split-button/split-button.d.ts +0 -21
  326. package/dist/ui/molecules/split-button/split-button.d.ts.map +0 -1
  327. package/dist/ui/molecules/split-button/split-button.js +0 -35
  328. package/dist/ui/molecules/split-button/split-button.js.map +0 -1
@@ -25,10 +25,14 @@
25
25
  export * from './i18n/index.js';
26
26
  export * from './theme/index.js';
27
27
  // Atoms — text, buttons, fields, tables, loading placeholders.
28
+ export * from './ui/atoms/alert/index.js';
28
29
  export * from './ui/atoms/button/index.js';
29
30
  export * from './ui/atoms/external-link/index.js';
30
31
  export * from './ui/atoms/field/index.js';
32
+ export * from './ui/atoms/money/index.js';
33
+ export * from './ui/atoms/number-input/index.js';
31
34
  export * from './ui/atoms/skeleton/index.js';
35
+ export * from './ui/atoms/status-tag/index.js';
32
36
  export * from './ui/atoms/switch/index.js';
33
37
  export * from './ui/atoms/table/index.js';
34
38
  export * from './ui/atoms/text/index.js';
@@ -45,13 +49,15 @@ export * from './ui/layout/switcher/index.js';
45
49
  export * from './ui/molecules/breadcrumbs/index.js';
46
50
  export * from './ui/molecules/card/index.js';
47
51
  export * from './ui/molecules/confirm-dialog/index.js';
52
+ export * from './ui/molecules/description-list/index.js';
53
+ export * from './ui/molecules/empty-state/index.js';
48
54
  export * from './ui/molecules/loading-boundary/index.js';
55
+ export * from './ui/molecules/media-gallery/index.js';
49
56
  export * from './ui/molecules/menu/index.js';
50
57
  export * from './ui/molecules/nav-menu/index.js';
51
58
  export * from './ui/molecules/pagination/index.js';
52
59
  export * from './ui/molecules/segmented-control/index.js';
53
60
  export * from './ui/molecules/segmented-nav/index.js';
54
- export * from './ui/molecules/split-button/index.js';
55
61
  export * from './ui/molecules/split-view/index.js';
56
62
  export * from './ui/molecules/stack/index.js';
57
63
  export * from './ui/molecules/tab-strip/index.js';
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/primitives.ts"],"sourcesContent":["// The entity-free half of the design system, published as\n// `@entifix/react-controls/primitives`.\n//\n// It exists because the package's main barrel is one flat re-export of\n// everything, and a bundler cannot drop what a module graph reaches: a\n// storefront page importing `Card` from `.` pulled `EntityTable`,\n// `FilterBuilder`, `SortBuilder`, `ColumnSettings` and the RSQL machinery\n// behind them into its client bundle — 541 KB of back-office UI shipped to a\n// visitor looking at a product.\n//\n// The line drawn here is not \"small vs large\", it is **presentational vs\n// entity-aware**: everything below can be understood without knowing what an\n// entity is. Anything that reads entity metadata (`CellValue`, `FieldControl`,\n// `EntityTable`, `EntityForm`, the filter/sort/column builders, the link\n// inputs) stays behind the main entry, where the back-office already imports it.\n//\n// Consumers that need both may import both; nothing is duplicated, and the main\n// barrel keeps re-exporting all of this so no existing import breaks.\n\n// Providers every app mounts, whatever it renders.\n//\n// `./preferences` is deliberately **not** here. The UI-preferences store is\n// backed by Effect `Layer`s, so re-exporting it drags the whole Effect runtime\n// into the browser — and what it remembers (column visibility, table density)\n// only exists in the back-office. A storefront has no preferences to store.\nexport * from './i18n/index.js';\nexport * from './theme/index.js';\n\n// Atoms — text, buttons, fields, tables, loading placeholders.\nexport * from './ui/atoms/button/index.js';\nexport * from './ui/atoms/external-link/index.js';\nexport * from './ui/atoms/field/index.js';\nexport * from './ui/atoms/skeleton/index.js';\nexport * from './ui/atoms/switch/index.js';\nexport * from './ui/atoms/table/index.js';\nexport * from './ui/atoms/text/index.js';\n\n// Layout primitives (Every Layout): flex-first, with `Grid` the one CSS-Grid\n// escape hatch.\nexport * from './ui/layout/box/index.js';\nexport * from './ui/layout/center/index.js';\nexport * from './ui/layout/cluster/index.js';\nexport * from './ui/layout/cover/index.js';\nexport * from './ui/layout/grid/index.js';\nexport * from './ui/layout/sidebar/index.js';\nexport * from './ui/layout/switcher/index.js';\n\n// Molecules that compose the above and nothing else.\nexport * from './ui/molecules/breadcrumbs/index.js';\nexport * from './ui/molecules/card/index.js';\nexport * from './ui/molecules/confirm-dialog/index.js';\nexport * from './ui/molecules/loading-boundary/index.js';\nexport * from './ui/molecules/menu/index.js';\nexport * from './ui/molecules/nav-menu/index.js';\nexport * from './ui/molecules/pagination/index.js';\nexport * from './ui/molecules/segmented-control/index.js';\nexport * from './ui/molecules/segmented-nav/index.js';\nexport * from './ui/molecules/split-button/index.js';\nexport * from './ui/molecules/split-view/index.js';\nexport * from './ui/molecules/stack/index.js';\nexport * from './ui/molecules/tab-strip/index.js';\nexport * from './ui/molecules/theme-switcher/index.js';\nexport * from './ui/utils/active-heading/index.js';\nexport * from './ui/utils/active-section/index.js';\nexport * from './ui/utils/cn.js';\nexport * from './ui/utils/fold-script/index.js';\nexport * from './ui/utils/keep-section/index.js';\nexport * from './ui/utils/media-query/index.js';\n"],"names":[],"mappings":"AAAA,0DAA0D;AAC1D,wCAAwC;AACxC,EAAE;AACF,uEAAuE;AACvE,uEAAuE;AACvE,kEAAkE;AAClE,0EAA0E;AAC1E,6EAA6E;AAC7E,gCAAgC;AAChC,EAAE;AACF,yEAAyE;AACzE,6EAA6E;AAC7E,+EAA+E;AAC/E,yEAAyE;AACzE,iFAAiF;AACjF,EAAE;AACF,gFAAgF;AAChF,sEAAsE;AAEtE,mDAAmD;AACnD,EAAE;AACF,4EAA4E;AAC5E,+EAA+E;AAC/E,8EAA8E;AAC9E,4EAA4E;AAC5E,cAAc,kBAAkB;AAChC,cAAc,mBAAmB;AAEjC,+DAA+D;AAC/D,cAAc,6BAA6B;AAC3C,cAAc,oCAAoC;AAClD,cAAc,4BAA4B;AAC1C,cAAc,+BAA+B;AAC7C,cAAc,6BAA6B;AAC3C,cAAc,4BAA4B;AAC1C,cAAc,2BAA2B;AAEzC,6EAA6E;AAC7E,gBAAgB;AAChB,cAAc,2BAA2B;AACzC,cAAc,8BAA8B;AAC5C,cAAc,+BAA+B;AAC7C,cAAc,6BAA6B;AAC3C,cAAc,4BAA4B;AAC1C,cAAc,+BAA+B;AAC7C,cAAc,gCAAgC;AAE9C,qDAAqD;AACrD,cAAc,sCAAsC;AACpD,cAAc,+BAA+B;AAC7C,cAAc,yCAAyC;AACvD,cAAc,2CAA2C;AACzD,cAAc,+BAA+B;AAC7C,cAAc,mCAAmC;AACjD,cAAc,qCAAqC;AACnD,cAAc,4CAA4C;AAC1D,cAAc,wCAAwC;AACtD,cAAc,uCAAuC;AACrD,cAAc,qCAAqC;AACnD,cAAc,gCAAgC;AAC9C,cAAc,oCAAoC;AAClD,cAAc,yCAAyC;AACvD,cAAc,qCAAqC;AACnD,cAAc,qCAAqC;AACnD,cAAc,mBAAmB;AACjC,cAAc,kCAAkC;AAChD,cAAc,mCAAmC;AACjD,cAAc,kCAAkC"}
1
+ {"version":3,"sources":["../src/primitives.ts"],"sourcesContent":["// The entity-free half of the design system, published as\n// `@entifix/react-controls/primitives`.\n//\n// It exists because the package's main barrel is one flat re-export of\n// everything, and a bundler cannot drop what a module graph reaches: a\n// storefront page importing `Card` from `.` pulled `EntityTable`,\n// `FilterBuilder`, `SortBuilder`, `ColumnSettings` and the RSQL machinery\n// behind them into its client bundle — 541 KB of back-office UI shipped to a\n// visitor looking at a product.\n//\n// The line drawn here is not \"small vs large\", it is **presentational vs\n// entity-aware**: everything below can be understood without knowing what an\n// entity is. Anything that reads entity metadata (`CellValue`, `FieldControl`,\n// `EntityTable`, `EntityForm`, the filter/sort/column builders, the link\n// inputs) stays behind the main entry, where the back-office already imports it.\n//\n// Consumers that need both may import both; nothing is duplicated, and the main\n// barrel keeps re-exporting all of this so no existing import breaks.\n\n// Providers every app mounts, whatever it renders.\n//\n// `./preferences` is deliberately **not** here. The UI-preferences store is\n// backed by Effect `Layer`s, so re-exporting it drags the whole Effect runtime\n// into the browser — and what it remembers (column visibility, table density)\n// only exists in the back-office. A storefront has no preferences to store.\nexport * from './i18n/index.js';\nexport * from './theme/index.js';\n\n// Atoms — text, buttons, fields, tables, loading placeholders.\nexport * from './ui/atoms/alert/index.js';\nexport * from './ui/atoms/button/index.js';\nexport * from './ui/atoms/external-link/index.js';\nexport * from './ui/atoms/field/index.js';\nexport * from './ui/atoms/money/index.js';\nexport * from './ui/atoms/number-input/index.js';\nexport * from './ui/atoms/skeleton/index.js';\nexport * from './ui/atoms/status-tag/index.js';\nexport * from './ui/atoms/switch/index.js';\nexport * from './ui/atoms/table/index.js';\nexport * from './ui/atoms/text/index.js';\n\n// Layout primitives (Every Layout): flex-first, with `Grid` the one CSS-Grid\n// escape hatch.\nexport * from './ui/layout/box/index.js';\nexport * from './ui/layout/center/index.js';\nexport * from './ui/layout/cluster/index.js';\nexport * from './ui/layout/cover/index.js';\nexport * from './ui/layout/grid/index.js';\nexport * from './ui/layout/sidebar/index.js';\nexport * from './ui/layout/switcher/index.js';\n\n// Molecules that compose the above and nothing else.\nexport * from './ui/molecules/breadcrumbs/index.js';\nexport * from './ui/molecules/card/index.js';\nexport * from './ui/molecules/confirm-dialog/index.js';\nexport * from './ui/molecules/description-list/index.js';\nexport * from './ui/molecules/empty-state/index.js';\nexport * from './ui/molecules/loading-boundary/index.js';\nexport * from './ui/molecules/media-gallery/index.js';\nexport * from './ui/molecules/menu/index.js';\nexport * from './ui/molecules/nav-menu/index.js';\nexport * from './ui/molecules/pagination/index.js';\nexport * from './ui/molecules/segmented-control/index.js';\nexport * from './ui/molecules/segmented-nav/index.js';\nexport * from './ui/molecules/split-view/index.js';\nexport * from './ui/molecules/stack/index.js';\nexport * from './ui/molecules/tab-strip/index.js';\nexport * from './ui/molecules/theme-switcher/index.js';\nexport * from './ui/utils/active-heading/index.js';\nexport * from './ui/utils/active-section/index.js';\nexport * from './ui/utils/cn.js';\nexport * from './ui/utils/fold-script/index.js';\nexport * from './ui/utils/keep-section/index.js';\nexport * from './ui/utils/media-query/index.js';\n"],"names":[],"mappings":"AAAA,0DAA0D;AAC1D,wCAAwC;AACxC,EAAE;AACF,uEAAuE;AACvE,uEAAuE;AACvE,kEAAkE;AAClE,0EAA0E;AAC1E,6EAA6E;AAC7E,gCAAgC;AAChC,EAAE;AACF,yEAAyE;AACzE,6EAA6E;AAC7E,+EAA+E;AAC/E,yEAAyE;AACzE,iFAAiF;AACjF,EAAE;AACF,gFAAgF;AAChF,sEAAsE;AAEtE,mDAAmD;AACnD,EAAE;AACF,4EAA4E;AAC5E,+EAA+E;AAC/E,8EAA8E;AAC9E,4EAA4E;AAC5E,cAAc,kBAAkB;AAChC,cAAc,mBAAmB;AAEjC,+DAA+D;AAC/D,cAAc,4BAA4B;AAC1C,cAAc,6BAA6B;AAC3C,cAAc,oCAAoC;AAClD,cAAc,4BAA4B;AAC1C,cAAc,4BAA4B;AAC1C,cAAc,mCAAmC;AACjD,cAAc,+BAA+B;AAC7C,cAAc,iCAAiC;AAC/C,cAAc,6BAA6B;AAC3C,cAAc,4BAA4B;AAC1C,cAAc,2BAA2B;AAEzC,6EAA6E;AAC7E,gBAAgB;AAChB,cAAc,2BAA2B;AACzC,cAAc,8BAA8B;AAC5C,cAAc,+BAA+B;AAC7C,cAAc,6BAA6B;AAC3C,cAAc,4BAA4B;AAC1C,cAAc,+BAA+B;AAC7C,cAAc,gCAAgC;AAE9C,qDAAqD;AACrD,cAAc,sCAAsC;AACpD,cAAc,+BAA+B;AAC7C,cAAc,yCAAyC;AACvD,cAAc,2CAA2C;AACzD,cAAc,sCAAsC;AACpD,cAAc,2CAA2C;AACzD,cAAc,wCAAwC;AACtD,cAAc,+BAA+B;AAC7C,cAAc,mCAAmC;AACjD,cAAc,qCAAqC;AACnD,cAAc,4CAA4C;AAC1D,cAAc,wCAAwC;AACtD,cAAc,qCAAqC;AACnD,cAAc,gCAAgC;AAC9C,cAAc,oCAAoC;AAClD,cAAc,yCAAyC;AACvD,cAAc,qCAAqC;AACnD,cAAc,qCAAqC;AACnD,cAAc,mBAAmB;AACjC,cAAc,kCAAkC;AAChD,cAAc,mCAAmC;AACjD,cAAc,kCAAkC"}
@@ -1,4 +1,5 @@
1
1
  export * from './theme-context.js';
2
+ export * from './theme-cookie.js';
2
3
  export * from './theme-script.js';
3
4
  export * from './types.js';
4
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/theme/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/theme/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,YAAY,CAAC"}
@@ -1,4 +1,5 @@
1
1
  export * from './theme-context.js';
2
+ export * from './theme-cookie.js';
2
3
  export * from './theme-script.js';
3
4
  export * from './types.js';
4
5
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/theme/index.ts"],"sourcesContent":["export * from './theme-context.js';\nexport * from './theme-script.js';\nexport * from './types.js';\n"],"names":[],"mappings":"AAAA,cAAc,qBAAqB;AACnC,cAAc,oBAAoB;AAClC,cAAc,aAAa"}
1
+ {"version":3,"sources":["../../src/theme/index.ts"],"sourcesContent":["export * from './theme-context.js';\nexport * from './theme-cookie.js';\nexport * from './theme-script.js';\nexport * from './types.js';\n"],"names":[],"mappings":"AAAA,cAAc,qBAAqB;AACnC,cAAc,oBAAoB;AAClC,cAAc,oBAAoB;AAClC,cAAc,aAAa"}
@@ -1,13 +1,31 @@
1
1
  import { type PropsWithChildren } from 'react';
2
- import type { ThemeContextValue, ThemeOption, ThemePalette } from './types.js';
2
+ import type { Density, ThemeContextValue, ThemeOption, ThemePalette } from './types.js';
3
3
  export interface ThemeProviderProps extends PropsWithChildren {
4
4
  /** The themes this app exposes. First entry is the default unless
5
5
  * `defaultTheme` is given. Drives `data-theme` + the switcher. */
6
6
  themes: ThemeOption[];
7
7
  /** Theme id used for the first paint / when nothing is stored. */
8
8
  defaultTheme?: string;
9
- /** localStorage key — namespace it per app so apps don't clobber each other. */
9
+ /**
10
+ * The density when nothing is stored. Omitted, the provider leaves
11
+ * `data-density` as the document has it until a density is chosen.
12
+ */
13
+ defaultDensity?: Density;
14
+ /**
15
+ * The cookie the theme is kept in — namespace it per app so apps don't
16
+ * clobber each other. The density is kept beside it, under
17
+ * `${storageKey}-density`. A cookie rather than local storage, so a server
18
+ * can read the choice and render `data-theme` and `data-density` with the
19
+ * page: no paint in the wrong palette before a script corrects it.
20
+ */
10
21
  storageKey?: string;
22
+ /**
23
+ * The theme and density the server read from those cookies and rendered
24
+ * the page in (`readThemeCookies` in `@entifix/next-shell/server`). Given,
25
+ * the provider starts there and nothing changes after the page loads.
26
+ */
27
+ initialTheme?: string;
28
+ initialDensity?: Density;
11
29
  /**
12
30
  * Runtime palettes for brands not shipped as CSS presets (multi-tenant /
13
31
  * white-label). Keyed by theme id; injected as `[data-theme='id']{…}` vars
@@ -16,11 +34,21 @@ export interface ThemeProviderProps extends PropsWithChildren {
16
34
  palettes?: Record<string, ThemePalette>;
17
35
  }
18
36
  /**
19
- * Applies the active palette by writing `data-theme` on <html> and persisting
20
- * the choice. Static palette VALUES live in CSS (@entifix/style presets or
21
- * an app-local themes.css); this flips the selector. Dynamic palettes passed via
22
- * `palettes` are injected at runtime under the same `data-theme` mechanism.
37
+ * Applies the active palette and density by writing `data-theme` and
38
+ * `data-density` on <html>, and remembers what the user chooses. Static palette
39
+ * VALUES live in CSS (@entifix/style presets or an app-local themes.css); this
40
+ * flips the selector. Dynamic palettes passed via `palettes` are injected at
41
+ * runtime under the same `data-theme` mechanism.
42
+ *
43
+ * ⚠️ **Only a choice is written to storage, never a default.** The provider
44
+ * used to persist whatever theme it held from an effect, and under StrictMode
45
+ * the effect ran before the stored value had been read back: the default
46
+ * overwrote the stored theme, and a reload in development always came back on
47
+ * the default. Writing in `setTheme` and `setDensity` alone means mounting,
48
+ * however many times, can never lose what was chosen.
23
49
  */
24
- export declare function ThemeProvider({ children, themes, defaultTheme, storageKey, palettes, }: ThemeProviderProps): import("react").JSX.Element;
50
+ export declare function ThemeProvider({ children, themes, defaultTheme, defaultDensity, storageKey, palettes, initialTheme, initialDensity, }: ThemeProviderProps): import("react").JSX.Element;
51
+ /** The theme context, or `null` outside a {@link ThemeProvider}. */
52
+ export declare const useOptionalTheme: () => ThemeContextValue | null;
25
53
  export declare function useTheme(): ThemeContextValue;
26
54
  //# sourceMappingURL=theme-context.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"theme-context.d.ts","sourceRoot":"","sources":["../../src/theme/theme-context.tsx"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,iBAAiB,EAMvB,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAI/E,MAAM,WAAW,kBAAmB,SAAQ,iBAAiB;IAC3D;uEACmE;IACnE,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,kEAAkE;IAClE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gFAAgF;IAChF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;CACzC;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,EAC5B,QAAQ,EACR,MAAM,EACN,YAAY,EACZ,UAA4B,EAC5B,QAAQ,GACT,EAAE,kBAAkB,+BA2DpB;AAED,wBAAgB,QAAQ,IAAI,iBAAiB,CAI5C"}
1
+ {"version":3,"file":"theme-context.d.ts","sourceRoot":"","sources":["../../src/theme/theme-context.tsx"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,iBAAiB,EAMvB,MAAM,OAAO,CAAC;AAIf,OAAO,KAAK,EACV,OAAO,EACP,iBAAiB,EACjB,WAAW,EACX,YAAY,EACb,MAAM,YAAY,CAAC;AAIpB,MAAM,WAAW,kBAAmB,SAAQ,iBAAiB;IAC3D;uEACmE;IACnE,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,kEAAkE;IAClE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;CACzC;AAiCD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAAC,EAC5B,QAAQ,EACR,MAAM,EACN,YAAY,EACZ,cAAc,EACd,UAAyB,EACzB,QAAQ,EACR,YAAY,EACZ,cAAc,GACf,EAAE,kBAAkB,+BAoHpB;AAED,oEAAoE;AACpE,eAAO,MAAM,gBAAgB,QAAO,iBAAiB,GAAG,IAC9B,CAAC;AAE3B,wBAAgB,QAAQ,IAAI,iBAAiB,CAI5C"}
@@ -1,31 +1,83 @@
1
1
  'use client';
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { Effect } from 'effect';
3
4
  import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';
5
+ import { useUiPreferencesState } from '../preferences/ui-preferences-context.js';
6
+ import { densityCookie, THEME_COOKIE } from './theme-cookie.js';
4
7
  const ThemeContext = /*#__PURE__*/ createContext(null);
8
+ const DENSITIES = [
9
+ 'comfortable',
10
+ 'compact'
11
+ ];
12
+ const isDensity = (value)=>DENSITIES.includes(value);
13
+ /** Storage that may be absent or refuse (a private window, blocked site data). */ /** A year: a preference outlives a session. */ const COOKIE_MAX_AGE = 60 * 60 * 24 * 365;
14
+ /** A first-party cookie's value, or `null` when it is not set. */ function readCookie(name) {
15
+ try {
16
+ for (const pair of document.cookie.split('; ')){
17
+ const at = pair.indexOf('=');
18
+ if (pair.slice(0, at) === name) return decodeURIComponent(pair.slice(at + 1));
19
+ }
20
+ } catch (unused) {
21
+ // A sandboxed document refuses cookies; nothing was stored, then.
22
+ }
23
+ return null;
24
+ }
25
+ function writeCookie(name, value) {
26
+ try {
27
+ document.cookie = `${name}=${encodeURIComponent(value)}; path=/; max-age=${COOKIE_MAX_AGE}; samesite=lax`;
28
+ } catch (unused) {
29
+ // Nothing to remember it in; the choice still applies to this page.
30
+ }
31
+ }
5
32
  /**
6
- * Applies the active palette by writing `data-theme` on <html> and persisting
7
- * the choice. Static palette VALUES live in CSS (@entifix/style presets or
8
- * an app-local themes.css); this flips the selector. Dynamic palettes passed via
9
- * `palettes` are injected at runtime under the same `data-theme` mechanism.
10
- */ export function ThemeProvider({ children, themes, defaultTheme, storageKey = 'entifix-theme', palettes }) {
11
- var _ref;
33
+ * Applies the active palette and density by writing `data-theme` and
34
+ * `data-density` on <html>, and remembers what the user chooses. Static palette
35
+ * VALUES live in CSS (@entifix/style presets or an app-local themes.css); this
36
+ * flips the selector. Dynamic palettes passed via `palettes` are injected at
37
+ * runtime under the same `data-theme` mechanism.
38
+ *
39
+ * ⚠️ **Only a choice is written to storage, never a default.** The provider
40
+ * used to persist whatever theme it held from an effect, and under StrictMode
41
+ * the effect ran before the stored value had been read back: the default
42
+ * overwrote the stored theme, and a reload in development always came back on
43
+ * the default. Writing in `setTheme` and `setDensity` alone means mounting,
44
+ * however many times, can never lose what was chosen.
45
+ */ export function ThemeProvider({ children, themes, defaultTheme, defaultDensity, storageKey = THEME_COOKIE, palettes, initialTheme, initialDensity }) {
46
+ var _ref, _ref1;
12
47
  var _themes_;
13
- const initial = (_ref = defaultTheme != null ? defaultTheme : (_themes_ = themes[0]) == null ? void 0 : _themes_.id) != null ? _ref : '';
48
+ const initial = (_ref = (_ref1 = initialTheme != null ? initialTheme : defaultTheme) != null ? _ref1 : (_themes_ = themes[0]) == null ? void 0 : _themes_.id) != null ? _ref : '';
14
49
  const [theme, setThemeState] = useState(initial);
50
+ const densityKey = densityCookie(storageKey);
51
+ // `undefined` until a density is stored, chosen or defaulted: the document's
52
+ // own `data-density` stands until then.
53
+ const [density, setDensityState] = useState(initialDensity != null ? initialDensity : defaultDensity);
54
+ const preferences = useUiPreferencesState();
15
55
  const isKnown = useCallback((value)=>typeof value === 'string' && themes.some((t)=>t.id === value), [
16
56
  themes
17
57
  ]);
18
- // Hydrate from a previously stored preference on mount. This intentionally
19
- // runs in an effect (not a lazy initializer): localStorage is unavailable
20
- // during SSR, so the server renders `initial` and the client corrects after
21
- // mount — reading it in render would cause a hydration mismatch.
58
+ // Read the stored choice on mount, for a host that could not: a static
59
+ // export has no server to read the cookie, so it renders `initial` and the
60
+ // client corrects after mount. Reading in render would mismatch hydration.
61
+ // Where the server read it, `initial` already is the stored choice and this
62
+ // changes nothing. It only reads, so running twice changes nothing.
22
63
  useEffect(()=>{
23
- const stored = window.localStorage.getItem(storageKey);
64
+ const stored = readCookie(storageKey);
24
65
  // eslint-disable-next-line react-hooks/set-state-in-effect -- one-shot SSR-safe hydration, see comment above
25
66
  if (isKnown(stored)) setThemeState(stored);
67
+ // A stored density wins; otherwise the default, otherwise whatever the
68
+ // document was served with, so the context never reports a density the
69
+ // page is not in.
70
+ const storedDensity = readCookie(densityKey);
71
+ const served = document.documentElement.dataset.density;
72
+ if (isDensity(storedDensity)) setDensityState(storedDensity);
73
+ else if (defaultDensity === undefined && isDensity(served)) {
74
+ setDensityState(served);
75
+ }
26
76
  }, [
27
77
  storageKey,
28
- isKnown
78
+ densityKey,
79
+ isKnown,
80
+ defaultDensity
29
81
  ]);
30
82
  // Inject runtime palettes as a single <style> appended to <head>. Being last
31
83
  // in the cascade, these win over any static preset defining the same tokens.
@@ -47,29 +99,65 @@ const ThemeContext = /*#__PURE__*/ createContext(null);
47
99
  palettes,
48
100
  storageKey
49
101
  ]);
50
- // Reflect the active theme onto the document + persist it.
102
+ // Reflect the active theme and density onto the document. Storage is not
103
+ // touched here — see the ⚠️ above.
104
+ //
105
+ // Written only when it differs: a page the server rendered in the stored
106
+ // theme is already right, and even a write of the same value is a change
107
+ // something watching the document would see.
51
108
  useEffect(()=>{
52
- document.documentElement.dataset.theme = theme;
53
- window.localStorage.setItem(storageKey, theme);
109
+ const root = document.documentElement;
110
+ if (root.dataset.theme !== theme) root.dataset.theme = theme;
54
111
  }, [
55
- theme,
56
- storageKey
112
+ theme
113
+ ]);
114
+ useEffect(()=>{
115
+ const root = document.documentElement;
116
+ if (density !== undefined && root.dataset.density !== density) root.dataset.density = density;
117
+ }, [
118
+ density
119
+ ]);
120
+ // The cookie is what the next page is rendered in; the UI-preferences port
121
+ // gets a copy, so a host that keeps preferences server-side has them too.
122
+ const remember = useCallback((cookie, key, value)=>{
123
+ writeCookie(cookie, value);
124
+ void Effect.runPromise(preferences.write(key, value)).catch(()=>undefined);
125
+ }, [
126
+ preferences
127
+ ]);
128
+ const setTheme = useCallback((next)=>{
129
+ setThemeState(next);
130
+ remember(storageKey, 'theme', next);
131
+ }, [
132
+ storageKey,
133
+ remember
134
+ ]);
135
+ const setDensity = useCallback((next)=>{
136
+ setDensityState(next);
137
+ remember(densityKey, 'density', next);
138
+ }, [
139
+ densityKey,
140
+ remember
57
141
  ]);
58
- const setTheme = useCallback((next)=>setThemeState(next), []);
59
142
  const value = useMemo(()=>({
60
143
  theme,
61
144
  setTheme,
62
- themes
145
+ themes,
146
+ density: density != null ? density : 'comfortable',
147
+ setDensity
63
148
  }), [
64
149
  theme,
65
150
  setTheme,
66
- themes
151
+ themes,
152
+ density,
153
+ setDensity
67
154
  ]);
68
155
  return /*#__PURE__*/ _jsx(ThemeContext.Provider, {
69
156
  value: value,
70
157
  children: children
71
158
  });
72
159
  }
160
+ /** The theme context, or `null` outside a {@link ThemeProvider}. */ export const useOptionalTheme = ()=>useContext(ThemeContext);
73
161
  export function useTheme() {
74
162
  const ctx = useContext(ThemeContext);
75
163
  if (!ctx) throw new Error('useTheme must be used within a ThemeProvider');
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/theme/theme-context.tsx"],"sourcesContent":["'use client';\n\nimport {\n createContext,\n type PropsWithChildren,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useState,\n} from 'react';\n\nimport type { ThemeContextValue, ThemeOption, ThemePalette } from './types.js';\n\nconst ThemeContext = createContext<ThemeContextValue | null>(null);\n\nexport interface ThemeProviderProps extends PropsWithChildren {\n /** The themes this app exposes. First entry is the default unless\n * `defaultTheme` is given. Drives `data-theme` + the switcher. */\n themes: ThemeOption[];\n /** Theme id used for the first paint / when nothing is stored. */\n defaultTheme?: string;\n /** localStorage key — namespace it per app so apps don't clobber each other. */\n storageKey?: string;\n /**\n * Runtime palettes for brands not shipped as CSS presets (multi-tenant /\n * white-label). Keyed by theme id; injected as `[data-theme='id']{…}` vars\n * appended after the app stylesheet, so they override static presets.\n */\n palettes?: Record<string, ThemePalette>;\n}\n\n/**\n * Applies the active palette by writing `data-theme` on <html> and persisting\n * the choice. Static palette VALUES live in CSS (@entifix/style presets or\n * an app-local themes.css); this flips the selector. Dynamic palettes passed via\n * `palettes` are injected at runtime under the same `data-theme` mechanism.\n */\nexport function ThemeProvider({\n children,\n themes,\n defaultTheme,\n storageKey = 'entifix-theme',\n palettes,\n}: ThemeProviderProps) {\n const initial = defaultTheme ?? themes[0]?.id ?? '';\n const [theme, setThemeState] = useState<string>(initial);\n\n const isKnown = useCallback(\n (value: unknown): value is string =>\n typeof value === 'string' && themes.some(t => t.id === value),\n [themes],\n );\n\n // Hydrate from a previously stored preference on mount. This intentionally\n // runs in an effect (not a lazy initializer): localStorage is unavailable\n // during SSR, so the server renders `initial` and the client corrects after\n // mount — reading it in render would cause a hydration mismatch.\n useEffect(() => {\n const stored = window.localStorage.getItem(storageKey);\n // eslint-disable-next-line react-hooks/set-state-in-effect -- one-shot SSR-safe hydration, see comment above\n if (isKnown(stored)) setThemeState(stored);\n }, [storageKey, isKnown]);\n\n // Inject runtime palettes as a single <style> appended to <head>. Being last\n // in the cascade, these win over any static preset defining the same tokens.\n useEffect(() => {\n if (!palettes || Object.keys(palettes).length === 0) return;\n const styleId = `${storageKey}-runtime-palettes`;\n const css = Object.entries(palettes)\n .map(([id, palette]) => {\n const decls = Object.entries(palette)\n .map(([token, value]) => `--color-${token}: ${value};`)\n .join(' ');\n return `[data-theme='${id}'] { ${decls} }`;\n })\n .join('\\n');\n\n let el = document.getElementById(styleId) as HTMLStyleElement | null;\n if (!el) {\n el = document.createElement('style');\n el.id = styleId;\n document.head.appendChild(el);\n }\n el.textContent = css;\n }, [palettes, storageKey]);\n\n // Reflect the active theme onto the document + persist it.\n useEffect(() => {\n document.documentElement.dataset.theme = theme;\n window.localStorage.setItem(storageKey, theme);\n }, [theme, storageKey]);\n\n const setTheme = useCallback((next: string) => setThemeState(next), []);\n\n const value = useMemo<ThemeContextValue>(\n () => ({ theme, setTheme, themes }),\n [theme, setTheme, themes],\n );\n\n return (\n <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>\n );\n}\n\nexport function useTheme(): ThemeContextValue {\n const ctx = useContext(ThemeContext);\n if (!ctx) throw new Error('useTheme must be used within a ThemeProvider');\n return ctx;\n}\n"],"names":["createContext","useCallback","useContext","useEffect","useMemo","useState","ThemeContext","ThemeProvider","children","themes","defaultTheme","storageKey","palettes","initial","id","theme","setThemeState","isKnown","value","some","t","stored","window","localStorage","getItem","Object","keys","length","styleId","css","entries","map","palette","decls","token","join","el","document","getElementById","createElement","head","appendChild","textContent","documentElement","dataset","setItem","setTheme","next","Provider","useTheme","ctx","Error"],"mappings":"AAAA;;AAEA,SACEA,aAAa,EAEbC,WAAW,EACXC,UAAU,EACVC,SAAS,EACTC,OAAO,EACPC,QAAQ,QACH,QAAQ;AAIf,MAAMC,6BAAeN,cAAwC;AAkB7D;;;;;CAKC,GACD,OAAO,SAASO,cAAc,EAC5BC,QAAQ,EACRC,MAAM,EACNC,YAAY,EACZC,aAAa,eAAe,EAC5BC,QAAQ,EACW;QACHF;QAAgBD;IAAhC,MAAMI,WAAUH,OAAAA,uBAAAA,gBAAgBD,WAAAA,MAAM,CAAC,EAAE,qBAATA,SAAWK,EAAE,YAA7BJ,OAAiC;IACjD,MAAM,CAACK,OAAOC,cAAc,GAAGX,SAAiBQ;IAEhD,MAAMI,UAAUhB,YACd,CAACiB,QACC,OAAOA,UAAU,YAAYT,OAAOU,IAAI,CAACC,CAAAA,IAAKA,EAAEN,EAAE,KAAKI,QACzD;QAACT;KAAO;IAGV,2EAA2E;IAC3E,0EAA0E;IAC1E,4EAA4E;IAC5E,iEAAiE;IACjEN,UAAU;QACR,MAAMkB,SAASC,OAAOC,YAAY,CAACC,OAAO,CAACb;QAC3C,6GAA6G;QAC7G,IAAIM,QAAQI,SAASL,cAAcK;IACrC,GAAG;QAACV;QAAYM;KAAQ;IAExB,6EAA6E;IAC7E,6EAA6E;IAC7Ed,UAAU;QACR,IAAI,CAACS,YAAYa,OAAOC,IAAI,CAACd,UAAUe,MAAM,KAAK,GAAG;QACrD,MAAMC,UAAU,GAAGjB,WAAW,iBAAiB,CAAC;QAChD,MAAMkB,MAAMJ,OAAOK,OAAO,CAAClB,UACxBmB,GAAG,CAAC,CAAC,CAACjB,IAAIkB,QAAQ;YACjB,MAAMC,QAAQR,OAAOK,OAAO,CAACE,SAC1BD,GAAG,CAAC,CAAC,CAACG,OAAOhB,MAAM,GAAK,CAAC,QAAQ,EAAEgB,MAAM,EAAE,EAAEhB,MAAM,CAAC,CAAC,EACrDiB,IAAI,CAAC;YACR,OAAO,CAAC,aAAa,EAAErB,GAAG,KAAK,EAAEmB,MAAM,EAAE,CAAC;QAC5C,GACCE,IAAI,CAAC;QAER,IAAIC,KAAKC,SAASC,cAAc,CAACV;QACjC,IAAI,CAACQ,IAAI;YACPA,KAAKC,SAASE,aAAa,CAAC;YAC5BH,GAAGtB,EAAE,GAAGc;YACRS,SAASG,IAAI,CAACC,WAAW,CAACL;QAC5B;QACAA,GAAGM,WAAW,GAAGb;IACnB,GAAG;QAACjB;QAAUD;KAAW;IAEzB,2DAA2D;IAC3DR,UAAU;QACRkC,SAASM,eAAe,CAACC,OAAO,CAAC7B,KAAK,GAAGA;QACzCO,OAAOC,YAAY,CAACsB,OAAO,CAAClC,YAAYI;IAC1C,GAAG;QAACA;QAAOJ;KAAW;IAEtB,MAAMmC,WAAW7C,YAAY,CAAC8C,OAAiB/B,cAAc+B,OAAO,EAAE;IAEtE,MAAM7B,QAAQd,QACZ,IAAO,CAAA;YAAEW;YAAO+B;YAAUrC;QAAO,CAAA,GACjC;QAACM;QAAO+B;QAAUrC;KAAO;IAG3B,qBACE,KAACH,aAAa0C,QAAQ;QAAC9B,OAAOA;kBAAQV;;AAE1C;AAEA,OAAO,SAASyC;IACd,MAAMC,MAAMhD,WAAWI;IACvB,IAAI,CAAC4C,KAAK,MAAM,IAAIC,MAAM;IAC1B,OAAOD;AACT"}
1
+ {"version":3,"sources":["../../src/theme/theme-context.tsx"],"sourcesContent":["'use client';\n\nimport { Effect } from 'effect';\nimport {\n createContext,\n type PropsWithChildren,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useState,\n} from 'react';\n\nimport { useUiPreferencesState } from '../preferences/ui-preferences-context.js';\nimport { densityCookie, THEME_COOKIE } from './theme-cookie.js';\nimport type {\n Density,\n ThemeContextValue,\n ThemeOption,\n ThemePalette,\n} from './types.js';\n\nconst ThemeContext = createContext<ThemeContextValue | null>(null);\n\nexport interface ThemeProviderProps extends PropsWithChildren {\n /** The themes this app exposes. First entry is the default unless\n * `defaultTheme` is given. Drives `data-theme` + the switcher. */\n themes: ThemeOption[];\n /** Theme id used for the first paint / when nothing is stored. */\n defaultTheme?: string;\n /**\n * The density when nothing is stored. Omitted, the provider leaves\n * `data-density` as the document has it until a density is chosen.\n */\n defaultDensity?: Density;\n /**\n * The cookie the theme is kept in — namespace it per app so apps don't\n * clobber each other. The density is kept beside it, under\n * `${storageKey}-density`. A cookie rather than local storage, so a server\n * can read the choice and render `data-theme` and `data-density` with the\n * page: no paint in the wrong palette before a script corrects it.\n */\n storageKey?: string;\n /**\n * The theme and density the server read from those cookies and rendered\n * the page in (`readThemeCookies` in `@entifix/next-shell/server`). Given,\n * the provider starts there and nothing changes after the page loads.\n */\n initialTheme?: string;\n initialDensity?: Density;\n /**\n * Runtime palettes for brands not shipped as CSS presets (multi-tenant /\n * white-label). Keyed by theme id; injected as `[data-theme='id']{…}` vars\n * appended after the app stylesheet, so they override static presets.\n */\n palettes?: Record<string, ThemePalette>;\n}\n\nconst DENSITIES: readonly Density[] = ['comfortable', 'compact'];\n\nconst isDensity = (value: unknown): value is Density =>\n DENSITIES.includes(value as Density);\n\n/** Storage that may be absent or refuse (a private window, blocked site data). */\n/** A year: a preference outlives a session. */\nconst COOKIE_MAX_AGE = 60 * 60 * 24 * 365;\n\n/** A first-party cookie's value, or `null` when it is not set. */\nfunction readCookie(name: string): string | null {\n try {\n for (const pair of document.cookie.split('; ')) {\n const at = pair.indexOf('=');\n if (pair.slice(0, at) === name)\n return decodeURIComponent(pair.slice(at + 1));\n }\n } catch {\n // A sandboxed document refuses cookies; nothing was stored, then.\n }\n return null;\n}\n\nfunction writeCookie(name: string, value: string) {\n try {\n document.cookie = `${name}=${encodeURIComponent(value)}; path=/; max-age=${COOKIE_MAX_AGE}; samesite=lax`;\n } catch {\n // Nothing to remember it in; the choice still applies to this page.\n }\n}\n\n/**\n * Applies the active palette and density by writing `data-theme` and\n * `data-density` on <html>, and remembers what the user chooses. Static palette\n * VALUES live in CSS (@entifix/style presets or an app-local themes.css); this\n * flips the selector. Dynamic palettes passed via `palettes` are injected at\n * runtime under the same `data-theme` mechanism.\n *\n * ⚠️ **Only a choice is written to storage, never a default.** The provider\n * used to persist whatever theme it held from an effect, and under StrictMode\n * the effect ran before the stored value had been read back: the default\n * overwrote the stored theme, and a reload in development always came back on\n * the default. Writing in `setTheme` and `setDensity` alone means mounting,\n * however many times, can never lose what was chosen.\n */\nexport function ThemeProvider({\n children,\n themes,\n defaultTheme,\n defaultDensity,\n storageKey = THEME_COOKIE,\n palettes,\n initialTheme,\n initialDensity,\n}: ThemeProviderProps) {\n const initial = initialTheme ?? defaultTheme ?? themes[0]?.id ?? '';\n const [theme, setThemeState] = useState<string>(initial);\n const densityKey = densityCookie(storageKey);\n // `undefined` until a density is stored, chosen or defaulted: the document's\n // own `data-density` stands until then.\n const [density, setDensityState] = useState<Density | undefined>(\n initialDensity ?? defaultDensity,\n );\n const preferences = useUiPreferencesState();\n\n const isKnown = useCallback(\n (value: unknown): value is string =>\n typeof value === 'string' && themes.some(t => t.id === value),\n [themes],\n );\n\n // Read the stored choice on mount, for a host that could not: a static\n // export has no server to read the cookie, so it renders `initial` and the\n // client corrects after mount. Reading in render would mismatch hydration.\n // Where the server read it, `initial` already is the stored choice and this\n // changes nothing. It only reads, so running twice changes nothing.\n useEffect(() => {\n const stored = readCookie(storageKey);\n // eslint-disable-next-line react-hooks/set-state-in-effect -- one-shot SSR-safe hydration, see comment above\n if (isKnown(stored)) setThemeState(stored);\n // A stored density wins; otherwise the default, otherwise whatever the\n // document was served with, so the context never reports a density the\n // page is not in.\n const storedDensity = readCookie(densityKey);\n const served = document.documentElement.dataset.density;\n if (isDensity(storedDensity)) setDensityState(storedDensity);\n else if (defaultDensity === undefined && isDensity(served)) {\n setDensityState(served);\n }\n }, [storageKey, densityKey, isKnown, defaultDensity]);\n\n // Inject runtime palettes as a single <style> appended to <head>. Being last\n // in the cascade, these win over any static preset defining the same tokens.\n useEffect(() => {\n if (!palettes || Object.keys(palettes).length === 0) return;\n const styleId = `${storageKey}-runtime-palettes`;\n const css = Object.entries(palettes)\n .map(([id, palette]) => {\n const decls = Object.entries(palette)\n .map(([token, value]) => `--color-${token}: ${value};`)\n .join(' ');\n return `[data-theme='${id}'] { ${decls} }`;\n })\n .join('\\n');\n\n let el = document.getElementById(styleId) as HTMLStyleElement | null;\n if (!el) {\n el = document.createElement('style');\n el.id = styleId;\n document.head.appendChild(el);\n }\n el.textContent = css;\n }, [palettes, storageKey]);\n\n // Reflect the active theme and density onto the document. Storage is not\n // touched here — see the ⚠️ above.\n //\n // Written only when it differs: a page the server rendered in the stored\n // theme is already right, and even a write of the same value is a change\n // something watching the document would see.\n useEffect(() => {\n const root = document.documentElement;\n if (root.dataset.theme !== theme) root.dataset.theme = theme;\n }, [theme]);\n useEffect(() => {\n const root = document.documentElement;\n if (density !== undefined && root.dataset.density !== density)\n root.dataset.density = density;\n }, [density]);\n\n // The cookie is what the next page is rendered in; the UI-preferences port\n // gets a copy, so a host that keeps preferences server-side has them too.\n const remember = useCallback(\n (cookie: string, key: 'theme' | 'density', value: string) => {\n writeCookie(cookie, value);\n void Effect.runPromise(preferences.write(key, value)).catch(\n () => undefined,\n );\n },\n [preferences],\n );\n const setTheme = useCallback(\n (next: string) => {\n setThemeState(next);\n remember(storageKey, 'theme', next);\n },\n [storageKey, remember],\n );\n const setDensity = useCallback(\n (next: Density) => {\n setDensityState(next);\n remember(densityKey, 'density', next);\n },\n [densityKey, remember],\n );\n\n const value = useMemo<ThemeContextValue>(\n () => ({\n theme,\n setTheme,\n themes,\n density: density ?? 'comfortable',\n setDensity,\n }),\n [theme, setTheme, themes, density, setDensity],\n );\n\n return (\n <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>\n );\n}\n\n/** The theme context, or `null` outside a {@link ThemeProvider}. */\nexport const useOptionalTheme = (): ThemeContextValue | null =>\n useContext(ThemeContext);\n\nexport function useTheme(): ThemeContextValue {\n const ctx = useContext(ThemeContext);\n if (!ctx) throw new Error('useTheme must be used within a ThemeProvider');\n return ctx;\n}\n"],"names":["Effect","createContext","useCallback","useContext","useEffect","useMemo","useState","useUiPreferencesState","densityCookie","THEME_COOKIE","ThemeContext","DENSITIES","isDensity","value","includes","COOKIE_MAX_AGE","readCookie","name","pair","document","cookie","split","at","indexOf","slice","decodeURIComponent","writeCookie","encodeURIComponent","ThemeProvider","children","themes","defaultTheme","defaultDensity","storageKey","palettes","initialTheme","initialDensity","initial","id","theme","setThemeState","densityKey","density","setDensityState","preferences","isKnown","some","t","stored","storedDensity","served","documentElement","dataset","undefined","Object","keys","length","styleId","css","entries","map","palette","decls","token","join","el","getElementById","createElement","head","appendChild","textContent","root","remember","key","runPromise","write","catch","setTheme","next","setDensity","Provider","useOptionalTheme","useTheme","ctx","Error"],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * The cookie a theme is kept in unless a provider names another; the density
3
+ * is kept beside it, under `${name}-density`. Server-safe, so a layout and the
4
+ * inline script can name it without a client boundary.
5
+ */
6
+ export declare const THEME_COOKIE = "entifix-theme";
7
+ /** The density's cookie, beside the theme's. */
8
+ export declare const densityCookie: (themeCookie: string) => string;
9
+ //# sourceMappingURL=theme-cookie.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme-cookie.d.ts","sourceRoot":"","sources":["../../src/theme/theme-cookie.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,eAAO,MAAM,YAAY,kBAAkB,CAAC;AAE5C,gDAAgD;AAChD,eAAO,MAAM,aAAa,GAAI,aAAa,MAAM,KAAG,MAC1B,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * The cookie a theme is kept in unless a provider names another; the density
3
+ * is kept beside it, under `${name}-density`. Server-safe, so a layout and the
4
+ * inline script can name it without a client boundary.
5
+ */ export const THEME_COOKIE = 'entifix-theme';
6
+ /** The density's cookie, beside the theme's. */ export const densityCookie = (themeCookie)=>`${themeCookie}-density`;
7
+
8
+ //# sourceMappingURL=theme-cookie.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/theme/theme-cookie.ts"],"sourcesContent":["/**\n * The cookie a theme is kept in unless a provider names another; the density\n * is kept beside it, under `${name}-density`. Server-safe, so a layout and the\n * inline script can name it without a client boundary.\n */\nexport const THEME_COOKIE = 'entifix-theme';\n\n/** The density's cookie, beside the theme's. */\nexport const densityCookie = (themeCookie: string): string =>\n `${themeCookie}-density`;\n"],"names":["THEME_COOKIE","densityCookie","themeCookie"],"mappings":"AAAA;;;;CAIC,GACD,OAAO,MAAMA,eAAe,gBAAgB;AAE5C,8CAA8C,GAC9C,OAAO,MAAMC,gBAAgB,CAACC,cAC5B,GAAGA,YAAY,QAAQ,CAAC,CAAC"}
@@ -4,7 +4,7 @@ export interface ThemeScriptProps {
4
4
  themes: readonly ThemeOption[];
5
5
  /** Painted when nothing valid is stored; the first theme otherwise. */
6
6
  defaultTheme?: string;
7
- /** The key `ThemeProvider` stores the choice under. */
7
+ /** The cookie `ThemeProvider` keeps the choice in. */
8
8
  storageKey?: string;
9
9
  /** For a Content-Security-Policy that allows inline scripts by nonce. */
10
10
  nonce?: string;
@@ -15,10 +15,13 @@ export interface ThemeScriptProps {
15
15
  * in <head>: it runs ahead of any stylesheet applying and long before React
16
16
  * hydrates.
17
17
  *
18
- * A stored choice wins; otherwise `defaultTheme`, which is then stored too:
19
- * `ThemeProvider` persists whatever theme it mounts with, and without a stored
20
- * value to read it would mount with its own default instead. A page whose
21
- * storage cannot be read is left unthemed, as it would be without the script.
18
+ * For a host with no server to read the theme cookie — a static export. One
19
+ * that has a server renders the attributes from `readThemeCookies` instead,
20
+ * and needs no script at all.
21
+ *
22
+ * The stored choice wins; otherwise `defaultTheme`. A stored density is
23
+ * applied the same way; with none stored the document's own `data-density`
24
+ * stands. Nothing is written: only a choice is ever stored.
22
25
  *
23
26
  * Render it from a server component; it ships no client code.
24
27
  */
@@ -1 +1 @@
1
- {"version":3,"file":"theme-script.d.ts","sourceRoot":"","sources":["../../src/theme/theme-script.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,MAAM,WAAW,gBAAgB;IAC/B,kDAAkD;IAClD,MAAM,EAAE,SAAS,WAAW,EAAE,CAAC;IAC/B,uEAAuE;IACvE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uDAAuD;IACvD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,EAC1B,MAAM,EACN,YAAY,EACZ,UAA4B,EAC5B,KAAK,GACN,EAAE,gBAAgB,+BAgBlB"}
1
+ {"version":3,"file":"theme-script.d.ts","sourceRoot":"","sources":["../../src/theme/theme-script.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,MAAM,WAAW,gBAAgB;IAC/B,kDAAkD;IAClD,MAAM,EAAE,SAAS,WAAW,EAAE,CAAC;IAC/B,uEAAuE;IACvE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sDAAsD;IACtD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,CAAC,EAC1B,MAAM,EACN,YAAY,EACZ,UAAyB,EACzB,KAAK,GACN,EAAE,gBAAgB,+BA0BlB"}
@@ -1,17 +1,21 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { THEME_COOKIE } from './theme-cookie.js';
2
3
  /**
3
4
  * Sets `data-theme` on <html> before the first paint, so a server-rendered or
4
5
  * statically exported page never flashes the wrong palette. Render it inline
5
6
  * in <head>: it runs ahead of any stylesheet applying and long before React
6
7
  * hydrates.
7
8
  *
8
- * A stored choice wins; otherwise `defaultTheme`, which is then stored too:
9
- * `ThemeProvider` persists whatever theme it mounts with, and without a stored
10
- * value to read it would mount with its own default instead. A page whose
11
- * storage cannot be read is left unthemed, as it would be without the script.
9
+ * For a host with no server to read the theme cookie — a static export. One
10
+ * that has a server renders the attributes from `readThemeCookies` instead,
11
+ * and needs no script at all.
12
+ *
13
+ * The stored choice wins; otherwise `defaultTheme`. A stored density is
14
+ * applied the same way; with none stored the document's own `data-density`
15
+ * stands. Nothing is written: only a choice is ever stored.
12
16
  *
13
17
  * Render it from a server component; it ships no client code.
14
- */ export function ThemeScript({ themes, defaultTheme, storageKey = 'entifix-theme', nonce }) {
18
+ */ export function ThemeScript({ themes, defaultTheme, storageKey = THEME_COOKIE, nonce }) {
15
19
  var _ref;
16
20
  const ids = themes.map((theme)=>theme.id);
17
21
  const fallback = (_ref = defaultTheme != null ? defaultTheme : ids[0]) != null ? _ref : '';
@@ -19,12 +23,22 @@ import { jsx as _jsx } from "react/jsx-runtime";
19
23
  try {
20
24
  var themes = ${JSON.stringify(ids)};
21
25
  var key = ${JSON.stringify(storageKey)};
22
- var theme = window.localStorage.getItem(key);
23
- if (themes.indexOf(theme) === -1) {
24
- theme = ${JSON.stringify(fallback)};
25
- window.localStorage.setItem(key, theme);
26
- }
26
+ var read = function (name) {
27
+ var pairs = document.cookie.split('; ');
28
+ for (var i = 0; i < pairs.length; i++) {
29
+ var at = pairs[i].indexOf('=');
30
+ if (pairs[i].slice(0, at) === name)
31
+ return decodeURIComponent(pairs[i].slice(at + 1));
32
+ }
33
+ return null;
34
+ };
35
+ var theme = read(key);
36
+ if (themes.indexOf(theme) === -1) theme = ${JSON.stringify(fallback)};
27
37
  document.documentElement.dataset.theme = theme;
38
+ var density = read(key + '-density');
39
+ if (density === 'comfortable' || density === 'compact') {
40
+ document.documentElement.dataset.density = density;
41
+ }
28
42
  } catch (error) {}
29
43
  })();`;
30
44
  return /*#__PURE__*/ _jsx("script", {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/theme/theme-script.tsx"],"sourcesContent":["import type { ThemeOption } from './types.js';\n\nexport interface ThemeScriptProps {\n /** The same registry `ThemeProvider` is given. */\n themes: readonly ThemeOption[];\n /** Painted when nothing valid is stored; the first theme otherwise. */\n defaultTheme?: string;\n /** The key `ThemeProvider` stores the choice under. */\n storageKey?: string;\n /** For a Content-Security-Policy that allows inline scripts by nonce. */\n nonce?: string;\n}\n\n/**\n * Sets `data-theme` on <html> before the first paint, so a server-rendered or\n * statically exported page never flashes the wrong palette. Render it inline\n * in <head>: it runs ahead of any stylesheet applying and long before React\n * hydrates.\n *\n * A stored choice wins; otherwise `defaultTheme`, which is then stored too:\n * `ThemeProvider` persists whatever theme it mounts with, and without a stored\n * value to read it would mount with its own default instead. A page whose\n * storage cannot be read is left unthemed, as it would be without the script.\n *\n * Render it from a server component; it ships no client code.\n */\nexport function ThemeScript({\n themes,\n defaultTheme,\n storageKey = 'entifix-theme',\n nonce,\n}: ThemeScriptProps) {\n const ids = themes.map(theme => theme.id);\n const fallback = defaultTheme ?? ids[0] ?? '';\n const script = `(function () {\n try {\n var themes = ${JSON.stringify(ids)};\n var key = ${JSON.stringify(storageKey)};\n var theme = window.localStorage.getItem(key);\n if (themes.indexOf(theme) === -1) {\n theme = ${JSON.stringify(fallback)};\n window.localStorage.setItem(key, theme);\n }\n document.documentElement.dataset.theme = theme;\n } catch (error) {}\n})();`;\n return <script nonce={nonce} dangerouslySetInnerHTML={{ __html: script }} />;\n}\n"],"names":["ThemeScript","themes","defaultTheme","storageKey","nonce","ids","map","theme","id","fallback","script","JSON","stringify","dangerouslySetInnerHTML","__html"],"mappings":";AAaA;;;;;;;;;;;;CAYC,GACD,OAAO,SAASA,YAAY,EAC1BC,MAAM,EACNC,YAAY,EACZC,aAAa,eAAe,EAC5BC,KAAK,EACY;QAEAF;IADjB,MAAMG,MAAMJ,OAAOK,GAAG,CAACC,CAAAA,QAASA,MAAMC,EAAE;IACxC,MAAMC,YAAWP,OAAAA,uBAAAA,eAAgBG,GAAG,CAAC,EAAE,YAAtBH,OAA0B;IAC3C,MAAMQ,SAAS,CAAC;;iBAED,EAAEC,KAAKC,SAAS,CAACP,KAAK;cACzB,EAAEM,KAAKC,SAAS,CAACT,YAAY;;;cAG7B,EAAEQ,KAAKC,SAAS,CAACH,UAAU;;;;;KAKpC,CAAC;IACJ,qBAAO,KAACC;QAAON,OAAOA;QAAOS,yBAAyB;YAAEC,QAAQJ;QAAO;;AACzE"}
1
+ {"version":3,"sources":["../../src/theme/theme-script.tsx"],"sourcesContent":["import { THEME_COOKIE } from './theme-cookie.js';\nimport type { ThemeOption } from './types.js';\n\nexport interface ThemeScriptProps {\n /** The same registry `ThemeProvider` is given. */\n themes: readonly ThemeOption[];\n /** Painted when nothing valid is stored; the first theme otherwise. */\n defaultTheme?: string;\n /** The cookie `ThemeProvider` keeps the choice in. */\n storageKey?: string;\n /** For a Content-Security-Policy that allows inline scripts by nonce. */\n nonce?: string;\n}\n\n/**\n * Sets `data-theme` on <html> before the first paint, so a server-rendered or\n * statically exported page never flashes the wrong palette. Render it inline\n * in <head>: it runs ahead of any stylesheet applying and long before React\n * hydrates.\n *\n * For a host with no server to read the theme cookie — a static export. One\n * that has a server renders the attributes from `readThemeCookies` instead,\n * and needs no script at all.\n *\n * The stored choice wins; otherwise `defaultTheme`. A stored density is\n * applied the same way; with none stored the document's own `data-density`\n * stands. Nothing is written: only a choice is ever stored.\n *\n * Render it from a server component; it ships no client code.\n */\nexport function ThemeScript({\n themes,\n defaultTheme,\n storageKey = THEME_COOKIE,\n nonce,\n}: ThemeScriptProps) {\n const ids = themes.map(theme => theme.id);\n const fallback = defaultTheme ?? ids[0] ?? '';\n const script = `(function () {\n try {\n var themes = ${JSON.stringify(ids)};\n var key = ${JSON.stringify(storageKey)};\n var read = function (name) {\n var pairs = document.cookie.split('; ');\n for (var i = 0; i < pairs.length; i++) {\n var at = pairs[i].indexOf('=');\n if (pairs[i].slice(0, at) === name)\n return decodeURIComponent(pairs[i].slice(at + 1));\n }\n return null;\n };\n var theme = read(key);\n if (themes.indexOf(theme) === -1) theme = ${JSON.stringify(fallback)};\n document.documentElement.dataset.theme = theme;\n var density = read(key + '-density');\n if (density === 'comfortable' || density === 'compact') {\n document.documentElement.dataset.density = density;\n }\n } catch (error) {}\n})();`;\n return <script nonce={nonce} dangerouslySetInnerHTML={{ __html: script }} />;\n}\n"],"names":["THEME_COOKIE","ThemeScript","themes","defaultTheme","storageKey","nonce","ids","map","theme","id","fallback","script","JSON","stringify","dangerouslySetInnerHTML","__html"],"mappings":";AAAA,SAASA,YAAY,QAAQ,oBAAoB;AAcjD;;;;;;;;;;;;;;;CAeC,GACD,OAAO,SAASC,YAAY,EAC1BC,MAAM,EACNC,YAAY,EACZC,aAAaJ,YAAY,EACzBK,KAAK,EACY;QAEAF;IADjB,MAAMG,MAAMJ,OAAOK,GAAG,CAACC,CAAAA,QAASA,MAAMC,EAAE;IACxC,MAAMC,YAAWP,OAAAA,uBAAAA,eAAgBG,GAAG,CAAC,EAAE,YAAtBH,OAA0B;IAC3C,MAAMQ,SAAS,CAAC;;iBAED,EAAEC,KAAKC,SAAS,CAACP,KAAK;cACzB,EAAEM,KAAKC,SAAS,CAACT,YAAY;;;;;;;;;;;8CAWG,EAAEQ,KAAKC,SAAS,CAACH,UAAU;;;;;;;KAOpE,CAAC;IACJ,qBAAO,KAACC;QAAON,OAAOA;QAAOS,yBAAyB;YAAEC,QAAQJ;QAAO;;AACzE"}
@@ -8,15 +8,31 @@ export interface ThemeOption {
8
8
  }
9
9
  /** The semantic color tokens an app may supply values for. Matches the
10
10
  * `--color-*` contract declared in @entifix/style/tokens.css. */
11
- export type ThemeColorToken = 'surface' | 'surface-elevated' | 'content' | 'content-muted' | 'primary' | 'primary-content' | 'border' | 'accent' | 'danger' | 'danger-subtle' | 'danger-content';
11
+ export type ThemeColorToken = 'surface' | 'surface-elevated' | 'content' | 'content-muted' | 'primary' | 'primary-content' | 'border' | 'border-control' | 'selected' | 'accent' | 'focus-ring' | 'danger' | 'danger-subtle' | 'danger-content' | 'success' | 'success-subtle' | 'success-content' | 'warning' | 'warning-subtle' | 'warning-content' | 'info' | 'info-subtle' | 'info-content' | 'scrim';
12
+ /**
13
+ * The tokens a runtime palette must state. Each one is held to a contrast pair
14
+ * against the palette's own surfaces (ADR 0025), so the neutral default cannot
15
+ * stand in for it: a ring or a control boundary that clears 3:1 on grey may be
16
+ * invisible on a brand's surface. Omitting one is a type error, not a silent
17
+ * fallback.
18
+ */
19
+ export type ThemePaletteRequiredToken = 'focus-ring' | 'border-control' | 'selected';
12
20
  /** A runtime palette: token → CSS color. Injected as `[data-theme]` vars for
13
- * brands not known at build time (multi-tenant / white-label). */
14
- export type ThemePalette = Partial<Record<ThemeColorToken, string>>;
21
+ * brands not known at build time (multi-tenant / white-label). Hold one to
22
+ * the contract with `assertPaletteContract` from `@entifix/style/testing`. */
23
+ export type ThemePalette = Partial<Record<ThemeColorToken, string>> & Record<ThemePaletteRequiredToken, string>;
24
+ /** How much room the UI takes: `fixed-scale.css` reads it as `data-density`. */
25
+ export type Density = 'comfortable' | 'compact';
15
26
  export interface ThemeContextValue {
16
27
  /** Active theme id (written to `data-theme`). */
17
28
  theme: string;
29
+ /** Chooses a theme, and remembers the choice. */
18
30
  setTheme: (id: string) => void;
19
31
  /** The registry this provider was configured with. */
20
32
  themes: ThemeOption[];
33
+ /** Active density (written to `data-density`). */
34
+ density: Density;
35
+ /** Chooses a density, and remembers the choice. */
36
+ setDensity: (density: Density) => void;
21
37
  }
22
38
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/theme/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;CACf;AAED;kEACkE;AAClE,MAAM,MAAM,eAAe,GACvB,SAAS,GACT,kBAAkB,GAClB,SAAS,GACT,eAAe,GACf,SAAS,GACT,iBAAiB,GACjB,QAAQ,GACR,QAAQ,GACR,QAAQ,GACR,eAAe,GACf,gBAAgB,CAAC;AAErB;mEACmE;AACnE,MAAM,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,CAAC;AAEpE,MAAM,WAAW,iBAAiB;IAChC,iDAAiD;IACjD,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,sDAAsD;IACtD,MAAM,EAAE,WAAW,EAAE,CAAC;CACvB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/theme/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;CACf;AAED;kEACkE;AAClE,MAAM,MAAM,eAAe,GACvB,SAAS,GACT,kBAAkB,GAClB,SAAS,GACT,eAAe,GACf,SAAS,GACT,iBAAiB,GACjB,QAAQ,GACR,gBAAgB,GAChB,UAAU,GACV,QAAQ,GACR,YAAY,GACZ,QAAQ,GACR,eAAe,GACf,gBAAgB,GAChB,SAAS,GACT,gBAAgB,GAChB,iBAAiB,GACjB,SAAS,GACT,gBAAgB,GAChB,iBAAiB,GACjB,MAAM,GACN,aAAa,GACb,cAAc,GACd,OAAO,CAAC;AAEZ;;;;;;GAMG;AACH,MAAM,MAAM,yBAAyB,GACnC,YAAY,GAAG,gBAAgB,GAAG,UAAU,CAAC;AAE/C;;+EAE+E;AAC/E,MAAM,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,GACjE,MAAM,CAAC,yBAAyB,EAAE,MAAM,CAAC,CAAC;AAE5C,gFAAgF;AAChF,MAAM,MAAM,OAAO,GAAG,aAAa,GAAG,SAAS,CAAC;AAEhD,MAAM,WAAW,iBAAiB;IAChC,iDAAiD;IACjD,KAAK,EAAE,MAAM,CAAC;IACd,iDAAiD;IACjD,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,sDAAsD;IACtD,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,kDAAkD;IAClD,OAAO,EAAE,OAAO,CAAC;IACjB,mDAAmD;IACnD,UAAU,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CACxC"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/theme/types.ts"],"sourcesContent":["/**\n * A selectable theme. `id` is written to `data-theme` on <html> and matched\n * against the CSS palette blocks; `label` is what the switcher renders.\n */\nexport interface ThemeOption {\n id: string;\n label: string;\n}\n\n/** The semantic color tokens an app may supply values for. Matches the\n * `--color-*` contract declared in @entifix/style/tokens.css. */\nexport type ThemeColorToken =\n | 'surface'\n | 'surface-elevated'\n | 'content'\n | 'content-muted'\n | 'primary'\n | 'primary-content'\n | 'border'\n | 'accent'\n | 'danger'\n | 'danger-subtle'\n | 'danger-content';\n\n/** A runtime palette: token → CSS color. Injected as `[data-theme]` vars for\n * brands not known at build time (multi-tenant / white-label). */\nexport type ThemePalette = Partial<Record<ThemeColorToken, string>>;\n\nexport interface ThemeContextValue {\n /** Active theme id (written to `data-theme`). */\n theme: string;\n setTheme: (id: string) => void;\n /** The registry this provider was configured with. */\n themes: ThemeOption[];\n}\n"],"names":[],"mappings":"AAAA;;;CAGC,GAyBD,WAMC"}
1
+ {"version":3,"sources":["../../src/theme/types.ts"],"sourcesContent":["/**\n * A selectable theme. `id` is written to `data-theme` on <html> and matched\n * against the CSS palette blocks; `label` is what the switcher renders.\n */\nexport interface ThemeOption {\n id: string;\n label: string;\n}\n\n/** The semantic color tokens an app may supply values for. Matches the\n * `--color-*` contract declared in @entifix/style/tokens.css. */\nexport type ThemeColorToken =\n | 'surface'\n | 'surface-elevated'\n | 'content'\n | 'content-muted'\n | 'primary'\n | 'primary-content'\n | 'border'\n | 'border-control'\n | 'selected'\n | 'accent'\n | 'focus-ring'\n | 'danger'\n | 'danger-subtle'\n | 'danger-content'\n | 'success'\n | 'success-subtle'\n | 'success-content'\n | 'warning'\n | 'warning-subtle'\n | 'warning-content'\n | 'info'\n | 'info-subtle'\n | 'info-content'\n | 'scrim';\n\n/**\n * The tokens a runtime palette must state. Each one is held to a contrast pair\n * against the palette's own surfaces (ADR 0025), so the neutral default cannot\n * stand in for it: a ring or a control boundary that clears 3:1 on grey may be\n * invisible on a brand's surface. Omitting one is a type error, not a silent\n * fallback.\n */\nexport type ThemePaletteRequiredToken =\n 'focus-ring' | 'border-control' | 'selected';\n\n/** A runtime palette: token → CSS color. Injected as `[data-theme]` vars for\n * brands not known at build time (multi-tenant / white-label). Hold one to\n * the contract with `assertPaletteContract` from `@entifix/style/testing`. */\nexport type ThemePalette = Partial<Record<ThemeColorToken, string>> &\n Record<ThemePaletteRequiredToken, string>;\n\n/** How much room the UI takes: `fixed-scale.css` reads it as `data-density`. */\nexport type Density = 'comfortable' | 'compact';\n\nexport interface ThemeContextValue {\n /** Active theme id (written to `data-theme`). */\n theme: string;\n /** Chooses a theme, and remembers the choice. */\n setTheme: (id: string) => void;\n /** The registry this provider was configured with. */\n themes: ThemeOption[];\n /** Active density (written to `data-density`). */\n density: Density;\n /** Chooses a density, and remembers the choice. */\n setDensity: (density: Density) => void;\n}\n"],"names":[],"mappings":"AAAA;;;CAGC,GAqDD,WAWC"}
@@ -18,7 +18,7 @@ export type ActionSurface = (typeof ACTION_SURFACES)[number];
18
18
  * A constant rather than a literal in JSX, because `react/jsx-no-literals`
19
19
  * fails the build on written-in copy and is right to: it cannot tell a
20
20
  * typographic glyph from a forgotten Spanish string. The trigger's *name* is a
21
- * catalog key (`form.moreActions`, `table.actions`) — this is only the mark,
21
+ * catalog key (`actions.more`, `actions.forRecord`) — this is only the mark,
22
22
  * and it is never read aloud.
23
23
  */
24
24
  export declare const OVERFLOW_GLYPH = "\u22EF";
@@ -43,7 +43,7 @@
43
43
  * A constant rather than a literal in JSX, because `react/jsx-no-literals`
44
44
  * fails the build on written-in copy and is right to: it cannot tell a
45
45
  * typographic glyph from a forgotten Spanish string. The trigger's *name* is a
46
- * catalog key (`form.moreActions`, `table.actions`) — this is only the mark,
46
+ * catalog key (`actions.more`, `actions.forRecord`) — this is only the mark,
47
47
  * and it is never read aloud.
48
48
  */ export const OVERFLOW_GLYPH = '\u22ef';
49
49
  /** Which surface renders one cell. Throws on a cell no surface owns. */ function surfaceForCell(key, binding, placement) {