@nadicodeai/ui 9.2.0 → 10.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 (216) hide show
  1. package/AGENTS.md +1 -0
  2. package/README.md +5 -5
  3. package/dist/agent-orb.d.ts +3 -0
  4. package/dist/agent-orb.d.ts.map +1 -0
  5. package/dist/agent-orb.js +2 -0
  6. package/dist/assets/brand/aionlabs.svg +2 -0
  7. package/dist/assets/brand/airtable.svg +2 -0
  8. package/dist/assets/brand/apple.svg +2 -0
  9. package/dist/assets/brand/arcee.svg +2 -0
  10. package/dist/assets/brand/asana.svg +2 -0
  11. package/dist/assets/brand/atlassian.svg +2 -0
  12. package/dist/assets/brand/baidu.svg +2 -0
  13. package/dist/assets/brand/bytedance.svg +2 -0
  14. package/dist/assets/brand/claude.svg +2 -0
  15. package/dist/assets/brand/cohere.svg +2 -0
  16. package/dist/assets/brand/datadog.svg +2 -0
  17. package/dist/assets/brand/deepseek.svg +2 -0
  18. package/dist/assets/brand/discord.svg +2 -0
  19. package/dist/assets/brand/dolphin.svg +2 -0
  20. package/dist/assets/brand/dotsstudio.svg +2 -0
  21. package/dist/assets/brand/figma.svg +2 -0
  22. package/dist/assets/brand/gemini.svg +2 -0
  23. package/dist/assets/brand/github.svg +2 -0
  24. package/dist/assets/brand/gitlab.svg +2 -0
  25. package/dist/assets/brand/gmail.svg +2 -0
  26. package/dist/assets/brand/google-calendar.svg +2 -0
  27. package/dist/assets/brand/google-drive.svg +2 -0
  28. package/dist/assets/brand/grok.svg +2 -0
  29. package/dist/assets/brand/huggingface.svg +2 -0
  30. package/dist/assets/brand/ibm.svg +2 -0
  31. package/dist/assets/brand/inception.svg +2 -0
  32. package/dist/assets/brand/inclusionai.svg +2 -0
  33. package/dist/assets/brand/index.json +778 -0
  34. package/dist/assets/brand/inference.svg +2 -0
  35. package/dist/assets/brand/intercom.svg +2 -0
  36. package/dist/assets/brand/jira.svg +2 -0
  37. package/dist/assets/brand/kwaipilot.svg +2 -0
  38. package/dist/assets/brand/linear.svg +2 -0
  39. package/dist/assets/brand/linux.svg +2 -0
  40. package/dist/assets/brand/liquid.svg +2 -0
  41. package/dist/assets/brand/longcat.svg +2 -0
  42. package/dist/assets/brand/mattermost.svg +2 -0
  43. package/dist/assets/brand/meta.svg +2 -0
  44. package/dist/assets/brand/microsoft.svg +2 -0
  45. package/dist/assets/brand/minimax.svg +2 -0
  46. package/dist/assets/brand/mistral.svg +2 -0
  47. package/dist/assets/brand/moonshot.svg +2 -0
  48. package/dist/assets/brand/morph.svg +2 -0
  49. package/dist/assets/brand/n8n.svg +2 -0
  50. package/dist/assets/brand/netlify.svg +2 -0
  51. package/dist/assets/brand/nexagi.svg +2 -0
  52. package/dist/assets/brand/notion.svg +2 -0
  53. package/dist/assets/brand/nousresearch.svg +2 -0
  54. package/dist/assets/brand/nova.svg +2 -0
  55. package/dist/assets/brand/nvidia.svg +2 -0
  56. package/dist/assets/brand/openai.svg +2 -0
  57. package/dist/assets/brand/openrouter.svg +2 -0
  58. package/dist/assets/brand/paypal.svg +2 -0
  59. package/dist/assets/brand/perceptron.svg +2 -0
  60. package/dist/assets/brand/perplexity.svg +2 -0
  61. package/dist/assets/brand/poolside.svg +2 -0
  62. package/dist/assets/brand/postgresql.svg +2 -0
  63. package/dist/assets/brand/qwen.svg +2 -0
  64. package/dist/assets/brand/reka.svg +2 -0
  65. package/dist/assets/brand/relace.svg +2 -0
  66. package/dist/assets/brand/sakana.svg +2 -0
  67. package/dist/assets/brand/sentry.svg +2 -0
  68. package/dist/assets/brand/signal.svg +2 -0
  69. package/dist/assets/brand/slack.svg +2 -0
  70. package/dist/assets/brand/spotify.svg +2 -0
  71. package/dist/assets/brand/square.svg +2 -0
  72. package/dist/assets/brand/stepfun.svg +2 -0
  73. package/dist/assets/brand/stripe.svg +2 -0
  74. package/dist/assets/brand/supabase.svg +2 -0
  75. package/dist/assets/brand/telegram.svg +2 -0
  76. package/dist/assets/brand/tencent.svg +2 -0
  77. package/dist/assets/brand/the-drummer.svg +2 -0
  78. package/dist/assets/brand/thinkingmachines.svg +2 -0
  79. package/dist/assets/brand/todoist.svg +2 -0
  80. package/dist/assets/brand/unbiased.svg +2 -0
  81. package/dist/assets/brand/unreal-engine.svg +2 -0
  82. package/dist/assets/brand/upstage.svg +2 -0
  83. package/dist/assets/brand/vercel.svg +2 -0
  84. package/dist/assets/brand/webflow.svg +2 -0
  85. package/dist/assets/brand/whatsapp.svg +2 -0
  86. package/dist/assets/brand/windows.svg +2 -0
  87. package/dist/assets/brand/writer.svg +2 -0
  88. package/dist/assets/brand/xiaomimimo.svg +2 -0
  89. package/dist/assets/brand/youtube.svg +2 -0
  90. package/dist/assets/brand/yuanbao.svg +2 -0
  91. package/dist/assets/brand/zai.svg +2 -0
  92. package/dist/assets/brand/zapier.svg +2 -0
  93. package/dist/components/action-band.js +1 -1
  94. package/dist/components/action-status.d.ts +5 -0
  95. package/dist/components/action-status.d.ts.map +1 -1
  96. package/dist/components/action-status.js +6 -2
  97. package/dist/components/agent-orb-appearance.d.ts +16 -2
  98. package/dist/components/agent-orb-appearance.d.ts.map +1 -1
  99. package/dist/components/agent-orb-appearance.js +28 -5
  100. package/dist/components/agent-orb.d.ts +6 -3
  101. package/dist/components/agent-orb.d.ts.map +1 -1
  102. package/dist/components/agent-orb.js +20 -7
  103. package/dist/components/app-mark-aliases.d.ts +16 -0
  104. package/dist/components/app-mark-aliases.d.ts.map +1 -0
  105. package/dist/components/app-mark-aliases.js +84 -0
  106. package/dist/components/app-mark.d.ts +4 -0
  107. package/dist/components/app-mark.d.ts.map +1 -1
  108. package/dist/components/app-mark.js +14 -31
  109. package/dist/components/automation-section.d.ts.map +1 -1
  110. package/dist/components/automation-section.js +2 -2
  111. package/dist/components/badge.js +1 -1
  112. package/dist/components/brand.d.ts +3 -2
  113. package/dist/components/brand.d.ts.map +1 -1
  114. package/dist/components/brand.js +18 -28
  115. package/dist/components/button.js +1 -1
  116. package/dist/components/code-editor-mockup.d.ts +1 -1
  117. package/dist/components/code-editor-mockup.js +1 -1
  118. package/dist/components/collection-filters.js +2 -2
  119. package/dist/components/confirm-dialog.d.ts +3 -1
  120. package/dist/components/confirm-dialog.d.ts.map +1 -1
  121. package/dist/components/confirm-dialog.js +3 -3
  122. package/dist/components/drawer.js +5 -5
  123. package/dist/components/feature-grid.js +2 -2
  124. package/dist/components/feedback-state.d.ts.map +1 -1
  125. package/dist/components/feedback-state.js +6 -9
  126. package/dist/components/footer.js +2 -2
  127. package/dist/components/hero.js +1 -1
  128. package/dist/components/house-icons.d.ts.map +1 -1
  129. package/dist/components/house-icons.js +9 -1
  130. package/dist/components/input-otp.js +1 -1
  131. package/dist/components/installer-shell.d.ts.map +1 -1
  132. package/dist/components/installer-shell.js +5 -6
  133. package/dist/components/logo-band.js +1 -1
  134. package/dist/components/navigation-menu.js +2 -2
  135. package/dist/components/pending-label.d.ts +15 -0
  136. package/dist/components/pending-label.d.ts.map +1 -0
  137. package/dist/components/pending-label.js +14 -0
  138. package/dist/components/proof-slot.js +1 -1
  139. package/dist/components/section-intro.js +2 -2
  140. package/dist/components/security-grid.js +1 -1
  141. package/dist/components/sheet.js +1 -1
  142. package/dist/components/shift-band.js +1 -1
  143. package/dist/components/skeleton.d.ts +4 -0
  144. package/dist/components/skeleton.d.ts.map +1 -1
  145. package/dist/components/skeleton.js +5 -1
  146. package/dist/components/sonner.d.ts.map +1 -1
  147. package/dist/components/sonner.js +5 -2
  148. package/dist/components/statement.js +2 -2
  149. package/dist/components/steps.js +2 -2
  150. package/dist/components/table.js +1 -1
  151. package/dist/components/tabs.js +1 -1
  152. package/dist/components/texture-strip.js +1 -1
  153. package/dist/components/toggle.js +1 -1
  154. package/dist/components/waiting-line.d.ts +30 -0
  155. package/dist/components/waiting-line.d.ts.map +1 -0
  156. package/dist/components/waiting-line.js +33 -0
  157. package/dist/eslint/rules/no-invalid-token-utility.js +1 -1
  158. package/dist/index.d.ts +2 -8
  159. package/dist/index.d.ts.map +1 -1
  160. package/dist/index.js +2 -8
  161. package/dist/internal/agent-orb-motion.d.ts +9 -1
  162. package/dist/internal/agent-orb-motion.d.ts.map +1 -1
  163. package/dist/internal/agent-orb-motion.js +23 -11
  164. package/dist/internal/agent-orb.d.ts +14 -1
  165. package/dist/internal/agent-orb.d.ts.map +1 -1
  166. package/dist/internal/agent-orb.js +78 -22
  167. package/dist/internal/assistant-ui/attachment.d.ts.map +1 -1
  168. package/dist/internal/assistant-ui/attachment.js +3 -2
  169. package/dist/internal/assistant-ui/reasoning.d.ts.map +1 -1
  170. package/dist/internal/assistant-ui/reasoning.js +4 -4
  171. package/dist/internal/assistant-ui/tool-fallback.d.ts.map +1 -1
  172. package/dist/internal/assistant-ui/tool-fallback.js +5 -4
  173. package/dist/internal/assistant-ui/tool-group.d.ts.map +1 -1
  174. package/dist/internal/assistant-ui/tool-group.js +4 -3
  175. package/dist/lib/motion.d.ts +18 -4
  176. package/dist/lib/motion.d.ts.map +1 -1
  177. package/dist/lib/motion.js +18 -4
  178. package/dist/styles/globals.css +0 -1
  179. package/docs/activity.md +99 -117
  180. package/docs/agent-orb.md +72 -19
  181. package/docs/component-classification.md +4 -4
  182. package/docs/consuming-cross-repo.md +8 -10
  183. package/docs/contract.md +10 -9
  184. package/docs/icon-assets.md +106 -0
  185. package/docs/migration/10.0.0.md +144 -0
  186. package/package.json +8 -7
  187. package/dist/activity.d.ts +0 -2
  188. package/dist/activity.d.ts.map +0 -1
  189. package/dist/activity.js +0 -2
  190. package/dist/components/activity-orb.d.ts +0 -21
  191. package/dist/components/activity-orb.d.ts.map +0 -1
  192. package/dist/components/activity-orb.js +0 -26
  193. package/dist/components/benefits-bento.d.ts +0 -15
  194. package/dist/components/benefits-bento.d.ts.map +0 -1
  195. package/dist/components/benefits-bento.js +0 -6
  196. package/dist/components/bento.d.ts +0 -39
  197. package/dist/components/bento.d.ts.map +0 -1
  198. package/dist/components/bento.js +0 -70
  199. package/dist/components/glyph-spinner.d.ts +0 -10
  200. package/dist/components/glyph-spinner.d.ts.map +0 -1
  201. package/dist/components/glyph-spinner.js +0 -101
  202. package/dist/components/nav-bar.d.ts +0 -24
  203. package/dist/components/nav-bar.d.ts.map +0 -1
  204. package/dist/components/nav-bar.js +0 -35
  205. package/dist/components/page-frame.d.ts +0 -30
  206. package/dist/components/page-frame.d.ts.map +0 -1
  207. package/dist/components/page-frame.js +0 -30
  208. package/dist/components/spinner.d.ts +0 -3
  209. package/dist/components/spinner.d.ts.map +0 -1
  210. package/dist/components/spinner.js +0 -7
  211. package/dist/components/use-case-bento.d.ts +0 -13
  212. package/dist/components/use-case-bento.d.ts.map +0 -1
  213. package/dist/components/use-case-bento.js +0 -8
  214. package/dist/internal/activity-orb.d.ts +0 -27
  215. package/dist/internal/activity-orb.d.ts.map +0 -1
  216. package/dist/internal/activity-orb.js +0 -150
@@ -1,30 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { cn } from "../lib/utils.js";
3
- /**
4
- * page-frame — React shell for the kept design-system page geometry.
5
- *
6
- * The design-system owns the frame, row, lane, side-fill, rail, and marker CSS.
7
- * This component gives website pages a small React vocabulary so they do not
8
- * hand-author the same structure for every section. It intentionally does not
9
- * replace the geometry layer; it only composes the approved classes.
10
- */
11
- function PageSystem({ className, ...props }) {
12
- return _jsx("div", { className: cn("nc-page-system", className), ...props });
13
- }
14
- function PageFrame({ className, ...props }) {
15
- return (_jsx("div", { "data-nc-component": "page-frame", className: cn("nc-page-frame", className), ...props }));
16
- }
17
- function PageRow({ lane = "active", laneClassName, sideFills, marker, className, children, ...props }) {
18
- const showSideFills = sideFills ?? lane === "active";
19
- return (_jsxs("section", { "data-nc-component": "page-row", className: cn("nc-page-row", className), ...props, children: [marker ? _jsx(PageMarker, { position: marker }) : null, showSideFills ? _jsx(PageSideFill, { side: "start" }) : null, _jsx(PageLane, { lane: lane, className: laneClassName, children: children }), showSideFills ? _jsx(PageSideFill, { side: "end" }) : null] }));
20
- }
21
- function PageLane({ lane = "active", className, ...props }) {
22
- return (_jsx("div", { "data-lane": lane, "data-nc-component": lane === "active" ? "active-lane" : undefined, className: cn("nc-row-lane", className), ...props }));
23
- }
24
- function PageSideFill({ side, className, ...props }) {
25
- return (_jsx("div", { "data-side": side, className: cn("nc-side-fill", className), "aria-hidden": "true", ...props }));
26
- }
27
- function PageMarker({ position, className, ...props }) {
28
- return (_jsx("span", { "data-position": position, className: cn("nc-marker", className), "aria-hidden": "true", ...props }));
29
- }
30
- export { PageSystem, PageFrame, PageRow, PageLane, PageSideFill, PageMarker };
@@ -1,3 +0,0 @@
1
- declare function Spinner({ className, ...props }: React.ComponentProps<"svg">): import("react").JSX.Element;
2
- export { Spinner };
3
- //# sourceMappingURL=spinner.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"spinner.d.ts","sourceRoot":"","sources":["../../src/components/spinner.tsx"],"names":[],"mappings":"AAGA,iBAAS,OAAO,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,+BAQpE;AAED,OAAO,EAAE,OAAO,EAAE,CAAC"}
@@ -1,7 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { cn } from "../lib/utils.js";
3
- import { Loader2Icon } from "lucide-react";
4
- function Spinner({ className, ...props }) {
5
- return (_jsx(Loader2Icon, { "data-slot": "spinner", className: cn("size-4 motion-safe:animate-spin motion-reduce:animate-pulse", className), ...props }));
6
- }
7
- export { Spinner };
@@ -1,13 +0,0 @@
1
- import * as React from "react";
2
- declare function UseCaseBento({ kicker, title, body, proof, proofLabel, media, mediaClassName, demo, className, ...props }: React.ComponentProps<"article"> & {
3
- kicker: string;
4
- title: string;
5
- body: string;
6
- proof: string;
7
- proofLabel?: string;
8
- media: React.ReactNode;
9
- mediaClassName?: string;
10
- demo: React.ReactNode;
11
- }): React.JSX.Element;
12
- export { UseCaseBento };
13
- //# sourceMappingURL=use-case-bento.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"use-case-bento.d.ts","sourceRoot":"","sources":["../../src/components/use-case-bento.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAO/B,iBAAS,YAAY,CAAC,EACpB,MAAM,EACN,KAAK,EACL,IAAI,EACJ,KAAK,EACL,UAAmC,EACnC,KAAK,EACL,cAAc,EACd,IAAI,EACJ,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,SAAS,CAAC,GAAG;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC;CACvB,qBAmCA;AAED,OAAO,EAAE,YAAY,EAAE,CAAC"}
@@ -1,8 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { cn } from "../lib/utils.js";
3
- import { Bento, BentoCopy, BentoDemo, BentoItem, BentoMedia } from "./bento.js";
4
- import { MediaMount } from "./media-mount.js";
5
- function UseCaseBento({ kicker, title, body, proof, proofLabel = "What the agent shows", media, mediaClassName, demo, className, ...props }) {
6
- return (_jsx("article", { "data-slot": "use-case-bento", className: className, ...props, children: _jsxs(Bento, { height: "primary", children: [_jsxs(BentoItem, { span: 3, children: [_jsx("div", { className: "nc-artifact-surface pointer-events-none absolute inset-0 border-0 p-0 opacity-60", "aria-hidden": "true" }), _jsxs(BentoCopy, { children: [_jsx("p", { className: "nc-type-caption-mono text-muted-foreground uppercase", children: kicker }), _jsx("h3", { className: "nc-type-title-md text-foreground", children: title }), _jsx("p", { className: "nc-type-body-sm text-[var(--nc-body)]", children: body }), _jsxs("div", { className: "grid gap-2 border-t border-border pt-4", children: [_jsx("p", { className: "nc-type-caption-mono text-muted-foreground uppercase", children: proofLabel }), _jsx("p", { className: "nc-type-body-sm text-foreground", children: proof })] })] })] }), _jsx(BentoItem, { span: 5, flush: true, stretch: true, className: "min-h-[var(--nc-h-bento-primary)]", children: _jsx(BentoMedia, { children: _jsx(MediaMount, { ratio: "auto", className: cn("!h-full min-h-[var(--nc-h-bento-primary)]", mediaClassName), children: media }) }) }), _jsx(BentoItem, { span: 4, surface: "soft", stretch: true, className: "min-h-0 p-[var(--nc-sm)]", children: _jsx(BentoDemo, { children: demo }) })] }) }));
7
- }
8
- export { UseCaseBento };
@@ -1,27 +0,0 @@
1
- /** Product activities, not the vendor's agent vocabulary. */
2
- declare const ACTIVITY_RECIPES: {
3
- readonly loading: {
4
- readonly state: "composing";
5
- readonly speed: 0.92;
6
- readonly still: 0.6;
7
- };
8
- readonly connecting: {
9
- readonly state: "connecting";
10
- readonly speed: 0.86;
11
- readonly still: 0.6;
12
- };
13
- readonly processing: {
14
- readonly state: "working";
15
- readonly speed: 0.92;
16
- readonly still: 0.6;
17
- };
18
- };
19
- export type ActivityKind = keyof typeof ACTIVITY_RECIPES;
20
- export type ActivityOrbSize = 20 | 64 | 88;
21
- /** Own canvas lifetime; callers supply activity and accessible meaning only. */
22
- export declare function mountActivityOrb(canvas: HTMLCanvasElement, activity: ActivityKind, size: ActivityOrbSize, initiallyPaused?: boolean): {
23
- destroy: () => void;
24
- setPaused: (_paused: boolean) => void;
25
- };
26
- export {};
27
- //# sourceMappingURL=activity-orb.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"activity-orb.d.ts","sourceRoot":"","sources":["../../src/internal/activity-orb.ts"],"names":[],"mappings":"AAEA,6DAA6D;AAC7D,QAAA,MAAM,gBAAgB;;;;;;;;;;;;;;;;CAIZ,CAAC;AAEX,MAAM,MAAM,YAAY,GAAG,MAAM,OAAO,gBAAgB,CAAC;AACzD,MAAM,MAAM,eAAe,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AAoE3C,gFAAgF;AAChF,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,iBAAiB,EACzB,QAAQ,EAAE,YAAY,EACtB,IAAI,EAAE,eAAe,EACrB,eAAe,UAAQ;;yBAEuC,OAAO;EA0FtE"}
@@ -1,150 +0,0 @@
1
- import { MODE_FRAMES, resolvePreset } from "thinking-orbs/engine";
2
- /** Product activities, not the vendor's agent vocabulary. */
3
- const ACTIVITY_RECIPES = {
4
- loading: { state: "composing", speed: 0.92, still: 0.6 },
5
- connecting: { state: "connecting", speed: 0.86, still: 0.6 },
6
- processing: { state: "working", speed: 0.92, still: 0.6 },
7
- };
8
- /** Preserve the library's geometry, depth ordering and optical size profiles. */
9
- function activityFrame(activity, size, seconds) {
10
- const recipe = ACTIVITY_RECIPES[activity];
11
- const preset = resolvePreset(recipe.state, size === 20 ? 20 : 64);
12
- return MODE_FRAMES[preset.mode](size, seconds * preset.speed * recipe.speed, preset.opts);
13
- }
14
- function colourAt(palette, white, opacity = 1) {
15
- const depth = Math.min(1, Math.max(0, white));
16
- // The foreground particles carry cobalto; the supporting structure keeps
17
- // inherited ink. Opacity lets the same material work on inverted controls.
18
- const accent = Math.min(1, Math.max(0, (0.4 - depth) / 0.32)) * 0.75;
19
- const channels = palette.ink.map((ink, i) => Math.round(ink + ((palette.accent[i] ?? ink) - ink) * accent));
20
- // eslint-disable-next-line no-restricted-syntax -- Canvas serializes channels resolved from currentColor and --nc-info; this adapter defines no palette literals.
21
- return `rgba(${channels.join(",")},${opacity * (1 - depth)})`;
22
- }
23
- function paintActivityFrame(context, activity, size, seconds, palette) {
24
- const frame = activityFrame(activity, size, seconds);
25
- context.clearRect(0, 0, size, size);
26
- for (const line of frame.lines) {
27
- context.strokeStyle = colourAt(palette, line.white, line.a);
28
- context.lineWidth = line.w;
29
- context.beginPath();
30
- context.moveTo(line.x1, line.y1);
31
- context.lineTo(line.x2, line.y2);
32
- context.stroke();
33
- }
34
- for (const dot of frame.dots) {
35
- context.fillStyle = colourAt(palette, dot.white, dot.a);
36
- context.beginPath();
37
- context.arc(dot.x, dot.y, dot.r, 0, Math.PI * 2);
38
- context.fill();
39
- }
40
- }
41
- function readPalette(canvas) {
42
- const probe = document.createElement("canvas");
43
- probe.width = 1;
44
- probe.height = 1;
45
- const context = probe.getContext("2d", { willReadFrequently: true });
46
- if (!context)
47
- return null;
48
- const style = getComputedStyle(canvas);
49
- const read = (value) => {
50
- context.clearRect(0, 0, 1, 1);
51
- context.fillStyle = value;
52
- context.fillRect(0, 0, 1, 1);
53
- const { data } = context.getImageData(0, 0, 1, 1);
54
- return [data[0] ?? 0, data[1] ?? 0, data[2] ?? 0];
55
- };
56
- const ink = read(style.color);
57
- const accent = read(style.getPropertyValue("--nc-info").trim() || style.color);
58
- return { ink, accent };
59
- }
60
- /** Own canvas lifetime; callers supply activity and accessible meaning only. */
61
- export function mountActivityOrb(canvas, activity, size, initiallyPaused = false) {
62
- const unavailable = { destroy: () => { }, setPaused: (_paused) => { } };
63
- const context = canvas.getContext("2d");
64
- if (!context)
65
- return unavailable;
66
- let palette = readPalette(canvas);
67
- if (!palette)
68
- return unavailable;
69
- const query = window.matchMedia("(prefers-reduced-motion: reduce)");
70
- let reduced = query.matches;
71
- let paused = initiallyPaused;
72
- let visible = true;
73
- let disposed = false;
74
- let request = 0;
75
- // Each recipe retains a representative pose under reduced motion.
76
- const still = ACTIVITY_RECIPES[activity].still;
77
- let seconds = still;
78
- let previous = null;
79
- let ratio = 1;
80
- function paint() {
81
- if (!palette || !context)
82
- return;
83
- context.setTransform(ratio, 0, 0, ratio, 0, 0);
84
- paintActivityFrame(context, activity, size, reduced ? still : seconds, palette);
85
- }
86
- function tick(now) {
87
- request = 0;
88
- if (disposed || !visible || document.hidden || reduced || paused)
89
- return;
90
- if (previous !== null)
91
- seconds += Math.min((now - previous) / 1000, 0.1);
92
- previous = now;
93
- paint();
94
- request = requestAnimationFrame(tick);
95
- }
96
- function play() {
97
- cancelAnimationFrame(request);
98
- previous = null;
99
- paint();
100
- if (!disposed && visible && !document.hidden && !reduced && !paused) {
101
- request = requestAnimationFrame(tick);
102
- }
103
- }
104
- function refresh() {
105
- ratio = Math.min(window.devicePixelRatio || 1, 2);
106
- canvas.width = Math.round(size * ratio);
107
- canvas.height = Math.round(size * ratio);
108
- palette = readPalette(canvas);
109
- play();
110
- }
111
- function motionChanged(event) {
112
- reduced = event.matches;
113
- play();
114
- }
115
- const visibility = typeof IntersectionObserver === "undefined"
116
- ? null
117
- : new IntersectionObserver(([entry]) => {
118
- visible = entry?.isIntersecting ?? false;
119
- play();
120
- });
121
- visibility?.observe(canvas);
122
- // Observe ancestors only: changing unrelated content must not repaint this
123
- // canvas or install a document-wide subtree observer per inline indicator.
124
- const theme = new MutationObserver(refresh);
125
- for (let ancestor = canvas; ancestor; ancestor = ancestor.parentElement) {
126
- theme.observe(ancestor, {
127
- attributes: true,
128
- attributeFilter: ["class", "style", "data-theme"],
129
- });
130
- }
131
- query.addEventListener("change", motionChanged);
132
- document.addEventListener("visibilitychange", play);
133
- window.addEventListener("resize", refresh);
134
- refresh();
135
- return {
136
- setPaused(value) {
137
- paused = value;
138
- play();
139
- },
140
- destroy() {
141
- disposed = true;
142
- cancelAnimationFrame(request);
143
- visibility?.disconnect();
144
- theme.disconnect();
145
- query.removeEventListener("change", motionChanged);
146
- document.removeEventListener("visibilitychange", play);
147
- window.removeEventListener("resize", refresh);
148
- },
149
- };
150
- }