@genesislcap/ai-assistant 15.28.1-FUI-0.6 → 15.28.1-FUI-0.8

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.
@@ -646,6 +646,24 @@ export declare class AiChatMarkdown extends GenesisElement {
646
646
  content: string;
647
647
  /** @internal */
648
648
  renderMarkdown(): string;
649
+ /**
650
+ * Tag the generated elements with shadow parts so an embedding app can style them.
651
+ *
652
+ * Runs AFTER sanitising, deliberately. It only ever *adds* attributes to DOM DOMPurify has
653
+ * already cleared, so it introduces no new sanitiser surface - reversing the order would mean
654
+ * sanitising our own output and inviting the question of whether these attributes survive it.
655
+ *
656
+ * Lists additionally carry a level: a top-level list is `md-ul md-ul-level-1`, a list nested
657
+ * inside it is `md-ul-level-2`, and an `li` takes the level of the list holding it. Chat markdown
658
+ * rarely nests, so this is a safety valve rather than a feature - without it, every list at every
659
+ * depth would answer to one selector and there would be no way to tell them apart afterwards.
660
+ * Depth comes from walking the tree rather than from marked's renderers, which are invoked
661
+ * innermost-first and so cannot count downwards.
662
+ *
663
+ * An author-supplied `part` on inline HTML is overwritten: these parts are the documented
664
+ * contract, and two sources for one attribute would make which-wins depend on the markdown.
665
+ */
666
+ private annotateParts;
649
667
  }
650
668
 
651
669
  /**
@@ -4929,48 +4929,6 @@
4929
4929
  "declarations": [],
4930
4930
  "exports": []
4931
4931
  },
4932
- {
4933
- "kind": "javascript-module",
4934
- "path": "src/provider/ai-provider-switcher.ts",
4935
- "declarations": [
4936
- {
4937
- "kind": "variable",
4938
- "name": "AIProviderSwitcher",
4939
- "description": "The DI token for the (AIProviderSwitcher:interface). Resolves a noop until the app\nregisters one."
4940
- }
4941
- ],
4942
- "exports": [
4943
- {
4944
- "kind": "js",
4945
- "name": "AIProviderSwitcher",
4946
- "declaration": {
4947
- "name": "AIProviderSwitcher",
4948
- "module": "src/provider/ai-provider-switcher.ts"
4949
- }
4950
- }
4951
- ]
4952
- },
4953
- {
4954
- "kind": "javascript-module",
4955
- "path": "src/provider/assistant-app-settings.ts",
4956
- "declarations": [
4957
- {
4958
- "kind": "variable",
4959
- "name": "AssistantAppSettingsProvider",
4960
- "description": "The DI token for the (AssistantAppSettingsProvider:interface). Resolves a noop\nuntil the host registers one."
4961
- }
4962
- ],
4963
- "exports": [
4964
- {
4965
- "kind": "js",
4966
- "name": "AssistantAppSettingsProvider",
4967
- "declaration": {
4968
- "name": "AssistantAppSettingsProvider",
4969
- "module": "src/provider/assistant-app-settings.ts"
4970
- }
4971
- }
4972
- ]
4973
- },
4974
4932
  {
4975
4933
  "kind": "javascript-module",
4976
4934
  "path": "src/state/ai-assistant-slice.ts",
@@ -5661,6 +5619,48 @@
5661
5619
  }
5662
5620
  ]
5663
5621
  },
5622
+ {
5623
+ "kind": "javascript-module",
5624
+ "path": "src/provider/ai-provider-switcher.ts",
5625
+ "declarations": [
5626
+ {
5627
+ "kind": "variable",
5628
+ "name": "AIProviderSwitcher",
5629
+ "description": "The DI token for the (AIProviderSwitcher:interface). Resolves a noop until the app\nregisters one."
5630
+ }
5631
+ ],
5632
+ "exports": [
5633
+ {
5634
+ "kind": "js",
5635
+ "name": "AIProviderSwitcher",
5636
+ "declaration": {
5637
+ "name": "AIProviderSwitcher",
5638
+ "module": "src/provider/ai-provider-switcher.ts"
5639
+ }
5640
+ }
5641
+ ]
5642
+ },
5643
+ {
5644
+ "kind": "javascript-module",
5645
+ "path": "src/provider/assistant-app-settings.ts",
5646
+ "declarations": [
5647
+ {
5648
+ "kind": "variable",
5649
+ "name": "AssistantAppSettingsProvider",
5650
+ "description": "The DI token for the (AssistantAppSettingsProvider:interface). Resolves a noop\nuntil the host registers one."
5651
+ }
5652
+ ],
5653
+ "exports": [
5654
+ {
5655
+ "kind": "js",
5656
+ "name": "AssistantAppSettingsProvider",
5657
+ "declaration": {
5658
+ "name": "AssistantAppSettingsProvider",
5659
+ "module": "src/provider/assistant-app-settings.ts"
5660
+ }
5661
+ }
5662
+ ]
5663
+ },
5664
5664
  {
5665
5665
  "kind": "javascript-module",
5666
5666
  "path": "src/suggestions/chat-suggestions.ts",
@@ -11939,6 +11939,25 @@
11939
11939
  },
11940
11940
  "default": "''",
11941
11941
  "description": "The markdown string to render."
11942
+ },
11943
+ {
11944
+ "kind": "method",
11945
+ "name": "annotateParts",
11946
+ "privacy": "private",
11947
+ "return": {
11948
+ "type": {
11949
+ "text": "string"
11950
+ }
11951
+ },
11952
+ "parameters": [
11953
+ {
11954
+ "name": "html",
11955
+ "type": {
11956
+ "text": "string"
11957
+ }
11958
+ }
11959
+ ],
11960
+ "description": "Tag the generated elements with shadow parts so an embedding app can style them.\n\nRuns AFTER sanitising, deliberately. It only ever *adds* attributes to DOM DOMPurify has\nalready cleared, so it introduces no new sanitiser surface - reversing the order would mean\nsanitising our own output and inviting the question of whether these attributes survive it.\n\nLists additionally carry a level: a top-level list is `md-ul md-ul-level-1`, a list nested\ninside it is `md-ul-level-2`, and an `li` takes the level of the list holding it. Chat markdown\nrarely nests, so this is a safety valve rather than a feature - without it, every list at every\ndepth would answer to one selector and there would be no way to tell them apart afterwards.\nDepth comes from walking the tree rather than from marked's renderers, which are invoked\ninnermost-first and so cannot count downwards.\n\nAn author-supplied `part` on inline HTML is overwritten: these parts are the documented\ncontract, and two sources for one attribute would make which-wins depend on the markdown."
11942
11961
  }
11943
11962
  ],
11944
11963
  "superclass": {
@@ -4,5 +4,23 @@ export declare class AiChatMarkdown extends GenesisElement {
4
4
  content: string;
5
5
  /** @internal */
6
6
  renderMarkdown(): string;
7
+ /**
8
+ * Tag the generated elements with shadow parts so an embedding app can style them.
9
+ *
10
+ * Runs AFTER sanitising, deliberately. It only ever *adds* attributes to DOM DOMPurify has
11
+ * already cleared, so it introduces no new sanitiser surface - reversing the order would mean
12
+ * sanitising our own output and inviting the question of whether these attributes survive it.
13
+ *
14
+ * Lists additionally carry a level: a top-level list is `md-ul md-ul-level-1`, a list nested
15
+ * inside it is `md-ul-level-2`, and an `li` takes the level of the list holding it. Chat markdown
16
+ * rarely nests, so this is a safety valve rather than a feature - without it, every list at every
17
+ * depth would answer to one selector and there would be no way to tell them apart afterwards.
18
+ * Depth comes from walking the tree rather than from marked's renderers, which are invoked
19
+ * innermost-first and so cannot count downwards.
20
+ *
21
+ * An author-supplied `part` on inline HTML is overwritten: these parts are the documented
22
+ * contract, and two sources for one attribute would make which-wins depend on the markdown.
23
+ */
24
+ private annotateParts;
7
25
  }
8
26
  //# sourceMappingURL=chat-markdown.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"chat-markdown.d.ts","sourceRoot":"","sources":["../../../../src/components/chat-markdown/chat-markdown.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,cAAc,EAAoB,MAAM,uBAAuB,CAAC;AAuE7F,qBAOa,cAAe,SAAQ,cAAc;IAChD,qCAAqC;IACzB,OAAO,EAAE,MAAM,CAAM;IAEjC,gBAAgB;IAChB,cAAc;CAKf"}
1
+ {"version":3,"file":"chat-markdown.d.ts","sourceRoot":"","sources":["../../../../src/components/chat-markdown/chat-markdown.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,cAAc,EAAoB,MAAM,uBAAuB,CAAC;AAkH7F,qBAOa,cAAe,SAAQ,cAAc;IAChD,qCAAqC;IACzB,OAAO,EAAE,MAAM,CAAM;IAEjC,gBAAgB;IAChB,cAAc;IAMd;;;;;;;;;;;;;;;;OAgBG;IACH,OAAO,CAAC,aAAa;CAsBtB"}
@@ -1 +1 @@
1
- {"version":3,"file":"main.template.d.ts","sourceRoot":"","sources":["../../../src/main/main.template.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAEV,WAAW,EAGZ,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EAAuC,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAQ1F,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,QAAQ,CAAC;AAsIpD;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,wBAAwB,kDAWpC,CAAC;AAoJF;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,oBAAoB,GAAI,GAAG,qBAAqB,KAAG,MAYlD,CAAC;AAEf;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,mBAAmB,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,mBAAmB,GAAI,GAAG,qBAAqB,KAAG,MAAM,GAAG,IACpB,CAAC;AAyJrD,eAAO,MAAM,6BAA6B,GACxC,oBAAoB,MAAM,KACzB,YAAY,CAAC,qBAAqB,CA8qBpC,CAAC"}
1
+ {"version":3,"file":"main.template.d.ts","sourceRoot":"","sources":["../../../src/main/main.template.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAEV,WAAW,EAGZ,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EAAuC,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAQ1F,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,QAAQ,CAAC;AAsIpD;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,wBAAwB,kDAWpC,CAAC;AAoJF;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,oBAAoB,GAAI,GAAG,qBAAqB,KAAG,MAYlD,CAAC;AAEf;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,mBAAmB,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,mBAAmB,GAAI,GAAG,qBAAqB,KAAG,MAAM,GAAG,IACpB,CAAC;AAyJrD,eAAO,MAAM,6BAA6B,GACxC,oBAAoB,MAAM,KACzB,YAAY,CAAC,qBAAqB,CA8rBpC,CAAC"}
@@ -68,6 +68,47 @@ const styles = css `
68
68
  font-weight: 600;
69
69
  }
70
70
  `;
71
+ /**
72
+ * Element tag -> the shadow part it is exposed as.
73
+ *
74
+ * Markdown is rendered from a string at runtime, so there is no template on which to author
75
+ * `part=` attributes - which is why this component previously exposed nothing at all and an
76
+ * embedding app could only reach it through whichever global design tokens the rules below happen
77
+ * to use. Annotating the generated DOM gives an app ordinary CSS over each element type
78
+ * (`ai-chat-markdown::part(md-li) { ... }`) instead of a per-property token API that would have to
79
+ * grow every time someone wants to style something new.
80
+ *
81
+ * The vocabulary is deliberately a fixed list of element kinds rather than anything derived from
82
+ * the content: it is a public API surface, so it should change only when this map does.
83
+ */
84
+ const MARKDOWN_PARTS = {
85
+ P: 'md-p',
86
+ UL: 'md-ul',
87
+ OL: 'md-ol',
88
+ LI: 'md-li',
89
+ PRE: 'md-pre',
90
+ CODE: 'md-code',
91
+ A: 'md-link',
92
+ BLOCKQUOTE: 'md-quote',
93
+ TABLE: 'md-table',
94
+ THEAD: 'md-thead',
95
+ TBODY: 'md-tbody',
96
+ TR: 'md-tr',
97
+ TH: 'md-th',
98
+ TD: 'md-td',
99
+ HR: 'md-hr',
100
+ IMG: 'md-img',
101
+ STRONG: 'md-strong',
102
+ EM: 'md-em',
103
+ H1: 'md-h1',
104
+ H2: 'md-h2',
105
+ H3: 'md-h3',
106
+ H4: 'md-h4',
107
+ H5: 'md-h5',
108
+ H6: 'md-h6',
109
+ };
110
+ /** Tags whose part is also emitted with a nesting level (see {@link annotateParts}). */
111
+ const DEPTH_TAGGED = new Set(['UL', 'OL', 'LI']);
71
112
  let AiChatMarkdown = class AiChatMarkdown extends GenesisElement {
72
113
  constructor() {
73
114
  super(...arguments);
@@ -79,7 +120,41 @@ let AiChatMarkdown = class AiChatMarkdown extends GenesisElement {
79
120
  if (!this.content)
80
121
  return '';
81
122
  const rawHtml = marked.parse(this.content);
82
- return DOMPurify.sanitize(rawHtml);
123
+ return this.annotateParts(DOMPurify.sanitize(rawHtml));
124
+ }
125
+ /**
126
+ * Tag the generated elements with shadow parts so an embedding app can style them.
127
+ *
128
+ * Runs AFTER sanitising, deliberately. It only ever *adds* attributes to DOM DOMPurify has
129
+ * already cleared, so it introduces no new sanitiser surface - reversing the order would mean
130
+ * sanitising our own output and inviting the question of whether these attributes survive it.
131
+ *
132
+ * Lists additionally carry a level: a top-level list is `md-ul md-ul-level-1`, a list nested
133
+ * inside it is `md-ul-level-2`, and an `li` takes the level of the list holding it. Chat markdown
134
+ * rarely nests, so this is a safety valve rather than a feature - without it, every list at every
135
+ * depth would answer to one selector and there would be no way to tell them apart afterwards.
136
+ * Depth comes from walking the tree rather than from marked's renderers, which are invoked
137
+ * innermost-first and so cannot count downwards.
138
+ *
139
+ * An author-supplied `part` on inline HTML is overwritten: these parts are the documented
140
+ * contract, and two sources for one attribute would make which-wins depend on the markdown.
141
+ */
142
+ annotateParts(html) {
143
+ const template = document.createElement('template');
144
+ template.innerHTML = html;
145
+ const walk = (parent, listDepth) => {
146
+ for (const el of Array.from(parent.children)) {
147
+ const base = MARKDOWN_PARTS[el.tagName];
148
+ // A list opens the next level; everything else sits at its parent list's level.
149
+ const depth = el.tagName === 'UL' || el.tagName === 'OL' ? listDepth + 1 : listDepth;
150
+ if (base) {
151
+ el.setAttribute('part', DEPTH_TAGGED.has(el.tagName) ? `${base} ${base}-level-${depth}` : base);
152
+ }
153
+ walk(el, depth);
154
+ }
155
+ };
156
+ walk(template.content, 0);
157
+ return template.innerHTML;
83
158
  }
84
159
  };
85
160
  __decorate([
@@ -849,12 +849,27 @@ ${(tc) => { var _a; return (((_a = tc.foldPath) === null || _a === void 0 ? void
849
849
  ${when((x) => !!x.headerTitle, html `
850
850
  <span class="chat-title" part="chat-title">${(x) => x.headerTitle}</span>
851
851
  `)}
852
+ <!--
853
+ The two buttons below re-publish rapid-button's inner parts (control, content) into
854
+ THIS component's part namespace via exportparts.
855
+
856
+ Without it they are unreachable by an embedding app: part() crosses exactly one shadow
857
+ boundary, and the control sits two away (app -> foundation-ai-assistant ->
858
+ rapid-button -> control). Exposing only the button host leaves an app able to size the
859
+ box but not the padded control inside it, which is how Genesis Create ended up sizing
860
+ the host and clipping the overflow to flatten these buttons - a workaround for a
861
+ missing hook rather than a styling choice.
862
+
863
+ Named with the owning button as a prefix so the namespace stays legible as more parts
864
+ are exported, and so control does not collide across buttons.
865
+ -->
852
866
  <div class="header-actions" part="header-actions">
853
867
  <slot name="header-actions-extra"></slot>
854
868
  ${when((x) => !!x.popoutMode, html `
855
869
  <${buttonTag}
856
870
  class="popout-button"
857
871
  part="popout-button"
872
+ exportparts="control: popout-button-control, content: popout-button-content"
858
873
  appearance="stealth"
859
874
  title="${(x) => (x.popoutMode === 'expand' ? 'Expand to panel' : 'Pop back to bubble')}"
860
875
  ?disabled=${(x) => x.hasActivePendingInteraction}
@@ -864,6 +879,7 @@ ${(tc) => { var _a; return (((_a = tc.foldPath) === null || _a === void 0 ? void
864
879
  <${buttonTag}
865
880
  class="settings-button"
866
881
  part="settings-button"
882
+ exportparts="control: settings-button-control, content: settings-button-content"
867
883
  appearance="stealth"
868
884
  title="Settings"
869
885
  aria-haspopup="dialog"
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@genesislcap/ai-assistant",
3
3
  "description": "Genesis AI Assistant micro-frontend",
4
- "version": "15.28.1-FUI-0.6",
4
+ "version": "15.28.1-FUI-0.8",
5
5
  "license": "SEE LICENSE IN license.txt",
6
6
  "main": "dist/esm/index.js",
7
7
  "types": "dist/ai-assistant.d.ts",
@@ -74,26 +74,26 @@
74
74
  }
75
75
  },
76
76
  "devDependencies": {
77
- "@genesislcap/foundation-testing": "15.28.1-FUI-0.6",
78
- "@genesislcap/genx": "15.28.1-FUI-0.6",
79
- "@genesislcap/rollup-builder": "15.28.1-FUI-0.6",
80
- "@genesislcap/ts-builder": "15.28.1-FUI-0.6",
81
- "@genesislcap/uvu-playwright-builder": "15.28.1-FUI-0.6",
82
- "@genesislcap/vite-builder": "15.28.1-FUI-0.6",
83
- "@genesislcap/webpack-builder": "15.28.1-FUI-0.6",
77
+ "@genesislcap/foundation-testing": "15.28.1-FUI-0.8",
78
+ "@genesislcap/genx": "15.28.1-FUI-0.8",
79
+ "@genesislcap/rollup-builder": "15.28.1-FUI-0.8",
80
+ "@genesislcap/ts-builder": "15.28.1-FUI-0.8",
81
+ "@genesislcap/uvu-playwright-builder": "15.28.1-FUI-0.8",
82
+ "@genesislcap/vite-builder": "15.28.1-FUI-0.8",
83
+ "@genesislcap/webpack-builder": "15.28.1-FUI-0.8",
84
84
  "@types/dompurify": "^3.0.5",
85
85
  "@types/marked": "^5.0.2",
86
86
  "esbuild": "0.25.12"
87
87
  },
88
88
  "dependencies": {
89
- "@genesislcap/foundation-ai": "15.28.1-FUI-0.6",
90
- "@genesislcap/foundation-logger": "15.28.1-FUI-0.6",
91
- "@genesislcap/foundation-notifications": "15.28.1-FUI-0.6",
92
- "@genesislcap/foundation-redux": "15.28.1-FUI-0.6",
93
- "@genesislcap/foundation-ui": "15.28.1-FUI-0.6",
94
- "@genesislcap/foundation-utils": "15.28.1-FUI-0.6",
95
- "@genesislcap/rapid-design-system": "15.28.1-FUI-0.6",
96
- "@genesislcap/web-core": "15.28.1-FUI-0.6",
89
+ "@genesislcap/foundation-ai": "15.28.1-FUI-0.8",
90
+ "@genesislcap/foundation-logger": "15.28.1-FUI-0.8",
91
+ "@genesislcap/foundation-notifications": "15.28.1-FUI-0.8",
92
+ "@genesislcap/foundation-redux": "15.28.1-FUI-0.8",
93
+ "@genesislcap/foundation-ui": "15.28.1-FUI-0.8",
94
+ "@genesislcap/foundation-utils": "15.28.1-FUI-0.8",
95
+ "@genesislcap/rapid-design-system": "15.28.1-FUI-0.8",
96
+ "@genesislcap/web-core": "15.28.1-FUI-0.8",
97
97
  "dompurify": "^3.3.1",
98
98
  "marked": "^17.0.3"
99
99
  },