@runtypelabs/persona 4.19.0 → 4.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/dist/animations/glyph-cycle.d.cts +1 -1
  2. package/dist/animations/glyph-cycle.d.ts +1 -1
  3. package/dist/animations/{types-CG-bLFmk.d.cts → types-B_JdVK9o.d.cts} +2 -0
  4. package/dist/animations/{types-CG-bLFmk.d.ts → types-B_JdVK9o.d.ts} +2 -0
  5. package/dist/animations/wipe.d.cts +1 -1
  6. package/dist/animations/wipe.d.ts +1 -1
  7. package/dist/animations-extra.d.cts +2 -0
  8. package/dist/animations-extra.d.ts +2 -0
  9. package/dist/approval-ui.d.cts +99 -5
  10. package/dist/approval-ui.d.ts +99 -5
  11. package/dist/artifacts-ui.d.cts +99 -5
  12. package/dist/artifacts-ui.d.ts +99 -5
  13. package/dist/codegen.cjs +1 -1
  14. package/dist/codegen.js +1 -1
  15. package/dist/context-mentions.d.cts +99 -5
  16. package/dist/context-mentions.d.ts +99 -5
  17. package/dist/event-stream-view.d.cts +99 -5
  18. package/dist/event-stream-view.d.ts +99 -5
  19. package/dist/forms-ui.d.cts +123 -9
  20. package/dist/forms-ui.d.ts +123 -9
  21. package/dist/history-view.d.cts +2 -0
  22. package/dist/history-view.d.ts +2 -0
  23. package/dist/index.cjs +51 -51
  24. package/dist/index.cjs.map +1 -1
  25. package/dist/index.d.cts +128 -10
  26. package/dist/index.d.ts +128 -10
  27. package/dist/index.global.js +34 -34
  28. package/dist/index.global.js.map +1 -1
  29. package/dist/index.js +51 -51
  30. package/dist/index.js.map +1 -1
  31. package/dist/launcher.global.js.map +1 -1
  32. package/dist/session-reconnect.d.cts +99 -5
  33. package/dist/session-reconnect.d.ts +99 -5
  34. package/dist/smart-dom-reader.d.cts +99 -5
  35. package/dist/smart-dom-reader.d.ts +99 -5
  36. package/dist/theme-editor-preview.cjs +53 -53
  37. package/dist/theme-editor-preview.d.cts +99 -5
  38. package/dist/theme-editor-preview.d.ts +99 -5
  39. package/dist/theme-editor-preview.js +31 -31
  40. package/dist/theme-editor.d.cts +99 -5
  41. package/dist/theme-editor.d.ts +99 -5
  42. package/dist/theme-reference.cjs +1 -1
  43. package/dist/theme-reference.d.cts +46 -5
  44. package/dist/theme-reference.d.ts +46 -5
  45. package/dist/theme-reference.js +1 -1
  46. package/dist/webmcp-runtime.d.cts +16 -0
  47. package/dist/webmcp-runtime.d.ts +16 -0
  48. package/dist/widget.css +1 -1
  49. package/package.json +1 -1
  50. package/src/client-visitor-history.test.ts +342 -3
  51. package/src/client.test.ts +141 -3
  52. package/src/client.ts +157 -39
  53. package/src/components/composer-actions.ts +27 -1
  54. package/src/components/composer-model-picker.ts +4 -14
  55. package/src/components/composer-overflow-menu.ts +14 -0
  56. package/src/components/composer-parts.ts +20 -0
  57. package/src/generated/runtype-openapi-contract.ts +2 -0
  58. package/src/index-core.ts +2 -0
  59. package/src/session.ts +139 -103
  60. package/src/session.webmcp.test.ts +48 -1
  61. package/src/styles/widget-styles.test.ts +83 -1
  62. package/src/styles/widget.css +50 -14
  63. package/src/theme-reference.ts +1 -1
  64. package/src/types/theme.ts +47 -5
  65. package/src/types.ts +63 -0
  66. package/src/ui.composer-action-visibility.test.ts +202 -0
  67. package/src/ui.composer-models.test.ts +37 -0
  68. package/src/ui.composer-modes.test.ts +82 -0
  69. package/src/ui.composer-overflow.test.ts +78 -0
  70. package/src/ui.history-lifecycle.test.ts +2 -2
  71. package/src/ui.ts +77 -6
  72. package/src/utils/__snapshots__/tokens-parity.test.ts.snap +1633 -686
  73. package/src/utils/composer-modes.test.ts +33 -0
  74. package/src/utils/composer-modes.ts +19 -2
  75. package/src/utils/tokens-parity.test.ts +20 -0
  76. package/src/utils/tokens.test.ts +76 -0
  77. 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((mode) => !isSegmentedModeGroup(mode.groupId, groups));
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)', () => {
@@ -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
+ });
@@ -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.*` and `.modelPicker.*` get no short
1112
- // aliases: the rows cost gzip in the critical launcher bundle, which never
1113
- // draws a composer. widget.css reads the auto-emitted full paths, like
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'],