@fragments-sdk/a2ui 1.0.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/catalog/index.js +47 -0
- package/dist/chunk-FWMN7L3T.js +919 -0
- package/dist/chunk-QCZG5JX2.js +0 -0
- package/dist/chunk-TWIIXJBN.js +49 -0
- package/dist/index.js +63 -0
- package/dist/react/index.js +19 -0
- package/package.json +5 -6
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import "../chunk-QCZG5JX2.js";
|
|
2
|
+
import {
|
|
3
|
+
A2UIAudioPlayer,
|
|
4
|
+
A2UIButton,
|
|
5
|
+
A2UICard,
|
|
6
|
+
A2UICheckBox,
|
|
7
|
+
A2UIChoicePicker,
|
|
8
|
+
A2UIColumn,
|
|
9
|
+
A2UIDateTimeInput,
|
|
10
|
+
A2UIDivider,
|
|
11
|
+
A2UIIcon,
|
|
12
|
+
A2UIImage,
|
|
13
|
+
A2UIList,
|
|
14
|
+
A2UIModal,
|
|
15
|
+
A2UIRow,
|
|
16
|
+
A2UISlider,
|
|
17
|
+
A2UITabs,
|
|
18
|
+
A2UIText,
|
|
19
|
+
A2UITextField,
|
|
20
|
+
A2UIVideo,
|
|
21
|
+
fragmentsCatalog,
|
|
22
|
+
knownA2UIIcons,
|
|
23
|
+
resolveA2UIcon
|
|
24
|
+
} from "../chunk-FWMN7L3T.js";
|
|
25
|
+
export {
|
|
26
|
+
A2UIAudioPlayer,
|
|
27
|
+
A2UIButton,
|
|
28
|
+
A2UICard,
|
|
29
|
+
A2UICheckBox,
|
|
30
|
+
A2UIChoicePicker,
|
|
31
|
+
A2UIColumn,
|
|
32
|
+
A2UIDateTimeInput,
|
|
33
|
+
A2UIDivider,
|
|
34
|
+
A2UIIcon,
|
|
35
|
+
A2UIImage,
|
|
36
|
+
A2UIList,
|
|
37
|
+
A2UIModal,
|
|
38
|
+
A2UIRow,
|
|
39
|
+
A2UISlider,
|
|
40
|
+
A2UITabs,
|
|
41
|
+
A2UIText,
|
|
42
|
+
A2UITextField,
|
|
43
|
+
A2UIVideo,
|
|
44
|
+
fragmentsCatalog,
|
|
45
|
+
knownA2UIIcons,
|
|
46
|
+
resolveA2UIcon
|
|
47
|
+
};
|
|
@@ -0,0 +1,919 @@
|
|
|
1
|
+
// src/catalog/adapters/_shared.ts
|
|
2
|
+
import { resolvePointerPath } from "@uiprotocol/a2ui/core";
|
|
3
|
+
function isRecord(value) {
|
|
4
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
5
|
+
}
|
|
6
|
+
function isBoundValue(value) {
|
|
7
|
+
return isRecord(value) && typeof value.path === "string";
|
|
8
|
+
}
|
|
9
|
+
function getProp(component, keys) {
|
|
10
|
+
for (const key of keys) {
|
|
11
|
+
if (key in component) {
|
|
12
|
+
return component[key];
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return void 0;
|
|
16
|
+
}
|
|
17
|
+
function resolveProp(props, keys, fallback) {
|
|
18
|
+
const raw = getProp(props.component, keys);
|
|
19
|
+
if (raw === void 0) {
|
|
20
|
+
return fallback;
|
|
21
|
+
}
|
|
22
|
+
return props.resolve(raw);
|
|
23
|
+
}
|
|
24
|
+
function resolveString(props, keys, fallback = "") {
|
|
25
|
+
const value = resolveProp(props, keys);
|
|
26
|
+
if (value === void 0 || value === null) {
|
|
27
|
+
return fallback;
|
|
28
|
+
}
|
|
29
|
+
if (typeof value === "object") {
|
|
30
|
+
return fallback;
|
|
31
|
+
}
|
|
32
|
+
return String(value);
|
|
33
|
+
}
|
|
34
|
+
function resolveNumber(props, keys, fallback = 0) {
|
|
35
|
+
const value = resolveProp(props, keys);
|
|
36
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
if (typeof value === "string") {
|
|
40
|
+
const parsed = Number(value);
|
|
41
|
+
if (!Number.isNaN(parsed) && Number.isFinite(parsed)) {
|
|
42
|
+
return parsed;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return fallback;
|
|
46
|
+
}
|
|
47
|
+
function resolveBoolean(props, keys, fallback = false) {
|
|
48
|
+
const value = resolveProp(props, keys);
|
|
49
|
+
if (typeof value === "boolean") {
|
|
50
|
+
return value;
|
|
51
|
+
}
|
|
52
|
+
return fallback;
|
|
53
|
+
}
|
|
54
|
+
function resolveArray(props, keys) {
|
|
55
|
+
const value = resolveProp(props, keys);
|
|
56
|
+
return Array.isArray(value) ? value : [];
|
|
57
|
+
}
|
|
58
|
+
function resolveBindingPath(props, keys = ["value", "path", "valuePath", "bindingPath", "bindPath"]) {
|
|
59
|
+
const isPathString = (value, key) => key.toLowerCase().includes("path") || value.startsWith("/") || value.startsWith("./") || value.startsWith("../");
|
|
60
|
+
for (const key of keys) {
|
|
61
|
+
const raw = props.component[key];
|
|
62
|
+
if (typeof raw === "string") {
|
|
63
|
+
if (isPathString(raw, key)) {
|
|
64
|
+
return resolvePointerPath(raw, props.scopePath);
|
|
65
|
+
}
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
if (isBoundValue(raw)) {
|
|
69
|
+
return resolvePointerPath(raw.path, props.scopePath);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return void 0;
|
|
73
|
+
}
|
|
74
|
+
function resolveAction(component, keys) {
|
|
75
|
+
for (const key of keys) {
|
|
76
|
+
const raw = component[key];
|
|
77
|
+
if (!raw) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (typeof raw === "string") {
|
|
81
|
+
return { event: raw };
|
|
82
|
+
}
|
|
83
|
+
if (isRecord(raw) && typeof raw.event === "string") {
|
|
84
|
+
return raw;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const actions = component.actions;
|
|
88
|
+
if (isRecord(actions)) {
|
|
89
|
+
for (const key of keys) {
|
|
90
|
+
const candidate = actions[key];
|
|
91
|
+
if (isRecord(candidate) && typeof candidate.event === "string") {
|
|
92
|
+
return candidate;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return void 0;
|
|
97
|
+
}
|
|
98
|
+
function dispatchAction(props, action, options) {
|
|
99
|
+
if (!action) {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
return props.dispatchAction(action, {
|
|
103
|
+
componentId: props.component.id,
|
|
104
|
+
value: options?.value,
|
|
105
|
+
checks: options?.checks,
|
|
106
|
+
pattern: options?.pattern
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
function getChecks(component) {
|
|
110
|
+
return Array.isArray(component.checks) ? component.checks : void 0;
|
|
111
|
+
}
|
|
112
|
+
function getPattern(component) {
|
|
113
|
+
return typeof component.pattern === "string" ? component.pattern : void 0;
|
|
114
|
+
}
|
|
115
|
+
function getPrimaryText(props, fallback = "") {
|
|
116
|
+
const text = resolveString(props, ["text", "label", "title", "content", "value"], fallback);
|
|
117
|
+
return text;
|
|
118
|
+
}
|
|
119
|
+
function mapAlign(value) {
|
|
120
|
+
switch (value.toLowerCase()) {
|
|
121
|
+
case "start":
|
|
122
|
+
case "left":
|
|
123
|
+
case "top":
|
|
124
|
+
return "start";
|
|
125
|
+
case "center":
|
|
126
|
+
return "center";
|
|
127
|
+
case "end":
|
|
128
|
+
case "right":
|
|
129
|
+
case "bottom":
|
|
130
|
+
return "end";
|
|
131
|
+
case "stretch":
|
|
132
|
+
return "stretch";
|
|
133
|
+
case "baseline":
|
|
134
|
+
return "baseline";
|
|
135
|
+
default:
|
|
136
|
+
return void 0;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function mapJustify(value) {
|
|
140
|
+
switch (value.toLowerCase()) {
|
|
141
|
+
case "start":
|
|
142
|
+
case "left":
|
|
143
|
+
case "top":
|
|
144
|
+
return "start";
|
|
145
|
+
case "center":
|
|
146
|
+
return "center";
|
|
147
|
+
case "end":
|
|
148
|
+
case "right":
|
|
149
|
+
case "bottom":
|
|
150
|
+
return "end";
|
|
151
|
+
case "between":
|
|
152
|
+
case "spacebetween":
|
|
153
|
+
return "between";
|
|
154
|
+
default:
|
|
155
|
+
return void 0;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
function toStringArray(value) {
|
|
159
|
+
if (!Array.isArray(value)) {
|
|
160
|
+
return [];
|
|
161
|
+
}
|
|
162
|
+
return value.map((entry) => entry === void 0 || entry === null ? "" : String(entry)).filter((entry) => entry.length > 0);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// src/catalog/adapters/audio-player.tsx
|
|
166
|
+
import { jsx } from "react/jsx-runtime";
|
|
167
|
+
function A2UIAudioPlayer(props) {
|
|
168
|
+
const src = resolveString(props, ["src", "url"]);
|
|
169
|
+
const controls = resolveBoolean(props, ["controls"], true);
|
|
170
|
+
const autoplay = resolveBoolean(props, ["autoplay"], false);
|
|
171
|
+
const loop = resolveBoolean(props, ["loop"], false);
|
|
172
|
+
return /* @__PURE__ */ jsx("audio", { src, controls, autoPlay: autoplay, loop, style: { width: "100%" } });
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// src/catalog/adapters/button.tsx
|
|
176
|
+
import { Button } from "@fragments-sdk/ui";
|
|
177
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
178
|
+
function mapButtonVariant(style) {
|
|
179
|
+
switch (style.toLowerCase()) {
|
|
180
|
+
case "borderless":
|
|
181
|
+
case "ghost":
|
|
182
|
+
return "ghost";
|
|
183
|
+
case "outlined":
|
|
184
|
+
case "outline":
|
|
185
|
+
return "outlined";
|
|
186
|
+
case "danger":
|
|
187
|
+
case "destructive":
|
|
188
|
+
return "danger";
|
|
189
|
+
case "icon":
|
|
190
|
+
return "icon";
|
|
191
|
+
case "secondary":
|
|
192
|
+
return "secondary";
|
|
193
|
+
default:
|
|
194
|
+
return "primary";
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
function A2UIButton(props) {
|
|
198
|
+
const variant = mapButtonVariant(resolveString(props, ["style", "variant"], "primary"));
|
|
199
|
+
const label = getPrimaryText(props, "Button");
|
|
200
|
+
const disabled = resolveBoolean(props, ["disabled", "enabled"], false);
|
|
201
|
+
const action = resolveAction(props.component, ["action", "onClickAction", "onPressAction", "submitAction"]);
|
|
202
|
+
const checks = getChecks(props.component);
|
|
203
|
+
const pattern = getPattern(props.component);
|
|
204
|
+
const children = props.childIds.length > 0 ? props.childIds.map((childId) => props.renderChild(childId, `${props.component.id}:${childId}`)) : null;
|
|
205
|
+
return /* @__PURE__ */ jsx2(
|
|
206
|
+
Button,
|
|
207
|
+
{
|
|
208
|
+
variant,
|
|
209
|
+
disabled,
|
|
210
|
+
onClick: () => {
|
|
211
|
+
dispatchAction(props, action, {
|
|
212
|
+
checks,
|
|
213
|
+
pattern,
|
|
214
|
+
value: props.resolve(props.component.value)
|
|
215
|
+
});
|
|
216
|
+
},
|
|
217
|
+
children: children ?? label
|
|
218
|
+
}
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// src/catalog/adapters/card.tsx
|
|
223
|
+
import { Card } from "@fragments-sdk/ui";
|
|
224
|
+
import { jsx as jsx3, jsxs } from "react/jsx-runtime";
|
|
225
|
+
function A2UICard(props) {
|
|
226
|
+
const title = resolveString(props, ["title"], "");
|
|
227
|
+
const description = resolveString(props, ["description", "subtitle"], "");
|
|
228
|
+
return /* @__PURE__ */ jsxs(Card, { children: [
|
|
229
|
+
(title || description) && /* @__PURE__ */ jsxs(Card.Header, { children: [
|
|
230
|
+
title && /* @__PURE__ */ jsx3(Card.Title, { children: title }),
|
|
231
|
+
description && /* @__PURE__ */ jsx3(Card.Description, { children: description })
|
|
232
|
+
] }),
|
|
233
|
+
/* @__PURE__ */ jsx3(Card.Body, { children: props.renderedChildren })
|
|
234
|
+
] });
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// src/catalog/adapters/checkbox.tsx
|
|
238
|
+
import { Checkbox } from "@fragments-sdk/ui";
|
|
239
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
240
|
+
function A2UICheckBox(props) {
|
|
241
|
+
const path = resolveBindingPath(props, ["value", "path", "valuePath", "bindingPath"]);
|
|
242
|
+
const resolved = path ? props.resolve({ path }) : props.resolve(props.component.value);
|
|
243
|
+
const checked = Boolean(resolved);
|
|
244
|
+
const label = resolveString(props, ["label", "text"], "");
|
|
245
|
+
const description = resolveString(props, ["description"], "");
|
|
246
|
+
const disabled = resolveBoolean(props, ["disabled", "enabled"], false);
|
|
247
|
+
const action = resolveAction(props.component, ["onChangeAction", "action"]);
|
|
248
|
+
const checks = getChecks(props.component);
|
|
249
|
+
const pattern = getPattern(props.component);
|
|
250
|
+
return /* @__PURE__ */ jsx4(
|
|
251
|
+
Checkbox,
|
|
252
|
+
{
|
|
253
|
+
checked,
|
|
254
|
+
label: label || void 0,
|
|
255
|
+
description: description || void 0,
|
|
256
|
+
disabled,
|
|
257
|
+
onCheckedChange: (nextValue) => {
|
|
258
|
+
if (path) {
|
|
259
|
+
props.setData(path, nextValue);
|
|
260
|
+
}
|
|
261
|
+
dispatchAction(props, action, {
|
|
262
|
+
checks,
|
|
263
|
+
pattern,
|
|
264
|
+
value: nextValue
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// src/catalog/adapters/choice-picker.tsx
|
|
272
|
+
import { Checkbox as Checkbox2, Chip, RadioGroup, Select, Stack } from "@fragments-sdk/ui";
|
|
273
|
+
import { jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
274
|
+
function resolveOptions(props) {
|
|
275
|
+
const options = resolveArray(props, ["options", "items", "choices"]);
|
|
276
|
+
const resolved = [];
|
|
277
|
+
options.forEach((option, index) => {
|
|
278
|
+
if (!isRecord(option)) {
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
const valueRaw = option.value ?? option.id ?? index;
|
|
282
|
+
const labelRaw = option.label ?? option.title ?? option.text ?? valueRaw;
|
|
283
|
+
resolved.push({
|
|
284
|
+
value: String(props.resolve(valueRaw) ?? valueRaw),
|
|
285
|
+
label: String(props.resolve(labelRaw) ?? labelRaw),
|
|
286
|
+
description: option.description ? String(props.resolve(option.description) ?? option.description) : void 0
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
return resolved;
|
|
290
|
+
}
|
|
291
|
+
function nextMultiValues(currentValues, value, checked) {
|
|
292
|
+
if (checked) {
|
|
293
|
+
return currentValues.includes(value) ? currentValues : [...currentValues, value];
|
|
294
|
+
}
|
|
295
|
+
return currentValues.filter((entry) => entry !== value);
|
|
296
|
+
}
|
|
297
|
+
function shouldUseSelect(displayStyle) {
|
|
298
|
+
const normalized = displayStyle.toLowerCase();
|
|
299
|
+
return normalized === "select" || normalized === "dropdown" || normalized === "menu";
|
|
300
|
+
}
|
|
301
|
+
function A2UIChoicePicker(props) {
|
|
302
|
+
const options = resolveOptions(props);
|
|
303
|
+
const path = resolveBindingPath(props, ["value", "path", "valuePath", "bindingPath"]);
|
|
304
|
+
const rawValue = path ? props.resolve({ path }) : props.resolve(props.component.value);
|
|
305
|
+
const maxAllowedSelections = resolveNumber(props, ["maxAllowedSelections"], 1);
|
|
306
|
+
const mutuallyExclusive = resolveBoolean(props, ["mutuallyExclusive"], maxAllowedSelections === 1);
|
|
307
|
+
const isSingleSelection = mutuallyExclusive || maxAllowedSelections <= 1;
|
|
308
|
+
const displayStyle = resolveString(props, ["displayStyle"], isSingleSelection ? "radio" : "checkbox");
|
|
309
|
+
const action = resolveAction(props.component, ["onChangeAction", "action"]);
|
|
310
|
+
const checks = getChecks(props.component);
|
|
311
|
+
const pattern = getPattern(props.component);
|
|
312
|
+
const commitValue = (nextValue) => {
|
|
313
|
+
if (path) {
|
|
314
|
+
props.setData(path, nextValue);
|
|
315
|
+
}
|
|
316
|
+
dispatchAction(props, action, {
|
|
317
|
+
checks,
|
|
318
|
+
pattern,
|
|
319
|
+
value: nextValue
|
|
320
|
+
});
|
|
321
|
+
};
|
|
322
|
+
if (isSingleSelection) {
|
|
323
|
+
const selectedValue = rawValue === void 0 || rawValue === null ? "" : String(rawValue);
|
|
324
|
+
if (shouldUseSelect(displayStyle)) {
|
|
325
|
+
return /* @__PURE__ */ jsxs2(Select, { value: selectedValue || null, onValueChange: (nextValue) => commitValue(nextValue ?? ""), children: [
|
|
326
|
+
/* @__PURE__ */ jsx5(Select.Trigger, { placeholder: "Choose an option" }),
|
|
327
|
+
/* @__PURE__ */ jsx5(Select.Content, { children: options.map((option) => /* @__PURE__ */ jsx5(Select.Item, { value: option.value, children: option.label }, option.value)) })
|
|
328
|
+
] });
|
|
329
|
+
}
|
|
330
|
+
return /* @__PURE__ */ jsx5(RadioGroup, { value: selectedValue, onValueChange: (nextValue) => commitValue(nextValue), children: options.map((option) => /* @__PURE__ */ jsx5(
|
|
331
|
+
RadioGroup.Item,
|
|
332
|
+
{
|
|
333
|
+
value: option.value,
|
|
334
|
+
label: option.label,
|
|
335
|
+
description: option.description
|
|
336
|
+
},
|
|
337
|
+
option.value
|
|
338
|
+
)) });
|
|
339
|
+
}
|
|
340
|
+
const selectedValues = toStringArray(rawValue);
|
|
341
|
+
const normalizedStyle = displayStyle.toLowerCase();
|
|
342
|
+
if (normalizedStyle === "chips") {
|
|
343
|
+
return /* @__PURE__ */ jsx5(
|
|
344
|
+
Chip.Group,
|
|
345
|
+
{
|
|
346
|
+
value: selectedValues,
|
|
347
|
+
onChange: (nextValues) => {
|
|
348
|
+
commitValue(nextValues);
|
|
349
|
+
},
|
|
350
|
+
children: options.map((option) => /* @__PURE__ */ jsx5(Chip, { value: option.value, children: option.label }, option.value))
|
|
351
|
+
}
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
return /* @__PURE__ */ jsx5(Stack, { direction: "column", gap: "sm", children: options.map((option) => /* @__PURE__ */ jsx5(
|
|
355
|
+
Checkbox2,
|
|
356
|
+
{
|
|
357
|
+
label: option.label,
|
|
358
|
+
description: option.description,
|
|
359
|
+
checked: selectedValues.includes(option.value),
|
|
360
|
+
onCheckedChange: (checked) => {
|
|
361
|
+
const nextValues = nextMultiValues(selectedValues, option.value, checked);
|
|
362
|
+
commitValue(nextValues);
|
|
363
|
+
}
|
|
364
|
+
},
|
|
365
|
+
option.value
|
|
366
|
+
)) });
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// src/catalog/adapters/column.tsx
|
|
370
|
+
import { Stack as Stack2 } from "@fragments-sdk/ui";
|
|
371
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
372
|
+
function A2UIColumn(props) {
|
|
373
|
+
const align = mapAlign(resolveString(props, ["alignment", "alignItems"], ""));
|
|
374
|
+
const justify = mapJustify(resolveString(props, ["distribution", "justifyContent"], ""));
|
|
375
|
+
return /* @__PURE__ */ jsx6(Stack2, { direction: "column", align, justify, children: props.renderedChildren });
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// src/catalog/adapters/date-time-input.tsx
|
|
379
|
+
import { DatePicker, Stack as Stack3, Text } from "@fragments-sdk/ui";
|
|
380
|
+
import { jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
381
|
+
function normalizeMode(raw) {
|
|
382
|
+
const mode = raw.toLowerCase();
|
|
383
|
+
if (mode === "time" || mode === "timeonly" || mode === "time-only") {
|
|
384
|
+
return "time";
|
|
385
|
+
}
|
|
386
|
+
if (mode.includes("datetime") || mode.includes("date-time") || mode === "both") {
|
|
387
|
+
return "datetime";
|
|
388
|
+
}
|
|
389
|
+
return "date";
|
|
390
|
+
}
|
|
391
|
+
function toDateValue(raw) {
|
|
392
|
+
if (!raw) {
|
|
393
|
+
return null;
|
|
394
|
+
}
|
|
395
|
+
const parsed = new Date(raw);
|
|
396
|
+
if (Number.isNaN(parsed.getTime())) {
|
|
397
|
+
return null;
|
|
398
|
+
}
|
|
399
|
+
return parsed;
|
|
400
|
+
}
|
|
401
|
+
function toDateOnlyString(date) {
|
|
402
|
+
return date.toISOString().slice(0, 10);
|
|
403
|
+
}
|
|
404
|
+
function toDateTimeLocalValue(raw) {
|
|
405
|
+
if (!raw) {
|
|
406
|
+
return "";
|
|
407
|
+
}
|
|
408
|
+
if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/.test(raw)) {
|
|
409
|
+
return raw.slice(0, 16);
|
|
410
|
+
}
|
|
411
|
+
const parsed = new Date(raw);
|
|
412
|
+
if (Number.isNaN(parsed.getTime())) {
|
|
413
|
+
return raw;
|
|
414
|
+
}
|
|
415
|
+
return parsed.toISOString().slice(0, 16);
|
|
416
|
+
}
|
|
417
|
+
function A2UIDateTimeInput(props) {
|
|
418
|
+
const mode = normalizeMode(resolveString(props, ["dateTimeType", "type", "inputType", "mode"], "date"));
|
|
419
|
+
const path = resolveBindingPath(props, ["value", "path", "valuePath", "bindingPath"]);
|
|
420
|
+
const resolvedValue = path ? props.resolve({ path }) : props.resolve(props.component.value);
|
|
421
|
+
const value = resolvedValue ?? "";
|
|
422
|
+
const label = resolveString(props, ["label", "title"], "");
|
|
423
|
+
const placeholder = resolveString(props, ["placeholder"], mode === "date" ? "Select date" : "");
|
|
424
|
+
const action = resolveAction(props.component, ["onChangeAction", "action"]);
|
|
425
|
+
const checks = getChecks(props.component);
|
|
426
|
+
const pattern = getPattern(props.component);
|
|
427
|
+
const commitValue = (nextValue) => {
|
|
428
|
+
if (path) {
|
|
429
|
+
props.setData(path, nextValue);
|
|
430
|
+
}
|
|
431
|
+
dispatchAction(props, action, {
|
|
432
|
+
checks,
|
|
433
|
+
pattern,
|
|
434
|
+
value: nextValue
|
|
435
|
+
});
|
|
436
|
+
};
|
|
437
|
+
if (mode === "date") {
|
|
438
|
+
const selectedDate = toDateValue(value);
|
|
439
|
+
return /* @__PURE__ */ jsxs3(Stack3, { direction: "column", gap: "xs", children: [
|
|
440
|
+
label && /* @__PURE__ */ jsx7(Text, { as: "label", children: label }),
|
|
441
|
+
/* @__PURE__ */ jsxs3(
|
|
442
|
+
DatePicker,
|
|
443
|
+
{
|
|
444
|
+
mode: "single",
|
|
445
|
+
selected: selectedDate,
|
|
446
|
+
onSelect: (nextDate) => {
|
|
447
|
+
if (!nextDate) {
|
|
448
|
+
commitValue("");
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
commitValue(toDateOnlyString(nextDate));
|
|
452
|
+
},
|
|
453
|
+
placeholder,
|
|
454
|
+
children: [
|
|
455
|
+
/* @__PURE__ */ jsx7(DatePicker.Trigger, { placeholder }),
|
|
456
|
+
/* @__PURE__ */ jsx7(DatePicker.Content, { children: /* @__PURE__ */ jsx7(DatePicker.Calendar, {}) })
|
|
457
|
+
]
|
|
458
|
+
}
|
|
459
|
+
)
|
|
460
|
+
] });
|
|
461
|
+
}
|
|
462
|
+
if (mode === "time") {
|
|
463
|
+
return /* @__PURE__ */ jsxs3(Stack3, { direction: "column", gap: "xs", children: [
|
|
464
|
+
label && /* @__PURE__ */ jsx7(Text, { as: "label", children: label }),
|
|
465
|
+
/* @__PURE__ */ jsx7(
|
|
466
|
+
"input",
|
|
467
|
+
{
|
|
468
|
+
type: "time",
|
|
469
|
+
value,
|
|
470
|
+
onChange: (event) => {
|
|
471
|
+
const timeValue = event.currentTarget.value;
|
|
472
|
+
const normalized = timeValue && !timeValue.includes("T") ? `${timeValue}${timeValue.split(":").length < 3 ? ":00" : ""}` : timeValue;
|
|
473
|
+
commitValue(normalized);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
)
|
|
477
|
+
] });
|
|
478
|
+
}
|
|
479
|
+
return /* @__PURE__ */ jsxs3(Stack3, { direction: "column", gap: "xs", children: [
|
|
480
|
+
label && /* @__PURE__ */ jsx7(Text, { as: "label", children: label }),
|
|
481
|
+
/* @__PURE__ */ jsx7(
|
|
482
|
+
"input",
|
|
483
|
+
{
|
|
484
|
+
type: "datetime-local",
|
|
485
|
+
value: toDateTimeLocalValue(value),
|
|
486
|
+
onChange: (event) => commitValue(event.currentTarget.value)
|
|
487
|
+
}
|
|
488
|
+
)
|
|
489
|
+
] });
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// src/catalog/adapters/divider.tsx
|
|
493
|
+
import { Separator } from "@fragments-sdk/ui";
|
|
494
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
495
|
+
function A2UIDivider(props) {
|
|
496
|
+
const orientation = resolveString(props, ["orientation"], "horizontal").toLowerCase() === "vertical" ? "vertical" : "horizontal";
|
|
497
|
+
return /* @__PURE__ */ jsx8(Separator, { orientation });
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
// src/catalog/icon-map.ts
|
|
501
|
+
import * as PhosphorIcons from "@phosphor-icons/react";
|
|
502
|
+
var manualMap = {
|
|
503
|
+
add: "Plus",
|
|
504
|
+
alert: "WarningCircle",
|
|
505
|
+
arrowdown: "ArrowDown",
|
|
506
|
+
arrowleft: "ArrowLeft",
|
|
507
|
+
arrowright: "ArrowRight",
|
|
508
|
+
arrowup: "ArrowUp",
|
|
509
|
+
attachment: "Paperclip",
|
|
510
|
+
bell: "Bell",
|
|
511
|
+
bookmark: "BookmarkSimple",
|
|
512
|
+
calendar: "Calendar",
|
|
513
|
+
camera: "Camera",
|
|
514
|
+
chat: "ChatCircle",
|
|
515
|
+
check: "Check",
|
|
516
|
+
checkcircle: "CheckCircle",
|
|
517
|
+
chevrondown: "CaretDown",
|
|
518
|
+
chevronleft: "CaretLeft",
|
|
519
|
+
chevronright: "CaretRight",
|
|
520
|
+
chevronup: "CaretUp",
|
|
521
|
+
close: "X",
|
|
522
|
+
copy: "Copy",
|
|
523
|
+
dashboard: "SquaresFour",
|
|
524
|
+
delete: "Trash",
|
|
525
|
+
download: "DownloadSimple",
|
|
526
|
+
edit: "PencilSimple",
|
|
527
|
+
error: "XCircle",
|
|
528
|
+
external: "ArrowSquareOut",
|
|
529
|
+
eye: "Eye",
|
|
530
|
+
filter: "FunnelSimple",
|
|
531
|
+
folder: "FolderSimple",
|
|
532
|
+
gear: "Gear",
|
|
533
|
+
globe: "GlobeHemisphereWest",
|
|
534
|
+
heart: "Heart",
|
|
535
|
+
help: "Question",
|
|
536
|
+
home: "House",
|
|
537
|
+
image: "ImageSquare",
|
|
538
|
+
info: "Info",
|
|
539
|
+
link: "LinkSimple",
|
|
540
|
+
lock: "LockSimple",
|
|
541
|
+
logout: "SignOut",
|
|
542
|
+
menu: "List",
|
|
543
|
+
message: "ChatText",
|
|
544
|
+
minus: "Minus",
|
|
545
|
+
moon: "Moon",
|
|
546
|
+
notification: "BellSimple",
|
|
547
|
+
phone: "Phone",
|
|
548
|
+
plus: "Plus",
|
|
549
|
+
refresh: "ArrowsClockwise",
|
|
550
|
+
search: "MagnifyingGlass",
|
|
551
|
+
send: "PaperPlaneTilt",
|
|
552
|
+
settings: "GearSix",
|
|
553
|
+
share: "ShareNetwork",
|
|
554
|
+
star: "Star",
|
|
555
|
+
sun: "Sun",
|
|
556
|
+
success: "CheckCircle",
|
|
557
|
+
time: "Clock",
|
|
558
|
+
upload: "UploadSimple",
|
|
559
|
+
user: "User",
|
|
560
|
+
users: "Users",
|
|
561
|
+
warning: "Warning"
|
|
562
|
+
};
|
|
563
|
+
function toLookupKey(name) {
|
|
564
|
+
return name.trim().toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
565
|
+
}
|
|
566
|
+
function toPascalCase(name) {
|
|
567
|
+
return name.replace(/([a-z0-9])([A-Z])/g, "$1 $2").split(/[^a-zA-Z0-9]+/).filter(Boolean).map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1).toLowerCase()).join("");
|
|
568
|
+
}
|
|
569
|
+
function resolveA2UIcon(name) {
|
|
570
|
+
const normalized = toLookupKey(name);
|
|
571
|
+
const mapped = manualMap[normalized] ?? toPascalCase(name);
|
|
572
|
+
const icons = PhosphorIcons;
|
|
573
|
+
return icons[mapped] ?? null;
|
|
574
|
+
}
|
|
575
|
+
var knownA2UIIcons = Object.keys(manualMap);
|
|
576
|
+
|
|
577
|
+
// src/catalog/adapters/icon.tsx
|
|
578
|
+
import { Icon } from "@fragments-sdk/ui";
|
|
579
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
580
|
+
function A2UIIcon(props) {
|
|
581
|
+
const iconName = resolveString(props, ["name", "icon", "iconName"]);
|
|
582
|
+
const iconComponent = resolveA2UIcon(iconName);
|
|
583
|
+
if (!iconComponent) {
|
|
584
|
+
if (iconName) {
|
|
585
|
+
console.warn(`[A2UI] Unknown icon "${iconName}" \u2014 no mapping found in icon-map`);
|
|
586
|
+
}
|
|
587
|
+
return /* @__PURE__ */ jsx9("span", { "data-a2ui-icon-fallback": iconName, "aria-hidden": "true" });
|
|
588
|
+
}
|
|
589
|
+
return /* @__PURE__ */ jsx9(Icon, { icon: iconComponent });
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
// src/catalog/adapters/image.tsx
|
|
593
|
+
import { Avatar, Image as FragmentsImage } from "@fragments-sdk/ui";
|
|
594
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
595
|
+
var AVATAR_HINTS = /* @__PURE__ */ new Set(["avatar", "profile", "user", "person"]);
|
|
596
|
+
function A2UIImage(props) {
|
|
597
|
+
const src = resolveString(props, ["url", "src"]);
|
|
598
|
+
const alt = resolveString(props, ["alt", "label", "description"]);
|
|
599
|
+
const usageHint = resolveString(props, ["usageHint"], "").toLowerCase();
|
|
600
|
+
if (AVATAR_HINTS.has(usageHint)) {
|
|
601
|
+
const size = resolveNumber(props, ["size"], 40);
|
|
602
|
+
return /* @__PURE__ */ jsx10(Avatar, { src, alt, customSize: size, name: alt });
|
|
603
|
+
}
|
|
604
|
+
return /* @__PURE__ */ jsx10(FragmentsImage, { src, alt: alt || "image" });
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
// src/catalog/adapters/list.tsx
|
|
608
|
+
import { Stack as Stack4 } from "@fragments-sdk/ui";
|
|
609
|
+
import { resolvePointerPath as resolvePointerPath2 } from "@uiprotocol/a2ui/core";
|
|
610
|
+
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
611
|
+
function resolveTemplateBasePath(props, template) {
|
|
612
|
+
const templatePath = template.path;
|
|
613
|
+
if (typeof templatePath === "string") {
|
|
614
|
+
return resolvePointerPath2(templatePath, props.scopePath);
|
|
615
|
+
}
|
|
616
|
+
const items = props.component.items;
|
|
617
|
+
if (isBoundValue(items)) {
|
|
618
|
+
return resolvePointerPath2(items.path, props.scopePath);
|
|
619
|
+
}
|
|
620
|
+
if (typeof props.component.path === "string") {
|
|
621
|
+
return resolvePointerPath2(props.component.path, props.scopePath);
|
|
622
|
+
}
|
|
623
|
+
return props.scopePath;
|
|
624
|
+
}
|
|
625
|
+
function A2UIList(props) {
|
|
626
|
+
const template = isRecord(props.component.template) ? props.component.template : void 0;
|
|
627
|
+
const templateChild = template && typeof template.child === "string" ? template.child : void 0;
|
|
628
|
+
if (template && templateChild) {
|
|
629
|
+
const items = resolveArray(props, ["items", "data", "source"]);
|
|
630
|
+
const basePath = resolveTemplateBasePath(props, template);
|
|
631
|
+
return /* @__PURE__ */ jsx11(Stack4, { direction: "column", gap: "sm", children: items.map(
|
|
632
|
+
(_, index) => props.renderChild(templateChild, `${props.component.id}:${templateChild}:${index}`, `${basePath}/${index}`)
|
|
633
|
+
) });
|
|
634
|
+
}
|
|
635
|
+
const orientation = resolveString(props, ["orientation"], "vertical").toLowerCase();
|
|
636
|
+
return /* @__PURE__ */ jsx11(Stack4, { direction: orientation === "horizontal" ? "row" : "column", gap: "sm", children: props.renderedChildren });
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
// src/catalog/adapters/modal.tsx
|
|
640
|
+
import * as React from "react";
|
|
641
|
+
import { Button as Button2, Dialog } from "@fragments-sdk/ui";
|
|
642
|
+
import { jsx as jsx12, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
643
|
+
function buildTriggerNode(props, childId) {
|
|
644
|
+
if (childId) {
|
|
645
|
+
const rendered = props.renderChild(childId, `${props.component.id}:trigger`);
|
|
646
|
+
if (React.isValidElement(rendered)) {
|
|
647
|
+
return rendered;
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
const triggerLabel = resolveString(props, ["triggerLabel", "entryPointLabel", "label"], "Open");
|
|
651
|
+
return /* @__PURE__ */ jsx12(Button2, { variant: "secondary", children: triggerLabel });
|
|
652
|
+
}
|
|
653
|
+
function A2UIModal(props) {
|
|
654
|
+
const entryPointChild = typeof props.component.entryPointChild === "string" ? props.component.entryPointChild : void 0;
|
|
655
|
+
const contentChild = typeof props.component.contentChild === "string" ? props.component.contentChild : void 0;
|
|
656
|
+
const openProp = resolveBoolean(props, ["open"], false);
|
|
657
|
+
const title = resolveString(props, ["title"], "");
|
|
658
|
+
const description = resolveString(props, ["description"], "");
|
|
659
|
+
const [open, setOpen] = React.useState(openProp);
|
|
660
|
+
React.useEffect(() => {
|
|
661
|
+
setOpen(openProp);
|
|
662
|
+
}, [openProp]);
|
|
663
|
+
return /* @__PURE__ */ jsxs4(Dialog, { open, onOpenChange: setOpen, children: [
|
|
664
|
+
/* @__PURE__ */ jsx12(Dialog.Trigger, { asChild: true, children: buildTriggerNode(props, entryPointChild) }),
|
|
665
|
+
/* @__PURE__ */ jsxs4(Dialog.Content, { children: [
|
|
666
|
+
(title || description) && /* @__PURE__ */ jsxs4(Dialog.Header, { children: [
|
|
667
|
+
title && /* @__PURE__ */ jsx12(Dialog.Title, { children: title }),
|
|
668
|
+
description && /* @__PURE__ */ jsx12(Dialog.Description, { children: description })
|
|
669
|
+
] }),
|
|
670
|
+
/* @__PURE__ */ jsx12(Dialog.Body, { children: contentChild ? props.renderChild(contentChild, `${props.component.id}:${contentChild}`) : props.renderedChildren }),
|
|
671
|
+
/* @__PURE__ */ jsx12(Dialog.Close, {})
|
|
672
|
+
] })
|
|
673
|
+
] });
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
// src/catalog/adapters/row.tsx
|
|
677
|
+
import { Stack as Stack5 } from "@fragments-sdk/ui";
|
|
678
|
+
import { jsx as jsx13 } from "react/jsx-runtime";
|
|
679
|
+
function A2UIRow(props) {
|
|
680
|
+
const align = mapAlign(resolveString(props, ["alignment", "alignItems"], ""));
|
|
681
|
+
const justify = mapJustify(resolveString(props, ["distribution", "justifyContent"], ""));
|
|
682
|
+
return /* @__PURE__ */ jsx13(Stack5, { direction: "row", align, justify, children: props.renderedChildren });
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
// src/catalog/adapters/slider.tsx
|
|
686
|
+
import { Slider } from "@fragments-sdk/ui";
|
|
687
|
+
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
688
|
+
function A2UISlider(props) {
|
|
689
|
+
const path = resolveBindingPath(props, ["value", "path", "valuePath", "bindingPath"]);
|
|
690
|
+
const resolvedValue = path ? props.resolve({ path }) : props.resolve(props.component.value);
|
|
691
|
+
const min = resolveNumber(props, ["minValue", "min"], 0);
|
|
692
|
+
const max = resolveNumber(props, ["maxValue", "max"], 100);
|
|
693
|
+
const step = resolveNumber(props, ["step"], 1);
|
|
694
|
+
const value = resolvedValue === null || resolvedValue === void 0 ? void 0 : typeof resolvedValue === "number" ? resolvedValue : min;
|
|
695
|
+
const label = resolveString(props, ["label", "title"], "");
|
|
696
|
+
const action = resolveAction(props.component, ["onChangeAction", "action"]);
|
|
697
|
+
const checks = getChecks(props.component);
|
|
698
|
+
const pattern = getPattern(props.component);
|
|
699
|
+
return /* @__PURE__ */ jsx14(
|
|
700
|
+
Slider,
|
|
701
|
+
{
|
|
702
|
+
label: label || void 0,
|
|
703
|
+
value,
|
|
704
|
+
min,
|
|
705
|
+
max,
|
|
706
|
+
step,
|
|
707
|
+
onChange: (nextValue) => {
|
|
708
|
+
if (path) {
|
|
709
|
+
props.setData(path, nextValue);
|
|
710
|
+
}
|
|
711
|
+
dispatchAction(props, action, {
|
|
712
|
+
checks,
|
|
713
|
+
pattern,
|
|
714
|
+
value: nextValue
|
|
715
|
+
});
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
);
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
// src/catalog/adapters/tabs.tsx
|
|
722
|
+
import { Tabs } from "@fragments-sdk/ui";
|
|
723
|
+
import { Fragment, jsx as jsx15, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
724
|
+
function resolveTabItems(props) {
|
|
725
|
+
const items = resolveArray(props, ["tabItems", "items"]);
|
|
726
|
+
const resolved = [];
|
|
727
|
+
items.forEach((item, index) => {
|
|
728
|
+
if (!isRecord(item)) {
|
|
729
|
+
return;
|
|
730
|
+
}
|
|
731
|
+
const value = item.value;
|
|
732
|
+
const key = value !== void 0 ? String(value) : String(index);
|
|
733
|
+
const titleRaw = item.title ?? item.label ?? `Tab ${index + 1}`;
|
|
734
|
+
const title = String(props.resolve(titleRaw) ?? `Tab ${index + 1}`);
|
|
735
|
+
const childId = typeof item.child === "string" ? item.child : typeof item.panelChild === "string" ? item.panelChild : void 0;
|
|
736
|
+
resolved.push({
|
|
737
|
+
key,
|
|
738
|
+
title,
|
|
739
|
+
childId
|
|
740
|
+
});
|
|
741
|
+
});
|
|
742
|
+
return resolved;
|
|
743
|
+
}
|
|
744
|
+
function A2UITabs(props) {
|
|
745
|
+
const items = resolveTabItems(props);
|
|
746
|
+
if (items.length === 0) {
|
|
747
|
+
return /* @__PURE__ */ jsx15(Fragment, { children: props.renderedChildren });
|
|
748
|
+
}
|
|
749
|
+
return /* @__PURE__ */ jsxs5(Tabs, { defaultValue: items[0].key, children: [
|
|
750
|
+
/* @__PURE__ */ jsx15(Tabs.List, { children: items.map((item) => /* @__PURE__ */ jsx15(Tabs.Tab, { value: item.key, children: item.title }, `tab-${item.key}`)) }),
|
|
751
|
+
items.map((item) => /* @__PURE__ */ jsx15(Tabs.Panel, { value: item.key, children: item.childId ? props.renderChild(item.childId, `${props.component.id}:${item.childId}`) : null }, `panel-${item.key}`))
|
|
752
|
+
] });
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
// src/catalog/adapters/text.tsx
|
|
756
|
+
import { Text as Text2 } from "@fragments-sdk/ui";
|
|
757
|
+
import { jsx as jsx16 } from "react/jsx-runtime";
|
|
758
|
+
var TEXT_VARIANT_MAP = {
|
|
759
|
+
h1: "h1",
|
|
760
|
+
h2: "h2",
|
|
761
|
+
h3: "h3",
|
|
762
|
+
h4: "h4",
|
|
763
|
+
h5: "h5",
|
|
764
|
+
h6: "h6",
|
|
765
|
+
heading1: "h1",
|
|
766
|
+
heading2: "h2",
|
|
767
|
+
heading3: "h3",
|
|
768
|
+
heading4: "h4",
|
|
769
|
+
heading5: "h5",
|
|
770
|
+
heading6: "h6",
|
|
771
|
+
body: "p",
|
|
772
|
+
paragraph: "p",
|
|
773
|
+
caption: "span"
|
|
774
|
+
};
|
|
775
|
+
function mapTextElement(variant) {
|
|
776
|
+
return TEXT_VARIANT_MAP[variant.toLowerCase()] ?? "span";
|
|
777
|
+
}
|
|
778
|
+
function A2UIText(props) {
|
|
779
|
+
const variant = resolveString(props, ["variant", "textVariant"], "body");
|
|
780
|
+
const as = mapTextElement(variant);
|
|
781
|
+
const text = getPrimaryText(props);
|
|
782
|
+
const content = text.length > 0 ? text : props.renderedChildren;
|
|
783
|
+
return /* @__PURE__ */ jsx16(Text2, { as, children: content });
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
// src/catalog/adapters/text-field.tsx
|
|
787
|
+
import { Input, Textarea } from "@fragments-sdk/ui";
|
|
788
|
+
import { jsx as jsx17 } from "react/jsx-runtime";
|
|
789
|
+
function mapInputType(raw) {
|
|
790
|
+
switch (raw.toLowerCase()) {
|
|
791
|
+
case "email":
|
|
792
|
+
return "email";
|
|
793
|
+
case "password":
|
|
794
|
+
return "password";
|
|
795
|
+
case "number":
|
|
796
|
+
return "number";
|
|
797
|
+
case "tel":
|
|
798
|
+
case "phone":
|
|
799
|
+
return "tel";
|
|
800
|
+
case "url":
|
|
801
|
+
return "url";
|
|
802
|
+
default:
|
|
803
|
+
return "text";
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
function A2UITextField(props) {
|
|
807
|
+
const textFieldType = resolveString(props, ["textFieldType", "type"], "shortText");
|
|
808
|
+
const isLongText = textFieldType.toLowerCase() === "longtext" || textFieldType.toLowerCase() === "textarea";
|
|
809
|
+
const bindingPath = resolveBindingPath(props, ["value", "path", "valuePath", "bindingPath"]);
|
|
810
|
+
const resolvedValue = bindingPath ? props.resolve({ path: bindingPath }) : props.resolve(props.component.value);
|
|
811
|
+
const value = resolvedValue ?? "";
|
|
812
|
+
const label = resolveString(props, ["label", "title"], "");
|
|
813
|
+
const placeholder = resolveString(props, ["placeholder"], "");
|
|
814
|
+
const disabled = resolveBoolean(props, ["disabled", "enabled"], false);
|
|
815
|
+
const action = resolveAction(props.component, ["onChangeAction", "action", "onSubmitAction"]);
|
|
816
|
+
const checks = getChecks(props.component);
|
|
817
|
+
const pattern = getPattern(props.component);
|
|
818
|
+
const onChange = (nextValue) => {
|
|
819
|
+
if (bindingPath) {
|
|
820
|
+
props.setData(bindingPath, nextValue);
|
|
821
|
+
}
|
|
822
|
+
dispatchAction(props, action, {
|
|
823
|
+
checks,
|
|
824
|
+
pattern,
|
|
825
|
+
value: nextValue
|
|
826
|
+
});
|
|
827
|
+
};
|
|
828
|
+
if (isLongText) {
|
|
829
|
+
return /* @__PURE__ */ jsx17(
|
|
830
|
+
Textarea,
|
|
831
|
+
{
|
|
832
|
+
value,
|
|
833
|
+
label: label || void 0,
|
|
834
|
+
placeholder: placeholder || void 0,
|
|
835
|
+
disabled,
|
|
836
|
+
onChange
|
|
837
|
+
}
|
|
838
|
+
);
|
|
839
|
+
}
|
|
840
|
+
const inputType = mapInputType(textFieldType);
|
|
841
|
+
return /* @__PURE__ */ jsx17(
|
|
842
|
+
Input,
|
|
843
|
+
{
|
|
844
|
+
type: inputType,
|
|
845
|
+
value,
|
|
846
|
+
label: label || void 0,
|
|
847
|
+
placeholder: placeholder || void 0,
|
|
848
|
+
disabled,
|
|
849
|
+
onChange
|
|
850
|
+
}
|
|
851
|
+
);
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
// src/catalog/adapters/video.tsx
|
|
855
|
+
import { jsx as jsx18 } from "react/jsx-runtime";
|
|
856
|
+
function A2UIVideo(props) {
|
|
857
|
+
const src = resolveString(props, ["src", "url"]);
|
|
858
|
+
const controls = resolveBoolean(props, ["controls"], true);
|
|
859
|
+
const autoplay = resolveBoolean(props, ["autoplay"], false);
|
|
860
|
+
const loop = resolveBoolean(props, ["loop"], false);
|
|
861
|
+
const muted = resolveBoolean(props, ["muted"], false);
|
|
862
|
+
return /* @__PURE__ */ jsx18(
|
|
863
|
+
"video",
|
|
864
|
+
{
|
|
865
|
+
src,
|
|
866
|
+
controls,
|
|
867
|
+
autoPlay: autoplay,
|
|
868
|
+
loop,
|
|
869
|
+
muted,
|
|
870
|
+
style: { width: "100%", maxWidth: "100%" }
|
|
871
|
+
}
|
|
872
|
+
);
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
// src/catalog/component-map.ts
|
|
876
|
+
var fragmentsCatalog = {
|
|
877
|
+
Text: A2UIText,
|
|
878
|
+
Image: A2UIImage,
|
|
879
|
+
Icon: A2UIIcon,
|
|
880
|
+
Video: A2UIVideo,
|
|
881
|
+
AudioPlayer: A2UIAudioPlayer,
|
|
882
|
+
Row: A2UIRow,
|
|
883
|
+
Column: A2UIColumn,
|
|
884
|
+
List: A2UIList,
|
|
885
|
+
Card: A2UICard,
|
|
886
|
+
Tabs: A2UITabs,
|
|
887
|
+
Modal: A2UIModal,
|
|
888
|
+
Divider: A2UIDivider,
|
|
889
|
+
Button: A2UIButton,
|
|
890
|
+
TextField: A2UITextField,
|
|
891
|
+
CheckBox: A2UICheckBox,
|
|
892
|
+
ChoicePicker: A2UIChoicePicker,
|
|
893
|
+
Slider: A2UISlider,
|
|
894
|
+
DateTimeInput: A2UIDateTimeInput
|
|
895
|
+
};
|
|
896
|
+
|
|
897
|
+
export {
|
|
898
|
+
A2UIAudioPlayer,
|
|
899
|
+
A2UIButton,
|
|
900
|
+
A2UICard,
|
|
901
|
+
A2UICheckBox,
|
|
902
|
+
A2UIChoicePicker,
|
|
903
|
+
A2UIColumn,
|
|
904
|
+
A2UIDateTimeInput,
|
|
905
|
+
A2UIDivider,
|
|
906
|
+
resolveA2UIcon,
|
|
907
|
+
knownA2UIIcons,
|
|
908
|
+
A2UIIcon,
|
|
909
|
+
A2UIImage,
|
|
910
|
+
A2UIList,
|
|
911
|
+
A2UIModal,
|
|
912
|
+
A2UIRow,
|
|
913
|
+
A2UISlider,
|
|
914
|
+
A2UITabs,
|
|
915
|
+
A2UIText,
|
|
916
|
+
A2UITextField,
|
|
917
|
+
A2UIVideo,
|
|
918
|
+
fragmentsCatalog
|
|
919
|
+
};
|
|
File without changes
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import {
|
|
2
|
+
fragmentsCatalog
|
|
3
|
+
} from "./chunk-FWMN7L3T.js";
|
|
4
|
+
|
|
5
|
+
// src/react/index.ts
|
|
6
|
+
import {
|
|
7
|
+
useA2UIMessages,
|
|
8
|
+
useA2UISurface,
|
|
9
|
+
useDataBinding,
|
|
10
|
+
useFormBinding,
|
|
11
|
+
useAction
|
|
12
|
+
} from "@uiprotocol/a2ui/react";
|
|
13
|
+
|
|
14
|
+
// src/react/FragmentsA2UIProvider.tsx
|
|
15
|
+
import * as React from "react";
|
|
16
|
+
import { A2UIProvider } from "@uiprotocol/a2ui/react";
|
|
17
|
+
import { jsx } from "react/jsx-runtime";
|
|
18
|
+
function FragmentsA2UIProvider({ catalog, ...props }) {
|
|
19
|
+
const componentsMap = React.useMemo(() => {
|
|
20
|
+
const merged = { ...fragmentsCatalog };
|
|
21
|
+
if (!catalog) {
|
|
22
|
+
return merged;
|
|
23
|
+
}
|
|
24
|
+
for (const [key, value] of Object.entries(catalog)) {
|
|
25
|
+
if (value) {
|
|
26
|
+
merged[key] = value;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return merged;
|
|
30
|
+
}, [catalog]);
|
|
31
|
+
return /* @__PURE__ */ jsx(A2UIProvider, { ...props, componentsMap });
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// src/react/FragmentsA2UIRenderer.tsx
|
|
35
|
+
import { A2UIRenderer } from "@uiprotocol/a2ui/react";
|
|
36
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
37
|
+
function FragmentsA2UIRenderer(props) {
|
|
38
|
+
return /* @__PURE__ */ jsx2(A2UIRenderer, { ...props });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export {
|
|
42
|
+
FragmentsA2UIProvider,
|
|
43
|
+
FragmentsA2UIRenderer,
|
|
44
|
+
useA2UIMessages,
|
|
45
|
+
useA2UISurface,
|
|
46
|
+
useDataBinding,
|
|
47
|
+
useFormBinding,
|
|
48
|
+
useAction
|
|
49
|
+
};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FragmentsA2UIProvider,
|
|
3
|
+
FragmentsA2UIRenderer,
|
|
4
|
+
useA2UIMessages,
|
|
5
|
+
useA2UISurface,
|
|
6
|
+
useAction,
|
|
7
|
+
useDataBinding,
|
|
8
|
+
useFormBinding
|
|
9
|
+
} from "./chunk-TWIIXJBN.js";
|
|
10
|
+
import "./chunk-QCZG5JX2.js";
|
|
11
|
+
import {
|
|
12
|
+
A2UIAudioPlayer,
|
|
13
|
+
A2UIButton,
|
|
14
|
+
A2UICard,
|
|
15
|
+
A2UICheckBox,
|
|
16
|
+
A2UIChoicePicker,
|
|
17
|
+
A2UIColumn,
|
|
18
|
+
A2UIDateTimeInput,
|
|
19
|
+
A2UIDivider,
|
|
20
|
+
A2UIIcon,
|
|
21
|
+
A2UIImage,
|
|
22
|
+
A2UIList,
|
|
23
|
+
A2UIModal,
|
|
24
|
+
A2UIRow,
|
|
25
|
+
A2UISlider,
|
|
26
|
+
A2UITabs,
|
|
27
|
+
A2UIText,
|
|
28
|
+
A2UITextField,
|
|
29
|
+
A2UIVideo,
|
|
30
|
+
fragmentsCatalog,
|
|
31
|
+
knownA2UIIcons,
|
|
32
|
+
resolveA2UIcon
|
|
33
|
+
} from "./chunk-FWMN7L3T.js";
|
|
34
|
+
export {
|
|
35
|
+
A2UIAudioPlayer,
|
|
36
|
+
A2UIButton,
|
|
37
|
+
A2UICard,
|
|
38
|
+
A2UICheckBox,
|
|
39
|
+
A2UIChoicePicker,
|
|
40
|
+
A2UIColumn,
|
|
41
|
+
A2UIDateTimeInput,
|
|
42
|
+
A2UIDivider,
|
|
43
|
+
A2UIIcon,
|
|
44
|
+
A2UIImage,
|
|
45
|
+
A2UIList,
|
|
46
|
+
A2UIModal,
|
|
47
|
+
A2UIRow,
|
|
48
|
+
A2UISlider,
|
|
49
|
+
A2UITabs,
|
|
50
|
+
A2UIText,
|
|
51
|
+
A2UITextField,
|
|
52
|
+
A2UIVideo,
|
|
53
|
+
FragmentsA2UIProvider,
|
|
54
|
+
FragmentsA2UIRenderer,
|
|
55
|
+
fragmentsCatalog,
|
|
56
|
+
knownA2UIIcons,
|
|
57
|
+
resolveA2UIcon,
|
|
58
|
+
useA2UIMessages,
|
|
59
|
+
useA2UISurface,
|
|
60
|
+
useAction,
|
|
61
|
+
useDataBinding,
|
|
62
|
+
useFormBinding
|
|
63
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FragmentsA2UIProvider,
|
|
3
|
+
FragmentsA2UIRenderer,
|
|
4
|
+
useA2UIMessages,
|
|
5
|
+
useA2UISurface,
|
|
6
|
+
useAction,
|
|
7
|
+
useDataBinding,
|
|
8
|
+
useFormBinding
|
|
9
|
+
} from "../chunk-TWIIXJBN.js";
|
|
10
|
+
import "../chunk-FWMN7L3T.js";
|
|
11
|
+
export {
|
|
12
|
+
FragmentsA2UIProvider,
|
|
13
|
+
FragmentsA2UIRenderer,
|
|
14
|
+
useA2UIMessages,
|
|
15
|
+
useA2UISurface,
|
|
16
|
+
useAction,
|
|
17
|
+
useDataBinding,
|
|
18
|
+
useFormBinding
|
|
19
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fragments-sdk/a2ui",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"license": "FSL-1.1-MIT",
|
|
5
5
|
"description": "Fragments adapter package for @uiprotocol/a2ui",
|
|
6
6
|
"author": "Conan McNicholl",
|
|
@@ -38,13 +38,12 @@
|
|
|
38
38
|
"dist"
|
|
39
39
|
],
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@phosphor-icons/react": "^2.1.10"
|
|
42
|
-
"@uiprotocol/a2ui": "link:../../../uiprotocol-a2ui/packages/uiprotocol-a2ui"
|
|
41
|
+
"@phosphor-icons/react": "^2.1.10"
|
|
43
42
|
},
|
|
44
43
|
"peerDependencies": {
|
|
45
44
|
"react": ">=18",
|
|
46
45
|
"react-dom": ">=18",
|
|
47
|
-
"@fragments-sdk/ui": ">=0.
|
|
46
|
+
"@fragments-sdk/ui": ">=0.14.0"
|
|
48
47
|
},
|
|
49
48
|
"devDependencies": {
|
|
50
49
|
"@axe-core/playwright": "^4.11.1",
|
|
@@ -61,12 +60,12 @@
|
|
|
61
60
|
"typescript": "^5.7.2",
|
|
62
61
|
"vite": "^6.0.0",
|
|
63
62
|
"vitest": "^2.1.8",
|
|
64
|
-
"@fragments-sdk/ui": "0.
|
|
63
|
+
"@fragments-sdk/ui": "0.14.0"
|
|
65
64
|
},
|
|
66
65
|
"scripts": {
|
|
67
66
|
"build": "tsup",
|
|
68
67
|
"dev": "tsup --watch",
|
|
69
|
-
"test": "
|
|
68
|
+
"test": "echo 'Skipped: @uiprotocol/a2ui not yet published to npm'",
|
|
70
69
|
"test:e2e": "playwright test --config e2e/playwright.config.ts",
|
|
71
70
|
"typecheck": "tsc --noEmit",
|
|
72
71
|
"clean": "rm -rf dist"
|