@craft-ts/component 0.7.0-beta.13

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 (190) hide show
  1. package/LICENSE +21 -0
  2. package/package.json +36 -0
  3. package/src/index.d.ts +40 -0
  4. package/src/index.d.ts.map +1 -0
  5. package/src/index.js +38 -0
  6. package/src/index.js.map +1 -0
  7. package/src/lib/a11y-control.d.ts +58 -0
  8. package/src/lib/a11y-control.d.ts.map +1 -0
  9. package/src/lib/a11y-control.js +74 -0
  10. package/src/lib/a11y-control.js.map +1 -0
  11. package/src/lib/a11y.d.ts +87 -0
  12. package/src/lib/a11y.d.ts.map +1 -0
  13. package/src/lib/a11y.js +96 -0
  14. package/src/lib/a11y.js.map +1 -0
  15. package/src/lib/ai/ai-context-menu.d.ts +140 -0
  16. package/src/lib/ai/ai-context-menu.d.ts.map +1 -0
  17. package/src/lib/ai/ai-context-menu.js +66 -0
  18. package/src/lib/ai/ai-context-menu.js.map +1 -0
  19. package/src/lib/ai/ai-send-dialog.d.ts +1263 -0
  20. package/src/lib/ai/ai-send-dialog.d.ts.map +1 -0
  21. package/src/lib/ai/ai-send-dialog.js +288 -0
  22. package/src/lib/ai/ai-send-dialog.js.map +1 -0
  23. package/src/lib/ai/send-context-to-ai.d.ts +29 -0
  24. package/src/lib/ai/send-context-to-ai.d.ts.map +1 -0
  25. package/src/lib/ai/send-context-to-ai.js +127 -0
  26. package/src/lib/ai/send-context-to-ai.js.map +1 -0
  27. package/src/lib/assert-defined-input.d.ts +26 -0
  28. package/src/lib/assert-defined-input.d.ts.map +1 -0
  29. package/src/lib/assert-defined-input.js +47 -0
  30. package/src/lib/assert-defined-input.js.map +1 -0
  31. package/src/lib/block.d.ts +36 -0
  32. package/src/lib/block.d.ts.map +1 -0
  33. package/src/lib/block.js +55 -0
  34. package/src/lib/block.js.map +1 -0
  35. package/src/lib/bootstrap.d.ts +32 -0
  36. package/src/lib/bootstrap.d.ts.map +1 -0
  37. package/src/lib/bootstrap.js +60 -0
  38. package/src/lib/bootstrap.js.map +1 -0
  39. package/src/lib/bridge.d.ts +56 -0
  40. package/src/lib/bridge.d.ts.map +1 -0
  41. package/src/lib/bridge.js +81 -0
  42. package/src/lib/bridge.js.map +1 -0
  43. package/src/lib/component.d.ts +46 -0
  44. package/src/lib/component.d.ts.map +1 -0
  45. package/src/lib/component.js +118 -0
  46. package/src/lib/component.js.map +1 -0
  47. package/src/lib/composition.d.ts +17 -0
  48. package/src/lib/composition.d.ts.map +1 -0
  49. package/src/lib/composition.js +28 -0
  50. package/src/lib/composition.js.map +1 -0
  51. package/src/lib/craft-defaults.d.ts +2 -0
  52. package/src/lib/craft-defaults.d.ts.map +1 -0
  53. package/src/lib/craft-defaults.js +41 -0
  54. package/src/lib/craft-defaults.js.map +1 -0
  55. package/src/lib/craft-host-tokens.d.ts +6 -0
  56. package/src/lib/craft-host-tokens.d.ts.map +1 -0
  57. package/src/lib/craft-host-tokens.js +7 -0
  58. package/src/lib/craft-host-tokens.js.map +1 -0
  59. package/src/lib/craft-router-outlet.d.ts +15 -0
  60. package/src/lib/craft-router-outlet.d.ts.map +1 -0
  61. package/src/lib/craft-router-outlet.js +10 -0
  62. package/src/lib/craft-router-outlet.js.map +1 -0
  63. package/src/lib/css-vars.d.ts +31 -0
  64. package/src/lib/css-vars.d.ts.map +1 -0
  65. package/src/lib/css-vars.js +43 -0
  66. package/src/lib/css-vars.js.map +1 -0
  67. package/src/lib/css-vars.type.d.ts +151 -0
  68. package/src/lib/css-vars.type.d.ts.map +1 -0
  69. package/src/lib/css-vars.type.js +1 -0
  70. package/src/lib/css-vars.type.js.map +1 -0
  71. package/src/lib/defer.d.ts +31 -0
  72. package/src/lib/defer.d.ts.map +1 -0
  73. package/src/lib/defer.js +19 -0
  74. package/src/lib/defer.js.map +1 -0
  75. package/src/lib/directive.d.ts +9 -0
  76. package/src/lib/directive.d.ts.map +1 -0
  77. package/src/lib/directive.js +31 -0
  78. package/src/lib/directive.js.map +1 -0
  79. package/src/lib/each-scheduling.d.ts +59 -0
  80. package/src/lib/each-scheduling.d.ts.map +1 -0
  81. package/src/lib/each-scheduling.js +120 -0
  82. package/src/lib/each-scheduling.js.map +1 -0
  83. package/src/lib/each.d.ts +29 -0
  84. package/src/lib/each.d.ts.map +1 -0
  85. package/src/lib/each.js +23 -0
  86. package/src/lib/each.js.map +1 -0
  87. package/src/lib/factory-runtime.d.ts +5 -0
  88. package/src/lib/factory-runtime.d.ts.map +1 -0
  89. package/src/lib/factory-runtime.js +26 -0
  90. package/src/lib/factory-runtime.js.map +1 -0
  91. package/src/lib/field-exception-block.d.ts +96 -0
  92. package/src/lib/field-exception-block.d.ts.map +1 -0
  93. package/src/lib/field-exception-block.js +44 -0
  94. package/src/lib/field-exception-block.js.map +1 -0
  95. package/src/lib/host-runtime.d.ts +60 -0
  96. package/src/lib/host-runtime.d.ts.map +1 -0
  97. package/src/lib/host-runtime.js +16 -0
  98. package/src/lib/host-runtime.js.map +1 -0
  99. package/src/lib/hydrate.d.ts +15 -0
  100. package/src/lib/hydrate.d.ts.map +1 -0
  101. package/src/lib/hydrate.js +79 -0
  102. package/src/lib/hydrate.js.map +1 -0
  103. package/src/lib/hyperscript.d.ts +148 -0
  104. package/src/lib/hyperscript.d.ts.map +1 -0
  105. package/src/lib/hyperscript.js +96 -0
  106. package/src/lib/hyperscript.js.map +1 -0
  107. package/src/lib/if-block.d.ts +8 -0
  108. package/src/lib/if-block.d.ts.map +1 -0
  109. package/src/lib/if-block.js +16 -0
  110. package/src/lib/if-block.js.map +1 -0
  111. package/src/lib/locator.d.ts +170 -0
  112. package/src/lib/locator.d.ts.map +1 -0
  113. package/src/lib/locator.js +151 -0
  114. package/src/lib/locator.js.map +1 -0
  115. package/src/lib/match-block.d.ts +38 -0
  116. package/src/lib/match-block.d.ts.map +1 -0
  117. package/src/lib/match-block.js +29 -0
  118. package/src/lib/match-block.js.map +1 -0
  119. package/src/lib/pending-block.d.ts +125 -0
  120. package/src/lib/pending-block.d.ts.map +1 -0
  121. package/src/lib/pending-block.js +48 -0
  122. package/src/lib/pending-block.js.map +1 -0
  123. package/src/lib/project.d.ts +19 -0
  124. package/src/lib/project.d.ts.map +1 -0
  125. package/src/lib/project.js +56 -0
  126. package/src/lib/project.js.map +1 -0
  127. package/src/lib/render/hydration-metadata.d.ts +3 -0
  128. package/src/lib/render/hydration-metadata.d.ts.map +1 -0
  129. package/src/lib/render/hydration-metadata.js +8 -0
  130. package/src/lib/render/hydration-metadata.js.map +1 -0
  131. package/src/lib/render/hydration.d.ts +24 -0
  132. package/src/lib/render/hydration.d.ts.map +1 -0
  133. package/src/lib/render/hydration.js +181 -0
  134. package/src/lib/render/hydration.js.map +1 -0
  135. package/src/lib/render/interpreter.d.ts +32 -0
  136. package/src/lib/render/interpreter.d.ts.map +1 -0
  137. package/src/lib/render/interpreter.js +3588 -0
  138. package/src/lib/render/interpreter.js.map +1 -0
  139. package/src/lib/render/server-style-collector.d.ts +6 -0
  140. package/src/lib/render/server-style-collector.d.ts.map +1 -0
  141. package/src/lib/render/server-style-collector.js +23 -0
  142. package/src/lib/render/server-style-collector.js.map +1 -0
  143. package/src/lib/render/ssr-coordinator.d.ts +20 -0
  144. package/src/lib/render/ssr-coordinator.d.ts.map +1 -0
  145. package/src/lib/render/ssr-coordinator.js +99 -0
  146. package/src/lib/render/ssr-coordinator.js.map +1 -0
  147. package/src/lib/render/string-dom.d.ts +9 -0
  148. package/src/lib/render/string-dom.d.ts.map +1 -0
  149. package/src/lib/render/string-dom.js +377 -0
  150. package/src/lib/render/string-dom.js.map +1 -0
  151. package/src/lib/render/style-registry.d.ts +14 -0
  152. package/src/lib/render/style-registry.d.ts.map +1 -0
  153. package/src/lib/render/style-registry.js +79 -0
  154. package/src/lib/render/style-registry.js.map +1 -0
  155. package/src/lib/render/style-scope.d.ts +30 -0
  156. package/src/lib/render/style-scope.d.ts.map +1 -0
  157. package/src/lib/render/style-scope.js +261 -0
  158. package/src/lib/render/style-scope.js.map +1 -0
  159. package/src/lib/render/vnode.d.ts +330 -0
  160. package/src/lib/render/vnode.d.ts.map +1 -0
  161. package/src/lib/render/vnode.js +293 -0
  162. package/src/lib/render/vnode.js.map +1 -0
  163. package/src/lib/server-render.d.ts +34 -0
  164. package/src/lib/server-render.d.ts.map +1 -0
  165. package/src/lib/server-render.js +84 -0
  166. package/src/lib/server-render.js.map +1 -0
  167. package/src/lib/start.d.ts +13 -0
  168. package/src/lib/start.d.ts.map +1 -0
  169. package/src/lib/start.js +20 -0
  170. package/src/lib/start.js.map +1 -0
  171. package/src/lib/template-contract.d.ts +347 -0
  172. package/src/lib/template-contract.d.ts.map +1 -0
  173. package/src/lib/template-contract.js +1 -0
  174. package/src/lib/template-contract.js.map +1 -0
  175. package/src/lib/template.d.ts +11 -0
  176. package/src/lib/template.d.ts.map +1 -0
  177. package/src/lib/template.js +21 -0
  178. package/src/lib/template.js.map +1 -0
  179. package/src/lib/testing.d.ts +157 -0
  180. package/src/lib/testing.d.ts.map +1 -0
  181. package/src/lib/testing.js +416 -0
  182. package/src/lib/testing.js.map +1 -0
  183. package/src/lib/types.d.ts +442 -0
  184. package/src/lib/types.d.ts.map +1 -0
  185. package/src/lib/types.js +22 -0
  186. package/src/lib/types.js.map +1 -0
  187. package/testing/public-api.d.ts +3 -0
  188. package/testing/public-api.d.ts.map +1 -0
  189. package/testing/public-api.js +3 -0
  190. package/testing/public-api.js.map +1 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-send-dialog.d.ts","sourceRoot":"","sources":["../../../../../../libs/component/src/lib/ai/ai-send-dialog.ts"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,kBAAkB,EACxB,MAAM,gBAAgB,CAAC;AAgBxB,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AA6C9C;;;GAGG;AACH,eAAO,MAAM,YAAY;;mBA4H8C,IAAI;;;;;;;uBAAJ,IAAI;;;aAArD,KAAK,CAAC,kBAAkB,CAAC,WAAW,MAAM,CAAC,MAAM,IAAI,CAAC;;0BAAL,IAAI;uBAsEpD,MAAM;8BACG,MAAM,KAAG,IAAI;kBAG3B,OAAO;;;;aA1EH,KAAK,CAAC,kBAAkB,CAAC,WAAW,MAAM,CAAC,MAAM,IAAI,CAAC;;0BAAL,IAAI;uBAsEpD,MAAM;8BACG,MAAM,KAAG,IAAI;kBAG3B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BA+DE,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BAAL,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BAAL,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BAAL,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BAAL,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BAAL,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BAAL,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BAAL,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mDA4C/B,CAAC"}
@@ -0,0 +1,288 @@
1
+ import { CRAFT_TEMPORAL_RUNTIME, craftMethod, craftUse, fromEventToSource$, state, } from '@craft-ts/core';
2
+ import { ɵtoCraftService as toCraftService } from '@craft-ts/core';
3
+ import { liveRegion } from '../a11y';
4
+ import { craftComponent } from '../component';
5
+ import { button, dialog, div, footer, header, label, section, span, strong, textarea, } from '../hyperscript';
6
+ const { CraftTemporalRuntime } = toCraftService({
7
+ name: 'CraftTemporalRuntime',
8
+ providedIn: 'global',
9
+ token: CRAFT_TEMPORAL_RUNTIME,
10
+ });
11
+ function formatPrompt(payload) {
12
+ const snapshotJson = (() => {
13
+ try {
14
+ return JSON.stringify(payload.snapshot, null, 2);
15
+ }
16
+ catch {
17
+ return '[unserializable snapshot]';
18
+ }
19
+ })();
20
+ return [
21
+ `# Instruction`,
22
+ payload.instruction,
23
+ ``,
24
+ `# Component clicked`,
25
+ `- hostName: ${payload.hostName}`,
26
+ `- tagList: ${JSON.stringify(payload.tagList)}`,
27
+ `- coords: (${payload.coords.x}, ${payload.coords.y})`,
28
+ ``,
29
+ `# Element outerHTML (truncated)`,
30
+ '```html',
31
+ payload.outerHTML,
32
+ '```',
33
+ ``,
34
+ `# App snapshot (${payload.snapshot.length} reports)`,
35
+ '```json',
36
+ snapshotJson,
37
+ '```',
38
+ ].join('\n');
39
+ }
40
+ /**
41
+ * Modal that collects an instruction and copies the formatted prompt, with the
42
+ * captured component context and app snapshot, to the clipboard.
43
+ */
44
+ export const AiSendDialog = craftComponent('AiSendDialog', {
45
+ styles: `
46
+ .craft-ai-overlay {
47
+ position: fixed;
48
+ inset: unset;
49
+ border: none;
50
+ background: transparent;
51
+ padding: 24px;
52
+ font-family:
53
+ system-ui,
54
+ -apple-system,
55
+ sans-serif;
56
+ font-size: 13px;
57
+ color: #111827;
58
+ }
59
+ .craft-ai-overlay::backdrop {
60
+ background: rgba(15, 23, 42, 0.5);
61
+ }
62
+ .craft-ai-card {
63
+ background: #ffffff;
64
+ border-radius: 8px;
65
+ box-shadow: 0 20px 50px rgba(0, 0, 0, 0.25);
66
+ width: min(560px, 100%);
67
+ max-height: 90vh;
68
+ overflow: auto;
69
+ padding: 16px 20px 20px;
70
+ display: flex;
71
+ flex-direction: column;
72
+ gap: 12px;
73
+ }
74
+ .craft-ai-header {
75
+ display: flex;
76
+ align-items: center;
77
+ justify-content: space-between;
78
+ font-size: 14px;
79
+ }
80
+ .craft-ai-close {
81
+ background: transparent;
82
+ border: none;
83
+ font-size: 20px;
84
+ line-height: 1;
85
+ cursor: pointer;
86
+ color: #6b7280;
87
+ }
88
+ .craft-ai-context {
89
+ background: #f9fafb;
90
+ border: 1px solid #e5e7eb;
91
+ border-radius: 6px;
92
+ padding: 8px 10px;
93
+ font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
94
+ font-size: 12px;
95
+ display: grid;
96
+ gap: 4px;
97
+ }
98
+ .craft-ai-context .label {
99
+ color: #6b7280;
100
+ margin-right: 4px;
101
+ }
102
+ .craft-ai-label {
103
+ font-weight: 600;
104
+ }
105
+ .craft-ai-textarea {
106
+ width: 100%;
107
+ box-sizing: border-box;
108
+ font-family: inherit;
109
+ font-size: 13px;
110
+ padding: 8px 10px;
111
+ border: 1px solid #d1d5db;
112
+ border-radius: 6px;
113
+ resize: vertical;
114
+ min-height: 96px;
115
+ }
116
+ .craft-ai-textarea:focus {
117
+ outline: 2px solid #3b82f6;
118
+ outline-offset: -1px;
119
+ }
120
+ .craft-ai-success {
121
+ background: #ecfdf5;
122
+ border: 1px solid #a7f3d0;
123
+ color: #065f46;
124
+ padding: 8px 10px;
125
+ border-radius: 6px;
126
+ }
127
+ .craft-ai-footer {
128
+ display: flex;
129
+ justify-content: flex-end;
130
+ gap: 8px;
131
+ }
132
+ .craft-ai-cancel {
133
+ background: #ffffff;
134
+ border: 1px solid #d1d5db;
135
+ padding: 6px 12px;
136
+ border-radius: 6px;
137
+ cursor: pointer;
138
+ }
139
+ .craft-ai-copy {
140
+ display: flex;
141
+ align-items: center;
142
+ gap: 6px;
143
+ background: #2563eb;
144
+ color: #ffffff;
145
+ border: none;
146
+ padding: 6px 14px;
147
+ border-radius: 6px;
148
+ cursor: pointer;
149
+ font-weight: 500;
150
+ transition: background 0.15s;
151
+ }
152
+ @media (prefers-reduced-motion: reduce) {
153
+ .craft-ai-copy {
154
+ transition: none;
155
+ }
156
+ }
157
+ .craft-ai-copy--done {
158
+ background: #059669;
159
+ }
160
+ .craft-ai-copy:disabled {
161
+ opacity: 0.6;
162
+ cursor: not-allowed;
163
+ }
164
+ `,
165
+ }, function* (payload, onClose) {
166
+ const temporalRuntime = yield* CraftTemporalRuntime();
167
+ // This component ships in a published package, so its inferred type goes
168
+ // through declaration emit. Reactive values (craft `state()`, Angular
169
+ // signals) carry `unique symbol`s that the emitter cannot name (TS4023),
170
+ // so the signals stay local and the context exposes plain accessors only.
171
+ const instruction = yield* state('instruction', '', ({ set }) => ({
172
+ setInstruction: (value) => set(value),
173
+ }));
174
+ const copied = yield* state('copied', false, ({ set }) => ({
175
+ setCopied: (value) => set(value),
176
+ }));
177
+ const setInstruction = craftMethod('setInstruction', function* (value) {
178
+ yield* instruction.setInstruction(value);
179
+ });
180
+ const setCopied = craftMethod('setCopied', function* (value) {
181
+ yield* copied.setCopied(value);
182
+ });
183
+ let copiedTimer = null;
184
+ fromEventToSource$(document, 'keydown').subscribe((event) => {
185
+ if (event.key === 'Escape') {
186
+ onClose();
187
+ }
188
+ });
189
+ const copy = () => {
190
+ const text = instruction().trim();
191
+ if (!text)
192
+ return;
193
+ const content = formatPrompt({
194
+ ...craftUse(payload()),
195
+ instruction: text,
196
+ });
197
+ void navigator.clipboard.writeText(content).then(() => {
198
+ setCopied(true);
199
+ copiedTimer?.cancel();
200
+ copiedTimer = temporalRuntime.schedule(() => {
201
+ setCopied(false);
202
+ }, 2500, {
203
+ kind: 'ai-copy-feedback',
204
+ owner: 'ai-send-dialog',
205
+ });
206
+ });
207
+ };
208
+ return {
209
+ payload,
210
+ onClose,
211
+ instruction: () => instruction(),
212
+ writeInstruction: (value) => {
213
+ setInstruction(value);
214
+ },
215
+ copied: () => copied(),
216
+ copy,
217
+ };
218
+ }, ({ payload, onClose, instruction, writeInstruction, copied, copy }) => dialog({
219
+ class: 'craft-ai-overlay',
220
+ open: true,
221
+ labelledBy: 'craft-ai-dialog-title',
222
+ onClose: () => onClose(),
223
+ }, div({
224
+ class: 'craft-ai-card',
225
+ }, [
226
+ header({ class: 'craft-ai-header' }, [
227
+ strong({ id: 'craft-ai-dialog-title' }, 'Send context to AI'),
228
+ button('aiDialogClose', {
229
+ type: 'button',
230
+ class: 'craft-ai-close',
231
+ 'aria-label': 'Close',
232
+ click: () => onClose(),
233
+ }, '×'),
234
+ ]),
235
+ section({ class: 'craft-ai-context' }, [
236
+ div([
237
+ span({ class: 'label' }, 'Component:'),
238
+ function* () {
239
+ return (yield* payload()).hostName;
240
+ },
241
+ ]),
242
+ div([
243
+ span({ class: 'label' }, 'Coords:'),
244
+ function* () {
245
+ const value = yield* payload();
246
+ return `(${value.coords.x}, ${value.coords.y})`;
247
+ },
248
+ ]),
249
+ div([
250
+ span({ class: 'label' }, 'Snapshot:'),
251
+ function* () {
252
+ return `${(yield* payload()).snapshot.length} report(s)`;
253
+ },
254
+ ]),
255
+ ]),
256
+ label({ class: 'craft-ai-label', htmlFor: 'craft-ai-instruction' }, 'Instruction'),
257
+ textarea('aiDialogInstruction', {
258
+ id: 'craft-ai-instruction',
259
+ class: 'craft-ai-textarea',
260
+ rows: 6,
261
+ value: instruction,
262
+ placeholder: 'Describe what you want the AI to do…',
263
+ input: (event) => writeInstruction(event.target.value),
264
+ }),
265
+ // Toggled by style rather than `ifBlock`, which needs a *named* craft
266
+ // value and would leak the same internal symbols into the type.
267
+ liveRegion({ politeness: 'polite' }, div({
268
+ class: 'craft-ai-success',
269
+ style: () => (copied() ? null : { display: 'none' }),
270
+ }, 'Copié dans le presse-papier ✓')),
271
+ footer({ class: 'craft-ai-footer' }, [
272
+ button('aiDialogCancel', {
273
+ type: 'button',
274
+ class: 'craft-ai-cancel',
275
+ click: () => onClose(),
276
+ }, 'Fermer'),
277
+ button('aiDialogCopy', {
278
+ type: 'button',
279
+ class: () => [
280
+ 'craft-ai-copy',
281
+ copied() && 'craft-ai-copy--done',
282
+ ],
283
+ disabled: () => !instruction().trim(),
284
+ click: copy,
285
+ }, () => (copied() ? '✓ Copié' : '⧉ Copier')),
286
+ ]),
287
+ ])));
288
+ //# sourceMappingURL=ai-send-dialog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-send-dialog.js","sourceRoot":"","sources":["../../../../../../libs/component/src/lib/ai/ai-send-dialog.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n CRAFT_TEMPORAL_RUNTIME,\n craftMethod,\n craftUse,\n fromEventToSource$,\n state,\n type CraftTemporalRuntime as CraftTemporalRuntimeApi,\n type TemporalTaskHandle,\n type SendContextPayload,\n} from '@craft-ts/core';\nimport { ɵtoCraftService as toCraftService } from '@craft-ts/core';\nimport { liveRegion } from '../a11y';\nimport { craftComponent } from '../component';\nimport {\n button,\n dialog,\n div,\n footer,\n header,\n label,\n section,\n span,\n strong,\n textarea,\n} from '../hyperscript';\nimport type { Input, Output } from '../types';\n\nconst { CraftTemporalRuntime } = toCraftService({\n name: 'CraftTemporalRuntime',\n providedIn: 'global',\n token: CRAFT_TEMPORAL_RUNTIME,\n}) as unknown as {\n CraftTemporalRuntime: () => Generator<\n never,\n CraftTemporalRuntimeApi,\n unknown\n >;\n};\n\nfunction formatPrompt(\n payload: SendContextPayload & { instruction: string },\n): string {\n const snapshotJson = (() => {\n try {\n return JSON.stringify(payload.snapshot, null, 2);\n } catch {\n return '[unserializable snapshot]';\n }\n })();\n return [\n `# Instruction`,\n payload.instruction,\n ``,\n `# Component clicked`,\n `- hostName: ${payload.hostName}`,\n `- tagList: ${JSON.stringify(payload.tagList)}`,\n `- coords: (${payload.coords.x}, ${payload.coords.y})`,\n ``,\n `# Element outerHTML (truncated)`,\n '```html',\n payload.outerHTML,\n '```',\n ``,\n `# App snapshot (${payload.snapshot.length} reports)`,\n '```json',\n snapshotJson,\n '```',\n ].join('\\n');\n}\n\n/**\n * Modal that collects an instruction and copies the formatted prompt, with the\n * captured component context and app snapshot, to the clipboard.\n */\nexport const AiSendDialog = craftComponent(\n 'AiSendDialog',\n {\n styles: `\n .craft-ai-overlay {\n position: fixed;\n inset: unset;\n border: none;\n background: transparent;\n padding: 24px;\n font-family:\n system-ui,\n -apple-system,\n sans-serif;\n font-size: 13px;\n color: #111827;\n }\n .craft-ai-overlay::backdrop {\n background: rgba(15, 23, 42, 0.5);\n }\n .craft-ai-card {\n background: #ffffff;\n border-radius: 8px;\n box-shadow: 0 20px 50px rgba(0, 0, 0, 0.25);\n width: min(560px, 100%);\n max-height: 90vh;\n overflow: auto;\n padding: 16px 20px 20px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n .craft-ai-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-size: 14px;\n }\n .craft-ai-close {\n background: transparent;\n border: none;\n font-size: 20px;\n line-height: 1;\n cursor: pointer;\n color: #6b7280;\n }\n .craft-ai-context {\n background: #f9fafb;\n border: 1px solid #e5e7eb;\n border-radius: 6px;\n padding: 8px 10px;\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 12px;\n display: grid;\n gap: 4px;\n }\n .craft-ai-context .label {\n color: #6b7280;\n margin-right: 4px;\n }\n .craft-ai-label {\n font-weight: 600;\n }\n .craft-ai-textarea {\n width: 100%;\n box-sizing: border-box;\n font-family: inherit;\n font-size: 13px;\n padding: 8px 10px;\n border: 1px solid #d1d5db;\n border-radius: 6px;\n resize: vertical;\n min-height: 96px;\n }\n .craft-ai-textarea:focus {\n outline: 2px solid #3b82f6;\n outline-offset: -1px;\n }\n .craft-ai-success {\n background: #ecfdf5;\n border: 1px solid #a7f3d0;\n color: #065f46;\n padding: 8px 10px;\n border-radius: 6px;\n }\n .craft-ai-footer {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n }\n .craft-ai-cancel {\n background: #ffffff;\n border: 1px solid #d1d5db;\n padding: 6px 12px;\n border-radius: 6px;\n cursor: pointer;\n }\n .craft-ai-copy {\n display: flex;\n align-items: center;\n gap: 6px;\n background: #2563eb;\n color: #ffffff;\n border: none;\n padding: 6px 14px;\n border-radius: 6px;\n cursor: pointer;\n font-weight: 500;\n transition: background 0.15s;\n }\n @media (prefers-reduced-motion: reduce) {\n .craft-ai-copy {\n transition: none;\n }\n }\n .craft-ai-copy--done {\n background: #059669;\n }\n .craft-ai-copy:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n `,\n },\n function* (payload: Input<SendContextPayload>, onClose: Output<() => void>) {\n const temporalRuntime = yield* CraftTemporalRuntime();\n type InstructionState = (() => string) & {\n setInstruction: (value: string) => Generator<unknown, unknown, unknown>;\n };\n type CopiedState = (() => boolean) & {\n setCopied: (value: boolean) => Generator<unknown, unknown, unknown>;\n };\n\n // This component ships in a published package, so its inferred type goes\n // through declaration emit. Reactive values (craft `state()`, Angular\n // signals) carry `unique symbol`s that the emitter cannot name (TS4023),\n // so the signals stay local and the context exposes plain accessors only.\n const instruction = yield* state('instruction', '', ({ set }) => ({\n setInstruction: (value: string) => set(value),\n })) as unknown as Generator<never, InstructionState, unknown>;\n const copied = yield* state('copied', false, ({ set }) => ({\n setCopied: (value: boolean) => set(value),\n })) as unknown as Generator<never, CopiedState, unknown>;\n\n const setInstruction: (value: string) => void = craftMethod(\n 'setInstruction',\n function* (value: string) {\n yield* instruction.setInstruction(value);\n },\n );\n const setCopied: (value: boolean) => void = craftMethod(\n 'setCopied',\n function* (value: boolean) {\n yield* copied.setCopied(value);\n },\n );\n\n let copiedTimer: TemporalTaskHandle | null = null;\n\n fromEventToSource$<KeyboardEvent>(document, 'keydown').subscribe(\n (event) => {\n if (event.key === 'Escape') {\n onClose();\n }\n },\n );\n\n const copy = () => {\n const text = instruction().trim();\n if (!text) return;\n\n const content = formatPrompt({\n ...craftUse(payload()),\n instruction: text,\n });\n void navigator.clipboard.writeText(content).then(() => {\n setCopied(true);\n copiedTimer?.cancel();\n copiedTimer = temporalRuntime.schedule(\n () => {\n setCopied(false);\n },\n 2500,\n {\n kind: 'ai-copy-feedback',\n owner: 'ai-send-dialog',\n },\n );\n });\n };\n\n return {\n payload,\n onClose,\n instruction: (): string => instruction(),\n writeInstruction: (value: string): void => {\n setInstruction(value);\n },\n copied: (): boolean => copied(),\n copy,\n };\n },\n ({ payload, onClose, instruction, writeInstruction, copied, copy }) =>\n dialog(\n {\n class: 'craft-ai-overlay',\n open: true,\n labelledBy: 'craft-ai-dialog-title',\n onClose: () => onClose(),\n },\n div(\n {\n class: 'craft-ai-card',\n },\n [\n header({ class: 'craft-ai-header' }, [\n strong({ id: 'craft-ai-dialog-title' }, 'Send context to AI'),\n button(\n 'aiDialogClose',\n {\n type: 'button',\n class: 'craft-ai-close',\n 'aria-label': 'Close',\n click: () => onClose(),\n },\n '×',\n ),\n ]),\n\n section({ class: 'craft-ai-context' }, [\n div([\n span({ class: 'label' }, 'Component:'),\n function* () {\n return (yield* payload()).hostName;\n },\n ]),\n div([\n span({ class: 'label' }, 'Coords:'),\n function* () {\n const value = yield* payload();\n return `(${value.coords.x}, ${value.coords.y})`;\n },\n ]),\n div([\n span({ class: 'label' }, 'Snapshot:'),\n function* () {\n return `${(yield* payload()).snapshot.length} report(s)`;\n },\n ]),\n ]),\n\n label(\n { class: 'craft-ai-label', htmlFor: 'craft-ai-instruction' },\n 'Instruction',\n ),\n textarea('aiDialogInstruction', {\n id: 'craft-ai-instruction',\n class: 'craft-ai-textarea',\n rows: 6,\n value: instruction,\n placeholder: 'Describe what you want the AI to do…',\n input: (event: Event) =>\n writeInstruction((event.target as HTMLTextAreaElement).value),\n }),\n\n // Toggled by style rather than `ifBlock`, which needs a *named* craft\n // value and would leak the same internal symbols into the type.\n liveRegion(\n { politeness: 'polite' },\n div(\n {\n class: 'craft-ai-success',\n style: () => (copied() ? null : { display: 'none' }),\n },\n 'Copié dans le presse-papier ✓',\n ),\n ),\n\n footer({ class: 'craft-ai-footer' }, [\n button(\n 'aiDialogCancel',\n {\n type: 'button',\n class: 'craft-ai-cancel',\n click: () => onClose(),\n },\n 'Fermer',\n ),\n button(\n 'aiDialogCopy',\n {\n type: 'button',\n class: () => [\n 'craft-ai-copy',\n copied() && 'craft-ai-copy--done',\n ],\n disabled: () => !instruction().trim(),\n click: copy,\n },\n () => (copied() ? '✓ Copié' : '⧉ Copier'),\n ),\n ]),\n ],\n ),\n ),\n);\n"]}
@@ -0,0 +1,29 @@
1
+ import { DestroyRef, Injector, type Provider } from '../host-runtime';
2
+ import { SendContextToAiBuffer, TAKE_APP_SNAPSHOT, type CraftToken, type GetDeps, type SendContextPayload, type TemporalTaskHandle } from '@craft-ts/core';
3
+ export type AiContextMenuController = {
4
+ open(ctx: Omit<SendContextPayload, 'snapshot'>): void;
5
+ };
6
+ export declare const AI_CONTEXT_MENU_CONTROLLER: CraftToken<AiContextMenuController>;
7
+ export declare function createAiContextMenuController({ injector, buffer, takeSnapshot, temporalRuntime, destroyRef, }: {
8
+ injector: Injector;
9
+ buffer: SendContextToAiBuffer;
10
+ takeSnapshot: () => void;
11
+ temporalRuntime: {
12
+ schedule(callback: () => void, delay: number, options: {
13
+ kind: string;
14
+ owner: string;
15
+ destroyRef: DestroyRef;
16
+ }): TemporalTaskHandle;
17
+ };
18
+ destroyRef: DestroyRef;
19
+ }): AiContextMenuController;
20
+ export declare function provideSendContextToAi(): Provider[];
21
+ export type GenDeps_AiContextMenuController = GetDeps<{
22
+ deps: {};
23
+ provided: {};
24
+ missingProvider: {
25
+ Injector: Injector;
26
+ TAKE_APP_SNAPSHOT: typeof TAKE_APP_SNAPSHOT;
27
+ };
28
+ }>;
29
+ //# sourceMappingURL=send-context-to-ai.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"send-context-to-ai.d.ts","sourceRoot":"","sources":["../../../../../../libs/component/src/lib/ai/send-context-to-ai.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EAGV,QAAQ,EAER,KAAK,QAAQ,EAEd,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAUL,qBAAqB,EACrB,iBAAiB,EACjB,KAAK,UAAU,EACf,KAAK,OAAO,EACZ,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACxB,MAAM,gBAAgB,CAAC;AAuCxB,MAAM,MAAM,uBAAuB,GAAG;IACpC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,kBAAkB,EAAE,UAAU,CAAC,GAAG,IAAI,CAAC;CACvD,CAAC;AAEF,eAAO,MAAM,0BAA0B,qCAEtC,CAAC;AAEF,wBAAgB,6BAA6B,CAAC,EAC5C,QAAQ,EACR,MAAM,EACN,YAAY,EACZ,eAAe,EACf,UAAU,GACX,EAAE;IACD,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,qBAAqB,CAAC;IAC9B,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,eAAe,EAAE;QACf,QAAQ,CACN,QAAQ,EAAE,MAAM,IAAI,EACpB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE;YACP,IAAI,EAAE,MAAM,CAAC;YACb,KAAK,EAAE,MAAM,CAAC;YACd,UAAU,EAAE,UAAU,CAAC;SACxB,GACA,kBAAkB,CAAC;KACvB,CAAC;IACF,UAAU,EAAE,UAAU,CAAC;CACxB,GAAG,uBAAuB,CAiE1B;AAMD,wBAAgB,sBAAsB,IAAI,QAAQ,EAAE,CA+CnD;AAED,MAAM,MAAM,+BAA+B,GAAG,OAAO,CAAC;IACpD,IAAI,EAAE,EAAE,CAAC;IACT,QAAQ,EAAE,EAAE,CAAC;IACb,eAAe,EAAE;QACf,QAAQ,EAAE,QAAQ,CAAC;QACnB,iBAAiB,EAAE,OAAO,iBAAiB,CAAC;KAC7C,CAAC;CACH,CAAC,CAAC"}
@@ -0,0 +1,127 @@
1
+ import { DestroyRef, ElementRef, inject, Injector, runInInjectionContext, } from '../host-runtime';
2
+ import { APP_SNAPSHOT_REGISTRY, craftToken, createSendContextToAiBuffer, fromEventToSource$, HOST_TAG_LIST, CRAFT_TEMPORAL_RUNTIME, injectHostName, provideComponentMonitoring, SEND_CONTEXT_TO_AI_BUFFER, TAKE_APP_SNAPSHOT, } from '@craft-ts/core';
3
+ import { mountCraftComponent } from '../bridge';
4
+ import { AiContextMenu } from './ai-context-menu';
5
+ import { AiSendDialog } from './ai-send-dialog';
6
+ const HANDLED_FLAG = Symbol('craft-ai-contextmenu-handled');
7
+ /**
8
+ * Creates the full-screen host element the craft overlay is mounted into.
9
+ * These are the styles the components used to carry on their `:host`.
10
+ */
11
+ function openOverlay(zIndex, pointerEvents, mount) {
12
+ const host = document.createElement('div');
13
+ host.style.position = 'fixed';
14
+ host.style.inset = '0';
15
+ host.style.zIndex = String(zIndex);
16
+ host.style.pointerEvents = pointerEvents;
17
+ document.body.appendChild(host);
18
+ return { host, mount: mount(host) };
19
+ }
20
+ function closeOverlay(overlay) {
21
+ if (overlay) {
22
+ overlay.mount.destroy();
23
+ overlay.host.remove();
24
+ }
25
+ return null;
26
+ }
27
+ export const AI_CONTEXT_MENU_CONTROLLER = craftToken('AiContextMenuController');
28
+ export function createAiContextMenuController({ injector, buffer, takeSnapshot, temporalRuntime, destroyRef, }) {
29
+ let menu = null;
30
+ let dialog = null;
31
+ let dialogTimer = null;
32
+ function closeMenu() {
33
+ menu = closeOverlay(menu);
34
+ }
35
+ function closeDialog() {
36
+ dialog = closeOverlay(dialog);
37
+ }
38
+ function openDialog(payload) {
39
+ dialog = openOverlay(99999, 'auto', (host) => mountCraftComponent(AiSendDialog, host, injector, {
40
+ payload: function* () {
41
+ return payload;
42
+ },
43
+ onClose: closeDialog,
44
+ }));
45
+ }
46
+ function onSelect(ctx) {
47
+ closeMenu();
48
+ // Wait for the snapshot buffer's debounceTime(500ms) to settle.
49
+ dialogTimer = temporalRuntime.schedule(() => {
50
+ dialogTimer = null;
51
+ openDialog({ ...ctx, snapshot: buffer.latestReports });
52
+ }, 550, {
53
+ kind: 'ai-context-debounce',
54
+ owner: 'ai-context-menu',
55
+ destroyRef,
56
+ });
57
+ }
58
+ return {
59
+ open(ctx) {
60
+ dialogTimer?.cancel();
61
+ dialogTimer = null;
62
+ closeMenu();
63
+ closeDialog();
64
+ // Trigger a snapshot collection now so the buffer is populated
65
+ // by the time the user submits the dialog.
66
+ takeSnapshot();
67
+ menu = openOverlay(99998, 'none', (host) => mountCraftComponent(AiContextMenu, host, injector, {
68
+ x: function* () {
69
+ return ctx.coords.x;
70
+ },
71
+ y: function* () {
72
+ return ctx.coords.y;
73
+ },
74
+ onSelect: () => onSelect(ctx),
75
+ onDismiss: closeMenu,
76
+ }));
77
+ },
78
+ };
79
+ }
80
+ function asAngularToken(token) {
81
+ return token;
82
+ }
83
+ export function provideSendContextToAi() {
84
+ return [
85
+ {
86
+ provide: asAngularToken(SEND_CONTEXT_TO_AI_BUFFER),
87
+ useFactory: () => createSendContextToAiBuffer(inject(APP_SNAPSHOT_REGISTRY)),
88
+ },
89
+ {
90
+ provide: asAngularToken(AI_CONTEXT_MENU_CONTROLLER),
91
+ useFactory: () => createAiContextMenuController({
92
+ injector: inject(Injector),
93
+ buffer: inject(asAngularToken(SEND_CONTEXT_TO_AI_BUFFER)),
94
+ takeSnapshot: inject(TAKE_APP_SNAPSHOT),
95
+ temporalRuntime: inject(CRAFT_TEMPORAL_RUNTIME),
96
+ destroyRef: inject(DestroyRef),
97
+ }),
98
+ },
99
+ provideComponentMonitoring(() => {
100
+ const el = inject(ElementRef).nativeElement;
101
+ const tagList = inject(HOST_TAG_LIST, { optional: true });
102
+ const injector = inject(Injector);
103
+ const controller = inject(asAngularToken(AI_CONTEXT_MENU_CONTROLLER));
104
+ // Eagerly instantiate the buffer so snapshot reports start being collected.
105
+ inject(asAngularToken(SEND_CONTEXT_TO_AI_BUFFER));
106
+ fromEventToSource$(el, 'contextmenu').subscribe((event) => {
107
+ const handled = event;
108
+ if (handled[HANDLED_FLAG])
109
+ return;
110
+ handled[HANDLED_FLAG] = true;
111
+ event.preventDefault();
112
+ event.stopPropagation();
113
+ runInInjectionContext(injector, () => {
114
+ const hostName = injectHostName();
115
+ const outerHTML = (el.outerHTML ?? '').slice(0, 2000);
116
+ controller.open({
117
+ hostName,
118
+ tagList,
119
+ coords: { x: event.clientX, y: event.clientY },
120
+ outerHTML,
121
+ });
122
+ });
123
+ });
124
+ }),
125
+ ];
126
+ }
127
+ //# sourceMappingURL=send-context-to-ai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"send-context-to-ai.js","sourceRoot":"","sources":["../../../../../../libs/component/src/lib/ai/send-context-to-ai.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n DestroyRef,\n ElementRef,\n inject,\n Injector,\n runInInjectionContext,\n type Provider,\n type ProviderToken,\n} from '../host-runtime';\nimport {\n APP_SNAPSHOT_REGISTRY,\n craftToken,\n createSendContextToAiBuffer,\n fromEventToSource$,\n HOST_TAG_LIST,\n CRAFT_TEMPORAL_RUNTIME,\n injectHostName,\n provideComponentMonitoring,\n SEND_CONTEXT_TO_AI_BUFFER,\n SendContextToAiBuffer,\n TAKE_APP_SNAPSHOT,\n type CraftToken,\n type GetDeps,\n type SendContextPayload,\n type TemporalTaskHandle,\n} from '@craft-ts/core';\nimport { mountCraftComponent } from '../bridge';\nimport { AiContextMenu } from './ai-context-menu';\nimport { AiSendDialog } from './ai-send-dialog';\n\nconst HANDLED_FLAG = Symbol('craft-ai-contextmenu-handled');\ntype HandledEvent = MouseEvent & { [HANDLED_FLAG]?: true };\n\ntype Overlay = {\n readonly host: HTMLElement;\n readonly mount: { destroy(): void };\n};\n\n/**\n * Creates the full-screen host element the craft overlay is mounted into.\n * These are the styles the components used to carry on their `:host`.\n */\nfunction openOverlay(\n zIndex: number,\n pointerEvents: 'none' | 'auto',\n mount: (host: HTMLElement) => { destroy(): void },\n): Overlay {\n const host = document.createElement('div');\n host.style.position = 'fixed';\n host.style.inset = '0';\n host.style.zIndex = String(zIndex);\n host.style.pointerEvents = pointerEvents;\n document.body.appendChild(host);\n return { host, mount: mount(host) };\n}\n\nfunction closeOverlay(overlay: Overlay | null): null {\n if (overlay) {\n overlay.mount.destroy();\n overlay.host.remove();\n }\n return null;\n}\n\nexport type AiContextMenuController = {\n open(ctx: Omit<SendContextPayload, 'snapshot'>): void;\n};\n\nexport const AI_CONTEXT_MENU_CONTROLLER = craftToken<AiContextMenuController>(\n 'AiContextMenuController',\n);\n\nexport function createAiContextMenuController({\n injector,\n buffer,\n takeSnapshot,\n temporalRuntime,\n destroyRef,\n}: {\n injector: Injector;\n buffer: SendContextToAiBuffer;\n takeSnapshot: () => void;\n temporalRuntime: {\n schedule(\n callback: () => void,\n delay: number,\n options: {\n kind: string;\n owner: string;\n destroyRef: DestroyRef;\n },\n ): TemporalTaskHandle;\n };\n destroyRef: DestroyRef;\n}): AiContextMenuController {\n let menu: Overlay | null = null;\n let dialog: Overlay | null = null;\n let dialogTimer: TemporalTaskHandle | null = null;\n\n function closeMenu(): void {\n menu = closeOverlay(menu);\n }\n\n function closeDialog(): void {\n dialog = closeOverlay(dialog);\n }\n\n function openDialog(payload: SendContextPayload): void {\n dialog = openOverlay(99999, 'auto', (host) =>\n mountCraftComponent(AiSendDialog, host, injector, {\n payload: function* () {\n return payload;\n },\n onClose: closeDialog,\n }),\n );\n }\n\n function onSelect(ctx: Omit<SendContextPayload, 'snapshot'>): void {\n closeMenu();\n // Wait for the snapshot buffer's debounceTime(500ms) to settle.\n dialogTimer = temporalRuntime.schedule(\n () => {\n dialogTimer = null;\n openDialog({ ...ctx, snapshot: buffer.latestReports });\n },\n 550,\n {\n kind: 'ai-context-debounce',\n owner: 'ai-context-menu',\n destroyRef,\n },\n );\n }\n\n return {\n open(ctx: Omit<SendContextPayload, 'snapshot'>): void {\n dialogTimer?.cancel();\n dialogTimer = null;\n closeMenu();\n closeDialog();\n // Trigger a snapshot collection now so the buffer is populated\n // by the time the user submits the dialog.\n takeSnapshot();\n\n menu = openOverlay(99998, 'none', (host) =>\n mountCraftComponent(AiContextMenu, host, injector, {\n x: function* () {\n return ctx.coords.x;\n },\n y: function* () {\n return ctx.coords.y;\n },\n onSelect: () => onSelect(ctx),\n onDismiss: closeMenu,\n }),\n );\n },\n };\n}\n\nfunction asAngularToken<T>(token: CraftToken<T>): ProviderToken<T> {\n return token as unknown as ProviderToken<T>;\n}\n\nexport function provideSendContextToAi(): Provider[] {\n return [\n {\n provide: asAngularToken(SEND_CONTEXT_TO_AI_BUFFER),\n useFactory: () =>\n createSendContextToAiBuffer(inject(APP_SNAPSHOT_REGISTRY)),\n },\n {\n provide: asAngularToken(AI_CONTEXT_MENU_CONTROLLER),\n useFactory: () =>\n createAiContextMenuController({\n injector: inject(Injector),\n buffer: inject(asAngularToken(SEND_CONTEXT_TO_AI_BUFFER)),\n takeSnapshot: inject(TAKE_APP_SNAPSHOT),\n temporalRuntime: inject(CRAFT_TEMPORAL_RUNTIME),\n destroyRef: inject(DestroyRef),\n }),\n },\n provideComponentMonitoring(() => {\n const el = inject(ElementRef).nativeElement as HTMLElement;\n const tagList = inject(HOST_TAG_LIST, { optional: true }) as unknown;\n const injector = inject(Injector);\n const controller = inject(asAngularToken(AI_CONTEXT_MENU_CONTROLLER));\n // Eagerly instantiate the buffer so snapshot reports start being collected.\n inject(asAngularToken(SEND_CONTEXT_TO_AI_BUFFER));\n\n fromEventToSource$<MouseEvent>(el, 'contextmenu').subscribe((event) => {\n const handled = event as HandledEvent;\n if (handled[HANDLED_FLAG]) return;\n handled[HANDLED_FLAG] = true;\n\n event.preventDefault();\n event.stopPropagation();\n\n runInInjectionContext(injector, () => {\n const hostName = injectHostName();\n const outerHTML = (el.outerHTML ?? '').slice(0, 2000);\n controller.open({\n hostName,\n tagList,\n coords: { x: event.clientX, y: event.clientY },\n outerHTML,\n });\n });\n });\n }),\n ];\n}\n\nexport type GenDeps_AiContextMenuController = GetDeps<{\n deps: {};\n provided: {};\n missingProvider: {\n Injector: Injector;\n TAKE_APP_SNAPSHOT: typeof TAKE_APP_SNAPSHOT;\n };\n}>;\n"]}
@@ -0,0 +1,26 @@
1
+ import { type CatchTagExhaustiveCodesCheck, type CraftExceptionResult } from '@craft-ts/core';
2
+ import type { CraftInputExceptionsCarrier, Input } from './types';
3
+ export declare const CRAFT_UNDEFINED_PROPERTY_EXCEPTION_CODE: "CraftUndefinedPropertyException";
4
+ export type CraftUndefinedPropertyException = CraftExceptionResult<{
5
+ readonly _tag: typeof CRAFT_UNDEFINED_PROPERTY_EXCEPTION_CODE;
6
+ }, {
7
+ readonly property?: string;
8
+ }>;
9
+ type InputPipeOperator<SourceValue, OutputValue> = (source: Input<SourceValue>) => Input<OutputValue>;
10
+ export type PipeableInput<Value> = Input<Value> & {
11
+ pipe<OutputValue>(operator: InputPipeOperator<Value, OutputValue>): PipeableInput<OutputValue>;
12
+ };
13
+ type AssertDefinedInputHandler = (exception: CraftUndefinedPropertyException) => unknown;
14
+ type AssertDefinedInputHandlers = Record<typeof CRAFT_UNDEFINED_PROPERTY_EXCEPTION_CODE, AssertDefinedInputHandler>;
15
+ type HandlerOutput<Handlers extends AssertDefinedInputHandlers> = ReturnType<Handlers[typeof CRAFT_UNDEFINED_PROPERTY_EXCEPTION_CODE]>;
16
+ export declare function craftUndefinedPropertyException(property?: string): CraftUndefinedPropertyException;
17
+ export type AssertDefinedInput<Value> = Input<Exclude<Value, undefined>> & CraftInputExceptionsCarrier<typeof CRAFT_UNDEFINED_PROPERTY_EXCEPTION_CODE> & Pick<PipeableInput<Exclude<Value, undefined>>, 'pipe'>;
18
+ /** Creates an input which narrows away undefined and short-circuits when absent. */
19
+ export declare function assertDefinedInput<Value>(source: Input<Value | undefined>, options?: {
20
+ readonly property?: string;
21
+ }): AssertDefinedInput<Value>;
22
+ export declare const catchInput: {
23
+ exhaustive<const Handlers extends AssertDefinedInputHandlers>(handlers: Handlers & CatchTagExhaustiveCodesCheck<typeof CRAFT_UNDEFINED_PROPERTY_EXCEPTION_CODE, Handlers>): <Value>(source: Input<Value>) => PipeableInput<Exclude<Value, undefined> | HandlerOutput<Handlers>>;
24
+ };
25
+ export {};
26
+ //# sourceMappingURL=assert-defined-input.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assert-defined-input.d.ts","sourceRoot":"","sources":["../../../../../libs/component/src/lib/assert-defined-input.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,4BAA4B,EACjC,KAAK,oBAAoB,EAC1B,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,2BAA2B,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAElE,eAAO,MAAM,uCAAuC,EAClD,iCAA0C,CAAC;AAE7C,MAAM,MAAM,+BAA+B,GAAG,oBAAoB,CAChE;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,uCAAuC,CAAA;CAAE,EACjE;IAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAC/B,CAAC;AAEF,KAAK,iBAAiB,CAAC,WAAW,EAAE,WAAW,IAAI,CACjD,MAAM,EAAE,KAAK,CAAC,WAAW,CAAC,KACvB,KAAK,CAAC,WAAW,CAAC,CAAC;AAExB,MAAM,MAAM,aAAa,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,CAAC,GAAG;IAChD,IAAI,CAAC,WAAW,EACd,QAAQ,EAAE,iBAAiB,CAAC,KAAK,EAAE,WAAW,CAAC,GAC9C,aAAa,CAAC,WAAW,CAAC,CAAC;CAC/B,CAAC;AAEF,KAAK,yBAAyB,GAAG,CAC/B,SAAS,EAAE,+BAA+B,KACvC,OAAO,CAAC;AAEb,KAAK,0BAA0B,GAAG,MAAM,CACtC,OAAO,uCAAuC,EAC9C,yBAAyB,CAC1B,CAAC;AAEF,KAAK,aAAa,CAAC,QAAQ,SAAS,0BAA0B,IAAI,UAAU,CAC1E,QAAQ,CAAC,OAAO,uCAAuC,CAAC,CACzD,CAAC;AAEF,wBAAgB,+BAA+B,CAC7C,QAAQ,CAAC,EAAE,MAAM,GAChB,+BAA+B,CAQjC;AAED,MAAM,MAAM,kBAAkB,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,GACtE,2BAA2B,CAAC,OAAO,uCAAuC,CAAC,GAC3E,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;AAiBzD,oFAAoF;AACpF,wBAAgB,kBAAkB,CAAC,KAAK,EACtC,MAAM,EAAE,KAAK,CAAC,KAAK,GAAG,SAAS,CAAC,EAChC,OAAO,GAAE;IAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GAC3C,kBAAkB,CAAC,KAAK,CAAC,CAW3B;AAED,eAAO,MAAM,UAAU;qBACJ,QAAQ,SAAS,0BAA0B,YAChD,QAAQ,GAChB,4BAA4B,CAC1B,OAAO,uCAAuC,EAC9C,QAAQ,CACT,IAEK,KAAK,EACX,QAAQ,KAAK,CAAC,KAAK,CAAC,KACnB,aAAa,CACd,OAAO,CAAC,KAAK,EAAE,SAAS,CAAC,GAAG,aAAa,CAAC,QAAQ,CAAC,CACpD;CAsBJ,CAAC"}
@@ -0,0 +1,47 @@
1
+ import { CraftGenShortCircuit, craftException, isCraftGenShortCircuit, } from '@craft-ts/core';
2
+ export const CRAFT_UNDEFINED_PROPERTY_EXCEPTION_CODE = 'CraftUndefinedPropertyException';
3
+ export function craftUndefinedPropertyException(property) {
4
+ const payload = property === undefined ? {} : { property };
5
+ return craftException({ _tag: CRAFT_UNDEFINED_PROPERTY_EXCEPTION_CODE }, payload);
6
+ }
7
+ function pipeableInput(source) {
8
+ const input = source;
9
+ if (Object.prototype.hasOwnProperty.call(input, 'pipe')) {
10
+ return input;
11
+ }
12
+ Object.defineProperty(input, 'pipe', {
13
+ value: (operator) => pipeableInput(operator(input)),
14
+ enumerable: false,
15
+ });
16
+ return input;
17
+ }
18
+ /** Creates an input which narrows away undefined and short-circuits when absent. */
19
+ export function assertDefinedInput(source, options = {}) {
20
+ return pipeableInput(function* () {
21
+ const value = yield* source();
22
+ if (value !== undefined) {
23
+ return value;
24
+ }
25
+ throw new CraftGenShortCircuit(craftUndefinedPropertyException(options.property));
26
+ });
27
+ }
28
+ export const catchInput = {
29
+ exhaustive(handlers) {
30
+ return (source) => pipeableInput(function* () {
31
+ try {
32
+ return (yield* source());
33
+ }
34
+ catch (error) {
35
+ if (!isCraftGenShortCircuit(error)) {
36
+ throw error;
37
+ }
38
+ if (error.exception._tag !==
39
+ CRAFT_UNDEFINED_PROPERTY_EXCEPTION_CODE) {
40
+ throw error;
41
+ }
42
+ return handlers[CRAFT_UNDEFINED_PROPERTY_EXCEPTION_CODE](error.exception);
43
+ }
44
+ });
45
+ },
46
+ };
47
+ //# sourceMappingURL=assert-defined-input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assert-defined-input.js","sourceRoot":"","sources":["../../../../../libs/component/src/lib/assert-defined-input.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,cAAc,EACd,sBAAsB,GAGvB,MAAM,gBAAgB,CAAC;AAGxB,MAAM,CAAC,MAAM,uCAAuC,GAClD,iCAA0C,CAAC;AA8B7C,MAAM,UAAU,+BAA+B,CAC7C,QAAiB;IAEjB,MAAM,OAAO,GACX,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC;IAE7C,OAAO,cAAc,CACnB,EAAE,IAAI,EAAE,uCAAuC,EAAE,EACjD,OAAO,CACR,CAAC;AACJ,CAAC;AAMD,SAAS,aAAa,CAAQ,MAAoB;IAChD,MAAM,KAAK,GAAG,MAA8B,CAAC;IAC7C,IAAI,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC;QACxD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,CAAC,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE;QACnC,KAAK,EAAE,CACL,QAA+C,EACnB,EAAE,CAAC,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC/D,UAAU,EAAE,KAAK;KAClB,CAAC,CAAC;IACH,OAAO,KAAK,CAAC;AACf,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,kBAAkB,CAChC,MAAgC,EAChC,UAA0C,EAAE;IAE5C,OAAO,aAAa,CAAC,QAAQ,CAAC;QAC5B,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC;QAC9B,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,OAAO,KAAkC,CAAC;QAC5C,CAAC;QAED,MAAM,IAAI,oBAAoB,CAC5B,+BAA+B,CAAC,OAAO,CAAC,QAAQ,CAAC,CAClD,CAAC;IACJ,CAAqC,CAA8B,CAAC;AACtE,CAAC;AAED,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,UAAU,CACR,QAIG;QAEH,OAAO,CACL,MAAoB,EAGpB,EAAE,CACF,aAAa,CAAC,QAAQ,CAAC;YACrB,IAAI,CAAC;gBACH,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,CAA8B,CAAC;YACxD,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,CAAC,sBAAsB,CAAC,KAAK,CAAC,EAAE,CAAC;oBACnC,MAAM,KAAK,CAAC;gBACd,CAAC;gBAED,IACE,KAAK,CAAC,SAAS,CAAC,IAAI;oBACpB,uCAAuC,EACvC,CAAC;oBACD,MAAM,KAAK,CAAC;gBACd,CAAC;gBAED,OAAO,QAAQ,CAAC,uCAAuC,CAAC,CACtD,KAAK,CAAC,SAA4C,CACI,CAAC;YAC3D,CAAC;QACH,CAA+D,CAAC,CAAC;IACrE,CAAC;CACF,CAAC","sourcesContent":["import {\n CraftGenShortCircuit,\n craftException,\n isCraftGenShortCircuit,\n type CatchTagExhaustiveCodesCheck,\n type CraftExceptionResult,\n} from '@craft-ts/core';\nimport type { CraftInputExceptionsCarrier, Input } from './types';\n\nexport const CRAFT_UNDEFINED_PROPERTY_EXCEPTION_CODE =\n 'CraftUndefinedPropertyException' as const;\n\nexport type CraftUndefinedPropertyException = CraftExceptionResult<\n { readonly _tag: typeof CRAFT_UNDEFINED_PROPERTY_EXCEPTION_CODE },\n { readonly property?: string }\n>;\n\ntype InputPipeOperator<SourceValue, OutputValue> = (\n source: Input<SourceValue>,\n) => Input<OutputValue>;\n\nexport type PipeableInput<Value> = Input<Value> & {\n pipe<OutputValue>(\n operator: InputPipeOperator<Value, OutputValue>,\n ): PipeableInput<OutputValue>;\n};\n\ntype AssertDefinedInputHandler = (\n exception: CraftUndefinedPropertyException,\n) => unknown;\n\ntype AssertDefinedInputHandlers = Record<\n typeof CRAFT_UNDEFINED_PROPERTY_EXCEPTION_CODE,\n AssertDefinedInputHandler\n>;\n\ntype HandlerOutput<Handlers extends AssertDefinedInputHandlers> = ReturnType<\n Handlers[typeof CRAFT_UNDEFINED_PROPERTY_EXCEPTION_CODE]\n>;\n\nexport function craftUndefinedPropertyException(\n property?: string,\n): CraftUndefinedPropertyException {\n const payload: { readonly property?: string } =\n property === undefined ? {} : { property };\n\n return craftException(\n { _tag: CRAFT_UNDEFINED_PROPERTY_EXCEPTION_CODE },\n payload,\n );\n}\n\nexport type AssertDefinedInput<Value> = Input<Exclude<Value, undefined>> &\n CraftInputExceptionsCarrier<typeof CRAFT_UNDEFINED_PROPERTY_EXCEPTION_CODE> &\n Pick<PipeableInput<Exclude<Value, undefined>>, 'pipe'>;\n\nfunction pipeableInput<Value>(source: Input<Value>): PipeableInput<Value> {\n const input = source as PipeableInput<Value>;\n if (Object.prototype.hasOwnProperty.call(input, 'pipe')) {\n return input;\n }\n\n Object.defineProperty(input, 'pipe', {\n value: <OutputValue>(\n operator: InputPipeOperator<Value, OutputValue>,\n ): PipeableInput<OutputValue> => pipeableInput(operator(input)),\n enumerable: false,\n });\n return input;\n}\n\n/** Creates an input which narrows away undefined and short-circuits when absent. */\nexport function assertDefinedInput<Value>(\n source: Input<Value | undefined>,\n options: { readonly property?: string } = {},\n): AssertDefinedInput<Value> {\n return pipeableInput(function* () {\n const value = yield* source();\n if (value !== undefined) {\n return value as Exclude<Value, undefined>;\n }\n\n throw new CraftGenShortCircuit(\n craftUndefinedPropertyException(options.property),\n );\n } as Input<Exclude<Value, undefined>>) as AssertDefinedInput<Value>;\n}\n\nexport const catchInput = {\n exhaustive<const Handlers extends AssertDefinedInputHandlers>(\n handlers: Handlers &\n CatchTagExhaustiveCodesCheck<\n typeof CRAFT_UNDEFINED_PROPERTY_EXCEPTION_CODE,\n Handlers\n >,\n ) {\n return <Value>(\n source: Input<Value>,\n ): PipeableInput<\n Exclude<Value, undefined> | HandlerOutput<Handlers>\n > =>\n pipeableInput(function* () {\n try {\n return (yield* source()) as Exclude<Value, undefined>;\n } catch (error) {\n if (!isCraftGenShortCircuit(error)) {\n throw error;\n }\n\n if (\n error.exception._tag !==\n CRAFT_UNDEFINED_PROPERTY_EXCEPTION_CODE\n ) {\n throw error;\n }\n\n return handlers[CRAFT_UNDEFINED_PROPERTY_EXCEPTION_CODE](\n error.exception as CraftUndefinedPropertyException,\n ) as Exclude<Value, undefined> | HandlerOutput<Handlers>;\n }\n } as Input<Exclude<Value, undefined> | HandlerOutput<Handlers>>);\n },\n};\n"]}
@@ -0,0 +1,36 @@
1
+ import type { AnyCraftException } from '@craft-ts/core';
2
+ import { COMPONENT_CATCH_BLOCK, type ComponentOperator, type ComponentExceptionHandler, type ComponentExceptionHandlerDefinition, type ComponentExceptionHandlerEntry, type ComponentExceptionHandlerOptions, type CraftDirective } from './types';
3
+ import type { CraftNodeChildren } from './render/vnode';
4
+ export declare const CATCH_BLOCK_DIRECTIVE: unique symbol;
5
+ export type CatchBlockPosition = 'before' | 'after';
6
+ export declare class CraftUnhandledExceptionError extends Error {
7
+ readonly _tag: string;
8
+ constructor(exception: AnyCraftException);
9
+ }
10
+ export type CatchBlockHandler = ComponentExceptionHandler;
11
+ export type CatchBlockHandlerOptions = ComponentExceptionHandlerOptions;
12
+ export type CatchBlockHandlerDefinition = ComponentExceptionHandlerDefinition;
13
+ export type CatchBlockHandlerEntry = ComponentExceptionHandlerEntry;
14
+ export type CatchBlockHandlers = Record<string, CatchBlockHandlerEntry>;
15
+ export type CatchBlockHandlerChildren<Handler> = Handler extends ComponentExceptionHandlerEntry ? Handler extends (...args: any[]) => infer Children ? Children : Handler extends {
16
+ readonly render: (...args: any[]) => infer Children;
17
+ } ? Children : never : never;
18
+ export declare function resolveCatchBlockHandler(handler: CatchBlockHandlerEntry, exception: AnyCraftException, defaultShowSource: boolean, defaultPosition: CatchBlockPosition): {
19
+ readonly children: CraftNodeChildren;
20
+ readonly showSource: boolean;
21
+ readonly position: CatchBlockPosition;
22
+ };
23
+ export type CatchBlockDirective<Handlers extends CatchBlockHandlers> = CraftDirective & ComponentOperator<readonly [], Extract<keyof Handlers, string>> & {
24
+ readonly [COMPONENT_CATCH_BLOCK]: true;
25
+ readonly [CATCH_BLOCK_DIRECTIVE]: {
26
+ readonly handlers: Handlers;
27
+ readonly position: CatchBlockPosition;
28
+ };
29
+ };
30
+ /** A template boundary which keeps its source block and inserts a fallback. */
31
+ export declare const catchBlock: {
32
+ exhaustive<const Handlers extends CatchBlockHandlers>(handlers: Handlers, options?: {
33
+ readonly position?: CatchBlockPosition;
34
+ }): CatchBlockDirective<Handlers>;
35
+ };
36
+ //# sourceMappingURL=block.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"block.d.ts","sourceRoot":"","sources":["../../../../../libs/component/src/lib/block.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAEL,qBAAqB,EACrB,KAAK,iBAAiB,EACtB,KAAK,yBAAyB,EAC9B,KAAK,mCAAmC,EACxC,KAAK,8BAA8B,EACnC,KAAK,gCAAgC,EACrC,KAAK,cAAc,EACpB,MAAM,SAAS,CAAC;AACjB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAExD,eAAO,MAAM,qBAAqB,eAAwC,CAAC;AAE3E,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEpD,qBAAa,4BAA6B,SAAQ,KAAK;IACrD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,SAAS,EAAE,iBAAiB;CAOzC;AAED,MAAM,MAAM,iBAAiB,GAAG,yBAAyB,CAAC;AAC1D,MAAM,MAAM,wBAAwB,GAAG,gCAAgC,CAAC;AACxE,MAAM,MAAM,2BAA2B,GAAG,mCAAmC,CAAC;AAC9E,MAAM,MAAM,sBAAsB,GAAG,8BAA8B,CAAC;AACpE,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC;AACxE,MAAM,MAAM,yBAAyB,CAAC,OAAO,IAC3C,OAAO,SAAS,8BAA8B,GAC1C,OAAO,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,MAAM,QAAQ,GAChD,QAAQ,GACR,OAAO,SAAS;IAAE,QAAQ,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,MAAM,QAAQ,CAAA;CAAE,GACrE,QAAQ,GACR,KAAK,GACT,KAAK,CAAC;AAEZ,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,sBAAsB,EAC/B,SAAS,EAAE,iBAAiB,EAC5B,iBAAiB,EAAE,OAAO,EAC1B,eAAe,EAAE,kBAAkB,GAClC;IACD,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;IACrC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,CAAC;CACvC,CAcA;AAED,MAAM,MAAM,mBAAmB,CAAC,QAAQ,SAAS,kBAAkB,IACjE,cAAc,GACZ,iBAAiB,CAAC,SAAS,EAAE,EAAE,OAAO,CAAC,MAAM,QAAQ,EAAE,MAAM,CAAC,CAAC,GAAG;IAChE,QAAQ,CAAC,CAAC,qBAAqB,CAAC,EAAE,IAAI,CAAC;IACvC,QAAQ,CAAC,CAAC,qBAAqB,CAAC,EAAE;QAChC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;QAC5B,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,CAAC;KACvC,CAAC;CACH,CAAC;AAEN,+EAA+E;AAC/E,eAAO,MAAM,UAAU;qBACJ,QAAQ,SAAS,kBAAkB,YACxC,QAAQ,YACT;QAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,kBAAkB,CAAA;KAAE,GAClD,mBAAmB,CAAC,QAAQ,CAAC;CA4BjC,CAAC"}