@nucleux/md3-personality 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 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,38 @@
1
- # Temporary Holding Version
1
+ # @nucleux/md3-personality
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Material 3 Personality — choose how the agent writes while the trust language stays fixed — 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
+ The Material 3 twin of [`@nucleux/personality`](https://www.npmjs.com/package/@nucleux/personality): it shares that package's API — the props types are re-exported from it — so you switch families by changing only the import. Only the look differs: Material 3 colour roles, shape, state layers and motion (with reduced-motion handling).
8
+
9
+ ## Exports
10
+
11
+ - **`Md3Personality`** — the tone-matrix: a radio group of M3 filter chips with roving focus; `options`, `value`, `defaultValue`, `onValueChange`, `label`
12
+ - **`Md3PersonalityVoiceCard`** — one sample utterance plus voice tags
13
+ - **`Md3PersonalitySampleDialog`** — a short exchange; `fixed` lines carry a lock and "Same in every personality"
14
+ - `defaultTones`, types `ToneOption`, `PersonalitySampleTurn` (shared with `@nucleux/personality`)
15
+ - Types: `Md3PersonalityProps`, `Md3PersonalityVoiceCardProps`, `Md3PersonalitySampleDialogProps`
16
+
17
+ ## Install
18
+
19
+ ```bash
20
+ pnpm add @nucleux/md3-personality @nucleux/tokens
21
+ ```
22
+
23
+ `react` / `react-dom` are peer dependencies.
24
+
25
+ ## Usage
26
+
27
+ ```tsx
28
+ import { Md3Personality } from "@nucleux/md3-personality";
29
+
30
+ <Md3Personality defaultValue="professional" onValueChange={setTone} />
31
+ ```
32
+
33
+ Requires the theme once in your app: `import "@nucleux/tokens/styles.css";`
34
+ and the Tailwind preset from `@nucleux/tokens/preset`.
35
+
36
+ ## License
37
+
38
+ MIT © Nucleux
package/dist/index.cjs ADDED
@@ -0,0 +1,178 @@
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 personality = require('@nucleux/personality');
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
+ var stateLayer = "relative overflow-hidden before:absolute before:inset-0 before:bg-current before:opacity-0 before:transition-opacity before:content-[''] hover:before:opacity-[0.08] focus-visible:before:opacity-[0.12] active:before:opacity-[0.12] motion-reduce:before:transition-none";
32
+ var Md3Personality = React__namespace.forwardRef(
33
+ ({ options = personality.defaultTones, value, defaultValue, onValueChange, label = "Tone", className, ...props }, ref) => {
34
+ const [internal, setInternal] = React__namespace.useState(defaultValue);
35
+ const current = value !== void 0 ? value : internal;
36
+ const refs = React__namespace.useRef([]);
37
+ const descId = React__namespace.useId();
38
+ const select = (next) => {
39
+ if (value === void 0) setInternal(next);
40
+ onValueChange?.(next);
41
+ };
42
+ const selectedIndex = options.findIndex((o) => o.value === current);
43
+ const tabStop = selectedIndex >= 0 ? selectedIndex : 0;
44
+ const onKeyDown = (e, index) => {
45
+ const last = options.length - 1;
46
+ let next = null;
47
+ if (e.key === "ArrowRight" || e.key === "ArrowDown") next = index === last ? 0 : index + 1;
48
+ else if (e.key === "ArrowLeft" || e.key === "ArrowUp") next = index === 0 ? last : index - 1;
49
+ else if (e.key === "Home") next = 0;
50
+ else if (e.key === "End") next = last;
51
+ if (next === null) return;
52
+ e.preventDefault();
53
+ refs.current[next]?.focus();
54
+ select(options[next].value);
55
+ };
56
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, "data-variant": "tone-matrix", className: utils.cn("flex flex-col gap-2", className), ...props, children: [
57
+ label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium tracking-[0.5px] text-md-on-surface-variant", children: label }),
58
+ /* @__PURE__ */ jsxRuntime.jsx(
59
+ "div",
60
+ {
61
+ role: "radiogroup",
62
+ "aria-label": typeof label === "string" ? label : "Tone",
63
+ className: "flex flex-wrap gap-2",
64
+ children: options.map((option, index) => {
65
+ const active = current === option.value;
66
+ return /* @__PURE__ */ jsxRuntime.jsxs(
67
+ "button",
68
+ {
69
+ ref: (el) => {
70
+ refs.current[index] = el;
71
+ },
72
+ type: "button",
73
+ role: "radio",
74
+ "aria-checked": active,
75
+ "aria-describedby": option.description ? `${descId}-${index}` : void 0,
76
+ tabIndex: index === tabStop ? 0 : -1,
77
+ onClick: () => select(option.value),
78
+ onKeyDown: (e) => onKeyDown(e, index),
79
+ className: utils.cn(
80
+ "inline-flex h-8 items-center gap-2 rounded-md-sm border px-3 text-sm font-medium tracking-[0.1px] outline-none transition-colors focus-visible:ring-2 focus-visible:ring-md-primary motion-reduce:transition-none [&_svg]:relative [&_svg]:size-[18px]",
81
+ stateLayer,
82
+ active ? "border-transparent bg-md-secondary-container pl-2 text-md-on-secondary-container" : "border-md-outline bg-transparent text-md-on-surface-variant"
83
+ ),
84
+ children: [
85
+ active && option.icon == null && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { "aria-hidden": "true" }),
86
+ option.icon,
87
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "relative", children: option.label }),
88
+ option.description && /* @__PURE__ */ jsxRuntime.jsx("span", { id: `${descId}-${index}`, className: "sr-only", children: option.description })
89
+ ]
90
+ },
91
+ option.value
92
+ );
93
+ })
94
+ }
95
+ )
96
+ ] });
97
+ }
98
+ );
99
+ Md3Personality.displayName = "Md3Personality";
100
+ var Md3PersonalityVoiceCard = React__namespace.forwardRef(
101
+ ({ quote, tags = [], label = "Voice", className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
102
+ "figure",
103
+ {
104
+ ref,
105
+ "aria-label": label,
106
+ "data-variant": "voice-card",
107
+ className: utils.cn(
108
+ "m-0 rounded-md-lg border border-md-outline-variant bg-md-surface p-5 text-md-on-surface",
109
+ className
110
+ ),
111
+ ...props,
112
+ children: [
113
+ /* @__PURE__ */ jsxRuntime.jsxs("blockquote", { className: "m-0 rounded-md-xs border-l-[3px] border-md-primary bg-md-surface-container px-3.5 py-3 text-sm leading-5 tracking-[0.25px] text-md-on-surface", children: [
114
+ "\u201C",
115
+ quote,
116
+ "\u201D"
117
+ ] }),
118
+ tags.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("figcaption", { className: "mt-3", children: [
119
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Voice: " }),
120
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "m-0 flex list-none flex-wrap gap-2 p-0", children: tags.map((tag) => /* @__PURE__ */ jsxRuntime.jsx(
121
+ "li",
122
+ {
123
+ className: "inline-flex h-6 items-center rounded-md-sm border border-md-outline-variant px-2 text-xs font-medium tracking-[0.5px] text-md-on-surface-variant",
124
+ children: tag
125
+ },
126
+ tag
127
+ )) })
128
+ ] })
129
+ ]
130
+ }
131
+ )
132
+ );
133
+ Md3PersonalityVoiceCard.displayName = "Md3PersonalityVoiceCard";
134
+ var Md3PersonalitySampleDialog = React__namespace.forwardRef(
135
+ ({ turns, agentName = "Assistant", label = "Sample dialog", className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
136
+ "div",
137
+ {
138
+ ref,
139
+ role: "group",
140
+ "aria-label": label,
141
+ "data-variant": "sample-dialog",
142
+ className: utils.cn("flex flex-col gap-2", className),
143
+ ...props,
144
+ children: turns.map((turn, i) => {
145
+ const user = turn.from === "user";
146
+ return /* @__PURE__ */ jsxRuntime.jsxs(
147
+ "div",
148
+ {
149
+ className: utils.cn(
150
+ "max-w-[85%] px-3.5 py-2.5 text-xs leading-[18px] tracking-[0.25px]",
151
+ user ? "self-end rounded-md-lg rounded-br-md-xs bg-md-surface-container-high text-md-on-surface" : "self-start rounded-md-lg rounded-bl-md-xs bg-md-primary-container text-md-on-primary-container"
152
+ ),
153
+ children: [
154
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: user ? "You said: " : `${agentName} said: ` }),
155
+ turn.text,
156
+ turn.fixed && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "mt-1 flex items-center gap-1 text-[11px] font-medium tracking-[0.5px] opacity-80", children: [
157
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Lock, { "aria-hidden": "true", className: "size-3" }),
158
+ "Same in every personality"
159
+ ] })
160
+ ]
161
+ },
162
+ i
163
+ );
164
+ })
165
+ }
166
+ )
167
+ );
168
+ Md3PersonalitySampleDialog.displayName = "Md3PersonalitySampleDialog";
169
+
170
+ Object.defineProperty(exports, "defaultTones", {
171
+ enumerable: true,
172
+ get: function () { return personality.defaultTones; }
173
+ });
174
+ exports.Md3Personality = Md3Personality;
175
+ exports.Md3PersonalitySampleDialog = Md3PersonalitySampleDialog;
176
+ exports.Md3PersonalityVoiceCard = Md3PersonalityVoiceCard;
177
+ //# sourceMappingURL=index.cjs.map
178
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.tsx"],"names":["React","defaultTones","jsxs","cn","jsx","Check","Lock"],"mappings":"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","file":"index.cjs","sourcesContent":["import * as React from \"react\";\nimport { Check, Lock } from \"lucide-react\";\nimport { cn } from \"@nucleux/utils\";\nimport { defaultTones } from \"@nucleux/personality\";\nimport type {\n PersonalityProps,\n PersonalitySampleDialogProps,\n PersonalityVoiceCardProps,\n} from \"@nucleux/personality\";\n\nexport type { ToneOption, PersonalitySampleTurn } from \"@nucleux/personality\";\nexport { defaultTones } from \"@nucleux/personality\";\nexport type Md3PersonalityProps = PersonalityProps;\nexport type Md3PersonalityVoiceCardProps = PersonalityVoiceCardProps;\nexport type Md3PersonalitySampleDialogProps = PersonalitySampleDialogProps;\n\nconst stateLayer =\n \"relative overflow-hidden before:absolute before:inset-0 before:bg-current before:opacity-0 before:transition-opacity before:content-[''] hover:before:opacity-[0.08] focus-visible:before:opacity-[0.12] active:before:opacity-[0.12] motion-reduce:before:transition-none\";\n\n/**\n * The `tone-matrix` in Material 3 — the twin of `Personality`, with the same\n * API and keyboard model. A small set of writing styles as M3 filter chips:\n * the selected one takes the secondary-container role and a leading check;\n * hover, focus and press are the chip's 8% / 12% state layer. It is a radio\n * group with roving focus (arrow keys move and select, Home / End jump).\n * Tone changes how the agent writes, never what it may do — keep\n * permission, caveat and refusal strings outside it.\n */\nexport const Md3Personality = React.forwardRef<HTMLDivElement, Md3PersonalityProps>(\n ({ options = defaultTones, value, defaultValue, onValueChange, label = \"Tone\", className, ...props }, ref) => {\n // Selection and roving-focus logic copied from @nucleux/personality (internal there).\n const [internal, setInternal] = React.useState<string | undefined>(defaultValue);\n const current = value !== undefined ? value : internal;\n const refs = React.useRef<(HTMLButtonElement | null)[]>([]);\n const descId = React.useId();\n const select = (next: string) => {\n if (value === undefined) setInternal(next);\n onValueChange?.(next);\n };\n const selectedIndex = options.findIndex((o) => o.value === current);\n const tabStop = selectedIndex >= 0 ? selectedIndex : 0;\n\n const onKeyDown = (e: React.KeyboardEvent, index: number) => {\n const last = options.length - 1;\n let next: number | null = null;\n if (e.key === \"ArrowRight\" || e.key === \"ArrowDown\") next = index === last ? 0 : index + 1;\n else if (e.key === \"ArrowLeft\" || e.key === \"ArrowUp\") next = index === 0 ? last : index - 1;\n else if (e.key === \"Home\") next = 0;\n else if (e.key === \"End\") next = last;\n if (next === null) return;\n e.preventDefault();\n refs.current[next]?.focus();\n select(options[next]!.value);\n };\n\n return (\n <div ref={ref} data-variant=\"tone-matrix\" className={cn(\"flex flex-col gap-2\", className)} {...props}>\n {label && (\n <span className=\"text-xs font-medium tracking-[0.5px] text-md-on-surface-variant\">{label}</span>\n )}\n <div\n role=\"radiogroup\"\n aria-label={typeof label === \"string\" ? label : \"Tone\"}\n className=\"flex flex-wrap gap-2\"\n >\n {options.map((option, index) => {\n const active = current === option.value;\n return (\n <button\n key={option.value}\n ref={(el) => {\n refs.current[index] = el;\n }}\n type=\"button\"\n role=\"radio\"\n aria-checked={active}\n aria-describedby={option.description ? `${descId}-${index}` : undefined}\n tabIndex={index === tabStop ? 0 : -1}\n onClick={() => select(option.value)}\n onKeyDown={(e) => onKeyDown(e, index)}\n className={cn(\n \"inline-flex h-8 items-center gap-2 rounded-md-sm border px-3 text-sm font-medium tracking-[0.1px] outline-none transition-colors focus-visible:ring-2 focus-visible:ring-md-primary motion-reduce:transition-none [&_svg]:relative [&_svg]:size-[18px]\",\n stateLayer,\n active\n ? \"border-transparent bg-md-secondary-container pl-2 text-md-on-secondary-container\"\n : \"border-md-outline bg-transparent text-md-on-surface-variant\",\n )}\n >\n {active && option.icon == null && <Check aria-hidden=\"true\" />}\n {option.icon}\n <span className=\"relative\">{option.label}</span>\n {option.description && (\n <span id={`${descId}-${index}`} className=\"sr-only\">\n {option.description}\n </span>\n )}\n </button>\n );\n })}\n </div>\n </div>\n );\n },\n);\nMd3Personality.displayName = \"Md3Personality\";\n\n/**\n * The `voice-card` in Material 3 — the twin of `PersonalityVoiceCard`. An\n * outlined card whose sample utterance sits on a surface-container ground\n * behind a primary rule (the voice, written down), with the voice tags as\n * outlined chips beneath it.\n */\nexport const Md3PersonalityVoiceCard = React.forwardRef<HTMLElement, Md3PersonalityVoiceCardProps>(\n ({ quote, tags = [], label = \"Voice\", className, ...props }, ref) => (\n <figure\n ref={ref}\n aria-label={label}\n data-variant=\"voice-card\"\n className={cn(\n \"m-0 rounded-md-lg border border-md-outline-variant bg-md-surface p-5 text-md-on-surface\",\n className,\n )}\n {...props}\n >\n <blockquote className=\"m-0 rounded-md-xs border-l-[3px] border-md-primary bg-md-surface-container px-3.5 py-3 text-sm leading-5 tracking-[0.25px] text-md-on-surface\">\n “{quote}”\n </blockquote>\n {tags.length > 0 && (\n <figcaption className=\"mt-3\">\n <span className=\"sr-only\">Voice: </span>\n <ul className=\"m-0 flex list-none flex-wrap gap-2 p-0\">\n {tags.map((tag) => (\n <li\n key={tag}\n className=\"inline-flex h-6 items-center rounded-md-sm border border-md-outline-variant px-2 text-xs font-medium tracking-[0.5px] text-md-on-surface-variant\"\n >\n {tag}\n </li>\n ))}\n </ul>\n </figcaption>\n )}\n </figure>\n ),\n);\nMd3PersonalityVoiceCard.displayName = \"Md3PersonalityVoiceCard\";\n\n/**\n * The `sample-dialog` in Material 3 — the twin of `PersonalitySampleDialog`.\n * Two authors, two grounds: the person's turns on surface-container-high,\n * the agent's on its primary-container ground, each with the M3 bubble\n * shape (a small corner toward its author). Lines marked `fixed` carry a\n * lock and \"Same in every personality\", so the contract is visible.\n */\nexport const Md3PersonalitySampleDialog = React.forwardRef<HTMLDivElement, Md3PersonalitySampleDialogProps>(\n ({ turns, agentName = \"Assistant\", label = \"Sample dialog\", className, ...props }, ref) => (\n <div\n ref={ref}\n role=\"group\"\n aria-label={label}\n data-variant=\"sample-dialog\"\n className={cn(\"flex flex-col gap-2\", className)}\n {...props}\n >\n {turns.map((turn, i) => {\n const user = turn.from === \"user\";\n return (\n <div\n key={i}\n className={cn(\n \"max-w-[85%] px-3.5 py-2.5 text-xs leading-[18px] tracking-[0.25px]\",\n user\n ? \"self-end rounded-md-lg rounded-br-md-xs bg-md-surface-container-high text-md-on-surface\"\n : \"self-start rounded-md-lg rounded-bl-md-xs bg-md-primary-container text-md-on-primary-container\",\n )}\n >\n <span className=\"sr-only\">{user ? \"You said: \" : `${agentName} said: `}</span>\n {turn.text}\n {turn.fixed && (\n <span className=\"mt-1 flex items-center gap-1 text-[11px] font-medium tracking-[0.5px] opacity-80\">\n <Lock aria-hidden=\"true\" className=\"size-3\" />\n Same in every personality\n </span>\n )}\n </div>\n );\n })}\n </div>\n ),\n);\nMd3PersonalitySampleDialog.displayName = \"Md3PersonalitySampleDialog\";\n"]}
@@ -0,0 +1,34 @@
1
+ import * as React from 'react';
2
+ import { PersonalityProps, PersonalitySampleDialogProps, PersonalityVoiceCardProps } from '@nucleux/personality';
3
+ export { PersonalitySampleTurn, ToneOption, defaultTones } from '@nucleux/personality';
4
+
5
+ type Md3PersonalityProps = PersonalityProps;
6
+ type Md3PersonalityVoiceCardProps = PersonalityVoiceCardProps;
7
+ type Md3PersonalitySampleDialogProps = PersonalitySampleDialogProps;
8
+ /**
9
+ * The `tone-matrix` in Material 3 — the twin of `Personality`, with the same
10
+ * API and keyboard model. A small set of writing styles as M3 filter chips:
11
+ * the selected one takes the secondary-container role and a leading check;
12
+ * hover, focus and press are the chip's 8% / 12% state layer. It is a radio
13
+ * group with roving focus (arrow keys move and select, Home / End jump).
14
+ * Tone changes how the agent writes, never what it may do — keep
15
+ * permission, caveat and refusal strings outside it.
16
+ */
17
+ declare const Md3Personality: React.ForwardRefExoticComponent<PersonalityProps & React.RefAttributes<HTMLDivElement>>;
18
+ /**
19
+ * The `voice-card` in Material 3 — the twin of `PersonalityVoiceCard`. An
20
+ * outlined card whose sample utterance sits on a surface-container ground
21
+ * behind a primary rule (the voice, written down), with the voice tags as
22
+ * outlined chips beneath it.
23
+ */
24
+ declare const Md3PersonalityVoiceCard: React.ForwardRefExoticComponent<PersonalityVoiceCardProps & React.RefAttributes<HTMLElement>>;
25
+ /**
26
+ * The `sample-dialog` in Material 3 — the twin of `PersonalitySampleDialog`.
27
+ * Two authors, two grounds: the person's turns on surface-container-high,
28
+ * the agent's on its primary-container ground, each with the M3 bubble
29
+ * shape (a small corner toward its author). Lines marked `fixed` carry a
30
+ * lock and "Same in every personality", so the contract is visible.
31
+ */
32
+ declare const Md3PersonalitySampleDialog: React.ForwardRefExoticComponent<PersonalitySampleDialogProps & React.RefAttributes<HTMLDivElement>>;
33
+
34
+ export { Md3Personality, type Md3PersonalityProps, Md3PersonalitySampleDialog, type Md3PersonalitySampleDialogProps, Md3PersonalityVoiceCard, type Md3PersonalityVoiceCardProps };
@@ -0,0 +1,34 @@
1
+ import * as React from 'react';
2
+ import { PersonalityProps, PersonalitySampleDialogProps, PersonalityVoiceCardProps } from '@nucleux/personality';
3
+ export { PersonalitySampleTurn, ToneOption, defaultTones } from '@nucleux/personality';
4
+
5
+ type Md3PersonalityProps = PersonalityProps;
6
+ type Md3PersonalityVoiceCardProps = PersonalityVoiceCardProps;
7
+ type Md3PersonalitySampleDialogProps = PersonalitySampleDialogProps;
8
+ /**
9
+ * The `tone-matrix` in Material 3 — the twin of `Personality`, with the same
10
+ * API and keyboard model. A small set of writing styles as M3 filter chips:
11
+ * the selected one takes the secondary-container role and a leading check;
12
+ * hover, focus and press are the chip's 8% / 12% state layer. It is a radio
13
+ * group with roving focus (arrow keys move and select, Home / End jump).
14
+ * Tone changes how the agent writes, never what it may do — keep
15
+ * permission, caveat and refusal strings outside it.
16
+ */
17
+ declare const Md3Personality: React.ForwardRefExoticComponent<PersonalityProps & React.RefAttributes<HTMLDivElement>>;
18
+ /**
19
+ * The `voice-card` in Material 3 — the twin of `PersonalityVoiceCard`. An
20
+ * outlined card whose sample utterance sits on a surface-container ground
21
+ * behind a primary rule (the voice, written down), with the voice tags as
22
+ * outlined chips beneath it.
23
+ */
24
+ declare const Md3PersonalityVoiceCard: React.ForwardRefExoticComponent<PersonalityVoiceCardProps & React.RefAttributes<HTMLElement>>;
25
+ /**
26
+ * The `sample-dialog` in Material 3 — the twin of `PersonalitySampleDialog`.
27
+ * Two authors, two grounds: the person's turns on surface-container-high,
28
+ * the agent's on its primary-container ground, each with the M3 bubble
29
+ * shape (a small corner toward its author). Lines marked `fixed` carry a
30
+ * lock and "Same in every personality", so the contract is visible.
31
+ */
32
+ declare const Md3PersonalitySampleDialog: React.ForwardRefExoticComponent<PersonalitySampleDialogProps & React.RefAttributes<HTMLDivElement>>;
33
+
34
+ export { Md3Personality, type Md3PersonalityProps, Md3PersonalitySampleDialog, type Md3PersonalitySampleDialogProps, Md3PersonalityVoiceCard, type Md3PersonalityVoiceCardProps };
package/dist/index.js ADDED
@@ -0,0 +1,151 @@
1
+ "use client";
2
+ import * as React from 'react';
3
+ import { Check, Lock } from 'lucide-react';
4
+ import { cn } from '@nucleux/utils';
5
+ import { defaultTones } from '@nucleux/personality';
6
+ export { defaultTones } from '@nucleux/personality';
7
+ import { jsxs, jsx } from 'react/jsx-runtime';
8
+
9
+ // src/index.tsx
10
+ var stateLayer = "relative overflow-hidden before:absolute before:inset-0 before:bg-current before:opacity-0 before:transition-opacity before:content-[''] hover:before:opacity-[0.08] focus-visible:before:opacity-[0.12] active:before:opacity-[0.12] motion-reduce:before:transition-none";
11
+ var Md3Personality = React.forwardRef(
12
+ ({ options = defaultTones, value, defaultValue, onValueChange, label = "Tone", className, ...props }, ref) => {
13
+ const [internal, setInternal] = React.useState(defaultValue);
14
+ const current = value !== void 0 ? value : internal;
15
+ const refs = React.useRef([]);
16
+ const descId = React.useId();
17
+ const select = (next) => {
18
+ if (value === void 0) setInternal(next);
19
+ onValueChange?.(next);
20
+ };
21
+ const selectedIndex = options.findIndex((o) => o.value === current);
22
+ const tabStop = selectedIndex >= 0 ? selectedIndex : 0;
23
+ const onKeyDown = (e, index) => {
24
+ const last = options.length - 1;
25
+ let next = null;
26
+ if (e.key === "ArrowRight" || e.key === "ArrowDown") next = index === last ? 0 : index + 1;
27
+ else if (e.key === "ArrowLeft" || e.key === "ArrowUp") next = index === 0 ? last : index - 1;
28
+ else if (e.key === "Home") next = 0;
29
+ else if (e.key === "End") next = last;
30
+ if (next === null) return;
31
+ e.preventDefault();
32
+ refs.current[next]?.focus();
33
+ select(options[next].value);
34
+ };
35
+ return /* @__PURE__ */ jsxs("div", { ref, "data-variant": "tone-matrix", className: cn("flex flex-col gap-2", className), ...props, children: [
36
+ label && /* @__PURE__ */ jsx("span", { className: "text-xs font-medium tracking-[0.5px] text-md-on-surface-variant", children: label }),
37
+ /* @__PURE__ */ jsx(
38
+ "div",
39
+ {
40
+ role: "radiogroup",
41
+ "aria-label": typeof label === "string" ? label : "Tone",
42
+ className: "flex flex-wrap gap-2",
43
+ children: options.map((option, index) => {
44
+ const active = current === option.value;
45
+ return /* @__PURE__ */ jsxs(
46
+ "button",
47
+ {
48
+ ref: (el) => {
49
+ refs.current[index] = el;
50
+ },
51
+ type: "button",
52
+ role: "radio",
53
+ "aria-checked": active,
54
+ "aria-describedby": option.description ? `${descId}-${index}` : void 0,
55
+ tabIndex: index === tabStop ? 0 : -1,
56
+ onClick: () => select(option.value),
57
+ onKeyDown: (e) => onKeyDown(e, index),
58
+ className: cn(
59
+ "inline-flex h-8 items-center gap-2 rounded-md-sm border px-3 text-sm font-medium tracking-[0.1px] outline-none transition-colors focus-visible:ring-2 focus-visible:ring-md-primary motion-reduce:transition-none [&_svg]:relative [&_svg]:size-[18px]",
60
+ stateLayer,
61
+ active ? "border-transparent bg-md-secondary-container pl-2 text-md-on-secondary-container" : "border-md-outline bg-transparent text-md-on-surface-variant"
62
+ ),
63
+ children: [
64
+ active && option.icon == null && /* @__PURE__ */ jsx(Check, { "aria-hidden": "true" }),
65
+ option.icon,
66
+ /* @__PURE__ */ jsx("span", { className: "relative", children: option.label }),
67
+ option.description && /* @__PURE__ */ jsx("span", { id: `${descId}-${index}`, className: "sr-only", children: option.description })
68
+ ]
69
+ },
70
+ option.value
71
+ );
72
+ })
73
+ }
74
+ )
75
+ ] });
76
+ }
77
+ );
78
+ Md3Personality.displayName = "Md3Personality";
79
+ var Md3PersonalityVoiceCard = React.forwardRef(
80
+ ({ quote, tags = [], label = "Voice", className, ...props }, ref) => /* @__PURE__ */ jsxs(
81
+ "figure",
82
+ {
83
+ ref,
84
+ "aria-label": label,
85
+ "data-variant": "voice-card",
86
+ className: cn(
87
+ "m-0 rounded-md-lg border border-md-outline-variant bg-md-surface p-5 text-md-on-surface",
88
+ className
89
+ ),
90
+ ...props,
91
+ children: [
92
+ /* @__PURE__ */ jsxs("blockquote", { className: "m-0 rounded-md-xs border-l-[3px] border-md-primary bg-md-surface-container px-3.5 py-3 text-sm leading-5 tracking-[0.25px] text-md-on-surface", children: [
93
+ "\u201C",
94
+ quote,
95
+ "\u201D"
96
+ ] }),
97
+ tags.length > 0 && /* @__PURE__ */ jsxs("figcaption", { className: "mt-3", children: [
98
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Voice: " }),
99
+ /* @__PURE__ */ jsx("ul", { className: "m-0 flex list-none flex-wrap gap-2 p-0", children: tags.map((tag) => /* @__PURE__ */ jsx(
100
+ "li",
101
+ {
102
+ className: "inline-flex h-6 items-center rounded-md-sm border border-md-outline-variant px-2 text-xs font-medium tracking-[0.5px] text-md-on-surface-variant",
103
+ children: tag
104
+ },
105
+ tag
106
+ )) })
107
+ ] })
108
+ ]
109
+ }
110
+ )
111
+ );
112
+ Md3PersonalityVoiceCard.displayName = "Md3PersonalityVoiceCard";
113
+ var Md3PersonalitySampleDialog = React.forwardRef(
114
+ ({ turns, agentName = "Assistant", label = "Sample dialog", className, ...props }, ref) => /* @__PURE__ */ jsx(
115
+ "div",
116
+ {
117
+ ref,
118
+ role: "group",
119
+ "aria-label": label,
120
+ "data-variant": "sample-dialog",
121
+ className: cn("flex flex-col gap-2", className),
122
+ ...props,
123
+ children: turns.map((turn, i) => {
124
+ const user = turn.from === "user";
125
+ return /* @__PURE__ */ jsxs(
126
+ "div",
127
+ {
128
+ className: cn(
129
+ "max-w-[85%] px-3.5 py-2.5 text-xs leading-[18px] tracking-[0.25px]",
130
+ user ? "self-end rounded-md-lg rounded-br-md-xs bg-md-surface-container-high text-md-on-surface" : "self-start rounded-md-lg rounded-bl-md-xs bg-md-primary-container text-md-on-primary-container"
131
+ ),
132
+ children: [
133
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: user ? "You said: " : `${agentName} said: ` }),
134
+ turn.text,
135
+ turn.fixed && /* @__PURE__ */ jsxs("span", { className: "mt-1 flex items-center gap-1 text-[11px] font-medium tracking-[0.5px] opacity-80", children: [
136
+ /* @__PURE__ */ jsx(Lock, { "aria-hidden": "true", className: "size-3" }),
137
+ "Same in every personality"
138
+ ] })
139
+ ]
140
+ },
141
+ i
142
+ );
143
+ })
144
+ }
145
+ )
146
+ );
147
+ Md3PersonalitySampleDialog.displayName = "Md3PersonalitySampleDialog";
148
+
149
+ export { Md3Personality, Md3PersonalitySampleDialog, Md3PersonalityVoiceCard };
150
+ //# sourceMappingURL=index.js.map
151
+ //# 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 { Check, Lock } from \"lucide-react\";\nimport { cn } from \"@nucleux/utils\";\nimport { defaultTones } from \"@nucleux/personality\";\nimport type {\n PersonalityProps,\n PersonalitySampleDialogProps,\n PersonalityVoiceCardProps,\n} from \"@nucleux/personality\";\n\nexport type { ToneOption, PersonalitySampleTurn } from \"@nucleux/personality\";\nexport { defaultTones } from \"@nucleux/personality\";\nexport type Md3PersonalityProps = PersonalityProps;\nexport type Md3PersonalityVoiceCardProps = PersonalityVoiceCardProps;\nexport type Md3PersonalitySampleDialogProps = PersonalitySampleDialogProps;\n\nconst stateLayer =\n \"relative overflow-hidden before:absolute before:inset-0 before:bg-current before:opacity-0 before:transition-opacity before:content-[''] hover:before:opacity-[0.08] focus-visible:before:opacity-[0.12] active:before:opacity-[0.12] motion-reduce:before:transition-none\";\n\n/**\n * The `tone-matrix` in Material 3 — the twin of `Personality`, with the same\n * API and keyboard model. A small set of writing styles as M3 filter chips:\n * the selected one takes the secondary-container role and a leading check;\n * hover, focus and press are the chip's 8% / 12% state layer. It is a radio\n * group with roving focus (arrow keys move and select, Home / End jump).\n * Tone changes how the agent writes, never what it may do — keep\n * permission, caveat and refusal strings outside it.\n */\nexport const Md3Personality = React.forwardRef<HTMLDivElement, Md3PersonalityProps>(\n ({ options = defaultTones, value, defaultValue, onValueChange, label = \"Tone\", className, ...props }, ref) => {\n // Selection and roving-focus logic copied from @nucleux/personality (internal there).\n const [internal, setInternal] = React.useState<string | undefined>(defaultValue);\n const current = value !== undefined ? value : internal;\n const refs = React.useRef<(HTMLButtonElement | null)[]>([]);\n const descId = React.useId();\n const select = (next: string) => {\n if (value === undefined) setInternal(next);\n onValueChange?.(next);\n };\n const selectedIndex = options.findIndex((o) => o.value === current);\n const tabStop = selectedIndex >= 0 ? selectedIndex : 0;\n\n const onKeyDown = (e: React.KeyboardEvent, index: number) => {\n const last = options.length - 1;\n let next: number | null = null;\n if (e.key === \"ArrowRight\" || e.key === \"ArrowDown\") next = index === last ? 0 : index + 1;\n else if (e.key === \"ArrowLeft\" || e.key === \"ArrowUp\") next = index === 0 ? last : index - 1;\n else if (e.key === \"Home\") next = 0;\n else if (e.key === \"End\") next = last;\n if (next === null) return;\n e.preventDefault();\n refs.current[next]?.focus();\n select(options[next]!.value);\n };\n\n return (\n <div ref={ref} data-variant=\"tone-matrix\" className={cn(\"flex flex-col gap-2\", className)} {...props}>\n {label && (\n <span className=\"text-xs font-medium tracking-[0.5px] text-md-on-surface-variant\">{label}</span>\n )}\n <div\n role=\"radiogroup\"\n aria-label={typeof label === \"string\" ? label : \"Tone\"}\n className=\"flex flex-wrap gap-2\"\n >\n {options.map((option, index) => {\n const active = current === option.value;\n return (\n <button\n key={option.value}\n ref={(el) => {\n refs.current[index] = el;\n }}\n type=\"button\"\n role=\"radio\"\n aria-checked={active}\n aria-describedby={option.description ? `${descId}-${index}` : undefined}\n tabIndex={index === tabStop ? 0 : -1}\n onClick={() => select(option.value)}\n onKeyDown={(e) => onKeyDown(e, index)}\n className={cn(\n \"inline-flex h-8 items-center gap-2 rounded-md-sm border px-3 text-sm font-medium tracking-[0.1px] outline-none transition-colors focus-visible:ring-2 focus-visible:ring-md-primary motion-reduce:transition-none [&_svg]:relative [&_svg]:size-[18px]\",\n stateLayer,\n active\n ? \"border-transparent bg-md-secondary-container pl-2 text-md-on-secondary-container\"\n : \"border-md-outline bg-transparent text-md-on-surface-variant\",\n )}\n >\n {active && option.icon == null && <Check aria-hidden=\"true\" />}\n {option.icon}\n <span className=\"relative\">{option.label}</span>\n {option.description && (\n <span id={`${descId}-${index}`} className=\"sr-only\">\n {option.description}\n </span>\n )}\n </button>\n );\n })}\n </div>\n </div>\n );\n },\n);\nMd3Personality.displayName = \"Md3Personality\";\n\n/**\n * The `voice-card` in Material 3 — the twin of `PersonalityVoiceCard`. An\n * outlined card whose sample utterance sits on a surface-container ground\n * behind a primary rule (the voice, written down), with the voice tags as\n * outlined chips beneath it.\n */\nexport const Md3PersonalityVoiceCard = React.forwardRef<HTMLElement, Md3PersonalityVoiceCardProps>(\n ({ quote, tags = [], label = \"Voice\", className, ...props }, ref) => (\n <figure\n ref={ref}\n aria-label={label}\n data-variant=\"voice-card\"\n className={cn(\n \"m-0 rounded-md-lg border border-md-outline-variant bg-md-surface p-5 text-md-on-surface\",\n className,\n )}\n {...props}\n >\n <blockquote className=\"m-0 rounded-md-xs border-l-[3px] border-md-primary bg-md-surface-container px-3.5 py-3 text-sm leading-5 tracking-[0.25px] text-md-on-surface\">\n “{quote}”\n </blockquote>\n {tags.length > 0 && (\n <figcaption className=\"mt-3\">\n <span className=\"sr-only\">Voice: </span>\n <ul className=\"m-0 flex list-none flex-wrap gap-2 p-0\">\n {tags.map((tag) => (\n <li\n key={tag}\n className=\"inline-flex h-6 items-center rounded-md-sm border border-md-outline-variant px-2 text-xs font-medium tracking-[0.5px] text-md-on-surface-variant\"\n >\n {tag}\n </li>\n ))}\n </ul>\n </figcaption>\n )}\n </figure>\n ),\n);\nMd3PersonalityVoiceCard.displayName = \"Md3PersonalityVoiceCard\";\n\n/**\n * The `sample-dialog` in Material 3 — the twin of `PersonalitySampleDialog`.\n * Two authors, two grounds: the person's turns on surface-container-high,\n * the agent's on its primary-container ground, each with the M3 bubble\n * shape (a small corner toward its author). Lines marked `fixed` carry a\n * lock and \"Same in every personality\", so the contract is visible.\n */\nexport const Md3PersonalitySampleDialog = React.forwardRef<HTMLDivElement, Md3PersonalitySampleDialogProps>(\n ({ turns, agentName = \"Assistant\", label = \"Sample dialog\", className, ...props }, ref) => (\n <div\n ref={ref}\n role=\"group\"\n aria-label={label}\n data-variant=\"sample-dialog\"\n className={cn(\"flex flex-col gap-2\", className)}\n {...props}\n >\n {turns.map((turn, i) => {\n const user = turn.from === \"user\";\n return (\n <div\n key={i}\n className={cn(\n \"max-w-[85%] px-3.5 py-2.5 text-xs leading-[18px] tracking-[0.25px]\",\n user\n ? \"self-end rounded-md-lg rounded-br-md-xs bg-md-surface-container-high text-md-on-surface\"\n : \"self-start rounded-md-lg rounded-bl-md-xs bg-md-primary-container text-md-on-primary-container\",\n )}\n >\n <span className=\"sr-only\">{user ? \"You said: \" : `${agentName} said: `}</span>\n {turn.text}\n {turn.fixed && (\n <span className=\"mt-1 flex items-center gap-1 text-[11px] font-medium tracking-[0.5px] opacity-80\">\n <Lock aria-hidden=\"true\" className=\"size-3\" />\n Same in every personality\n </span>\n )}\n </div>\n );\n })}\n </div>\n ),\n);\nMd3PersonalitySampleDialog.displayName = \"Md3PersonalitySampleDialog\";\n"]}
package/package.json CHANGED
@@ -1,6 +1,62 @@
1
1
  {
2
2
  "name": "@nucleux/md3-personality",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.7.0",
4
+ "type": "module",
5
+ "sideEffects": false,
6
+ "description": "Material 3 Personality — choose how the agent writes while the trust language stays fixed — Nucleux agentic UI for React.",
7
+ "keywords": [
8
+ "nucleux",
9
+ "react",
10
+ "ui",
11
+ "components",
12
+ "agentic",
13
+ "ai",
14
+ "tailwind",
15
+ "md3",
16
+ "material",
17
+ "md3-personality",
18
+ "personality"
19
+ ],
20
+ "main": "./dist/index.cjs",
21
+ "module": "./dist/index.js",
22
+ "types": "./dist/index.d.ts",
23
+ "exports": {
24
+ ".": {
25
+ "types": "./dist/index.d.ts",
26
+ "import": "./dist/index.js",
27
+ "require": "./dist/index.cjs"
28
+ }
29
+ },
30
+ "files": [
31
+ "dist",
32
+ "README.md"
33
+ ],
34
+ "peerDependencies": {
35
+ "react": ">=18",
36
+ "react-dom": ">=18"
37
+ },
38
+ "dependencies": {
39
+ "@nucleux/personality": "0.7.0",
40
+ "@nucleux/utils": "0.7.0",
41
+ "lucide-react": "^0.469.0"
42
+ },
43
+ "devDependencies": {
44
+ "tsup": "^8.3.5",
45
+ "typescript": "^5.7.2",
46
+ "@types/react": "^18.3.18",
47
+ "react": "^18.3.1"
48
+ },
49
+ "publishConfig": {
50
+ "access": "public"
51
+ },
52
+ "license": "MIT",
53
+ "repository": {
54
+ "type": "git",
55
+ "url": "git+https://github.com/intelligaia-open-labs/nucleux.git",
56
+ "directory": "packages/md3-personality"
57
+ },
58
+ "homepage": "https://github.com/intelligaia-open-labs/nucleux#readme",
59
+ "scripts": {
60
+ "build": "tsup"
61
+ }
6
62
  }