@nucleux/ai-icons 0.0.0-stage → 0.7.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/LICENSE +21 -0
- package/README.md +46 -2
- package/dist/index.cjs +261 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +112 -0
- package/dist/index.d.ts +112 -0
- package/dist/index.js +228 -0
- package/dist/index.js.map +1 -0
- package/package.json +56 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nucleux
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,47 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @nucleux/ai-icons
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Icons — a small, stable AI mark vocabulary: action, generated, working and tool use — Nucleux agentic UI for React.
|
|
4
|
+
|
|
5
|
+
Part of **[Nucleux](https://github.com/intelligaia-open-labs/nucleux)** — agentic UI components for React. Install a single component, or the full kit via [`@nucleux/react`](https://www.npmjs.com/package/@nucleux/react).
|
|
6
|
+
|
|
7
|
+
## Exports
|
|
8
|
+
|
|
9
|
+
- **`AiIcons`** — the AI presence mark. `variant`: `sparkle` (default) / `thinking-orb` (animated, for active states) / `branded-mark`; `size` sm/md/lg (24/32/40); `tone` solid/outline; `label` (accessible name — omit when words sit beside it); `glyph` (branded-mark content)
|
|
10
|
+
- **`AiIcon`** — one AI *meaning* with its mark and its words. `role`: `ai-action` / `generated-content` / `agent-working` (turns, announced in a polite live region) / `tool-use`; `label` (required); `showLabel`
|
|
11
|
+
- **`AiIconProvider`** (`glyphs`) + **`useAiGlyph(role)`** — choose the approved glyph per role once for the whole product; the approved lists don't overlap
|
|
12
|
+
- Glyphs: **`AiSparkleIcon`**, **`AiGeneratedIcon`**, **`AiWorkingIcon`** (`still`), **`AiWandIcon`**, **`AiRegenerateIcon`**, **`AiToolIcon`**; maps **`aiGlyphs`**, **`defaultAiIconGlyphs`**
|
|
13
|
+
|
|
14
|
+
## Rules
|
|
15
|
+
|
|
16
|
+
- The sparkle is the universal default; the orb is for active state only; never a photo or human face.
|
|
17
|
+
- Every mark travels with words — a visible label, or an accessible name.
|
|
18
|
+
- Only the working mark moves, only while work happens, and it holds still under reduced motion.
|
|
19
|
+
- `@nucleux/iconography`, `@nucleux/agent-avatar` and `@nucleux/disclosure` draw from these same glyphs.
|
|
20
|
+
|
|
21
|
+
## Install
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pnpm add @nucleux/ai-icons @nucleux/tokens
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
`react` / `react-dom` are peer dependencies.
|
|
28
|
+
|
|
29
|
+
## Usage
|
|
30
|
+
|
|
31
|
+
```tsx
|
|
32
|
+
import { AiIcons, AiIcon, AiIconProvider } from "@nucleux/ai-icons";
|
|
33
|
+
|
|
34
|
+
<AiIcon role="ai-action" label="Rewrite" />
|
|
35
|
+
<AiIcon role="agent-working" label="Rewriting release note…" />
|
|
36
|
+
<AiIcon role="generated-content" label="Generated with AI" />
|
|
37
|
+
<AiIcons variant="thinking-orb" /> <span role="status">Aria is thinking…</span>
|
|
38
|
+
|
|
39
|
+
<AiIconProvider glyphs={{ "ai-action": "wand" }}>{app}</AiIconProvider>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Requires the theme once in your app: `import "@nucleux/tokens/styles.css";`
|
|
43
|
+
and the Tailwind preset from `@nucleux/tokens/preset`.
|
|
44
|
+
|
|
45
|
+
## License
|
|
46
|
+
|
|
47
|
+
MIT © Nucleux
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var React = require('react');
|
|
5
|
+
var lucideReact = require('lucide-react');
|
|
6
|
+
var utils = require('@nucleux/utils');
|
|
7
|
+
var color = require('@nucleux/color');
|
|
8
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
9
|
+
|
|
10
|
+
function _interopNamespace(e) {
|
|
11
|
+
if (e && e.__esModule) return e;
|
|
12
|
+
var n = Object.create(null);
|
|
13
|
+
if (e) {
|
|
14
|
+
Object.keys(e).forEach(function (k) {
|
|
15
|
+
if (k !== 'default') {
|
|
16
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
17
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
18
|
+
enumerable: true,
|
|
19
|
+
get: function () { return e[k]; }
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
n.default = e;
|
|
25
|
+
return Object.freeze(n);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
29
|
+
|
|
30
|
+
// src/index.tsx
|
|
31
|
+
function glyphA11y(props) {
|
|
32
|
+
const named = props["aria-label"] != null || props["aria-labelledby"] != null;
|
|
33
|
+
return named ? { role: "img" } : { "aria-hidden": true };
|
|
34
|
+
}
|
|
35
|
+
var AiSparkleIcon = React__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
36
|
+
"svg",
|
|
37
|
+
{
|
|
38
|
+
ref,
|
|
39
|
+
viewBox: "0 0 24 24",
|
|
40
|
+
width: 16,
|
|
41
|
+
height: 16,
|
|
42
|
+
fill: "currentColor",
|
|
43
|
+
focusable: "false",
|
|
44
|
+
"data-ai-glyph": "sparkle",
|
|
45
|
+
className: utils.cn("size-4 shrink-0", className),
|
|
46
|
+
...glyphA11y(props),
|
|
47
|
+
...props,
|
|
48
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("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" })
|
|
49
|
+
}
|
|
50
|
+
));
|
|
51
|
+
AiSparkleIcon.displayName = "AiSparkleIcon";
|
|
52
|
+
var AiGeneratedIcon = React__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
53
|
+
"svg",
|
|
54
|
+
{
|
|
55
|
+
ref,
|
|
56
|
+
viewBox: "0 0 24 24",
|
|
57
|
+
width: 16,
|
|
58
|
+
height: 16,
|
|
59
|
+
fill: "none",
|
|
60
|
+
stroke: "currentColor",
|
|
61
|
+
strokeWidth: 1.8,
|
|
62
|
+
strokeLinejoin: "round",
|
|
63
|
+
focusable: "false",
|
|
64
|
+
"data-ai-glyph": "generated",
|
|
65
|
+
className: utils.cn("size-4 shrink-0", className),
|
|
66
|
+
...glyphA11y(props),
|
|
67
|
+
...props,
|
|
68
|
+
children: [
|
|
69
|
+
/* @__PURE__ */ jsxRuntime.jsx("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" }),
|
|
70
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
71
|
+
"path",
|
|
72
|
+
{
|
|
73
|
+
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",
|
|
74
|
+
fill: "currentColor",
|
|
75
|
+
stroke: "none"
|
|
76
|
+
}
|
|
77
|
+
)
|
|
78
|
+
]
|
|
79
|
+
}
|
|
80
|
+
));
|
|
81
|
+
AiGeneratedIcon.displayName = "AiGeneratedIcon";
|
|
82
|
+
var AiWorkingIcon = React__namespace.forwardRef(
|
|
83
|
+
({ still = false, className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
84
|
+
"svg",
|
|
85
|
+
{
|
|
86
|
+
ref,
|
|
87
|
+
viewBox: "0 0 24 24",
|
|
88
|
+
width: 16,
|
|
89
|
+
height: 16,
|
|
90
|
+
fill: "none",
|
|
91
|
+
stroke: "currentColor",
|
|
92
|
+
strokeWidth: 2.2,
|
|
93
|
+
strokeLinecap: "round",
|
|
94
|
+
focusable: "false",
|
|
95
|
+
"data-ai-glyph": "working",
|
|
96
|
+
className: utils.cn("size-4 shrink-0", !still && "animate-spin motion-reduce:animate-none", className),
|
|
97
|
+
...glyphA11y(props),
|
|
98
|
+
...props,
|
|
99
|
+
children: [
|
|
100
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "8.5", opacity: 0.25 }),
|
|
101
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 3.5a8.5 8.5 0 0 1 8.5 8.5" })
|
|
102
|
+
]
|
|
103
|
+
}
|
|
104
|
+
)
|
|
105
|
+
);
|
|
106
|
+
AiWorkingIcon.displayName = "AiWorkingIcon";
|
|
107
|
+
function lucideGlyph(Icon, name, displayName) {
|
|
108
|
+
const Glyph = React__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
109
|
+
Icon,
|
|
110
|
+
{
|
|
111
|
+
ref,
|
|
112
|
+
focusable: "false",
|
|
113
|
+
"data-ai-glyph": name,
|
|
114
|
+
className: utils.cn("size-4 shrink-0", className),
|
|
115
|
+
...glyphA11y(props),
|
|
116
|
+
...props
|
|
117
|
+
}
|
|
118
|
+
));
|
|
119
|
+
Glyph.displayName = displayName;
|
|
120
|
+
return Glyph;
|
|
121
|
+
}
|
|
122
|
+
var AiWandIcon = lucideGlyph(
|
|
123
|
+
lucideReact.WandSparkles,
|
|
124
|
+
"wand",
|
|
125
|
+
"AiWandIcon"
|
|
126
|
+
);
|
|
127
|
+
var AiRegenerateIcon = lucideGlyph(
|
|
128
|
+
lucideReact.RefreshCw,
|
|
129
|
+
"regenerate",
|
|
130
|
+
"AiRegenerateIcon"
|
|
131
|
+
);
|
|
132
|
+
var AiToolIcon = lucideGlyph(lucideReact.Wrench, "tool", "AiToolIcon");
|
|
133
|
+
var aiGlyphs = {
|
|
134
|
+
sparkle: AiSparkleIcon,
|
|
135
|
+
wand: AiWandIcon,
|
|
136
|
+
regenerate: AiRegenerateIcon,
|
|
137
|
+
generated: AiGeneratedIcon,
|
|
138
|
+
working: AiWorkingIcon,
|
|
139
|
+
tool: AiToolIcon
|
|
140
|
+
};
|
|
141
|
+
var defaultAiIconGlyphs = {
|
|
142
|
+
"ai-action": "sparkle",
|
|
143
|
+
"generated-content": "generated",
|
|
144
|
+
"agent-working": "working",
|
|
145
|
+
"tool-use": "tool"
|
|
146
|
+
};
|
|
147
|
+
var AiIconContext = React__namespace.createContext(defaultAiIconGlyphs);
|
|
148
|
+
function AiIconProvider({ glyphs, children }) {
|
|
149
|
+
const value = React__namespace.useMemo(() => ({ ...defaultAiIconGlyphs, ...glyphs }), [glyphs]);
|
|
150
|
+
return /* @__PURE__ */ jsxRuntime.jsx(AiIconContext.Provider, { value, children });
|
|
151
|
+
}
|
|
152
|
+
AiIconProvider.displayName = "AiIconProvider";
|
|
153
|
+
function useAiGlyph(role) {
|
|
154
|
+
const glyphs = React__namespace.useContext(AiIconContext);
|
|
155
|
+
return aiGlyphs[glyphs[role]];
|
|
156
|
+
}
|
|
157
|
+
var roleClasses = {
|
|
158
|
+
"ai-action": "text-foreground [&>svg]:text-brand",
|
|
159
|
+
"agent-working": "text-foreground [&>svg]:text-brand",
|
|
160
|
+
"tool-use": "text-muted-foreground",
|
|
161
|
+
"generated-content": "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"
|
|
162
|
+
};
|
|
163
|
+
var AiIcon = React__namespace.forwardRef(
|
|
164
|
+
({ role, label, showLabel = true, className, ...props }, ref) => {
|
|
165
|
+
const Glyph = useAiGlyph(role);
|
|
166
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
167
|
+
"span",
|
|
168
|
+
{
|
|
169
|
+
ref,
|
|
170
|
+
"data-ai-role": role,
|
|
171
|
+
role: role === "agent-working" ? "status" : void 0,
|
|
172
|
+
"aria-live": role === "agent-working" ? "polite" : void 0,
|
|
173
|
+
className: utils.cn("inline-flex items-center gap-1.5 text-sm", roleClasses[role], className),
|
|
174
|
+
...props,
|
|
175
|
+
children: [
|
|
176
|
+
/* @__PURE__ */ jsxRuntime.jsx(Glyph, {}),
|
|
177
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: showLabel ? void 0 : "sr-only", children: label })
|
|
178
|
+
]
|
|
179
|
+
}
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
);
|
|
183
|
+
AiIcon.displayName = "AiIcon";
|
|
184
|
+
var sizeClasses = {
|
|
185
|
+
sm: "size-6 text-xs [&>svg]:size-3.5",
|
|
186
|
+
md: "size-8 text-sm [&>svg]:size-4",
|
|
187
|
+
lg: "size-10 text-lg [&>svg]:size-5"
|
|
188
|
+
};
|
|
189
|
+
var AiIcons = React__namespace.forwardRef(
|
|
190
|
+
({ variant = "sparkle", size = "md", tone = "solid", label, glyph, className, ...props }, ref) => {
|
|
191
|
+
const Sparkle = useAiGlyph("ai-action");
|
|
192
|
+
const a11y = label ? { role: "img", "aria-label": label } : { "aria-hidden": true };
|
|
193
|
+
const base = "inline-grid shrink-0 place-items-center font-semibold";
|
|
194
|
+
if (variant === "thinking-orb") {
|
|
195
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
196
|
+
"span",
|
|
197
|
+
{
|
|
198
|
+
ref,
|
|
199
|
+
"data-variant": variant,
|
|
200
|
+
className: utils.cn(
|
|
201
|
+
base,
|
|
202
|
+
"rounded-full bg-gradient-to-br from-brand to-primary shadow-sm",
|
|
203
|
+
color.aiColorClasses.working,
|
|
204
|
+
sizeClasses[size],
|
|
205
|
+
className
|
|
206
|
+
),
|
|
207
|
+
...a11y,
|
|
208
|
+
...props
|
|
209
|
+
}
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
const toneClasses = tone === "solid" ? "bg-primary text-primary-foreground" : "border border-border bg-background text-foreground";
|
|
213
|
+
if (variant === "branded-mark") {
|
|
214
|
+
const content = glyph ?? (label ? label.charAt(0).toLowerCase() : /* @__PURE__ */ jsxRuntime.jsx(Sparkle, {}));
|
|
215
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
216
|
+
"span",
|
|
217
|
+
{
|
|
218
|
+
ref,
|
|
219
|
+
"data-variant": variant,
|
|
220
|
+
className: utils.cn(
|
|
221
|
+
base,
|
|
222
|
+
"rounded-[28%] font-serif italic",
|
|
223
|
+
tone === "solid" ? "bg-gradient-to-br from-primary to-primary/70 text-primary-foreground" : toneClasses,
|
|
224
|
+
sizeClasses[size],
|
|
225
|
+
className
|
|
226
|
+
),
|
|
227
|
+
...a11y,
|
|
228
|
+
...props,
|
|
229
|
+
children: content
|
|
230
|
+
}
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
234
|
+
"span",
|
|
235
|
+
{
|
|
236
|
+
ref,
|
|
237
|
+
"data-variant": variant,
|
|
238
|
+
className: utils.cn(base, "rounded-[22%]", toneClasses, sizeClasses[size], className),
|
|
239
|
+
...a11y,
|
|
240
|
+
...props,
|
|
241
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Sparkle, {})
|
|
242
|
+
}
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
);
|
|
246
|
+
AiIcons.displayName = "AiIcons";
|
|
247
|
+
|
|
248
|
+
exports.AiGeneratedIcon = AiGeneratedIcon;
|
|
249
|
+
exports.AiIcon = AiIcon;
|
|
250
|
+
exports.AiIconProvider = AiIconProvider;
|
|
251
|
+
exports.AiIcons = AiIcons;
|
|
252
|
+
exports.AiRegenerateIcon = AiRegenerateIcon;
|
|
253
|
+
exports.AiSparkleIcon = AiSparkleIcon;
|
|
254
|
+
exports.AiToolIcon = AiToolIcon;
|
|
255
|
+
exports.AiWandIcon = AiWandIcon;
|
|
256
|
+
exports.AiWorkingIcon = AiWorkingIcon;
|
|
257
|
+
exports.aiGlyphs = aiGlyphs;
|
|
258
|
+
exports.defaultAiIconGlyphs = defaultAiIconGlyphs;
|
|
259
|
+
exports.useAiGlyph = useAiGlyph;
|
|
260
|
+
//# sourceMappingURL=index.cjs.map
|
|
261
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +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"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
type AiGlyphProps = React.SVGProps<SVGSVGElement>;
|
|
4
|
+
/**
|
|
5
|
+
* The four-point AI sparkle — the reserved mark for "this runs AI" (generate).
|
|
6
|
+
* The same drawing appears on the agent avatar and the disclosure chip.
|
|
7
|
+
* Decorative (`aria-hidden`) unless given an `aria-label`.
|
|
8
|
+
*/
|
|
9
|
+
declare const AiSparkleIcon: React.ForwardRefExoticComponent<Omit<AiGlyphProps, "ref"> & React.RefAttributes<SVGSVGElement>>;
|
|
10
|
+
/**
|
|
11
|
+
* The "generated with AI" mark: a content outline carrying the sparkle. Used
|
|
12
|
+
* only on content AI wrote or changed, never on controls.
|
|
13
|
+
*/
|
|
14
|
+
declare const AiGeneratedIcon: React.ForwardRefExoticComponent<Omit<AiGlyphProps, "ref"> & React.RefAttributes<SVGSVGElement>>;
|
|
15
|
+
interface AiWorkingIconProps extends AiGlyphProps {
|
|
16
|
+
/** Hold the mark still (it only turns while work is happening). */
|
|
17
|
+
still?: boolean;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The "agent working" mark: a turning arc. The only AI mark that moves, and
|
|
21
|
+
* only while work is happening; it holds still under reduced motion.
|
|
22
|
+
*/
|
|
23
|
+
declare const AiWorkingIcon: React.ForwardRefExoticComponent<Omit<AiWorkingIconProps, "ref"> & React.RefAttributes<SVGSVGElement>>;
|
|
24
|
+
/** The "transform" mark (wand): for AI actions that change something the user already has — rewrite, enhance, restyle. */
|
|
25
|
+
declare const AiWandIcon: React.ForwardRefExoticComponent<Omit<AiGlyphProps, "ref"> & React.RefAttributes<SVGSVGElement>>;
|
|
26
|
+
/** The "regenerate" mark: run the same AI action again. */
|
|
27
|
+
declare const AiRegenerateIcon: React.ForwardRefExoticComponent<Omit<AiGlyphProps, "ref"> & React.RefAttributes<SVGSVGElement>>;
|
|
28
|
+
/** The "tool use" mark: on the lines that say which tool the agent used. */
|
|
29
|
+
declare const AiToolIcon: React.ForwardRefExoticComponent<Omit<AiGlyphProps, "ref"> & React.RefAttributes<SVGSVGElement>>;
|
|
30
|
+
/** The four AI meanings. Each has its own mark, used for that meaning only. */
|
|
31
|
+
type AiIconRole = "ai-action" | "generated-content" | "agent-working" | "tool-use";
|
|
32
|
+
/** Every reserved glyph by name. */
|
|
33
|
+
type AiGlyphName = "sparkle" | "wand" | "regenerate" | "generated" | "working" | "tool";
|
|
34
|
+
/**
|
|
35
|
+
* Approved glyphs per role. The lists do not overlap, so two meanings can
|
|
36
|
+
* never share a mark.
|
|
37
|
+
*/
|
|
38
|
+
interface AiIconGlyphs {
|
|
39
|
+
"ai-action"?: "sparkle" | "wand";
|
|
40
|
+
"generated-content"?: "generated";
|
|
41
|
+
"agent-working"?: "working";
|
|
42
|
+
"tool-use"?: "tool";
|
|
43
|
+
}
|
|
44
|
+
/** The reserved glyph components, by name. */
|
|
45
|
+
declare const aiGlyphs: Record<AiGlyphName, React.ComponentType<AiGlyphProps>>;
|
|
46
|
+
/** The default glyph for each role. */
|
|
47
|
+
declare const defaultAiIconGlyphs: Required<AiIconGlyphs>;
|
|
48
|
+
interface AiIconProviderProps {
|
|
49
|
+
/** Product-wide choice of approved glyph per role. Set once; unset roles keep the default. */
|
|
50
|
+
glyphs?: AiIconGlyphs;
|
|
51
|
+
children?: React.ReactNode;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Sets the approved glyph for each AI role once for the whole product.
|
|
55
|
+
* Every `AiIcon`, `AiIcons`, `Iconography` and `Disclosure` under it uses
|
|
56
|
+
* the same choice, so a meaning keeps one mark everywhere.
|
|
57
|
+
*/
|
|
58
|
+
declare function AiIconProvider({ glyphs, children }: AiIconProviderProps): React.JSX.Element;
|
|
59
|
+
declare namespace AiIconProvider {
|
|
60
|
+
var displayName: string;
|
|
61
|
+
}
|
|
62
|
+
/** The glyph component the nearest `AiIconProvider` approved for a role. */
|
|
63
|
+
declare function useAiGlyph(role: AiIconRole): React.ComponentType<AiGlyphProps>;
|
|
64
|
+
interface AiIconProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, "role"> {
|
|
65
|
+
/**
|
|
66
|
+
* Which AI meaning this is: `ai-action` (a control runs AI),
|
|
67
|
+
* `generated-content` (AI wrote this), `agent-working` (the agent is
|
|
68
|
+
* working now — announced politely) or `tool-use` (the agent used a tool).
|
|
69
|
+
*/
|
|
70
|
+
role: AiIconRole;
|
|
71
|
+
/** The words that travel with the mark ("Rewrite", "Generated with AI", "Rewriting release note…"). Required: a mark is never alone. */
|
|
72
|
+
label: React.ReactNode;
|
|
73
|
+
/** Show the words visibly (default) or keep them for assistive tech only. */
|
|
74
|
+
showLabel?: boolean;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* One AI meaning drawn with its reserved mark and its words. The product
|
|
78
|
+
* names the meaning; the component maps it to the approved glyph (see
|
|
79
|
+
* `AiIconProvider`). `agent-working` turns its mark and announces its words
|
|
80
|
+
* in a polite live region; the rest are static. For a control that runs
|
|
81
|
+
* AI, use `Iconography`, which puts the `ai-action` mark on a Button.
|
|
82
|
+
*/
|
|
83
|
+
declare const AiIcon: React.ForwardRefExoticComponent<AiIconProps & React.RefAttributes<HTMLSpanElement>>;
|
|
84
|
+
type AiIconsVariant = "sparkle" | "thinking-orb" | "branded-mark";
|
|
85
|
+
type AiIconsSize = "sm" | "md" | "lg";
|
|
86
|
+
type AiIconsTone = "solid" | "outline";
|
|
87
|
+
interface AiIconsProps extends React.HTMLAttributes<HTMLSpanElement> {
|
|
88
|
+
/**
|
|
89
|
+
* `sparkle` (the universal "AI" mark in a tile), `thinking-orb` (an
|
|
90
|
+
* animated orb for active, listening or generating states) or
|
|
91
|
+
* `branded-mark` (your product's own shape or letter).
|
|
92
|
+
*/
|
|
93
|
+
variant?: AiIconsVariant;
|
|
94
|
+
/** 24 / 32 / 40 px. */
|
|
95
|
+
size?: AiIconsSize;
|
|
96
|
+
/** `solid` (filled tile) or `outline` (bordered tile). Sparkle and branded mark only. */
|
|
97
|
+
tone?: AiIconsTone;
|
|
98
|
+
/** Accessible name. Omit when words sit beside the mark — it is then decorative. */
|
|
99
|
+
label?: string;
|
|
100
|
+
/** Content of the branded mark (a letter or your SVG). Defaults to the first letter of `label`, else the sparkle. */
|
|
101
|
+
glyph?: React.ReactNode;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
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
|
|
106
|
+
* (still under reduced motion — pair it with words such as an `AiIcon`
|
|
107
|
+
* `agent-working` line); `branded-mark` carries your product's own shape.
|
|
108
|
+
* Never a photo or a human face.
|
|
109
|
+
*/
|
|
110
|
+
declare const AiIcons: React.ForwardRefExoticComponent<AiIconsProps & React.RefAttributes<HTMLSpanElement>>;
|
|
111
|
+
|
|
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 };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
type AiGlyphProps = React.SVGProps<SVGSVGElement>;
|
|
4
|
+
/**
|
|
5
|
+
* The four-point AI sparkle — the reserved mark for "this runs AI" (generate).
|
|
6
|
+
* The same drawing appears on the agent avatar and the disclosure chip.
|
|
7
|
+
* Decorative (`aria-hidden`) unless given an `aria-label`.
|
|
8
|
+
*/
|
|
9
|
+
declare const AiSparkleIcon: React.ForwardRefExoticComponent<Omit<AiGlyphProps, "ref"> & React.RefAttributes<SVGSVGElement>>;
|
|
10
|
+
/**
|
|
11
|
+
* The "generated with AI" mark: a content outline carrying the sparkle. Used
|
|
12
|
+
* only on content AI wrote or changed, never on controls.
|
|
13
|
+
*/
|
|
14
|
+
declare const AiGeneratedIcon: React.ForwardRefExoticComponent<Omit<AiGlyphProps, "ref"> & React.RefAttributes<SVGSVGElement>>;
|
|
15
|
+
interface AiWorkingIconProps extends AiGlyphProps {
|
|
16
|
+
/** Hold the mark still (it only turns while work is happening). */
|
|
17
|
+
still?: boolean;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The "agent working" mark: a turning arc. The only AI mark that moves, and
|
|
21
|
+
* only while work is happening; it holds still under reduced motion.
|
|
22
|
+
*/
|
|
23
|
+
declare const AiWorkingIcon: React.ForwardRefExoticComponent<Omit<AiWorkingIconProps, "ref"> & React.RefAttributes<SVGSVGElement>>;
|
|
24
|
+
/** The "transform" mark (wand): for AI actions that change something the user already has — rewrite, enhance, restyle. */
|
|
25
|
+
declare const AiWandIcon: React.ForwardRefExoticComponent<Omit<AiGlyphProps, "ref"> & React.RefAttributes<SVGSVGElement>>;
|
|
26
|
+
/** The "regenerate" mark: run the same AI action again. */
|
|
27
|
+
declare const AiRegenerateIcon: React.ForwardRefExoticComponent<Omit<AiGlyphProps, "ref"> & React.RefAttributes<SVGSVGElement>>;
|
|
28
|
+
/** The "tool use" mark: on the lines that say which tool the agent used. */
|
|
29
|
+
declare const AiToolIcon: React.ForwardRefExoticComponent<Omit<AiGlyphProps, "ref"> & React.RefAttributes<SVGSVGElement>>;
|
|
30
|
+
/** The four AI meanings. Each has its own mark, used for that meaning only. */
|
|
31
|
+
type AiIconRole = "ai-action" | "generated-content" | "agent-working" | "tool-use";
|
|
32
|
+
/** Every reserved glyph by name. */
|
|
33
|
+
type AiGlyphName = "sparkle" | "wand" | "regenerate" | "generated" | "working" | "tool";
|
|
34
|
+
/**
|
|
35
|
+
* Approved glyphs per role. The lists do not overlap, so two meanings can
|
|
36
|
+
* never share a mark.
|
|
37
|
+
*/
|
|
38
|
+
interface AiIconGlyphs {
|
|
39
|
+
"ai-action"?: "sparkle" | "wand";
|
|
40
|
+
"generated-content"?: "generated";
|
|
41
|
+
"agent-working"?: "working";
|
|
42
|
+
"tool-use"?: "tool";
|
|
43
|
+
}
|
|
44
|
+
/** The reserved glyph components, by name. */
|
|
45
|
+
declare const aiGlyphs: Record<AiGlyphName, React.ComponentType<AiGlyphProps>>;
|
|
46
|
+
/** The default glyph for each role. */
|
|
47
|
+
declare const defaultAiIconGlyphs: Required<AiIconGlyphs>;
|
|
48
|
+
interface AiIconProviderProps {
|
|
49
|
+
/** Product-wide choice of approved glyph per role. Set once; unset roles keep the default. */
|
|
50
|
+
glyphs?: AiIconGlyphs;
|
|
51
|
+
children?: React.ReactNode;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Sets the approved glyph for each AI role once for the whole product.
|
|
55
|
+
* Every `AiIcon`, `AiIcons`, `Iconography` and `Disclosure` under it uses
|
|
56
|
+
* the same choice, so a meaning keeps one mark everywhere.
|
|
57
|
+
*/
|
|
58
|
+
declare function AiIconProvider({ glyphs, children }: AiIconProviderProps): React.JSX.Element;
|
|
59
|
+
declare namespace AiIconProvider {
|
|
60
|
+
var displayName: string;
|
|
61
|
+
}
|
|
62
|
+
/** The glyph component the nearest `AiIconProvider` approved for a role. */
|
|
63
|
+
declare function useAiGlyph(role: AiIconRole): React.ComponentType<AiGlyphProps>;
|
|
64
|
+
interface AiIconProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, "role"> {
|
|
65
|
+
/**
|
|
66
|
+
* Which AI meaning this is: `ai-action` (a control runs AI),
|
|
67
|
+
* `generated-content` (AI wrote this), `agent-working` (the agent is
|
|
68
|
+
* working now — announced politely) or `tool-use` (the agent used a tool).
|
|
69
|
+
*/
|
|
70
|
+
role: AiIconRole;
|
|
71
|
+
/** The words that travel with the mark ("Rewrite", "Generated with AI", "Rewriting release note…"). Required: a mark is never alone. */
|
|
72
|
+
label: React.ReactNode;
|
|
73
|
+
/** Show the words visibly (default) or keep them for assistive tech only. */
|
|
74
|
+
showLabel?: boolean;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* One AI meaning drawn with its reserved mark and its words. The product
|
|
78
|
+
* names the meaning; the component maps it to the approved glyph (see
|
|
79
|
+
* `AiIconProvider`). `agent-working` turns its mark and announces its words
|
|
80
|
+
* in a polite live region; the rest are static. For a control that runs
|
|
81
|
+
* AI, use `Iconography`, which puts the `ai-action` mark on a Button.
|
|
82
|
+
*/
|
|
83
|
+
declare const AiIcon: React.ForwardRefExoticComponent<AiIconProps & React.RefAttributes<HTMLSpanElement>>;
|
|
84
|
+
type AiIconsVariant = "sparkle" | "thinking-orb" | "branded-mark";
|
|
85
|
+
type AiIconsSize = "sm" | "md" | "lg";
|
|
86
|
+
type AiIconsTone = "solid" | "outline";
|
|
87
|
+
interface AiIconsProps extends React.HTMLAttributes<HTMLSpanElement> {
|
|
88
|
+
/**
|
|
89
|
+
* `sparkle` (the universal "AI" mark in a tile), `thinking-orb` (an
|
|
90
|
+
* animated orb for active, listening or generating states) or
|
|
91
|
+
* `branded-mark` (your product's own shape or letter).
|
|
92
|
+
*/
|
|
93
|
+
variant?: AiIconsVariant;
|
|
94
|
+
/** 24 / 32 / 40 px. */
|
|
95
|
+
size?: AiIconsSize;
|
|
96
|
+
/** `solid` (filled tile) or `outline` (bordered tile). Sparkle and branded mark only. */
|
|
97
|
+
tone?: AiIconsTone;
|
|
98
|
+
/** Accessible name. Omit when words sit beside the mark — it is then decorative. */
|
|
99
|
+
label?: string;
|
|
100
|
+
/** Content of the branded mark (a letter or your SVG). Defaults to the first letter of `label`, else the sparkle. */
|
|
101
|
+
glyph?: React.ReactNode;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
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
|
|
106
|
+
* (still under reduced motion — pair it with words such as an `AiIcon`
|
|
107
|
+
* `agent-working` line); `branded-mark` carries your product's own shape.
|
|
108
|
+
* Never a photo or a human face.
|
|
109
|
+
*/
|
|
110
|
+
declare const AiIcons: React.ForwardRefExoticComponent<AiIconsProps & React.RefAttributes<HTMLSpanElement>>;
|
|
111
|
+
|
|
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 };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { Wrench, RefreshCw, WandSparkles } from 'lucide-react';
|
|
4
|
+
import { cn } from '@nucleux/utils';
|
|
5
|
+
import { aiColorClasses } from '@nucleux/color';
|
|
6
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
7
|
+
|
|
8
|
+
// src/index.tsx
|
|
9
|
+
function glyphA11y(props) {
|
|
10
|
+
const named = props["aria-label"] != null || props["aria-labelledby"] != null;
|
|
11
|
+
return named ? { role: "img" } : { "aria-hidden": true };
|
|
12
|
+
}
|
|
13
|
+
var AiSparkleIcon = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
14
|
+
"svg",
|
|
15
|
+
{
|
|
16
|
+
ref,
|
|
17
|
+
viewBox: "0 0 24 24",
|
|
18
|
+
width: 16,
|
|
19
|
+
height: 16,
|
|
20
|
+
fill: "currentColor",
|
|
21
|
+
focusable: "false",
|
|
22
|
+
"data-ai-glyph": "sparkle",
|
|
23
|
+
className: cn("size-4 shrink-0", className),
|
|
24
|
+
...glyphA11y(props),
|
|
25
|
+
...props,
|
|
26
|
+
children: /* @__PURE__ */ jsx("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" })
|
|
27
|
+
}
|
|
28
|
+
));
|
|
29
|
+
AiSparkleIcon.displayName = "AiSparkleIcon";
|
|
30
|
+
var AiGeneratedIcon = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxs(
|
|
31
|
+
"svg",
|
|
32
|
+
{
|
|
33
|
+
ref,
|
|
34
|
+
viewBox: "0 0 24 24",
|
|
35
|
+
width: 16,
|
|
36
|
+
height: 16,
|
|
37
|
+
fill: "none",
|
|
38
|
+
stroke: "currentColor",
|
|
39
|
+
strokeWidth: 1.8,
|
|
40
|
+
strokeLinejoin: "round",
|
|
41
|
+
focusable: "false",
|
|
42
|
+
"data-ai-glyph": "generated",
|
|
43
|
+
className: cn("size-4 shrink-0", className),
|
|
44
|
+
...glyphA11y(props),
|
|
45
|
+
...props,
|
|
46
|
+
children: [
|
|
47
|
+
/* @__PURE__ */ jsx("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" }),
|
|
48
|
+
/* @__PURE__ */ jsx(
|
|
49
|
+
"path",
|
|
50
|
+
{
|
|
51
|
+
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",
|
|
52
|
+
fill: "currentColor",
|
|
53
|
+
stroke: "none"
|
|
54
|
+
}
|
|
55
|
+
)
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
));
|
|
59
|
+
AiGeneratedIcon.displayName = "AiGeneratedIcon";
|
|
60
|
+
var AiWorkingIcon = React.forwardRef(
|
|
61
|
+
({ still = false, className, ...props }, ref) => /* @__PURE__ */ jsxs(
|
|
62
|
+
"svg",
|
|
63
|
+
{
|
|
64
|
+
ref,
|
|
65
|
+
viewBox: "0 0 24 24",
|
|
66
|
+
width: 16,
|
|
67
|
+
height: 16,
|
|
68
|
+
fill: "none",
|
|
69
|
+
stroke: "currentColor",
|
|
70
|
+
strokeWidth: 2.2,
|
|
71
|
+
strokeLinecap: "round",
|
|
72
|
+
focusable: "false",
|
|
73
|
+
"data-ai-glyph": "working",
|
|
74
|
+
className: cn("size-4 shrink-0", !still && "animate-spin motion-reduce:animate-none", className),
|
|
75
|
+
...glyphA11y(props),
|
|
76
|
+
...props,
|
|
77
|
+
children: [
|
|
78
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "8.5", opacity: 0.25 }),
|
|
79
|
+
/* @__PURE__ */ jsx("path", { d: "M12 3.5a8.5 8.5 0 0 1 8.5 8.5" })
|
|
80
|
+
]
|
|
81
|
+
}
|
|
82
|
+
)
|
|
83
|
+
);
|
|
84
|
+
AiWorkingIcon.displayName = "AiWorkingIcon";
|
|
85
|
+
function lucideGlyph(Icon, name, displayName) {
|
|
86
|
+
const Glyph = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
87
|
+
Icon,
|
|
88
|
+
{
|
|
89
|
+
ref,
|
|
90
|
+
focusable: "false",
|
|
91
|
+
"data-ai-glyph": name,
|
|
92
|
+
className: cn("size-4 shrink-0", className),
|
|
93
|
+
...glyphA11y(props),
|
|
94
|
+
...props
|
|
95
|
+
}
|
|
96
|
+
));
|
|
97
|
+
Glyph.displayName = displayName;
|
|
98
|
+
return Glyph;
|
|
99
|
+
}
|
|
100
|
+
var AiWandIcon = lucideGlyph(
|
|
101
|
+
WandSparkles,
|
|
102
|
+
"wand",
|
|
103
|
+
"AiWandIcon"
|
|
104
|
+
);
|
|
105
|
+
var AiRegenerateIcon = lucideGlyph(
|
|
106
|
+
RefreshCw,
|
|
107
|
+
"regenerate",
|
|
108
|
+
"AiRegenerateIcon"
|
|
109
|
+
);
|
|
110
|
+
var AiToolIcon = lucideGlyph(Wrench, "tool", "AiToolIcon");
|
|
111
|
+
var aiGlyphs = {
|
|
112
|
+
sparkle: AiSparkleIcon,
|
|
113
|
+
wand: AiWandIcon,
|
|
114
|
+
regenerate: AiRegenerateIcon,
|
|
115
|
+
generated: AiGeneratedIcon,
|
|
116
|
+
working: AiWorkingIcon,
|
|
117
|
+
tool: AiToolIcon
|
|
118
|
+
};
|
|
119
|
+
var defaultAiIconGlyphs = {
|
|
120
|
+
"ai-action": "sparkle",
|
|
121
|
+
"generated-content": "generated",
|
|
122
|
+
"agent-working": "working",
|
|
123
|
+
"tool-use": "tool"
|
|
124
|
+
};
|
|
125
|
+
var AiIconContext = React.createContext(defaultAiIconGlyphs);
|
|
126
|
+
function AiIconProvider({ glyphs, children }) {
|
|
127
|
+
const value = React.useMemo(() => ({ ...defaultAiIconGlyphs, ...glyphs }), [glyphs]);
|
|
128
|
+
return /* @__PURE__ */ jsx(AiIconContext.Provider, { value, children });
|
|
129
|
+
}
|
|
130
|
+
AiIconProvider.displayName = "AiIconProvider";
|
|
131
|
+
function useAiGlyph(role) {
|
|
132
|
+
const glyphs = React.useContext(AiIconContext);
|
|
133
|
+
return aiGlyphs[glyphs[role]];
|
|
134
|
+
}
|
|
135
|
+
var roleClasses = {
|
|
136
|
+
"ai-action": "text-foreground [&>svg]:text-brand",
|
|
137
|
+
"agent-working": "text-foreground [&>svg]:text-brand",
|
|
138
|
+
"tool-use": "text-muted-foreground",
|
|
139
|
+
"generated-content": "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"
|
|
140
|
+
};
|
|
141
|
+
var AiIcon = React.forwardRef(
|
|
142
|
+
({ role, label, showLabel = true, className, ...props }, ref) => {
|
|
143
|
+
const Glyph = useAiGlyph(role);
|
|
144
|
+
return /* @__PURE__ */ jsxs(
|
|
145
|
+
"span",
|
|
146
|
+
{
|
|
147
|
+
ref,
|
|
148
|
+
"data-ai-role": role,
|
|
149
|
+
role: role === "agent-working" ? "status" : void 0,
|
|
150
|
+
"aria-live": role === "agent-working" ? "polite" : void 0,
|
|
151
|
+
className: cn("inline-flex items-center gap-1.5 text-sm", roleClasses[role], className),
|
|
152
|
+
...props,
|
|
153
|
+
children: [
|
|
154
|
+
/* @__PURE__ */ jsx(Glyph, {}),
|
|
155
|
+
/* @__PURE__ */ jsx("span", { className: showLabel ? void 0 : "sr-only", children: label })
|
|
156
|
+
]
|
|
157
|
+
}
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
);
|
|
161
|
+
AiIcon.displayName = "AiIcon";
|
|
162
|
+
var sizeClasses = {
|
|
163
|
+
sm: "size-6 text-xs [&>svg]:size-3.5",
|
|
164
|
+
md: "size-8 text-sm [&>svg]:size-4",
|
|
165
|
+
lg: "size-10 text-lg [&>svg]:size-5"
|
|
166
|
+
};
|
|
167
|
+
var AiIcons = React.forwardRef(
|
|
168
|
+
({ variant = "sparkle", size = "md", tone = "solid", label, glyph, className, ...props }, ref) => {
|
|
169
|
+
const Sparkle = useAiGlyph("ai-action");
|
|
170
|
+
const a11y = label ? { role: "img", "aria-label": label } : { "aria-hidden": true };
|
|
171
|
+
const base = "inline-grid shrink-0 place-items-center font-semibold";
|
|
172
|
+
if (variant === "thinking-orb") {
|
|
173
|
+
return /* @__PURE__ */ jsx(
|
|
174
|
+
"span",
|
|
175
|
+
{
|
|
176
|
+
ref,
|
|
177
|
+
"data-variant": variant,
|
|
178
|
+
className: cn(
|
|
179
|
+
base,
|
|
180
|
+
"rounded-full bg-gradient-to-br from-brand to-primary shadow-sm",
|
|
181
|
+
aiColorClasses.working,
|
|
182
|
+
sizeClasses[size],
|
|
183
|
+
className
|
|
184
|
+
),
|
|
185
|
+
...a11y,
|
|
186
|
+
...props
|
|
187
|
+
}
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
const toneClasses = tone === "solid" ? "bg-primary text-primary-foreground" : "border border-border bg-background text-foreground";
|
|
191
|
+
if (variant === "branded-mark") {
|
|
192
|
+
const content = glyph ?? (label ? label.charAt(0).toLowerCase() : /* @__PURE__ */ jsx(Sparkle, {}));
|
|
193
|
+
return /* @__PURE__ */ jsx(
|
|
194
|
+
"span",
|
|
195
|
+
{
|
|
196
|
+
ref,
|
|
197
|
+
"data-variant": variant,
|
|
198
|
+
className: cn(
|
|
199
|
+
base,
|
|
200
|
+
"rounded-[28%] font-serif italic",
|
|
201
|
+
tone === "solid" ? "bg-gradient-to-br from-primary to-primary/70 text-primary-foreground" : toneClasses,
|
|
202
|
+
sizeClasses[size],
|
|
203
|
+
className
|
|
204
|
+
),
|
|
205
|
+
...a11y,
|
|
206
|
+
...props,
|
|
207
|
+
children: content
|
|
208
|
+
}
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
return /* @__PURE__ */ jsx(
|
|
212
|
+
"span",
|
|
213
|
+
{
|
|
214
|
+
ref,
|
|
215
|
+
"data-variant": variant,
|
|
216
|
+
className: cn(base, "rounded-[22%]", toneClasses, sizeClasses[size], className),
|
|
217
|
+
...a11y,
|
|
218
|
+
...props,
|
|
219
|
+
children: /* @__PURE__ */ jsx(Sparkle, {})
|
|
220
|
+
}
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
);
|
|
224
|
+
AiIcons.displayName = "AiIcons";
|
|
225
|
+
|
|
226
|
+
export { AiGeneratedIcon, AiIcon, AiIconProvider, AiIcons, AiRegenerateIcon, AiSparkleIcon, AiToolIcon, AiWandIcon, AiWorkingIcon, aiGlyphs, defaultAiIconGlyphs, useAiGlyph };
|
|
227
|
+
//# sourceMappingURL=index.js.map
|
|
228
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +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"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,59 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nucleux/ai-icons",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.7.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"sideEffects": false,
|
|
6
|
+
"description": "Icons — a small, stable AI mark vocabulary: action, generated, working and tool use — Nucleux agentic UI for React.",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"nucleux",
|
|
9
|
+
"react",
|
|
10
|
+
"ui",
|
|
11
|
+
"components",
|
|
12
|
+
"agentic",
|
|
13
|
+
"ai",
|
|
14
|
+
"tailwind",
|
|
15
|
+
"ai-icons"
|
|
16
|
+
],
|
|
17
|
+
"main": "./dist/index.cjs",
|
|
18
|
+
"module": "./dist/index.js",
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"import": "./dist/index.js",
|
|
24
|
+
"require": "./dist/index.cjs"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist",
|
|
29
|
+
"README.md"
|
|
30
|
+
],
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"react": ">=18",
|
|
33
|
+
"react-dom": ">=18"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@nucleux/color": "0.7.0",
|
|
37
|
+
"@nucleux/utils": "0.7.0",
|
|
38
|
+
"lucide-react": "^0.469.0"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"tsup": "^8.3.5",
|
|
42
|
+
"typescript": "^5.7.2",
|
|
43
|
+
"@types/react": "^18.3.18",
|
|
44
|
+
"react": "^18.3.1"
|
|
45
|
+
},
|
|
46
|
+
"publishConfig": {
|
|
47
|
+
"access": "public"
|
|
48
|
+
},
|
|
49
|
+
"license": "MIT",
|
|
50
|
+
"repository": {
|
|
51
|
+
"type": "git",
|
|
52
|
+
"url": "git+https://github.com/intelligaia-open-labs/nucleux.git",
|
|
53
|
+
"directory": "packages/ai-icons"
|
|
54
|
+
},
|
|
55
|
+
"homepage": "https://github.com/intelligaia-open-labs/nucleux#readme",
|
|
56
|
+
"scripts": {
|
|
57
|
+
"build": "tsup"
|
|
58
|
+
}
|
|
6
59
|
}
|