@nucleux/ai-icons 0.9.0 → 0.10.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.
package/dist/index.cjs CHANGED
@@ -199,7 +199,7 @@ var AiIcons = React__namespace.forwardRef(
199
199
  "data-variant": variant,
200
200
  className: utils.cn(
201
201
  base,
202
- "rounded-full bg-gradient-to-br from-brand to-primary shadow-sm",
202
+ "rounded-full bg-gradient-to-br from-primary/80 to-primary ring-4 ring-primary/10",
203
203
  color.aiColorClasses.working,
204
204
  sizeClasses[size],
205
205
  className
@@ -244,9 +244,52 @@ var AiIcons = React__namespace.forwardRef(
244
244
  }
245
245
  );
246
246
  AiIcons.displayName = "AiIcons";
247
+ var defaultAiIconLegendTerms = [
248
+ { role: "ai-action", name: "AI action", meaning: "Pressing this runs AI on something specific." },
249
+ { role: "generated-content", name: "AI-generated content", meaning: "This content was created or changed by AI." },
250
+ { role: "agent-working", name: "Agent working", meaning: "The agent is currently performing work." },
251
+ { role: "tool-use", name: "Tool use", meaning: "The agent used another tool or system." }
252
+ ];
253
+ function AiLegendGlyph({ role, className }) {
254
+ const Glyph = useAiGlyph(role);
255
+ return role === "agent-working" ? /* @__PURE__ */ jsxRuntime.jsx(AiWorkingIcon, { still: true, className }) : /* @__PURE__ */ jsxRuntime.jsx(Glyph, { className });
256
+ }
257
+ var AiIconLegend = React__namespace.forwardRef(
258
+ ({ heading = "Icon language", terms = defaultAiIconLegendTerms, current, className, ...props }, ref) => {
259
+ const headingId = React__namespace.useId();
260
+ return /* @__PURE__ */ jsxRuntime.jsxs("section", { ref, "aria-labelledby": headingId, className: utils.cn("text-foreground", className), ...props, children: [
261
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { id: headingId, className: "mb-3 mt-0 text-xs font-semibold uppercase tracking-wider text-muted-foreground", children: heading }),
262
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "m-0 list-none border-t border-border p-0", children: terms.map((term) => {
263
+ const here = term.role === current;
264
+ return /* @__PURE__ */ jsxRuntime.jsxs(
265
+ "li",
266
+ {
267
+ "aria-current": here || void 0,
268
+ className: utils.cn(
269
+ "flex items-center gap-4 border-b border-l-[3px] border-b-border px-3 py-2.5 text-sm",
270
+ here ? "border-l-brand bg-muted" : "border-l-transparent"
271
+ ),
272
+ children: [
273
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { "aria-hidden": "true", className: "flex w-[5.5rem] shrink-0 items-center gap-2.5 text-brand", children: [
274
+ /* @__PURE__ */ jsxRuntime.jsx(AiLegendGlyph, { role: term.role, className: "size-6" }),
275
+ /* @__PURE__ */ jsxRuntime.jsx(AiLegendGlyph, { role: term.role, className: "size-5" }),
276
+ /* @__PURE__ */ jsxRuntime.jsx(AiLegendGlyph, { role: term.role, className: "size-4" })
277
+ ] }),
278
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-40 shrink-0 font-medium", children: term.name }),
279
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: term.meaning })
280
+ ]
281
+ },
282
+ term.role
283
+ );
284
+ }) })
285
+ ] });
286
+ }
287
+ );
288
+ AiIconLegend.displayName = "AiIconLegend";
247
289
 
248
290
  exports.AiGeneratedIcon = AiGeneratedIcon;
249
291
  exports.AiIcon = AiIcon;
292
+ exports.AiIconLegend = AiIconLegend;
250
293
  exports.AiIconProvider = AiIconProvider;
251
294
  exports.AiIcons = AiIcons;
252
295
  exports.AiRegenerateIcon = AiRegenerateIcon;
@@ -256,6 +299,7 @@ exports.AiWandIcon = AiWandIcon;
256
299
  exports.AiWorkingIcon = AiWorkingIcon;
257
300
  exports.aiGlyphs = aiGlyphs;
258
301
  exports.defaultAiIconGlyphs = defaultAiIconGlyphs;
302
+ exports.defaultAiIconLegendTerms = defaultAiIconLegendTerms;
259
303
  exports.useAiGlyph = useAiGlyph;
260
304
  //# sourceMappingURL=index.cjs.map
261
305
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.tsx"],"names":["React","jsx","cn","jsxs","WandSparkles","RefreshCw","Wrench","aiColorClasses"],"mappings":"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","file":"index.cjs","sourcesContent":["import * as React from \"react\";\nimport { RefreshCw, WandSparkles, Wrench } from \"lucide-react\";\nimport { cn } from \"@nucleux/utils\";\nimport { aiColorClasses } from \"@nucleux/color\";\n\n/* -------------------------------------------------------------------------- */\n/* Glyphs */\n/* -------------------------------------------------------------------------- */\n\nexport type AiGlyphProps = React.SVGProps<SVGSVGElement>;\n\n/** Decorative unless the caller names it. */\nfunction glyphA11y(props: AiGlyphProps) {\n const named = props[\"aria-label\"] != null || props[\"aria-labelledby\"] != null;\n return named ? { role: \"img\" as const } : { \"aria-hidden\": true as const };\n}\n\n/**\n * The four-point AI sparkle — the reserved mark for \"this runs AI\" (generate).\n * The same drawing appears on the agent avatar and the disclosure chip.\n * Decorative (`aria-hidden`) unless given an `aria-label`.\n */\nexport const AiSparkleIcon = React.forwardRef<SVGSVGElement, AiGlyphProps>(({ className, ...props }, ref) => (\n <svg\n ref={ref}\n viewBox=\"0 0 24 24\"\n width={16}\n height={16}\n fill=\"currentColor\"\n focusable=\"false\"\n data-ai-glyph=\"sparkle\"\n className={cn(\"size-4 shrink-0\", className)}\n {...glyphA11y(props)}\n {...props}\n >\n <path d=\"M12 3c.6 4.8 3.2 7.4 9 9-5.8 1.6-8.4 4.2-9 9-.6-4.8-3.2-7.4-9-9 5.8-1.6 8.4-4.2 9-9z\" />\n </svg>\n));\nAiSparkleIcon.displayName = \"AiSparkleIcon\";\n\n/**\n * The \"generated with AI\" mark: a content outline carrying the sparkle. Used\n * only on content AI wrote or changed, never on controls.\n */\nexport const AiGeneratedIcon = React.forwardRef<SVGSVGElement, AiGlyphProps>(({ className, ...props }, ref) => (\n <svg\n ref={ref}\n viewBox=\"0 0 24 24\"\n width={16}\n height={16}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={1.8}\n strokeLinejoin=\"round\"\n focusable=\"false\"\n data-ai-glyph=\"generated\"\n className={cn(\"size-4 shrink-0\", className)}\n {...glyphA11y(props)}\n {...props}\n >\n <path d=\"M5 4h14a1 1 0 0 1 1 1v11a1 1 0 0 1-1 1h-7l-4 3v-3H5a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1z\" />\n <path\n d=\"M12 6.5c.3 2.2 1.3 3.2 3.5 3.5-2.2.3-3.2 1.3-3.5 3.5-.3-2.2-1.3-3.2-3.5-3.5 2.2-.3 3.2-1.3 3.5-3.5z\"\n fill=\"currentColor\"\n stroke=\"none\"\n />\n </svg>\n));\nAiGeneratedIcon.displayName = \"AiGeneratedIcon\";\n\nexport interface AiWorkingIconProps extends AiGlyphProps {\n /** Hold the mark still (it only turns while work is happening). */\n still?: boolean;\n}\n\n/**\n * The \"agent working\" mark: a turning arc. The only AI mark that moves, and\n * only while work is happening; it holds still under reduced motion.\n */\nexport const AiWorkingIcon = React.forwardRef<SVGSVGElement, AiWorkingIconProps>(\n ({ still = false, className, ...props }, ref) => (\n <svg\n ref={ref}\n viewBox=\"0 0 24 24\"\n width={16}\n height={16}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2.2}\n strokeLinecap=\"round\"\n focusable=\"false\"\n data-ai-glyph=\"working\"\n className={cn(\"size-4 shrink-0\", !still && \"animate-spin motion-reduce:animate-none\", className)}\n {...glyphA11y(props)}\n {...props}\n >\n <circle cx=\"12\" cy=\"12\" r=\"8.5\" opacity={0.25} />\n <path d=\"M12 3.5a8.5 8.5 0 0 1 8.5 8.5\" />\n </svg>\n ),\n);\nAiWorkingIcon.displayName = \"AiWorkingIcon\";\n\nfunction lucideGlyph(Icon: React.ComponentType<AiGlyphProps>, name: string, displayName: string) {\n const Glyph = React.forwardRef<SVGSVGElement, AiGlyphProps>(({ className, ...props }, ref) => (\n <Icon\n ref={ref}\n focusable=\"false\"\n data-ai-glyph={name}\n className={cn(\"size-4 shrink-0\", className)}\n {...glyphA11y(props)}\n {...props}\n />\n ));\n Glyph.displayName = displayName;\n return Glyph;\n}\n\n/** The \"transform\" mark (wand): for AI actions that change something the user already has — rewrite, enhance, restyle. */\nexport const AiWandIcon = lucideGlyph(\n WandSparkles as unknown as React.ComponentType<AiGlyphProps>,\n \"wand\",\n \"AiWandIcon\",\n);\n/** The \"regenerate\" mark: run the same AI action again. */\nexport const AiRegenerateIcon = lucideGlyph(\n RefreshCw as unknown as React.ComponentType<AiGlyphProps>,\n \"regenerate\",\n \"AiRegenerateIcon\",\n);\n/** The \"tool use\" mark: on the lines that say which tool the agent used. */\nexport const AiToolIcon = lucideGlyph(Wrench as unknown as React.ComponentType<AiGlyphProps>, \"tool\", \"AiToolIcon\");\n\n/* -------------------------------------------------------------------------- */\n/* Roles and the approved glyph lists */\n/* -------------------------------------------------------------------------- */\n\n/** The four AI meanings. Each has its own mark, used for that meaning only. */\nexport type AiIconRole = \"ai-action\" | \"generated-content\" | \"agent-working\" | \"tool-use\";\n\n/** Every reserved glyph by name. */\nexport type AiGlyphName = \"sparkle\" | \"wand\" | \"regenerate\" | \"generated\" | \"working\" | \"tool\";\n\n/**\n * Approved glyphs per role. The lists do not overlap, so two meanings can\n * never share a mark.\n */\nexport interface AiIconGlyphs {\n \"ai-action\"?: \"sparkle\" | \"wand\";\n \"generated-content\"?: \"generated\";\n \"agent-working\"?: \"working\";\n \"tool-use\"?: \"tool\";\n}\n\n/** The reserved glyph components, by name. */\nexport const aiGlyphs: Record<AiGlyphName, React.ComponentType<AiGlyphProps>> = {\n sparkle: AiSparkleIcon,\n wand: AiWandIcon,\n regenerate: AiRegenerateIcon,\n generated: AiGeneratedIcon,\n working: AiWorkingIcon,\n tool: AiToolIcon,\n};\n\n/** The default glyph for each role. */\nexport const defaultAiIconGlyphs: Required<AiIconGlyphs> = {\n \"ai-action\": \"sparkle\",\n \"generated-content\": \"generated\",\n \"agent-working\": \"working\",\n \"tool-use\": \"tool\",\n};\n\nconst AiIconContext = React.createContext<Required<AiIconGlyphs>>(defaultAiIconGlyphs);\n\nexport interface AiIconProviderProps {\n /** Product-wide choice of approved glyph per role. Set once; unset roles keep the default. */\n glyphs?: AiIconGlyphs;\n children?: React.ReactNode;\n}\n\n/**\n * Sets the approved glyph for each AI role once for the whole product.\n * Every `AiIcon`, `AiIcons`, `Iconography` and `Disclosure` under it uses\n * the same choice, so a meaning keeps one mark everywhere.\n */\nexport function AiIconProvider({ glyphs, children }: AiIconProviderProps) {\n const value = React.useMemo(() => ({ ...defaultAiIconGlyphs, ...glyphs }), [glyphs]);\n return <AiIconContext.Provider value={value}>{children}</AiIconContext.Provider>;\n}\nAiIconProvider.displayName = \"AiIconProvider\";\n\n/** The glyph component the nearest `AiIconProvider` approved for a role. */\nexport function useAiGlyph(role: AiIconRole): React.ComponentType<AiGlyphProps> {\n const glyphs = React.useContext(AiIconContext);\n return aiGlyphs[glyphs[role]];\n}\n\n/* -------------------------------------------------------------------------- */\n/* AiIcon — a meaning, with its mark and its words */\n/* -------------------------------------------------------------------------- */\n\nexport interface AiIconProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, \"role\"> {\n /**\n * Which AI meaning this is: `ai-action` (a control runs AI),\n * `generated-content` (AI wrote this), `agent-working` (the agent is\n * working now — announced politely) or `tool-use` (the agent used a tool).\n */\n role: AiIconRole;\n /** The words that travel with the mark (\"Rewrite\", \"Generated with AI\", \"Rewriting release note…\"). Required: a mark is never alone. */\n label: React.ReactNode;\n /** Show the words visibly (default) or keep them for assistive tech only. */\n showLabel?: boolean;\n}\n\nconst roleClasses: Record<AiIconRole, string> = {\n \"ai-action\": \"text-foreground [&>svg]:text-brand\",\n \"agent-working\": \"text-foreground [&>svg]:text-brand\",\n \"tool-use\": \"text-muted-foreground\",\n \"generated-content\":\n \"rounded-full border border-brand/30 bg-background px-2 py-0.5 text-xs font-medium text-foreground [&>svg]:size-3.5 [&>svg]:text-brand\",\n};\n\n/**\n * One AI meaning drawn with its reserved mark and its words. The product\n * names the meaning; the component maps it to the approved glyph (see\n * `AiIconProvider`). `agent-working` turns its mark and announces its words\n * in a polite live region; the rest are static. For a control that runs\n * AI, use `Iconography`, which puts the `ai-action` mark on a Button.\n */\nexport const AiIcon = React.forwardRef<HTMLSpanElement, AiIconProps>(\n ({ role, label, showLabel = true, className, ...props }, ref) => {\n const Glyph = useAiGlyph(role);\n return (\n <span\n ref={ref}\n data-ai-role={role}\n role={role === \"agent-working\" ? \"status\" : undefined}\n aria-live={role === \"agent-working\" ? \"polite\" : undefined}\n className={cn(\"inline-flex items-center gap-1.5 text-sm\", roleClasses[role], className)}\n {...props}\n >\n <Glyph />\n <span className={showLabel ? undefined : \"sr-only\"}>{label}</span>\n </span>\n );\n },\n);\nAiIcon.displayName = \"AiIcon\";\n\n/* -------------------------------------------------------------------------- */\n/* AiIcons — the AI presence mark */\n/* -------------------------------------------------------------------------- */\n\nexport type AiIconsVariant = \"sparkle\" | \"thinking-orb\" | \"branded-mark\";\nexport type AiIconsSize = \"sm\" | \"md\" | \"lg\";\nexport type AiIconsTone = \"solid\" | \"outline\";\n\nconst sizeClasses: Record<AiIconsSize, string> = {\n sm: \"size-6 text-xs [&>svg]:size-3.5\",\n md: \"size-8 text-sm [&>svg]:size-4\",\n lg: \"size-10 text-lg [&>svg]:size-5\",\n};\n\nexport interface AiIconsProps extends React.HTMLAttributes<HTMLSpanElement> {\n /**\n * `sparkle` (the universal \"AI\" mark in a tile), `thinking-orb` (an\n * animated orb for active, listening or generating states) or\n * `branded-mark` (your product's own shape or letter).\n */\n variant?: AiIconsVariant;\n /** 24 / 32 / 40 px. */\n size?: AiIconsSize;\n /** `solid` (filled tile) or `outline` (bordered tile). Sparkle and branded mark only. */\n tone?: AiIconsTone;\n /** Accessible name. Omit when words sit beside the mark — it is then decorative. */\n label?: string;\n /** Content of the branded mark (a letter or your SVG). Defaults to the first letter of `label`, else the sparkle. */\n glyph?: React.ReactNode;\n}\n\n/**\n * The AI presence mark: one stable symbol that tells people the AI is here.\n * `sparkle` is the default; `thinking-orb` is the active state and pulses\n * (still under reduced motion — pair it with words such as an `AiIcon`\n * `agent-working` line); `branded-mark` carries your product's own shape.\n * Never a photo or a human face.\n */\nexport const AiIcons = React.forwardRef<HTMLSpanElement, AiIconsProps>(\n ({ variant = \"sparkle\", size = \"md\", tone = \"solid\", label, glyph, className, ...props }, ref) => {\n const Sparkle = useAiGlyph(\"ai-action\");\n const a11y = label ? { role: \"img\" as const, \"aria-label\": label } : { \"aria-hidden\": true as const };\n const base = \"inline-grid shrink-0 place-items-center font-semibold\";\n\n if (variant === \"thinking-orb\") {\n return (\n <span\n ref={ref}\n data-variant={variant}\n className={cn(\n base,\n \"rounded-full bg-gradient-to-br from-brand to-primary shadow-sm\",\n aiColorClasses.working,\n sizeClasses[size],\n className,\n )}\n {...a11y}\n {...props}\n />\n );\n }\n\n const toneClasses =\n tone === \"solid\"\n ? \"bg-primary text-primary-foreground\"\n : \"border border-border bg-background text-foreground\";\n\n if (variant === \"branded-mark\") {\n const content = glyph ?? (label ? label.charAt(0).toLowerCase() : <Sparkle />);\n return (\n <span\n ref={ref}\n data-variant={variant}\n className={cn(\n base,\n \"rounded-[28%] font-serif italic\",\n tone === \"solid\" ? \"bg-gradient-to-br from-primary to-primary/70 text-primary-foreground\" : toneClasses,\n sizeClasses[size],\n className,\n )}\n {...a11y}\n {...props}\n >\n {content}\n </span>\n );\n }\n\n return (\n <span\n ref={ref}\n data-variant={variant}\n className={cn(base, \"rounded-[22%]\", toneClasses, sizeClasses[size], className)}\n {...a11y}\n {...props}\n >\n <Sparkle />\n </span>\n );\n },\n);\nAiIcons.displayName = \"AiIcons\";\n"]}
1
+ {"version":3,"sources":["../src/index.tsx"],"names":["React","jsx","cn","jsxs","WandSparkles","RefreshCw","Wrench","aiColorClasses"],"mappings":"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","file":"index.cjs","sourcesContent":["import * as React from \"react\";\nimport { RefreshCw, WandSparkles, Wrench } from \"lucide-react\";\nimport { cn } from \"@nucleux/utils\";\nimport { aiColorClasses } from \"@nucleux/color\";\n\n/* -------------------------------------------------------------------------- */\n/* Glyphs */\n/* -------------------------------------------------------------------------- */\n\nexport type AiGlyphProps = React.SVGProps<SVGSVGElement>;\n\n/** Decorative unless the caller names it. */\nfunction glyphA11y(props: AiGlyphProps) {\n const named = props[\"aria-label\"] != null || props[\"aria-labelledby\"] != null;\n return named ? { role: \"img\" as const } : { \"aria-hidden\": true as const };\n}\n\n/**\n * The four-point AI sparkle — the reserved mark for \"this runs AI\" (generate).\n * The same drawing appears on the agent avatar and the disclosure chip.\n * Decorative (`aria-hidden`) unless given an `aria-label`.\n */\nexport const AiSparkleIcon = React.forwardRef<SVGSVGElement, AiGlyphProps>(({ className, ...props }, ref) => (\n <svg\n ref={ref}\n viewBox=\"0 0 24 24\"\n width={16}\n height={16}\n fill=\"currentColor\"\n focusable=\"false\"\n data-ai-glyph=\"sparkle\"\n className={cn(\"size-4 shrink-0\", className)}\n {...glyphA11y(props)}\n {...props}\n >\n <path d=\"M12 3c.6 4.8 3.2 7.4 9 9-5.8 1.6-8.4 4.2-9 9-.6-4.8-3.2-7.4-9-9 5.8-1.6 8.4-4.2 9-9z\" />\n </svg>\n));\nAiSparkleIcon.displayName = \"AiSparkleIcon\";\n\n/**\n * The \"generated with AI\" mark: a content outline carrying the sparkle. Used\n * only on content AI wrote or changed, never on controls.\n */\nexport const AiGeneratedIcon = React.forwardRef<SVGSVGElement, AiGlyphProps>(({ className, ...props }, ref) => (\n <svg\n ref={ref}\n viewBox=\"0 0 24 24\"\n width={16}\n height={16}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={1.8}\n strokeLinejoin=\"round\"\n focusable=\"false\"\n data-ai-glyph=\"generated\"\n className={cn(\"size-4 shrink-0\", className)}\n {...glyphA11y(props)}\n {...props}\n >\n <path d=\"M5 4h14a1 1 0 0 1 1 1v11a1 1 0 0 1-1 1h-7l-4 3v-3H5a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1z\" />\n <path\n d=\"M12 6.5c.3 2.2 1.3 3.2 3.5 3.5-2.2.3-3.2 1.3-3.5 3.5-.3-2.2-1.3-3.2-3.5-3.5 2.2-.3 3.2-1.3 3.5-3.5z\"\n fill=\"currentColor\"\n stroke=\"none\"\n />\n </svg>\n));\nAiGeneratedIcon.displayName = \"AiGeneratedIcon\";\n\nexport interface AiWorkingIconProps extends AiGlyphProps {\n /** Hold the mark still (it only turns while work is happening). */\n still?: boolean;\n}\n\n/**\n * The \"agent working\" mark: a turning arc. The only AI mark that moves, and\n * only while work is happening; it holds still under reduced motion.\n */\nexport const AiWorkingIcon = React.forwardRef<SVGSVGElement, AiWorkingIconProps>(\n ({ still = false, className, ...props }, ref) => (\n <svg\n ref={ref}\n viewBox=\"0 0 24 24\"\n width={16}\n height={16}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2.2}\n strokeLinecap=\"round\"\n focusable=\"false\"\n data-ai-glyph=\"working\"\n className={cn(\"size-4 shrink-0\", !still && \"animate-spin motion-reduce:animate-none\", className)}\n {...glyphA11y(props)}\n {...props}\n >\n <circle cx=\"12\" cy=\"12\" r=\"8.5\" opacity={0.25} />\n <path d=\"M12 3.5a8.5 8.5 0 0 1 8.5 8.5\" />\n </svg>\n ),\n);\nAiWorkingIcon.displayName = \"AiWorkingIcon\";\n\nfunction lucideGlyph(Icon: React.ComponentType<AiGlyphProps>, name: string, displayName: string) {\n const Glyph = React.forwardRef<SVGSVGElement, AiGlyphProps>(({ className, ...props }, ref) => (\n <Icon\n ref={ref}\n focusable=\"false\"\n data-ai-glyph={name}\n className={cn(\"size-4 shrink-0\", className)}\n {...glyphA11y(props)}\n {...props}\n />\n ));\n Glyph.displayName = displayName;\n return Glyph;\n}\n\n/** The \"transform\" mark (wand): for AI actions that change something the user already has — rewrite, enhance, restyle. */\nexport const AiWandIcon = lucideGlyph(\n WandSparkles as unknown as React.ComponentType<AiGlyphProps>,\n \"wand\",\n \"AiWandIcon\",\n);\n/** The \"regenerate\" mark: run the same AI action again. */\nexport const AiRegenerateIcon = lucideGlyph(\n RefreshCw as unknown as React.ComponentType<AiGlyphProps>,\n \"regenerate\",\n \"AiRegenerateIcon\",\n);\n/** The \"tool use\" mark: on the lines that say which tool the agent used. */\nexport const AiToolIcon = lucideGlyph(Wrench as unknown as React.ComponentType<AiGlyphProps>, \"tool\", \"AiToolIcon\");\n\n/* -------------------------------------------------------------------------- */\n/* Roles and the approved glyph lists */\n/* -------------------------------------------------------------------------- */\n\n/** The four AI meanings. Each has its own mark, used for that meaning only. */\nexport type AiIconRole = \"ai-action\" | \"generated-content\" | \"agent-working\" | \"tool-use\";\n\n/** Every reserved glyph by name. */\nexport type AiGlyphName = \"sparkle\" | \"wand\" | \"regenerate\" | \"generated\" | \"working\" | \"tool\";\n\n/**\n * Approved glyphs per role. The lists do not overlap, so two meanings can\n * never share a mark.\n */\nexport interface AiIconGlyphs {\n \"ai-action\"?: \"sparkle\" | \"wand\";\n \"generated-content\"?: \"generated\";\n \"agent-working\"?: \"working\";\n \"tool-use\"?: \"tool\";\n}\n\n/** The reserved glyph components, by name. */\nexport const aiGlyphs: Record<AiGlyphName, React.ComponentType<AiGlyphProps>> = {\n sparkle: AiSparkleIcon,\n wand: AiWandIcon,\n regenerate: AiRegenerateIcon,\n generated: AiGeneratedIcon,\n working: AiWorkingIcon,\n tool: AiToolIcon,\n};\n\n/** The default glyph for each role. */\nexport const defaultAiIconGlyphs: Required<AiIconGlyphs> = {\n \"ai-action\": \"sparkle\",\n \"generated-content\": \"generated\",\n \"agent-working\": \"working\",\n \"tool-use\": \"tool\",\n};\n\nconst AiIconContext = React.createContext<Required<AiIconGlyphs>>(defaultAiIconGlyphs);\n\nexport interface AiIconProviderProps {\n /** Product-wide choice of approved glyph per role. Set once; unset roles keep the default. */\n glyphs?: AiIconGlyphs;\n children?: React.ReactNode;\n}\n\n/**\n * Sets the approved glyph for each AI role once for the whole product.\n * Every `AiIcon`, `AiIcons`, `Iconography` and `Disclosure` under it uses\n * the same choice, so a meaning keeps one mark everywhere.\n */\nexport function AiIconProvider({ glyphs, children }: AiIconProviderProps) {\n const value = React.useMemo(() => ({ ...defaultAiIconGlyphs, ...glyphs }), [glyphs]);\n return <AiIconContext.Provider value={value}>{children}</AiIconContext.Provider>;\n}\nAiIconProvider.displayName = \"AiIconProvider\";\n\n/** The glyph component the nearest `AiIconProvider` approved for a role. */\nexport function useAiGlyph(role: AiIconRole): React.ComponentType<AiGlyphProps> {\n const glyphs = React.useContext(AiIconContext);\n return aiGlyphs[glyphs[role]];\n}\n\n/* -------------------------------------------------------------------------- */\n/* AiIcon — a meaning, with its mark and its words */\n/* -------------------------------------------------------------------------- */\n\nexport interface AiIconProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, \"role\"> {\n /**\n * Which AI meaning this is: `ai-action` (a control runs AI),\n * `generated-content` (AI wrote this), `agent-working` (the agent is\n * working now — announced politely) or `tool-use` (the agent used a tool).\n */\n role: AiIconRole;\n /** The words that travel with the mark (\"Rewrite\", \"Generated with AI\", \"Rewriting release note…\"). Required: a mark is never alone. */\n label: React.ReactNode;\n /** Show the words visibly (default) or keep them for assistive tech only. */\n showLabel?: boolean;\n}\n\nconst roleClasses: Record<AiIconRole, string> = {\n \"ai-action\": \"text-foreground [&>svg]:text-brand\",\n \"agent-working\": \"text-foreground [&>svg]:text-brand\",\n \"tool-use\": \"text-muted-foreground\",\n \"generated-content\":\n \"rounded-full border border-brand/30 bg-background px-2 py-0.5 text-xs font-medium text-foreground [&>svg]:size-3.5 [&>svg]:text-brand\",\n};\n\n/**\n * One AI meaning drawn with its reserved mark and its words. The product\n * names the meaning; the component maps it to the approved glyph (see\n * `AiIconProvider`). `agent-working` turns its mark and announces its words\n * in a polite live region; the rest are static. For a control that runs\n * AI, use `Iconography`, which puts the `ai-action` mark on a Button.\n */\nexport const AiIcon = React.forwardRef<HTMLSpanElement, AiIconProps>(\n ({ role, label, showLabel = true, className, ...props }, ref) => {\n const Glyph = useAiGlyph(role);\n return (\n <span\n ref={ref}\n data-ai-role={role}\n role={role === \"agent-working\" ? \"status\" : undefined}\n aria-live={role === \"agent-working\" ? \"polite\" : undefined}\n className={cn(\"inline-flex items-center gap-1.5 text-sm\", roleClasses[role], className)}\n {...props}\n >\n <Glyph />\n <span className={showLabel ? undefined : \"sr-only\"}>{label}</span>\n </span>\n );\n },\n);\nAiIcon.displayName = \"AiIcon\";\n\n/* -------------------------------------------------------------------------- */\n/* AiIcons — the AI presence mark */\n/* -------------------------------------------------------------------------- */\n\nexport type AiIconsVariant = \"sparkle\" | \"thinking-orb\" | \"branded-mark\";\nexport type AiIconsSize = \"sm\" | \"md\" | \"lg\";\nexport type AiIconsTone = \"solid\" | \"outline\";\n\nconst sizeClasses: Record<AiIconsSize, string> = {\n sm: \"size-6 text-xs [&>svg]:size-3.5\",\n md: \"size-8 text-sm [&>svg]:size-4\",\n lg: \"size-10 text-lg [&>svg]:size-5\",\n};\n\nexport interface AiIconsProps extends React.HTMLAttributes<HTMLSpanElement> {\n /**\n * `sparkle` (the universal \"AI\" mark in a tile), `thinking-orb` (an\n * animated orb for active, listening or generating states) or\n * `branded-mark` (your product's own shape or letter).\n */\n variant?: AiIconsVariant;\n /** 24 / 32 / 40 px. */\n size?: AiIconsSize;\n /** `solid` (filled tile) or `outline` (bordered tile). Sparkle and branded mark only. */\n tone?: AiIconsTone;\n /** Accessible name. Omit when words sit beside the mark — it is then decorative. */\n label?: string;\n /** Content of the branded mark (a letter or your SVG). Defaults to the first letter of `label`, else the sparkle. */\n glyph?: React.ReactNode;\n}\n\n/**\n * The AI presence mark: one stable symbol that tells people the AI is here.\n * `sparkle` is the default; `thinking-orb` is the active state — a dark orb\n * with a soft halo that pulses\n * (still under reduced motion — pair it with words such as an `AiIcon`\n * `agent-working` line); `branded-mark` carries your product's own shape.\n * Never a photo or a human face.\n */\nexport const AiIcons = React.forwardRef<HTMLSpanElement, AiIconsProps>(\n ({ variant = \"sparkle\", size = \"md\", tone = \"solid\", label, glyph, className, ...props }, ref) => {\n const Sparkle = useAiGlyph(\"ai-action\");\n const a11y = label ? { role: \"img\" as const, \"aria-label\": label } : { \"aria-hidden\": true as const };\n const base = \"inline-grid shrink-0 place-items-center font-semibold\";\n\n if (variant === \"thinking-orb\") {\n return (\n <span\n ref={ref}\n data-variant={variant}\n className={cn(\n base,\n \"rounded-full bg-gradient-to-br from-primary/80 to-primary ring-4 ring-primary/10\",\n aiColorClasses.working,\n sizeClasses[size],\n className,\n )}\n {...a11y}\n {...props}\n />\n );\n }\n\n const toneClasses =\n tone === \"solid\"\n ? \"bg-primary text-primary-foreground\"\n : \"border border-border bg-background text-foreground\";\n\n if (variant === \"branded-mark\") {\n const content = glyph ?? (label ? label.charAt(0).toLowerCase() : <Sparkle />);\n return (\n <span\n ref={ref}\n data-variant={variant}\n className={cn(\n base,\n \"rounded-[28%] font-serif italic\",\n tone === \"solid\" ? \"bg-gradient-to-br from-primary to-primary/70 text-primary-foreground\" : toneClasses,\n sizeClasses[size],\n className,\n )}\n {...a11y}\n {...props}\n >\n {content}\n </span>\n );\n }\n\n return (\n <span\n ref={ref}\n data-variant={variant}\n className={cn(base, \"rounded-[22%]\", toneClasses, sizeClasses[size], className)}\n {...a11y}\n {...props}\n >\n <Sparkle />\n </span>\n );\n },\n);\nAiIcons.displayName = \"AiIcons\";\n\n/* -------------------------------------------------------------------------- */\n/* AiIconLegend — the icon language, written down */\n/* -------------------------------------------------------------------------- */\n\nexport interface AiIconLegendTerm {\n /** The AI meaning this row explains. */\n role: AiIconRole;\n /** Its name — \"AI action\". */\n name: React.ReactNode;\n /** What it tells people — \"Pressing this runs AI on something specific.\" */\n meaning: React.ReactNode;\n}\n\n/** The four meanings in the words nucleux.in uses. */\nexport const defaultAiIconLegendTerms: AiIconLegendTerm[] = [\n { role: \"ai-action\", name: \"AI action\", meaning: \"Pressing this runs AI on something specific.\" },\n { role: \"generated-content\", name: \"AI-generated content\", meaning: \"This content was created or changed by AI.\" },\n { role: \"agent-working\", name: \"Agent working\", meaning: \"The agent is currently performing work.\" },\n { role: \"tool-use\", name: \"Tool use\", meaning: \"The agent used another tool or system.\" },\n];\n\nexport interface AiIconLegendProps extends React.HTMLAttributes<HTMLElement> {\n /** Heading. Default \"Icon language\". */\n heading?: React.ReactNode;\n /** The rows. Defaults to {@link defaultAiIconLegendTerms}. */\n terms?: AiIconLegendTerm[];\n /** The meaning in use on this screen; its row is highlighted and marked `aria-current`. */\n current?: AiIconRole;\n}\n\n/** The approved glyph for a role, drawn still (the legend never animates). */\nfunction AiLegendGlyph({ role, className }: { role: AiIconRole; className?: string }) {\n const Glyph = useAiGlyph(role);\n return role === \"agent-working\" ? <AiWorkingIcon still className={className} /> : <Glyph className={className} />;\n}\n\n/**\n * The product's icon language, written down: each AI meaning with its mark\n * at 24, 20 and 16 px, its name and what it tells people. Put it in\n * onboarding, help or settings so the marks are learned once. Highlight the\n * meaning in use with `current`. Uses the glyphs the nearest\n * `AiIconProvider` approved.\n */\nexport const AiIconLegend = React.forwardRef<HTMLElement, AiIconLegendProps>(\n ({ heading = \"Icon language\", terms = defaultAiIconLegendTerms, current, className, ...props }, ref) => {\n const headingId = React.useId();\n return (\n <section ref={ref} aria-labelledby={headingId} className={cn(\"text-foreground\", className)} {...props}>\n <h3 id={headingId} className=\"mb-3 mt-0 text-xs font-semibold uppercase tracking-wider text-muted-foreground\">\n {heading}\n </h3>\n <ul className=\"m-0 list-none border-t border-border p-0\">\n {terms.map((term) => {\n const here = term.role === current;\n return (\n <li\n key={term.role}\n aria-current={here || undefined}\n className={cn(\n \"flex items-center gap-4 border-b border-l-[3px] border-b-border px-3 py-2.5 text-sm\",\n here ? \"border-l-brand bg-muted\" : \"border-l-transparent\",\n )}\n >\n <span aria-hidden=\"true\" className=\"flex w-[5.5rem] shrink-0 items-center gap-2.5 text-brand\">\n <AiLegendGlyph role={term.role} className=\"size-6\" />\n <AiLegendGlyph role={term.role} className=\"size-5\" />\n <AiLegendGlyph role={term.role} className=\"size-4\" />\n </span>\n <span className=\"w-40 shrink-0 font-medium\">{term.name}</span>\n <span className=\"text-muted-foreground\">{term.meaning}</span>\n </li>\n );\n })}\n </ul>\n </section>\n );\n },\n);\nAiIconLegend.displayName = \"AiIconLegend\";\n"]}
package/dist/index.d.cts CHANGED
@@ -102,11 +102,38 @@ interface AiIconsProps extends React.HTMLAttributes<HTMLSpanElement> {
102
102
  }
103
103
  /**
104
104
  * The AI presence mark: one stable symbol that tells people the AI is here.
105
- * `sparkle` is the default; `thinking-orb` is the active state and pulses
105
+ * `sparkle` is the default; `thinking-orb` is the active state — a dark orb
106
+ * with a soft halo that pulses
106
107
  * (still under reduced motion — pair it with words such as an `AiIcon`
107
108
  * `agent-working` line); `branded-mark` carries your product's own shape.
108
109
  * Never a photo or a human face.
109
110
  */
110
111
  declare const AiIcons: React.ForwardRefExoticComponent<AiIconsProps & React.RefAttributes<HTMLSpanElement>>;
112
+ interface AiIconLegendTerm {
113
+ /** The AI meaning this row explains. */
114
+ role: AiIconRole;
115
+ /** Its name — "AI action". */
116
+ name: React.ReactNode;
117
+ /** What it tells people — "Pressing this runs AI on something specific." */
118
+ meaning: React.ReactNode;
119
+ }
120
+ /** The four meanings in the words nucleux.in uses. */
121
+ declare const defaultAiIconLegendTerms: AiIconLegendTerm[];
122
+ interface AiIconLegendProps extends React.HTMLAttributes<HTMLElement> {
123
+ /** Heading. Default "Icon language". */
124
+ heading?: React.ReactNode;
125
+ /** The rows. Defaults to {@link defaultAiIconLegendTerms}. */
126
+ terms?: AiIconLegendTerm[];
127
+ /** The meaning in use on this screen; its row is highlighted and marked `aria-current`. */
128
+ current?: AiIconRole;
129
+ }
130
+ /**
131
+ * The product's icon language, written down: each AI meaning with its mark
132
+ * at 24, 20 and 16 px, its name and what it tells people. Put it in
133
+ * onboarding, help or settings so the marks are learned once. Highlight the
134
+ * meaning in use with `current`. Uses the glyphs the nearest
135
+ * `AiIconProvider` approved.
136
+ */
137
+ declare const AiIconLegend: React.ForwardRefExoticComponent<AiIconLegendProps & React.RefAttributes<HTMLElement>>;
111
138
 
112
- export { AiGeneratedIcon, type AiGlyphName, type AiGlyphProps, AiIcon, type AiIconGlyphs, type AiIconProps, AiIconProvider, type AiIconProviderProps, type AiIconRole, AiIcons, type AiIconsProps, type AiIconsSize, type AiIconsTone, type AiIconsVariant, AiRegenerateIcon, AiSparkleIcon, AiToolIcon, AiWandIcon, AiWorkingIcon, type AiWorkingIconProps, aiGlyphs, defaultAiIconGlyphs, useAiGlyph };
139
+ export { AiGeneratedIcon, type AiGlyphName, type AiGlyphProps, AiIcon, type AiIconGlyphs, AiIconLegend, type AiIconLegendProps, type AiIconLegendTerm, type AiIconProps, AiIconProvider, type AiIconProviderProps, type AiIconRole, AiIcons, type AiIconsProps, type AiIconsSize, type AiIconsTone, type AiIconsVariant, AiRegenerateIcon, AiSparkleIcon, AiToolIcon, AiWandIcon, AiWorkingIcon, type AiWorkingIconProps, aiGlyphs, defaultAiIconGlyphs, defaultAiIconLegendTerms, useAiGlyph };
package/dist/index.d.ts CHANGED
@@ -102,11 +102,38 @@ interface AiIconsProps extends React.HTMLAttributes<HTMLSpanElement> {
102
102
  }
103
103
  /**
104
104
  * The AI presence mark: one stable symbol that tells people the AI is here.
105
- * `sparkle` is the default; `thinking-orb` is the active state and pulses
105
+ * `sparkle` is the default; `thinking-orb` is the active state — a dark orb
106
+ * with a soft halo that pulses
106
107
  * (still under reduced motion — pair it with words such as an `AiIcon`
107
108
  * `agent-working` line); `branded-mark` carries your product's own shape.
108
109
  * Never a photo or a human face.
109
110
  */
110
111
  declare const AiIcons: React.ForwardRefExoticComponent<AiIconsProps & React.RefAttributes<HTMLSpanElement>>;
112
+ interface AiIconLegendTerm {
113
+ /** The AI meaning this row explains. */
114
+ role: AiIconRole;
115
+ /** Its name — "AI action". */
116
+ name: React.ReactNode;
117
+ /** What it tells people — "Pressing this runs AI on something specific." */
118
+ meaning: React.ReactNode;
119
+ }
120
+ /** The four meanings in the words nucleux.in uses. */
121
+ declare const defaultAiIconLegendTerms: AiIconLegendTerm[];
122
+ interface AiIconLegendProps extends React.HTMLAttributes<HTMLElement> {
123
+ /** Heading. Default "Icon language". */
124
+ heading?: React.ReactNode;
125
+ /** The rows. Defaults to {@link defaultAiIconLegendTerms}. */
126
+ terms?: AiIconLegendTerm[];
127
+ /** The meaning in use on this screen; its row is highlighted and marked `aria-current`. */
128
+ current?: AiIconRole;
129
+ }
130
+ /**
131
+ * The product's icon language, written down: each AI meaning with its mark
132
+ * at 24, 20 and 16 px, its name and what it tells people. Put it in
133
+ * onboarding, help or settings so the marks are learned once. Highlight the
134
+ * meaning in use with `current`. Uses the glyphs the nearest
135
+ * `AiIconProvider` approved.
136
+ */
137
+ declare const AiIconLegend: React.ForwardRefExoticComponent<AiIconLegendProps & React.RefAttributes<HTMLElement>>;
111
138
 
112
- export { AiGeneratedIcon, type AiGlyphName, type AiGlyphProps, AiIcon, type AiIconGlyphs, type AiIconProps, AiIconProvider, type AiIconProviderProps, type AiIconRole, AiIcons, type AiIconsProps, type AiIconsSize, type AiIconsTone, type AiIconsVariant, AiRegenerateIcon, AiSparkleIcon, AiToolIcon, AiWandIcon, AiWorkingIcon, type AiWorkingIconProps, aiGlyphs, defaultAiIconGlyphs, useAiGlyph };
139
+ export { AiGeneratedIcon, type AiGlyphName, type AiGlyphProps, AiIcon, type AiIconGlyphs, AiIconLegend, type AiIconLegendProps, type AiIconLegendTerm, type AiIconProps, AiIconProvider, type AiIconProviderProps, type AiIconRole, AiIcons, type AiIconsProps, type AiIconsSize, type AiIconsTone, type AiIconsVariant, AiRegenerateIcon, AiSparkleIcon, AiToolIcon, AiWandIcon, AiWorkingIcon, type AiWorkingIconProps, aiGlyphs, defaultAiIconGlyphs, defaultAiIconLegendTerms, useAiGlyph };
package/dist/index.js CHANGED
@@ -177,7 +177,7 @@ var AiIcons = React.forwardRef(
177
177
  "data-variant": variant,
178
178
  className: cn(
179
179
  base,
180
- "rounded-full bg-gradient-to-br from-brand to-primary shadow-sm",
180
+ "rounded-full bg-gradient-to-br from-primary/80 to-primary ring-4 ring-primary/10",
181
181
  aiColorClasses.working,
182
182
  sizeClasses[size],
183
183
  className
@@ -222,7 +222,49 @@ var AiIcons = React.forwardRef(
222
222
  }
223
223
  );
224
224
  AiIcons.displayName = "AiIcons";
225
+ var defaultAiIconLegendTerms = [
226
+ { role: "ai-action", name: "AI action", meaning: "Pressing this runs AI on something specific." },
227
+ { role: "generated-content", name: "AI-generated content", meaning: "This content was created or changed by AI." },
228
+ { role: "agent-working", name: "Agent working", meaning: "The agent is currently performing work." },
229
+ { role: "tool-use", name: "Tool use", meaning: "The agent used another tool or system." }
230
+ ];
231
+ function AiLegendGlyph({ role, className }) {
232
+ const Glyph = useAiGlyph(role);
233
+ return role === "agent-working" ? /* @__PURE__ */ jsx(AiWorkingIcon, { still: true, className }) : /* @__PURE__ */ jsx(Glyph, { className });
234
+ }
235
+ var AiIconLegend = React.forwardRef(
236
+ ({ heading = "Icon language", terms = defaultAiIconLegendTerms, current, className, ...props }, ref) => {
237
+ const headingId = React.useId();
238
+ return /* @__PURE__ */ jsxs("section", { ref, "aria-labelledby": headingId, className: cn("text-foreground", className), ...props, children: [
239
+ /* @__PURE__ */ jsx("h3", { id: headingId, className: "mb-3 mt-0 text-xs font-semibold uppercase tracking-wider text-muted-foreground", children: heading }),
240
+ /* @__PURE__ */ jsx("ul", { className: "m-0 list-none border-t border-border p-0", children: terms.map((term) => {
241
+ const here = term.role === current;
242
+ return /* @__PURE__ */ jsxs(
243
+ "li",
244
+ {
245
+ "aria-current": here || void 0,
246
+ className: cn(
247
+ "flex items-center gap-4 border-b border-l-[3px] border-b-border px-3 py-2.5 text-sm",
248
+ here ? "border-l-brand bg-muted" : "border-l-transparent"
249
+ ),
250
+ children: [
251
+ /* @__PURE__ */ jsxs("span", { "aria-hidden": "true", className: "flex w-[5.5rem] shrink-0 items-center gap-2.5 text-brand", children: [
252
+ /* @__PURE__ */ jsx(AiLegendGlyph, { role: term.role, className: "size-6" }),
253
+ /* @__PURE__ */ jsx(AiLegendGlyph, { role: term.role, className: "size-5" }),
254
+ /* @__PURE__ */ jsx(AiLegendGlyph, { role: term.role, className: "size-4" })
255
+ ] }),
256
+ /* @__PURE__ */ jsx("span", { className: "w-40 shrink-0 font-medium", children: term.name }),
257
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: term.meaning })
258
+ ]
259
+ },
260
+ term.role
261
+ );
262
+ }) })
263
+ ] });
264
+ }
265
+ );
266
+ AiIconLegend.displayName = "AiIconLegend";
225
267
 
226
- export { AiGeneratedIcon, AiIcon, AiIconProvider, AiIcons, AiRegenerateIcon, AiSparkleIcon, AiToolIcon, AiWandIcon, AiWorkingIcon, aiGlyphs, defaultAiIconGlyphs, useAiGlyph };
268
+ export { AiGeneratedIcon, AiIcon, AiIconLegend, AiIconProvider, AiIcons, AiRegenerateIcon, AiSparkleIcon, AiToolIcon, AiWandIcon, AiWorkingIcon, aiGlyphs, defaultAiIconGlyphs, defaultAiIconLegendTerms, useAiGlyph };
227
269
  //# sourceMappingURL=index.js.map
228
270
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.tsx"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import * as React from \"react\";\nimport { RefreshCw, WandSparkles, Wrench } from \"lucide-react\";\nimport { cn } from \"@nucleux/utils\";\nimport { aiColorClasses } from \"@nucleux/color\";\n\n/* -------------------------------------------------------------------------- */\n/* Glyphs */\n/* -------------------------------------------------------------------------- */\n\nexport type AiGlyphProps = React.SVGProps<SVGSVGElement>;\n\n/** Decorative unless the caller names it. */\nfunction glyphA11y(props: AiGlyphProps) {\n const named = props[\"aria-label\"] != null || props[\"aria-labelledby\"] != null;\n return named ? { role: \"img\" as const } : { \"aria-hidden\": true as const };\n}\n\n/**\n * The four-point AI sparkle — the reserved mark for \"this runs AI\" (generate).\n * The same drawing appears on the agent avatar and the disclosure chip.\n * Decorative (`aria-hidden`) unless given an `aria-label`.\n */\nexport const AiSparkleIcon = React.forwardRef<SVGSVGElement, AiGlyphProps>(({ className, ...props }, ref) => (\n <svg\n ref={ref}\n viewBox=\"0 0 24 24\"\n width={16}\n height={16}\n fill=\"currentColor\"\n focusable=\"false\"\n data-ai-glyph=\"sparkle\"\n className={cn(\"size-4 shrink-0\", className)}\n {...glyphA11y(props)}\n {...props}\n >\n <path d=\"M12 3c.6 4.8 3.2 7.4 9 9-5.8 1.6-8.4 4.2-9 9-.6-4.8-3.2-7.4-9-9 5.8-1.6 8.4-4.2 9-9z\" />\n </svg>\n));\nAiSparkleIcon.displayName = \"AiSparkleIcon\";\n\n/**\n * The \"generated with AI\" mark: a content outline carrying the sparkle. Used\n * only on content AI wrote or changed, never on controls.\n */\nexport const AiGeneratedIcon = React.forwardRef<SVGSVGElement, AiGlyphProps>(({ className, ...props }, ref) => (\n <svg\n ref={ref}\n viewBox=\"0 0 24 24\"\n width={16}\n height={16}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={1.8}\n strokeLinejoin=\"round\"\n focusable=\"false\"\n data-ai-glyph=\"generated\"\n className={cn(\"size-4 shrink-0\", className)}\n {...glyphA11y(props)}\n {...props}\n >\n <path d=\"M5 4h14a1 1 0 0 1 1 1v11a1 1 0 0 1-1 1h-7l-4 3v-3H5a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1z\" />\n <path\n d=\"M12 6.5c.3 2.2 1.3 3.2 3.5 3.5-2.2.3-3.2 1.3-3.5 3.5-.3-2.2-1.3-3.2-3.5-3.5 2.2-.3 3.2-1.3 3.5-3.5z\"\n fill=\"currentColor\"\n stroke=\"none\"\n />\n </svg>\n));\nAiGeneratedIcon.displayName = \"AiGeneratedIcon\";\n\nexport interface AiWorkingIconProps extends AiGlyphProps {\n /** Hold the mark still (it only turns while work is happening). */\n still?: boolean;\n}\n\n/**\n * The \"agent working\" mark: a turning arc. The only AI mark that moves, and\n * only while work is happening; it holds still under reduced motion.\n */\nexport const AiWorkingIcon = React.forwardRef<SVGSVGElement, AiWorkingIconProps>(\n ({ still = false, className, ...props }, ref) => (\n <svg\n ref={ref}\n viewBox=\"0 0 24 24\"\n width={16}\n height={16}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2.2}\n strokeLinecap=\"round\"\n focusable=\"false\"\n data-ai-glyph=\"working\"\n className={cn(\"size-4 shrink-0\", !still && \"animate-spin motion-reduce:animate-none\", className)}\n {...glyphA11y(props)}\n {...props}\n >\n <circle cx=\"12\" cy=\"12\" r=\"8.5\" opacity={0.25} />\n <path d=\"M12 3.5a8.5 8.5 0 0 1 8.5 8.5\" />\n </svg>\n ),\n);\nAiWorkingIcon.displayName = \"AiWorkingIcon\";\n\nfunction lucideGlyph(Icon: React.ComponentType<AiGlyphProps>, name: string, displayName: string) {\n const Glyph = React.forwardRef<SVGSVGElement, AiGlyphProps>(({ className, ...props }, ref) => (\n <Icon\n ref={ref}\n focusable=\"false\"\n data-ai-glyph={name}\n className={cn(\"size-4 shrink-0\", className)}\n {...glyphA11y(props)}\n {...props}\n />\n ));\n Glyph.displayName = displayName;\n return Glyph;\n}\n\n/** The \"transform\" mark (wand): for AI actions that change something the user already has — rewrite, enhance, restyle. */\nexport const AiWandIcon = lucideGlyph(\n WandSparkles as unknown as React.ComponentType<AiGlyphProps>,\n \"wand\",\n \"AiWandIcon\",\n);\n/** The \"regenerate\" mark: run the same AI action again. */\nexport const AiRegenerateIcon = lucideGlyph(\n RefreshCw as unknown as React.ComponentType<AiGlyphProps>,\n \"regenerate\",\n \"AiRegenerateIcon\",\n);\n/** The \"tool use\" mark: on the lines that say which tool the agent used. */\nexport const AiToolIcon = lucideGlyph(Wrench as unknown as React.ComponentType<AiGlyphProps>, \"tool\", \"AiToolIcon\");\n\n/* -------------------------------------------------------------------------- */\n/* Roles and the approved glyph lists */\n/* -------------------------------------------------------------------------- */\n\n/** The four AI meanings. Each has its own mark, used for that meaning only. */\nexport type AiIconRole = \"ai-action\" | \"generated-content\" | \"agent-working\" | \"tool-use\";\n\n/** Every reserved glyph by name. */\nexport type AiGlyphName = \"sparkle\" | \"wand\" | \"regenerate\" | \"generated\" | \"working\" | \"tool\";\n\n/**\n * Approved glyphs per role. The lists do not overlap, so two meanings can\n * never share a mark.\n */\nexport interface AiIconGlyphs {\n \"ai-action\"?: \"sparkle\" | \"wand\";\n \"generated-content\"?: \"generated\";\n \"agent-working\"?: \"working\";\n \"tool-use\"?: \"tool\";\n}\n\n/** The reserved glyph components, by name. */\nexport const aiGlyphs: Record<AiGlyphName, React.ComponentType<AiGlyphProps>> = {\n sparkle: AiSparkleIcon,\n wand: AiWandIcon,\n regenerate: AiRegenerateIcon,\n generated: AiGeneratedIcon,\n working: AiWorkingIcon,\n tool: AiToolIcon,\n};\n\n/** The default glyph for each role. */\nexport const defaultAiIconGlyphs: Required<AiIconGlyphs> = {\n \"ai-action\": \"sparkle\",\n \"generated-content\": \"generated\",\n \"agent-working\": \"working\",\n \"tool-use\": \"tool\",\n};\n\nconst AiIconContext = React.createContext<Required<AiIconGlyphs>>(defaultAiIconGlyphs);\n\nexport interface AiIconProviderProps {\n /** Product-wide choice of approved glyph per role. Set once; unset roles keep the default. */\n glyphs?: AiIconGlyphs;\n children?: React.ReactNode;\n}\n\n/**\n * Sets the approved glyph for each AI role once for the whole product.\n * Every `AiIcon`, `AiIcons`, `Iconography` and `Disclosure` under it uses\n * the same choice, so a meaning keeps one mark everywhere.\n */\nexport function AiIconProvider({ glyphs, children }: AiIconProviderProps) {\n const value = React.useMemo(() => ({ ...defaultAiIconGlyphs, ...glyphs }), [glyphs]);\n return <AiIconContext.Provider value={value}>{children}</AiIconContext.Provider>;\n}\nAiIconProvider.displayName = \"AiIconProvider\";\n\n/** The glyph component the nearest `AiIconProvider` approved for a role. */\nexport function useAiGlyph(role: AiIconRole): React.ComponentType<AiGlyphProps> {\n const glyphs = React.useContext(AiIconContext);\n return aiGlyphs[glyphs[role]];\n}\n\n/* -------------------------------------------------------------------------- */\n/* AiIcon — a meaning, with its mark and its words */\n/* -------------------------------------------------------------------------- */\n\nexport interface AiIconProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, \"role\"> {\n /**\n * Which AI meaning this is: `ai-action` (a control runs AI),\n * `generated-content` (AI wrote this), `agent-working` (the agent is\n * working now — announced politely) or `tool-use` (the agent used a tool).\n */\n role: AiIconRole;\n /** The words that travel with the mark (\"Rewrite\", \"Generated with AI\", \"Rewriting release note…\"). Required: a mark is never alone. */\n label: React.ReactNode;\n /** Show the words visibly (default) or keep them for assistive tech only. */\n showLabel?: boolean;\n}\n\nconst roleClasses: Record<AiIconRole, string> = {\n \"ai-action\": \"text-foreground [&>svg]:text-brand\",\n \"agent-working\": \"text-foreground [&>svg]:text-brand\",\n \"tool-use\": \"text-muted-foreground\",\n \"generated-content\":\n \"rounded-full border border-brand/30 bg-background px-2 py-0.5 text-xs font-medium text-foreground [&>svg]:size-3.5 [&>svg]:text-brand\",\n};\n\n/**\n * One AI meaning drawn with its reserved mark and its words. The product\n * names the meaning; the component maps it to the approved glyph (see\n * `AiIconProvider`). `agent-working` turns its mark and announces its words\n * in a polite live region; the rest are static. For a control that runs\n * AI, use `Iconography`, which puts the `ai-action` mark on a Button.\n */\nexport const AiIcon = React.forwardRef<HTMLSpanElement, AiIconProps>(\n ({ role, label, showLabel = true, className, ...props }, ref) => {\n const Glyph = useAiGlyph(role);\n return (\n <span\n ref={ref}\n data-ai-role={role}\n role={role === \"agent-working\" ? \"status\" : undefined}\n aria-live={role === \"agent-working\" ? \"polite\" : undefined}\n className={cn(\"inline-flex items-center gap-1.5 text-sm\", roleClasses[role], className)}\n {...props}\n >\n <Glyph />\n <span className={showLabel ? undefined : \"sr-only\"}>{label}</span>\n </span>\n );\n },\n);\nAiIcon.displayName = \"AiIcon\";\n\n/* -------------------------------------------------------------------------- */\n/* AiIcons — the AI presence mark */\n/* -------------------------------------------------------------------------- */\n\nexport type AiIconsVariant = \"sparkle\" | \"thinking-orb\" | \"branded-mark\";\nexport type AiIconsSize = \"sm\" | \"md\" | \"lg\";\nexport type AiIconsTone = \"solid\" | \"outline\";\n\nconst sizeClasses: Record<AiIconsSize, string> = {\n sm: \"size-6 text-xs [&>svg]:size-3.5\",\n md: \"size-8 text-sm [&>svg]:size-4\",\n lg: \"size-10 text-lg [&>svg]:size-5\",\n};\n\nexport interface AiIconsProps extends React.HTMLAttributes<HTMLSpanElement> {\n /**\n * `sparkle` (the universal \"AI\" mark in a tile), `thinking-orb` (an\n * animated orb for active, listening or generating states) or\n * `branded-mark` (your product's own shape or letter).\n */\n variant?: AiIconsVariant;\n /** 24 / 32 / 40 px. */\n size?: AiIconsSize;\n /** `solid` (filled tile) or `outline` (bordered tile). Sparkle and branded mark only. */\n tone?: AiIconsTone;\n /** Accessible name. Omit when words sit beside the mark — it is then decorative. */\n label?: string;\n /** Content of the branded mark (a letter or your SVG). Defaults to the first letter of `label`, else the sparkle. */\n glyph?: React.ReactNode;\n}\n\n/**\n * The AI presence mark: one stable symbol that tells people the AI is here.\n * `sparkle` is the default; `thinking-orb` is the active state and pulses\n * (still under reduced motion — pair it with words such as an `AiIcon`\n * `agent-working` line); `branded-mark` carries your product's own shape.\n * Never a photo or a human face.\n */\nexport const AiIcons = React.forwardRef<HTMLSpanElement, AiIconsProps>(\n ({ variant = \"sparkle\", size = \"md\", tone = \"solid\", label, glyph, className, ...props }, ref) => {\n const Sparkle = useAiGlyph(\"ai-action\");\n const a11y = label ? { role: \"img\" as const, \"aria-label\": label } : { \"aria-hidden\": true as const };\n const base = \"inline-grid shrink-0 place-items-center font-semibold\";\n\n if (variant === \"thinking-orb\") {\n return (\n <span\n ref={ref}\n data-variant={variant}\n className={cn(\n base,\n \"rounded-full bg-gradient-to-br from-brand to-primary shadow-sm\",\n aiColorClasses.working,\n sizeClasses[size],\n className,\n )}\n {...a11y}\n {...props}\n />\n );\n }\n\n const toneClasses =\n tone === \"solid\"\n ? \"bg-primary text-primary-foreground\"\n : \"border border-border bg-background text-foreground\";\n\n if (variant === \"branded-mark\") {\n const content = glyph ?? (label ? label.charAt(0).toLowerCase() : <Sparkle />);\n return (\n <span\n ref={ref}\n data-variant={variant}\n className={cn(\n base,\n \"rounded-[28%] font-serif italic\",\n tone === \"solid\" ? \"bg-gradient-to-br from-primary to-primary/70 text-primary-foreground\" : toneClasses,\n sizeClasses[size],\n className,\n )}\n {...a11y}\n {...props}\n >\n {content}\n </span>\n );\n }\n\n return (\n <span\n ref={ref}\n data-variant={variant}\n className={cn(base, \"rounded-[22%]\", toneClasses, sizeClasses[size], className)}\n {...a11y}\n {...props}\n >\n <Sparkle />\n </span>\n );\n },\n);\nAiIcons.displayName = \"AiIcons\";\n"]}
1
+ {"version":3,"sources":["../src/index.tsx"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import * as React from \"react\";\nimport { RefreshCw, WandSparkles, Wrench } from \"lucide-react\";\nimport { cn } from \"@nucleux/utils\";\nimport { aiColorClasses } from \"@nucleux/color\";\n\n/* -------------------------------------------------------------------------- */\n/* Glyphs */\n/* -------------------------------------------------------------------------- */\n\nexport type AiGlyphProps = React.SVGProps<SVGSVGElement>;\n\n/** Decorative unless the caller names it. */\nfunction glyphA11y(props: AiGlyphProps) {\n const named = props[\"aria-label\"] != null || props[\"aria-labelledby\"] != null;\n return named ? { role: \"img\" as const } : { \"aria-hidden\": true as const };\n}\n\n/**\n * The four-point AI sparkle — the reserved mark for \"this runs AI\" (generate).\n * The same drawing appears on the agent avatar and the disclosure chip.\n * Decorative (`aria-hidden`) unless given an `aria-label`.\n */\nexport const AiSparkleIcon = React.forwardRef<SVGSVGElement, AiGlyphProps>(({ className, ...props }, ref) => (\n <svg\n ref={ref}\n viewBox=\"0 0 24 24\"\n width={16}\n height={16}\n fill=\"currentColor\"\n focusable=\"false\"\n data-ai-glyph=\"sparkle\"\n className={cn(\"size-4 shrink-0\", className)}\n {...glyphA11y(props)}\n {...props}\n >\n <path d=\"M12 3c.6 4.8 3.2 7.4 9 9-5.8 1.6-8.4 4.2-9 9-.6-4.8-3.2-7.4-9-9 5.8-1.6 8.4-4.2 9-9z\" />\n </svg>\n));\nAiSparkleIcon.displayName = \"AiSparkleIcon\";\n\n/**\n * The \"generated with AI\" mark: a content outline carrying the sparkle. Used\n * only on content AI wrote or changed, never on controls.\n */\nexport const AiGeneratedIcon = React.forwardRef<SVGSVGElement, AiGlyphProps>(({ className, ...props }, ref) => (\n <svg\n ref={ref}\n viewBox=\"0 0 24 24\"\n width={16}\n height={16}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={1.8}\n strokeLinejoin=\"round\"\n focusable=\"false\"\n data-ai-glyph=\"generated\"\n className={cn(\"size-4 shrink-0\", className)}\n {...glyphA11y(props)}\n {...props}\n >\n <path d=\"M5 4h14a1 1 0 0 1 1 1v11a1 1 0 0 1-1 1h-7l-4 3v-3H5a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1z\" />\n <path\n d=\"M12 6.5c.3 2.2 1.3 3.2 3.5 3.5-2.2.3-3.2 1.3-3.5 3.5-.3-2.2-1.3-3.2-3.5-3.5 2.2-.3 3.2-1.3 3.5-3.5z\"\n fill=\"currentColor\"\n stroke=\"none\"\n />\n </svg>\n));\nAiGeneratedIcon.displayName = \"AiGeneratedIcon\";\n\nexport interface AiWorkingIconProps extends AiGlyphProps {\n /** Hold the mark still (it only turns while work is happening). */\n still?: boolean;\n}\n\n/**\n * The \"agent working\" mark: a turning arc. The only AI mark that moves, and\n * only while work is happening; it holds still under reduced motion.\n */\nexport const AiWorkingIcon = React.forwardRef<SVGSVGElement, AiWorkingIconProps>(\n ({ still = false, className, ...props }, ref) => (\n <svg\n ref={ref}\n viewBox=\"0 0 24 24\"\n width={16}\n height={16}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2.2}\n strokeLinecap=\"round\"\n focusable=\"false\"\n data-ai-glyph=\"working\"\n className={cn(\"size-4 shrink-0\", !still && \"animate-spin motion-reduce:animate-none\", className)}\n {...glyphA11y(props)}\n {...props}\n >\n <circle cx=\"12\" cy=\"12\" r=\"8.5\" opacity={0.25} />\n <path d=\"M12 3.5a8.5 8.5 0 0 1 8.5 8.5\" />\n </svg>\n ),\n);\nAiWorkingIcon.displayName = \"AiWorkingIcon\";\n\nfunction lucideGlyph(Icon: React.ComponentType<AiGlyphProps>, name: string, displayName: string) {\n const Glyph = React.forwardRef<SVGSVGElement, AiGlyphProps>(({ className, ...props }, ref) => (\n <Icon\n ref={ref}\n focusable=\"false\"\n data-ai-glyph={name}\n className={cn(\"size-4 shrink-0\", className)}\n {...glyphA11y(props)}\n {...props}\n />\n ));\n Glyph.displayName = displayName;\n return Glyph;\n}\n\n/** The \"transform\" mark (wand): for AI actions that change something the user already has — rewrite, enhance, restyle. */\nexport const AiWandIcon = lucideGlyph(\n WandSparkles as unknown as React.ComponentType<AiGlyphProps>,\n \"wand\",\n \"AiWandIcon\",\n);\n/** The \"regenerate\" mark: run the same AI action again. */\nexport const AiRegenerateIcon = lucideGlyph(\n RefreshCw as unknown as React.ComponentType<AiGlyphProps>,\n \"regenerate\",\n \"AiRegenerateIcon\",\n);\n/** The \"tool use\" mark: on the lines that say which tool the agent used. */\nexport const AiToolIcon = lucideGlyph(Wrench as unknown as React.ComponentType<AiGlyphProps>, \"tool\", \"AiToolIcon\");\n\n/* -------------------------------------------------------------------------- */\n/* Roles and the approved glyph lists */\n/* -------------------------------------------------------------------------- */\n\n/** The four AI meanings. Each has its own mark, used for that meaning only. */\nexport type AiIconRole = \"ai-action\" | \"generated-content\" | \"agent-working\" | \"tool-use\";\n\n/** Every reserved glyph by name. */\nexport type AiGlyphName = \"sparkle\" | \"wand\" | \"regenerate\" | \"generated\" | \"working\" | \"tool\";\n\n/**\n * Approved glyphs per role. The lists do not overlap, so two meanings can\n * never share a mark.\n */\nexport interface AiIconGlyphs {\n \"ai-action\"?: \"sparkle\" | \"wand\";\n \"generated-content\"?: \"generated\";\n \"agent-working\"?: \"working\";\n \"tool-use\"?: \"tool\";\n}\n\n/** The reserved glyph components, by name. */\nexport const aiGlyphs: Record<AiGlyphName, React.ComponentType<AiGlyphProps>> = {\n sparkle: AiSparkleIcon,\n wand: AiWandIcon,\n regenerate: AiRegenerateIcon,\n generated: AiGeneratedIcon,\n working: AiWorkingIcon,\n tool: AiToolIcon,\n};\n\n/** The default glyph for each role. */\nexport const defaultAiIconGlyphs: Required<AiIconGlyphs> = {\n \"ai-action\": \"sparkle\",\n \"generated-content\": \"generated\",\n \"agent-working\": \"working\",\n \"tool-use\": \"tool\",\n};\n\nconst AiIconContext = React.createContext<Required<AiIconGlyphs>>(defaultAiIconGlyphs);\n\nexport interface AiIconProviderProps {\n /** Product-wide choice of approved glyph per role. Set once; unset roles keep the default. */\n glyphs?: AiIconGlyphs;\n children?: React.ReactNode;\n}\n\n/**\n * Sets the approved glyph for each AI role once for the whole product.\n * Every `AiIcon`, `AiIcons`, `Iconography` and `Disclosure` under it uses\n * the same choice, so a meaning keeps one mark everywhere.\n */\nexport function AiIconProvider({ glyphs, children }: AiIconProviderProps) {\n const value = React.useMemo(() => ({ ...defaultAiIconGlyphs, ...glyphs }), [glyphs]);\n return <AiIconContext.Provider value={value}>{children}</AiIconContext.Provider>;\n}\nAiIconProvider.displayName = \"AiIconProvider\";\n\n/** The glyph component the nearest `AiIconProvider` approved for a role. */\nexport function useAiGlyph(role: AiIconRole): React.ComponentType<AiGlyphProps> {\n const glyphs = React.useContext(AiIconContext);\n return aiGlyphs[glyphs[role]];\n}\n\n/* -------------------------------------------------------------------------- */\n/* AiIcon — a meaning, with its mark and its words */\n/* -------------------------------------------------------------------------- */\n\nexport interface AiIconProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, \"role\"> {\n /**\n * Which AI meaning this is: `ai-action` (a control runs AI),\n * `generated-content` (AI wrote this), `agent-working` (the agent is\n * working now — announced politely) or `tool-use` (the agent used a tool).\n */\n role: AiIconRole;\n /** The words that travel with the mark (\"Rewrite\", \"Generated with AI\", \"Rewriting release note…\"). Required: a mark is never alone. */\n label: React.ReactNode;\n /** Show the words visibly (default) or keep them for assistive tech only. */\n showLabel?: boolean;\n}\n\nconst roleClasses: Record<AiIconRole, string> = {\n \"ai-action\": \"text-foreground [&>svg]:text-brand\",\n \"agent-working\": \"text-foreground [&>svg]:text-brand\",\n \"tool-use\": \"text-muted-foreground\",\n \"generated-content\":\n \"rounded-full border border-brand/30 bg-background px-2 py-0.5 text-xs font-medium text-foreground [&>svg]:size-3.5 [&>svg]:text-brand\",\n};\n\n/**\n * One AI meaning drawn with its reserved mark and its words. The product\n * names the meaning; the component maps it to the approved glyph (see\n * `AiIconProvider`). `agent-working` turns its mark and announces its words\n * in a polite live region; the rest are static. For a control that runs\n * AI, use `Iconography`, which puts the `ai-action` mark on a Button.\n */\nexport const AiIcon = React.forwardRef<HTMLSpanElement, AiIconProps>(\n ({ role, label, showLabel = true, className, ...props }, ref) => {\n const Glyph = useAiGlyph(role);\n return (\n <span\n ref={ref}\n data-ai-role={role}\n role={role === \"agent-working\" ? \"status\" : undefined}\n aria-live={role === \"agent-working\" ? \"polite\" : undefined}\n className={cn(\"inline-flex items-center gap-1.5 text-sm\", roleClasses[role], className)}\n {...props}\n >\n <Glyph />\n <span className={showLabel ? undefined : \"sr-only\"}>{label}</span>\n </span>\n );\n },\n);\nAiIcon.displayName = \"AiIcon\";\n\n/* -------------------------------------------------------------------------- */\n/* AiIcons — the AI presence mark */\n/* -------------------------------------------------------------------------- */\n\nexport type AiIconsVariant = \"sparkle\" | \"thinking-orb\" | \"branded-mark\";\nexport type AiIconsSize = \"sm\" | \"md\" | \"lg\";\nexport type AiIconsTone = \"solid\" | \"outline\";\n\nconst sizeClasses: Record<AiIconsSize, string> = {\n sm: \"size-6 text-xs [&>svg]:size-3.5\",\n md: \"size-8 text-sm [&>svg]:size-4\",\n lg: \"size-10 text-lg [&>svg]:size-5\",\n};\n\nexport interface AiIconsProps extends React.HTMLAttributes<HTMLSpanElement> {\n /**\n * `sparkle` (the universal \"AI\" mark in a tile), `thinking-orb` (an\n * animated orb for active, listening or generating states) or\n * `branded-mark` (your product's own shape or letter).\n */\n variant?: AiIconsVariant;\n /** 24 / 32 / 40 px. */\n size?: AiIconsSize;\n /** `solid` (filled tile) or `outline` (bordered tile). Sparkle and branded mark only. */\n tone?: AiIconsTone;\n /** Accessible name. Omit when words sit beside the mark — it is then decorative. */\n label?: string;\n /** Content of the branded mark (a letter or your SVG). Defaults to the first letter of `label`, else the sparkle. */\n glyph?: React.ReactNode;\n}\n\n/**\n * The AI presence mark: one stable symbol that tells people the AI is here.\n * `sparkle` is the default; `thinking-orb` is the active state — a dark orb\n * with a soft halo that pulses\n * (still under reduced motion — pair it with words such as an `AiIcon`\n * `agent-working` line); `branded-mark` carries your product's own shape.\n * Never a photo or a human face.\n */\nexport const AiIcons = React.forwardRef<HTMLSpanElement, AiIconsProps>(\n ({ variant = \"sparkle\", size = \"md\", tone = \"solid\", label, glyph, className, ...props }, ref) => {\n const Sparkle = useAiGlyph(\"ai-action\");\n const a11y = label ? { role: \"img\" as const, \"aria-label\": label } : { \"aria-hidden\": true as const };\n const base = \"inline-grid shrink-0 place-items-center font-semibold\";\n\n if (variant === \"thinking-orb\") {\n return (\n <span\n ref={ref}\n data-variant={variant}\n className={cn(\n base,\n \"rounded-full bg-gradient-to-br from-primary/80 to-primary ring-4 ring-primary/10\",\n aiColorClasses.working,\n sizeClasses[size],\n className,\n )}\n {...a11y}\n {...props}\n />\n );\n }\n\n const toneClasses =\n tone === \"solid\"\n ? \"bg-primary text-primary-foreground\"\n : \"border border-border bg-background text-foreground\";\n\n if (variant === \"branded-mark\") {\n const content = glyph ?? (label ? label.charAt(0).toLowerCase() : <Sparkle />);\n return (\n <span\n ref={ref}\n data-variant={variant}\n className={cn(\n base,\n \"rounded-[28%] font-serif italic\",\n tone === \"solid\" ? \"bg-gradient-to-br from-primary to-primary/70 text-primary-foreground\" : toneClasses,\n sizeClasses[size],\n className,\n )}\n {...a11y}\n {...props}\n >\n {content}\n </span>\n );\n }\n\n return (\n <span\n ref={ref}\n data-variant={variant}\n className={cn(base, \"rounded-[22%]\", toneClasses, sizeClasses[size], className)}\n {...a11y}\n {...props}\n >\n <Sparkle />\n </span>\n );\n },\n);\nAiIcons.displayName = \"AiIcons\";\n\n/* -------------------------------------------------------------------------- */\n/* AiIconLegend — the icon language, written down */\n/* -------------------------------------------------------------------------- */\n\nexport interface AiIconLegendTerm {\n /** The AI meaning this row explains. */\n role: AiIconRole;\n /** Its name — \"AI action\". */\n name: React.ReactNode;\n /** What it tells people — \"Pressing this runs AI on something specific.\" */\n meaning: React.ReactNode;\n}\n\n/** The four meanings in the words nucleux.in uses. */\nexport const defaultAiIconLegendTerms: AiIconLegendTerm[] = [\n { role: \"ai-action\", name: \"AI action\", meaning: \"Pressing this runs AI on something specific.\" },\n { role: \"generated-content\", name: \"AI-generated content\", meaning: \"This content was created or changed by AI.\" },\n { role: \"agent-working\", name: \"Agent working\", meaning: \"The agent is currently performing work.\" },\n { role: \"tool-use\", name: \"Tool use\", meaning: \"The agent used another tool or system.\" },\n];\n\nexport interface AiIconLegendProps extends React.HTMLAttributes<HTMLElement> {\n /** Heading. Default \"Icon language\". */\n heading?: React.ReactNode;\n /** The rows. Defaults to {@link defaultAiIconLegendTerms}. */\n terms?: AiIconLegendTerm[];\n /** The meaning in use on this screen; its row is highlighted and marked `aria-current`. */\n current?: AiIconRole;\n}\n\n/** The approved glyph for a role, drawn still (the legend never animates). */\nfunction AiLegendGlyph({ role, className }: { role: AiIconRole; className?: string }) {\n const Glyph = useAiGlyph(role);\n return role === \"agent-working\" ? <AiWorkingIcon still className={className} /> : <Glyph className={className} />;\n}\n\n/**\n * The product's icon language, written down: each AI meaning with its mark\n * at 24, 20 and 16 px, its name and what it tells people. Put it in\n * onboarding, help or settings so the marks are learned once. Highlight the\n * meaning in use with `current`. Uses the glyphs the nearest\n * `AiIconProvider` approved.\n */\nexport const AiIconLegend = React.forwardRef<HTMLElement, AiIconLegendProps>(\n ({ heading = \"Icon language\", terms = defaultAiIconLegendTerms, current, className, ...props }, ref) => {\n const headingId = React.useId();\n return (\n <section ref={ref} aria-labelledby={headingId} className={cn(\"text-foreground\", className)} {...props}>\n <h3 id={headingId} className=\"mb-3 mt-0 text-xs font-semibold uppercase tracking-wider text-muted-foreground\">\n {heading}\n </h3>\n <ul className=\"m-0 list-none border-t border-border p-0\">\n {terms.map((term) => {\n const here = term.role === current;\n return (\n <li\n key={term.role}\n aria-current={here || undefined}\n className={cn(\n \"flex items-center gap-4 border-b border-l-[3px] border-b-border px-3 py-2.5 text-sm\",\n here ? \"border-l-brand bg-muted\" : \"border-l-transparent\",\n )}\n >\n <span aria-hidden=\"true\" className=\"flex w-[5.5rem] shrink-0 items-center gap-2.5 text-brand\">\n <AiLegendGlyph role={term.role} className=\"size-6\" />\n <AiLegendGlyph role={term.role} className=\"size-5\" />\n <AiLegendGlyph role={term.role} className=\"size-4\" />\n </span>\n <span className=\"w-40 shrink-0 font-medium\">{term.name}</span>\n <span className=\"text-muted-foreground\">{term.meaning}</span>\n </li>\n );\n })}\n </ul>\n </section>\n );\n },\n);\nAiIconLegend.displayName = \"AiIconLegend\";\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nucleux/ai-icons",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "description": "Icons — a small, stable AI mark vocabulary: action, generated, working and tool use — Nucleux agentic UI for React.",
@@ -33,8 +33,10 @@
33
33
  "react-dom": ">=18"
34
34
  },
35
35
  "dependencies": {
36
- "@nucleux/color": "0.9.0",
37
- "@nucleux/utils": "0.9.0",
36
+ "@nucleux/button": "0.10.0",
37
+ "@nucleux/card": "0.10.0",
38
+ "@nucleux/color": "0.10.0",
39
+ "@nucleux/utils": "0.10.0",
38
40
  "lucide-react": "^0.469.0"
39
41
  },
40
42
  "devDependencies": {