@cube-dev/ui-kit 0.0.0-canary-2757f7b → 0.0.0-canary-8b6ee8a

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 (550) hide show
  1. package/README.md +12 -0
  2. package/dist/README.md +12 -0
  3. package/dist/_internal/hooks/use-chained-callback.js +1 -1
  4. package/dist/_internal/hooks/use-debounced-value.js +1 -1
  5. package/dist/_internal/hooks/use-deprecation-warning.js +1 -1
  6. package/dist/_internal/hooks/use-event.js +1 -1
  7. package/dist/_internal/hooks/use-is-first-render.js +1 -1
  8. package/dist/_internal/hooks/use-sync-ref.js +1 -1
  9. package/dist/_internal/hooks/use-timer/timer.js +1 -1
  10. package/dist/_internal/hooks/use-timer/use-timer.js +1 -1
  11. package/dist/_internal/hooks/use-warn.js +1 -1
  12. package/dist/components/Block.js +1 -1
  13. package/dist/components/CollectionItem.js +1 -1
  14. package/dist/components/GlobalStyles.js +3 -2
  15. package/dist/components/GlobalStyles.js.map +1 -1
  16. package/dist/components/GridProvider.js +1 -1
  17. package/dist/components/HiddenInput.js +1 -1
  18. package/dist/components/Root.d.ts +10 -0
  19. package/dist/components/Root.js +7 -3
  20. package/dist/components/Root.js.map +1 -1
  21. package/dist/components/actions/Action/Action.js +1 -1
  22. package/dist/components/actions/Banner/Banner.js +1 -1
  23. package/dist/components/actions/Button/Button.d.ts +1 -0
  24. package/dist/components/actions/Button/Button.js +1 -1
  25. package/dist/components/actions/ButtonGroup/ButtonGroup.js +1 -1
  26. package/dist/components/actions/ButtonSplit/ButtonSplit.js +1 -1
  27. package/dist/components/actions/ButtonSplit/context.js +1 -1
  28. package/dist/components/actions/CommandMenu/CommandMenu.js +1 -1
  29. package/dist/components/actions/CommandMenu/styled.js +1 -1
  30. package/dist/components/actions/ItemAction/ItemAction.js +1 -1
  31. package/dist/components/actions/ItemActionContext.js +1 -1
  32. package/dist/components/actions/ItemButton/ItemButton.js +1 -1
  33. package/dist/components/actions/Link/Link.js +1 -1
  34. package/dist/components/actions/Menu/Menu.js +1 -1
  35. package/dist/components/actions/Menu/MenuItem.js +1 -1
  36. package/dist/components/actions/Menu/MenuSection.js +1 -1
  37. package/dist/components/actions/Menu/MenuTrigger.js +1 -1
  38. package/dist/components/actions/Menu/SubMenuTrigger.js +1 -1
  39. package/dist/components/actions/Menu/SubmenuTriggerContext.js +1 -1
  40. package/dist/components/actions/Menu/context.js +1 -1
  41. package/dist/components/actions/Menu/styled.js +1 -1
  42. package/dist/components/actions/index.js +1 -1
  43. package/dist/components/actions/use-action.js +1 -1
  44. package/dist/components/actions/use-anchored-menu.js +1 -1
  45. package/dist/components/actions/use-context-menu.js +1 -1
  46. package/dist/components/content/ActiveZone/ActiveZone.js +1 -1
  47. package/dist/components/content/Alert/Alert.js +1 -1
  48. package/dist/components/content/Alert/use-alert.js +1 -1
  49. package/dist/components/content/Avatar/Avatar.js +1 -1
  50. package/dist/components/content/Badge/Badge.js +1 -1
  51. package/dist/components/content/Card/Card.js +1 -1
  52. package/dist/components/content/Content.js +1 -1
  53. package/dist/components/content/CopyPasteBlock/CopyPasteBlock.js +1 -1
  54. package/dist/components/content/CopySnippet/CopySnippet.js +1 -1
  55. package/dist/components/content/Disclosure/Disclosure.js +1 -1
  56. package/dist/components/content/Divider.js +1 -1
  57. package/dist/components/content/Footer.js +1 -1
  58. package/dist/components/content/Header.js +1 -1
  59. package/dist/components/content/HotKeys/HotKeys.js +1 -1
  60. package/dist/components/content/InfoBadge/InfoBadge.js +1 -1
  61. package/dist/components/content/InlineInput/InlineInput.js +1 -1
  62. package/dist/components/content/Item/Item.d.ts +1 -2
  63. package/dist/components/content/Item/Item.js +1 -1
  64. package/dist/components/content/Item/Item.js.map +1 -1
  65. package/dist/components/content/ItemBadge/ItemBadge.js +1 -1
  66. package/dist/components/content/ItemCard/ItemCard.js +1 -1
  67. package/dist/components/content/Layout/GridLayout.js +1 -1
  68. package/dist/components/content/Layout/Layout.js +1 -1
  69. package/dist/components/content/Layout/LayoutBlock.js +1 -1
  70. package/dist/components/content/Layout/LayoutCenter.js +1 -1
  71. package/dist/components/content/Layout/LayoutContainer.js +1 -1
  72. package/dist/components/content/Layout/LayoutContent.js +1 -1
  73. package/dist/components/content/Layout/LayoutContext.js +1 -1
  74. package/dist/components/content/Layout/LayoutFlex.js +1 -1
  75. package/dist/components/content/Layout/LayoutFooter.js +1 -1
  76. package/dist/components/content/Layout/LayoutGrid.js +1 -1
  77. package/dist/components/content/Layout/LayoutHeader.js +1 -1
  78. package/dist/components/content/Layout/LayoutPane.js +1 -1
  79. package/dist/components/content/Layout/LayoutPanel.js +1 -1
  80. package/dist/components/content/Layout/LayoutPanelHeader.js +1 -1
  81. package/dist/components/content/Layout/LayoutToolbar.js +1 -1
  82. package/dist/components/content/Layout/hooks/useTinyScrollbar.js +1 -1
  83. package/dist/components/content/Layout/index.js +1 -1
  84. package/dist/components/content/Layout/utils.js +1 -1
  85. package/dist/components/content/Paragraph.js +1 -1
  86. package/dist/components/content/Placeholder/Placeholder.js +1 -1
  87. package/dist/components/content/PrismCode/PrismCode.js +1 -1
  88. package/dist/components/content/PrismCode/prismSetup.js +1 -1
  89. package/dist/components/content/PrismDiffCode/PrismDiffCode.js +1 -1
  90. package/dist/components/content/Result/Result.js +1 -1
  91. package/dist/components/content/Skeleton/Skeleton.js +1 -1
  92. package/dist/components/content/Tag/Tag.js +1 -1
  93. package/dist/components/content/Text.d.ts +35 -28
  94. package/dist/components/content/Text.js +1 -1
  95. package/dist/components/content/Text.js.map +1 -1
  96. package/dist/components/content/TextItem/TextItem.js +1 -1
  97. package/dist/components/content/Title.d.ts +0 -6
  98. package/dist/components/content/Title.js +3 -2
  99. package/dist/components/content/Title.js.map +1 -1
  100. package/dist/components/content/Tree/Tree.js +1 -1
  101. package/dist/components/content/Tree/TreeNode.js +1 -1
  102. package/dist/components/content/Tree/TreeNode.js.map +1 -1
  103. package/dist/components/content/Tree/styled.js +1 -1
  104. package/dist/components/content/Tree/tree-index.js +1 -1
  105. package/dist/components/content/Tree/use-checkbox-tree.js +1 -1
  106. package/dist/components/content/Tree/use-load-data.js +1 -1
  107. package/dist/components/content/highlightText.js +1 -1
  108. package/dist/components/content/use-auto-tooltip.d.ts +1 -0
  109. package/dist/components/content/use-auto-tooltip.js +1 -1
  110. package/dist/components/content/use-auto-tooltip.js.map +1 -1
  111. package/dist/components/fields/Checkbox/Checkbox.d.ts +2 -2
  112. package/dist/components/fields/Checkbox/Checkbox.js +2 -2
  113. package/dist/components/fields/Checkbox/Checkbox.js.map +1 -1
  114. package/dist/components/fields/Checkbox/CheckboxGroup.js +1 -1
  115. package/dist/components/fields/Checkbox/context.js +1 -1
  116. package/dist/components/fields/ComboBox/ComboBox.js +1 -1
  117. package/dist/components/fields/CommandTextArea/CommandTextArea.js +1 -1
  118. package/dist/components/fields/CommandTextArea/caretPosition.js +1 -1
  119. package/dist/components/fields/CommandTextArea/useCaretAnchor.js +1 -1
  120. package/dist/components/fields/DatePicker/DateInput.js +1 -1
  121. package/dist/components/fields/DatePicker/DateInputBase.js +1 -1
  122. package/dist/components/fields/DatePicker/DateInputBase.js.map +1 -1
  123. package/dist/components/fields/DatePicker/DatePicker.js +1 -1
  124. package/dist/components/fields/DatePicker/DatePickerButton.js +1 -1
  125. package/dist/components/fields/DatePicker/DatePickerElement.js +1 -1
  126. package/dist/components/fields/DatePicker/DatePickerInput.js +1 -1
  127. package/dist/components/fields/DatePicker/DatePickerSegment.js +1 -1
  128. package/dist/components/fields/DatePicker/DateRangePicker.js +1 -1
  129. package/dist/components/fields/DatePicker/DateRangeSeparatedPicker.js +1 -1
  130. package/dist/components/fields/DatePicker/TimeInput.js +1 -1
  131. package/dist/components/fields/DatePicker/parseDate.js +1 -1
  132. package/dist/components/fields/DatePicker/props.js +1 -1
  133. package/dist/components/fields/DatePicker/utils.js +1 -1
  134. package/dist/components/fields/FileInput/FileInput.d.ts +1 -2
  135. package/dist/components/fields/FileInput/FileInput.js +1 -1
  136. package/dist/components/fields/FileInput/FileInput.js.map +1 -1
  137. package/dist/components/fields/FilterListBox/FilterListBox.js +1 -1
  138. package/dist/components/fields/FilterPicker/FilterPicker.js +1 -1
  139. package/dist/components/fields/Input/Input.js +1 -1
  140. package/dist/components/fields/ListBox/DraggableListBox.js +1 -1
  141. package/dist/components/fields/ListBox/ListBox.js +1 -1
  142. package/dist/components/fields/ListBoxPopover/ListBoxPopover.js +1 -1
  143. package/dist/components/fields/ListBoxPopover/index.d.ts +1 -0
  144. package/dist/components/fields/ListBoxPopover/listNavigation.js +1 -1
  145. package/dist/components/fields/ListBoxPopover/useCompositeFocus.d.ts +2 -0
  146. package/dist/components/fields/ListBoxPopover/useCompositeFocus.js +1 -1
  147. package/dist/components/fields/NumberInput/NumberInput.js +1 -1
  148. package/dist/components/fields/NumberInput/StepButton.js +1 -1
  149. package/dist/components/fields/PasswordInput/PasswordInput.js +1 -1
  150. package/dist/components/fields/Picker/Picker.js +1 -1
  151. package/dist/components/fields/RadioGroup/Radio.js +1 -1
  152. package/dist/components/fields/RadioGroup/RadioGroup.js +1 -1
  153. package/dist/components/fields/RadioGroup/context.js +1 -1
  154. package/dist/components/fields/SearchComboBox/SearchComboBox.js +1 -1
  155. package/dist/components/fields/SearchInput/SearchInput.js +1 -1
  156. package/dist/components/fields/Select/Select.d.ts +1 -2
  157. package/dist/components/fields/Select/Select.js +1 -1
  158. package/dist/components/fields/Select/Select.js.map +1 -1
  159. package/dist/components/fields/Slider/Gradation.js +1 -1
  160. package/dist/components/fields/Slider/HueSlider.js +1 -1
  161. package/dist/components/fields/Slider/RangeSlider.js +1 -1
  162. package/dist/components/fields/Slider/Slider.js +1 -1
  163. package/dist/components/fields/Slider/SliderBase.js +1 -1
  164. package/dist/components/fields/Slider/SliderThumb.js +1 -1
  165. package/dist/components/fields/Slider/SliderTrack.js +1 -1
  166. package/dist/components/fields/Slider/elements.js +1 -1
  167. package/dist/components/fields/Slider/index.js +1 -1
  168. package/dist/components/fields/Switch/Switch.d.ts +2 -2
  169. package/dist/components/fields/Switch/Switch.js +1 -1
  170. package/dist/components/fields/Switch/Switch.js.map +1 -1
  171. package/dist/components/fields/TextArea/TextArea.js +1 -1
  172. package/dist/components/fields/TextInput/TextInput.js +1 -1
  173. package/dist/components/fields/TextInput/TextInputBase.d.ts +1 -2
  174. package/dist/components/fields/TextInput/TextInputBase.js +1 -1
  175. package/dist/components/fields/TextInput/TextInputBase.js.map +1 -1
  176. package/dist/components/fields/TextInputMapper/TextInputMapper.js +1 -1
  177. package/dist/components/form/FieldWrapper/FieldWrapper.d.ts +1 -2
  178. package/dist/components/form/FieldWrapper/FieldWrapper.js +1 -1
  179. package/dist/components/form/FieldWrapper/types.d.ts +1 -2
  180. package/dist/components/form/Form/Field.js +1 -1
  181. package/dist/components/form/Form/Form.js +1 -1
  182. package/dist/components/form/Form/ResetButton/ResetButton.js +1 -1
  183. package/dist/components/form/Form/SubmitButton/SubmitButton.js +1 -1
  184. package/dist/components/form/Form/SubmitError.js +1 -1
  185. package/dist/components/form/Form/index.js +1 -1
  186. package/dist/components/form/Form/use-field/use-field-props.js +1 -1
  187. package/dist/components/form/Form/use-field/use-field.js +1 -1
  188. package/dist/components/form/Form/use-form.js +1 -1
  189. package/dist/components/form/Form/validation.js +1 -1
  190. package/dist/components/form/Label.js +1 -1
  191. package/dist/components/form/validation/ValidationIndicator.js +1 -1
  192. package/dist/components/form/validation/resolve-validation-props.js +1 -1
  193. package/dist/components/form/validation/use-validation-props.js +1 -1
  194. package/dist/components/form/wrapper.js +1 -1
  195. package/dist/components/helpers/DisplayTransition/DisplayTransition.js +1 -1
  196. package/dist/components/helpers/IconSwitch/IconSwitch.js +1 -1
  197. package/dist/components/layout/Board/Board.js +1 -1
  198. package/dist/components/layout/Board/BoardProvider.js +1 -1
  199. package/dist/components/layout/Board/BoardResponsive.js +1 -1
  200. package/dist/components/layout/Board/Widget.js +1 -1
  201. package/dist/components/layout/Board/WidgetHost.js +1 -1
  202. package/dist/components/layout/Board/board-context.js +1 -1
  203. package/dist/components/layout/Board/board-store.js +1 -1
  204. package/dist/components/layout/Board/grid-core/calculate.js +1 -1
  205. package/dist/components/layout/Board/grid-core/collision.js +1 -1
  206. package/dist/components/layout/Board/grid-core/compactors.js +1 -1
  207. package/dist/components/layout/Board/grid-core/constraints.js +1 -1
  208. package/dist/components/layout/Board/grid-core/layout.js +1 -1
  209. package/dist/components/layout/Board/grid-core/sort.js +1 -1
  210. package/dist/components/layout/Board/index.js +1 -1
  211. package/dist/components/layout/Board/responsive-utils.js +1 -1
  212. package/dist/components/layout/Board/use-board-layout.js +1 -1
  213. package/dist/components/layout/Board/use-board-registry.js +1 -1
  214. package/dist/components/layout/Flex.js +1 -1
  215. package/dist/components/layout/Flow.js +1 -1
  216. package/dist/components/layout/Grid.js +1 -1
  217. package/dist/components/layout/Panel.js +1 -1
  218. package/dist/components/layout/Prefix.js +1 -1
  219. package/dist/components/layout/ResizablePanel.js +1 -1
  220. package/dist/components/layout/Space.js +1 -1
  221. package/dist/components/layout/Suffix.js +1 -1
  222. package/dist/components/navigation/Tabs/DraggableTabList.js +1 -1
  223. package/dist/components/navigation/Tabs/TabButton.js +1 -1
  224. package/dist/components/navigation/Tabs/TabDropIndicator.js +1 -1
  225. package/dist/components/navigation/Tabs/TabPanel.js +1 -1
  226. package/dist/components/navigation/Tabs/TabPicker.js +1 -1
  227. package/dist/components/navigation/Tabs/Tabs.js +1 -1
  228. package/dist/components/navigation/Tabs/TabsAction.js +1 -1
  229. package/dist/components/navigation/Tabs/TabsContext.js +1 -1
  230. package/dist/components/navigation/Tabs/popover-placement.js +1 -1
  231. package/dist/components/navigation/Tabs/styled.js +1 -1
  232. package/dist/components/navigation/Tabs/types.js +1 -1
  233. package/dist/components/navigation/Tabs/use-tab-editing.js +1 -1
  234. package/dist/components/navigation/Tabs/use-tab-indicator.js +1 -1
  235. package/dist/components/organisms/FileTabs/FileTabs.js +1 -1
  236. package/dist/components/organisms/StatsCard/StatsCard.js +1 -1
  237. package/dist/components/other/Calendar/Calendar.js +1 -1
  238. package/dist/components/other/Calendar/CalendarCell.js +1 -1
  239. package/dist/components/other/Calendar/CalendarGrid.js +1 -1
  240. package/dist/components/other/Calendar/RangeCalendar.js +1 -1
  241. package/dist/components/other/CubeLogo/CubeLogo.js +1 -1
  242. package/dist/components/overlays/AlertDialog/AlertDialog.js +1 -1
  243. package/dist/components/overlays/AlertDialog/AlertDialogApiProvider.js +1 -1
  244. package/dist/components/overlays/AlertDialog/AlertDialogZone.js +1 -1
  245. package/dist/components/overlays/Dialog/Dialog.js +1 -1
  246. package/dist/components/overlays/Dialog/DialogContainer.js +1 -1
  247. package/dist/components/overlays/Dialog/DialogForm.js +1 -1
  248. package/dist/components/overlays/Dialog/DialogTrigger.js +1 -1
  249. package/dist/components/overlays/Dialog/context.js +1 -1
  250. package/dist/components/overlays/Dialog/use-dialog-container.js +1 -1
  251. package/dist/components/overlays/Modal/Modal.d.ts +2 -1
  252. package/dist/components/overlays/Modal/Modal.js +1 -1
  253. package/dist/components/overlays/Modal/Modal.js.map +1 -1
  254. package/dist/components/overlays/Modal/OpenTransitionContext.js +1 -1
  255. package/dist/components/overlays/Modal/Overlay.d.ts +1 -0
  256. package/dist/components/overlays/Modal/Overlay.js +1 -1
  257. package/dist/components/overlays/Modal/Overlay.js.map +1 -1
  258. package/dist/components/overlays/Modal/Popover.js +1 -1
  259. package/dist/components/overlays/Modal/Tray.js +1 -1
  260. package/dist/components/overlays/Modal/Tray.js.map +1 -1
  261. package/dist/components/overlays/Modal/Underlay.js +1 -1
  262. package/dist/components/overlays/Modal/types.d.ts +1 -0
  263. package/dist/components/overlays/Notifications/Notification.js +1 -1
  264. package/dist/components/overlays/Notifications/NotificationAction.js +1 -1
  265. package/dist/components/overlays/Notifications/NotificationCard.js +1 -1
  266. package/dist/components/overlays/Notifications/NotificationContext.d.ts +2 -0
  267. package/dist/components/overlays/Notifications/NotificationContext.js +1 -1
  268. package/dist/components/overlays/Notifications/NotificationItem.js +1 -1
  269. package/dist/components/overlays/Notifications/OverlayContainer.js +1 -1
  270. package/dist/components/overlays/Notifications/OverlayProvider.js +1 -1
  271. package/dist/components/overlays/Notifications/PersistentNotificationsList.js +1 -1
  272. package/dist/components/overlays/Notifications/dismissed-storage.js +1 -1
  273. package/dist/components/overlays/Notifications/format-relative-time.js +1 -1
  274. package/dist/components/overlays/Notifications/index.js +1 -1
  275. package/dist/components/overlays/Notifications/use-notification-state.js +1 -1
  276. package/dist/components/overlays/Notifications/use-notifications.js +1 -1
  277. package/dist/components/overlays/Notifications/use-overlay-timers.js +1 -1
  278. package/dist/components/overlays/Notifications/use-persistent-notifications.js +1 -1
  279. package/dist/components/overlays/Notifications/use-persistent-state.js +1 -1
  280. package/dist/components/overlays/Notifications/use-toast-state.js +1 -1
  281. package/dist/components/overlays/Toast/ToastItem.js +1 -1
  282. package/dist/components/overlays/Toast/index.js +1 -1
  283. package/dist/components/overlays/Toast/useProgressToast.js +1 -1
  284. package/dist/components/overlays/Toast/useToast.js +1 -1
  285. package/dist/components/overlays/Tooltip/Tooltip.js +1 -1
  286. package/dist/components/overlays/Tooltip/TooltipProvider.js +1 -1
  287. package/dist/components/overlays/Tooltip/TooltipTrigger.js +1 -1
  288. package/dist/components/overlays/Tooltip/context.js +1 -1
  289. package/dist/components/overlays/Tooltip/context.js.map +1 -1
  290. package/dist/components/portal/Portal.js +1 -1
  291. package/dist/components/portal/PortalProvider.d.ts +2 -0
  292. package/dist/components/portal/PortalProvider.js +1 -1
  293. package/dist/components/portal/index.d.ts +1 -0
  294. package/dist/components/portal/usePortal.js +1 -1
  295. package/dist/components/shared/DraggableCollection.js +1 -1
  296. package/dist/components/shared/InvalidIcon.js +1 -1
  297. package/dist/components/shared/ValidIcon.js +1 -1
  298. package/dist/components/status/LoadingAnimation/LoadingAnimation.js +1 -1
  299. package/dist/components/status/Spin/Cube.js +1 -1
  300. package/dist/components/status/Spin/InternalSpinner.js +1 -1
  301. package/dist/components/status/Spin/Spin.js +1 -1
  302. package/dist/components/status/Spin/SpinsContainer.js +1 -1
  303. package/dist/data/item-themes.js +1 -1
  304. package/dist/data/themes.js +1 -1
  305. package/dist/eslint-plugin/defaults.generated.js +1 -1
  306. package/dist/eslint-plugin/index.js +1 -1
  307. package/dist/eslint-plugin/rules/no-redundant-default-prop.js +1 -1
  308. package/dist/i18n/I18nProvider.js +1 -1
  309. package/dist/i18n/createFormatter.js +1 -1
  310. package/dist/i18n/index.js +1 -1
  311. package/dist/i18n/instance.js +1 -1
  312. package/dist/i18n/locales/de-DE/uikit.js +1 -1
  313. package/dist/i18n/locales/en-US/uikit.js +1 -1
  314. package/dist/i18n/locales/es-ES/uikit.js +1 -1
  315. package/dist/i18n/locales/es-MX/uikit.js +1 -1
  316. package/dist/i18n/locales/fr-FR/uikit.js +1 -1
  317. package/dist/i18n/locales/it-IT/uikit.js +1 -1
  318. package/dist/i18n/locales/ja-JP/uikit.js +1 -1
  319. package/dist/i18n/locales/nb-NO/uikit.js +1 -1
  320. package/dist/i18n/locales/pt-BR/uikit.js +1 -1
  321. package/dist/i18n/locales/pt-PT/uikit.js +1 -1
  322. package/dist/i18n/locales/sv-SE/uikit.js +1 -1
  323. package/dist/i18n/locales/vi-VN/uikit.js +1 -1
  324. package/dist/i18n/locales.js +1 -1
  325. package/dist/i18n/useFormatter.js +1 -1
  326. package/dist/i18n/useI18n.js +1 -1
  327. package/dist/icons/AdjustmentsHorizontalIcon.js +1 -1
  328. package/dist/icons/AdjustmentsIcon.js +1 -1
  329. package/dist/icons/AiIcon.js +1 -1
  330. package/dist/icons/AreaChartIcon.js +1 -1
  331. package/dist/icons/BackwardIcon.js +1 -1
  332. package/dist/icons/BarChartIcon.js +1 -1
  333. package/dist/icons/BellFilledIcon.js +1 -1
  334. package/dist/icons/BellIcon.js +1 -1
  335. package/dist/icons/BooleanIcon.js +1 -1
  336. package/dist/icons/CalendarEditIcon.js +1 -1
  337. package/dist/icons/CalendarIcon.js +1 -1
  338. package/dist/icons/CaretDownIcon.js +1 -1
  339. package/dist/icons/CaretUpIcon.js +1 -1
  340. package/dist/icons/ChartAreaStackedIcon.js +1 -1
  341. package/dist/icons/ChartAreaStackedPercentageIcon.js +1 -1
  342. package/dist/icons/ChartBarGroupedHorizontalIcon.js +1 -1
  343. package/dist/icons/ChartBarGroupedIcon.js +1 -1
  344. package/dist/icons/ChartBarHorizontalIcon.js +1 -1
  345. package/dist/icons/ChartBarLineIcon.js +1 -1
  346. package/dist/icons/ChartBarStackedHorizontalIcon.js +1 -1
  347. package/dist/icons/ChartBarStackedIcon.js +1 -1
  348. package/dist/icons/ChartBarStackedPercentageHorizontalIcon.js +1 -1
  349. package/dist/icons/ChartBarStackedPercentageIcon.js +1 -1
  350. package/dist/icons/ChartBoxPlot2Icon.js +1 -1
  351. package/dist/icons/ChartBoxPlotIcon.js +1 -1
  352. package/dist/icons/ChartBubbleIcon.js +1 -1
  353. package/dist/icons/ChartDonut2Icon.js +1 -1
  354. package/dist/icons/ChartFunnelIcon.js +1 -1
  355. package/dist/icons/ChartHeatmapIcon.js +1 -1
  356. package/dist/icons/ChartKPIIcon.js +1 -1
  357. package/dist/icons/ChartPie2Icon.js +1 -1
  358. package/dist/icons/ChartScatterIcon.js +1 -1
  359. package/dist/icons/CheckCircleFilledIcon.js +1 -1
  360. package/dist/icons/CheckCircleIcon.js +1 -1
  361. package/dist/icons/CheckIcon.js +1 -1
  362. package/dist/icons/CircleFilledIcon.js +1 -1
  363. package/dist/icons/ClearIcon.js +1 -1
  364. package/dist/icons/CloseCircleFilledIcon.js +1 -1
  365. package/dist/icons/CloseCircleIcon.js +1 -1
  366. package/dist/icons/CloseIcon.js +1 -1
  367. package/dist/icons/CodeIcon.js +1 -1
  368. package/dist/icons/ColumnTotalIcon.js +1 -1
  369. package/dist/icons/CopyIcon.js +1 -1
  370. package/dist/icons/CountIcon.js +1 -1
  371. package/dist/icons/CubeIcon.js +1 -1
  372. package/dist/icons/CubePauseIcon.js +1 -1
  373. package/dist/icons/CubePlayIcon.js +1 -1
  374. package/dist/icons/CurrencyDollarIcon.js +1 -1
  375. package/dist/icons/DangerIcon.js +1 -1
  376. package/dist/icons/DashboardIcon.js +1 -1
  377. package/dist/icons/DatabaseIcon.js +1 -1
  378. package/dist/icons/DecimalDecreaseIcon.js +1 -1
  379. package/dist/icons/DecimalIncreaseIcon.js +1 -1
  380. package/dist/icons/DirectionIcon.js +1 -1
  381. package/dist/icons/DonutIcon.js +1 -1
  382. package/dist/icons/DownIcon.js +1 -1
  383. package/dist/icons/EditIcon.js +1 -1
  384. package/dist/icons/ExclamationCircleFilledIcon.js +1 -1
  385. package/dist/icons/ExclamationCircleIcon.js +1 -1
  386. package/dist/icons/ExclamationIcon.js +1 -1
  387. package/dist/icons/EyeIcon.js +1 -1
  388. package/dist/icons/EyeInvisibleIcon.js +1 -1
  389. package/dist/icons/FilterIcon.js +1 -1
  390. package/dist/icons/FolderFilledIcon.js +1 -1
  391. package/dist/icons/FolderIcon.js +1 -1
  392. package/dist/icons/FolderOpenFilledIcon.js +1 -1
  393. package/dist/icons/FolderOpenIcon.js +1 -1
  394. package/dist/icons/ForwardIcon.js +1 -1
  395. package/dist/icons/GripVerticalIcon.js +1 -1
  396. package/dist/icons/HierarchyIcon.js +1 -1
  397. package/dist/icons/HierarchyOpenIcon.js +1 -1
  398. package/dist/icons/Icon.js +1 -1
  399. package/dist/icons/InfoCircleIcon.js +1 -1
  400. package/dist/icons/InfoIcon.js +1 -1
  401. package/dist/icons/KeyIcon.js +1 -1
  402. package/dist/icons/LeftIcon.js +1 -1
  403. package/dist/icons/LineChartIcon.js +1 -1
  404. package/dist/icons/LoadingIcon.js +1 -1
  405. package/dist/icons/LockFilledIcon.js +1 -1
  406. package/dist/icons/LockIcon.js +1 -1
  407. package/dist/icons/MoreIcon.js +1 -1
  408. package/dist/icons/NotAllowedIcon.js +1 -1
  409. package/dist/icons/Number123Icon.js +1 -1
  410. package/dist/icons/NumberIcon.js +1 -1
  411. package/dist/icons/PauseCircleFilledIcon.js +1 -1
  412. package/dist/icons/PauseCircleIcon.js +1 -1
  413. package/dist/icons/PauseIcon.js +1 -1
  414. package/dist/icons/PercentageIcon.js +1 -1
  415. package/dist/icons/PieChartIcon.js +1 -1
  416. package/dist/icons/PlayCircleIcon.js +1 -1
  417. package/dist/icons/PlayIcon.js +1 -1
  418. package/dist/icons/PlusIcon.js +1 -1
  419. package/dist/icons/ProgressBarIcon.js +1 -1
  420. package/dist/icons/ReloadIcon.js +1 -1
  421. package/dist/icons/ReportIcon.js +1 -1
  422. package/dist/icons/ReturnIcon.js +1 -1
  423. package/dist/icons/RightIcon.js +1 -1
  424. package/dist/icons/RowTotalsIcon.js +1 -1
  425. package/dist/icons/SchemeIcon.js +1 -1
  426. package/dist/icons/SearchIcon.js +1 -1
  427. package/dist/icons/SemanticQueryIcon.js +1 -1
  428. package/dist/icons/SettingsIcon.js +1 -1
  429. package/dist/icons/ShieldFilledIcon.js +1 -1
  430. package/dist/icons/ShieldIcon.js +1 -1
  431. package/dist/icons/SlashIcon.js +1 -1
  432. package/dist/icons/SparklesIcon.js +1 -1
  433. package/dist/icons/SqlIcon.js +1 -1
  434. package/dist/icons/StatsIcon.js +1 -1
  435. package/dist/icons/StopIcon.js +1 -1
  436. package/dist/icons/StringIcon.js +1 -1
  437. package/dist/icons/SubtotalsIcon.js +1 -1
  438. package/dist/icons/SwitchIcon.js +1 -1
  439. package/dist/icons/TableIcon.js +1 -1
  440. package/dist/icons/ThumbsDownIcon.js +1 -1
  441. package/dist/icons/ThumbsUpIcon.js +1 -1
  442. package/dist/icons/ThunderboltCrossedIcon.js +1 -1
  443. package/dist/icons/ThunderboltFilledIcon.js +1 -1
  444. package/dist/icons/ThunderboltIcon.js +1 -1
  445. package/dist/icons/TimeIcon.js +1 -1
  446. package/dist/icons/TrashIcon.js +1 -1
  447. package/dist/icons/UnlockIcon.js +1 -1
  448. package/dist/icons/UpIcon.js +1 -1
  449. package/dist/icons/UserGroupIcon.js +1 -1
  450. package/dist/icons/UserIcon.js +1 -1
  451. package/dist/icons/UserLockIcon.js +1 -1
  452. package/dist/icons/ViewIcon.js +1 -1
  453. package/dist/icons/WarningFilledIcon.js +1 -1
  454. package/dist/icons/WarningIcon.js +1 -1
  455. package/dist/icons/wrap-icon.js +1 -1
  456. package/dist/index.d.ts +6 -6
  457. package/dist/index.js +6 -5
  458. package/dist/index.js.map +1 -1
  459. package/dist/provider.d.ts +1 -1
  460. package/dist/provider.js +1 -1
  461. package/dist/provider.js.map +1 -1
  462. package/dist/providers/TrackingProvider.js +1 -1
  463. package/dist/providers/navigationAdapter.default.js +1 -1
  464. package/dist/shared/form.d.ts +28 -3
  465. package/dist/shared/index.d.ts +1 -1
  466. package/dist/tokens/base.js +1 -1
  467. package/dist/tokens/colors.d.ts +41 -2
  468. package/dist/tokens/colors.js +77 -9
  469. package/dist/tokens/colors.js.map +1 -1
  470. package/dist/tokens/index.d.ts +3 -2
  471. package/dist/tokens/index.js +23 -16
  472. package/dist/tokens/index.js.map +1 -1
  473. package/dist/tokens/layout.js +1 -1
  474. package/dist/tokens/lazy-styles.js +10 -6
  475. package/dist/tokens/lazy-styles.js.map +1 -1
  476. package/dist/tokens/palette-config.d.ts +203 -0
  477. package/dist/tokens/palette-config.js +253 -0
  478. package/dist/tokens/palette-config.js.map +1 -0
  479. package/dist/tokens/palette.d.ts +45 -5
  480. package/dist/tokens/palette.js +567 -403
  481. package/dist/tokens/palette.js.map +1 -1
  482. package/dist/tokens/shadows.js +1 -1
  483. package/dist/tokens/sizes.js +1 -1
  484. package/dist/tokens/spacing.js +1 -1
  485. package/dist/tokens/typography.js +1 -1
  486. package/dist/utils/ResizeSensor.js +1 -1
  487. package/dist/utils/is-dev-env.js +1 -1
  488. package/dist/utils/modules.js +1 -1
  489. package/dist/utils/promise.js +1 -1
  490. package/dist/utils/raf.js +1 -1
  491. package/dist/utils/random.js +1 -1
  492. package/dist/utils/range.js +1 -1
  493. package/dist/utils/react/RenderCache.js +1 -1
  494. package/dist/utils/react/Slots.js +1 -1
  495. package/dist/utils/react/chain.js +1 -1
  496. package/dist/utils/react/forwardRefWithGenerics.js +1 -1
  497. package/dist/utils/react/index.js +1 -1
  498. package/dist/utils/react/interactions.js +1 -1
  499. package/dist/utils/react/isTextOnly.js +1 -1
  500. package/dist/utils/react/mapProps.js +1 -1
  501. package/dist/utils/react/mergeProps.d.ts +1 -1
  502. package/dist/utils/react/mergeProps.js +1 -1
  503. package/dist/utils/react/mergeProps.js.map +1 -1
  504. package/dist/utils/react/nullableValue.d.ts +1 -1
  505. package/dist/utils/react/nullableValue.js +1 -1
  506. package/dist/utils/react/nullableValue.js.map +1 -1
  507. package/dist/utils/react/resolveIcon.js +1 -1
  508. package/dist/utils/react/sharedStore.js +1 -1
  509. package/dist/utils/react/useCombinedRefs.js +1 -1
  510. package/dist/utils/react/useControlledFocusVisible.js +1 -1
  511. package/dist/utils/react/useEventBus.js +1 -1
  512. package/dist/utils/react/useId.js +1 -1
  513. package/dist/utils/react/useIsDarwin.js +1 -1
  514. package/dist/utils/react/useKeySymbols.js +1 -1
  515. package/dist/utils/react/useLayoutEffect.js +1 -1
  516. package/dist/utils/react/useLocalStorage.js +1 -1
  517. package/dist/utils/react/useMergeStyles.js +1 -1
  518. package/dist/utils/react/usePopoverSync.js +1 -1
  519. package/dist/utils/react/useQaProps.js +1 -1
  520. package/dist/utils/react/useViewportSize.js +1 -1
  521. package/dist/utils/react/wrapNodeIfPlain.js +1 -1
  522. package/dist/utils/selection.js +1 -1
  523. package/dist/utils/styles.js +1 -1
  524. package/dist/utils/tree.js +1 -1
  525. package/dist/utils/warnings.js +1 -1
  526. package/dist/version.js +3 -3
  527. package/docs/Colors.md +4 -0
  528. package/docs/Theming.md +327 -0
  529. package/docs/Usage.md +30 -3
  530. package/docs/components/Root.md +1 -0
  531. package/docs/glaze/api.md +156 -8
  532. package/docs/glaze/methodology.md +21 -1
  533. package/docs/glaze/okhst.md +13 -0
  534. package/docs/tasty/README.md +1 -3
  535. package/docs/tasty/ai-agents.md +7 -21
  536. package/docs/tasty/configuration.md +30 -220
  537. package/docs/tasty/debug.md +7 -7
  538. package/docs/tasty/design-system.md +2 -2
  539. package/docs/tasty/dsl.md +8 -68
  540. package/docs/tasty/injector.md +4 -31
  541. package/docs/tasty/methodology.md +1 -1
  542. package/docs/tasty/pipeline.md +3 -3
  543. package/docs/tasty/react-api.md +1 -61
  544. package/docs/tasty/ssr.md +33 -40
  545. package/docs/tasty/styles.md +9 -27
  546. package/docs/tasty/tasty-static.md +6 -8
  547. package/package.json +4 -4
  548. package/dist/props.d.ts +0 -13
  549. package/docs/tasty/migration-v3.md +0 -285
  550. package/docs/tasty/plugins.md +0 -349
@@ -0,0 +1,327 @@
1
+ # Theming
2
+
3
+ The whole palette is generated by [Glaze](https://github.com/tenphi/glaze) from a
4
+ handful of seeds: an accent hue, a base hue, a saturation, and a hue per status
5
+ theme. Those seeds are tunable at runtime — change one and every token re-resolves, in light,
6
+ dark, and high-contrast schemes at once.
7
+
8
+ ```ts
9
+ import { setPaletteConfig } from '@cube-dev/ui-kit';
10
+
11
+ setPaletteConfig({
12
+ hue: 210,
13
+ saturation: 72,
14
+ themes: { danger: { hue: 12 } },
15
+ });
16
+ ```
17
+
18
+ With no configuration set, the palette is exactly the one the kit ships — the
19
+ defaults below are the shipped seeds, and a snapshot test pins every resolved
20
+ value so this stays true.
21
+
22
+ ## What is tunable
23
+
24
+ | Option | Scope | Default |
25
+ | --- | --- | --- |
26
+ | `hue` | **Accent** hue in degrees — the brand. Drives the `accent-*` family, `primary` / `purple` / `special`, and the brand-tinted `focus`, loading faces and disabled chip. | `280.3` |
27
+ | `baseHue` | **Base** hue in degrees — the neutral chrome: `surface` and its ladder, the `surface-text*` ramp, `border`, `placeholder`. | inherits `hue` |
28
+ | `saturation` | Seed saturation (0–100) for the `default` theme, and the fallback for every theme that sets none. | `80` |
29
+ | `themes.<status>.hue` | Hue for `success` / `danger` / `warning` / `note`. | `156.9` / `23.1` / `84.3` / `302.3` |
30
+ | `themes.<status>.saturation` | Saturation for that status theme. | inherits `saturation` |
31
+ | `themes.code.saturation` | Saturation for the `code-*` syntax family. Hues are fixed, and this does **not** inherit `saturation`. | `80` |
32
+ | `pastel` | Global. Relaxes the sRGB-safe chroma limit. | `false` |
33
+ | `contrastLevel` | Global. `'auto'`, or a manual `0`–`100` level. | `'auto'` |
34
+
35
+ Fields merge, like `glaze.configure()` — omitted fields keep their current
36
+ value, and per-theme fields left unset keep inheriting. So this leaves `warning`
37
+ at its explicit saturation while everything else follows the new palette-level
38
+ one:
39
+
40
+ ```ts
41
+ setPaletteConfig({ themes: { warning: { saturation: 95 } } });
42
+ setPaletteConfig({ saturation: 55 }); // warning stays at 95
43
+ ```
44
+
45
+ `resetPaletteConfig()` drops all tuning at once.
46
+
47
+ ### Two hue zones
48
+
49
+ Hue is split into an **accent** zone and a **base** zone:
50
+
51
+ - **Accent** (`hue`) — the `accent-*` family on every theme, `primary` / `purple` /
52
+ `special`, plus `focus`, the loading faces and the disabled chip.
53
+ - **Base** (`baseHue`) — the neutral chrome: `surface` and its ladder, the
54
+ `surface-text*` ramp, `border`, `placeholder`.
55
+
56
+ `baseHue` inherits `hue`, so out of the box the chrome carries a faint tint of the
57
+ brand. Set it to decouple them — a warm grey UI under a cool blue brand:
58
+
59
+ ```ts
60
+ setPaletteConfig({ hue: 235, baseHue: 60 });
61
+ ```
62
+
63
+ Only the `default` theme is affected. A colored theme's tinted `surface`
64
+ deliberately follows *its own* hue, because a danger banner should read as red.
65
+
66
+ ### One saturation scale per theme
67
+
68
+ Saturation is *not* split, deliberately: `saturation` is the theme's **seed**, and
69
+ every color's own `saturation` is a 0–1 factor of it. `surface` sits at `0.12`,
70
+ `border` at `0.175`, the text ramp at `0.2`, the accent family at ~`1.0`.
71
+
72
+ So the palette has one saturation *scale*, and everything on it keeps its
73
+ proportions: turning `saturation` down mutes the brand fills and the neutral tint
74
+ together, in the ratios the palette was designed around. That is the point — the
75
+ relationship between a subtle surface tint and a saturated accent is part of the
76
+ design, not something to tune per token.
77
+
78
+ ### The `code-*` family is the exception
79
+
80
+ Syntax colors are their own theme with their own seed, so neither the brand hue nor
81
+ the palette saturation reaches them. Hues are absolute literals — a brand re-seeded
82
+ toward green would otherwise collide `code-string` with `code-number` (156°) — and
83
+ the saturation is fixed at `80` rather than inheriting, so muting the app cannot
84
+ wash out a code block. Tune it on its own:
85
+
86
+ ```ts
87
+ setPaletteConfig({ themes: { code: { saturation: 60 } } });
88
+ ```
89
+
90
+ They are still *adaptive*: each one is anchored to the real `surface` with an
91
+ `['AA','AAA']` floor, so they re-solve for light, dark and high contrast. Only hue
92
+ and saturation are pinned.
93
+
94
+ That separate seed is also a hard requirement, not a preference: a Glaze colour can
95
+ never exceed its own theme seed, and four of these sit at factor `1.0`. Inside a
96
+ default theme seeded below 80 they simply could not hold their chroma.
97
+
98
+ ### Inherited vs pinned
99
+
100
+ Every per-theme field starts out **inheriting** the palette-level value, so
101
+ `baseHue` tracks `hue` until something sets it, and `themes.<status>.saturation`
102
+ tracks `saturation`. Moving the accent hue therefore appears to move the base hue
103
+ too — they are not linked, `baseHue` simply has no value of its own yet.
104
+
105
+ Writing the field pins it; passing `undefined` clears the pin so it inherits again:
106
+
107
+ ```ts
108
+ setPaletteConfig({ baseHue: 60 }); // pin
109
+ setPaletteConfig({ hue: 235 }); // baseHue stays at 60
110
+ setPaletteConfig({ baseHue: undefined }); // inherit again → 235
111
+ ```
112
+
113
+ `getPaletteConfig()` resolves everything, which loses that distinction — it cannot
114
+ tell you whether `80` was chosen or inherited. `getPaletteConfigInput()` returns the
115
+ sparse config as set, which is what a settings UI needs to render an inherited value
116
+ as inherited and offer a way back:
117
+
118
+ ```ts
119
+ const pinned = getPaletteConfigInput().baseHue !== undefined;
120
+ ```
121
+
122
+ Pinning a field to the value it already inherited resolves to the same colors but
123
+ still counts as a change, so a UI reading the sparse config re-renders. Re-applying
124
+ an *already pinned* value is a true no-op and costs nothing.
125
+
126
+ ## Palette playground
127
+
128
+ Drag the brand hue and watch the accent ramp, the neutral surfaces, the buttons,
129
+ the borders and the shadows move together. Nothing re-renders: every color in the
130
+ kit compiles to a CSS custom property, so re-seeding replaces a single rule on
131
+ `body` and the browser repaints.
132
+
133
+ Two things worth noticing while you tune:
134
+
135
+ - The **neutral** surfaces carry saturation factors of 0.10–0.175, so they read
136
+ as a faint tint of the brand hue. That is where the saturation seed is
137
+ legible — the solid accents hide it.
138
+ - The **syntax** colors do not move at all — they are their own theme with their
139
+ own seed, so neither the accent hue nor the saturation reaches them.
140
+
141
+ ## Status themes
142
+
143
+ Each status theme is a Glaze `extend()` of the default theme with its own hue, so
144
+ tuning one moves only its own `#<theme>-*` family.
145
+
146
+ ## Contrast level
147
+
148
+ By default contrast is a two-tier switch: normal colors plus a separate
149
+ high-contrast set, selected by `<html data-contrast="high">` or a
150
+ `prefers-contrast: more` preference.
151
+
152
+ A manual `contrastLevel` replaces both tiers with a single 0–100 slider. Because
153
+ the level already carries the contrast preference, **no separate high-contrast
154
+ variant is emitted** — which means `data-contrast="high"` and
155
+ `prefers-contrast: more` stop having any effect while a level is set. Levels `0`
156
+ and `100` reproduce the normal and high-contrast palettes bit for bit, so the
157
+ slider is a continuous interpolation between exactly what the two tiers ship
158
+ today.
159
+
160
+ That is a real accessibility trade-off: leave `contrastLevel` at `'auto'` unless
161
+ you are giving users their own contrast control.
162
+
163
+ ## Theme builder
164
+
165
+ The `Theme Builder` story puts the whole config behind controls and renders the
166
+ result into a single region: pick **Auto / Light / Dark** and **Auto / Normal /
167
+ High** and the preview shows exactly that variant while the page around it stays
168
+ as it is. `Auto` is resolved from the document — a flat token value cannot mean
169
+ "follow the OS", so the story reads `<html data-schema>` / `data-contrast` with the
170
+ matching media query as a fallback, the same two sources `Root` uses.
171
+
172
+ The preview deliberately shows all three surface levels with their own text ramps
173
+ (`#surface-text`, `#surface-2-text`, `#surface-3-text`), because a theme that looks
174
+ fine on the page surface can fall apart two panels deep.
175
+
176
+ ## Previewing a theme in a region
177
+
178
+ `setPaletteConfig()` re-themes the whole document, which is no use for a theme
179
+ picker — you want several themes visible at once, or a dark preview inside a light
180
+ page. `renderColorTokens()` does that: it resolves the palette for **one** config
181
+ and **one** scheme and returns flat literal values, ready to apply to a subtree
182
+ through a tasty `tokens` prop.
183
+
184
+ ```tsx
185
+ import { renderColorTokens, tasty } from '@cube-dev/ui-kit';
186
+
187
+ const Region = tasty({ styles: { fill: '#surface', color: '#surface-text' } });
188
+
189
+ const preview = useMemo(
190
+ () => renderColorTokens({ hue: 210, scheme: 'dark' }),
191
+ [],
192
+ );
193
+
194
+ <Region tokens={preview}>…everything in here renders in that theme…</Region>;
195
+ ```
196
+
197
+ The reason this needs its own API: the document palette emits **state maps**
198
+ (`{ '': …, '@dark': …, '@hc': … }`), so a page can only ever show one scheme at a
199
+ time — that is what `@dark` means. Collapsing the palette to a chosen scheme
200
+ removes the conditionality, so several themes can coexist.
201
+
202
+ | Option | Meaning |
203
+ | --- | --- |
204
+ | every `PaletteConfig` field | merged over the **current** config, so `{ scheme: 'dark' }` previews the active theme in dark |
205
+ | `scheme` | `'light'` (default) or `'dark'` |
206
+ | `highContrast` | resolve that scheme's high-contrast variant. Default `false` |
207
+
208
+ Nothing is applied globally — the live palette and the stored config are
209
+ untouched, so previews are safe to render anywhere.
210
+
211
+ Notes:
212
+
213
+ - Real components work inside a region. Every color in the kit compiles to a CSS
214
+ custom property, so overriding those properties on one element re-colors its
215
+ whole subtree with no scheme attribute and no second `<Root>`.
216
+ - The legacy aliases come along **by reference** (`'#dark': '#surface-text'`), and
217
+ so do the shadow tokens and scrollbar colors, whose values embed a palette
218
+ color. Tasty re-declares them on the region so each `var()` resolves against the
219
+ region's own values; resolving them up front would freeze them to the outer
220
+ theme instead.
221
+ - Typography, spacing, sizes and layout are **not** included — nothing in their
222
+ values references a color, so the region inherits them from `<Root>`.
223
+ - `contrastLevel` works per region, so the whole 0–100 ramp can be shown at once —
224
+ something a document cannot do, since it is only ever at one level. Level `0`
225
+ reproduces the normal tier and `100` the high-contrast tier exactly, in both
226
+ schemes. Because a manual level leaves no separate high-contrast tier,
227
+ `highContrast: true` correctly returns the same colors as the normal variant.
228
+ Note that tokens carrying a contrast *floor* (most text) can sit still over part
229
+ of the ramp — the floor is solved, not approximated, so the value only moves once
230
+ the interpolated target does. Tokens positioned by a plain tone pair, like
231
+ `#border`, step at every level.
232
+ - Resolving a palette costs a few milliseconds. The last config is memoized, but
233
+ `useMemo` on the caller side if you drive it from state.
234
+
235
+ `renderPaletteTokens()` is the same thing without the aliases and companion
236
+ tokens, if you want only the Glaze palette.
237
+
238
+ ## Reading and reacting to the config
239
+
240
+ ```tsx
241
+ import {
242
+ DEFAULT_PALETTE_CONFIG,
243
+ getPaletteConfig,
244
+ resetPaletteConfig,
245
+ setPaletteConfig,
246
+ subscribePaletteConfig,
247
+ usePaletteConfig,
248
+ } from '@cube-dev/ui-kit';
249
+
250
+ // In React — `useState`-style, and re-renders on change.
251
+ const [palette, setPalette] = usePaletteConfig();
252
+
253
+ // Outside React.
254
+ getPaletteConfig(); // every field resolved to a concrete value
255
+ subscribePaletteConfig(() => {
256
+ /* … */
257
+ });
258
+ ```
259
+
260
+ `getPaletteConfig()` always returns the fully resolved form, so
261
+ `getPaletteConfig().themes.danger.saturation` is a number even if nobody ever set
262
+ it. `DEFAULT_PALETTE_CONFIG` is the shipped baseline in the same shape.
263
+
264
+ ## `<Root palette>`
265
+
266
+ `<Root>` accepts the same config as a prop, applied during render so the first
267
+ paint is already correct:
268
+
269
+ ```tsx
270
+ <Root palette={{ hue: userAccentHue }}>
271
+ <App />
272
+ </Root>
273
+ ```
274
+
275
+ This is a convenience wrapper over `setPaletteConfig()`, not a separate scope.
276
+ **The palette is process-global** — Glaze's own config is, and so is the single
277
+ `body` rule the tokens are injected into. One palette per process, not per tree
278
+ and not per request:
279
+
280
+ - Two `<Root>`s with different `palette` props will fight over the same tokens.
281
+ - Under SSR, apply the palette in code that runs on **both** server and client.
282
+ A client-only `setPaletteConfig` disposes and replaces the server-rendered
283
+ token block on the first render, which is visible as a flash. Per-request
284
+ palettes are not supported.
285
+
286
+ ## Caveats
287
+
288
+ **`pastel: true` is a redesign, not a filter.** It changes every resolved color.
289
+ The per-color saturation factors in this palette were tuned for the non-pastel
290
+ space — pastel equalizes chroma across hues, so a pastel palette on the shipped
291
+ seeds resolves more saturated than you may expect. Re-tune the seeds alongside
292
+ it.
293
+
294
+ **Re-seeding costs about 10 ms.** Rebuilding the eight themes and re-solving
295
+ ~156 tokens across four scheme variants is not free, though it is inside a frame.
296
+ A manual `contrastLevel` is cheaper, since it skips both high-contrast passes.
297
+ Setting the config to a value it already holds is free — it does not even bump
298
+ the version. If you are driving it from a slider, let the input coalesce to
299
+ frames (a pointer-driven `onChange` already does) rather than writing on every
300
+ event.
301
+
302
+ **If you call Glaze directly, tell the kit.** `glaze.configure({ darkTone })` and
303
+ friends invalidate Glaze's own caches, but the kit's token maps are memoized
304
+ against the palette config version:
305
+
306
+ ```ts
307
+ import { glaze, invalidatePaletteTokens } from '@cube-dev/ui-kit';
308
+
309
+ glaze.configure({ darkDesaturation: 0.2 });
310
+ invalidatePaletteTokens(); // only needed once the kit is already mounted
311
+ ```
312
+
313
+ `contrastLevel` is the one field the kit writes to Glaze's global config, and it
314
+ only ever does so if you asked for a level. A host that sets its own
315
+ `glaze.configure({ contrastLevel })` and never passes `contrastLevel` here keeps
316
+ it.
317
+
318
+ **Some things are not tunable at all.** Tasty locks its configuration on the
319
+ first style injection, so the `@dark` / `@hc` state definitions and the
320
+ `colorSpace` (both set in `Root`) are fixed for the lifetime of the page. Only
321
+ token *values* stay mutable — which is all re-seeding needs.
322
+
323
+ ## See also
324
+
325
+ - [Colors](./Colors.md) — how to pair surfaces with
326
+ foregrounds, and what each token family is for.
327
+ - [Usage](./Usage.md) — the full token reference.
package/docs/Usage.md CHANGED
@@ -94,6 +94,8 @@ All color tokens use `#name` syntax in styles. Opacity variants use `#name.NN` (
94
94
 
95
95
  The palette is generated by [`@tenphi/glaze`](https://github.com/tenphi/glaze) (see `src/tokens/palette.ts`). Every color token is emitted as a state map with `light`, `@dark`, and `@hc` (high-contrast) variants, so the entire UI Kit adapts to dark / high-contrast schemes automatically.
96
96
 
97
+ The seeds it is generated from — brand hue, saturation, per-status hues, `pastel`, `contrastLevel` — are tunable at runtime. See [Theming](./Theming.md).
98
+
97
99
  ### Color Schemes
98
100
 
99
101
  The `@dark` and `@hc` predefined states are wired up in `src/components/Root.tsx` to support both an attribute opt-in and the user's system preference:
@@ -156,10 +158,12 @@ In the `default` theme these tokens are unprefixed (`#accent-surface`). In color
156
158
 
157
159
  ### Themed Surfaces
158
160
 
159
- Each colored theme (`primary`, `purple`, `success`, `danger`, `warning`, `note`) also provides its own tinted `<theme>-surface` (banner / chip background) and `<theme>-surface-text` (banner text):
161
+ Each colored theme (`primary`, `purple`, `success`, `danger`, `warning`, `note`) also provides its own tinted `<theme>-surface` (banner / chip background) and `<theme>-surface-text` (banner text).
162
+
163
+ The hues below are the *defaults*; each is tunable at runtime (see [Theming](./Theming.md)).
160
164
 
161
- | Group | Hue | Purpose |
162
- |-------|-----|---------|
165
+ | Group | Default hue | Purpose |
166
+ |-------|-------------|---------|
163
167
  | `#primary-*` / `#purple-*` | 280.3° | Primary actions, brand color |
164
168
  | `#success-*` | 156.9° | Success states, confirmations |
165
169
  | `#danger-*` | 23.1° | Errors, destructive actions |
@@ -168,6 +172,29 @@ Each colored theme (`primary`, `purple`, `success`, `danger`, `warning`, `note`)
168
172
 
169
173
  For example, a success banner uses `fill: '#success-surface'` + `color: '#success-surface-text'`, while a primary button uses `fill: '#primary-accent-surface'` + `color: '#primary-accent-surface-text'`.
170
174
 
175
+ ### Runtime Theming
176
+
177
+ `setPaletteConfig()` re-seeds the palette after the kit has mounted; every token re-resolves and `<Root>` re-injects the token block. No component re-render is involved, because every color compiles to a CSS custom property.
178
+
179
+ ```ts
180
+ import { resetPaletteConfig, setPaletteConfig } from '@cube-dev/ui-kit';
181
+
182
+ setPaletteConfig({ hue: 210, themes: { danger: { hue: 12 } } });
183
+ resetPaletteConfig();
184
+ ```
185
+
186
+ Also available: `getPaletteConfig()`, `subscribePaletteConfig()`, the `usePaletteConfig()` hook, a `<Root palette={…}>` prop, `DEFAULT_PALETTE_CONFIG`, and `invalidatePaletteTokens()` for when you drive `glaze.configure(...)` yourself after mount. The palette is process-global — one palette per process, not per tree or per request.
187
+
188
+ To theme a *region* instead of the document — a theme preview, or a dark panel inside a light page — use `renderColorTokens()`. It resolves one config and one scheme to flat values you apply via a `tokens` prop, without touching the live palette:
189
+
190
+ ```tsx
191
+ <Block tokens={renderColorTokens({ hue: 210, scheme: 'dark' })} fill="#surface">
192
+ …
193
+ </Block>
194
+ ```
195
+
196
+ Full contract, caveats and a live playground: [Theming](./Theming.md).
197
+
171
198
  ### Legacy Aliases
172
199
 
173
200
  The previous token names continue to work as aliases (defined at the bottom of `src/tokens/colors.ts`). New code should prefer the Glaze tokens, but existing components do not need to be migrated:
@@ -13,6 +13,7 @@ The root application wrapper. Provides theme context, global styles, portal cont
13
13
  - **`navigation`** `NavigationAdapter` — Custom navigation adapter for routing
14
14
  - **`tracking`** `TrackingProps` — Analytics/tracking event configuration
15
15
  - **`tokens`** `Record<string, string>` — Custom design tokens (CSS custom properties)
16
+ - **`palette`** `PaletteConfig` — Tune the generated color palette: brand `hue` / `saturation`, per-status theme seeds, `pastel`, `contrastLevel`. Applied during render, so the first paint is already correct. A convenience wrapper over `setPaletteConfig()` — the palette is process-global, not per tree. See [Theming](../Theming.md)
16
17
  - **`fonts`** `boolean` — Whether to load default fonts
17
18
  - **`font`** `string` — Custom font family name
18
19
  - **`monospaceFont`** `string` — Custom monospace font family name
package/docs/glaze/api.md CHANGED
@@ -10,6 +10,7 @@ Full reference for every public method, option, and type exported by `@tenphi/gl
10
10
  - [DTCG Resolver-Module](#themedtcgresolveroptions)
11
11
  - [Tailwind CSS](#themetailwindoptions)
12
12
  - [High-contrast pairs](#high-contrast-pairs)
13
+ - [Manual contrast level](#manual-contrast-level)
13
14
  - [Color definitions](#color-definitions)
14
15
  - [Dark seed](#dark-seed-darkhue--darksaturation)
15
16
  - [Standalone color tokens](#standalone-color-tokens)
@@ -408,6 +409,144 @@ promotion for that color.
408
409
 
409
410
  ---
410
411
 
412
+ ## Manual contrast level
413
+
414
+ `contrastLevel` turns contrast from a two-tier switch into a `0–100` slider.
415
+ It is a config field, so it works globally, per theme, per token, and through
416
+ `extend()`:
417
+
418
+ ```ts
419
+ glaze.configure({ contrastLevel: 60 });
420
+ const theme = glaze(280, 80, { contrastLevel: 60 });
421
+ glaze.color('#26fcb2', { contrastLevel: 60 });
422
+ ```
423
+
424
+ | Value | Meaning |
425
+ | ---------------- | -------------------------------------------------------------------- |
426
+ | `'auto'` | Default. The two-tier model: normal variants plus a high-contrast tier. |
427
+ | `0` | Normal contrast, with **no** high-contrast tier. |
428
+ | `100` | The high-contrast scheme as the only scheme. |
429
+ | anything between | Resolved *at* that level. |
430
+
431
+ Levels `0` and `100` reproduce the classic `light` / `dark` and
432
+ `lightContrast` / `darkContrast` output **bit for bit**.
433
+
434
+ ### What the level interpolates
435
+
436
+ Exactly the three things that make a high-contrast variant differ from its
437
+ normal counterpart:
438
+
439
+ | Mechanism | At level `L` |
440
+ | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
441
+ | Authored `HCPair`s — `tone`, `contrast`, shadow `intensity`, mix `value` | the two ends are interpolated |
442
+ | The tone-window bypass | each endpoint moves toward the full range: light `10→0`, dark `15→0 / 95→100` |
443
+ | Contrast escalation — `AA → AAA`, APCA `+15 Lc` | the two numeric targets are interpolated (`AA` at level 50 solves for 5.75) |
444
+
445
+ The interpolated values are then fed through the ordinary resolve, so a
446
+ contrast floor at any level is **solved**, not approximated, and `autoFlip`
447
+ decides once per level.
448
+
449
+ Everything that does not vary by high contrast today — hue, saturation,
450
+ `darkDesaturation`, `opacity`, `pastel` — is unaffected by the level.
451
+
452
+ ### Un-interpolable tone pairs switch at 50
453
+
454
+ Two ends of different kinds have no midpoint, because blending them would
455
+ change *which* resolution rule applies partway up the ramp. These switch from
456
+ the normal entry to the high-contrast one at level 50:
457
+
458
+ ```ts
459
+ tone: [50, 'max']; // absolute vs. extreme
460
+ tone: [50, '+20']; // absolute vs. relative
461
+ tone: ['max', 'min']; // opposite extremes
462
+ ```
463
+
464
+ Same-kind pairs (`[30, 20]`, `['-6', '-12']`, `{ wcag: [4.5, 7] }`,
465
+ `[{ apca: 60 }, { apca: 90 }]`) interpolate smoothly.
466
+
467
+ A `contrast` pair may **not** switch metric — `[4.5, { apca: 75 }]` throws. A
468
+ WCAG ratio and an APCA Lc are different scales, so no target exists between
469
+ them, and even in `'auto'` mode the two variants would be incomparable. Pair
470
+ values inside one metric instead: `{ wcag: [4.5, 7] }` or `{ apca: [60, 90] }`.
471
+
472
+ ### A color never swaps sides mid-slider
473
+
474
+ [`autoFlip`](#autoflip) decides per solve, and its tie-break — when both
475
+ directions meet the floor, take the one nearer the authored tone — depends on
476
+ the target. Along a ramp of targets that criterion shifts, so a naive
477
+ implementation lets a color leap across its own base as the slider moves.
478
+
479
+ Under a manual level the side is instead decided once, from the nearer
480
+ endpoint's target, and preferred at every level in that half of the ramp.
481
+ Consequences:
482
+
483
+ - A color whose two ends land on the same side of its base **never** changes
484
+ side, at any level.
485
+ - A color whose ends genuinely disagree — no single side can satisfy both its
486
+ normal and its high-contrast floor — changes side exactly once, at level 50,
487
+ the same place un-interpolable tone pairs switch.
488
+ - Flipping is not disabled, only re-ordered, so a side that physically cannot
489
+ reach the requested contrast still falls back to the opposite one. The floor
490
+ is met at every level.
491
+
492
+ The underlying solver option is `preferInitial` on
493
+ [`findToneForContrast`](#contrast-solver), should you need the same behavior
494
+ directly.
495
+
496
+ ### High-contrast output
497
+
498
+ A manual level already carries the contrast preference, so there is no second
499
+ tier to emit:
500
+
501
+ - `resolve()` still returns four variants, but `lightContrast` / `darkContrast`
502
+ **mirror** `light` / `dark`.
503
+ - A **global** level turns high-contrast output off outright, so
504
+ `tokens()` / `tasty()` / `json()` / `dtcg()` / `dtcgResolver()` / `tailwind()`
505
+ emit no high-contrast tier. `modes.highContrast` goes inert — it reads as
506
+ "emit a separate high-contrast set *when* contrast is automatic" — so leaving
507
+ `highContrast: true` set in a build config while a user switches their
508
+ preference from auto to manual is fine, and silent.
509
+ - `css()` always returns four strings and ignores `modes`, so its
510
+ `lightContrast` / `darkContrast` strings repeat the normal declarations —
511
+ an existing `@media (prefers-contrast: more)` block keeps matching the base
512
+ block as the level changes, with nothing to rewire.
513
+ - A level on a **single theme or token** does not change which modes are
514
+ emitted. Sibling themes in a palette keep their real high-contrast tier, and
515
+ the manual one reports its own resolved values there.
516
+
517
+ ### Driving it at runtime
518
+
519
+ `configure()` bumps the config version, which invalidates every theme and token
520
+ cache, so a slider only needs to re-export:
521
+
522
+ ```ts
523
+ slider.oninput = () => {
524
+ glaze.configure({ contrastLevel: slider.valueAsNumber });
525
+ apply(theme.css());
526
+ };
527
+ ```
528
+
529
+ Because a manual level skips the two high-contrast passes, a manual resolve is
530
+ also half the work of an `'auto'` one.
531
+
532
+ ### Clearing it, exporting it, base links
533
+
534
+ - **`configure()` never clears a field by omission.** Pass `'auto'` explicitly
535
+ to leave manual mode — globally, or on one theme of a palette.
536
+ - **`.export()` freezes only an *authored* level.** A level set on the instance
537
+ (or passed to `.export()`) is authored intent and is written to the snapshot;
538
+ a level merely inherited from the global config is a live user preference and
539
+ is left out, so a restored theme still follows the current slider. This
540
+ matches how `modes` and `states` are treated.
541
+ - **Set the level globally, or on both sides of a base link.** A per-token level
542
+ on a dependent but not on its base anchors the two at different levels — the
543
+ same caveat as a per-instance `lightTone` override.
544
+
545
+ `resolveContrastForLevel(spec, level, polarity?)` is exported for advanced use;
546
+ see [Contrast solver](#contrast-solver).
547
+
548
+ ---
549
+
411
550
  ## Color definitions
412
551
 
413
552
  `ColorDef` is a discriminated union:
@@ -490,7 +629,7 @@ type ContrastSpec =
490
629
  | number // bare WCAG ratio
491
630
  | ContrastPreset // named WCAG preset
492
631
  | { wcag: HCPair<number | ContrastPreset> }
493
- | { apca: HCPair<number> }; // APCA Lc target
632
+ | { apca: HCPair<number | ApcaPreset> }; // APCA Lc target
494
633
  ```
495
634
 
496
635
  | Preset | WCAG ratio |
@@ -1553,6 +1692,7 @@ glaze.configure({
1553
1692
  alphaMax: 0.6,
1554
1693
  bgHueBlend: 0.2,
1555
1694
  },
1695
+ contrastLevel: 'auto', // or 0–100 for a manual contrast slider
1556
1696
  });
1557
1697
  ```
1558
1698
 
@@ -1565,16 +1705,17 @@ boundaries, not the tone transfer.
1565
1705
 
1566
1706
  | Field | Default | Description |
1567
1707
  | --------------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1568
- | `lightTone` | `[10, 100]` | Light scheme tone window: `[lo, hi]`, `{ lo, hi, eps }`, or `false` to disable clamping. Bypassed in HC. |
1569
- | `darkTone` | `[15, 95]` | Dark scheme tone window: `[lo, hi]`, `{ lo, hi, eps }`, or `false` to disable clamping. Bypassed in HC. |
1708
+ | `lightTone` | `[10, 100]` | Light scheme tone window: `[lo, hi]`, `{ lo, hi, eps }`, or `false` to disable clamping. Bypassed in HC; widened continuously by [`contrastLevel`](#manual-contrast-level). |
1709
+ | `darkTone` | `[15, 95]` | Dark scheme tone window: `[lo, hi]`, `{ lo, hi, eps }`, or `false` to disable clamping. Bypassed in HC; widened continuously by [`contrastLevel`](#manual-contrast-level). |
1570
1710
  | `darkDesaturation` | `0.1` | Saturation reduction in dark scheme (0–1). |
1571
1711
  | `states.dark` | `'@media(prefers-color-scheme: dark)'` | State alias for dark mode tokens ([Tasty](https://tasty.style) export). Defaults to a media query so tokens react to the OS preference without registering custom states. |
1572
1712
  | `states.highContrast` | `'@media(prefers-contrast: more)'` | State alias for HC tokens ([Tasty](https://tasty.style) export). |
1573
1713
  | `modes.dark` | `true` | Include dark variants in exports. |
1574
- | `modes.highContrast` | `false` | Include HC variants. |
1714
+ | `modes.highContrast` | `false` | Include HC variants. Inert while a global [`contrastLevel`](#manual-contrast-level) is set — a manual level has no separate HC tier, so this reads as "emit HC variants when contrast is automatic". |
1575
1715
  | `shadowTuning` | `undefined` | Default tuning for all shadow colors. Per-color tuning merges field-by-field. |
1576
1716
  | `autoFlip` | `true` | Default for each color's `autoFlip`. When solving `contrast` (or applying a relative `tone` that overshoots `[0, 100]`), allow crossing to the opposite side instead of clamping. With `false`, only the requested direction is considered; unmet contrasts pin the tone to that direction's extreme (and emit a warning) and overshooting offsets clamp to the boundary. Override per color via [`autoFlip`](#autoflip). |
1577
1717
  | `inferRole` | `true` | Infer each color's [`role`](#roles) from its name when no explicit `role` is set. Set to `false` to opt out of name-based inference (the base-opposite and foreground-default fallbacks still apply). |
1718
+ | `contrastLevel` | `'auto'` | Manual contrast level, `0`–`100`, replacing the two-tier high-contrast model with a slider. `0` reproduces the normal output and `100` the high-contrast output, bit for bit. See [Manual contrast level](#manual-contrast-level). |
1578
1719
 
1579
1720
  | Method | Description |
1580
1721
  | ------------------------- | ----------------------------------------------------------------------------------- |
@@ -1582,7 +1723,7 @@ boundaries, not the tone transfer.
1582
1723
  | `glaze.getConfig()` | Snapshot the current resolved config (shallow copy). |
1583
1724
  | `glaze.resetConfig()` | Reset to defaults (also bumps the version counter). |
1584
1725
 
1585
- Themes and standalone color tokens keep a sparse local `GlazeConfigOverride` and merge the live global at resolve time for omitted fields. Authoring `.export(override?)` freezes the effective merge at call time; restored instances pin that freeze. `pastel` is instance-only (theme/token override or per-color) — not set via `configure()`.
1726
+ Themes and standalone color tokens keep a sparse local `GlazeConfigOverride` and merge the live global at resolve time for omitted fields. Authoring `.export(override?)` freezes the effective merge at call time; restored instances pin that freeze. `pastel` is instance-only (theme/token override or per-color) — not set via `configure()`. `contrastLevel` is the one field the freeze treats as a live preference: only an instance-authored level is written to the snapshot ([why](#two-rules-worth-knowing)).
1586
1727
 
1587
1728
  ---
1588
1729
 
@@ -1604,9 +1745,12 @@ palette.tokens({ modes: { dark: true, highContrast: true } });
1604
1745
 
1605
1746
  Resolution priority (highest first):
1606
1747
 
1607
- 1. Per-call `modes` option on `tokens` / `tasty` / `json`.
1608
- 2. `glaze.configure({ modes })` — global config.
1609
- 3. Built-in default: `{ dark: true, highContrast: false }`.
1748
+ 1. A global [`contrastLevel`](#manual-contrast-level) — pins
1749
+ `highContrast: false`, since a manual level leaves no separate high-contrast
1750
+ tier to emit. `highContrast` is inert while it is set.
1751
+ 2. Per-call `modes` option on `tokens` / `tasty` / `json`.
1752
+ 3. `glaze.configure({ modes })` — global config.
1753
+ 4. Built-in default: `{ dark: true, highContrast: false }`.
1610
1754
 
1611
1755
  ---
1612
1756
 
@@ -1621,6 +1765,7 @@ available result.
1621
1765
  | Condition | Behavior |
1622
1766
  | --------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
1623
1767
  | `contrast` without `base` in a **theme** color | Validation error |
1768
+ | `contrast` pair switching metric (`[4.5, { apca: 75 }]`) | Validation error — a WCAG ratio and an APCA Lc are different scales |
1624
1769
  | Relative `tone` without `base` in a **theme** color | Validation error |
1625
1770
  | `contrast` without `base` in `glaze.color()` | Anchors against the literal seed (no error) |
1626
1771
  | Relative `tone` without `base` in `glaze.color()` | Anchors against the literal seed (no error) |
@@ -1732,6 +1877,7 @@ import {
1732
1877
  findToneForContrast,
1733
1878
  findValueForMixContrast,
1734
1879
  resolveContrastForMode,
1880
+ resolveContrastForLevel,
1735
1881
  resolveMinContrast,
1736
1882
  apcaContrast,
1737
1883
  } from '@tenphi/glaze';
@@ -1742,6 +1888,7 @@ import {
1742
1888
  | `findToneForContrast(opts)` | Binary-search for the tone (0–1) that meets a contrast floor (WCAG or APCA) against a base color. Returns `{ tone, contrast, met, branch, flipped? }`. |
1743
1889
  | `findValueForMixContrast(opts)` | Same, but searches for a mix `value` (0–1) that meets a contrast floor between a base and a target. |
1744
1890
  | `resolveContrastForMode(spec, isHC, polarity?, outerExplicitHC?)` | Resolves a `ContrastSpec` to `{ metric: 'wcag' \| 'apca', target }` for the requested mode (picks the normal or HC entry of any pair). In HC, applies the metric's auto-enhancement unless `outerExplicitHC` is set or the inner metric pair carries an explicit HC value: APCA +15 Lc (clamped to 106); WCAG AA → AAA / AA-large → AAA-large (AAA-family and bare numbers unchanged). |
1891
+ | `resolveContrastForLevel(spec, level, polarity?)` | Resolves a `ContrastSpec` — including its outer `[normal, highContrast]` pair — at a [manual contrast level](#manual-contrast-level) (0–100), interpolating the two numeric targets. Levels 0 / 100 delegate verbatim to `resolveContrastForMode`; a WCAG-vs-APCA metric switch across the pair has no midpoint and switches at 50. |
1745
1892
  | `resolveMinContrast(value)` | Resolves a `MinContrast` (WCAG preset or number) to a numeric ratio. |
1746
1893
  | `apcaContrast(yText, yBg)` | APCA Lc magnitude (0–106) for two relative luminances. |
1747
1894
 
@@ -1761,5 +1908,6 @@ Exported constants: `APCA_PRESETS`, `APCA_HC_ENHANCEMENT` (`15`, the Enhanced Le
1761
1908
  | `maxIterations` | `18` | Max binary-search iterations per branch. |
1762
1909
  | `initialDirection` | higher-contrast side | Direction to search first (`'lighter'` or `'darker'`). |
1763
1910
  | `flip` | `false` | When `true`, try the opposite direction if the initial one doesn't meet the target. When `false`, only the initial direction is searched — unmet contrasts pin the result to that direction's extreme. |
1911
+ | `preferInitial` | `false` | With `flip` on and **both** directions meeting the target, keep `initialDirection` instead of taking whichever result lands nearer `preferredTone`. Makes the chosen side independent of the target — what [`contrastLevel`](#manual-contrast-level) uses to keep a color on one side of its base across the ramp. The flip fallback is unaffected. |
1764
1912
 
1765
1913
  Result: `{ tone, contrast, met, branch: 'lighter' | 'darker' | 'preferred', flipped? }`. `flipped: true` indicates the initial direction failed and the opposite direction satisfied the target.