tempest-react-sdk 0.74.0 → 0.76.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 (147) hide show
  1. package/README.md +3 -1
  2. package/dist/br/BrazilMap.module.cjs.map +1 -1
  3. package/dist/br/BrazilMap.module.js.map +1 -1
  4. package/dist/br/MunicipalitySearch.cjs +1 -1
  5. package/dist/br/MunicipalitySearch.cjs.map +1 -1
  6. package/dist/br/MunicipalitySearch.js +66 -48
  7. package/dist/br/MunicipalitySearch.js.map +1 -1
  8. package/dist/br/MunicipalitySearch.module.cjs +1 -1
  9. package/dist/br/MunicipalitySearch.module.cjs.map +1 -1
  10. package/dist/br/MunicipalitySearch.module.js +4 -3
  11. package/dist/br/MunicipalitySearch.module.js.map +1 -1
  12. package/dist/br.d.ts +12 -0
  13. package/dist/components/AIChat/AIChat.module.cjs.map +1 -1
  14. package/dist/components/AIChat/AIChat.module.js.map +1 -1
  15. package/dist/components/AppBar/AppBar.cjs +1 -1
  16. package/dist/components/AppBar/AppBar.cjs.map +1 -1
  17. package/dist/components/AppBar/AppBar.js +1 -0
  18. package/dist/components/AppBar/AppBar.js.map +1 -1
  19. package/dist/components/AppBar/AppBar.module.cjs +1 -1
  20. package/dist/components/AppBar/AppBar.module.cjs.map +1 -1
  21. package/dist/components/AppBar/AppBar.module.js +12 -11
  22. package/dist/components/AppBar/AppBar.module.js.map +1 -1
  23. package/dist/components/Button/Button.module.cjs.map +1 -1
  24. package/dist/components/Button/Button.module.js.map +1 -1
  25. package/dist/components/Button/ButtonContent.cjs.map +1 -1
  26. package/dist/components/Button/ButtonContent.js.map +1 -1
  27. package/dist/components/Carousel/Carousel.module.cjs.map +1 -1
  28. package/dist/components/Carousel/Carousel.module.js.map +1 -1
  29. package/dist/components/Chat/Chat.module.cjs.map +1 -1
  30. package/dist/components/Chat/Chat.module.js.map +1 -1
  31. package/dist/components/Combobox/Combobox.cjs +1 -1
  32. package/dist/components/Combobox/Combobox.cjs.map +1 -1
  33. package/dist/components/Combobox/Combobox.js +18 -23
  34. package/dist/components/Combobox/Combobox.js.map +1 -1
  35. package/dist/components/Combobox/use-listbox-dismiss.cjs +2 -0
  36. package/dist/components/Combobox/use-listbox-dismiss.cjs.map +1 -0
  37. package/dist/components/Combobox/use-listbox-dismiss.js +34 -0
  38. package/dist/components/Combobox/use-listbox-dismiss.js.map +1 -0
  39. package/dist/components/Dropzone/Dropzone.module.cjs.map +1 -1
  40. package/dist/components/Dropzone/Dropzone.module.js.map +1 -1
  41. package/dist/components/FilterBar/FilterBar.module.cjs.map +1 -1
  42. package/dist/components/FilterBar/FilterBar.module.js.map +1 -1
  43. package/dist/components/FloatingActionButton/FloatingActionButton.module.cjs.map +1 -1
  44. package/dist/components/FloatingActionButton/FloatingActionButton.module.js.map +1 -1
  45. package/dist/components/ImageCropper/ImageCropper.module.cjs.map +1 -1
  46. package/dist/components/ImageCropper/ImageCropper.module.js.map +1 -1
  47. package/dist/components/ListTile/ListTile.module.cjs.map +1 -1
  48. package/dist/components/ListTile/ListTile.module.js.map +1 -1
  49. package/dist/components/Markdown/Markdown.module.cjs.map +1 -1
  50. package/dist/components/Markdown/Markdown.module.js.map +1 -1
  51. package/dist/components/Menubar/Menubar.module.cjs.map +1 -1
  52. package/dist/components/Menubar/Menubar.module.js.map +1 -1
  53. package/dist/components/MultiSelect/MultiSelect.cjs +1 -1
  54. package/dist/components/MultiSelect/MultiSelect.cjs.map +1 -1
  55. package/dist/components/MultiSelect/MultiSelect.js +55 -54
  56. package/dist/components/MultiSelect/MultiSelect.js.map +1 -1
  57. package/dist/components/Navbar/Navbar.cjs +1 -1
  58. package/dist/components/Navbar/Navbar.cjs.map +1 -1
  59. package/dist/components/Navbar/Navbar.js +1 -0
  60. package/dist/components/Navbar/Navbar.js.map +1 -1
  61. package/dist/components/Navbar/Navbar.module.cjs +1 -1
  62. package/dist/components/Navbar/Navbar.module.cjs.map +1 -1
  63. package/dist/components/Navbar/Navbar.module.js +9 -8
  64. package/dist/components/Navbar/Navbar.module.js.map +1 -1
  65. package/dist/components/NavigationMenu/NavigationMenu.module.cjs.map +1 -1
  66. package/dist/components/NavigationMenu/NavigationMenu.module.js.map +1 -1
  67. package/dist/components/NavigationRail/NavigationRail.module.cjs.map +1 -1
  68. package/dist/components/NavigationRail/NavigationRail.module.js.map +1 -1
  69. package/dist/components/NotificationCenter/NotificationCenter.module.cjs.map +1 -1
  70. package/dist/components/NotificationCenter/NotificationCenter.module.js.map +1 -1
  71. package/dist/components/PasswordInput/PasswordInput.module.cjs.map +1 -1
  72. package/dist/components/PasswordInput/PasswordInput.module.js.map +1 -1
  73. package/dist/components/PinInput/PinInput.module.cjs.map +1 -1
  74. package/dist/components/PinInput/PinInput.module.js.map +1 -1
  75. package/dist/components/SectionHeader/SectionHeader.cjs +1 -1
  76. package/dist/components/SectionHeader/SectionHeader.cjs.map +1 -1
  77. package/dist/components/SectionHeader/SectionHeader.js +33 -25
  78. package/dist/components/SectionHeader/SectionHeader.js.map +1 -1
  79. package/dist/components/Tour/Tour.module.cjs.map +1 -1
  80. package/dist/components/Tour/Tour.module.js.map +1 -1
  81. package/dist/components/Transfer/Transfer.module.cjs.map +1 -1
  82. package/dist/components/Transfer/Transfer.module.js.map +1 -1
  83. package/dist/components/VirtualTable/VirtualTable.module.cjs.map +1 -1
  84. package/dist/components/VirtualTable/VirtualTable.module.js.map +1 -1
  85. package/dist/geo/TrajectoryMap.module.cjs.map +1 -1
  86. package/dist/geo/TrajectoryMap.module.js.map +1 -1
  87. package/dist/icons/IconPicker.module.cjs.map +1 -1
  88. package/dist/icons/IconPicker.module.js.map +1 -1
  89. package/dist/neural.cjs +2 -0
  90. package/dist/neural.cjs.map +1 -0
  91. package/dist/neural.d.ts +110 -0
  92. package/dist/neural.js +48 -0
  93. package/dist/neural.js.map +1 -0
  94. package/dist/styles/actions.css +2 -2
  95. package/dist/styles/br.css +3 -3
  96. package/dist/styles/chat.css +5 -5
  97. package/dist/styles/component/AIChat.css +3 -3
  98. package/dist/styles/component/AppBar.css +1 -0
  99. package/dist/styles/component/BrazilMap.css +2 -2
  100. package/dist/styles/component/Button.css +1 -1
  101. package/dist/styles/component/Carousel.css +3 -3
  102. package/dist/styles/component/Chat.css +2 -2
  103. package/dist/styles/component/Dropzone.css +2 -1
  104. package/dist/styles/component/FilterBar.css +2 -2
  105. package/dist/styles/component/FloatingActionButton.css +1 -1
  106. package/dist/styles/component/IconPicker.css +1 -1
  107. package/dist/styles/component/ImageCropper.css +2 -2
  108. package/dist/styles/component/ListTile.css +1 -1
  109. package/dist/styles/component/Markdown.css +1 -1
  110. package/dist/styles/component/Menubar.css +1 -1
  111. package/dist/styles/component/MunicipalitySearch.css +1 -1
  112. package/dist/styles/component/Navbar.css +1 -0
  113. package/dist/styles/component/NavigationMenu.css +1 -1
  114. package/dist/styles/component/NavigationRail.css +1 -1
  115. package/dist/styles/component/NotificationCenter.css +3 -3
  116. package/dist/styles/component/PasswordInput.css +1 -1
  117. package/dist/styles/component/PinInput.css +1 -1
  118. package/dist/styles/component/Tour.css +2 -2
  119. package/dist/styles/component/TrajectoryMap.css +1 -1
  120. package/dist/styles/component/Transfer.css +2 -2
  121. package/dist/styles/component/VirtualTable.css +2 -2
  122. package/dist/styles/data.css +10 -10
  123. package/dist/styles/feedback.css +3 -3
  124. package/dist/styles/forms.css +6 -5
  125. package/dist/styles/geo.css +1 -1
  126. package/dist/styles/icons.css +1 -1
  127. package/dist/styles/inverse.css +225 -0
  128. package/dist/styles/navigation.css +8 -6
  129. package/dist/styles.css +1 -1
  130. package/dist/tempest-react-sdk.d.ts +130 -17
  131. package/dist/theme/create-theme.cjs +1 -1
  132. package/dist/theme/create-theme.cjs.map +1 -1
  133. package/dist/theme/create-theme.js +6 -1
  134. package/dist/theme/create-theme.js.map +1 -1
  135. package/dist/theme/inverse-render.cjs +1 -1
  136. package/dist/theme/inverse-render.cjs.map +1 -1
  137. package/dist/theme/inverse-render.js +1 -1
  138. package/dist/theme/inverse-render.js.map +1 -1
  139. package/dist/theme/inverse-restore.cjs +5 -0
  140. package/dist/theme/inverse-restore.cjs.map +1 -0
  141. package/dist/theme/inverse-restore.js +30 -0
  142. package/dist/theme/inverse-restore.js.map +1 -0
  143. package/dist/theme/inverse-surface.cjs +1 -1
  144. package/dist/theme/inverse-surface.cjs.map +1 -1
  145. package/dist/theme/inverse-surface.js +69 -72
  146. package/dist/theme/inverse-surface.js.map +1 -1
  147. package/package.json +11 -1
@@ -1 +1 @@
1
- {"version":3,"file":"inverse-surface.js","names":[],"sources":["../../src/theme/inverse-surface.ts"],"sourcesContent":["/**\n * @tempest-limits file-lines — the inverse surface is a whole scheme: surfaces,\n * text, the action color, focus, selection, statuses, charts and syntax colors,\n * each derived and then measured against the brand fill it sits on. Splitting\n * the derivation from the table it is measured against is how the two drift.\n */\n/**\n * Inverse surface: the token set for a section painted in the brand color —\n * a hero, a call-to-action band, a footer — so the components inside it invert\n * instead of inheriting the page's tokens.\n *\n * Every value is derived from the brand and measured against the fill it will\n * sit on, the same way {@link createTheme} measures the page schemes. Overriding\n * eight tokens by hand (what #409 had to do) leaves the rest of the scheme on\n * the page's values: measured over a navy `#1e2a5a`, the inherited\n * `--tempest-text-subtle` lands at 2.75:1, `--tempest-danger` at 2.12:1, the\n * selected indicator at 2.01:1, and a `Card` puts white text on\n * `--tempest-surface` at 1.05:1.\n */\nimport {\n contrastRatio,\n createColorScale,\n hexToOklch,\n oklchToHex,\n readableForeground,\n type ColorScale,\n type Oklch,\n type ScaleStep,\n} from \"./color\";\nimport { buildDivergingRamp, buildRamp, hueOf } from \"./data-viz-ramps\";\nimport type { InverseScheme, InverseSurface, InverseSurfaceOptions } from \"./inverse-render\";\nimport { THEME_STATUSES, writeStatus, type ThemeStatus } from \"./status-tokens\";\n\nexport { INVERSE_SELECTOR, renderInverseSurface } from \"./inverse-render\";\nexport type {\n InverseScheme,\n InverseSurface,\n InverseSurfaceGenerator,\n InverseSurfaceOptions,\n} from \"./inverse-render\";\n\n/** WCAG 2.x AA floor for body text. */\nconst AA_TEXT = 4.5;\n\n/**\n * What text is fitted to, rather than the floor itself.\n *\n * The margin the SDK's dark theme keeps on `--tempest-text-subtle` (4.79 over its\n * surface): a value solved to exactly 4.5 turns the next rounding into a failure.\n */\nconst TEXT_TARGET = 4.75;\n\n/** WCAG 2.2 SC 1.4.11 floor for a non-text indicator. */\nconst INDICATOR_FLOOR = 3;\n\n/**\n * What the focus ring and the selected indicator are fitted to.\n *\n * Well above the 3:1 floor on purpose: the SDK's own rings keep 5.40:1 (dark)\n * and 5.50:1 (light) worst case, because a ring travels onto surfaces nobody\n * validated it against.\n */\nconst RING_TARGET = 4.5;\n\n/**\n * The smallest contrast the ink must keep — on the fill, the surfaces and the\n * glow — before the fill is accepted.\n *\n * AA (4.5) is not enough here, because the surface has three text levels — text,\n * muted and subtle — and all three must clear AA. With text at 4.83:1 (white on\n * the default `#0066ff`) the three collapse into one color. 7:1 (AAA) leaves room\n * for muted to sit visibly between text and subtle.\n */\nconst MIN_TEXT_RATIO = 7;\n\n/**\n * Fill candidates, nearest the brand first, darker before lighter on a tie.\n *\n * `500` is the brand itself and wins whenever it can carry the scheme. When it\n * cannot — a mid-tone brand such as `#0066ff`, where white measures 4.83:1 —\n * the walk moves one step at a time, so the section stays as close to the brand\n * as the measurement allows.\n *\n * Measuring the glow is what most of the walking pays for: against the flat\n * fill and the surfaces alone, 9 of the 14 test brands keep their `500`; with\n * the glow, 6 do. The three that move (`#8100D7`, `#22d3ee`, `#14b8a6`) are the\n * ones whose subtle text would fail on a lifted region of their own band.\n */\nconst FILL_CANDIDATES: readonly ScaleStep[] = [500, 600, 400, 700, 300, 800, 200, 900];\n\n/**\n * Lightness offsets from the fill, per scheme.\n *\n * The sizes are the SDK's own, measured in OKLCH: the dark theme's surfaces sit\n * 0.046, 0.094 and 0.140 from `#0b0d12`, its borders 0.155 and 0.222; the light\n * theme's surfaces sit 0.018, 0.037 and 0.073 from white, its borders 0.073 and\n * 0.128.\n *\n * The direction is not the SDK's. On the page, raised surfaces move toward the\n * ink, which costs nothing there: the page fill is near-white or near-black, so\n * the ink keeps 13:1 or more on the third surface. A brand fill sits mid-axis,\n * and moving toward the ink spends exactly the contrast the text needs. Measured\n * across the fourteen brands of the contrast test, every text level held to AA\n * on every surface and on the glow ({@link GLOW_OFFSET}):\n *\n * | surfaces move | brands keeping their own `500` | where `#8100D7` / `#4f46e5` land |\n * | --- | --- | --- |\n * | toward the ink | 6 of 14 | `800` / `800` |\n * | away from the ink | 6 of 14 | `700` / `700` |\n *\n * Never worse and one step nearer the brand for the purples, and with every\n * surface carrying the ink at least as well as the fill does.\n *\n * So surfaces move away from the ink — a card in a navy band is a deeper navy,\n * one in a yellow band a paler yellow — and every surface then carries the ink\n * at least as well as the fill does. Borders still move toward the ink, since a\n * border has to separate from the fill and the surfaces alike.\n */\nconst OFFSETS: Record<\n InverseScheme,\n { surfaces: readonly [number, number, number]; border: number; borderStrong: number }\n> = {\n dark: { surfaces: [0.046, 0.094, 0.14], border: 0.155, borderStrong: 0.222 },\n light: { surfaces: [0.018, 0.037, 0.073], border: 0.073, borderStrong: 0.128 },\n};\n\n/**\n * How far toward the ink a region of the band may lift and still be measured.\n *\n * A brand section is rarely one flat color: the landing that opened #409 lays a\n * radial glow of `#1f3f8f` at 55% over its navy `#03184b`, which lifts the\n * ground by 0.09 in OKLCH lightness, and a hover tint does the same. Text fitted\n * to the flat fill alone failed there — subtle measured 3.64:1 on that glow. So\n * every text and indicator token is also fitted against the fill lifted by this\n * much; darker variations (the landing's `#020f30` footer) only add contrast.\n */\nconst GLOW_OFFSET = 0.1;\n\n/** Text ink per scheme — the SDK's own extremes. */\nconst INK: Record<InverseScheme, string> = { dark: \"#ffffff\", light: \"#101828\" };\n\n/**\n * The SDK's default status colors, used when a theme names none.\n *\n * Ported from `src/styles/colors.css` (`--tempest-*-solid` in the light block),\n * and pinned by a test that reads that file.\n */\nexport const DEFAULT_STATUS_COLORS: Record<ThemeStatus, string> = {\n success: \"#16a34a\",\n warning: \"#d97706\",\n danger: \"#dc2626\",\n info: \"#2563eb\",\n};\n\n/**\n * The SDK's categorical chart colors, per scheme.\n *\n * Ported from `src/styles/colors.css` (`--tempest-chart-1` … `-8`), pinned by a\n * test that reads that file. Used as the starting hue for each slot, then fitted\n * to the inverse fill.\n */\nexport const DEFAULT_CHART_COLORS: Record<InverseScheme, readonly string[]> = {\n light: [\"#2563eb\", \"#16a34a\", \"#f59e0b\", \"#7c3aed\", \"#ec4899\", \"#06b6d4\", \"#ea580c\", \"#0f766e\"],\n dark: [\"#60a5fa\", \"#4ade80\", \"#fbbf24\", \"#a78bfa\", \"#f472b6\", \"#22d3ee\", \"#fb923c\", \"#2dd4bf\"],\n};\n\n/** Names of the `CodeBlock` syntax tokens, in `colors.css` order. */\nconst CODE_TOKENS = [\n \"comment\",\n \"punctuation\",\n \"string\",\n \"number\",\n \"keyword\",\n \"literal\",\n \"function\",\n \"tag\",\n \"attribute\",\n \"property\",\n] as const;\n\n/**\n * The SDK's syntax colors, per scheme, in {@link CODE_TOKENS} order.\n *\n * Ported from `src/styles/colors.css` (`--tempest-code-*`), pinned by a test\n * that reads that file. Used as the starting hue, then fitted to the inverse\n * code grounds.\n */\nexport const DEFAULT_CODE_COLORS: Record<InverseScheme, readonly string[]> = {\n light: [\n \"#5f666e\",\n \"#5d6671\",\n \"#327243\",\n \"#9d5035\",\n \"#625baf\",\n \"#9f4c4f\",\n \"#1a6c94\",\n \"#974d72\",\n \"#127171\",\n \"#127171\",\n ],\n dark: [\n \"#838b93\",\n \"#818b95\",\n \"#589866\",\n \"#c57558\",\n \"#8580d8\",\n \"#c87172\",\n \"#2893c6\",\n \"#c07197\",\n \"#349897\",\n \"#349897\",\n ],\n};\n\n/**\n * The SDK's elevation shadows, per scheme.\n *\n * Ported from `src/styles/colors.css` (`--tempest-shadow-*`). A light-ink fill\n * takes the dark theme's heavier shadows, since a faint shadow vanishes on it.\n * The dark block does not override `--tempest-shadow-inner`, so the dark row\n * carries the light value it inherits.\n */\nconst SHADOWS: Record<InverseScheme, Record<string, string>> = {\n light: {\n xs: \"0 1px 2px rgba(15, 23, 42, 0.04)\",\n sm: \"0 1px 3px rgba(15, 23, 42, 0.08), 0 1px 2px rgba(15, 23, 42, 0.04)\",\n md: \"0 4px 12px rgba(15, 23, 42, 0.08), 0 2px 4px rgba(15, 23, 42, 0.04)\",\n lg: \"0 12px 32px rgba(15, 23, 42, 0.12), 0 4px 8px rgba(15, 23, 42, 0.06)\",\n xl: \"0 24px 48px rgba(15, 23, 42, 0.18), 0 8px 16px rgba(15, 23, 42, 0.08)\",\n inner: \"inset 0 2px 4px rgba(15, 23, 42, 0.06)\",\n },\n dark: {\n xs: \"0 1px 2px rgba(0, 0, 0, 0.3)\",\n sm: \"0 1px 3px rgba(0, 0, 0, 0.4), 0 1px 2px rgba(0, 0, 0, 0.2)\",\n md: \"0 4px 12px rgba(0, 0, 0, 0.4), 0 2px 4px rgba(0, 0, 0, 0.2)\",\n lg: \"0 12px 32px rgba(0, 0, 0, 0.5), 0 4px 8px rgba(0, 0, 0, 0.3)\",\n xl: \"0 24px 48px rgba(0, 0, 0, 0.6), 0 8px 16px rgba(0, 0, 0, 0.3)\",\n inner: \"inset 0 2px 4px rgba(15, 23, 42, 0.06)\",\n },\n};\n\n/** Lightness step used when fitting a color toward the ink. */\nconst FIT_STEP = 0.005;\n\n/**\n * Move a color along the lightness axis toward (positive `delta`) or away from\n * the ink, keeping its hue.\n *\n * @param base - The color to move, in OKLCH.\n * @param direction - `1` when the ink is lighter than the fill, `-1` otherwise.\n * @param delta - How far to move, in OKLCH lightness.\n * @param chroma - Chroma of the result; defaults to the base's.\n * @returns The moved color as hex, gamut-mapped.\n */\nfunction shift(base: Oklch, direction: 1 | -1, delta: number, chroma: number = base.c): string {\n const l = Math.min(1, Math.max(0, base.l + direction * delta));\n return oklchToHex({ l, c: chroma, h: base.h });\n}\n\n/** Weakest contrast of `color` against every ground. */\nfunction worst(color: string, grounds: readonly string[]): number {\n return Math.min(...grounds.map((ground) => contrastRatio(color, ground)));\n}\n\n/**\n * Walk a color toward the ink until it clears `floor` against every ground.\n *\n * Hue and chroma are kept, so a danger stays red and a keyword stays violet;\n * only lightness moves, and only as far as the measurement asks. When the walk\n * reaches the end of the lightness axis without clearing, the ink itself is\n * returned — it is the most contrasting color the scheme has.\n *\n * @param start - Where to start, as hex.\n * @param direction - `1` when the ink is lighter than the grounds, `-1` otherwise.\n * @param grounds - Every background the color will sit on.\n * @param floor - The ratio to clear against all of them.\n * @param ink - Fallback when nothing on the walk clears.\n * @returns The first color on the walk that clears, else `ink`.\n */\nfunction fitToward(\n start: string,\n direction: 1 | -1,\n grounds: readonly string[],\n floor: number,\n ink: string,\n): string {\n const base = hexToOklch(start);\n for (let delta = 0; delta <= 1; delta += FIT_STEP) {\n const candidate = shift(base, direction, delta);\n if (worst(candidate, grounds) >= floor) return candidate;\n if ((direction === 1 && base.l + delta >= 1) || (direction === -1 && base.l - delta <= 0)) {\n break;\n }\n }\n return ink;\n}\n\n/**\n * How far the soft tint sits from the fill, per scheme; the hover tint sits\n * {@link SOFT_HOVER_FACTOR} times as far.\n */\nconst SOFT_OFFSET: Record<InverseScheme, number> = { dark: 0.07, light: 0.05 };\n\n/** Distance of the soft hover tint, relative to the soft tint's. */\nconst SOFT_HOVER_FACTOR = 1.6;\n\n/**\n * The soft tint and its hover, lifted toward the ink only as far as the ink\n * still reads on both.\n *\n * A tint toward the ink is what reads as \"highlighted\" on a fill, and it is also\n * what eats the ink's contrast: on the `#8100D7` fill, the full offset left white\n * at 4.42:1 on the hover tint. So the offset shrinks until the ink clears\n * {@link TEXT_TARGET} on both, and when even a sliver cannot — the fill gives the\n * ink no room — the tints move away from the ink instead, like the surfaces.\n *\n * @param base - The fill, in OKLCH.\n * @param direction - `1` when the ink is lighter than the fill, `-1` otherwise.\n * @param offset - The preferred distance of the soft tint.\n * @param ink - The scheme's text ink.\n * @returns The soft tint and its hover, as hex.\n */\nfunction softTints(base: Oklch, direction: 1 | -1, offset: number, ink: string): [string, string] {\n for (let delta = offset; delta > FIT_STEP; delta -= FIT_STEP) {\n const tints: [string, string] = [\n shift(base, direction, delta),\n shift(base, direction, delta * SOFT_HOVER_FACTOR),\n ];\n if (worst(ink, tints) >= TEXT_TARGET) return tints;\n }\n return [shift(base, direction, -offset), shift(base, direction, -offset * SOFT_HOVER_FACTOR)];\n}\n\n/** Mix `top` over `bottom` at `amount`, the way `color-mix(in srgb, …)` composites. */\nfunction mix(bottom: string, top: string, amount: number): string {\n const parse = (hex: string): number[] =>\n [1, 3, 5].map((index) => Number.parseInt(hex.slice(index, index + 2), 16));\n const [a, b] = [parse(bottom), parse(top)];\n const channels = a.map((channel, index) =>\n Math.round(channel + ((b[index] as number) - channel) * amount),\n );\n return `#${channels.map((channel) => channel.toString(16).padStart(2, \"0\")).join(\"\")}`;\n}\n\n/**\n * Derive the inverse scheme over one candidate fill.\n *\n * Text is three levels, like the page: the ink, then `muted` fitted to the\n * geometric mean of the ink's contrast and {@link TEXT_TARGET} (so it sits\n * visibly between the two), then `subtle` fitted to {@link TEXT_TARGET} on\n * `bg` and `surface` — the same pairs the SDK holds its own `text-subtle` to.\n *\n * The action color is the ink itself: a white button on a navy band, labelled in\n * the fill. Hover and active step back toward the fill, because the ink is\n * already the end of the axis and has nowhere further to go.\n *\n * `--tempest-danger-hover` steps toward the side that keeps `-on-solid`\n * readable: darker when the ink is white, lighter when it is dark. A fixed\n * direction cannot hold one ink over both fills — over the dark scheme's\n * `#dc2626` it measured 4.00:1 with the lighter hover.\n *\n * The ramp (`--tempest-primary-50` … `-900`) is emitted too, because `Tag` and\n * `Sidebar` pair raw steps (`100` under `700`). It is the scheme's unanchored\n * ramp, so that pair keeps the shape it has on the page.\n *\n * @param fill - The fill, as hex.\n * @param options - The brand description.\n * @returns The token map and the scheme it reads as.\n */\nfunction deriveOver(\n fill: string,\n options: InverseSurfaceOptions,\n): { tokens: Record<string, string>; scheme: InverseScheme; glow: string } {\n const ink = readableForeground(fill, INK.dark, INK.light);\n const scheme: InverseScheme = ink === INK.dark ? \"dark\" : \"light\";\n const direction: 1 | -1 = scheme === \"dark\" ? 1 : -1;\n const base = hexToOklch(fill);\n const offsets = OFFSETS[scheme];\n const tokens: Record<string, string> = {};\n\n const surfaces = [fill, ...offsets.surfaces.map((delta) => shift(base, direction, -delta))];\n const [bg, surface, surface2, surface3] = surfaces as [string, string, string, string];\n const glow = shift(base, direction, GLOW_OFFSET);\n const grounds = [...surfaces, glow];\n tokens[\"--tempest-bg\"] = bg;\n tokens[\"--tempest-surface\"] = surface;\n tokens[\"--tempest-surface-2\"] = surface2;\n tokens[\"--tempest-surface-3\"] = surface3;\n tokens[\"--tempest-border\"] = shift(base, direction, offsets.border);\n tokens[\"--tempest-border-strong\"] = shift(base, direction, offsets.borderStrong);\n\n const textWorst = worst(ink, grounds);\n const tint = base.c * 0.4;\n tokens[\"--tempest-text\"] = ink;\n tokens[\"--tempest-text-muted\"] = fitToward(\n shift(base, direction, 0, tint),\n direction,\n grounds,\n Math.max(TEXT_TARGET, Math.sqrt(textWorst * TEXT_TARGET)),\n ink,\n );\n tokens[\"--tempest-text-subtle\"] = fitToward(\n shift(base, direction, 0, tint),\n direction,\n [bg, surface, glow],\n TEXT_TARGET,\n ink,\n );\n\n const inkBase: Oklch = { ...hexToOklch(ink), h: base.h };\n tokens[\"--tempest-primary\"] = ink;\n tokens[\"--tempest-primary-hover\"] = shift(inkBase, direction, -0.05, base.c * 0.25);\n tokens[\"--tempest-primary-active\"] = shift(inkBase, direction, -0.1, base.c * 0.3);\n tokens[\"--tempest-primary-foreground\"] = fill;\n tokens[\"--tempest-text-on-primary\"] = fill;\n\n const [soft, softHover] = softTints(base, direction, SOFT_OFFSET[scheme], ink);\n tokens[\"--tempest-primary-soft\"] = soft;\n tokens[\"--tempest-primary-soft-hover\"] = softHover;\n tokens[\"--tempest-primary-on-soft\"] = fitToward(\n soft,\n direction,\n [soft, softHover],\n TEXT_TARGET,\n ink,\n );\n\n const ring = fitToward(fill, direction, grounds, RING_TARGET, ink);\n tokens[\"--tempest-focus-ring-color\"] = ring;\n tokens[\"--tempest-selected-indicator\"] = ring;\n\n const ramp: ColorScale = createColorScale(options.primary, scheme, { anchor: false });\n for (const [step, value] of Object.entries(ramp)) {\n tokens[`--tempest-primary-${step}`] = value;\n }\n\n for (const status of THEME_STATUSES) {\n const scale = createColorScale(\n options.statuses?.[status] ?? DEFAULT_STATUS_COLORS[status],\n scheme,\n );\n writeStatus(tokens, status, scale, scheme);\n tokens[`--tempest-${status}`] = fitToward(\n tokens[`--tempest-${status}`] as string,\n direction,\n grounds,\n TEXT_TARGET,\n ink,\n );\n if (status === \"danger\") {\n const whiteInk = tokens[\"--tempest-danger-on-solid\"] === \"#ffffff\";\n const darker: ScaleStep = scheme === \"dark\" ? 400 : 700;\n const lighter: ScaleStep = scheme === \"dark\" ? 600 : 500;\n tokens[\"--tempest-danger-hover\"] = scale[whiteInk ? darker : lighter];\n }\n }\n\n const chart = options.chart?.length ? options.chart : DEFAULT_CHART_COLORS[scheme];\n chart.forEach((color, index) => {\n tokens[`--tempest-chart-${index + 1}`] = fitToward(\n color,\n direction,\n [bg, surface, glow],\n INDICATOR_FLOOR,\n ink,\n );\n });\n const coolHue = hueOf(options.chart?.[0] ?? options.primary);\n const warmHue = options.statuses?.danger\n ? hueOf(options.statuses.danger)\n : (coolHue + 180) % 360;\n buildRamp(coolHue, scheme).forEach((value, index) => {\n tokens[`--tempest-chart-sequential-${index + 1}`] = value;\n });\n const diverging = buildDivergingRamp({ coolHue, warmHue, mid: surface3, mode: scheme });\n [...diverging.cool, diverging.mid, ...diverging.warm].forEach((value, index) => {\n tokens[`--tempest-chart-diverging-${index + 1}`] = value;\n });\n tokens[\"--tempest-chart-grid\"] = tokens[\"--tempest-border\"] as string;\n tokens[\"--tempest-chart-axis\"] = tokens[\"--tempest-text-subtle\"] as string;\n\n const codeGrounds = [bg, surface, mix(surface, ink, 0.1)];\n CODE_TOKENS.forEach((name, index) => {\n tokens[`--tempest-code-${name}`] = fitToward(\n DEFAULT_CODE_COLORS[scheme][index] as string,\n direction,\n codeGrounds,\n TEXT_TARGET,\n ink,\n );\n });\n\n for (const [name, value] of Object.entries(SHADOWS[scheme])) {\n tokens[`--tempest-shadow-${name}`] = value;\n }\n\n return { tokens, scheme, glow };\n}\n\n/**\n * The gates a candidate fill must clear before it is accepted.\n *\n * Text reaches {@link MIN_TEXT_RATIO} on every surface, every fitted text token\n * clears AA where it is used, the ring clears 3:1 on every surface, and the\n * action label clears AA on all three button states.\n *\n * @param tokens - A derived token map.\n * @param glow - The fill lifted by {@link GLOW_OFFSET}, measured alongside the surfaces.\n * @returns The weakest margin over its floor across all gates; `>= 0` passes.\n */\nfunction margin(tokens: Record<string, string>, glow: string): number {\n const read = (name: string): string => tokens[name] as string;\n const surfaces = [\n read(\"--tempest-bg\"),\n read(\"--tempest-surface\"),\n read(\"--tempest-surface-2\"),\n read(\"--tempest-surface-3\"),\n ];\n const label = read(\"--tempest-primary-foreground\");\n const checks: number[] = [\n worst(read(\"--tempest-text\"), [...surfaces, glow]) / MIN_TEXT_RATIO,\n worst(read(\"--tempest-text-muted\"), [...surfaces, glow]) / AA_TEXT,\n worst(read(\"--tempest-text-subtle\"), [...surfaces.slice(0, 2), glow]) / AA_TEXT,\n worst(read(\"--tempest-focus-ring-color\"), [...surfaces, glow]) / INDICATOR_FLOOR,\n worst(label, [\n read(\"--tempest-primary\"),\n read(\"--tempest-primary-hover\"),\n read(\"--tempest-primary-active\"),\n ]) / AA_TEXT,\n ];\n return Math.min(...checks) - 1;\n}\n\n/**\n * Build the inverse surface for a brand.\n *\n * The fill is the brand's own `500` whenever it can carry the scheme, and\n * otherwise the nearest ramp step that can (see {@link FILL_CANDIDATES}). Whether\n * the surface reads light-on-dark or dark-on-light follows the fill, so a yellow\n * brand gets dark ink and a navy one white — the same pick `createTheme` makes\n * for `--tempest-primary-foreground`.\n *\n * The values are literal colors, not references to the page's ramp, so the\n * section paints the same in the light and the dark page scheme: the brand is\n * the brand in both.\n *\n * @param options - The brand, plus the status and chart colors the theme names.\n * @returns The token map, the scheme it reads as, and the fill step used.\n */\nexport function createInverseSurface(options: InverseSurfaceOptions): InverseSurface {\n const ramp = createColorScale(options.primary, \"light\");\n let best: InverseSurface | null = null;\n let bestMargin = Number.NEGATIVE_INFINITY;\n for (const step of FILL_CANDIDATES) {\n const derived = deriveOver(ramp[step], options);\n const measured = margin(derived.tokens, derived.glow);\n if (measured >= 0) return { tokens: derived.tokens, scheme: derived.scheme, step };\n if (measured > bestMargin) {\n best = { tokens: derived.tokens, scheme: derived.scheme, step };\n bestMargin = measured;\n }\n }\n return best as InverseSurface;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"inverse-surface.js","names":[],"sources":["../../src/theme/inverse-surface.ts"],"sourcesContent":["/**\n * @tempest-limits file-lines — the inverse surface is a whole scheme: surfaces,\n * text, the action color, focus, selection, statuses, charts and syntax colors,\n * each derived and then measured against the brand fill it sits on. Splitting\n * the derivation from the table it is measured against is how the two drift.\n */\n/**\n * Inverse surface: the token set for a section painted in the brand color —\n * a hero, a call-to-action band, a footer — so the components inside it invert\n * instead of inheriting the page's tokens.\n *\n * Every value is derived from the brand and measured against the fill it will\n * sit on, the same way {@link createTheme} measures the page schemes. Overriding\n * eight tokens by hand (what #409 had to do) leaves the rest of the scheme on\n * the page's values: measured over a navy `#1e2a5a`, the inherited\n * `--tempest-text-subtle` lands at 2.75:1, `--tempest-danger` at 2.12:1, the\n * selected indicator at 2.01:1, and a `Card` puts white text on\n * `--tempest-surface` at 1.05:1.\n */\nimport {\n contrastRatio,\n createColorScale,\n hexToOklch,\n oklchToHex,\n readableForeground,\n type ColorScale,\n type Oklch,\n type ScaleStep,\n} from \"./color\";\nimport { buildDivergingRamp, buildRamp, hueOf } from \"./data-viz-ramps\";\nimport {\n INVERSE_SELECTOR,\n type InverseScheme,\n type InverseSurface,\n type InverseSurfaceOptions,\n} from \"./inverse-render\";\nimport { DEFAULT_PAGE_SELECTORS, defaultToneRules } from \"./inverse-restore\";\nimport { THEME_STATUSES, writeStatus, type ThemeStatus } from \"./status-tokens\";\n\nexport { INVERSE_SELECTOR, renderInverseSurface } from \"./inverse-render\";\nexport { DEFAULT_TONE_SELECTOR } from \"./inverse-restore\";\nexport type {\n InverseScheme,\n InverseSurface,\n InverseSurfaceGenerator,\n InverseSurfaceOptions,\n PageSelectors,\n} from \"./inverse-render\";\n\n/** WCAG 2.x AA floor for body text. */\nconst AA_TEXT = 4.5;\n\n/**\n * What text is fitted to, rather than the floor itself.\n *\n * The margin the SDK's dark theme keeps on `--tempest-text-subtle` (4.79 over its\n * surface): a value solved to exactly 4.5 turns the next rounding into a failure.\n */\nconst TEXT_TARGET = 4.75;\n\n/** WCAG 2.2 SC 1.4.11 floor for a non-text indicator. */\nconst INDICATOR_FLOOR = 3;\n\n/**\n * What the focus ring and the selected indicator are fitted to.\n *\n * Well above the 3:1 floor on purpose: the SDK's own rings keep 5.40:1 (dark)\n * and 5.50:1 (light) worst case, because a ring travels onto surfaces nobody\n * validated it against.\n */\nconst RING_TARGET = 4.5;\n\n/**\n * The smallest contrast the ink must keep — on the fill, the surfaces and the\n * glow — before the fill is accepted.\n *\n * AA (4.5) is not enough here, because the surface has three text levels — text,\n * muted and subtle — and all three must clear AA. With text at 4.83:1 (white on\n * the default `#0066ff`) the three collapse into one color. 7:1 (AAA) leaves room\n * for muted to sit visibly between text and subtle.\n */\nconst MIN_TEXT_RATIO = 7;\n\n/**\n * Fill candidates, nearest the brand first, darker before lighter on a tie.\n *\n * `500` is the brand itself and wins whenever it can carry the scheme. When it\n * cannot — a mid-tone brand such as `#0066ff`, where white measures 4.83:1 —\n * the walk moves one step at a time, so the section stays as close to the brand\n * as the measurement allows.\n *\n * Measuring the glow is what most of the walking pays for: against the flat\n * fill and the surfaces alone, 9 of the 14 test brands keep their `500`; with\n * the glow, 6 do. The three that move (`#8100D7`, `#22d3ee`, `#14b8a6`) are the\n * ones whose subtle text would fail on a lifted region of their own band.\n */\nconst FILL_CANDIDATES: readonly ScaleStep[] = [500, 600, 400, 700, 300, 800, 200, 900];\n\n/**\n * Lightness offsets from the fill, per scheme.\n *\n * The sizes are the SDK's own, measured in OKLCH: the dark theme's surfaces sit\n * 0.046, 0.094 and 0.140 from `#0b0d12`, its borders 0.155 and 0.222; the light\n * theme's surfaces sit 0.018, 0.037 and 0.073 from white, its borders 0.073 and\n * 0.128.\n *\n * The direction is not the SDK's. On the page, raised surfaces move toward the\n * ink, which costs nothing there: the page fill is near-white or near-black, so\n * the ink keeps 13:1 or more on the third surface. A brand fill sits mid-axis,\n * and moving toward the ink spends exactly the contrast the text needs. Measured\n * across the fourteen brands of the contrast test, every text level held to AA\n * on every surface and on the glow ({@link GLOW_OFFSET}):\n *\n * | surfaces move | brands keeping their own `500` | where `#8100D7` / `#4f46e5` land |\n * | --- | --- | --- |\n * | toward the ink | 6 of 14 | `800` / `800` |\n * | away from the ink | 6 of 14 | `700` / `700` |\n *\n * Never worse and one step nearer the brand for the purples, and with every\n * surface carrying the ink at least as well as the fill does.\n *\n * So surfaces move away from the ink — a card in a navy band is a deeper navy,\n * one in a yellow band a paler yellow — and every surface then carries the ink\n * at least as well as the fill does. Borders still move toward the ink, since a\n * border has to separate from the fill and the surfaces alike.\n */\nconst OFFSETS: Record<\n InverseScheme,\n { surfaces: readonly [number, number, number]; border: number; borderStrong: number }\n> = {\n dark: { surfaces: [0.046, 0.094, 0.14], border: 0.155, borderStrong: 0.222 },\n light: { surfaces: [0.018, 0.037, 0.073], border: 0.073, borderStrong: 0.128 },\n};\n\n/**\n * How far toward the ink a region of the band may lift and still be measured.\n *\n * A brand section is rarely one flat color: the landing that opened #409 lays a\n * radial glow of `#1f3f8f` at 55% over its navy `#03184b`, which lifts the\n * ground by 0.09 in OKLCH lightness, and a hover tint does the same. Text fitted\n * to the flat fill alone failed there — subtle measured 3.64:1 on that glow. So\n * every text and indicator token is also fitted against the fill lifted by this\n * much; darker variations (the landing's `#020f30` footer) only add contrast.\n */\nconst GLOW_OFFSET = 0.1;\n\n/** Text ink per scheme — the SDK's own extremes. */\nconst INK: Record<InverseScheme, string> = { dark: \"#ffffff\", light: \"#101828\" };\n\n/**\n * The SDK's default status colors, used when a theme names none.\n *\n * Ported from `src/styles/colors.css` (`--tempest-*-solid` in the light block),\n * and pinned by a test that reads that file.\n */\nexport const DEFAULT_STATUS_COLORS: Record<ThemeStatus, string> = {\n success: \"#16a34a\",\n warning: \"#d97706\",\n danger: \"#dc2626\",\n info: \"#2563eb\",\n};\n\n/**\n * The SDK's categorical chart colors, per scheme.\n *\n * Ported from `src/styles/colors.css` (`--tempest-chart-1` … `-8`), pinned by a\n * test that reads that file. Used as the starting hue for each slot, then fitted\n * to the inverse fill.\n */\nexport const DEFAULT_CHART_COLORS: Record<InverseScheme, readonly string[]> = {\n light: [\"#2563eb\", \"#16a34a\", \"#f59e0b\", \"#7c3aed\", \"#ec4899\", \"#06b6d4\", \"#ea580c\", \"#0f766e\"],\n dark: [\"#60a5fa\", \"#4ade80\", \"#fbbf24\", \"#a78bfa\", \"#f472b6\", \"#22d3ee\", \"#fb923c\", \"#2dd4bf\"],\n};\n\n/** Names of the `CodeBlock` syntax tokens, in `colors.css` order. */\nconst CODE_TOKENS = [\n \"comment\",\n \"punctuation\",\n \"string\",\n \"number\",\n \"keyword\",\n \"literal\",\n \"function\",\n \"tag\",\n \"attribute\",\n \"property\",\n] as const;\n\n/**\n * The SDK's syntax colors, per scheme, in {@link CODE_TOKENS} order.\n *\n * Ported from `src/styles/colors.css` (`--tempest-code-*`), pinned by a test\n * that reads that file. Used as the starting hue, then fitted to the inverse\n * code grounds.\n */\nexport const DEFAULT_CODE_COLORS: Record<InverseScheme, readonly string[]> = {\n light: [\n \"#5f666e\",\n \"#5d6671\",\n \"#327243\",\n \"#9d5035\",\n \"#625baf\",\n \"#9f4c4f\",\n \"#1a6c94\",\n \"#974d72\",\n \"#127171\",\n \"#127171\",\n ],\n dark: [\n \"#838b93\",\n \"#818b95\",\n \"#589866\",\n \"#c57558\",\n \"#8580d8\",\n \"#c87172\",\n \"#2893c6\",\n \"#c07197\",\n \"#349897\",\n \"#349897\",\n ],\n};\n\n/**\n * The SDK's elevation shadows, per scheme.\n *\n * Ported from `src/styles/colors.css` (`--tempest-shadow-*`). A light-ink fill\n * takes the dark theme's heavier shadows, since a faint shadow vanishes on it.\n * The dark block does not override `--tempest-shadow-inner`, so the dark row\n * carries the light value it inherits.\n */\nconst SHADOWS: Record<InverseScheme, Record<string, string>> = {\n light: {\n xs: \"0 1px 2px rgba(15, 23, 42, 0.04)\",\n sm: \"0 1px 3px rgba(15, 23, 42, 0.08), 0 1px 2px rgba(15, 23, 42, 0.04)\",\n md: \"0 4px 12px rgba(15, 23, 42, 0.08), 0 2px 4px rgba(15, 23, 42, 0.04)\",\n lg: \"0 12px 32px rgba(15, 23, 42, 0.12), 0 4px 8px rgba(15, 23, 42, 0.06)\",\n xl: \"0 24px 48px rgba(15, 23, 42, 0.18), 0 8px 16px rgba(15, 23, 42, 0.08)\",\n inner: \"inset 0 2px 4px rgba(15, 23, 42, 0.06)\",\n },\n dark: {\n xs: \"0 1px 2px rgba(0, 0, 0, 0.3)\",\n sm: \"0 1px 3px rgba(0, 0, 0, 0.4), 0 1px 2px rgba(0, 0, 0, 0.2)\",\n md: \"0 4px 12px rgba(0, 0, 0, 0.4), 0 2px 4px rgba(0, 0, 0, 0.2)\",\n lg: \"0 12px 32px rgba(0, 0, 0, 0.5), 0 4px 8px rgba(0, 0, 0, 0.3)\",\n xl: \"0 24px 48px rgba(0, 0, 0, 0.6), 0 8px 16px rgba(0, 0, 0, 0.3)\",\n inner: \"inset 0 2px 4px rgba(15, 23, 42, 0.06)\",\n },\n};\n\n/** Lightness step used when fitting a color toward the ink. */\nconst FIT_STEP = 0.005;\n\n/**\n * Move a color along the lightness axis toward (positive `delta`) or away from\n * the ink, keeping its hue.\n *\n * @param base - The color to move, in OKLCH.\n * @param direction - `1` when the ink is lighter than the fill, `-1` otherwise.\n * @param delta - How far to move, in OKLCH lightness.\n * @param chroma - Chroma of the result; defaults to the base's.\n * @returns The moved color as hex, gamut-mapped.\n */\nfunction shift(base: Oklch, direction: 1 | -1, delta: number, chroma: number = base.c): string {\n const l = Math.min(1, Math.max(0, base.l + direction * delta));\n return oklchToHex({ l, c: chroma, h: base.h });\n}\n\n/** Weakest contrast of `color` against every ground. */\nfunction worst(color: string, grounds: readonly string[]): number {\n return Math.min(...grounds.map((ground) => contrastRatio(color, ground)));\n}\n\n/**\n * Walk a color toward the ink until it clears `floor` against every ground.\n *\n * Hue and chroma are kept, so a danger stays red and a keyword stays violet;\n * only lightness moves, and only as far as the measurement asks. When the walk\n * reaches the end of the lightness axis without clearing, the ink itself is\n * returned — it is the most contrasting color the scheme has.\n *\n * @param start - Where to start, as hex.\n * @param direction - `1` when the ink is lighter than the grounds, `-1` otherwise.\n * @param grounds - Every background the color will sit on.\n * @param floor - The ratio to clear against all of them.\n * @param ink - Fallback when nothing on the walk clears.\n * @returns The first color on the walk that clears, else `ink`.\n */\nfunction fitToward(\n start: string,\n direction: 1 | -1,\n grounds: readonly string[],\n floor: number,\n ink: string,\n): string {\n const base = hexToOklch(start);\n for (let delta = 0; delta <= 1; delta += FIT_STEP) {\n const candidate = shift(base, direction, delta);\n if (worst(candidate, grounds) >= floor) return candidate;\n if ((direction === 1 && base.l + delta >= 1) || (direction === -1 && base.l - delta <= 0)) {\n break;\n }\n }\n return ink;\n}\n\n/**\n * How far the soft tint sits from the fill, per scheme; the hover tint sits\n * {@link SOFT_HOVER_FACTOR} times as far.\n */\nconst SOFT_OFFSET: Record<InverseScheme, number> = { dark: 0.07, light: 0.05 };\n\n/** Distance of the soft hover tint, relative to the soft tint's. */\nconst SOFT_HOVER_FACTOR = 1.6;\n\n/**\n * The soft tint and its hover, lifted toward the ink only as far as the ink\n * still reads on both.\n *\n * A tint toward the ink is what reads as \"highlighted\" on a fill, and it is also\n * what eats the ink's contrast: on the `#8100D7` fill, the full offset left white\n * at 4.42:1 on the hover tint. So the offset shrinks until the ink clears\n * {@link TEXT_TARGET} on both, and when even a sliver cannot — the fill gives the\n * ink no room — the tints move away from the ink instead, like the surfaces.\n *\n * @param base - The fill, in OKLCH.\n * @param direction - `1` when the ink is lighter than the fill, `-1` otherwise.\n * @param offset - The preferred distance of the soft tint.\n * @param ink - The scheme's text ink.\n * @returns The soft tint and its hover, as hex.\n */\nfunction softTints(base: Oklch, direction: 1 | -1, offset: number, ink: string): [string, string] {\n for (let delta = offset; delta > FIT_STEP; delta -= FIT_STEP) {\n const tints: [string, string] = [\n shift(base, direction, delta),\n shift(base, direction, delta * SOFT_HOVER_FACTOR),\n ];\n if (worst(ink, tints) >= TEXT_TARGET) return tints;\n }\n return [shift(base, direction, -offset), shift(base, direction, -offset * SOFT_HOVER_FACTOR)];\n}\n\n/** Mix `top` over `bottom` at `amount`, the way `color-mix(in srgb, …)` composites. */\nfunction mix(bottom: string, top: string, amount: number): string {\n const parse = (hex: string): number[] =>\n [1, 3, 5].map((index) => Number.parseInt(hex.slice(index, index + 2), 16));\n const [a, b] = [parse(bottom), parse(top)];\n const channels = a.map((channel, index) =>\n Math.round(channel + ((b[index] as number) - channel) * amount),\n );\n return `#${channels.map((channel) => channel.toString(16).padStart(2, \"0\")).join(\"\")}`;\n}\n\n/**\n * Derive the inverse scheme over one candidate fill.\n *\n * Text is three levels, like the page: the ink, then `muted` fitted to the\n * geometric mean of the ink's contrast and {@link TEXT_TARGET} (so it sits\n * visibly between the two), then `subtle` fitted to {@link TEXT_TARGET} on\n * `bg` and `surface` — the same pairs the SDK holds its own `text-subtle` to.\n *\n * The action color is the ink itself: a white button on a navy band, labelled in\n * the fill. Hover and active step back toward the fill, because the ink is\n * already the end of the axis and has nowhere further to go.\n *\n * `--tempest-danger-hover` steps toward the side that keeps `-on-solid`\n * readable: darker when the ink is white, lighter when it is dark. A fixed\n * direction cannot hold one ink over both fills — over the dark scheme's\n * `#dc2626` it measured 4.00:1 with the lighter hover.\n *\n * The ramp (`--tempest-primary-50` … `-900`) is emitted too, because `Tag` and\n * `Sidebar` pair raw steps (`100` under `700`). It is the scheme's unanchored\n * ramp, so that pair keeps the shape it has on the page.\n *\n * @param fill - The fill, as hex.\n * @param options - The brand description.\n * @returns The token map and the scheme it reads as.\n */\nfunction deriveOver(\n fill: string,\n options: InverseSurfaceOptions,\n): { tokens: Record<string, string>; scheme: InverseScheme; glow: string } {\n const ink = readableForeground(fill, INK.dark, INK.light);\n const scheme: InverseScheme = ink === INK.dark ? \"dark\" : \"light\";\n const direction: 1 | -1 = scheme === \"dark\" ? 1 : -1;\n const base = hexToOklch(fill);\n const offsets = OFFSETS[scheme];\n const tokens: Record<string, string> = {};\n\n const surfaces = [fill, ...offsets.surfaces.map((delta) => shift(base, direction, -delta))];\n const [bg, surface, surface2, surface3] = surfaces as [string, string, string, string];\n const glow = shift(base, direction, GLOW_OFFSET);\n const grounds = [...surfaces, glow];\n tokens[\"--tempest-bg\"] = bg;\n tokens[\"--tempest-surface\"] = surface;\n tokens[\"--tempest-surface-2\"] = surface2;\n tokens[\"--tempest-surface-3\"] = surface3;\n tokens[\"--tempest-border\"] = shift(base, direction, offsets.border);\n tokens[\"--tempest-border-strong\"] = shift(base, direction, offsets.borderStrong);\n\n const textWorst = worst(ink, grounds);\n const tint = base.c * 0.4;\n tokens[\"--tempest-text\"] = ink;\n tokens[\"--tempest-text-muted\"] = fitToward(\n shift(base, direction, 0, tint),\n direction,\n grounds,\n Math.max(TEXT_TARGET, Math.sqrt(textWorst * TEXT_TARGET)),\n ink,\n );\n tokens[\"--tempest-text-subtle\"] = fitToward(\n shift(base, direction, 0, tint),\n direction,\n [bg, surface, glow],\n TEXT_TARGET,\n ink,\n );\n\n const inkBase: Oklch = { ...hexToOklch(ink), h: base.h };\n tokens[\"--tempest-primary\"] = ink;\n tokens[\"--tempest-primary-hover\"] = shift(inkBase, direction, -0.05, base.c * 0.25);\n tokens[\"--tempest-primary-active\"] = shift(inkBase, direction, -0.1, base.c * 0.3);\n tokens[\"--tempest-primary-foreground\"] = fill;\n tokens[\"--tempest-text-on-primary\"] = fill;\n\n const [soft, softHover] = softTints(base, direction, SOFT_OFFSET[scheme], ink);\n tokens[\"--tempest-primary-soft\"] = soft;\n tokens[\"--tempest-primary-soft-hover\"] = softHover;\n tokens[\"--tempest-primary-on-soft\"] = fitToward(\n soft,\n direction,\n [soft, softHover],\n TEXT_TARGET,\n ink,\n );\n\n const ring = fitToward(fill, direction, grounds, RING_TARGET, ink);\n tokens[\"--tempest-focus-ring-color\"] = ring;\n tokens[\"--tempest-selected-indicator\"] = ring;\n\n const ramp: ColorScale = createColorScale(options.primary, scheme, { anchor: false });\n for (const [step, value] of Object.entries(ramp)) {\n tokens[`--tempest-primary-${step}`] = value;\n }\n\n for (const status of THEME_STATUSES) {\n const scale = createColorScale(\n options.statuses?.[status] ?? DEFAULT_STATUS_COLORS[status],\n scheme,\n );\n writeStatus(tokens, status, scale, scheme);\n tokens[`--tempest-${status}`] = fitToward(\n tokens[`--tempest-${status}`] as string,\n direction,\n grounds,\n TEXT_TARGET,\n ink,\n );\n if (status === \"danger\") {\n const whiteInk = tokens[\"--tempest-danger-on-solid\"] === \"#ffffff\";\n const darker: ScaleStep = scheme === \"dark\" ? 400 : 700;\n const lighter: ScaleStep = scheme === \"dark\" ? 600 : 500;\n tokens[\"--tempest-danger-hover\"] = scale[whiteInk ? darker : lighter];\n }\n }\n\n const chart = options.chart?.length ? options.chart : DEFAULT_CHART_COLORS[scheme];\n chart.forEach((color, index) => {\n tokens[`--tempest-chart-${index + 1}`] = fitToward(\n color,\n direction,\n [bg, surface, glow],\n INDICATOR_FLOOR,\n ink,\n );\n });\n const coolHue = hueOf(options.chart?.[0] ?? options.primary);\n const warmHue = options.statuses?.danger\n ? hueOf(options.statuses.danger)\n : (coolHue + 180) % 360;\n buildRamp(coolHue, scheme).forEach((value, index) => {\n tokens[`--tempest-chart-sequential-${index + 1}`] = value;\n });\n const diverging = buildDivergingRamp({ coolHue, warmHue, mid: surface3, mode: scheme });\n [...diverging.cool, diverging.mid, ...diverging.warm].forEach((value, index) => {\n tokens[`--tempest-chart-diverging-${index + 1}`] = value;\n });\n tokens[\"--tempest-chart-grid\"] = tokens[\"--tempest-border\"] as string;\n tokens[\"--tempest-chart-axis\"] = tokens[\"--tempest-text-subtle\"] as string;\n\n const codeGrounds = [bg, surface, mix(surface, ink, 0.1)];\n CODE_TOKENS.forEach((name, index) => {\n tokens[`--tempest-code-${name}`] = fitToward(\n DEFAULT_CODE_COLORS[scheme][index] as string,\n direction,\n codeGrounds,\n TEXT_TARGET,\n ink,\n );\n });\n\n for (const [name, value] of Object.entries(SHADOWS[scheme])) {\n tokens[`--tempest-shadow-${name}`] = value;\n }\n\n return { tokens, scheme, glow };\n}\n\n/**\n * The gates a candidate fill must clear before it is accepted.\n *\n * Text reaches {@link MIN_TEXT_RATIO} on every surface, every fitted text token\n * clears AA where it is used, the ring clears 3:1 on every surface, and the\n * action label clears AA on all three button states.\n *\n * @param tokens - A derived token map.\n * @param glow - The fill lifted by {@link GLOW_OFFSET}, measured alongside the surfaces.\n * @returns The weakest margin over its floor across all gates; `>= 0` passes.\n */\nfunction margin(tokens: Record<string, string>, glow: string): number {\n const read = (name: string): string => tokens[name] as string;\n const surfaces = [\n read(\"--tempest-bg\"),\n read(\"--tempest-surface\"),\n read(\"--tempest-surface-2\"),\n read(\"--tempest-surface-3\"),\n ];\n const label = read(\"--tempest-primary-foreground\");\n const checks: number[] = [\n worst(read(\"--tempest-text\"), [...surfaces, glow]) / MIN_TEXT_RATIO,\n worst(read(\"--tempest-text-muted\"), [...surfaces, glow]) / AA_TEXT,\n worst(read(\"--tempest-text-subtle\"), [...surfaces.slice(0, 2), glow]) / AA_TEXT,\n worst(read(\"--tempest-focus-ring-color\"), [...surfaces, glow]) / INDICATOR_FLOOR,\n worst(label, [\n read(\"--tempest-primary\"),\n read(\"--tempest-primary-hover\"),\n read(\"--tempest-primary-active\"),\n ]) / AA_TEXT,\n ];\n return Math.min(...checks) - 1;\n}\n\n/**\n * Build the inverse surface for a brand.\n *\n * The fill is the brand's own `500` whenever it can carry the scheme, and\n * otherwise the nearest ramp step that can (see {@link FILL_CANDIDATES}). Whether\n * the surface reads light-on-dark or dark-on-light follows the fill, so a yellow\n * brand gets dark ink and a navy one white — the same pick `createTheme` makes\n * for `--tempest-primary-foreground`.\n *\n * The values are literal colors, not references to the page's ramp, so the\n * section paints the same in the light and the dark page scheme: the brand is\n * the brand in both.\n *\n * The result also carries the rules that let a region inside the surface go\n * back to the page's tokens (`data-tempest-tone=\"default\"`), written for the\n * selectors in `options`.\n *\n * @param options - The brand, plus the status and chart colors the theme names\n * and the selectors the surface and the page are written under.\n * @returns The token map, the scheme it reads as, the fill step used and the\n * default-tone rules.\n */\nexport function createInverseSurface(options: InverseSurfaceOptions): InverseSurface {\n const ramp = createColorScale(options.primary, \"light\");\n let best: InverseSurface | null = null;\n let bestMargin = Number.NEGATIVE_INFINITY;\n for (const step of FILL_CANDIDATES) {\n const derived = deriveOver(ramp[step], options);\n const measured = margin(derived.tokens, derived.glow);\n if (measured > bestMargin) {\n best = { tokens: derived.tokens, scheme: derived.scheme, step };\n bestMargin = measured;\n }\n if (measured >= 0) break;\n }\n const surface = best as InverseSurface;\n surface.rules = defaultToneRules(\n Object.keys(surface.tokens),\n options.selector ?? INVERSE_SELECTOR,\n options.page ?? DEFAULT_PAGE_SELECTORS,\n );\n return surface;\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tempest-react-sdk",
3
- "version": "0.74.0",
3
+ "version": "0.76.0",
4
4
  "description": "SDK público da Tempest com componentes, hooks e integrações para projetos React.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -87,6 +87,11 @@
87
87
  "import": "./dist/vision.js",
88
88
  "require": "./dist/vision.cjs"
89
89
  },
90
+ "./neural": {
91
+ "types": "./dist/neural.d.ts",
92
+ "import": "./dist/neural.js",
93
+ "require": "./dist/neural.cjs"
94
+ },
90
95
  "./br": {
91
96
  "types": "./dist/br.d.ts",
92
97
  "import": "./dist/br.js",
@@ -151,6 +156,7 @@
151
156
  "zustand": "^4.0.0 || ^5.0.0"
152
157
  },
153
158
  "peerDependencies": {
159
+ "@sapphi-red/web-noise-suppressor": "^0.4.1",
154
160
  "@tiptap/react": "^2.0.0 || ^3.0.0",
155
161
  "@tiptap/starter-kit": "^2.0.0 || ^3.0.0",
156
162
  "@vitejs/plugin-react": "^4.0.0 || ^5.0.0 || ^6.0.0",
@@ -183,12 +189,16 @@
183
189
  },
184
190
  "onnxruntime-web": {
185
191
  "optional": true
192
+ },
193
+ "@sapphi-red/web-noise-suppressor": {
194
+ "optional": true
186
195
  }
187
196
  },
188
197
  "devDependencies": {
189
198
  "@eslint/js": "^10.0.1",
190
199
  "@microsoft/api-extractor": "^7.58.12",
191
200
  "@playwright/test": "^1.62.0",
201
+ "@sapphi-red/web-noise-suppressor": "^0.4.1",
192
202
  "@size-limit/preset-small-lib": "^13.0.1",
193
203
  "@tanstack/react-query": "^5.90.0",
194
204
  "@testing-library/jest-dom": "^7.0.0",