@assistant-ui/react-generative-ui 0.0.14 → 0.0.16

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 (61) hide show
  1. package/README.md +48 -0
  2. package/dist/convert/boundSpec.d.ts +47 -0
  3. package/dist/convert/boundSpec.d.ts.map +1 -0
  4. package/dist/convert/boundSpec.js +99 -0
  5. package/dist/convert/boundSpec.js.map +1 -0
  6. package/dist/convert/copyBounded.d.ts +28 -0
  7. package/dist/convert/copyBounded.d.ts.map +1 -0
  8. package/dist/convert/copyBounded.js +38 -0
  9. package/dist/convert/copyBounded.js.map +1 -0
  10. package/dist/convert/isElement.d.ts +6 -0
  11. package/dist/convert/isElement.d.ts.map +1 -0
  12. package/dist/convert/isElement.js +6 -0
  13. package/dist/convert/isElement.js.map +1 -0
  14. package/dist/convert/takeRun.d.ts +9 -0
  15. package/dist/convert/takeRun.d.ts.map +1 -0
  16. package/dist/convert/takeRun.js +20 -0
  17. package/dist/convert/takeRun.js.map +1 -0
  18. package/dist/slack/constants.d.ts +1 -26
  19. package/dist/slack/constants.d.ts.map +1 -1
  20. package/dist/slack/constants.js +1 -26
  21. package/dist/slack/constants.js.map +1 -1
  22. package/dist/slack/fromSlackBlocks.js +6 -10
  23. package/dist/slack/fromSlackBlocks.js.map +1 -1
  24. package/dist/slack/toSlackBlocks.d.ts.map +1 -1
  25. package/dist/slack/toSlackBlocks.js +28 -95
  26. package/dist/slack/toSlackBlocks.js.map +1 -1
  27. package/dist/teams/constants.d.ts +1 -28
  28. package/dist/teams/constants.d.ts.map +1 -1
  29. package/dist/teams/constants.js +1 -32
  30. package/dist/teams/constants.js.map +1 -1
  31. package/dist/teams/toAdaptiveCard.d.ts.map +1 -1
  32. package/dist/teams/toAdaptiveCard.js +13 -24
  33. package/dist/teams/toAdaptiveCard.js.map +1 -1
  34. package/dist/teams/toTeamsAttachments.d.ts.map +1 -1
  35. package/dist/teams/toTeamsAttachments.js +3 -4
  36. package/dist/teams/toTeamsAttachments.js.map +1 -1
  37. package/dist/vocabulary/list.js +4 -2
  38. package/dist/vocabulary/list.js.map +1 -1
  39. package/package.json +6 -6
  40. package/src/convert/boundSpec.test.ts +147 -0
  41. package/src/{teams → convert}/boundSpec.ts +48 -14
  42. package/src/convert/copyBounded.test.ts +131 -0
  43. package/src/convert/copyBounded.ts +38 -0
  44. package/src/convert/isElement.ts +6 -0
  45. package/src/convert/takeRun.test.ts +64 -0
  46. package/src/convert/takeRun.ts +19 -0
  47. package/src/slack/constants.ts +0 -29
  48. package/src/slack/fromSlackBlocks.test.ts +105 -7
  49. package/src/slack/fromSlackBlocks.ts +9 -9
  50. package/src/slack/toSlackBlocks.test.ts +82 -2
  51. package/src/slack/toSlackBlocks.ts +68 -164
  52. package/src/teams/constants.ts +0 -42
  53. package/src/teams/toAdaptiveCard.test.ts +75 -3
  54. package/src/teams/toAdaptiveCard.ts +30 -37
  55. package/src/teams/toTeamsAttachments.ts +2 -8
  56. package/src/vocabulary/list.test.tsx +35 -9
  57. package/src/vocabulary/list.tsx +4 -2
  58. package/dist/teams/boundSpec.d.ts +0 -20
  59. package/dist/teams/boundSpec.d.ts.map +0 -1
  60. package/dist/teams/boundSpec.js +0 -67
  61. package/dist/teams/boundSpec.js.map +0 -1
@@ -69,13 +69,17 @@ describe("listVocabulary $action dispatch", () => {
69
69
  const trigger = rowOut(registry.dispatch).props.children as ReactElement;
70
70
  const onClick = (trigger.props as { onClick: (e: unknown) => void })
71
71
  .onClick;
72
- onClick({ target: { closest: () => null } });
72
+ onClick({
73
+ target: { closest: () => trigger },
74
+ currentTarget: trigger,
75
+ });
73
76
  expect(handler).toHaveBeenCalledWith({ payload: { type: "open" } });
74
77
  });
75
78
 
76
79
  type KeyDownEvent = {
77
80
  key: string;
78
81
  target: { closest: (selector: string) => unknown };
82
+ currentTarget: unknown;
79
83
  preventDefault: () => void;
80
84
  };
81
85
 
@@ -89,14 +93,17 @@ describe("listVocabulary $action dispatch", () => {
89
93
  const handler = vi.fn();
90
94
  const registry = createActionRegistry({ open: handler });
91
95
  const onKeyDown = getOnKeyDown(registry.dispatch);
96
+ const currentTarget = {};
92
97
  onKeyDown({
93
98
  key: "Enter",
94
- target: { closest: () => null },
99
+ target: { closest: () => currentTarget },
100
+ currentTarget,
95
101
  preventDefault: vi.fn(),
96
102
  });
97
103
  onKeyDown({
98
104
  key: " ",
99
- target: { closest: () => null },
105
+ target: { closest: () => currentTarget },
106
+ currentTarget,
100
107
  preventDefault: vi.fn(),
101
108
  });
102
109
  expect(handler).toHaveBeenCalledTimes(2);
@@ -109,6 +116,7 @@ describe("listVocabulary $action dispatch", () => {
109
116
  onKeyDown({
110
117
  key: "Tab",
111
118
  target: { closest: () => null },
119
+ currentTarget: {},
112
120
  preventDefault: vi.fn(),
113
121
  });
114
122
  expect(handler).not.toHaveBeenCalled();
@@ -124,7 +132,7 @@ describe("listVocabulary $action dispatch", () => {
124
132
  closest: (selector: string) =>
125
133
  selector.includes("button") ? nestedButton : null,
126
134
  };
127
- onClick({ target: nestedButton });
135
+ onClick({ target: nestedButton, currentTarget: {} });
128
136
  expect(handler).not.toHaveBeenCalled();
129
137
  });
130
138
 
@@ -137,7 +145,12 @@ describe("listVocabulary $action dispatch", () => {
137
145
  selector.includes("input") ? nestedInput : null,
138
146
  };
139
147
  const preventDefault = vi.fn();
140
- onKeyDown({ key: "Enter", target: nestedInput, preventDefault });
148
+ onKeyDown({
149
+ key: "Enter",
150
+ target: nestedInput,
151
+ currentTarget: {},
152
+ preventDefault,
153
+ });
141
154
  expect(handler).not.toHaveBeenCalled();
142
155
  expect(preventDefault).not.toHaveBeenCalled();
143
156
  });
@@ -152,7 +165,7 @@ describe("listVocabulary $action dispatch", () => {
152
165
  closest: (selector: string) =>
153
166
  selector.includes('[role="button"]') ? nestedRoleButton : null,
154
167
  };
155
- onClick({ target: nestedRoleButton });
168
+ onClick({ target: nestedRoleButton, currentTarget: {} });
156
169
  expect(handler).not.toHaveBeenCalled();
157
170
  });
158
171
 
@@ -165,7 +178,12 @@ describe("listVocabulary $action dispatch", () => {
165
178
  selector.includes('[role="button"]') ? nestedRoleButton : null,
166
179
  };
167
180
  const preventDefault = vi.fn();
168
- onKeyDown({ key: "Enter", target: nestedRoleButton, preventDefault });
181
+ onKeyDown({
182
+ key: "Enter",
183
+ target: nestedRoleButton,
184
+ currentTarget: {},
185
+ preventDefault,
186
+ });
169
187
  expect(handler).not.toHaveBeenCalled();
170
188
  });
171
189
 
@@ -173,8 +191,14 @@ describe("listVocabulary $action dispatch", () => {
173
191
  const handler = vi.fn();
174
192
  const registry = createActionRegistry({ open: handler });
175
193
  const onKeyDown = getOnKeyDown(registry.dispatch);
194
+ const currentTarget = {};
176
195
  const preventDefault = vi.fn();
177
- onKeyDown({ key: " ", target: { closest: () => null }, preventDefault });
196
+ onKeyDown({
197
+ key: " ",
198
+ target: { closest: () => currentTarget },
199
+ currentTarget,
200
+ preventDefault,
201
+ });
178
202
  expect(handler).toHaveBeenCalledWith({ payload: { type: "open" } });
179
203
  expect(preventDefault).toHaveBeenCalledTimes(1);
180
204
  });
@@ -183,10 +207,12 @@ describe("listVocabulary $action dispatch", () => {
183
207
  const handler = vi.fn();
184
208
  const registry = createActionRegistry({ open: handler });
185
209
  const onKeyDown = getOnKeyDown(registry.dispatch);
210
+ const currentTarget = {};
186
211
  const preventDefault = vi.fn();
187
212
  onKeyDown({
188
213
  key: "Enter",
189
- target: { closest: () => null },
214
+ target: { closest: () => currentTarget },
215
+ currentTarget,
190
216
  preventDefault,
191
217
  });
192
218
  expect(handler).toHaveBeenCalledWith({ payload: { type: "open" } });
@@ -28,13 +28,15 @@ export const listVocabulary = {
28
28
  data-aui="listview-item-trigger"
29
29
  onClick={(event) => {
30
30
  const target = event.target as Element;
31
- if (target.closest(INTERACTIVE_DESCENDANT_SELECTOR)) return;
31
+ const hit = target.closest(INTERACTIVE_DESCENDANT_SELECTOR);
32
+ if (hit !== null && hit !== event.currentTarget) return;
32
33
  fire($action, $dispatch);
33
34
  }}
34
35
  onKeyDown={(event) => {
35
36
  if (event.key !== "Enter" && event.key !== " ") return;
36
37
  const target = event.target as Element;
37
- if (target.closest(INTERACTIVE_DESCENDANT_SELECTOR)) return;
38
+ const hit = target.closest(INTERACTIVE_DESCENDANT_SELECTOR);
39
+ if (hit !== null && hit !== event.currentTarget) return;
38
40
  if (event.key === " ") event.preventDefault();
39
41
  fire($action, $dispatch);
40
42
  }}
@@ -1,20 +0,0 @@
1
- import { ClampReason } from "./constants.js";
2
- //#region src/teams/boundSpec.d.ts
3
- /**
4
- * Produces a bounded plain copy of a raw generative-ui spec before it
5
- * reaches `normalizeSpec`, whose own traversal of the root array or any
6
- * `children` array walks the full reported length of a hostile proxied
7
- * array before any per-field cap downstream ever applies. Every array
8
- * (root, or `children` at any depth) is capped to {@link CHILDREN_CAP}
9
- * entries via `Array.prototype.slice`, which bounds even a proxy with a
10
- * fabricated `length`; recursion itself is capped at
11
- * {@link MAX_TRAVERSAL_DEPTH}. `onClamp` fires once per level that was
12
- * truncated, receiving the reason for that truncation: `"children"`,
13
- * `"depth"`, `"budget"`, or `"cycle"`. The walk also spends a total budget of
14
- * {@link NODE_BUDGET} nodes, so shared references cannot multiply work
15
- * exponentially, and a node that is its own ancestor is cut to `null`.
16
- */
17
- declare function boundSpec(spec: unknown, onClamp: (reason: ClampReason) => void): unknown;
18
- //#endregion
19
- export { boundSpec };
20
- //# sourceMappingURL=boundSpec.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"boundSpec.d.ts","names":[],"sources":["../../src/teams/boundSpec.ts"],"mappings":";;;;;;;;;;;;;;;;iBA0FgB,UACd,eACA,UAAU,QAAQ"}
@@ -1,67 +0,0 @@
1
- import { NODE_BUDGET } from "./constants.js";
2
- //#region src/teams/boundSpec.ts
3
- function boundNode(value, depth, onClamp, state, ancestors) {
4
- if (state.remaining <= 0) {
5
- if (!state.exhausted) {
6
- state.exhausted = true;
7
- onClamp("budget");
8
- }
9
- return null;
10
- }
11
- state.remaining -= 1;
12
- if (depth > 64) {
13
- onClamp("depth");
14
- return null;
15
- }
16
- if (Array.isArray(value)) {
17
- if (ancestors.has(value)) {
18
- onClamp("cycle");
19
- return null;
20
- }
21
- ancestors.add(value);
22
- const bounded = Array.prototype.slice.call(value, 0, 200);
23
- if (value.length > 200) onClamp("children");
24
- const result = bounded.map((item) => boundNode(item, depth + 1, onClamp, state, ancestors));
25
- ancestors.delete(value);
26
- return result;
27
- }
28
- if (value !== null && typeof value === "object" && "children" in value) {
29
- if (ancestors.has(value)) {
30
- onClamp("cycle");
31
- return null;
32
- }
33
- ancestors.add(value);
34
- const record = value;
35
- const result = {
36
- ...record,
37
- children: boundNode(record["children"], depth + 1, onClamp, state, ancestors)
38
- };
39
- ancestors.delete(value);
40
- return result;
41
- }
42
- return value;
43
- }
44
- /**
45
- * Produces a bounded plain copy of a raw generative-ui spec before it
46
- * reaches `normalizeSpec`, whose own traversal of the root array or any
47
- * `children` array walks the full reported length of a hostile proxied
48
- * array before any per-field cap downstream ever applies. Every array
49
- * (root, or `children` at any depth) is capped to {@link CHILDREN_CAP}
50
- * entries via `Array.prototype.slice`, which bounds even a proxy with a
51
- * fabricated `length`; recursion itself is capped at
52
- * {@link MAX_TRAVERSAL_DEPTH}. `onClamp` fires once per level that was
53
- * truncated, receiving the reason for that truncation: `"children"`,
54
- * `"depth"`, `"budget"`, or `"cycle"`. The walk also spends a total budget of
55
- * {@link NODE_BUDGET} nodes, so shared references cannot multiply work
56
- * exponentially, and a node that is its own ancestor is cut to `null`.
57
- */
58
- function boundSpec(spec, onClamp) {
59
- return boundNode(spec, 0, onClamp, {
60
- remaining: NODE_BUDGET,
61
- exhausted: false
62
- }, /* @__PURE__ */ new WeakSet());
63
- }
64
- //#endregion
65
- export { boundSpec };
66
-
67
- //# sourceMappingURL=boundSpec.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"boundSpec.js","names":[],"sources":["../../src/teams/boundSpec.ts"],"sourcesContent":["import {\n CHILDREN_CAP,\n MAX_TRAVERSAL_DEPTH,\n NODE_BUDGET,\n type ClampReason,\n} from \"./constants\";\n\ninterface BoundState {\n remaining: number;\n exhausted: boolean;\n}\n\nfunction boundNode(\n value: unknown,\n depth: number,\n onClamp: (reason: ClampReason) => void,\n state: BoundState,\n ancestors: WeakSet<object>,\n): unknown {\n if (state.remaining <= 0) {\n if (!state.exhausted) {\n state.exhausted = true;\n onClamp(\"budget\");\n }\n return null;\n }\n state.remaining -= 1;\n if (depth > MAX_TRAVERSAL_DEPTH) {\n onClamp(\"depth\");\n return null;\n }\n if (Array.isArray(value)) {\n if (ancestors.has(value)) {\n onClamp(\"cycle\");\n return null;\n }\n ancestors.add(value);\n const bounded = Array.prototype.slice.call(\n value,\n 0,\n CHILDREN_CAP,\n ) as unknown[];\n if (value.length > CHILDREN_CAP) onClamp(\"children\");\n const result = bounded.map((item) =>\n boundNode(item, depth + 1, onClamp, state, ancestors),\n );\n ancestors.delete(value);\n return result;\n }\n if (\n value !== null &&\n typeof value === \"object\" &&\n \"children\" in (value as Record<string, unknown>)\n ) {\n if (ancestors.has(value)) {\n onClamp(\"cycle\");\n return null;\n }\n ancestors.add(value);\n const record = value as Record<string, unknown>;\n const result = {\n ...record,\n children: boundNode(\n record[\"children\"],\n depth + 1,\n onClamp,\n state,\n ancestors,\n ),\n };\n ancestors.delete(value);\n return result;\n }\n return value;\n}\n\n/**\n * Produces a bounded plain copy of a raw generative-ui spec before it\n * reaches `normalizeSpec`, whose own traversal of the root array or any\n * `children` array walks the full reported length of a hostile proxied\n * array before any per-field cap downstream ever applies. Every array\n * (root, or `children` at any depth) is capped to {@link CHILDREN_CAP}\n * entries via `Array.prototype.slice`, which bounds even a proxy with a\n * fabricated `length`; recursion itself is capped at\n * {@link MAX_TRAVERSAL_DEPTH}. `onClamp` fires once per level that was\n * truncated, receiving the reason for that truncation: `\"children\"`,\n * `\"depth\"`, `\"budget\"`, or `\"cycle\"`. The walk also spends a total budget of\n * {@link NODE_BUDGET} nodes, so shared references cannot multiply work\n * exponentially, and a node that is its own ancestor is cut to `null`.\n */\nexport function boundSpec(\n spec: unknown,\n onClamp: (reason: ClampReason) => void,\n): unknown {\n return boundNode(\n spec,\n 0,\n onClamp,\n { remaining: NODE_BUDGET, exhausted: false },\n new WeakSet(),\n );\n}\n"],"mappings":";;AAYA,SAAS,UACP,OACA,OACA,SACA,OACA,WACS;CACT,IAAI,MAAM,aAAa,GAAG;EACxB,IAAI,CAAC,MAAM,WAAW;GACpB,MAAM,YAAY;GAClB,QAAQ,QAAQ;EAClB;EACA,OAAO;CACT;CACA,MAAM,aAAa;CACnB,IAAI,QAAA,IAA6B;EAC/B,QAAQ,OAAO;EACf,OAAO;CACT;CACA,IAAI,MAAM,QAAQ,KAAK,GAAG;EACxB,IAAI,UAAU,IAAI,KAAK,GAAG;GACxB,QAAQ,OAAO;GACf,OAAO;EACT;EACA,UAAU,IAAI,KAAK;EACnB,MAAM,UAAU,MAAM,UAAU,MAAM,KACpC,OACA,GAAA,GAEF;EACA,IAAI,MAAM,SAAA,KAAuB,QAAQ,UAAU;EACnD,MAAM,SAAS,QAAQ,KAAK,SAC1B,UAAU,MAAM,QAAQ,GAAG,SAAS,OAAO,SAAS,CACtD;EACA,UAAU,OAAO,KAAK;EACtB,OAAO;CACT;CACA,IACE,UAAU,QACV,OAAO,UAAU,YACjB,cAAe,OACf;EACA,IAAI,UAAU,IAAI,KAAK,GAAG;GACxB,QAAQ,OAAO;GACf,OAAO;EACT;EACA,UAAU,IAAI,KAAK;EACnB,MAAM,SAAS;EACf,MAAM,SAAS;GACb,GAAG;GACH,UAAU,UACR,OAAO,aACP,QAAQ,GACR,SACA,OACA,SACF;EACF;EACA,UAAU,OAAO,KAAK;EACtB,OAAO;CACT;CACA,OAAO;AACT;;;;;;;;;;;;;;;AAgBA,SAAgB,UACd,MACA,SACS;CACT,OAAO,UACL,MACA,GACA,SACA;EAAE,WAAW;EAAa,WAAW;CAAM,mBAC3C,IAAI,QAAQ,CACd;AACF"}