@heyramzi/ui 2.11.1 → 2.11.2

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 (266) hide show
  1. package/dist/agents/helpers.js +38 -38
  2. package/dist/agents/page-state.js +49 -50
  3. package/dist/agents/vendor/color.js +146 -127
  4. package/dist/agents/vendor/draw.js +617 -508
  5. package/dist/agents/vendor/engine.js +698 -599
  6. package/dist/agents/vendor/mesh.js +653 -683
  7. package/dist/agents/vendor/plastic.js +3913 -3112
  8. package/dist/agents/vendor/presets.js +163 -164
  9. package/dist/agents/vendor/shapes.js +21 -20
  10. package/dist/agents/vendor/ticker.js +41 -42
  11. package/dist/agents/vendor/types.js +1 -0
  12. package/dist/agents/vendor/wear.js +1421 -1448
  13. package/dist/ai/confirmation/confirmation-context.svelte.js +6 -6
  14. package/dist/ai/confirmation/index.js +3 -1
  15. package/dist/ai/index.js +33 -0
  16. package/dist/ai/prompt-input/index.js +3 -1
  17. package/dist/ai/reasoning/index.js +3 -1
  18. package/dist/ai/reasoning/reasoning-context.svelte.js +6 -6
  19. package/dist/ai/suggestion/index.js +3 -1
  20. package/dist/ai/typing-dots/index.js +3 -1
  21. package/dist/animations/text-swap.js +24 -24
  22. package/dist/brand/index.js +54 -48
  23. package/dist/canvas/card/resize.js +5 -3
  24. package/dist/canvas/edges/edge-path.js +255 -242
  25. package/dist/canvas/editor/context-menu.js +39 -36
  26. package/dist/canvas/editor/dispatch.svelte.js +154 -151
  27. package/dist/canvas/editor/editor-context.js +7 -2
  28. package/dist/canvas/editor/editor-mode.js +1 -0
  29. package/dist/canvas/editor/frame.js +73 -76
  30. package/dist/canvas/editor/hand-context.js +5 -2
  31. package/dist/canvas/editor/history-core.js +163 -191
  32. package/dist/canvas/editor/keymap.js +95 -169
  33. package/dist/canvas/editor/layout-actions.js +143 -144
  34. package/dist/canvas/editor/lock.js +52 -51
  35. package/dist/canvas/editor/rebase.js +217 -240
  36. package/dist/canvas/editor/style.js +132 -137
  37. package/dist/canvas/editor/text-field-context.js +7 -2
  38. package/dist/canvas/editor/z-order.js +65 -70
  39. package/dist/canvas/headless/alignment.js +22 -16
  40. package/dist/canvas/headless/break-apart-find.js +286 -279
  41. package/dist/canvas/headless/break-apart-pieces.js +62 -58
  42. package/dist/canvas/headless/break-apart-plan.js +299 -325
  43. package/dist/canvas/headless/break-apart-style.js +75 -70
  44. package/dist/canvas/headless/break-apart.js +188 -181
  45. package/dist/canvas/headless/canvas-cleanup.js +78 -58
  46. package/dist/canvas/headless/edge-anchors.js +115 -116
  47. package/dist/canvas/headless/edge-memo.js +24 -22
  48. package/dist/canvas/headless/edge-serialization.js +17 -27
  49. package/dist/canvas/headless/figure-geometry.js +232 -264
  50. package/dist/canvas/headless/fit-viewport.js +84 -67
  51. package/dist/canvas/headless/grid.js +88 -86
  52. package/dist/canvas/headless/icon-node.js +44 -36
  53. package/dist/canvas/headless/index.js +1 -0
  54. package/dist/canvas/headless/linkify.js +17 -19
  55. package/dist/canvas/headless/pen-marks.js +101 -95
  56. package/dist/canvas/headless/sketch.js +231 -209
  57. package/dist/canvas/headless/snap-guides.js +99 -83
  58. package/dist/canvas/headless/svg-figure.js +133 -117
  59. package/dist/canvas/headless/table-layout.js +146 -107
  60. package/dist/canvas/index.js +2 -0
  61. package/dist/canvas/lod/lod-mode.svelte.js +20 -18
  62. package/dist/canvas/lod/render-all.svelte.js +36 -39
  63. package/dist/canvas/ops/arrange.js +78 -71
  64. package/dist/canvas/ops/ops.js +260 -255
  65. package/dist/canvas/pen/colors.js +37 -35
  66. package/dist/canvas/pen/eraser.js +28 -27
  67. package/dist/canvas/pen/geometry.js +120 -130
  68. package/dist/canvas/pen/index.js +1 -0
  69. package/dist/canvas/pen/ops.js +11 -11
  70. package/dist/canvas/pen/pen-session.js +150 -159
  71. package/dist/canvas/pen/plugin.js +107 -104
  72. package/dist/canvas/pen/shapes.js +73 -68
  73. package/dist/canvas/pen/stroke-path.js +32 -30
  74. package/dist/canvas/pen/types.js +21 -21
  75. package/dist/canvas/pen/ui.js +10 -8
  76. package/dist/canvas/plugin.js +46 -46
  77. package/dist/canvas/screen/glyphs.js +12 -11
  78. package/dist/canvas/screen/labels.js +22 -22
  79. package/dist/canvas/screen/parts.js +98 -111
  80. package/dist/canvas/screen/plugin.js +47 -56
  81. package/dist/canvas/screen/types.js +30 -35
  82. package/dist/canvas/screen/ui.js +7 -7
  83. package/dist/canvas/test-utils.js +14 -14
  84. package/dist/canvas/types.js +1 -0
  85. package/dist/canvas/ui/forward-wheel.js +24 -25
  86. package/dist/canvas/ui/icons.js +64 -131
  87. package/dist/canvas/ui/place-panel.js +58 -49
  88. package/dist/canvas/ui/shortcut-tip.js +14 -12
  89. package/dist/canvas/ui/tools.js +300 -385
  90. package/dist/charts/dashboard/chart.js +4 -0
  91. package/dist/charts/dashboard/data-table.js +11 -0
  92. package/dist/charts/dashboard/windows.js +8 -3
  93. package/dist/charts/edge-fade.js +10 -5
  94. package/dist/charts/hover-band.js +16 -11
  95. package/dist/charts/index.js +0 -1
  96. package/dist/charts/motion.js +11 -7
  97. package/dist/charts/primitives/chart-utils.js +12 -12
  98. package/dist/components/copy/clipboard.js +32 -32
  99. package/dist/components/copy/copied.svelte.js +31 -23
  100. package/dist/components/data-table/data-table.js +39 -39
  101. package/dist/components/docs/index.js +4 -0
  102. package/dist/components/docs/scroll-spy.svelte.js +73 -68
  103. package/dist/components/list-page/filter-section.js +4 -1
  104. package/dist/components/list-page/index.js +2 -0
  105. package/dist/components/list-page/list-table.js +7 -2
  106. package/dist/components/list-page/queue-rail.js +14 -0
  107. package/dist/components/list-page/section-host.js +4 -2
  108. package/dist/components/list-page/step.js +4 -3
  109. package/dist/components/list-page/types.js +1 -0
  110. package/dist/components/picker/trigger.js +48 -30
  111. package/dist/components/picker/types.js +1 -0
  112. package/dist/components/segmented/collapse.js +38 -27
  113. package/dist/components/segmented/index.js +8 -0
  114. package/dist/components/segmented/segmented.js +67 -42
  115. package/dist/components/star-rating-input/index.js +3 -1
  116. package/dist/components/table-view/types.js +1 -0
  117. package/dist/components/tags-input/tags.js +81 -69
  118. package/dist/components/theme/index.js +4 -0
  119. package/dist/components/toolbar/index.js +4 -0
  120. package/dist/components/toolbar/toolbar-trigger.js +14 -1
  121. package/dist/editor/anchors.js +17 -13
  122. package/dist/editor/block-id.js +52 -51
  123. package/dist/editor/block-ops.js +108 -80
  124. package/dist/editor/doc-blocks.js +155 -166
  125. package/dist/editor/extensions.js +139 -180
  126. package/dist/editor/index.js +4 -0
  127. package/dist/editor/markdown-test-helpers.js +4 -2
  128. package/dist/editor/markdown.js +420 -408
  129. package/dist/editor/serializer.js +204 -200
  130. package/dist/editor/slash-items.js +89 -101
  131. package/dist/editor/youtube-url.js +25 -20
  132. package/dist/effects/animated-beam/path-calculator.svelte.js +43 -38
  133. package/dist/effects/animated-beam/types.js +1 -0
  134. package/dist/effects/border-beam/css.js +92 -78
  135. package/dist/effects/border-beam/presets.js +1705 -1720
  136. package/dist/effects/border-beam/register-properties.js +43 -33
  137. package/dist/effects/border-beam/types.js +1 -0
  138. package/dist/effects/image-comparison/compare.js +3 -2
  139. package/dist/effects/image-reveal/types.js +1 -0
  140. package/dist/effects/magnetic/magnetic.js +58 -52
  141. package/dist/effects/reveal/observe.js +50 -40
  142. package/dist/effects/reveal/types.js +1 -0
  143. package/dist/effects/shader-gradient/color.js +36 -29
  144. package/dist/effects/shader-gradient/renderer.js +384 -295
  145. package/dist/effects/shader-gradient/shaders.js +31 -0
  146. package/dist/effects/shader-gradient/types.js +1 -0
  147. package/dist/icons/apple-symbol-exports.js +99 -124
  148. package/dist/icons/sf-symbols.js +357 -461
  149. package/dist/icons/trades.js +43 -28
  150. package/dist/inbox/index.js +1 -0
  151. package/dist/inbox/logic.js +126 -122
  152. package/dist/inbox/types.js +43 -43
  153. package/dist/lib/arrive.js +19 -12
  154. package/dist/lib/icon-types.js +1 -0
  155. package/dist/lib/initials.js +16 -10
  156. package/dist/lib/layout.js +5 -0
  157. package/dist/lib/panel.js +13 -0
  158. package/dist/lib/result.js +22 -22
  159. package/dist/lib/sliding-pill.js +59 -44
  160. package/dist/lib/theme-transition.js +43 -43
  161. package/dist/lib/tone.js +31 -24
  162. package/dist/lib/utils.js +3 -1
  163. package/dist/onboarding/define-tours.js +24 -23
  164. package/dist/onboarding/onboarding.svelte.js +16 -12
  165. package/dist/onboarding/pick.js +10 -6
  166. package/dist/onboarding/stores.js +40 -41
  167. package/dist/onboarding/wait.js +24 -23
  168. package/dist/panel/side-panel-types.js +1 -0
  169. package/dist/record/demo-data.js +459 -486
  170. package/dist/record/fields.js +129 -131
  171. package/dist/record/format.js +70 -82
  172. package/dist/record/gutter.js +1 -0
  173. package/dist/record/kinds.js +95 -105
  174. package/dist/record/logic.js +238 -219
  175. package/dist/record/types.js +49 -48
  176. package/dist/shadcn/accordion/index.js +3 -1
  177. package/dist/shadcn/alert/index.js +3 -1
  178. package/dist/shadcn/alert-dialog/index.js +3 -1
  179. package/dist/shadcn/attachment/index.js +3 -1
  180. package/dist/shadcn/avatar/index.js +3 -1
  181. package/dist/shadcn/breadcrumb/index.js +3 -1
  182. package/dist/shadcn/bubble/index.js +3 -1
  183. package/dist/shadcn/button/index.js +3 -1
  184. package/dist/shadcn/calendar/index.js +3 -1
  185. package/dist/shadcn/card/index.js +3 -1
  186. package/dist/shadcn/checkbox/index.js +3 -1
  187. package/dist/shadcn/code-block/index.js +3 -1
  188. package/dist/shadcn/collapsible/index.js +3 -1
  189. package/dist/shadcn/command/index.js +4 -1
  190. package/dist/shadcn/context-menu/index.js +3 -1
  191. package/dist/shadcn/dialog/index.js +3 -1
  192. package/dist/shadcn/dropdown-menu/menu-item.js +40 -20
  193. package/dist/shadcn/empty/index.js +3 -1
  194. package/dist/shadcn/field/index.js +3 -1
  195. package/dist/shadcn/hooks/highlighter.js +77 -75
  196. package/dist/shadcn/hooks/is-mobile.svelte.js +3 -3
  197. package/dist/shadcn/hooks/use-highlighted-code.svelte.js +62 -62
  198. package/dist/shadcn/input/index.js +3 -1
  199. package/dist/shadcn/kbd/index.js +3 -1
  200. package/dist/shadcn/label/index.js +3 -1
  201. package/dist/shadcn/marker/index.js +3 -1
  202. package/dist/shadcn/message/index.js +3 -1
  203. package/dist/shadcn/message-scroller/index.js +3 -1
  204. package/dist/shadcn/popover/index.js +3 -1
  205. package/dist/shadcn/progress/index.js +3 -1
  206. package/dist/shadcn/progress/tone.js +8 -7
  207. package/dist/shadcn/radio-group/index.js +3 -1
  208. package/dist/shadcn/scroll-area/index.js +3 -1
  209. package/dist/shadcn/select/index.js +3 -1
  210. package/dist/shadcn/separator/index.js +3 -1
  211. package/dist/shadcn/sheet/index.js +3 -1
  212. package/dist/shadcn/sidebar/context.svelte.js +42 -28
  213. package/dist/shadcn/sidebar/index.js +3 -1
  214. package/dist/shadcn/skeleton/index.js +3 -1
  215. package/dist/shadcn/slider/index.js +3 -1
  216. package/dist/shadcn/switch/index.js +3 -1
  217. package/dist/shadcn/table/index.js +3 -1
  218. package/dist/shadcn/tabs/index.js +3 -1
  219. package/dist/shadcn/textarea/index.js +3 -1
  220. package/dist/shadcn/toggle/index.js +3 -1
  221. package/dist/shadcn/toggle-group/index.js +3 -1
  222. package/dist/shadcn/tooltip/context.js +7 -2
  223. package/dist/shadcn/tooltip/index.js +3 -1
  224. package/dist/shadcn/trace/index.js +3 -1
  225. package/dist/slides/bridges.js +65 -59
  226. package/dist/slides/deck-controller.svelte.js +210 -207
  227. package/dist/slides/export/capture.js +66 -71
  228. package/dist/slides/export/ffmpeg.js +76 -72
  229. package/dist/slides/export/index.js +3 -0
  230. package/dist/slides/export/launch.js +9 -6
  231. package/dist/slides/export/pdf.js +60 -54
  232. package/dist/slides/export/types.js +1 -0
  233. package/dist/slides/labels.js +24 -24
  234. package/dist/slides/layout.js +39 -41
  235. package/dist/slides/model.js +9 -7
  236. package/dist/slides/navigation.js +78 -73
  237. package/dist/slides/types.js +2 -2
  238. package/dist/status/define-statuses.js +18 -14
  239. package/dist/status/status-types.js +1 -0
  240. package/dist/test-setup.js +24 -20
  241. package/dist/thread/logic.js +73 -77
  242. package/dist/thread/types.js +21 -21
  243. package/dist/work/board-order.js +94 -90
  244. package/dist/work/dates.js +16 -9
  245. package/dist/work/detail/detail-types.js +18 -18
  246. package/dist/work/docs/edited.js +32 -29
  247. package/dist/work/docs/index.js +4 -0
  248. package/dist/work/docs/labels.js +34 -34
  249. package/dist/work/docs/menu.js +113 -106
  250. package/dist/work/docs/outline.js +39 -29
  251. package/dist/work/gantt/logic.js +211 -235
  252. package/dist/work/inbox/inbox-logic.js +71 -75
  253. package/dist/work/inbox/inbox-statuses.js +75 -72
  254. package/dist/work/inbox/inbox-types.js +1 -0
  255. package/dist/work/kanban-drag.js +27 -22
  256. package/dist/work/kanban-types.js +1 -0
  257. package/dist/work/presets/sales.js +36 -32
  258. package/dist/work/reorder.js +9 -8
  259. package/dist/work/task-types.js +1 -0
  260. package/dist/work/time/duration.js +51 -46
  261. package/dist/work/time/time-types.js +23 -23
  262. package/dist/work/use-kanban-dnd.svelte.js +126 -125
  263. package/package.json +3 -1
  264. package/src/components/list-page/master-detail.svelte +3 -1
  265. package/src/components/list-page/rail-row.svelte +4 -4
  266. package/src/editor/markdown.ts +30 -35
@@ -1,52 +1,52 @@
1
+ /* Pure helpers for the avatar: numbers, theme, lights, idle scheduling. */
1
2
  import { DARK_INK, LIGHT_INK, luminance } from "./vendor/color.js";
2
3
  import { stockLights } from "./vendor/plastic.js";
3
- const contrast = (a, b)=>(Math.max(a, b) + 0.05) / (Math.min(a, b) + 0.05);
4
+ const contrast = (a, b) => (Math.max(a, b) + .05) / (Math.min(a, b) + .05);
5
+ /** Off-black or off-white eyes, whichever reads stronger on the body: the vendor's fixed cutoff left 2:1 eyes on mid blues. */
4
6
  export function inkFor(body) {
5
- const l = luminance(body);
6
- return contrast(l, luminance(DARK_INK)) >= contrast(l, luminance(LIGHT_INK)) ? DARK_INK : LIGHT_INK;
7
+ const l = luminance(body);
8
+ return contrast(l, luminance(DARK_INK)) >= contrast(l, luminance(LIGHT_INK)) ? DARK_INK : LIGHT_INK;
7
9
  }
8
- export const clamp = (v, lo, hi)=>Math.min(hi, Math.max(lo, Number.isFinite(v) ? v : 1));
9
- export const q = (v, lo, hi)=>Math.round(clamp(v, lo, hi) * 20) / 20;
10
- export const clampOpt = (v, d, lo, hi)=>clamp(v ?? d, lo, hi);
11
- export const deviceDpr = ()=>Math.min(2, typeof devicePixelRatio === "number" && devicePixelRatio || 1);
10
+ export const clamp = (v, lo, hi) => Math.min(hi, Math.max(lo, Number.isFinite(v) ? v : 1));
11
+ export const q = (v, lo, hi) => Math.round(clamp(v, lo, hi) * 20) / 20;
12
+ export const clampOpt = (v, d, lo, hi) => clamp(v ?? d, lo, hi);
13
+ export const deviceDpr = () => Math.min(2, typeof devicePixelRatio === "number" && devicePixelRatio || 1);
12
14
  export function hashSeed(id) {
13
- let h = 2166136261;
14
- for(let i = 0; i < id.length; i++)h = Math.imul(h ^ id.charCodeAt(i), 16777619);
15
- return (h >>> 0) % 1000 / 1000;
15
+ let h = 2166136261;
16
+ for (let i = 0; i < id.length; i++) h = Math.imul(h ^ id.charCodeAt(i), 16777619);
17
+ return (h >>> 0) % 1e3 / 1e3;
16
18
  }
17
- export const reducedMotion = ()=>typeof matchMedia === "function" && matchMedia("(prefers-reduced-motion: reduce)").matches;
19
+ export const reducedMotion = () => typeof matchMedia === "function" && matchMedia("(prefers-reduced-motion: reduce)").matches;
18
20
  export function resolveTheme(theme, el) {
19
- if (theme !== "auto") return theme;
20
- const host = el?.closest("[data-theme], .dark, .light");
21
- if (host) {
22
- const v = host.getAttribute("data-theme");
23
- if (v === "dark" || v === "light") return v;
24
- if (host.classList.contains("dark")) return "dark";
25
- if (host.classList.contains("light")) return "light";
26
- }
27
- return typeof matchMedia === "function" && matchMedia("(prefers-color-scheme: light)").matches ? "light" : "dark";
21
+ if (theme !== "auto") return theme;
22
+ const host = el?.closest("[data-theme], .dark, .light");
23
+ if (host) {
24
+ const v = host.getAttribute("data-theme");
25
+ if (v === "dark" || v === "light") return v;
26
+ if (host.classList.contains("dark")) return "dark";
27
+ if (host.classList.contains("light")) return "light";
28
+ }
29
+ return typeof matchMedia === "function" && matchMedia("(prefers-color-scheme: light)").matches ? "light" : "dark";
28
30
  }
29
31
  export function lightsFor(lightAt, backLight, lightFront) {
30
- const a = lightAt * Math.PI / 180;
31
- const b = (backLight ?? 0) * Math.PI / 180;
32
- const lights = stockLights(Math.sin(a), -Math.cos(a));
33
- if (backLight !== undefined) [lights.bx, lights.by] = [
34
- Math.sin(b),
35
- -Math.cos(b)
36
- ];
37
- if (lightFront !== undefined) lights.front = Math.min(85, Math.max(0, lightFront)) * Math.PI / 180;
38
- return lights;
32
+ const a = lightAt * Math.PI / 180;
33
+ const b = (backLight ?? 0) * Math.PI / 180;
34
+ const lights = stockLights(Math.sin(a), -Math.cos(a));
35
+ if (backLight !== undefined) [lights.bx, lights.by] = [Math.sin(b), -Math.cos(b)];
36
+ if (lightFront !== undefined) lights.front = Math.min(85, Math.max(0, lightFront)) * Math.PI / 180;
37
+ return lights;
39
38
  }
40
39
  export function warmIdle(fn) {
41
- if (typeof requestIdleCallback === "function") {
42
- const id = requestIdleCallback(fn);
43
- return ()=>cancelIdleCallback(id);
44
- }
45
- const id = setTimeout(fn, 1);
46
- return ()=>clearTimeout(id);
40
+ if (typeof requestIdleCallback === "function") {
41
+ const id = requestIdleCallback(fn);
42
+ return () => cancelIdleCallback(id);
43
+ }
44
+ const id = setTimeout(fn, 1);
45
+ return () => clearTimeout(id);
47
46
  }
47
+ /* Full pull up close, fading to nothing by 3 head widths. */
48
48
  export function pointerStrength(d) {
49
- if (d < 1) return 1;
50
- if (d > 3) return 0;
51
- return 1 - (d - 1) / 2;
49
+ if (d < 1) return 1;
50
+ if (d > 3) return 0;
51
+ return 1 - (d - 1) / 2;
52
52
  }
@@ -1,65 +1,64 @@
1
+ /* What every avatar on the page shares: the batching shown-gate, so a row of
2
+ them comes in together, the path caches, and one theme watcher. */
1
3
  import { bakesPending } from "./vendor/plastic.js";
2
- export const SHOW_WITHIN = 4000;
4
+ export const SHOW_WITHIN = 4e3;
3
5
  export const waiters = new Map();
4
6
  export function showReady() {
5
- if (bakesPending()) return;
6
- for (const w of waiters.values())if (!w.ready()) return;
7
- const all = [
8
- ...waiters.values()
9
- ];
10
- waiters.clear();
11
- for (const w of all)w.show();
7
+ if (bakesPending()) return;
8
+ for (const w of waiters.values()) if (!w.ready()) return;
9
+ const all = [...waiters.values()];
10
+ waiters.clear();
11
+ for (const w of all) w.show();
12
12
  }
13
13
  const pathCache = new Map();
14
14
  export function bodyPath(d) {
15
- let p = pathCache.get(d);
16
- if (!p) {
17
- p = new Path2D(d);
18
- pathCache.set(d, p);
19
- }
20
- return p;
15
+ let p = pathCache.get(d);
16
+ if (!p) {
17
+ p = new Path2D(d);
18
+ pathCache.set(d, p);
19
+ }
20
+ return p;
21
21
  }
22
22
  const partsCache = new Map();
23
23
  export function partPaths(d) {
24
- let p = partsCache.get(d);
25
- if (!p) {
26
- p = d.split(/(?=M)/).filter((s)=>s.trim()).map((s)=>new Path2D(s));
27
- partsCache.set(d, p);
28
- }
29
- return p;
24
+ let p = partsCache.get(d);
25
+ if (!p) {
26
+ p = d.split(/(?=M)/).filter((s) => s.trim()).map((s) => new Path2D(s));
27
+ partsCache.set(d, p);
28
+ }
29
+ return p;
30
30
  }
31
31
  let uidSeq = 0;
32
- export const nextUid = ()=>`ba-${++uidSeq}`;
32
+ export const nextUid = () => `ba-${++uidSeq}`;
33
+ /* One observer for the whole page: a `.dark` or `data-theme` flip on
34
+ <html> or <body>, or the OS scheme changing, repaints every auto avatar. */
33
35
  const themeListeners = new Set();
34
36
  let themeWatch = null;
35
37
  export function onThemeChange(fn) {
36
- themeListeners.add(fn);
37
- if (!themeWatch && typeof MutationObserver === "function" && typeof document !== "undefined") {
38
- const fire = ()=>{
39
- for (const l of themeListeners)l();
40
- };
41
- const mo = new MutationObserver(fire);
42
- const opts = {
43
- attributes: true,
44
- attributeFilter: [
45
- "class",
46
- "data-theme"
47
- ]
48
- };
49
- mo.observe(document.documentElement, opts);
50
- if (document.body) mo.observe(document.body, opts);
51
- const mq = typeof matchMedia === "function" ? matchMedia("(prefers-color-scheme: dark)") : null;
52
- mq?.addEventListener("change", fire);
53
- themeWatch = ()=>{
54
- mo.disconnect();
55
- mq?.removeEventListener("change", fire);
56
- };
57
- }
58
- return ()=>{
59
- themeListeners.delete(fn);
60
- if (themeListeners.size === 0 && themeWatch) {
61
- themeWatch();
62
- themeWatch = null;
63
- }
64
- };
38
+ themeListeners.add(fn);
39
+ if (!themeWatch && typeof MutationObserver === "function" && typeof document !== "undefined") {
40
+ const fire = () => {
41
+ for (const l of themeListeners) l();
42
+ };
43
+ const mo = new MutationObserver(fire);
44
+ const opts = {
45
+ attributes: true,
46
+ attributeFilter: ["class", "data-theme"]
47
+ };
48
+ mo.observe(document.documentElement, opts);
49
+ if (document.body) mo.observe(document.body, opts);
50
+ const mq = typeof matchMedia === "function" ? matchMedia("(prefers-color-scheme: dark)") : null;
51
+ mq?.addEventListener("change", fire);
52
+ themeWatch = () => {
53
+ mo.disconnect();
54
+ mq?.removeEventListener("change", fire);
55
+ };
56
+ }
57
+ return () => {
58
+ themeListeners.delete(fn);
59
+ if (themeListeners.size === 0 && themeWatch) {
60
+ themeWatch();
61
+ themeWatch = null;
62
+ }
63
+ };
65
64
  }
@@ -1,149 +1,168 @@
1
+ // @ts-nocheck WHY: vendored engine, kept as upstream wrote it so a re-sync stays a clean diff. Strict flags in consumers (review) would flag ~870 spots.
2
+ /** Parse #rgb / #rrggbb / rgb() / hsl() into 0–255 channels; null for anything else. */
1
3
  export function parseColor(input) {
2
- const s = input.trim();
3
- const hsl = s.match(/^hsla?\(\s*([\d.]+)(?:deg)?[,\s]+([\d.]+)%[,\s]+([\d.]+)%/i);
4
- if (hsl) return hslToRgb([
5
- Number(hsl[1]) / 360,
6
- Number(hsl[2]) / 100,
7
- Number(hsl[3]) / 100
8
- ]);
9
- const hex = s.match(/^#([0-9a-f]{3}|[0-9a-f]{6})$/i);
10
- if (hex) {
11
- let h = hex[1];
12
- if (h.length === 3) h = h.split("").map((c)=>c + c).join("");
13
- const n = parseInt(h, 16);
14
- return [
15
- n >> 16 & 255,
16
- n >> 8 & 255,
17
- n & 255
18
- ];
19
- }
20
- const rgb = s.match(/^rgba?\(\s*([\d.]+)[,\s]+([\d.]+)[,\s]+([\d.]+)/i);
21
- if (rgb) return [
22
- Number(rgb[1]),
23
- Number(rgb[2]),
24
- Number(rgb[3])
25
- ];
26
- return null;
4
+ const s = input.trim();
5
+ const hsl = s.match(/^hsla?\(\s*([\d.]+)(?:deg)?[,\s]+([\d.]+)%[,\s]+([\d.]+)%/i);
6
+ if (hsl) return hslToRgb([
7
+ Number(hsl[1]) / 360,
8
+ Number(hsl[2]) / 100,
9
+ Number(hsl[3]) / 100
10
+ ]);
11
+ const hex = s.match(/^#([0-9a-f]{3}|[0-9a-f]{6})$/i);
12
+ if (hex) {
13
+ let h = hex[1];
14
+ if (h.length === 3) h = h.split("").map((c) => c + c).join("");
15
+ const n = parseInt(h, 16);
16
+ return [
17
+ n >> 16 & 255,
18
+ n >> 8 & 255,
19
+ n & 255
20
+ ];
21
+ }
22
+ const rgb = s.match(/^rgba?\(\s*([\d.]+)[,\s]+([\d.]+)[,\s]+([\d.]+)/i);
23
+ if (rgb) return [
24
+ Number(rgb[1]),
25
+ Number(rgb[2]),
26
+ Number(rgb[3])
27
+ ];
28
+ return null;
27
29
  }
30
+ /** Relative luminance (WCAG), 0–1. Unparseable colours count as mid-grey. */
28
31
  export function luminance(color) {
29
- const c = parseColor(color);
30
- if (!c) return 0.5;
31
- const lin = (v)=>{
32
- const x = v / 255;
33
- return x <= 0.03928 ? x / 12.92 : ((x + 0.055) / 1.055) ** 2.4;
34
- };
35
- return 0.2126 * lin(c[0]) + 0.7152 * lin(c[1]) + 0.0722 * lin(c[2]);
32
+ const c = parseColor(color);
33
+ if (!c) return .5;
34
+ const lin = (v) => {
35
+ const x = v / 255;
36
+ return x <= .03928 ? x / 12.92 : ((x + .055) / 1.055) ** 2.4;
37
+ };
38
+ return .2126 * lin(c[0]) + .7152 * lin(c[1]) + .0722 * lin(c[2]);
36
39
  }
37
40
  export const DARK_INK = "#1E1A33";
38
41
  export const LIGHT_INK = "#F7F5F2";
42
+ /** Face ink for a body colour: dark ink, or light ink on a dark body. */
39
43
  export function autoInk(color) {
40
- return luminance(color) < 0.13 ? LIGHT_INK : DARK_INK;
44
+ return luminance(color) < .13 ? LIGHT_INK : DARK_INK;
41
45
  }
46
+ /* ── HSL, for the body's shades ─────────────────────────────────────── */
42
47
  function rgbToHsl([r, g, b]) {
43
- r /= 255;
44
- g /= 255;
45
- b /= 255;
46
- const max = Math.max(r, g, b), min = Math.min(r, g, b);
47
- const l = (max + min) / 2;
48
- if (max === min) return [
49
- 0,
50
- 0,
51
- l
52
- ];
53
- const d = max - min;
54
- const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
55
- let h = 0;
56
- if (max === r) h = (g - b) / d + (g < b ? 6 : 0);
57
- else if (max === g) h = (b - r) / d + 2;
58
- else h = (r - g) / d + 4;
59
- return [
60
- h / 6,
61
- s,
62
- l
63
- ];
48
+ r /= 255;
49
+ g /= 255;
50
+ b /= 255;
51
+ const max = Math.max(r, g, b), min = Math.min(r, g, b);
52
+ const l = (max + min) / 2;
53
+ if (max === min) return [
54
+ 0,
55
+ 0,
56
+ l
57
+ ];
58
+ const d = max - min;
59
+ const s = l > .5 ? d / (2 - max - min) : d / (max + min);
60
+ let h = 0;
61
+ if (max === r) h = (g - b) / d + (g < b ? 6 : 0);
62
+ else if (max === g) h = (b - r) / d + 2;
63
+ else h = (r - g) / d + 4;
64
+ return [
65
+ h / 6,
66
+ s,
67
+ l
68
+ ];
64
69
  }
65
70
  function hslToRgb([h, s, l]) {
66
- if (s === 0) return [
67
- l * 255,
68
- l * 255,
69
- l * 255
70
- ];
71
- const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
72
- const p = 2 * l - q;
73
- const f = (t)=>{
74
- t = (t % 1 + 1) % 1;
75
- if (t < 1 / 6) return p + (q - p) * 6 * t;
76
- if (t < 1 / 2) return q;
77
- if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
78
- return p;
79
- };
80
- return [
81
- f(h + 1 / 3) * 255,
82
- f(h) * 255,
83
- f(h - 1 / 3) * 255
84
- ];
71
+ if (s === 0) return [
72
+ l * 255,
73
+ l * 255,
74
+ l * 255
75
+ ];
76
+ const q = l < .5 ? l * (1 + s) : l + s - l * s;
77
+ const p = 2 * l - q;
78
+ const f = (t) => {
79
+ t = (t % 1 + 1) % 1;
80
+ if (t < 1 / 6) return p + (q - p) * 6 * t;
81
+ if (t < 1 / 2) return q;
82
+ if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
83
+ return p;
84
+ };
85
+ return [
86
+ f(h + 1 / 3) * 255,
87
+ f(h) * 255,
88
+ f(h - 1 / 3) * 255
89
+ ];
85
90
  }
86
91
  function hslToCss([h, s, l]) {
87
- return `hsl(${(h * 360).toFixed(1)} ${(s * 100).toFixed(1)}% ${(l * 100).toFixed(1)}%)`;
92
+ return `hsl(${(h * 360).toFixed(1)} ${(s * 100).toFixed(1)}% ${(l * 100).toFixed(1)}%)`;
88
93
  }
89
- const clamp01 = (v)=>Math.min(1, Math.max(0, v));
94
+ const clamp01 = (v) => Math.min(1, Math.max(0, v));
95
+ /**
96
+ * A shade of a colour: `dl` moves the lightness (−1..1), `ds` the
97
+ * saturation. Darker shades get a touch more saturation so they stay
98
+ * rich instead of going grey, the way a painted surface falls into shadow.
99
+ */
90
100
  export function shade(color, dl, ds = 0) {
91
- const c = parseColor(color);
92
- if (!c) return color;
93
- const [h, s, l] = rgbToHsl(c);
94
- return hslToCss([
95
- h,
96
- clamp01(s + ds + (dl < 0 ? -dl * 0.25 : 0)),
97
- clamp01(l + dl)
98
- ]);
101
+ const c = parseColor(color);
102
+ if (!c) return color;
103
+ const [h, s, l] = rgbToHsl(c);
104
+ return hslToCss([
105
+ h,
106
+ clamp01(s + ds + (dl < 0 ? -dl * .25 : 0)),
107
+ clamp01(l + dl)
108
+ ]);
99
109
  }
100
- const toLinear = (u)=>u <= 0.04045 ? u / 12.92 : Math.pow((u + 0.055) / 1.055, 2.4);
101
- const toSrgb = (u)=>u <= 0.0031308 ? 12.92 * u : 1.055 * Math.pow(u, 1 / 2.4) - 0.055;
110
+ /* OKLab, for moving a colour along its own hue (Björn Ottosson's) */
111
+ const toLinear = (u) => u <= .04045 ? u / 12.92 : Math.pow((u + .055) / 1.055, 2.4);
112
+ const toSrgb = (u) => u <= .0031308 ? 12.92 * u : 1.055 * Math.pow(u, 1 / 2.4) - .055;
102
113
  function oklab(r, g, b) {
103
- const l = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b);
104
- const m = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b);
105
- const s = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b);
106
- return [
107
- 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s,
108
- 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s,
109
- 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s
110
- ];
114
+ const l = Math.cbrt(.4122214708 * r + .5363325363 * g + .0514459929 * b);
115
+ const m = Math.cbrt(.2119034982 * r + .6806995451 * g + .1073969566 * b);
116
+ const s = Math.cbrt(.0883024619 * r + .2817188376 * g + .6299787005 * b);
117
+ return [
118
+ .2104542553 * l + .793617785 * m - .0040720468 * s,
119
+ 1.9779984951 * l - 2.428592205 * m + .4505937099 * s,
120
+ .0259040371 * l + .7827717662 * m - .808675766 * s
121
+ ];
111
122
  }
112
123
  function fromOklab(L, a, b) {
113
- const l = Math.pow(L + 0.3963377774 * a + 0.2158037573 * b, 3);
114
- const m = Math.pow(L - 0.1055613458 * a - 0.0638541728 * b, 3);
115
- const s = Math.pow(L - 0.0894841775 * a - 1.291485548 * b, 3);
116
- return [
117
- 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,
118
- -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,
119
- -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s
120
- ];
124
+ const l = Math.pow(L + .3963377774 * a + .2158037573 * b, 3);
125
+ const m = Math.pow(L - .1055613458 * a - .0638541728 * b, 3);
126
+ const s = Math.pow(L - .0894841775 * a - 1.291485548 * b, 3);
127
+ return [
128
+ 4.0767416621 * l - 3.3077115913 * m + .2309699292 * s,
129
+ -1.2684380046 * l + 2.6097574011 * m - .3413193965 * s,
130
+ -.0041960863 * l - .7034186147 * m + 1.707614701 * s
131
+ ];
121
132
  }
122
- const inGamut = (c)=>c.every((v)=>v >= -1e-4 && v <= 1 + 1e-4);
133
+ const inGamut = (c) => c.every((v) => v >= -1e-4 && v <= 1 + 1e-4);
134
+ /** A more vivid version of a colour, `t` 0–1: its chroma raised along its
135
+ own hue (in OKLab) by up to half again. Where the screen cannot show that
136
+ at the same lightness, the colour deepens a little — by at most 15% of
137
+ its lightness — toward the hue's most vivid shade (a sky blue toward a
138
+ royal one), and the chroma stops at whatever the screen can show. */
123
139
  export function richer(color, t) {
124
- const c = parseColor(color);
125
- if (!c || !(t > 0)) return color;
126
- const [L, a, b] = oklab(toLinear(c[0] / 255), toLinear(c[1] / 255), toLinear(c[2] / 255));
127
- const C = Math.hypot(a, b);
128
- if (C < 1e-4) return color;
129
- const ua = a / C, ub = b / C;
130
- const want = C * (1 + 0.5 * t);
131
- let best = null, bestC = C;
132
- for(let k = 0; k <= 6; k++){
133
- const Lk = L * (1 - 0.15 * t * k / 6);
134
- let lo = 0, hi = want;
135
- for(let it = 0; it < 18; it++){
136
- const mid = (lo + hi) / 2;
137
- if (inGamut(fromOklab(Lk, ua * mid, ub * mid))) lo = mid;
138
- else hi = mid;
139
- }
140
- if (lo > bestC + 0.004 * k) {
141
- bestC = lo;
142
- best = fromOklab(Lk, ua * lo, ub * lo);
143
- }
144
- if (lo >= want - 1e-4) break;
145
- }
146
- if (!best) return color;
147
- const out = best.map((v)=>Math.round(255 * toSrgb(Math.min(1, Math.max(0, v)))));
148
- return `rgb(${out[0]} ${out[1]} ${out[2]})`;
140
+ const c = parseColor(color);
141
+ if (!c || !(t > 0)) return color;
142
+ const [L, a, b] = oklab(toLinear(c[0] / 255), toLinear(c[1] / 255), toLinear(c[2] / 255));
143
+ const C = Math.hypot(a, b);
144
+ if (C < 1e-4) return color;
145
+ const ua = a / C, ub = b / C;
146
+ const want = C * (1 + .5 * t);
147
+ let best = null, bestC = C;
148
+ /* the lightness from the colour's own down to 15% deeper, in steps; at
149
+ each, the most chroma the screen shows up to `want` */
150
+ for (let k = 0; k <= 6; k++) {
151
+ const Lk = L * (1 - .15 * t * k / 6);
152
+ let lo = 0, hi = want;
153
+ for (let it = 0; it < 18; it++) {
154
+ const mid = (lo + hi) / 2;
155
+ if (inGamut(fromOklab(Lk, ua * mid, ub * mid))) lo = mid;
156
+ else hi = mid;
157
+ }
158
+ /* deeper only for what it gains: each step must buy real chroma */
159
+ if (lo > bestC + .004 * k) {
160
+ bestC = lo;
161
+ best = fromOklab(Lk, ua * lo, ub * lo);
162
+ }
163
+ if (lo >= want - 1e-4) break;
164
+ }
165
+ if (!best) return color;
166
+ const out = best.map((v) => Math.round(255 * toSrgb(Math.min(1, Math.max(0, v)))));
167
+ return `rgb(${out[0]} ${out[1]} ${out[2]})`;
149
168
  }