@runtypelabs/persona 4.19.0 → 4.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/approval-ui.d.cts +77 -5
- package/dist/approval-ui.d.ts +77 -5
- package/dist/artifacts-ui.d.cts +77 -5
- package/dist/artifacts-ui.d.ts +77 -5
- package/dist/codegen.cjs +1 -1
- package/dist/codegen.js +1 -1
- package/dist/context-mentions.d.cts +77 -5
- package/dist/context-mentions.d.ts +77 -5
- package/dist/event-stream-view.d.cts +77 -5
- package/dist/event-stream-view.d.ts +77 -5
- package/dist/forms-ui.d.cts +77 -5
- package/dist/forms-ui.d.ts +77 -5
- package/dist/index.cjs +50 -50
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +78 -6
- package/dist/index.d.ts +78 -6
- package/dist/index.global.js +31 -31
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +50 -50
- package/dist/index.js.map +1 -1
- package/dist/launcher.global.js.map +1 -1
- package/dist/session-reconnect.d.cts +77 -5
- package/dist/session-reconnect.d.ts +77 -5
- package/dist/smart-dom-reader.d.cts +77 -5
- package/dist/smart-dom-reader.d.ts +77 -5
- package/dist/theme-editor-preview.cjs +49 -49
- package/dist/theme-editor-preview.d.cts +77 -5
- package/dist/theme-editor-preview.d.ts +77 -5
- package/dist/theme-editor-preview.js +28 -28
- package/dist/theme-editor.d.cts +77 -5
- package/dist/theme-editor.d.ts +77 -5
- package/dist/theme-reference.cjs +1 -1
- package/dist/theme-reference.d.cts +46 -5
- package/dist/theme-reference.d.ts +46 -5
- package/dist/theme-reference.js +1 -1
- package/dist/widget.css +1 -1
- package/package.json +1 -1
- package/src/components/composer-actions.ts +27 -1
- package/src/components/composer-model-picker.ts +4 -14
- package/src/components/composer-overflow-menu.ts +14 -0
- package/src/components/composer-parts.ts +20 -0
- package/src/index-core.ts +2 -0
- package/src/styles/widget-styles.test.ts +83 -1
- package/src/styles/widget.css +50 -14
- package/src/theme-reference.ts +1 -1
- package/src/types/theme.ts +47 -5
- package/src/types.ts +33 -0
- package/src/ui.composer-action-visibility.test.ts +202 -0
- package/src/ui.composer-models.test.ts +37 -0
- package/src/ui.composer-modes.test.ts +82 -0
- package/src/ui.composer-overflow.test.ts +78 -0
- package/src/utils/__snapshots__/tokens-parity.test.ts.snap +1633 -686
- package/src/utils/composer-modes.test.ts +33 -0
- package/src/utils/composer-modes.ts +19 -2
- package/src/utils/tokens-parity.test.ts +20 -0
- package/src/utils/tokens.test.ts +76 -0
- package/src/utils/tokens.ts +4 -4
|
@@ -4,6 +4,7 @@ import type { ComposerMode, ComposerModeGroup } from "../types";
|
|
|
4
4
|
import {
|
|
5
5
|
chipVisibleComposerModes,
|
|
6
6
|
clearOnceComposerModes,
|
|
7
|
+
hasHiddenModeChips,
|
|
7
8
|
composerModeActionId,
|
|
8
9
|
composerModeGroupActionId,
|
|
9
10
|
composerModeOrder,
|
|
@@ -139,6 +140,38 @@ describe("segmented mode groups", () => {
|
|
|
139
140
|
});
|
|
140
141
|
});
|
|
141
142
|
|
|
143
|
+
describe("chipVisibility on a mode group", () => {
|
|
144
|
+
const hidden: ComposerModeGroup[] = [
|
|
145
|
+
{ id: "tool", selection: "single", chipVisibility: "hidden" },
|
|
146
|
+
{ id: "style", selection: "multiple", chipVisibility: "auto" },
|
|
147
|
+
];
|
|
148
|
+
|
|
149
|
+
it("reads the opt-out off the group", () => {
|
|
150
|
+
expect(hasHiddenModeChips("tool", hidden)).toBe(true);
|
|
151
|
+
expect(hasHiddenModeChips("style", hidden)).toBe(false);
|
|
152
|
+
expect(hasHiddenModeChips("tool", groups)).toBe(false);
|
|
153
|
+
expect(hasHiddenModeChips(undefined, hidden)).toBe(false);
|
|
154
|
+
expect(hasHiddenModeChips("missing", hidden)).toBe(false);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it("suppresses chips for a buttons group on the segmented pathway", () => {
|
|
158
|
+
expect(chipVisibleComposerModes(modes, hidden).map((mode) => mode.id)).toEqual([
|
|
159
|
+
"concise",
|
|
160
|
+
"verbose",
|
|
161
|
+
"draft",
|
|
162
|
+
]);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it("leaves no chip-visible mode when every group opts out", () => {
|
|
166
|
+
const allHidden: ComposerModeGroup[] = [
|
|
167
|
+
{ id: "tool", selection: "single", chipVisibility: "hidden" },
|
|
168
|
+
{ id: "style", selection: "multiple", chipVisibility: "hidden" },
|
|
169
|
+
];
|
|
170
|
+
const grouped = modes.filter((mode) => mode.groupId);
|
|
171
|
+
expect(chipVisibleComposerModes(grouped, allHidden)).toEqual([]);
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
|
|
142
175
|
describe("mode action identity and ordering", () => {
|
|
143
176
|
it("namespaces the registry id", () => {
|
|
144
177
|
expect(composerModeActionId("search")).toBe("core:mode:search");
|
|
@@ -38,16 +38,33 @@ export function isSegmentedModeGroup(
|
|
|
38
38
|
);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
/** True when this group opts out of chips, whatever its presentation. */
|
|
42
|
+
export function hasHiddenModeChips(
|
|
43
|
+
groupId: string | undefined,
|
|
44
|
+
groups: readonly ComposerModeGroup[] | undefined
|
|
45
|
+
): boolean {
|
|
46
|
+
if (!groupId) return false;
|
|
47
|
+
return (
|
|
48
|
+
groups?.find((group) => group.id === groupId)?.chipVisibility === "hidden"
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
41
52
|
/**
|
|
42
53
|
* Modes that still earn a header chip. A segmented track already shows its own
|
|
43
|
-
* state, so a chip for the same mode would be a second, removable copy of it
|
|
54
|
+
* state, so a chip for the same mode would be a second, removable copy of it;
|
|
55
|
+
* `chipVisibility: "hidden"` opts a buttons-presentation group out of the same
|
|
56
|
+
* row on the same pathway.
|
|
44
57
|
*/
|
|
45
58
|
export function chipVisibleComposerModes(
|
|
46
59
|
modes: readonly ComposerMode[] | undefined,
|
|
47
60
|
groups: readonly ComposerModeGroup[] | undefined
|
|
48
61
|
): ComposerMode[] {
|
|
49
62
|
if (!modes?.length) return [];
|
|
50
|
-
return modes.filter(
|
|
63
|
+
return modes.filter(
|
|
64
|
+
(mode) =>
|
|
65
|
+
!isSegmentedModeGroup(mode.groupId, groups) &&
|
|
66
|
+
!hasHiddenModeChips(mode.groupId, groups)
|
|
67
|
+
);
|
|
51
68
|
}
|
|
52
69
|
|
|
53
70
|
const groupSelection = (
|
|
@@ -150,6 +150,26 @@ const FIXTURES: Record<string, DeepPartial<PersonaTheme>> = {
|
|
|
150
150
|
},
|
|
151
151
|
},
|
|
152
152
|
},
|
|
153
|
+
'composer model picker closed control + overflow menu': {
|
|
154
|
+
components: {
|
|
155
|
+
composer: {
|
|
156
|
+
modelPicker: {
|
|
157
|
+
background: '#303030',
|
|
158
|
+
hoverBackground: '#3f3f3f',
|
|
159
|
+
borderColor: 'rgba(255, 255, 255, 0.08)',
|
|
160
|
+
borderRadius: '9999px',
|
|
161
|
+
labelColor: '#c4c7c5',
|
|
162
|
+
},
|
|
163
|
+
overflowMenu: {
|
|
164
|
+
background: '#353535',
|
|
165
|
+
borderColor: 'rgba(255, 255, 255, 0.08)',
|
|
166
|
+
borderRadius: '12px',
|
|
167
|
+
foreground: '#ececec',
|
|
168
|
+
shadow: '0 12px 32px rgba(0, 0, 0, 0.4)',
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
},
|
|
153
173
|
};
|
|
154
174
|
|
|
155
175
|
describe('token pipeline parity (golden)', () => {
|
package/src/utils/tokens.test.ts
CHANGED
|
@@ -95,3 +95,79 @@ describe('interactive-state defaults', () => {
|
|
|
95
95
|
expect(css['--persona-icon-btn-active-border']).toBe('#0000ff');
|
|
96
96
|
});
|
|
97
97
|
});
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* `components.composer.modelPicker.*` and `.overflowMenu.*` carry no short
|
|
101
|
+
* aliases (they would cost gzip in the launcher bundle, which draws no
|
|
102
|
+
* composer), so the emitted contract is the full path. The rules that read
|
|
103
|
+
* them are covered in styles/widget-styles.test.ts.
|
|
104
|
+
*/
|
|
105
|
+
describe('composer surface tokens', () => {
|
|
106
|
+
it('emits the model picker closed-control vars as full paths', () => {
|
|
107
|
+
const css = vars({
|
|
108
|
+
components: {
|
|
109
|
+
composer: {
|
|
110
|
+
modelPicker: {
|
|
111
|
+
background: '#303030',
|
|
112
|
+
hoverBackground: '#3f3f3f',
|
|
113
|
+
borderColor: 'rgba(255, 255, 255, 0.08)',
|
|
114
|
+
borderRadius: '9999px',
|
|
115
|
+
labelColor: '#c4c7c5',
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
expect(css['--persona-components-composer-modelPicker-background']).toBe('#303030');
|
|
122
|
+
expect(css['--persona-components-composer-modelPicker-hoverBackground']).toBe('#3f3f3f');
|
|
123
|
+
expect(css['--persona-components-composer-modelPicker-borderColor']).toBe(
|
|
124
|
+
'rgba(255, 255, 255, 0.08)'
|
|
125
|
+
);
|
|
126
|
+
expect(css['--persona-components-composer-modelPicker-borderRadius']).toBe('9999px');
|
|
127
|
+
expect(css['--persona-components-composer-modelPicker-labelColor']).toBe('#c4c7c5');
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('resolves a token reference on a model picker surface key', () => {
|
|
131
|
+
const css = vars({
|
|
132
|
+
components: {
|
|
133
|
+
composer: { modelPicker: { background: 'palette.colors.gray.800' } },
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
expect(css['--persona-components-composer-modelPicker-background']).toBe('#1f2937');
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('emits the overflow menu panel vars as full paths', () => {
|
|
141
|
+
const css = vars({
|
|
142
|
+
components: {
|
|
143
|
+
composer: {
|
|
144
|
+
overflowMenu: {
|
|
145
|
+
background: '#353535',
|
|
146
|
+
borderColor: 'rgba(255, 255, 255, 0.08)',
|
|
147
|
+
borderRadius: '12px',
|
|
148
|
+
foreground: '#ececec',
|
|
149
|
+
shadow: 'none',
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
expect(css['--persona-components-composer-overflowMenu-background']).toBe('#353535');
|
|
156
|
+
expect(css['--persona-components-composer-overflowMenu-borderColor']).toBe(
|
|
157
|
+
'rgba(255, 255, 255, 0.08)'
|
|
158
|
+
);
|
|
159
|
+
expect(css['--persona-components-composer-overflowMenu-borderRadius']).toBe('12px');
|
|
160
|
+
expect(css['--persona-components-composer-overflowMenu-foreground']).toBe('#ececec');
|
|
161
|
+
expect(css['--persona-components-composer-overflowMenu-shadow']).toBe('none');
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('leaves every composer surface var unset on the stock theme', () => {
|
|
165
|
+
const css = vars({});
|
|
166
|
+
|
|
167
|
+
for (const name of Object.keys(css)) {
|
|
168
|
+
expect(name.startsWith('--persona-components-composer-modelPicker-')).toBe(false);
|
|
169
|
+
expect(name.startsWith('--persona-components-composer-overflowMenu-')).toBe(false);
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
});
|
package/src/utils/tokens.ts
CHANGED
|
@@ -1108,10 +1108,10 @@ export function themeToCssVariables(theme: PersonaTheme): Record<string, string>
|
|
|
1108
1108
|
['motion-easing', 'components-motion-easing', '=cubic-bezier(0.2, 0, 0, 1)'],
|
|
1109
1109
|
['composer-border-color', 'components-composer-borderColor', 'border', '=#e5e7eb'],
|
|
1110
1110
|
['composer-overlay-band', 'components-composer-overlayBand', '=transparent'],
|
|
1111
|
-
// `components.composer.segmented
|
|
1112
|
-
// aliases: the rows cost gzip in the critical launcher bundle,
|
|
1113
|
-
// draws a composer. widget.css reads the auto-emitted full
|
|
1114
|
-
// introCard title/subtitle.
|
|
1111
|
+
// `components.composer.segmented.*`, `.modelPicker.*`, and `.overflowMenu.*`
|
|
1112
|
+
// get no short aliases: the rows cost gzip in the critical launcher bundle,
|
|
1113
|
+
// which never draws a composer. widget.css reads the auto-emitted full
|
|
1114
|
+
// paths, like introCard title/subtitle.
|
|
1115
1115
|
['scrollbar-thumb', 'components-scrollbar-thumb', 'border', '=#e5e7eb'],
|
|
1116
1116
|
['scrollbar-track', 'components-scrollbar-track', '=transparent'],
|
|
1117
1117
|
['md-inline-code-bg', 'components-markdown-inlineCode-background', 'container'],
|