@ankhorage/surface 8.0.0 → 9.0.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 (478) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/{surfaceColor.d.ts → constants/surfaceColor.d.ts} +0 -4
  3. package/dist/constants/surfaceColor.d.ts.map +1 -0
  4. package/dist/constants/surfaceColor.js.map +1 -0
  5. package/dist/features/app-bar/adapters/inbound/AppBar.d.ts.map +1 -1
  6. package/dist/features/app-bar/adapters/inbound/AppBar.js +1 -1
  7. package/dist/features/app-bar/adapters/inbound/AppBar.js.map +1 -1
  8. package/dist/features/badge/adapters/inbound/Badge.d.ts.map +1 -1
  9. package/dist/features/badge/adapters/inbound/Badge.js +1 -1
  10. package/dist/features/badge/adapters/inbound/Badge.js.map +1 -1
  11. package/dist/features/button/adapters/inbound/Button.d.ts.map +1 -1
  12. package/dist/features/button/adapters/inbound/Button.js +1 -1
  13. package/dist/features/button/adapters/inbound/Button.js.map +1 -1
  14. package/dist/features/button/adapters/inbound/IconButton.d.ts.map +1 -1
  15. package/dist/features/button/adapters/inbound/IconButton.js +1 -1
  16. package/dist/features/button/adapters/inbound/IconButton.js.map +1 -1
  17. package/dist/features/card/adapters/inbound/Card.d.ts.map +1 -1
  18. package/dist/features/card/adapters/inbound/Card.js +1 -1
  19. package/dist/features/card/adapters/inbound/Card.js.map +1 -1
  20. package/dist/features/font/adapters/inbound/FontProvider.d.ts +4 -0
  21. package/dist/features/font/adapters/inbound/FontProvider.d.ts.map +1 -0
  22. package/dist/features/font/adapters/inbound/FontProvider.js +16 -0
  23. package/dist/features/font/adapters/inbound/FontProvider.js.map +1 -0
  24. package/dist/features/font/adapters/inbound/FontRuntimeContext.d.ts +4 -0
  25. package/dist/features/font/adapters/inbound/FontRuntimeContext.d.ts.map +1 -0
  26. package/dist/features/font/adapters/inbound/FontRuntimeContext.js +9 -0
  27. package/dist/features/font/adapters/inbound/FontRuntimeContext.js.map +1 -0
  28. package/dist/features/font/adapters/inbound/useFontRuntime.d.ts +4 -0
  29. package/dist/features/font/adapters/inbound/useFontRuntime.d.ts.map +1 -0
  30. package/dist/features/font/adapters/inbound/useFontRuntime.js +7 -0
  31. package/dist/features/font/adapters/inbound/useFontRuntime.js.map +1 -0
  32. package/dist/features/font/public.d.ts +3 -0
  33. package/dist/features/font/public.d.ts.map +1 -0
  34. package/dist/features/font/public.js +2 -0
  35. package/dist/features/font/public.js.map +1 -0
  36. package/dist/features/form/checkbox/adapters/inbound/Checkbox.d.ts.map +1 -1
  37. package/dist/features/form/checkbox/adapters/inbound/Checkbox.js +1 -1
  38. package/dist/features/form/checkbox/adapters/inbound/Checkbox.js.map +1 -1
  39. package/dist/features/form/radio/adapters/inbound/Radio.d.ts.map +1 -1
  40. package/dist/features/form/radio/adapters/inbound/Radio.js +1 -1
  41. package/dist/features/form/radio/adapters/inbound/Radio.js.map +1 -1
  42. package/dist/features/form/switch/adapters/inbound/Switch.d.ts.map +1 -1
  43. package/dist/features/form/switch/adapters/inbound/Switch.js +1 -1
  44. package/dist/features/form/switch/adapters/inbound/Switch.js.map +1 -1
  45. package/dist/features/form/text-input/adapters/inbound/TextInput.d.ts.map +1 -1
  46. package/dist/features/form/text-input/adapters/inbound/TextInput.js +1 -1
  47. package/dist/features/form/text-input/adapters/inbound/TextInput.js.map +1 -1
  48. package/dist/features/form/text-input/utils/resolveTextInputPresentation.d.ts +1 -1
  49. package/dist/features/form/text-input/utils/resolveTextInputPresentation.d.ts.map +1 -1
  50. package/dist/features/form/text-input/utils/resolveTextInputPresentation.js.map +1 -1
  51. package/dist/features/icon/adapters/inbound/Icon.d.ts.map +1 -1
  52. package/dist/features/icon/adapters/inbound/Icon.js +2 -2
  53. package/dist/features/icon/adapters/inbound/Icon.js.map +1 -1
  54. package/dist/features/image/adapters/inbound/Image.d.ts.map +1 -1
  55. package/dist/features/image/adapters/inbound/Image.js +1 -1
  56. package/dist/features/image/adapters/inbound/Image.js.map +1 -1
  57. package/dist/features/image/utils/resolveImageStyle.d.ts +1 -1
  58. package/dist/features/image/utils/resolveImageStyle.d.ts.map +1 -1
  59. package/dist/features/image/utils/resolveImageStyle.js +1 -1
  60. package/dist/features/image/utils/resolveImageStyle.js.map +1 -1
  61. package/dist/features/layout/adapters/inbound/Grid.d.ts.map +1 -1
  62. package/dist/features/layout/adapters/inbound/Grid.js +1 -1
  63. package/dist/features/layout/adapters/inbound/Grid.js.map +1 -1
  64. package/dist/features/layout/adapters/inbound/ScrollView.d.ts.map +1 -1
  65. package/dist/features/layout/adapters/inbound/ScrollView.js +1 -1
  66. package/dist/features/layout/adapters/inbound/ScrollView.js.map +1 -1
  67. package/dist/features/layout/adapters/inbound/View.d.ts.map +1 -1
  68. package/dist/features/layout/adapters/inbound/View.js +1 -1
  69. package/dist/features/layout/adapters/inbound/View.js.map +1 -1
  70. package/dist/features/list/adapters/inbound/ListItem.d.ts.map +1 -1
  71. package/dist/features/list/adapters/inbound/ListItem.js +1 -1
  72. package/dist/features/list/adapters/inbound/ListItem.js.map +1 -1
  73. package/dist/features/modal/adapters/inbound/Modal.d.ts.map +1 -1
  74. package/dist/features/modal/adapters/inbound/Modal.js +1 -1
  75. package/dist/features/modal/adapters/inbound/Modal.js.map +1 -1
  76. package/dist/features/popover-menu/adapters/inbound/PopoverMenu.d.ts.map +1 -1
  77. package/dist/features/popover-menu/adapters/inbound/PopoverMenu.js +1 -1
  78. package/dist/features/popover-menu/adapters/inbound/PopoverMenu.js.map +1 -1
  79. package/dist/features/pressable/adapters/inbound/Pressable.d.ts.map +1 -1
  80. package/dist/features/pressable/adapters/inbound/Pressable.js +1 -1
  81. package/dist/features/pressable/adapters/inbound/Pressable.js.map +1 -1
  82. package/dist/features/surface/adapters/inbound/Surface.d.ts.map +1 -1
  83. package/dist/features/surface/adapters/inbound/Surface.js +1 -1
  84. package/dist/features/surface/adapters/inbound/Surface.js.map +1 -1
  85. package/dist/features/tabs/adapters/inbound/Tab.d.ts.map +1 -1
  86. package/dist/features/tabs/adapters/inbound/Tab.js +1 -1
  87. package/dist/features/tabs/adapters/inbound/Tab.js.map +1 -1
  88. package/dist/features/theme/adapters/inbound/ThemeProvider.d.ts +4 -0
  89. package/dist/features/theme/adapters/inbound/ThemeProvider.d.ts.map +1 -0
  90. package/dist/features/theme/adapters/inbound/ThemeProvider.js +27 -0
  91. package/dist/features/theme/adapters/inbound/ThemeProvider.js.map +1 -0
  92. package/dist/features/theme/adapters/inbound/ThemeRuntimeContext.d.ts +4 -0
  93. package/dist/features/theme/adapters/inbound/ThemeRuntimeContext.d.ts.map +1 -0
  94. package/dist/features/theme/adapters/inbound/ThemeRuntimeContext.js +11 -0
  95. package/dist/features/theme/adapters/inbound/ThemeRuntimeContext.js.map +1 -0
  96. package/dist/features/theme/adapters/inbound/ThemeScope.d.ts +4 -0
  97. package/dist/features/theme/adapters/inbound/ThemeScope.d.ts.map +1 -0
  98. package/dist/features/theme/adapters/inbound/ThemeScope.js +17 -0
  99. package/dist/features/theme/adapters/inbound/ThemeScope.js.map +1 -0
  100. package/dist/features/theme/adapters/inbound/useTheme.d.ts +4 -0
  101. package/dist/features/theme/adapters/inbound/useTheme.d.ts.map +1 -0
  102. package/dist/features/theme/adapters/inbound/useTheme.js +7 -0
  103. package/dist/features/theme/adapters/inbound/useTheme.js.map +1 -0
  104. package/dist/features/theme/application/use-cases/createTheme.d.ts +5 -0
  105. package/dist/features/theme/application/use-cases/createTheme.d.ts.map +1 -0
  106. package/dist/features/theme/application/use-cases/createTheme.js +56 -0
  107. package/dist/features/theme/application/use-cases/createTheme.js.map +1 -0
  108. package/dist/features/theme/constants.d.ts +10 -0
  109. package/dist/features/theme/constants.d.ts.map +1 -0
  110. package/dist/{theme/defaultTokens.js → features/theme/constants.js} +9 -2
  111. package/dist/features/theme/constants.js.map +1 -0
  112. package/dist/{theme → features/theme/domain}/createSurfaceColorDiagnosticCollector.d.ts +1 -1
  113. package/dist/features/theme/domain/createSurfaceColorDiagnosticCollector.d.ts.map +1 -0
  114. package/dist/features/theme/domain/createSurfaceColorDiagnosticCollector.js.map +1 -0
  115. package/dist/{theme → features/theme/domain}/createSurfaceSemanticPolicy.d.ts +1 -1
  116. package/dist/features/theme/domain/createSurfaceSemanticPolicy.d.ts.map +1 -0
  117. package/dist/{theme → features/theme/domain}/createSurfaceSemanticPolicy.js +1 -1
  118. package/dist/features/theme/domain/createSurfaceSemanticPolicy.js.map +1 -0
  119. package/dist/features/theme/domain/generatePalette.d.ts +10 -0
  120. package/dist/features/theme/domain/generatePalette.d.ts.map +1 -0
  121. package/dist/{theme/colorEngine.js → features/theme/domain/generatePalette.js} +2 -10
  122. package/dist/features/theme/domain/generatePalette.js.map +1 -0
  123. package/dist/{theme → features/theme/domain}/resolveRoleSemantics.d.ts +1 -1
  124. package/dist/features/theme/domain/resolveRoleSemantics.d.ts.map +1 -0
  125. package/dist/{theme → features/theme/domain}/resolveRoleSemantics.js +1 -1
  126. package/dist/features/theme/domain/resolveRoleSemantics.js.map +1 -0
  127. package/dist/features/theme/domain/resolveSemanticColors.d.ts +4 -0
  128. package/dist/features/theme/domain/resolveSemanticColors.d.ts.map +1 -0
  129. package/dist/features/theme/domain/resolveSemanticColors.js +10 -0
  130. package/dist/features/theme/domain/resolveSemanticColors.js.map +1 -0
  131. package/dist/{theme → features/theme/domain}/resolveSurfaceSemanticModel.d.ts +1 -1
  132. package/dist/features/theme/domain/resolveSurfaceSemanticModel.d.ts.map +1 -0
  133. package/dist/features/theme/domain/resolveSurfaceSemanticModel.js.map +1 -0
  134. package/dist/features/theme/public.d.ts +3 -0
  135. package/dist/features/theme/public.d.ts.map +1 -0
  136. package/dist/features/theme/public.js +2 -0
  137. package/dist/features/theme/public.js.map +1 -0
  138. package/dist/features/theme/runtime.d.ts +5 -0
  139. package/dist/features/theme/runtime.d.ts.map +1 -0
  140. package/dist/features/theme/runtime.js +4 -0
  141. package/dist/features/theme/runtime.js.map +1 -0
  142. package/dist/{theme → features/theme/utils}/resolveGlobalTokens.d.ts +1 -1
  143. package/dist/features/theme/utils/resolveGlobalTokens.d.ts.map +1 -0
  144. package/dist/{theme → features/theme/utils}/resolveGlobalTokens.js +1 -1
  145. package/dist/features/theme/utils/resolveGlobalTokens.js.map +1 -0
  146. package/dist/{theme → features/theme/utils}/resolveHeadingTokenOverrides.d.ts +1 -1
  147. package/dist/features/theme/utils/resolveHeadingTokenOverrides.d.ts.map +1 -0
  148. package/dist/features/theme/utils/resolveHeadingTokenOverrides.js.map +1 -0
  149. package/dist/features/theme/utils/resolveNumericTokenOverrides.d.ts.map +1 -0
  150. package/dist/features/theme/utils/resolveNumericTokenOverrides.js.map +1 -0
  151. package/dist/{theme → features/theme/utils}/resolveToken.d.ts +2 -8
  152. package/dist/features/theme/utils/resolveToken.d.ts.map +1 -0
  153. package/dist/features/theme/utils/resolveToken.js +10 -0
  154. package/dist/features/theme/utils/resolveToken.js.map +1 -0
  155. package/dist/{theme → features/theme/utils}/resolveWeightTokenOverrides.d.ts +1 -1
  156. package/dist/features/theme/utils/resolveWeightTokenOverrides.d.ts.map +1 -0
  157. package/dist/{theme → features/theme/utils}/resolveWeightTokenOverrides.js +3 -5
  158. package/dist/features/theme/utils/resolveWeightTokenOverrides.js.map +1 -0
  159. package/dist/features/toast/adapters/inbound/Toast.d.ts.map +1 -1
  160. package/dist/features/toast/adapters/inbound/Toast.js +1 -1
  161. package/dist/features/toast/adapters/inbound/Toast.js.map +1 -1
  162. package/dist/features/tooltip/adapters/inbound/Tooltip.d.ts.map +1 -1
  163. package/dist/features/tooltip/adapters/inbound/Tooltip.js +1 -1
  164. package/dist/features/tooltip/adapters/inbound/Tooltip.js.map +1 -1
  165. package/dist/features/typography/adapters/inbound/Heading.d.ts +2 -2
  166. package/dist/features/typography/adapters/inbound/Heading.d.ts.map +1 -1
  167. package/dist/features/typography/adapters/inbound/Heading.js +4 -20
  168. package/dist/features/typography/adapters/inbound/Heading.js.map +1 -1
  169. package/dist/features/typography/adapters/inbound/Text.d.ts +1 -1
  170. package/dist/features/typography/adapters/inbound/Text.d.ts.map +1 -1
  171. package/dist/features/typography/adapters/inbound/Text.js +3 -20
  172. package/dist/features/typography/adapters/inbound/Text.js.map +1 -1
  173. package/dist/features/typography/utils/resolveHeadingTextStyle.d.ts +2 -2
  174. package/dist/features/typography/utils/resolveHeadingTextStyle.d.ts.map +1 -1
  175. package/dist/features/typography/utils/resolveHeadingTextStyle.js.map +1 -1
  176. package/dist/index.d.ts +9 -10
  177. package/dist/index.d.ts.map +1 -1
  178. package/dist/index.js +4 -6
  179. package/dist/index.js.map +1 -1
  180. package/dist/internal/resolvers/resolveControlSize.d.ts +1 -1
  181. package/dist/internal/resolvers/resolveControlSize.js.map +1 -1
  182. package/dist/internal/resolvers/resolveFieldPresentation.d.ts +1 -1
  183. package/dist/internal/resolvers/resolveFieldPresentation.d.ts.map +1 -1
  184. package/dist/internal/resolvers/resolveFieldPresentation.js.map +1 -1
  185. package/dist/internal/resolvers/resolveIconSize.d.ts +1 -1
  186. package/dist/internal/resolvers/resolveIconSize.js.map +1 -1
  187. package/dist/internal/resolvers/resolveInteractiveColors.d.ts +2 -2
  188. package/dist/internal/resolvers/resolveInteractiveColors.d.ts.map +1 -1
  189. package/dist/internal/resolvers/resolveInteractiveColors.js.map +1 -1
  190. package/dist/internal/resolvers/resolveSelectionControlColors.d.ts +2 -2
  191. package/dist/internal/resolvers/resolveSelectionControlColors.d.ts.map +1 -1
  192. package/dist/internal/resolvers/resolveSelectionControlColors.js.map +1 -1
  193. package/dist/internal/resolvers/resolveSurfaceColor.d.ts +2 -2
  194. package/dist/internal/resolvers/resolveSurfaceColor.d.ts.map +1 -1
  195. package/dist/internal/resolvers/resolveSurfaceColor.js.map +1 -1
  196. package/dist/internal/resolvers/resolveTextColor.d.ts +2 -2
  197. package/dist/internal/resolvers/resolveTextColor.d.ts.map +1 -1
  198. package/dist/internal/resolvers/resolveTextColor.js.map +1 -1
  199. package/dist/internal/resolvers/resolveTextStyles.d.ts +1 -1
  200. package/dist/internal/resolvers/resolveTextStyles.js.map +1 -1
  201. package/dist/types/accordion.d.ts +1 -1
  202. package/dist/types/accordion.d.ts.map +1 -1
  203. package/dist/types/accordion.js.map +1 -1
  204. package/dist/types/badge.d.ts +1 -1
  205. package/dist/types/badge.d.ts.map +1 -1
  206. package/dist/types/badge.js.map +1 -1
  207. package/dist/types/button.d.ts +1 -1
  208. package/dist/types/button.d.ts.map +1 -1
  209. package/dist/types/button.js.map +1 -1
  210. package/dist/types/checkbox.d.ts +1 -1
  211. package/dist/types/checkbox.d.ts.map +1 -1
  212. package/dist/types/checkbox.js.map +1 -1
  213. package/dist/types/font.d.ts +13 -0
  214. package/dist/types/font.d.ts.map +1 -0
  215. package/dist/types/font.js +2 -0
  216. package/dist/types/font.js.map +1 -0
  217. package/dist/types/icon.d.ts +1 -1
  218. package/dist/types/icon.d.ts.map +1 -1
  219. package/dist/types/icon.js.map +1 -1
  220. package/dist/types/image.d.ts +1 -1
  221. package/dist/types/image.d.ts.map +1 -1
  222. package/dist/types/image.js.map +1 -1
  223. package/dist/types/interactionPolicy.d.ts.map +1 -0
  224. package/dist/types/interactionPolicy.js.map +1 -0
  225. package/dist/types/layout.d.ts +1 -1
  226. package/dist/types/layout.d.ts.map +1 -1
  227. package/dist/types/layout.js.map +1 -1
  228. package/dist/types/list.d.ts +1 -1
  229. package/dist/types/list.d.ts.map +1 -1
  230. package/dist/types/list.js.map +1 -1
  231. package/dist/types/modal.d.ts +1 -1
  232. package/dist/types/modal.d.ts.map +1 -1
  233. package/dist/types/modal.js.map +1 -1
  234. package/dist/types/popover.d.ts +1 -1
  235. package/dist/types/popover.d.ts.map +1 -1
  236. package/dist/types/popover.js.map +1 -1
  237. package/dist/types/popoverMenu.d.ts +1 -1
  238. package/dist/types/popoverMenu.d.ts.map +1 -1
  239. package/dist/types/popoverMenu.js.map +1 -1
  240. package/dist/types/pressable.d.ts +1 -1
  241. package/dist/types/pressable.d.ts.map +1 -1
  242. package/dist/types/pressable.js.map +1 -1
  243. package/dist/types/radio.d.ts +1 -1
  244. package/dist/types/radio.d.ts.map +1 -1
  245. package/dist/types/radio.js.map +1 -1
  246. package/dist/types/surfaceColor.d.ts +6 -0
  247. package/dist/types/surfaceColor.d.ts.map +1 -0
  248. package/dist/types/surfaceColor.js +2 -0
  249. package/dist/types/surfaceColor.js.map +1 -0
  250. package/dist/types/switch.d.ts +1 -1
  251. package/dist/types/switch.d.ts.map +1 -1
  252. package/dist/types/switch.js.map +1 -1
  253. package/dist/types/tabs.d.ts +1 -1
  254. package/dist/types/tabs.d.ts.map +1 -1
  255. package/dist/types/tabs.js.map +1 -1
  256. package/dist/types/text-input.d.ts +1 -1
  257. package/dist/types/text-input.d.ts.map +1 -1
  258. package/dist/types/text-input.js.map +1 -1
  259. package/dist/{theme/types.d.ts → types/theme.d.ts} +19 -3
  260. package/dist/types/theme.d.ts.map +1 -0
  261. package/dist/types/theme.js +2 -0
  262. package/dist/types/theme.js.map +1 -0
  263. package/dist/types/toast.d.ts +2 -2
  264. package/dist/types/toast.d.ts.map +1 -1
  265. package/dist/types/toast.js.map +1 -1
  266. package/dist/types/tooltip.d.ts +1 -1
  267. package/dist/types/tooltip.d.ts.map +1 -1
  268. package/dist/types/tooltip.js.map +1 -1
  269. package/dist/types/typography.d.ts +1 -1
  270. package/dist/types/typography.d.ts.map +1 -1
  271. package/dist/types/typography.js.map +1 -1
  272. package/dist/utils/resolveSpacing.d.ts +1 -1
  273. package/dist/utils/resolveSpacing.d.ts.map +1 -1
  274. package/dist/utils/resolveSpacing.js +1 -1
  275. package/dist/utils/resolveSpacing.js.map +1 -1
  276. package/dist/utils/resolveViewStyles.d.ts +1 -1
  277. package/dist/utils/resolveViewStyles.d.ts.map +1 -1
  278. package/dist/utils/resolveViewStyles.js +1 -1
  279. package/dist/utils/resolveViewStyles.js.map +1 -1
  280. package/package.json +8 -7
  281. package/src/constants/surfaceColor.test.ts +18 -0
  282. package/src/{surfaceColor.ts → constants/surfaceColor.ts} +0 -5
  283. package/src/features/app-bar/adapters/inbound/AppBar.tsx +1 -1
  284. package/src/features/badge/adapters/inbound/Badge.tsx +1 -1
  285. package/src/features/button/adapters/inbound/Button.tsx +2 -2
  286. package/src/features/button/adapters/inbound/IconButton.tsx +1 -1
  287. package/src/features/card/adapters/inbound/Card.tsx +1 -1
  288. package/src/features/font/adapters/inbound/FontProvider.tsx +27 -0
  289. package/src/features/font/adapters/inbound/FontRuntimeContext.tsx +12 -0
  290. package/src/features/font/adapters/inbound/useFontRuntime.ts +9 -0
  291. package/src/features/font/public.ts +2 -0
  292. package/src/features/form/checkbox/adapters/inbound/Checkbox.tsx +2 -2
  293. package/src/features/form/radio/adapters/inbound/Radio.tsx +2 -2
  294. package/src/features/form/switch/adapters/inbound/Switch.tsx +1 -1
  295. package/src/features/form/text-input/adapters/inbound/TextInput.tsx +1 -1
  296. package/src/features/form/text-input/utils/resolveTextInputPresentation.ts +1 -1
  297. package/src/features/icon/adapters/inbound/Icon.tsx +2 -2
  298. package/src/features/image/adapters/inbound/Image.tsx +1 -1
  299. package/src/features/image/utils/resolveImageProps.test.ts +1 -1
  300. package/src/features/image/utils/resolveImageStyle.ts +2 -2
  301. package/src/features/layout/adapters/inbound/Grid.tsx +1 -1
  302. package/src/features/layout/adapters/inbound/ScrollView.tsx +1 -1
  303. package/src/features/layout/adapters/inbound/View.tsx +1 -1
  304. package/src/features/list/adapters/inbound/ListItem.tsx +2 -2
  305. package/src/features/modal/adapters/inbound/Modal.tsx +1 -1
  306. package/src/features/popover-menu/adapters/inbound/PopoverMenu.tsx +1 -1
  307. package/src/features/pressable/adapters/inbound/Pressable.tsx +1 -1
  308. package/src/features/surface/adapters/inbound/Surface.tsx +1 -1
  309. package/src/features/tabs/adapters/inbound/Tab.tsx +1 -1
  310. package/src/features/theme/adapters/inbound/ThemeProvider.tsx +46 -0
  311. package/src/features/theme/adapters/inbound/ThemeRuntimeContext.tsx +14 -0
  312. package/src/features/theme/adapters/inbound/ThemeScope.test.tsx +52 -0
  313. package/src/features/theme/adapters/inbound/ThemeScope.tsx +29 -0
  314. package/src/features/theme/adapters/inbound/useTheme.ts +9 -0
  315. package/src/features/theme/application/use-cases/createTheme.ts +71 -0
  316. package/src/{theme → features/theme/application/use-cases}/createThemeOverrides.test.ts +8 -9
  317. package/src/{theme → features/theme/application/use-cases}/createThemeValidation.test.ts +4 -2
  318. package/src/features/theme/constants.ts +68 -0
  319. package/src/{theme → features/theme/domain}/createSurfaceColorDiagnosticCollector.ts +4 -1
  320. package/src/{theme → features/theme/domain}/createSurfaceSemanticPolicy.ts +2 -2
  321. package/src/features/theme/domain/generatePalette.test.ts +294 -0
  322. package/src/{theme/colorEngine.ts → features/theme/domain/generatePalette.ts} +3 -30
  323. package/src/{theme → features/theme/domain}/inverseSemantics.test.ts +1 -1
  324. package/src/{theme → features/theme/domain}/resolveRoleSemantics.ts +2 -2
  325. package/src/features/theme/domain/resolveSemanticColors.ts +23 -0
  326. package/src/{theme → features/theme/domain}/resolveSurfaceSemanticModel.ts +4 -4
  327. package/src/{theme → features/theme}/public.test.ts +1 -1
  328. package/src/features/theme/public.ts +18 -0
  329. package/src/features/theme/runtime.test.ts +13 -0
  330. package/src/features/theme/runtime.ts +4 -0
  331. package/src/{theme → features/theme/utils}/resolveGlobalTokens.ts +2 -2
  332. package/src/{theme → features/theme/utils}/resolveHeadingTokenOverrides.ts +1 -1
  333. package/src/features/theme/utils/resolveToken.ts +16 -0
  334. package/src/{theme → features/theme/utils}/resolveWeightTokenOverrides.ts +12 -12
  335. package/src/features/toast/adapters/inbound/Toast.tsx +3 -3
  336. package/src/features/tooltip/adapters/inbound/Tooltip.tsx +1 -1
  337. package/src/features/typography/adapters/inbound/Heading.tsx +3 -30
  338. package/src/features/typography/adapters/inbound/Text.tsx +3 -23
  339. package/src/features/typography/utils/resolveHeadingTextStyle.test.ts +1 -1
  340. package/src/features/typography/utils/resolveHeadingTextStyle.ts +2 -2
  341. package/src/index.test.ts +11 -9
  342. package/src/index.ts +30 -15
  343. package/src/internal/resolvers/resolveControlSize.test.ts +1 -1
  344. package/src/internal/resolvers/resolveControlSize.ts +1 -1
  345. package/src/internal/resolvers/resolveFieldPresentation.ts +1 -1
  346. package/src/internal/resolvers/resolveIconSize.ts +1 -1
  347. package/src/internal/resolvers/resolveInteractiveColors.test.ts +1 -1
  348. package/src/internal/resolvers/resolveInteractiveColors.ts +2 -2
  349. package/src/internal/resolvers/resolveSelectionControlColors.test.ts +1 -1
  350. package/src/internal/resolvers/resolveSelectionControlColors.ts +2 -2
  351. package/src/internal/resolvers/resolveSurfaceColor.test.ts +1 -1
  352. package/src/internal/resolvers/resolveSurfaceColor.ts +2 -2
  353. package/src/internal/resolvers/resolveTextColor.test.ts +1 -1
  354. package/src/internal/resolvers/resolveTextColor.ts +2 -2
  355. package/src/internal/resolvers/resolveTextStyles.test.ts +1 -1
  356. package/src/internal/resolvers/resolveTextStyles.ts +1 -1
  357. package/src/structureOwnership.test.ts +16 -0
  358. package/src/types/accordion.ts +1 -1
  359. package/src/types/badge.ts +1 -1
  360. package/src/types/button.ts +1 -1
  361. package/src/types/checkbox.ts +1 -1
  362. package/src/types/font.ts +14 -0
  363. package/src/types/icon.ts +1 -1
  364. package/src/types/image.ts +1 -1
  365. package/src/types/interactionPolicy.test.ts +30 -0
  366. package/src/types/layout.ts +1 -1
  367. package/src/types/list.ts +1 -1
  368. package/src/types/modal.ts +1 -1
  369. package/src/types/popover.ts +1 -1
  370. package/src/types/popoverMenu.ts +1 -1
  371. package/src/types/pressable.ts +1 -1
  372. package/src/types/radio.ts +1 -1
  373. package/src/types/surfaceColor.test.ts +18 -0
  374. package/src/types/surfaceColor.ts +11 -0
  375. package/src/types/switch.ts +1 -1
  376. package/src/types/tabs.ts +1 -1
  377. package/src/types/text-input.ts +1 -1
  378. package/src/{theme/types.ts → types/theme.ts} +22 -13
  379. package/src/types/toast.ts +2 -2
  380. package/src/types/tooltip.ts +1 -1
  381. package/src/types/typography.ts +1 -1
  382. package/src/utils/resolveSpacing.ts +2 -2
  383. package/src/utils/resolveViewStyles.test.ts +1 -1
  384. package/src/utils/resolveViewStyles.ts +2 -2
  385. package/src/webAcceptance.test.tsx +1 -1
  386. package/dist/context/FontContext.d.ts +0 -20
  387. package/dist/context/FontContext.d.ts.map +0 -1
  388. package/dist/context/FontContext.js +0 -27
  389. package/dist/context/FontContext.js.map +0 -1
  390. package/dist/context/TranslationContext.d.ts +0 -22
  391. package/dist/context/TranslationContext.d.ts.map +0 -1
  392. package/dist/context/TranslationContext.js +0 -25
  393. package/dist/context/TranslationContext.js.map +0 -1
  394. package/dist/interactionPolicy.d.ts.map +0 -1
  395. package/dist/interactionPolicy.js.map +0 -1
  396. package/dist/surfaceColor.d.ts.map +0 -1
  397. package/dist/surfaceColor.js.map +0 -1
  398. package/dist/theme/ThemeContext.d.ts +0 -27
  399. package/dist/theme/ThemeContext.d.ts.map +0 -1
  400. package/dist/theme/ThemeContext.js +0 -59
  401. package/dist/theme/ThemeContext.js.map +0 -1
  402. package/dist/theme/colorEngine.d.ts +0 -16
  403. package/dist/theme/colorEngine.d.ts.map +0 -1
  404. package/dist/theme/colorEngine.js.map +0 -1
  405. package/dist/theme/createSurfaceColorDiagnosticCollector.d.ts.map +0 -1
  406. package/dist/theme/createSurfaceColorDiagnosticCollector.js.map +0 -1
  407. package/dist/theme/createSurfaceSemanticPolicy.d.ts.map +0 -1
  408. package/dist/theme/createSurfaceSemanticPolicy.js.map +0 -1
  409. package/dist/theme/createTheme.d.ts +0 -5
  410. package/dist/theme/createTheme.d.ts.map +0 -1
  411. package/dist/theme/createTheme.js +0 -49
  412. package/dist/theme/createTheme.js.map +0 -1
  413. package/dist/theme/defaultTokens.d.ts +0 -3
  414. package/dist/theme/defaultTokens.d.ts.map +0 -1
  415. package/dist/theme/defaultTokens.js.map +0 -1
  416. package/dist/theme/index.d.ts +0 -3
  417. package/dist/theme/index.d.ts.map +0 -1
  418. package/dist/theme/index.js +0 -3
  419. package/dist/theme/index.js.map +0 -1
  420. package/dist/theme/public.d.ts +0 -5
  421. package/dist/theme/public.d.ts.map +0 -1
  422. package/dist/theme/public.js +0 -5
  423. package/dist/theme/public.js.map +0 -1
  424. package/dist/theme/resolveGlobalTokens.d.ts.map +0 -1
  425. package/dist/theme/resolveGlobalTokens.js.map +0 -1
  426. package/dist/theme/resolveHeadingTokenOverrides.d.ts.map +0 -1
  427. package/dist/theme/resolveHeadingTokenOverrides.js.map +0 -1
  428. package/dist/theme/resolveNumericTokenOverrides.d.ts.map +0 -1
  429. package/dist/theme/resolveNumericTokenOverrides.js.map +0 -1
  430. package/dist/theme/resolveRoleSemantics.d.ts.map +0 -1
  431. package/dist/theme/resolveRoleSemantics.js.map +0 -1
  432. package/dist/theme/resolveSurfaceSemanticModel.d.ts.map +0 -1
  433. package/dist/theme/resolveSurfaceSemanticModel.js.map +0 -1
  434. package/dist/theme/resolveToken.d.ts.map +0 -1
  435. package/dist/theme/resolveToken.js +0 -19
  436. package/dist/theme/resolveToken.js.map +0 -1
  437. package/dist/theme/resolveWeightTokenOverrides.d.ts.map +0 -1
  438. package/dist/theme/resolveWeightTokenOverrides.js.map +0 -1
  439. package/dist/theme/surfaceColorPolicy.d.ts +0 -8
  440. package/dist/theme/surfaceColorPolicy.d.ts.map +0 -1
  441. package/dist/theme/surfaceColorPolicy.js +0 -8
  442. package/dist/theme/surfaceColorPolicy.js.map +0 -1
  443. package/dist/theme/types.d.ts.map +0 -1
  444. package/dist/theme/types.js +0 -2
  445. package/dist/theme/types.js.map +0 -1
  446. package/dist/utils/deepEqual.d.ts +0 -6
  447. package/dist/utils/deepEqual.d.ts.map +0 -1
  448. package/dist/utils/deepEqual.js +0 -36
  449. package/dist/utils/deepEqual.js.map +0 -1
  450. package/dist/utils/deepMerge.d.ts +0 -6
  451. package/dist/utils/deepMerge.d.ts.map +0 -1
  452. package/dist/utils/deepMerge.js +0 -26
  453. package/dist/utils/deepMerge.js.map +0 -1
  454. package/src/context/FontContext.tsx +0 -59
  455. package/src/context/TranslationContext.tsx +0 -50
  456. package/src/interactionPolicy.test.ts +0 -86
  457. package/src/surfaceColor.test.ts +0 -44
  458. package/src/theme/ThemeContext.tsx +0 -94
  459. package/src/theme/colorEngine.test.ts +0 -302
  460. package/src/theme/createTheme.ts +0 -60
  461. package/src/theme/defaultTokens.ts +0 -61
  462. package/src/theme/index.ts +0 -2
  463. package/src/theme/public.ts +0 -4
  464. package/src/theme/resolveToken.ts +0 -32
  465. package/src/theme/surfaceColorPolicy.ts +0 -7
  466. package/src/utils/deepEqual.ts +0 -34
  467. package/src/utils/deepMerge.test.ts +0 -113
  468. package/src/utils/deepMerge.ts +0 -29
  469. /package/dist/{surfaceColor.js → constants/surfaceColor.js} +0 -0
  470. /package/dist/{theme → features/theme/domain}/createSurfaceColorDiagnosticCollector.js +0 -0
  471. /package/dist/{theme → features/theme/domain}/resolveSurfaceSemanticModel.js +0 -0
  472. /package/dist/{theme → features/theme/utils}/resolveHeadingTokenOverrides.js +0 -0
  473. /package/dist/{theme → features/theme/utils}/resolveNumericTokenOverrides.d.ts +0 -0
  474. /package/dist/{theme → features/theme/utils}/resolveNumericTokenOverrides.js +0 -0
  475. /package/dist/{interactionPolicy.d.ts → types/interactionPolicy.d.ts} +0 -0
  476. /package/dist/{interactionPolicy.js → types/interactionPolicy.js} +0 -0
  477. /package/src/{theme → features/theme/utils}/resolveNumericTokenOverrides.ts +0 -0
  478. /package/src/{interactionPolicy.ts → types/interactionPolicy.ts} +0 -0
@@ -1,12 +1,14 @@
1
1
  import type { ThemeConfig } from '@ankhorage/contracts';
2
2
  import { describe, expect, it } from 'bun:test';
3
3
 
4
- import { createTheme, DEFAULT_CONFIG, DEFAULT_TOKENS } from './createTheme';
4
+ import { DEFAULT_TOKENS } from '../../constants';
5
+ import { createTheme } from './createTheme';
6
+
7
+ const defaultConfig = createTheme().config;
5
8
 
6
9
  describe('createTheme authored global tokens', () => {
7
10
  it('preserves defaults when no authored overrides exist', () => {
8
- const theme = createTheme(DEFAULT_CONFIG);
9
-
11
+ const theme = createTheme(defaultConfig);
10
12
  expect(theme.spacing).toEqual(DEFAULT_TOKENS.spacing);
11
13
  expect(theme.radii).toEqual(DEFAULT_TOKENS.radii);
12
14
  expect(theme.typography.sizes).toEqual(DEFAULT_TOKENS.typography.sizes);
@@ -16,7 +18,7 @@ describe('createTheme authored global tokens', () => {
16
18
 
17
19
  it('merges authored global tokens without copying omitted defaults into config', () => {
18
20
  const config: ThemeConfig = {
19
- ...DEFAULT_CONFIG,
21
+ ...defaultConfig,
20
22
  tokens: {
21
23
  spacing: { m: 18, hero: 64 },
22
24
  radii: { l: 20, pill: 999 },
@@ -28,9 +30,7 @@ describe('createTheme authored global tokens', () => {
28
30
  shadows: { soft: 3, floating: 12 },
29
31
  },
30
32
  };
31
-
32
33
  const theme = createTheme(config);
33
-
34
34
  expect(theme.spacing).toMatchObject({ xs: 4, m: 18, hero: 64 });
35
35
  expect(theme.radii).toMatchObject({ m: 8, l: 20, pill: 999 });
36
36
  expect(theme.typography.sizes).toMatchObject({ s: 14, m: 17, display: 44 });
@@ -41,9 +41,8 @@ describe('createTheme authored global tokens', () => {
41
41
  });
42
42
 
43
43
  it('keeps module-derived font families isolated per resolved theme', () => {
44
- const withFont = createTheme(DEFAULT_CONFIG, 'light', 'source-sans');
45
- const withoutFont = createTheme(DEFAULT_CONFIG);
46
-
44
+ const withFont = createTheme(defaultConfig, 'light', 'source-sans');
45
+ const withoutFont = createTheme(defaultConfig);
47
46
  expect(withFont.typography.fonts.normal['400']).toBe('SourceSans_400Regular');
48
47
  expect(withoutFont.typography.fonts.normal['400']).toBeUndefined();
49
48
  expect(DEFAULT_TOKENS.typography.fonts.normal['400']).toBeUndefined();
@@ -1,7 +1,9 @@
1
1
  import type { ThemeConfig, ThemeGlobalTokenOverrides } from '@ankhorage/contracts';
2
2
  import { describe, expect, it } from 'bun:test';
3
3
 
4
- import { createTheme, DEFAULT_CONFIG } from './createTheme';
4
+ import { createTheme } from './createTheme';
5
+
6
+ const defaultConfig = createTheme().config;
5
7
 
6
8
  describe('createTheme token validation', () => {
7
9
  it('rejects negative or non-finite numeric tokens', () => {
@@ -46,5 +48,5 @@ describe('createTheme token validation', () => {
46
48
  });
47
49
 
48
50
  function withTokens(tokens: ThemeGlobalTokenOverrides): ThemeConfig {
49
- return { ...DEFAULT_CONFIG, tokens };
51
+ return { ...defaultConfig, tokens };
50
52
  }
@@ -0,0 +1,68 @@
1
+ import type { FontWeight, ThemeTokens } from '../../types/theme';
2
+
3
+ const EMPTY_FONT_MAP: Record<FontWeight, string | undefined> = {
4
+ '100': undefined,
5
+ '200': undefined,
6
+ '300': undefined,
7
+ '400': undefined,
8
+ '500': undefined,
9
+ '600': undefined,
10
+ '700': undefined,
11
+ '800': undefined,
12
+ '900': undefined,
13
+ bold: undefined,
14
+ normal: undefined,
15
+ };
16
+
17
+ const DEFAULT_TOKENS: Omit<ThemeTokens, 'colors' | 'swatches' | 'semantics' | 'colorDiagnostics'> =
18
+ {
19
+ spacing: { none: 0, xs: 4, s: 8, m: 16, l: 24, xl: 32, xxl: 48 },
20
+ radii: { none: 0, s: 4, m: 8, l: 16, full: 9999 },
21
+ typography: {
22
+ headings: {
23
+ 1: { size: 32, lineHeight: 40, weight: 'bold' },
24
+ 2: { size: 24, lineHeight: 32, weight: 'bold' },
25
+ 3: { size: 20, lineHeight: 28, weight: 'bold' },
26
+ 4: { size: 18, lineHeight: 24, weight: 'semiBold' },
27
+ 5: { size: 16, lineHeight: 22, weight: 'semiBold' },
28
+ 6: { size: 14, lineHeight: 20, weight: 'semiBold' },
29
+ },
30
+ sizes: {
31
+ xs: 12,
32
+ s: 14,
33
+ m: 16,
34
+ l: 18,
35
+ xl: 20,
36
+ xxl: 24,
37
+ '3xl': 30,
38
+ h1: 32,
39
+ h2: 24,
40
+ h3: 20,
41
+ h4: 18,
42
+ h5: 16,
43
+ h6: 14,
44
+ },
45
+ weights: {
46
+ thin: '100',
47
+ extraLight: '200',
48
+ light: '300',
49
+ regular: '400',
50
+ medium: '500',
51
+ semiBold: '600',
52
+ bold: '700',
53
+ extraBold: '800',
54
+ black: '900',
55
+ },
56
+ fonts: { normal: { ...EMPTY_FONT_MAP }, italic: { ...EMPTY_FONT_MAP } },
57
+ },
58
+ shadows: { soft: 2, medium: 4, hard: 8 },
59
+ };
60
+
61
+ export const SURFACE_COLOR_POLICY = {
62
+ disabledContrast: 3,
63
+ surfaceSeparation: 1.05,
64
+ textContrast: 4.5,
65
+ uiContrast: 3,
66
+ } as const;
67
+
68
+ export { DEFAULT_TOKENS };
@@ -11,7 +11,10 @@ import {
11
11
  selectColorSwatchStep,
12
12
  } from '@ankhorage/color-theory';
13
13
 
14
- import type { SurfaceColorSelectionDiagnostic, SurfaceContrastDiagnostic } from './types';
14
+ import type {
15
+ SurfaceColorSelectionDiagnostic,
16
+ SurfaceContrastDiagnostic,
17
+ } from '../../../types/theme';
15
18
 
16
19
  /** Collect deterministic Color Theory evidence while Surface resolves semantic colors. */
17
20
  export function createSurfaceColorDiagnosticCollector() {
@@ -8,13 +8,13 @@ import type {
8
8
  } from '@ankhorage/color-theory';
9
9
  import { parseHexColorOrThrow } from '@ankhorage/color-theory';
10
10
 
11
- import { SURFACE_COLOR_POLICY } from './surfaceColorPolicy';
12
11
  import type {
13
12
  ContentSemantics,
14
13
  NeutralSemantics,
15
14
  SurfaceContrastDiagnostic,
16
15
  SurfaceSemantics,
17
- } from './types';
16
+ } from '../../../types/theme';
17
+ import { SURFACE_COLOR_POLICY } from '../constants';
18
18
 
19
19
  type ResolvedSemanticColors = Record<SemanticColorToken, HexColor>;
20
20
 
@@ -0,0 +1,294 @@
1
+ import type { SemanticColorToken } from '@ankhorage/color-theory';
2
+ import {
3
+ COLOR_HARMONIES,
4
+ DARK_SEMANTIC_COLOR_REFERENCES,
5
+ DEFAULT_SEMANTIC_STATUS_COLOR_SEEDS,
6
+ LIGHT_SEMANTIC_COLOR_REFERENCES,
7
+ } from '@ankhorage/color-theory';
8
+ import type { ThemeConfig } from '@ankhorage/contracts';
9
+ import { isRecord, readOwnProperty } from '@ankhorage/utility/object';
10
+ import { expect, it } from 'bun:test';
11
+
12
+ import { generatePalette } from './generatePalette';
13
+ import { resolveSemanticColors } from './resolveSemanticColors';
14
+
15
+ const mockConfig: ThemeConfig = {
16
+ id: 'test',
17
+ name: 'Test Theme',
18
+ light: {
19
+ primaryColor: '#3B82F6',
20
+ harmony: 'triadic',
21
+ },
22
+ dark: {
23
+ primaryColor: '#3B82F6',
24
+ harmony: 'triadic',
25
+ },
26
+ };
27
+
28
+ function expectCompleteSemanticValues(value: unknown): void {
29
+ if (typeof value === 'string') {
30
+ expect(value.length).toBeGreaterThan(0);
31
+ return;
32
+ }
33
+ if (!isRecord(value)) return;
34
+ Object.values(value).forEach(expectCompleteSemanticValues);
35
+ }
36
+
37
+ it('generates a valid palette for light mode', () => {
38
+ const { colors, swatches, semantics } = generatePalette(mockConfig, 'light');
39
+
40
+ expect(colors.primary).toBeDefined();
41
+ expect(swatches.primary).toBeDefined();
42
+ expect(swatches.neutral).toBeDefined();
43
+ expect(Object.keys(swatches.primary)).toHaveLength(11);
44
+ expect(Object.keys(swatches.neutral)).toHaveLength(11);
45
+
46
+ // Surface semantic aliases
47
+ expect(semantics.surface.default).toBe(semantics.neutral.surface);
48
+ expect(semantics.content.muted).toBe(semantics.neutral.textMuted);
49
+ expect(semantics.border.focus).toBe(semantics.brand.outline);
50
+ expect(semantics.action.primary.base).toBe(semantics.brand.base);
51
+ expect(semantics.action.danger.base).toBe(semantics.danger.base);
52
+
53
+ // Surface runtime semantic aliases derived from ordinal swatches
54
+ expect(semantics.accent.base).toBeDefined();
55
+ expect(semantics.highlight.base).toBeDefined();
56
+ // accent/highlight are Surface semantic aliases (tertiary/quaternary fallback to primary when absent)
57
+ expect(semantics.accent.base).toBe(colors.accent);
58
+ expect(semantics.highlight.base).toBe(colors.highlight);
59
+ });
60
+
61
+ it('generates a valid palette for dark mode', () => {
62
+ const { colors, swatches, semantics } = generatePalette(mockConfig, 'dark');
63
+
64
+ expect(colors.background).toBe(semantics.neutral.bg);
65
+ expect(semantics.surface.inverse).toBe(swatches.neutral[50]);
66
+ expect(semantics.content.inverse).toBe(swatches.neutral[900]);
67
+ });
68
+
69
+ it('uses the Color Theory status owner independently from brand harmony', () => {
70
+ const statusConfig: ThemeConfig = {
71
+ ...mockConfig,
72
+ light: { primaryColor: '#dc2626', harmony: 'monochromatic' },
73
+ dark: { primaryColor: '#dc2626', harmony: 'monochromatic' },
74
+ };
75
+ const light = generatePalette(statusConfig, 'light');
76
+ const dark = generatePalette(statusConfig, 'dark');
77
+
78
+ expect(light.semantics.danger.base).toBe('#ef4444');
79
+ expect(light.semantics.success.base).toBe('#22c55e');
80
+ expect(light.semantics.warning.base).toBe('#f59e0b');
81
+ expect(light.semantics.error.base).toBe(light.semantics.danger.base);
82
+ expect(light.semantics.info.base).toBe(DEFAULT_SEMANTIC_STATUS_COLOR_SEEDS.info);
83
+ expect(light.semantics.info.base).not.toBe(light.semantics.brand.base);
84
+
85
+ expect(dark.semantics.danger.base).toBe('#ef4444');
86
+ expect(dark.semantics.success.base).toBe('#22c55e');
87
+ expect(dark.semantics.warning.base).toBe('#f59e0b');
88
+ expect(dark.semantics.error.base).toBe(dark.semantics.danger.base);
89
+ expect(dark.semantics.info.base).toBe(DEFAULT_SEMANTIC_STATUS_COLOR_SEEDS.info);
90
+ expect(dark.semantics.info.base).not.toBe(dark.semantics.brand.base);
91
+ expect(light.semantics.error).toBe(light.semantics.danger);
92
+ expect(dark.semantics.error).toBe(dark.semantics.danger);
93
+ });
94
+
95
+ it('uses mode-aware role semantics for dark mode soft states', () => {
96
+ const light = generatePalette(mockConfig, 'light');
97
+ const dark = generatePalette(mockConfig, 'dark');
98
+
99
+ expect(light.semantics.brand.softBg).toBe(light.swatches.primary[100]);
100
+ expect(light.semantics.brand.softHover).toBe(light.swatches.primary[200]);
101
+ expect(light.semantics.brand.softActive).toBe(light.swatches.primary[300]);
102
+ expect(dark.semantics.brand.softBg).toBe(dark.swatches.primary[900]);
103
+ expect(dark.semantics.brand.softHover).toBe(dark.swatches.primary[800]);
104
+ expect(dark.semantics.brand.softActive).toBe(dark.swatches.primary[700]);
105
+ });
106
+
107
+ it('preserves the primary color at swatch step 500 in light mode', () => {
108
+ const { swatches } = generatePalette(mockConfig, 'light');
109
+ expect(String(swatches.primary[500])).toBe(mockConfig.light.primaryColor);
110
+ });
111
+
112
+ it('preserves the primary color at swatch step 500 in dark mode', () => {
113
+ const { swatches } = generatePalette(mockConfig, 'dark');
114
+ expect(String(swatches.primary[500])).toBe(mockConfig.dark.primaryColor);
115
+ });
116
+
117
+ it('provides a neutral swatch with neutralKeyColor at step 500', () => {
118
+ const { swatches } = generatePalette(mockConfig, 'light');
119
+ // neutral swatch must have a step 500 entry
120
+ expect(swatches.neutral[500]).toBeDefined();
121
+ });
122
+
123
+ it('throws deterministically on invalid primary color', () => {
124
+ const config = {
125
+ ...mockConfig,
126
+ light: { ...mockConfig.light, primaryColor: 'not-a-hex-color' },
127
+ };
128
+ expect(() => generatePalette(config, 'light')).toThrow();
129
+ });
130
+
131
+ it('throws deterministically on invalid primary color in dark mode', () => {
132
+ const config = {
133
+ ...mockConfig,
134
+ dark: { ...mockConfig.dark, primaryColor: 'rgb(0,0,0)' },
135
+ };
136
+ expect(() => generatePalette(config, 'dark')).toThrow();
137
+ });
138
+
139
+ it('emits required semantic roles for all harmonies', () => {
140
+ for (const harmony of COLOR_HARMONIES) {
141
+ const config = {
142
+ ...mockConfig,
143
+ light: { ...mockConfig.light, harmony },
144
+ dark: { ...mockConfig.dark, harmony },
145
+ };
146
+ const light = generatePalette(config, 'light');
147
+ const dark = generatePalette(config, 'dark');
148
+ expectCompleteSemanticValues(light.semantics);
149
+ expectCompleteSemanticValues(dark.semantics);
150
+ }
151
+ });
152
+
153
+ it('resolves canonical semantic references and returns their selected steps', () => {
154
+ const light = generatePalette(mockConfig, 'light');
155
+ const dark = generatePalette(mockConfig, 'dark');
156
+
157
+ expect(light.colorDiagnostics.semanticReferences).toBe(LIGHT_SEMANTIC_COLOR_REFERENCES);
158
+ expect(dark.colorDiagnostics.semanticReferences).toBe(DARK_SEMANTIC_COLOR_REFERENCES);
159
+ expect(light.colorDiagnostics.generated.swatches).toBe(light.swatches);
160
+ expect(dark.colorDiagnostics.generated.swatches).toBe(dark.swatches);
161
+ });
162
+
163
+ it('returns measured selections and contrast diagnostics for both modes', () => {
164
+ for (const mode of ['light', 'dark'] as const) {
165
+ const palette = generatePalette(mockConfig, mode);
166
+
167
+ expect(palette.colorDiagnostics.selections.length).toBeGreaterThan(0);
168
+ expect(
169
+ palette.colorDiagnostics.selections.every(({ result }) => result.selected !== null),
170
+ ).toBe(true);
171
+ expect(palette.colorDiagnostics.contrasts.length).toBeGreaterThan(0);
172
+ expect(palette.colorDiagnostics.contrasts.every(({ passes }) => passes)).toBe(true);
173
+ expect(palette.colorDiagnostics.surfaceSeparation.length).toBeGreaterThan(0);
174
+ }
175
+ });
176
+
177
+ it('reports neutral and surface-separation evidence without hiding failed separation', () => {
178
+ const palette = generatePalette(mockConfig, 'light');
179
+ const failedSeparation = palette.colorDiagnostics.surfaceSeparation.find(({ passes }) => !passes);
180
+
181
+ expect(palette.colorDiagnostics.generated.neutral.neutralKeyColor).toBe(
182
+ palette.swatches.neutral[500],
183
+ );
184
+ expect(palette.colorDiagnostics.generated.neutral.diagnostics.isUsable).toBeBoolean();
185
+ expect(failedSeparation).toBeDefined();
186
+ expect(failedSeparation?.contrast).toBeLessThan(failedSeparation?.minimumContrast ?? 0);
187
+ });
188
+
189
+ it('preserves owner diagnostics for achromatic and low-chroma inputs', () => {
190
+ const achromaticConfig: ThemeConfig = {
191
+ ...mockConfig,
192
+ light: { primaryColor: '#777777', harmony: 'square' },
193
+ };
194
+ const palette = generatePalette(achromaticConfig, 'light');
195
+
196
+ expect(palette.colorDiagnostics.generated.harmonyRoleColors.diagnostics.isHueReliable).toBe(
197
+ false,
198
+ );
199
+ expect(
200
+ palette.colorDiagnostics.generated.harmonyRoleColors.diagnostics.warnings.length,
201
+ ).toBeGreaterThan(0);
202
+ expect(palette.colorDiagnostics.generated.neutral.diagnostics).toBeDefined();
203
+ });
204
+
205
+ it('generates ordinal chromatic role swatches (no accent/highlight as swatch keys)', () => {
206
+ const { swatches } = generatePalette(mockConfig, 'light');
207
+ const keys = Object.keys(swatches);
208
+ expect(keys).not.toContain('accent');
209
+ expect(keys).not.toContain('highlight');
210
+ expect(keys).not.toContain('surfaceTint');
211
+ expect(keys).not.toContain('base');
212
+ // ordinal roles are present
213
+ expect(keys).toContain('primary');
214
+ expect(keys).toContain('neutral');
215
+ });
216
+
217
+ it('semantic resolver maps all SemanticColorToken entries for light mode', () => {
218
+ const { swatches } = generatePalette(mockConfig, 'light');
219
+ // Build a minimal GeneratedThemeModeColors for resolver testing
220
+ const generated = {
221
+ harmonyRoleColors: {} as never,
222
+ swatches,
223
+ neutral: { neutralKeyColor: swatches.neutral[500], diagnostics: {} as never },
224
+ };
225
+ const resolved = resolveSemanticColors(generated, LIGHT_SEMANTIC_COLOR_REFERENCES);
226
+ const tokens: SemanticColorToken[] = [
227
+ 'background',
228
+ 'surface',
229
+ 'surfaceRaised',
230
+ 'border',
231
+ 'divider',
232
+ 'text',
233
+ 'textMuted',
234
+ 'disabledBg',
235
+ 'disabledText',
236
+ 'brand',
237
+ 'brandEmphasis',
238
+ 'action',
239
+ 'actionEmphasis',
240
+ ];
241
+ for (const token of tokens) {
242
+ expect(readOwnProperty(resolved, token)).toBeDefined();
243
+ expect(typeof readOwnProperty(resolved, token)).toBe('string');
244
+ }
245
+ });
246
+
247
+ it('semantic resolver maps all SemanticColorToken entries for dark mode', () => {
248
+ const { swatches } = generatePalette(mockConfig, 'dark');
249
+ const generated = {
250
+ harmonyRoleColors: {} as never,
251
+ swatches,
252
+ neutral: { neutralKeyColor: swatches.neutral[500], diagnostics: {} as never },
253
+ };
254
+ const resolved = resolveSemanticColors(generated, DARK_SEMANTIC_COLOR_REFERENCES);
255
+ const tokens: SemanticColorToken[] = [
256
+ 'background',
257
+ 'surface',
258
+ 'surfaceRaised',
259
+ 'border',
260
+ 'divider',
261
+ 'text',
262
+ 'textMuted',
263
+ 'disabledBg',
264
+ 'disabledText',
265
+ 'brand',
266
+ 'brandEmphasis',
267
+ 'action',
268
+ 'actionEmphasis',
269
+ ];
270
+ for (const token of tokens) {
271
+ expect(readOwnProperty(resolved, token)).toBeDefined();
272
+ }
273
+ });
274
+
275
+ it('neutral semantics power backgrounds, borders, text in light mode', () => {
276
+ const { semantics } = generatePalette(mockConfig, 'light');
277
+ expect(semantics.neutral.bg).toBeDefined();
278
+ expect(semantics.neutral.bgSubtle).toBeDefined();
279
+ expect(semantics.neutral.surface).toBeDefined();
280
+ expect(semantics.neutral.surfaceHover).toBeDefined();
281
+ expect(semantics.neutral.border).toBeDefined();
282
+ expect(semantics.neutral.borderStrong).toBeDefined();
283
+ expect(semantics.neutral.divider).toBeDefined();
284
+ expect(semantics.neutral.text).toBeDefined();
285
+ expect(semantics.neutral.textMuted).toBeDefined();
286
+ expect(semantics.neutral.textSubtle).toBeDefined();
287
+ });
288
+
289
+ it('readable foregrounds are generated for brand base in both modes', () => {
290
+ const light = generatePalette(mockConfig, 'light');
291
+ const dark = generatePalette(mockConfig, 'dark');
292
+ expect(light.semantics.brand.onSolidText).toMatch(/^#/);
293
+ expect(dark.semantics.brand.onSolidText).toMatch(/^#/);
294
+ });
@@ -1,11 +1,4 @@
1
- import type {
2
- GeneratedThemeModeColors,
3
- GeneratedThemeSwatches,
4
- HexColor,
5
- SemanticColorReferenceMap,
6
- SemanticColorToken,
7
- ThemeColorMode,
8
- } from '@ankhorage/color-theory';
1
+ import type { GeneratedThemeSwatches, ThemeColorMode } from '@ankhorage/color-theory';
9
2
  import {
10
3
  DARK_SEMANTIC_COLOR_REFERENCES,
11
4
  generateThemeModeColors,
@@ -14,29 +7,9 @@ import {
14
7
  } from '@ankhorage/color-theory';
15
8
  import type { ThemeConfig } from '@ankhorage/contracts';
16
9
 
10
+ import type { SurfaceColorDiagnostics, ThemeSemantics, ThemeTokens } from '../../../types/theme';
11
+ import { resolveSemanticColors } from './resolveSemanticColors';
17
12
  import { resolveSurfaceSemanticModel } from './resolveSurfaceSemanticModel';
18
- import type { SurfaceColorDiagnostics, ThemeSemantics, ThemeTokens } from './types';
19
-
20
- /**
21
- * Surface semantic resolver: maps color-theory SemanticColorToken references
22
- * to hex values from the generated swatches.
23
- */
24
- export type SurfaceSemanticColors = Record<SemanticColorToken, HexColor>;
25
-
26
- export function resolveSemanticColors(
27
- generated: GeneratedThemeModeColors,
28
- references: SemanticColorReferenceMap,
29
- ): SurfaceSemanticColors {
30
- return Object.fromEntries(
31
- Object.entries(references).map(([token, ref]) => {
32
- const swatch = generated.swatches[ref.role];
33
- if (!swatch) {
34
- throw new Error(`Missing swatch for role '${ref.role}' (token: '${token}')`);
35
- }
36
- return [token, swatch[ref.step]];
37
- }),
38
- ) as SurfaceSemanticColors;
39
- }
40
13
 
41
14
  export function generatePalette(
42
15
  config: ThemeConfig,
@@ -1,7 +1,7 @@
1
1
  import type { ThemeConfig } from '@ankhorage/contracts';
2
2
  import { describe, expect, it } from 'bun:test';
3
3
 
4
- import { generatePalette } from './colorEngine';
4
+ import { generatePalette } from './generatePalette';
5
5
 
6
6
  const config: ThemeConfig = {
7
7
  id: 'inverse-semantics-test',
@@ -1,7 +1,7 @@
1
1
  import type { ColorSwatch, HexColor } from '@ankhorage/color-theory';
2
2
 
3
- import { SURFACE_COLOR_POLICY } from './surfaceColorPolicy';
4
- import type { RoleSemantics } from './types';
3
+ import type { RoleSemantics } from '../../../types/theme';
4
+ import { SURFACE_COLOR_POLICY } from '../constants';
5
5
 
6
6
  interface ResolveRoleSemanticsInput {
7
7
  base?: HexColor;
@@ -0,0 +1,23 @@
1
+ import type {
2
+ GeneratedThemeModeColors,
3
+ HexColor,
4
+ SemanticColorReferenceMap,
5
+ SemanticColorToken,
6
+ } from '@ankhorage/color-theory';
7
+
8
+ export type SurfaceSemanticColors = Record<SemanticColorToken, HexColor>;
9
+
10
+ export function resolveSemanticColors(
11
+ generated: GeneratedThemeModeColors,
12
+ references: SemanticColorReferenceMap,
13
+ ): SurfaceSemanticColors {
14
+ return Object.fromEntries(
15
+ Object.entries(references).map(([token, ref]) => {
16
+ const swatch = generated.swatches[ref.role];
17
+ if (!swatch) {
18
+ throw new Error(`Missing swatch for role '${ref.role}' (token: '${token}')`);
19
+ }
20
+ return [token, swatch[ref.step]];
21
+ }),
22
+ ) as SurfaceSemanticColors;
23
+ }
@@ -10,16 +10,16 @@ import type {
10
10
  } from '@ankhorage/color-theory';
11
11
  import { createDefaultSemanticStatusSwatches } from '@ankhorage/color-theory';
12
12
 
13
- import { createSurfaceColorDiagnosticCollector } from './createSurfaceColorDiagnosticCollector';
14
- import { createSurfaceSemanticPolicy } from './createSurfaceSemanticPolicy';
15
- import { resolveRoleSemantics } from './resolveRoleSemantics';
16
13
  import type {
17
14
  BorderSemantics,
18
15
  ContentSemantics,
19
16
  RoleSemantics,
20
17
  SurfaceColorDiagnostics,
21
18
  ThemeSemantics,
22
- } from './types';
19
+ } from '../../../types/theme';
20
+ import { createSurfaceColorDiagnosticCollector } from './createSurfaceColorDiagnosticCollector';
21
+ import { createSurfaceSemanticPolicy } from './createSurfaceSemanticPolicy';
22
+ import { resolveRoleSemantics } from './resolveRoleSemantics';
23
23
 
24
24
  type ResolvedSemanticColors = Record<SemanticColorToken, HexColor>;
25
25
 
@@ -17,7 +17,7 @@ describe('public theme subpath', () => {
17
17
 
18
18
  expect(source).not.toContain('ThemeContext');
19
19
  expect(source).not.toMatch(/from ['"]react(?:-native)?['"]/);
20
- expect(source).toContain("export * from './createTheme';");
20
+ expect(source).toContain("export { createTheme } from './application/use-cases/createTheme';");
21
21
  });
22
22
 
23
23
  test('imports and executes through the package subpath in plain Bun', async () => {
@@ -0,0 +1,18 @@
1
+ export type {
2
+ ActionSemantics,
3
+ BorderSemantics,
4
+ ContentSemantics,
5
+ FontWeight,
6
+ NeutralSemantics,
7
+ RoleSemantics,
8
+ SelectionSemantics,
9
+ SurfaceColorDiagnostics,
10
+ SurfaceColorSelectionDiagnostic,
11
+ SurfaceContrastDiagnostic,
12
+ SurfaceSemantics,
13
+ SurfaceTheme,
14
+ ThemeMode,
15
+ ThemeSemantics,
16
+ ThemeTokens,
17
+ } from '../../types/theme';
18
+ export { createTheme } from './application/use-cases/createTheme';
@@ -0,0 +1,13 @@
1
+ import { readFileSync } from 'node:fs';
2
+
3
+ import { describe, expect, it } from 'bun:test';
4
+
5
+ describe('theme runtime ownership', () => {
6
+ it('keeps nested scopes on the Surface runtime boundary without exposing raw context', () => {
7
+ const root = readFileSync(new URL('../../index.ts', import.meta.url), 'utf8');
8
+ const runtime = readFileSync(new URL('./runtime.ts', import.meta.url), 'utf8');
9
+ expect(root).toContain('ThemeProvider, ThemeScope, useTheme');
10
+ expect(root).not.toContain('ThemeContext');
11
+ expect(runtime).not.toContain('ThemeRuntimeContext');
12
+ });
13
+ });
@@ -0,0 +1,4 @@
1
+ export type { ThemeProviderProps, ThemeRuntime, ThemeScopeProps } from '../../types/theme';
2
+ export { ThemeProvider } from './adapters/inbound/ThemeProvider';
3
+ export { ThemeScope } from './adapters/inbound/ThemeScope';
4
+ export { useTheme } from './adapters/inbound/useTheme';
@@ -1,10 +1,10 @@
1
1
  import type { ThemeGlobalTokenOverrides } from '@ankhorage/contracts';
2
2
 
3
- import { DEFAULT_TOKENS } from './defaultTokens';
3
+ import type { ThemeTokens } from '../../../types/theme';
4
+ import { DEFAULT_TOKENS } from '../constants';
4
5
  import { resolveHeadingTokenOverrides } from './resolveHeadingTokenOverrides';
5
6
  import { resolveNumericTokenOverrides } from './resolveNumericTokenOverrides';
6
7
  import { resolveWeightTokenOverrides } from './resolveWeightTokenOverrides';
7
- import type { ThemeTokens } from './types';
8
8
 
9
9
  type GlobalThemeTokens = Omit<
10
10
  ThemeTokens,
@@ -1,6 +1,6 @@
1
1
  import type { ThemeTypographyHeadingOverrides } from '@ankhorage/contracts';
2
2
 
3
- import type { ThemeTokens } from './types';
3
+ import type { ThemeTokens } from '../../../types/theme';
4
4
 
5
5
  type HeadingTokens = ThemeTokens['typography']['headings'];
6
6
  type HeadingToken = HeadingTokens[1];
@@ -0,0 +1,16 @@
1
+ /*** Resolve a theme token key through its map while preserving raw values. */
2
+ type ResolvedToken<TMap, TValue> = TValue extends keyof TMap ? TMap[TValue] : TValue;
3
+
4
+ /*** Resolve a mapped theme token or return the supplied raw value unchanged. */
5
+ export function resolveToken<
6
+ TMap extends Record<string | number, unknown>,
7
+ TValue extends string | number | undefined,
8
+ >(map: TMap, value: TValue): ResolvedToken<TMap, TValue> {
9
+ if (value === undefined) return undefined as ResolvedToken<TMap, TValue>;
10
+
11
+ if (Object.prototype.hasOwnProperty.call(map, value)) {
12
+ return map[value as keyof TMap] as ResolvedToken<TMap, TValue>;
13
+ }
14
+
15
+ return value as ResolvedToken<TMap, TValue>;
16
+ }