@pipelex/mthds-form 0.32.0 → 0.34.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/README.md +1 -1
- package/dist/brand/index.js +2 -2
- package/dist/{chunk-PCNFELNT.js → chunk-5RV3ASMO.js} +141 -69
- package/dist/chunk-5RV3ASMO.js.map +1 -0
- package/dist/{chunk-VH5CDQDR.js → chunk-AURDKAIC.js} +3 -3
- package/dist/{chunk-VH5CDQDR.js.map → chunk-AURDKAIC.js.map} +1 -1
- package/dist/{chunk-ZX52CQJ4.js → chunk-CFBK7NO7.js} +3 -3
- package/dist/{chunk-ZX52CQJ4.js.map → chunk-CFBK7NO7.js.map} +1 -1
- package/dist/{chunk-3GO65HWP.js → chunk-PNNWNRPG.js} +11 -7
- package/dist/chunk-PNNWNRPG.js.map +1 -0
- package/dist/{chunk-XO5OENNF.js → chunk-TF4RTKLH.js} +32 -5
- package/dist/chunk-TF4RTKLH.js.map +1 -0
- package/dist/{chunk-IBBAJXIO.js → chunk-XIWBKV7T.js} +3 -3
- package/dist/{chunk-IBBAJXIO.js.map → chunk-XIWBKV7T.js.map} +1 -1
- package/dist/{chunk-VBXFGUCG.js → chunk-XYS5KCXB.js} +465 -112
- package/dist/chunk-XYS5KCXB.js.map +1 -0
- package/dist/core/gate.js +2 -2
- package/dist/core/index.js +4 -4
- package/dist/core/readiness.d.ts +34 -1
- package/dist/core/readiness.js +1 -1
- package/dist/core/seed.js +2 -2
- package/dist/core/values.js +2 -2
- package/dist/{field-renderer-Dz03dpig.d.ts → field-renderer-BYN6YrU-.d.ts} +6 -6
- package/dist/generative/headless/index.d.ts +53 -16
- package/dist/generative/headless/index.js +3 -2
- package/dist/generative/index.d.ts +79 -25
- package/dist/generative/index.js +942 -275
- package/dist/generative/index.js.map +1 -1
- package/dist/react/index.d.ts +56 -29
- package/dist/react/index.js +4 -4
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/dist/chunk-3GO65HWP.js.map +0 -1
- package/dist/chunk-PCNFELNT.js.map +0 -1
- package/dist/chunk-VBXFGUCG.js.map +0 -1
- package/dist/chunk-XO5OENNF.js.map +0 -1
package/dist/generative/index.js
CHANGED
|
@@ -1,33 +1,34 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { cn, headingClass, checkedAccentClass, focusOutlineClass, useResolveUrl, panelSurfaceClass, panelFlatShadowClass, linkTextClass, actionShadowClass, panelRaisedShadowClass, fieldControlClass, ResultRoot, ResultField, FieldRenderer, enumLabeler,
|
|
3
|
-
import { baseCatalog, catalog, frameComponents, resultFieldAtPath, segmentsUnder, RESULT_ROOT, inputFieldAtPath } from '../chunk-
|
|
4
|
-
export { COMPONENT_NAMES, COMPONENT_RENDERINGS, COMPOSER_COMPONENTS, CUSTOM_COMPONENTS, DESIGNER_BRIEF_CONCEPT, DESIGNER_CATALOG_CONCEPT, FRAMES, FRAME_COMPONENTS, ICON_NAMES, INPUTS_ROOT, METRIC_FORMATS, PICKED_SHADCN, PRODUCT_COMPONENTS, PROMPT_HASH, REPAIR_ATTEMPTS, RESULT_COMPONENTS, RESULT_ROOT, absoluteHatchPath, catalog, componentNamesFor, designerCatalog, fieldAtSegments, findFixture, fixtureId, fixtureLabel, formatProblems, frameCatalog, inputBrief, inputFieldAtPath, isDelegatedInput, isDelegatedResult, joinPath, jsonlLines, layoutCheckProblems, layoutFits, layoutProblems, payloadToState, promptHashSubject, repeatBasePathOf, resultBrief, resultFieldAtPath, seedLine, segmentsUnder, specFromJsonl, specToJsonl, validateAgainstCatalog } from '../chunk-
|
|
2
|
+
import { cn, headingClass, checkedAccentClass, focusOutlineClass, useResolveUrl, panelSurfaceClass, panelFlatShadowClass, linkTextClass, actionShadowClass, panelRaisedShadowClass, fieldControlClass, useFieldPresentation, useFieldStrings, fieldLabel, ResultRoot, ResultField, FieldRenderer, enumLabeler, ToggleGroup, ToggleGroupItem, selectedFillStrongClass, Switch, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, selectedBorderClass, selectedFillClass, isThenable } from '../chunk-5RV3ASMO.js';
|
|
3
|
+
import { baseCatalog, catalog, frameComponents, shareAmount, INPUTS_ROOT, joinPath, resultFieldAtPath, segmentsUnder, RESULT_ROOT, inputFieldAtPath, definitionChain, unwrapped } from '../chunk-XYS5KCXB.js';
|
|
4
|
+
export { COMPONENT_NAMES, COMPONENT_RENDERINGS, COMPOSER_COMPONENTS, CUSTOM_COMPONENTS, DESIGNER_BRIEF_CONCEPT, DESIGNER_CATALOG_CONCEPT, FRAMES, FRAME_COMPONENTS, ICON_NAMES, INPUTS_ROOT, METRIC_FORMATS, PICKED_SHADCN, PRODUCT_COMPONENTS, PROMPT_HASH, REPAIR_ATTEMPTS, RESULT_COMPONENTS, RESULT_ROOT, absoluteHatchPath, catalog, componentNamesFor, designerCatalog, fieldAtSegments, findFixture, fixtureId, fixtureLabel, formatProblems, frameCatalog, inputBrief, inputFieldAtPath, isDelegatedInput, isDelegatedResult, joinPath, jsonlLines, layoutCheck, layoutCheckProblems, layoutFits, layoutProblems, payloadToState, promptHashSubject, repeatBasePathOf, resultBrief, resultFieldAtPath, seedLine, segmentsUnder, specFromJsonl, specToJsonl, validateAgainstCatalog } from '../chunk-XYS5KCXB.js';
|
|
5
5
|
import '../chunk-4VAO6BDE.js';
|
|
6
|
-
export { seedInputs } from '../chunk-
|
|
6
|
+
export { seedInputs } from '../chunk-AURDKAIC.js';
|
|
7
7
|
import '../chunk-L23R3JNQ.js';
|
|
8
8
|
import '../chunk-56WECFBD.js';
|
|
9
|
-
import '../chunk-
|
|
9
|
+
import '../chunk-CFBK7NO7.js';
|
|
10
10
|
import '../chunk-GHVVULHY.js';
|
|
11
11
|
import { readImageContent, viewableUrl, readDateContent } from '../chunk-QQK6Y55E.js';
|
|
12
12
|
export { brandManifestSchema } from '../chunk-QGFR57OH.js';
|
|
13
|
-
import '../chunk-
|
|
13
|
+
import '../chunk-PNNWNRPG.js';
|
|
14
14
|
import '../chunk-ZB4RYUKV.js';
|
|
15
15
|
import '../chunk-FABY3DEY.js';
|
|
16
16
|
import '../chunk-XCO6GTEC.js';
|
|
17
17
|
import '../chunk-E6BIXJ6C.js';
|
|
18
|
-
import '../chunk-
|
|
18
|
+
import { waitingFields } from '../chunk-TF4RTKLH.js';
|
|
19
19
|
import '../chunk-OD3VYXUY.js';
|
|
20
20
|
import '../chunk-WYH56SOZ.js';
|
|
21
|
-
import { hasOwnProp } from '../chunk-V3OV2XQT.js';
|
|
21
|
+
import { hasOwnProp, ownProp } from '../chunk-V3OV2XQT.js';
|
|
22
22
|
import '../chunk-GKV77RAS.js';
|
|
23
|
-
import * as
|
|
24
|
-
import { defineRegistry, useStateValue, useRepeatScope, useStateStore, useBoundProp, useFieldValidation, JSONUIProvider, Renderer } from '@json-render/react';
|
|
23
|
+
import * as React2 from 'react';
|
|
24
|
+
import { defineRegistry, useStateValue, useRepeatScope, useStateStore, useBoundProp, useFieldValidation, useOptionalValidation, JSONUIProvider, Renderer, useVisibility } from '@json-render/react';
|
|
25
25
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
26
|
+
import { builtInValidationFunctions, resolveRepeatStatePath, getByPath, evaluateVisibility, resolveElementProps, resolveRepeatItemStatePath } from '@json-render/core';
|
|
27
|
+
export { createStateStore } from '@json-render/core';
|
|
26
28
|
import { Clock, ArrowRight, Send, Pencil, Zap, Lightbulb, Truck, Package, Briefcase, Bookmark, Flag, Shield, Info, AlertCircle, CheckCircle2, ListChecks, Layers, Tag, Phone, Mail, Paperclip, Upload, FileText, BarChart3, TrendingUp, Hash, Percent, Receipt, Coins, Banknote, Wallet, Gift, Ticket, Image, Camera, Music, Coffee, Utensils, Star, Heart, Accessibility, Baby, User, Users, Hourglass, Calendar, Moon, Sun, Leaf, Mountain, Globe, Landmark, Building2, Home, Hotel, Ship, Car, Train, Plane, Route, MapPin, Map as Map$1, Compass, Rocket, Sparkles, ChevronDown } from 'lucide-react';
|
|
27
29
|
import * as TabsPrimitive from '@radix-ui/react-tabs';
|
|
28
|
-
export { createStateStore } from '@json-render/core';
|
|
29
30
|
|
|
30
|
-
var BrandContext =
|
|
31
|
+
var BrandContext = React2.createContext(null);
|
|
31
32
|
function BrandProvider({
|
|
32
33
|
manifest,
|
|
33
34
|
children
|
|
@@ -36,7 +37,7 @@ function BrandProvider({
|
|
|
36
37
|
return /* @__PURE__ */ jsx(BrandContext.Provider, { value: manifest, children });
|
|
37
38
|
}
|
|
38
39
|
function useBrand() {
|
|
39
|
-
const manifest =
|
|
40
|
+
const manifest = React2.useContext(BrandContext);
|
|
40
41
|
if (!manifest)
|
|
41
42
|
throw new Error(
|
|
42
43
|
"useBrand: no brand in scope. Pass `brand` to GenerativePage, or wrap the tree in BrandProvider."
|
|
@@ -47,7 +48,7 @@ var WEIGHTS = "400;500;600;700";
|
|
|
47
48
|
function useWebfont(webfont) {
|
|
48
49
|
const provider = webfont?.provider;
|
|
49
50
|
const family = webfont?.family;
|
|
50
|
-
|
|
51
|
+
React2.useEffect(() => {
|
|
51
52
|
if (!provider || !family) return;
|
|
52
53
|
const key = `${provider}:${family}`;
|
|
53
54
|
if (document.head.querySelector(`link[data-brand-webfont="${CSS.escape(key)}"]`)) return;
|
|
@@ -67,40 +68,414 @@ function useWebfont(webfont) {
|
|
|
67
68
|
document.head.appendChild(link);
|
|
68
69
|
}, [provider, family]);
|
|
69
70
|
}
|
|
70
|
-
var
|
|
71
|
-
var
|
|
71
|
+
var CHECK_WHEN = "checkedFieldWhen";
|
|
72
|
+
var WHEN_ENABLED = "checkedFieldEnabled";
|
|
73
|
+
var WHEN_TYPE = "checkedFieldType";
|
|
74
|
+
var CHECKED_FIELD_FUNCTIONS = {
|
|
75
|
+
[CHECK_WHEN]: (value, args) => {
|
|
76
|
+
if (args?.[WHEN_ENABLED] !== true) return true;
|
|
77
|
+
const type = args[WHEN_TYPE];
|
|
78
|
+
if (typeof type !== "string" || !hasOwnProp(builtInValidationFunctions, type)) return true;
|
|
79
|
+
return builtInValidationFunctions[type](value, args);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
function heldTo(check, enabled) {
|
|
83
|
+
return {
|
|
84
|
+
type: CHECK_WHEN,
|
|
85
|
+
message: check.message,
|
|
86
|
+
args: {
|
|
87
|
+
...check.args,
|
|
88
|
+
[WHEN_ENABLED]: { $cond: enabled, $then: true, $else: false },
|
|
89
|
+
[WHEN_TYPE]: check.type
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
var CheckedFields = class {
|
|
94
|
+
constructor() {
|
|
95
|
+
// One entry per mounted field, so two fields handed one config object are
|
|
96
|
+
// two entries, and one leaving does not take the other's checks with it.
|
|
97
|
+
this.byPath = /* @__PURE__ */ new Map();
|
|
98
|
+
// Every path the record speaks for: those it carries now, and those it has
|
|
99
|
+
// just emptied, whose old checks json-render may still read until it has
|
|
100
|
+
// drawn once with the emptied ones. The verdict on these is the record's.
|
|
101
|
+
this.told = /* @__PURE__ */ new Set();
|
|
102
|
+
// The emptied paths, each with the validation json-render handed over when
|
|
103
|
+
// the record emptied it. A later one has drawn with the emptied checks, so
|
|
104
|
+
// the path goes back to json-render: a host's control that registers its
|
|
105
|
+
// checks there directly is then judged by them.
|
|
106
|
+
this.emptied = /* @__PURE__ */ new Map();
|
|
107
|
+
this.validation = null;
|
|
108
|
+
}
|
|
109
|
+
/** Hands the record json-render's validation, and tells it what is already mounted. */
|
|
110
|
+
attach(validation) {
|
|
111
|
+
if (validation === this.validation) return;
|
|
112
|
+
const first = this.validation === null;
|
|
113
|
+
this.validation = validation;
|
|
114
|
+
for (const [path, at] of this.emptied) {
|
|
115
|
+
if (at === validation) continue;
|
|
116
|
+
this.emptied.delete(path);
|
|
117
|
+
this.told.delete(path);
|
|
118
|
+
}
|
|
119
|
+
if (first) for (const path of this.byPath.keys()) this.publish(path);
|
|
120
|
+
}
|
|
121
|
+
/** Enters one mounted field; what it returns leaves it again. */
|
|
122
|
+
enter(path, config, field = {}) {
|
|
123
|
+
const entries = this.byPath.get(path) ?? /* @__PURE__ */ new Set();
|
|
124
|
+
this.byPath.set(path, entries);
|
|
125
|
+
const entry = {
|
|
126
|
+
config,
|
|
127
|
+
reveal: field.reveal ?? (() => {
|
|
128
|
+
}),
|
|
129
|
+
focus: field.focus ?? (() => {
|
|
130
|
+
}),
|
|
131
|
+
element: field.element ?? (() => null)
|
|
132
|
+
};
|
|
133
|
+
entries.add(entry);
|
|
134
|
+
this.publish(path);
|
|
135
|
+
return () => {
|
|
136
|
+
entries.delete(entry);
|
|
137
|
+
if (entries.size === 0) this.byPath.delete(path);
|
|
138
|
+
this.publish(path);
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* The checks of every field mounted at `path`, combined, or none when no
|
|
143
|
+
* field is. A field's `enabled` condition holds its own checks and no
|
|
144
|
+
* other field's: json-render reads `enabled` once for a whole config, and
|
|
145
|
+
* compares two configs without it, so each check of a conditional config
|
|
146
|
+
* carries its condition itself (`CHECK_WHEN`).
|
|
147
|
+
*/
|
|
148
|
+
configFor(path) {
|
|
149
|
+
const entries = this.byPath.get(path);
|
|
150
|
+
if (!entries || entries.size === 0) return void 0;
|
|
151
|
+
const [first] = entries;
|
|
152
|
+
return {
|
|
153
|
+
checks: [...entries].flatMap(({ config }) => {
|
|
154
|
+
const checks = config.checks ?? [];
|
|
155
|
+
return config.enabled === void 0 ? checks : checks.map((check) => heldTo(check, config.enabled));
|
|
156
|
+
}),
|
|
157
|
+
...first?.config.validateOn ? { validateOn: first.config.validateOn } : {}
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Runs the checks of the page and answers whether they all pass; every
|
|
162
|
+
* check runs, so each failing field shows its message. When one fails, the
|
|
163
|
+
* person is taken to the first failing field in the page's order: the
|
|
164
|
+
* panels around it opened and the focus put on it, since a tab, a step or a
|
|
165
|
+
* section that is not open keeps its fields mounted and hidden.
|
|
166
|
+
*
|
|
167
|
+
* Each path is judged once, by one side. A path the record has carried is
|
|
168
|
+
* judged by the record's checks as it holds them now: json-render's own
|
|
169
|
+
* `validateAll` reads what it was told as of its provider's last render,
|
|
170
|
+
* which a press can beat by one task, so a field hidden or mounted the
|
|
171
|
+
* task before would be judged by checks it no longer carries, or not yet
|
|
172
|
+
* by those it does. A path the record does not carry, and has not just
|
|
173
|
+
* emptied, is a host's control that registered its checks with json-render
|
|
174
|
+
* directly (`useFieldValidation`), and json-render's verdict on it stands,
|
|
175
|
+
* a path the record once carried included.
|
|
176
|
+
*/
|
|
177
|
+
check(validation) {
|
|
178
|
+
const before = validation.fieldStates;
|
|
179
|
+
validation.validateAll();
|
|
180
|
+
const after = validation.fieldStates;
|
|
181
|
+
let pass = true;
|
|
182
|
+
for (const [path, state] of Object.entries(after)) {
|
|
183
|
+
if (state === before[path] || this.told.has(path)) continue;
|
|
184
|
+
if (state.result?.valid === false) pass = false;
|
|
185
|
+
}
|
|
186
|
+
const failing = [];
|
|
187
|
+
for (const path of this.told) {
|
|
188
|
+
const combined = this.configFor(path);
|
|
189
|
+
if (combined) {
|
|
190
|
+
if (!validation.validate(path, combined).valid) {
|
|
191
|
+
pass = false;
|
|
192
|
+
failing.push(...this.byPath.get(path) ?? []);
|
|
193
|
+
}
|
|
194
|
+
} else if (after[path] !== before[path]) {
|
|
195
|
+
validation.clear(path);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
const first = firstInPage(failing);
|
|
199
|
+
if (first) {
|
|
200
|
+
first.reveal();
|
|
201
|
+
first.focus();
|
|
202
|
+
}
|
|
203
|
+
return pass;
|
|
204
|
+
}
|
|
205
|
+
publish(path) {
|
|
206
|
+
if (!this.validation) return;
|
|
207
|
+
const config = this.configFor(path);
|
|
208
|
+
this.told.add(path);
|
|
209
|
+
if (config) this.emptied.delete(path);
|
|
210
|
+
else this.emptied.set(path, this.validation);
|
|
211
|
+
this.validation.registerField(path, config ?? { checks: [] });
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
var FOLLOWING = 4;
|
|
215
|
+
function firstInPage(entries) {
|
|
216
|
+
let first;
|
|
217
|
+
let firstElement = null;
|
|
218
|
+
for (const entry of entries) {
|
|
219
|
+
const element = entry.element();
|
|
220
|
+
if (!first) {
|
|
221
|
+
first = entry;
|
|
222
|
+
firstElement = element;
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
if (!element) continue;
|
|
226
|
+
if (!firstElement || element.compareDocumentPosition(firstElement) & FOLLOWING) {
|
|
227
|
+
first = entry;
|
|
228
|
+
firstElement = element;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return first;
|
|
232
|
+
}
|
|
233
|
+
var CheckedFieldsContext = React2.createContext(null);
|
|
234
|
+
var RevealContext = React2.createContext(null);
|
|
235
|
+
function RevealPanel({ open, children }) {
|
|
236
|
+
const outer = React2.useContext(RevealContext);
|
|
237
|
+
const latest = React2.useRef({ open, outer });
|
|
238
|
+
React2.useInsertionEffect(() => {
|
|
239
|
+
latest.current = { open, outer };
|
|
240
|
+
});
|
|
241
|
+
const reveal = React2.useCallback(() => {
|
|
242
|
+
latest.current.outer?.();
|
|
243
|
+
latest.current.open();
|
|
244
|
+
}, []);
|
|
245
|
+
return /* @__PURE__ */ jsx(RevealContext.Provider, { value: reveal, children });
|
|
246
|
+
}
|
|
247
|
+
function useCheckedField(path, config) {
|
|
248
|
+
const fields = React2.useContext(CheckedFieldsContext);
|
|
249
|
+
const field = useFieldValidation(path, fields ? void 0 : config);
|
|
250
|
+
const validation = useOptionalValidation();
|
|
251
|
+
const reveal = React2.useContext(RevealContext);
|
|
252
|
+
const element = React2.useRef(null);
|
|
253
|
+
const focusRef = React2.useCallback((node) => {
|
|
254
|
+
element.current = node;
|
|
255
|
+
}, []);
|
|
256
|
+
const [focusAsked, askFocus] = React2.useState(0);
|
|
257
|
+
React2.useEffect(() => {
|
|
258
|
+
if (focusAsked === 0) return;
|
|
259
|
+
const target = element.current;
|
|
260
|
+
if (!target) return;
|
|
261
|
+
target.focus({ preventScroll: true });
|
|
262
|
+
target.scrollIntoView?.({ block: "center" });
|
|
263
|
+
}, [focusAsked]);
|
|
264
|
+
const signature = config ? JSON.stringify(config) : "";
|
|
265
|
+
const latest = React2.useRef({ config, reveal });
|
|
266
|
+
React2.useInsertionEffect(() => {
|
|
267
|
+
latest.current = { config, reveal };
|
|
268
|
+
});
|
|
269
|
+
React2.useEffect(() => {
|
|
270
|
+
const entered = latest.current.config;
|
|
271
|
+
if (!fields || !path || !entered) return void 0;
|
|
272
|
+
return fields.enter(path, entered, {
|
|
273
|
+
reveal: () => latest.current.reveal?.(),
|
|
274
|
+
focus: () => askFocus((asked) => asked + 1),
|
|
275
|
+
element: () => element.current
|
|
276
|
+
});
|
|
277
|
+
}, [fields, path, signature]);
|
|
278
|
+
const fallback = field.validate;
|
|
279
|
+
const validate = React2.useCallback(() => {
|
|
280
|
+
const combined = fields?.configFor(path);
|
|
281
|
+
return validation && combined ? validation.validate(path, combined) : fallback();
|
|
282
|
+
}, [fields, path, validation, fallback]);
|
|
283
|
+
return { ...field, validate, focusRef };
|
|
284
|
+
}
|
|
285
|
+
var ReportingContext = React2.createContext(false);
|
|
286
|
+
function said(error) {
|
|
287
|
+
try {
|
|
288
|
+
return String(error);
|
|
289
|
+
} catch {
|
|
290
|
+
return "an error that cannot be written out";
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
function contentOf(value) {
|
|
294
|
+
const open = [];
|
|
295
|
+
let entries = 0;
|
|
296
|
+
try {
|
|
297
|
+
return JSON.stringify(value, function(_key, entry) {
|
|
298
|
+
if (++entries > MAX_CONTENT_ENTRIES) throw new RangeError("too large to compare");
|
|
299
|
+
while (open.length > 0 && open[open.length - 1] !== this) open.pop();
|
|
300
|
+
if (typeof entry === "bigint") return `${entry}n`;
|
|
301
|
+
if (typeof entry === "object" && entry !== null) {
|
|
302
|
+
if (open.includes(entry)) return "[cycle]";
|
|
303
|
+
open.push(entry);
|
|
304
|
+
}
|
|
305
|
+
return entry;
|
|
306
|
+
}) ?? "undefined";
|
|
307
|
+
} catch {
|
|
308
|
+
return "an input that cannot be written out";
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
var MAX_CONTENT_ENTRIES = 5e6;
|
|
312
|
+
function sameCue(a, b) {
|
|
313
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
314
|
+
return a.length === b.length && a.every((entry, index) => Object.is(entry, b[index]));
|
|
315
|
+
}
|
|
316
|
+
return Object.is(a, b);
|
|
317
|
+
}
|
|
318
|
+
var ElementBoundary = class extends React2.Component {
|
|
72
319
|
constructor(props) {
|
|
73
320
|
super(props);
|
|
74
|
-
this.state = { failed: false, error: void 0
|
|
321
|
+
this.state = { failed: false, error: void 0 };
|
|
75
322
|
}
|
|
76
323
|
static getDerivedStateFromError(error) {
|
|
77
324
|
return { failed: true, error };
|
|
78
325
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
326
|
+
/** What the element renders from, as text; total, since it reads a model's layout and the store. */
|
|
327
|
+
input() {
|
|
328
|
+
try {
|
|
329
|
+
return contentOf(this.props.inputOf ? this.props.inputOf() : this.props.resetOn);
|
|
330
|
+
} catch (error) {
|
|
331
|
+
return `the input could not be read: ${said(error)}`;
|
|
332
|
+
}
|
|
82
333
|
}
|
|
83
334
|
componentDidCatch(error, info) {
|
|
84
|
-
if (
|
|
335
|
+
if (this.props.loading) {
|
|
336
|
+
this.failedOn = void 0;
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
this.failedOn = this.input();
|
|
85
340
|
const componentStack = info.componentStack ?? void 0;
|
|
86
|
-
this.props.
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
341
|
+
if (this.props.reporting) {
|
|
342
|
+
this.props.report.current?.(error, {
|
|
343
|
+
type: this.props.type,
|
|
344
|
+
...componentStack ? { componentStack } : {}
|
|
345
|
+
});
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
if (!this.props.root) {
|
|
349
|
+
console.error(
|
|
350
|
+
`[json-render] Rendering error in <${this.props.type}>:`,
|
|
351
|
+
error,
|
|
352
|
+
componentStack
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
componentDidUpdate(previous, previousState) {
|
|
357
|
+
if (!this.state.failed || !previousState.failed) return;
|
|
358
|
+
const streamEnded = previous.loading === true && !this.props.loading;
|
|
359
|
+
if (streamEnded || this.inputChanged(previous)) {
|
|
360
|
+
this.failedOn = void 0;
|
|
361
|
+
this.setState({ failed: false, error: void 0 });
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
/** Whether what the element renders from is no longer what it failed on. */
|
|
365
|
+
inputChanged(previous) {
|
|
366
|
+
if (sameCue(this.props.resetOn, previous.resetOn)) return false;
|
|
367
|
+
if (this.props.loading || this.failedOn === void 0) return true;
|
|
368
|
+
return !Object.is(this.input(), this.failedOn);
|
|
90
369
|
}
|
|
91
|
-
// Whether
|
|
92
|
-
//
|
|
93
|
-
//
|
|
94
|
-
//
|
|
95
|
-
//
|
|
96
|
-
//
|
|
97
|
-
// once, as if this one were not here.
|
|
370
|
+
// Whether the root throws the error on is decided as it renders its
|
|
371
|
+
// failure, from whether the host passes a handler in this very render:
|
|
372
|
+
// decided later, it cost a blank commit and a second record of the same
|
|
373
|
+
// error, and decided from the ref, it read the previous render's callback.
|
|
374
|
+
// No host to tell: the root's error goes on, in the same render, to the
|
|
375
|
+
// host's boundary around the page, which records it once.
|
|
98
376
|
render() {
|
|
99
377
|
if (!this.state.failed) return this.props.children;
|
|
100
|
-
if (!this.props.reporting) throw this.state.error;
|
|
378
|
+
if (this.props.root && !this.props.reporting && !this.props.loading) throw this.state.error;
|
|
101
379
|
return null;
|
|
102
380
|
}
|
|
103
381
|
};
|
|
382
|
+
function resolvedOf(element, ctx) {
|
|
383
|
+
if (!element) return void 0;
|
|
384
|
+
try {
|
|
385
|
+
return {
|
|
386
|
+
props: resolveElementProps(element.props ?? {}, ctx),
|
|
387
|
+
visible: element.visible === void 0 ? true : evaluateVisibility(element.visible, ctx)
|
|
388
|
+
};
|
|
389
|
+
} catch (error) {
|
|
390
|
+
return `throws: ${said(error)}`;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
function childElementOf(node) {
|
|
394
|
+
if (!React2.isValidElement(node)) return void 0;
|
|
395
|
+
const { element, elementKey } = node.props;
|
|
396
|
+
if (typeof elementKey !== "string") return void 0;
|
|
397
|
+
return typeof element === "object" && element !== null ? element : void 0;
|
|
398
|
+
}
|
|
399
|
+
function repeatOf(node) {
|
|
400
|
+
if (!React2.isValidElement(node)) return void 0;
|
|
401
|
+
const { element, spec, elementKey, itemFilter } = node.props;
|
|
402
|
+
if (elementKey !== void 0 || element?.repeat === void 0) return void 0;
|
|
403
|
+
const elements = spec?.elements;
|
|
404
|
+
if (typeof elements !== "object" || elements === null || !Array.isArray(element.children)) {
|
|
405
|
+
return void 0;
|
|
406
|
+
}
|
|
407
|
+
return { keys: element.children, elements, itemFilter };
|
|
408
|
+
}
|
|
409
|
+
function inputOfElement(props, visibility, scope) {
|
|
410
|
+
const element = props.element;
|
|
411
|
+
const state = visibility.stateModel;
|
|
412
|
+
const ctx = {
|
|
413
|
+
...visibility,
|
|
414
|
+
...scope ? { repeatItem: scope.item, repeatIndex: scope.index, repeatBasePath: scope.basePath } : {}
|
|
415
|
+
};
|
|
416
|
+
const statePath = element?.repeat?.statePath;
|
|
417
|
+
let list;
|
|
418
|
+
let listPath;
|
|
419
|
+
if (statePath !== void 0) {
|
|
420
|
+
try {
|
|
421
|
+
listPath = resolveRepeatStatePath(statePath, scope?.basePath);
|
|
422
|
+
list = listPath === void 0 ? void 0 : getByPath(state, listPath);
|
|
423
|
+
} catch (error) {
|
|
424
|
+
list = `throws: ${said(error)}`;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
const repeated = (repeat) => {
|
|
428
|
+
if (listPath === void 0 || !Array.isArray(list)) return null;
|
|
429
|
+
const path = listPath;
|
|
430
|
+
return list.map((item, index) => {
|
|
431
|
+
const itemCtx = {
|
|
432
|
+
...visibility,
|
|
433
|
+
repeatItem: item,
|
|
434
|
+
repeatIndex: index,
|
|
435
|
+
repeatBasePath: resolveRepeatItemStatePath(path, index)
|
|
436
|
+
};
|
|
437
|
+
if (repeat.itemFilter !== void 0) {
|
|
438
|
+
try {
|
|
439
|
+
if (!evaluateVisibility(repeat.itemFilter, itemCtx)) return null;
|
|
440
|
+
} catch (error) {
|
|
441
|
+
return `throws: ${said(error)}`;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
return repeat.keys.map((key) => {
|
|
445
|
+
const child = typeof key === "string" ? ownProp(repeat.elements, key) : void 0;
|
|
446
|
+
return child ? { element: child, resolved: resolvedOf(child, itemCtx) } : null;
|
|
447
|
+
});
|
|
448
|
+
});
|
|
449
|
+
};
|
|
450
|
+
const under = (nodes) => React2.Children.toArray(nodes).map((node) => {
|
|
451
|
+
const repeat = repeatOf(node);
|
|
452
|
+
if (repeat) return { repeated: repeated(repeat) };
|
|
453
|
+
const child = childElementOf(node);
|
|
454
|
+
return child ? { element: child, resolved: resolvedOf(child, ctx) } : null;
|
|
455
|
+
});
|
|
456
|
+
const slots = typeof props.slots === "object" && props.slots !== null ? Object.fromEntries(Object.entries(props.slots).map(([name, nodes]) => [name, under(nodes)])) : void 0;
|
|
457
|
+
return { props: element?.props, list, children: under(props.children), slots };
|
|
458
|
+
}
|
|
459
|
+
function inputOfRoot(spec, visibility) {
|
|
460
|
+
const root = spec?.elements?.[spec.root];
|
|
461
|
+
return { spec, root: resolvedOf(root, visibility) };
|
|
462
|
+
}
|
|
463
|
+
function RootBoundary(props) {
|
|
464
|
+
const { ctx } = useVisibility();
|
|
465
|
+
return /* @__PURE__ */ jsx(
|
|
466
|
+
ElementBoundary,
|
|
467
|
+
{
|
|
468
|
+
type: props.type,
|
|
469
|
+
report: props.report,
|
|
470
|
+
reporting: props.reporting,
|
|
471
|
+
loading: props.loading,
|
|
472
|
+
resetOn: [props.spec, ctx],
|
|
473
|
+
inputOf: () => inputOfRoot(props.spec, ctx),
|
|
474
|
+
root: true,
|
|
475
|
+
children: props.children
|
|
476
|
+
}
|
|
477
|
+
);
|
|
478
|
+
}
|
|
104
479
|
function reportingRegistry(registry, report, made) {
|
|
105
480
|
const wrapped = {};
|
|
106
481
|
for (const [type, Renderer2] of Object.entries(registry)) {
|
|
@@ -110,13 +485,90 @@ function reportingRegistry(registry, report, made) {
|
|
|
110
485
|
continue;
|
|
111
486
|
}
|
|
112
487
|
const Component2 = Renderer2;
|
|
113
|
-
const Reported = (props) =>
|
|
488
|
+
const Reported = (props) => {
|
|
489
|
+
const reporting = React2.useContext(ReportingContext);
|
|
490
|
+
const { ctx } = useVisibility();
|
|
491
|
+
const scope = useRepeatScope();
|
|
492
|
+
return /* @__PURE__ */ jsx(
|
|
493
|
+
ElementBoundary,
|
|
494
|
+
{
|
|
495
|
+
type,
|
|
496
|
+
report,
|
|
497
|
+
reporting,
|
|
498
|
+
loading: props.loading === true,
|
|
499
|
+
resetOn: [props.element, props.children, props.slots, ctx, scope],
|
|
500
|
+
inputOf: () => inputOfElement(props, ctx, scope),
|
|
501
|
+
children: /* @__PURE__ */ jsx(Component2, { ...props })
|
|
502
|
+
}
|
|
503
|
+
);
|
|
504
|
+
};
|
|
114
505
|
Reported.displayName = `Reported(${type})`;
|
|
115
506
|
made.set(type, { renderer: Renderer2, wrapper: Reported });
|
|
116
507
|
wrapped[type] = Reported;
|
|
117
508
|
}
|
|
118
509
|
return wrapped;
|
|
119
510
|
}
|
|
511
|
+
function placedInputs(spec) {
|
|
512
|
+
const placed = /* @__PURE__ */ new Map();
|
|
513
|
+
const elements = spec?.elements;
|
|
514
|
+
if (!isRecord(elements) || typeof spec?.root !== "string") return placed;
|
|
515
|
+
const seen = /* @__PURE__ */ new Set();
|
|
516
|
+
const pending = [spec.root];
|
|
517
|
+
while (pending.length > 0) {
|
|
518
|
+
const key = pending.pop();
|
|
519
|
+
if (seen.has(key)) continue;
|
|
520
|
+
seen.add(key);
|
|
521
|
+
const element = ownProp(elements, key);
|
|
522
|
+
if (!isRecord(element)) continue;
|
|
523
|
+
const props = isRecord(element.props) ? element.props : {};
|
|
524
|
+
place(placed, [...repeatedList(element.repeat), ...inputPathsOf(element.type, props)], props);
|
|
525
|
+
pending.push(...[...keysOf(element.children), ...slotKeys(element.slots)].reverse());
|
|
526
|
+
}
|
|
527
|
+
return placed;
|
|
528
|
+
}
|
|
529
|
+
function place(placed, paths, props) {
|
|
530
|
+
const label = typeof props.label === "string" ? props.label.trim() : "";
|
|
531
|
+
for (const path of paths) {
|
|
532
|
+
const known = placed.get(path);
|
|
533
|
+
if (!known) placed.set(path, { order: placed.size, ...label ? { label } : {} });
|
|
534
|
+
else if (known.label === void 0 && label) known.label = label;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
function inputPathsOf(type, props) {
|
|
538
|
+
const paths = [];
|
|
539
|
+
if (type === "MthdsField" && typeof props.path === "string") paths.push(props.path);
|
|
540
|
+
for (const value of Object.values(props)) {
|
|
541
|
+
if (isRecord(value) && typeof value.$bindState === "string") paths.push(value.$bindState);
|
|
542
|
+
}
|
|
543
|
+
return paths.flatMap(inputPath);
|
|
544
|
+
}
|
|
545
|
+
function repeatedList(repeat) {
|
|
546
|
+
return isRecord(repeat) && typeof repeat.statePath === "string" ? inputPath(repeat.statePath) : [];
|
|
547
|
+
}
|
|
548
|
+
function inputPath(path) {
|
|
549
|
+
const segments = segmentsUnder(INPUTS_ROOT, path);
|
|
550
|
+
return segments && segments.length > 0 ? [joinPath(INPUTS_ROOT, ...segments)] : [];
|
|
551
|
+
}
|
|
552
|
+
function keysOf(value) {
|
|
553
|
+
return Array.isArray(value) ? value.filter((key) => typeof key === "string") : [];
|
|
554
|
+
}
|
|
555
|
+
function slotKeys(slots) {
|
|
556
|
+
return isRecord(slots) ? Object.values(slots).flatMap(keysOf) : [];
|
|
557
|
+
}
|
|
558
|
+
function isRecord(value) {
|
|
559
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
560
|
+
}
|
|
561
|
+
var PlacedInputsContext = React2.createContext(/* @__PURE__ */ new Map());
|
|
562
|
+
function PlacedInputsProvider({
|
|
563
|
+
spec,
|
|
564
|
+
children
|
|
565
|
+
}) {
|
|
566
|
+
const placed = React2.useMemo(() => placedInputs(spec), [spec]);
|
|
567
|
+
return /* @__PURE__ */ jsx(PlacedInputsContext.Provider, { value: placed, children });
|
|
568
|
+
}
|
|
569
|
+
function usePlacedInputs() {
|
|
570
|
+
return React2.useContext(PlacedInputsContext);
|
|
571
|
+
}
|
|
120
572
|
var CONTAINER = "mx-auto w-full max-w-6xl px-6 sm:px-8";
|
|
121
573
|
function BrandBar({ app, links, tag }) {
|
|
122
574
|
const brand = useBrand();
|
|
@@ -147,7 +599,10 @@ function BrandBar({ app, links, tag }) {
|
|
|
147
599
|
{
|
|
148
600
|
href: "#",
|
|
149
601
|
onClick: (event) => event.preventDefault(),
|
|
150
|
-
className:
|
|
602
|
+
className: cn(
|
|
603
|
+
"rounded-sm text-sm text-muted-foreground transition-colors hover:text-foreground",
|
|
604
|
+
focusOutlineClass
|
|
605
|
+
),
|
|
151
606
|
children: link
|
|
152
607
|
},
|
|
153
608
|
`${index}-${link}`
|
|
@@ -169,39 +624,72 @@ function BrandBar({ app, links, tag }) {
|
|
|
169
624
|
}
|
|
170
625
|
|
|
171
626
|
// src/generative/declared-props.ts
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
627
|
+
var factsBySchema = /* @__PURE__ */ new WeakMap();
|
|
628
|
+
function factsOf(schema) {
|
|
629
|
+
const known = factsBySchema.get(schema);
|
|
630
|
+
if (known) return known;
|
|
631
|
+
const chain = definitionChain(schema);
|
|
632
|
+
const def = chain[chain.length - 1];
|
|
633
|
+
const acceptsNull = schema.safeParse(null).success;
|
|
634
|
+
const acceptsUndefined = schema.safeParse(void 0).success;
|
|
635
|
+
const absent = acceptsNull ? null : acceptsUndefined ? void 0 : def?.type === "string" ? "" : def?.type === "array" ? [] : void 0;
|
|
636
|
+
const facts = { def, plain: plainType(chain), acceptsNull, acceptsUndefined, absent };
|
|
637
|
+
factsBySchema.set(schema, facts);
|
|
638
|
+
return facts;
|
|
639
|
+
}
|
|
640
|
+
var PASSING_WRAPPERS = /* @__PURE__ */ new Set([
|
|
641
|
+
"optional",
|
|
642
|
+
"nullable",
|
|
643
|
+
"default",
|
|
644
|
+
"prefault",
|
|
645
|
+
"readonly",
|
|
646
|
+
"catch",
|
|
647
|
+
"nonoptional"
|
|
648
|
+
]);
|
|
649
|
+
function plainType(chain) {
|
|
650
|
+
const def = chain[chain.length - 1];
|
|
651
|
+
if (!def || def.format !== void 0) return void 0;
|
|
652
|
+
if (chain.some((link) => link.checks !== void 0 && link.checks.length > 0)) return void 0;
|
|
653
|
+
if (!chain.slice(0, -1).every((link) => PASSING_WRAPPERS.has(link.type))) return void 0;
|
|
654
|
+
return def.type === "string" || def.type === "boolean" || def.type === "number" ? def.type : void 0;
|
|
655
|
+
}
|
|
656
|
+
function plainlyConforms(plain, value) {
|
|
657
|
+
if (plain === "number") return typeof value === "number" && Number.isFinite(value);
|
|
658
|
+
return plain !== void 0 && typeof value === plain;
|
|
659
|
+
}
|
|
660
|
+
function writtenOut(schema, value) {
|
|
661
|
+
if (typeof value !== "number" && typeof value !== "boolean") return void 0;
|
|
662
|
+
const text = String(value);
|
|
663
|
+
return schema.safeParse(text).success ? text : void 0;
|
|
664
|
+
}
|
|
665
|
+
function keptEntries(schema, element, entries, absent) {
|
|
666
|
+
const textItems = unwrapped(element)?.type === "string";
|
|
667
|
+
const kept = entries.flatMap((entry) => {
|
|
668
|
+
if (element.safeParse(entry).success) return [entry];
|
|
669
|
+
const text = textItems ? writtenOut(element, entry) : void 0;
|
|
670
|
+
return text === void 0 ? [] : [text];
|
|
671
|
+
});
|
|
672
|
+
return schema.safeParse(kept).success ? kept : absent;
|
|
190
673
|
}
|
|
674
|
+
var conformedBySchema = /* @__PURE__ */ new WeakMap();
|
|
191
675
|
function conformValue(schema, value) {
|
|
192
|
-
|
|
193
|
-
|
|
676
|
+
const facts = factsOf(schema);
|
|
677
|
+
if (value === void 0) return facts.acceptsUndefined ? value : facts.absent;
|
|
678
|
+
if (value === null) return facts.acceptsNull ? value : facts.absent;
|
|
679
|
+
if (typeof value !== "object") {
|
|
680
|
+
if (plainlyConforms(facts.plain, value) || schema.safeParse(value).success) return value;
|
|
681
|
+
if (facts.def?.type === "string") return writtenOut(schema, value) ?? facts.absent;
|
|
682
|
+
return facts.absent;
|
|
194
683
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
684
|
+
let byValue = conformedBySchema.get(schema);
|
|
685
|
+
if (!byValue) {
|
|
686
|
+
byValue = /* @__PURE__ */ new WeakMap();
|
|
687
|
+
conformedBySchema.set(schema, byValue);
|
|
199
688
|
}
|
|
200
|
-
if (
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
return absentValueOf(schema);
|
|
689
|
+
if (byValue.has(value)) return byValue.get(value);
|
|
690
|
+
const held = schema.safeParse(value).success ? value : facts.def?.type === "array" && facts.def.element && Array.isArray(value) ? keptEntries(schema, facts.def.element, value, facts.absent) : facts.absent;
|
|
691
|
+
byValue.set(value, held);
|
|
692
|
+
return held;
|
|
205
693
|
}
|
|
206
694
|
function conformProps(shape, props, asWritten = []) {
|
|
207
695
|
let conformed;
|
|
@@ -229,18 +717,13 @@ function withDeclaredProps(definitions, renderers, asWritten = {}) {
|
|
|
229
717
|
}
|
|
230
718
|
function textOf(value) {
|
|
231
719
|
if (value === void 0 || value === null) return "";
|
|
232
|
-
if (
|
|
233
|
-
|
|
234
|
-
return String(value);
|
|
235
|
-
} catch {
|
|
236
|
-
try {
|
|
237
|
-
return JSON.stringify(value) ?? "";
|
|
238
|
-
} catch {
|
|
239
|
-
return "";
|
|
240
|
-
}
|
|
720
|
+
if (Array.isArray(value)) {
|
|
721
|
+
return value.map(textOf).filter((text) => text !== "").join(", ");
|
|
241
722
|
}
|
|
723
|
+
if (typeof value === "object") return "";
|
|
724
|
+
return String(value);
|
|
242
725
|
}
|
|
243
|
-
var FrameHostContext =
|
|
726
|
+
var FrameHostContext = React2.createContext({});
|
|
244
727
|
function FrameHostProvider({
|
|
245
728
|
host,
|
|
246
729
|
children
|
|
@@ -248,25 +731,115 @@ function FrameHostProvider({
|
|
|
248
731
|
return /* @__PURE__ */ jsx(FrameHostContext.Provider, { value: host, children });
|
|
249
732
|
}
|
|
250
733
|
function useFrameHost() {
|
|
251
|
-
return
|
|
734
|
+
return React2.useContext(FrameHostContext);
|
|
252
735
|
}
|
|
253
|
-
|
|
736
|
+
|
|
737
|
+
// src/generative/format.ts
|
|
738
|
+
var LAYOUT_LOCALE = "en-GB";
|
|
739
|
+
var NUMBER_OPTIONS = {
|
|
740
|
+
// Grouped, with the places it has up to two, never padded.
|
|
741
|
+
grouped: { maximumFractionDigits: 2 },
|
|
742
|
+
integer: { maximumFractionDigits: 0 },
|
|
743
|
+
decimal: { minimumFractionDigits: 2, maximumFractionDigits: 2 },
|
|
744
|
+
compact: { notation: "compact", maximumFractionDigits: 1 },
|
|
745
|
+
// As written: every place, and no grouping, so a year or an id reads as itself.
|
|
746
|
+
plain: { maximumFractionDigits: 20, useGrouping: false }
|
|
747
|
+
};
|
|
748
|
+
var numbers = /* @__PURE__ */ new Map();
|
|
749
|
+
function formatNumber(value, style = "grouped") {
|
|
750
|
+
let format = numbers.get(style);
|
|
751
|
+
if (!format) {
|
|
752
|
+
format = new Intl.NumberFormat(LAYOUT_LOCALE, NUMBER_OPTIONS[style]);
|
|
753
|
+
numbers.set(style, format);
|
|
754
|
+
}
|
|
755
|
+
return format.format(value);
|
|
756
|
+
}
|
|
757
|
+
var currencies = /* @__PURE__ */ new Map();
|
|
758
|
+
var KNOWN_CURRENCIES = (() => {
|
|
759
|
+
try {
|
|
760
|
+
return typeof Intl.supportedValuesOf === "function" ? new Set(Intl.supportedValuesOf("currency")) : null;
|
|
761
|
+
} catch {
|
|
762
|
+
return null;
|
|
763
|
+
}
|
|
764
|
+
})();
|
|
765
|
+
function currencyFormat(code) {
|
|
766
|
+
if (!currencies.has(code)) {
|
|
767
|
+
if (KNOWN_CURRENCIES && !KNOWN_CURRENCIES.has(code)) {
|
|
768
|
+
currencies.set(code, null);
|
|
769
|
+
return null;
|
|
770
|
+
}
|
|
771
|
+
let money;
|
|
772
|
+
try {
|
|
773
|
+
money = {
|
|
774
|
+
whole: new Intl.NumberFormat(LAYOUT_LOCALE, {
|
|
775
|
+
style: "currency",
|
|
776
|
+
currency: code,
|
|
777
|
+
minimumFractionDigits: 0,
|
|
778
|
+
maximumFractionDigits: 0
|
|
779
|
+
}),
|
|
780
|
+
fractional: new Intl.NumberFormat(LAYOUT_LOCALE, { style: "currency", currency: code })
|
|
781
|
+
};
|
|
782
|
+
} catch {
|
|
783
|
+
money = null;
|
|
784
|
+
}
|
|
785
|
+
currencies.set(code, money);
|
|
786
|
+
}
|
|
787
|
+
return currencies.get(code);
|
|
788
|
+
}
|
|
789
|
+
function formatAmount(value, unit) {
|
|
790
|
+
if (unit && /^[A-Z]{3}$/.test(unit)) {
|
|
791
|
+
const money = currencyFormat(unit);
|
|
792
|
+
if (money) {
|
|
793
|
+
const fraction = money.fractional.formatToParts(value).find((p) => p.type === "fraction");
|
|
794
|
+
const whole = fraction === void 0 || /^0+$/.test(fraction.value);
|
|
795
|
+
return (whole ? money.whole : money.fractional).format(value);
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
const written = formatNumber(value);
|
|
799
|
+
return unit ? `${written} ${unit}` : written;
|
|
800
|
+
}
|
|
801
|
+
var DAY_OPTIONS = {
|
|
802
|
+
long: { weekday: "long", day: "numeric", month: "long", year: "numeric", timeZone: "UTC" },
|
|
803
|
+
short: { day: "numeric", month: "short", year: "numeric", timeZone: "UTC" },
|
|
804
|
+
weekday: { weekday: "short", day: "numeric", month: "long", timeZone: "UTC" }
|
|
805
|
+
};
|
|
806
|
+
var days = /* @__PURE__ */ new Map();
|
|
807
|
+
function formatDay(value, style = "long") {
|
|
808
|
+
const written = readDateContent(value)?.date;
|
|
809
|
+
const day = written === void 0 ? null : /^\d{4}-\d{2}-\d{2}/.exec(written);
|
|
810
|
+
if (!day) return void 0;
|
|
811
|
+
const date = /* @__PURE__ */ new Date(`${day[0]}T12:00:00Z`);
|
|
812
|
+
if (Number.isNaN(date.getTime()) || date.toISOString().slice(0, 10) !== day[0]) {
|
|
813
|
+
return void 0;
|
|
814
|
+
}
|
|
815
|
+
let format = days.get(style);
|
|
816
|
+
if (!format) {
|
|
817
|
+
format = new Intl.DateTimeFormat(LAYOUT_LOCALE, DAY_OPTIONS[style]);
|
|
818
|
+
days.set(style, format);
|
|
819
|
+
}
|
|
820
|
+
return format.format(date);
|
|
821
|
+
}
|
|
822
|
+
function useBoundField(literal, binding, empty, { checks, validateOn }, id) {
|
|
254
823
|
const [boundValue, setBoundValue] = useBoundProp(literal ?? void 0, binding);
|
|
255
|
-
const [localValue, setLocalValue] =
|
|
824
|
+
const [localValue, setLocalValue] = React2.useState(literal ?? empty);
|
|
256
825
|
const isBound = Boolean(binding);
|
|
257
826
|
const hasValidation = Boolean(binding && checks?.length);
|
|
258
827
|
const when = validateOn ?? "change";
|
|
259
|
-
const { errors, validate } =
|
|
828
|
+
const { errors, validate, focusRef } = useCheckedField(
|
|
260
829
|
binding ?? "",
|
|
261
830
|
hasValidation ? { checks: checks ?? [], validateOn: when } : void 0
|
|
262
831
|
);
|
|
832
|
+
const error = errors[0];
|
|
263
833
|
return {
|
|
264
834
|
value: isBound ? boundValue ?? empty : localValue,
|
|
265
835
|
setValue: (next) => {
|
|
266
836
|
if (isBound) setBoundValue(next);
|
|
267
837
|
else setLocalValue(next);
|
|
268
838
|
},
|
|
269
|
-
error
|
|
839
|
+
error,
|
|
840
|
+
errorId: `${id}-error`,
|
|
841
|
+
describedBy: error ? `${id}-error` : void 0,
|
|
842
|
+
focusRef,
|
|
270
843
|
validateOnChange: () => {
|
|
271
844
|
if (hasValidation && when === "change") validate();
|
|
272
845
|
},
|
|
@@ -276,8 +849,8 @@ function useBoundField(literal, binding, empty, { checks, validateOn }) {
|
|
|
276
849
|
};
|
|
277
850
|
}
|
|
278
851
|
var LABEL = "block text-sm leading-none font-medium";
|
|
279
|
-
function FieldError({ message }) {
|
|
280
|
-
return message ? /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: message }) : null;
|
|
852
|
+
function FieldError({ id, message }) {
|
|
853
|
+
return message ? /* @__PURE__ */ jsx("p", { id, className: "text-sm text-destructive", children: message }) : null;
|
|
281
854
|
}
|
|
282
855
|
function pickKey(table, key, fallback) {
|
|
283
856
|
return key != null && hasOwnProp(table, key) ? key : fallback;
|
|
@@ -338,19 +911,21 @@ function Stack({
|
|
|
338
911
|
children
|
|
339
912
|
}) {
|
|
340
913
|
const horizontal = props.direction === "horizontal";
|
|
341
|
-
|
|
914
|
+
const column = !horizontal && props.align === "center";
|
|
915
|
+
const stack = /* @__PURE__ */ jsx(
|
|
342
916
|
"div",
|
|
343
917
|
{
|
|
344
918
|
className: cn(
|
|
345
919
|
"flex",
|
|
346
920
|
horizontal ? "flex-row" : "flex-col",
|
|
347
921
|
pick(GAP, props.gap, "md"),
|
|
348
|
-
pick(ALIGN, props.align, horizontal ? "start" : "stretch"),
|
|
922
|
+
column ? "w-fit max-w-full grow items-stretch" : pick(ALIGN, props.align, horizontal ? "start" : "stretch"),
|
|
349
923
|
props.justify ? pick(JUSTIFY, props.justify, "start") : void 0
|
|
350
924
|
),
|
|
351
925
|
children
|
|
352
926
|
}
|
|
353
927
|
);
|
|
928
|
+
return column ? /* @__PURE__ */ jsx("div", { className: "flex flex-col items-center", children: stack }) : stack;
|
|
354
929
|
}
|
|
355
930
|
var COLUMNS = {
|
|
356
931
|
1: "grid-cols-1",
|
|
@@ -384,9 +959,14 @@ function Collapsible({
|
|
|
384
959
|
props,
|
|
385
960
|
children
|
|
386
961
|
}) {
|
|
962
|
+
const details = React2.useRef(null);
|
|
963
|
+
const open = React2.useCallback(() => {
|
|
964
|
+
if (details.current) details.current.open = true;
|
|
965
|
+
}, []);
|
|
387
966
|
return /* @__PURE__ */ jsxs(
|
|
388
967
|
"details",
|
|
389
968
|
{
|
|
969
|
+
ref: details,
|
|
390
970
|
className: "rounded-md border border-border",
|
|
391
971
|
open: props.defaultOpen ?? false,
|
|
392
972
|
"data-slot": "collapsible",
|
|
@@ -401,7 +981,7 @@ function Collapsible({
|
|
|
401
981
|
}
|
|
402
982
|
)
|
|
403
983
|
] }),
|
|
404
|
-
/* @__PURE__ */ jsx("div", { className: "border-t border-border px-4 py-3", children })
|
|
984
|
+
/* @__PURE__ */ jsx("div", { className: "border-t border-border px-4 py-3", children: /* @__PURE__ */ jsx(RevealPanel, { open, children }) })
|
|
405
985
|
]
|
|
406
986
|
}
|
|
407
987
|
);
|
|
@@ -524,7 +1104,7 @@ function Progress({
|
|
|
524
1104
|
] });
|
|
525
1105
|
}
|
|
526
1106
|
function useControlId(name) {
|
|
527
|
-
return `jr-${name}-${
|
|
1107
|
+
return `jr-${name}-${React2.useId()}`;
|
|
528
1108
|
}
|
|
529
1109
|
function Input({
|
|
530
1110
|
props,
|
|
@@ -532,7 +1112,7 @@ function Input({
|
|
|
532
1112
|
emit
|
|
533
1113
|
}) {
|
|
534
1114
|
const id = useControlId(props.name);
|
|
535
|
-
const field = useBoundField(props.value, bindings?.value, "", props);
|
|
1115
|
+
const field = useBoundField(props.value, bindings?.value, "", props, id);
|
|
536
1116
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
537
1117
|
/* @__PURE__ */ jsx("label", { htmlFor: id, className: LABEL, children: props.label }),
|
|
538
1118
|
/* @__PURE__ */ jsx(
|
|
@@ -544,7 +1124,9 @@ function Input({
|
|
|
544
1124
|
className: cn(fieldControlClass, "min-h-11 px-3 py-2"),
|
|
545
1125
|
placeholder: props.placeholder ?? void 0,
|
|
546
1126
|
value: field.value,
|
|
1127
|
+
ref: field.focusRef,
|
|
547
1128
|
"aria-invalid": field.error ? true : void 0,
|
|
1129
|
+
"aria-describedby": field.describedBy,
|
|
548
1130
|
onChange: (event) => {
|
|
549
1131
|
field.setValue(event.target.value);
|
|
550
1132
|
field.validateOnChange();
|
|
@@ -556,7 +1138,7 @@ function Input({
|
|
|
556
1138
|
}
|
|
557
1139
|
}
|
|
558
1140
|
),
|
|
559
|
-
/* @__PURE__ */ jsx(FieldError, { message: field.error })
|
|
1141
|
+
/* @__PURE__ */ jsx(FieldError, { id: field.errorId, message: field.error })
|
|
560
1142
|
] });
|
|
561
1143
|
}
|
|
562
1144
|
function Textarea({
|
|
@@ -564,7 +1146,7 @@ function Textarea({
|
|
|
564
1146
|
bindings
|
|
565
1147
|
}) {
|
|
566
1148
|
const id = useControlId(props.name);
|
|
567
|
-
const field = useBoundField(props.value, bindings?.value, "", props);
|
|
1149
|
+
const field = useBoundField(props.value, bindings?.value, "", props, id);
|
|
568
1150
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
569
1151
|
/* @__PURE__ */ jsx("label", { htmlFor: id, className: LABEL, children: props.label }),
|
|
570
1152
|
/* @__PURE__ */ jsx(
|
|
@@ -576,7 +1158,9 @@ function Textarea({
|
|
|
576
1158
|
className: cn(fieldControlClass, "px-3 py-2"),
|
|
577
1159
|
placeholder: props.placeholder ?? void 0,
|
|
578
1160
|
value: field.value,
|
|
1161
|
+
ref: field.focusRef,
|
|
579
1162
|
"aria-invalid": field.error ? true : void 0,
|
|
1163
|
+
"aria-describedby": field.describedBy,
|
|
580
1164
|
onChange: (event) => {
|
|
581
1165
|
field.setValue(event.target.value);
|
|
582
1166
|
field.validateOnChange();
|
|
@@ -584,7 +1168,7 @@ function Textarea({
|
|
|
584
1168
|
onBlur: field.validateOnBlur
|
|
585
1169
|
}
|
|
586
1170
|
),
|
|
587
|
-
/* @__PURE__ */ jsx(FieldError, { message: field.error })
|
|
1171
|
+
/* @__PURE__ */ jsx(FieldError, { id: field.errorId, message: field.error })
|
|
588
1172
|
] });
|
|
589
1173
|
}
|
|
590
1174
|
var NATIVE_CHECK = cn("size-4 shrink-0", checkedAccentClass, focusOutlineClass);
|
|
@@ -595,30 +1179,39 @@ function Radio({
|
|
|
595
1179
|
emit
|
|
596
1180
|
}) {
|
|
597
1181
|
const id = useControlId(props.name);
|
|
598
|
-
const field = useBoundField(props.value, bindings?.value, "", props);
|
|
1182
|
+
const field = useBoundField(props.value, bindings?.value, "", props, id);
|
|
599
1183
|
const labelOf = enumLabeler(props.options ?? [], useFieldPresentation());
|
|
600
|
-
return /* @__PURE__ */ jsxs(
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
1184
|
+
return /* @__PURE__ */ jsxs(
|
|
1185
|
+
"fieldset",
|
|
1186
|
+
{
|
|
1187
|
+
className: "space-y-2",
|
|
1188
|
+
"aria-invalid": field.error ? true : void 0,
|
|
1189
|
+
"aria-describedby": field.describedBy,
|
|
1190
|
+
children: [
|
|
1191
|
+
/* @__PURE__ */ jsx("legend", { className: LABEL, children: props.label }),
|
|
1192
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-2 max-sm:space-y-0", children: (props.options ?? []).map((option, index, options) => /* @__PURE__ */ jsxs("label", { className: NATIVE_CHECK_ROW, children: [
|
|
1193
|
+
/* @__PURE__ */ jsx(
|
|
1194
|
+
"input",
|
|
1195
|
+
{
|
|
1196
|
+
type: "radio",
|
|
1197
|
+
name: id,
|
|
1198
|
+
value: option,
|
|
1199
|
+
checked: field.value === option,
|
|
1200
|
+
ref: field.value === option || index === 0 && !options.some((other) => other === field.value) ? field.focusRef : void 0,
|
|
1201
|
+
className: NATIVE_CHECK,
|
|
1202
|
+
onChange: () => {
|
|
1203
|
+
field.setValue(option);
|
|
1204
|
+
field.validateOnChange();
|
|
1205
|
+
emit("change");
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
),
|
|
1209
|
+
/* @__PURE__ */ jsx("span", { children: labelOf(option) })
|
|
1210
|
+
] }, `${index}-${option}`)) }),
|
|
1211
|
+
/* @__PURE__ */ jsx(FieldError, { id: field.errorId, message: field.error })
|
|
1212
|
+
]
|
|
1213
|
+
}
|
|
1214
|
+
);
|
|
622
1215
|
}
|
|
623
1216
|
function Checkbox({
|
|
624
1217
|
props,
|
|
@@ -626,7 +1219,7 @@ function Checkbox({
|
|
|
626
1219
|
emit
|
|
627
1220
|
}) {
|
|
628
1221
|
const id = useControlId(props.name);
|
|
629
|
-
const field = useBoundField(props.checked, bindings?.checked, false, props);
|
|
1222
|
+
const field = useBoundField(props.checked, bindings?.checked, false, props, id);
|
|
630
1223
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
631
1224
|
/* @__PURE__ */ jsxs("label", { htmlFor: id, className: NATIVE_CHECK_ROW, children: [
|
|
632
1225
|
/* @__PURE__ */ jsx(
|
|
@@ -637,7 +1230,9 @@ function Checkbox({
|
|
|
637
1230
|
type: "checkbox",
|
|
638
1231
|
className: NATIVE_CHECK,
|
|
639
1232
|
checked: field.value,
|
|
1233
|
+
ref: field.focusRef,
|
|
640
1234
|
"aria-invalid": field.error ? true : void 0,
|
|
1235
|
+
"aria-describedby": field.describedBy,
|
|
641
1236
|
onChange: (event) => {
|
|
642
1237
|
field.setValue(event.target.checked);
|
|
643
1238
|
field.validateOnChange();
|
|
@@ -647,7 +1242,7 @@ function Checkbox({
|
|
|
647
1242
|
),
|
|
648
1243
|
/* @__PURE__ */ jsx("span", { children: props.label })
|
|
649
1244
|
] }),
|
|
650
|
-
/* @__PURE__ */ jsx(FieldError, { message: field.error })
|
|
1245
|
+
/* @__PURE__ */ jsx(FieldError, { id: field.errorId, message: field.error })
|
|
651
1246
|
] });
|
|
652
1247
|
}
|
|
653
1248
|
function Switch2({
|
|
@@ -656,7 +1251,7 @@ function Switch2({
|
|
|
656
1251
|
emit
|
|
657
1252
|
}) {
|
|
658
1253
|
const id = useControlId(props.name);
|
|
659
|
-
const field = useBoundField(props.checked, bindings?.checked, false, props);
|
|
1254
|
+
const field = useBoundField(props.checked, bindings?.checked, false, props, id);
|
|
660
1255
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
661
1256
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 max-sm:py-2.5", children: [
|
|
662
1257
|
/* @__PURE__ */ jsx(
|
|
@@ -665,7 +1260,9 @@ function Switch2({
|
|
|
665
1260
|
id,
|
|
666
1261
|
name: props.name,
|
|
667
1262
|
checked: field.value,
|
|
1263
|
+
ref: field.focusRef,
|
|
668
1264
|
"aria-invalid": field.error ? true : void 0,
|
|
1265
|
+
"aria-describedby": field.describedBy,
|
|
669
1266
|
onCheckedChange: (next) => {
|
|
670
1267
|
field.setValue(next);
|
|
671
1268
|
field.validateOnChange();
|
|
@@ -675,7 +1272,7 @@ function Switch2({
|
|
|
675
1272
|
),
|
|
676
1273
|
/* @__PURE__ */ jsx("label", { htmlFor: id, className: "text-sm", children: props.label })
|
|
677
1274
|
] }),
|
|
678
|
-
/* @__PURE__ */ jsx(FieldError, { message: field.error })
|
|
1275
|
+
/* @__PURE__ */ jsx(FieldError, { id: field.errorId, message: field.error })
|
|
679
1276
|
] });
|
|
680
1277
|
}
|
|
681
1278
|
var BUTTON = {
|
|
@@ -694,7 +1291,7 @@ function Button({
|
|
|
694
1291
|
disabled: props.disabled ?? false,
|
|
695
1292
|
className: cn(
|
|
696
1293
|
"inline-flex min-h-11 w-fit items-center justify-center rounded-md px-4 py-2 text-sm font-medium transition-colors",
|
|
697
|
-
|
|
1294
|
+
focusOutlineClass,
|
|
698
1295
|
"disabled:pointer-events-none disabled:opacity-50",
|
|
699
1296
|
pick(BUTTON, props.variant, "primary")
|
|
700
1297
|
),
|
|
@@ -703,9 +1300,9 @@ function Button({
|
|
|
703
1300
|
}
|
|
704
1301
|
);
|
|
705
1302
|
}
|
|
706
|
-
var DescriptorContext =
|
|
1303
|
+
var DescriptorContext = React2.createContext({});
|
|
707
1304
|
function useDescriptorScope() {
|
|
708
|
-
return
|
|
1305
|
+
return React2.useContext(DescriptorContext);
|
|
709
1306
|
}
|
|
710
1307
|
function DescriptorProvider({
|
|
711
1308
|
scope,
|
|
@@ -721,8 +1318,9 @@ function Unresolved({ path, side }) {
|
|
|
721
1318
|
className: "rounded-md border border-destructive/50 px-2.5 py-1.5 text-[12px] text-destructive",
|
|
722
1319
|
children: [
|
|
723
1320
|
side === "input" ? "No input" : "No result",
|
|
724
|
-
" at
|
|
725
|
-
|
|
1321
|
+
" at",
|
|
1322
|
+
" ",
|
|
1323
|
+
/* @__PURE__ */ jsx("span", { className: "font-mono", children: typeof path === "string" ? path : JSON.stringify(path) ?? String(path) })
|
|
726
1324
|
]
|
|
727
1325
|
}
|
|
728
1326
|
);
|
|
@@ -747,10 +1345,12 @@ function pathFromDomId(prefix, id) {
|
|
|
747
1345
|
const path = own.split("-").map(decodeSegment).join("/");
|
|
748
1346
|
return `${path}${children.map((child) => `/${child}`).join("")}`;
|
|
749
1347
|
}
|
|
750
|
-
function useAbsolutePath(path) {
|
|
1348
|
+
function useAbsolutePath(path, emptyIsItem = false) {
|
|
751
1349
|
const repeat = useRepeatScope();
|
|
1350
|
+
if (typeof path !== "string") return void 0;
|
|
752
1351
|
if (path.startsWith("/")) return path;
|
|
753
|
-
|
|
1352
|
+
if (!repeat) return void 0;
|
|
1353
|
+
return path === "" && emptyIsItem ? repeat.basePath : `${repeat.basePath}/${path}`;
|
|
754
1354
|
}
|
|
755
1355
|
function withoutOptionalMark(label) {
|
|
756
1356
|
return label.replace(/\s*\(optional\)\s*$/i, "") || label;
|
|
@@ -758,10 +1358,10 @@ function withoutOptionalMark(label) {
|
|
|
758
1358
|
function MthdsField({
|
|
759
1359
|
props
|
|
760
1360
|
}) {
|
|
761
|
-
const scope =
|
|
1361
|
+
const scope = React2.useContext(DescriptorContext);
|
|
762
1362
|
const path = useAbsolutePath(props.path) ?? "";
|
|
763
1363
|
const found = scope.inputs && path ? inputFieldAtPath(scope.inputs, path) : void 0;
|
|
764
|
-
const field =
|
|
1364
|
+
const field = React2.useMemo(
|
|
765
1365
|
() => found && (props.label || props.hint) ? {
|
|
766
1366
|
...found,
|
|
767
1367
|
// The control marks an optional field itself, so a label that
|
|
@@ -773,7 +1373,7 @@ function MthdsField({
|
|
|
773
1373
|
);
|
|
774
1374
|
const value = useStateValue(path);
|
|
775
1375
|
const { set } = useStateStore();
|
|
776
|
-
const onChange =
|
|
1376
|
+
const onChange = React2.useCallback((next) => set(path, next), [set, path]);
|
|
777
1377
|
if (!field) return /* @__PURE__ */ jsx(Unresolved, { path: props.path, side: "input" });
|
|
778
1378
|
return /* @__PURE__ */ jsx(
|
|
779
1379
|
FieldRenderer,
|
|
@@ -787,30 +1387,32 @@ function MthdsField({
|
|
|
787
1387
|
);
|
|
788
1388
|
}
|
|
789
1389
|
function MthdsResult({ props }) {
|
|
790
|
-
const scope =
|
|
1390
|
+
const scope = React2.useContext(DescriptorContext);
|
|
791
1391
|
const path = useAbsolutePath(props.path) ?? "";
|
|
792
1392
|
const field = scope.result && path ? resultFieldAtPath(scope.result, path) : void 0;
|
|
793
1393
|
const value = useStateValue(path);
|
|
794
1394
|
if (!field || !scope.result) return /* @__PURE__ */ jsx(Unresolved, { path: props.path, side: "result" });
|
|
795
|
-
const
|
|
796
|
-
return /* @__PURE__ */ jsx(ResultRoot, { baseName: scope.result.name, path:
|
|
1395
|
+
const place2 = [scope.result.name, ...segmentsUnder(RESULT_ROOT, path) ?? []];
|
|
1396
|
+
return /* @__PURE__ */ jsx(ResultRoot, { baseName: scope.result.name, path: place2, children: /* @__PURE__ */ jsx(ResultField, { field, value, hideLabel: props.hideLabel ?? false }) });
|
|
797
1397
|
}
|
|
798
1398
|
function AccessibleSelect({ props, bindings, emit }) {
|
|
799
1399
|
const [boundValue, setBoundValue] = useBoundProp(
|
|
800
1400
|
props.value ?? void 0,
|
|
801
1401
|
bindings?.value
|
|
802
1402
|
);
|
|
803
|
-
const [localValue, setLocalValue] =
|
|
1403
|
+
const [localValue, setLocalValue] = React2.useState("");
|
|
804
1404
|
const isBound = Boolean(bindings?.value);
|
|
805
1405
|
const value = isBound ? boundValue ?? "" : localValue;
|
|
806
1406
|
const setValue = isBound ? setBoundValue : setLocalValue;
|
|
807
1407
|
const validateOn = props.validateOn ?? "change";
|
|
808
1408
|
const hasValidation = Boolean(bindings?.value && props.checks?.length);
|
|
809
|
-
const { errors, validate } =
|
|
1409
|
+
const { errors, validate, focusRef } = useCheckedField(
|
|
810
1410
|
bindings?.value ?? "",
|
|
811
1411
|
hasValidation ? { checks: props.checks ?? [], validateOn } : void 0
|
|
812
1412
|
);
|
|
813
1413
|
const id = useControlId(props.name);
|
|
1414
|
+
const errorId = `${id}-error`;
|
|
1415
|
+
const error = errors[0];
|
|
814
1416
|
const labelOf = enumLabeler(props.options ?? [], useFieldPresentation());
|
|
815
1417
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
816
1418
|
/* @__PURE__ */ jsx("label", { htmlFor: id, className: "block text-sm leading-none font-medium", children: props.label }),
|
|
@@ -824,12 +1426,22 @@ function AccessibleSelect({ props, bindings, emit }) {
|
|
|
824
1426
|
emit("change");
|
|
825
1427
|
},
|
|
826
1428
|
children: [
|
|
827
|
-
/* @__PURE__ */ jsx(
|
|
1429
|
+
/* @__PURE__ */ jsx(
|
|
1430
|
+
SelectTrigger,
|
|
1431
|
+
{
|
|
1432
|
+
id,
|
|
1433
|
+
ref: focusRef,
|
|
1434
|
+
"aria-invalid": error ? true : void 0,
|
|
1435
|
+
"aria-describedby": error ? errorId : void 0,
|
|
1436
|
+
className: "h-11 w-full",
|
|
1437
|
+
children: /* @__PURE__ */ jsx(SelectValue, { placeholder: props.placeholder ?? "Select..." })
|
|
1438
|
+
}
|
|
1439
|
+
),
|
|
828
1440
|
/* @__PURE__ */ jsx(SelectContent, { children: (props.options ?? []).map((option, index) => /* @__PURE__ */ jsx(SelectItem, { value: option, children: labelOf(option) }, `${index}-${option}`)) })
|
|
829
1441
|
]
|
|
830
1442
|
}
|
|
831
1443
|
),
|
|
832
|
-
|
|
1444
|
+
error ? /* @__PURE__ */ jsx("p", { id: errorId, className: "text-sm text-destructive", children: error }) : null
|
|
833
1445
|
] });
|
|
834
1446
|
}
|
|
835
1447
|
function valueAt(row, relativePath) {
|
|
@@ -840,27 +1452,20 @@ function valueAt(row, relativePath) {
|
|
|
840
1452
|
}
|
|
841
1453
|
return current;
|
|
842
1454
|
}
|
|
843
|
-
var CELL_NUMBER = new Intl.NumberFormat("en-US", { maximumFractionDigits: 2 });
|
|
844
1455
|
function formatCell(value) {
|
|
845
1456
|
if (value === null || value === void 0 || value === "") return "\u2014";
|
|
846
1457
|
if (typeof value === "boolean") return value ? "yes" : "no";
|
|
847
|
-
if (typeof value === "number") return
|
|
1458
|
+
if (typeof value === "number") return formatNumber(value);
|
|
848
1459
|
if (typeof value === "string") return value;
|
|
849
1460
|
if (Array.isArray(value)) return value.map(formatCell).join(", ");
|
|
850
1461
|
return JSON.stringify(value);
|
|
851
1462
|
}
|
|
852
1463
|
function formatColumnCell(value, format) {
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
if (
|
|
856
|
-
const
|
|
857
|
-
if (
|
|
858
|
-
return date.toLocaleDateString("en-GB", {
|
|
859
|
-
day: "numeric",
|
|
860
|
-
month: "short",
|
|
861
|
-
year: "numeric",
|
|
862
|
-
timeZone: "UTC"
|
|
863
|
-
});
|
|
1464
|
+
if (format === "date") return formatDay(value, "short") ?? formatCell(value);
|
|
1465
|
+
if (format === "text" && typeof value === "number") return formatNumber(value, "plain");
|
|
1466
|
+
if (format === "number") {
|
|
1467
|
+
const amount = shareAmount(value);
|
|
1468
|
+
if (Number.isFinite(amount)) return formatNumber(amount);
|
|
864
1469
|
}
|
|
865
1470
|
return formatCell(value);
|
|
866
1471
|
}
|
|
@@ -881,23 +1486,9 @@ function DataTable({ props }) {
|
|
|
881
1486
|
/* @__PURE__ */ jsx("tbody", { children: rows.map((row, index) => /* @__PURE__ */ jsx("tr", { className: "border-b border-border/60 last:border-b-0", children: columns.map((column) => /* @__PURE__ */ jsx("td", { className: "px-2.5 py-1.5 align-top text-foreground", children: formatColumnCell(valueAt(row, column.path), column.format) }, column.path)) }, index)) })
|
|
882
1487
|
] }) });
|
|
883
1488
|
}
|
|
884
|
-
function numberFormat(format) {
|
|
885
|
-
switch (format) {
|
|
886
|
-
case "integer":
|
|
887
|
-
return new Intl.NumberFormat("en-US", { maximumFractionDigits: 0 });
|
|
888
|
-
case "decimal":
|
|
889
|
-
return new Intl.NumberFormat("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
|
890
|
-
case "compact":
|
|
891
|
-
return new Intl.NumberFormat("en-US", { notation: "compact", maximumFractionDigits: 1 });
|
|
892
|
-
case "plain":
|
|
893
|
-
return new Intl.NumberFormat("en-US", { maximumFractionDigits: 20, useGrouping: false });
|
|
894
|
-
default:
|
|
895
|
-
return format;
|
|
896
|
-
}
|
|
897
|
-
}
|
|
898
1489
|
function Metric({ props }) {
|
|
899
1490
|
const value = props.value;
|
|
900
|
-
const text = typeof value === "number" ?
|
|
1491
|
+
const text = typeof value === "number" ? formatNumber(value, props.format ?? "plain") : textOf(value) || "\u2014";
|
|
901
1492
|
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
|
|
902
1493
|
/* @__PURE__ */ jsx("span", { className: "text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: props.label }),
|
|
903
1494
|
/* @__PURE__ */ jsxs("span", { className: "text-2xl font-semibold tabular-nums text-foreground", children: [
|
|
@@ -930,30 +1521,53 @@ function Split({
|
|
|
930
1521
|
}
|
|
931
1522
|
function Tabs({ props, children }) {
|
|
932
1523
|
const tabs = props.tabs ?? [];
|
|
933
|
-
const panels =
|
|
934
|
-
const [
|
|
935
|
-
|
|
936
|
-
|
|
1524
|
+
const panels = React2.Children.toArray(children);
|
|
1525
|
+
const [chosen, setChosen] = React2.useState(null);
|
|
1526
|
+
const open = chosen ? openIndex(tabs, chosen) : 0;
|
|
1527
|
+
const value = String(open);
|
|
1528
|
+
const choose = (next) => {
|
|
1529
|
+
const index = Number(next);
|
|
1530
|
+
const tab = tabs[index];
|
|
1531
|
+
if (!tab) return;
|
|
1532
|
+
const occurrence = tabs.slice(0, index).filter((t) => t.value === tab.value).length;
|
|
1533
|
+
setChosen({ value: tab.value, occurrence });
|
|
1534
|
+
};
|
|
1535
|
+
return /* @__PURE__ */ jsxs(TabsPrimitive.Root, { value, onValueChange: choose, className: "w-full", children: [
|
|
1536
|
+
/* @__PURE__ */ jsx(TabsPrimitive.List, { className: "inline-flex h-10 items-center justify-start rounded-md bg-muted p-1 text-muted-foreground max-sm:h-auto max-sm:flex-wrap", children: tabs.map((tab, index) => /* @__PURE__ */ jsx(
|
|
937
1537
|
TabsPrimitive.Trigger,
|
|
938
1538
|
{
|
|
939
|
-
value:
|
|
1539
|
+
value: String(index),
|
|
940
1540
|
className: "inline-flex items-center justify-center rounded-sm px-3 py-1.5 text-sm font-medium whitespace-nowrap transition-all focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-hidden data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm max-sm:min-h-11 max-sm:min-w-11",
|
|
941
1541
|
children: tab.label
|
|
942
1542
|
},
|
|
943
|
-
|
|
1543
|
+
index
|
|
944
1544
|
)) }),
|
|
945
|
-
tabs.map((
|
|
1545
|
+
tabs.map((_tab, index) => /* @__PURE__ */ jsx(
|
|
946
1546
|
TabsPrimitive.Content,
|
|
947
1547
|
{
|
|
948
|
-
value:
|
|
1548
|
+
value: String(index),
|
|
1549
|
+
forceMount: true,
|
|
1550
|
+
hidden: index !== open,
|
|
949
1551
|
className: "mt-4 focus-visible:outline-hidden",
|
|
950
|
-
children: panels[index] ?? null
|
|
1552
|
+
children: /* @__PURE__ */ jsx(RevealPanel, { open: () => choose(String(index)), children: panels[index] ?? null })
|
|
951
1553
|
},
|
|
952
|
-
|
|
1554
|
+
index
|
|
953
1555
|
))
|
|
954
1556
|
] });
|
|
955
1557
|
}
|
|
956
|
-
|
|
1558
|
+
function openIndex(tabs, { value, occurrence }) {
|
|
1559
|
+
let seen = 0;
|
|
1560
|
+
for (const [index, tab] of tabs.entries()) {
|
|
1561
|
+
if (tab.value !== value) continue;
|
|
1562
|
+
if (seen === occurrence) return index;
|
|
1563
|
+
seen += 1;
|
|
1564
|
+
}
|
|
1565
|
+
return 0;
|
|
1566
|
+
}
|
|
1567
|
+
var BUTTON_BASE = cn(
|
|
1568
|
+
"inline-flex min-h-11 items-center justify-center rounded-md px-4 text-sm font-medium transition-colors disabled:pointer-events-none disabled:opacity-50",
|
|
1569
|
+
focusOutlineClass
|
|
1570
|
+
);
|
|
957
1571
|
var PRIMARY_BUTTON = cn(BUTTON_BASE, "bg-primary text-primary-foreground hover:bg-primary/90");
|
|
958
1572
|
var SECONDARY_BUTTON = cn(
|
|
959
1573
|
BUTTON_BASE,
|
|
@@ -961,9 +1575,10 @@ var SECONDARY_BUTTON = cn(
|
|
|
961
1575
|
);
|
|
962
1576
|
function Steps({ props, children }) {
|
|
963
1577
|
const steps = props.steps ?? [];
|
|
964
|
-
const panels =
|
|
965
|
-
const [
|
|
1578
|
+
const panels = React2.Children.toArray(children);
|
|
1579
|
+
const [chosen, setIndex] = React2.useState(0);
|
|
966
1580
|
const last = steps.length - 1;
|
|
1581
|
+
const index = Math.max(0, Math.min(chosen, last));
|
|
967
1582
|
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-5", children: [
|
|
968
1583
|
/* @__PURE__ */ jsx("ol", { className: "flex flex-wrap items-center gap-x-5 gap-y-2", children: steps.map((label, position) => /* @__PURE__ */ jsxs(
|
|
969
1584
|
"li",
|
|
@@ -989,14 +1604,14 @@ function Steps({ props, children }) {
|
|
|
989
1604
|
},
|
|
990
1605
|
`${position}-${label}`
|
|
991
1606
|
)) }),
|
|
992
|
-
/* @__PURE__ */ jsx("div", { children: panels[
|
|
1607
|
+
steps.map((_step, position) => /* @__PURE__ */ jsx("div", { hidden: position !== index, children: /* @__PURE__ */ jsx(RevealPanel, { open: () => setIndex(position), children: panels[position] ?? null }) }, position)),
|
|
993
1608
|
index > 0 || index < last ? /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3", children: [
|
|
994
1609
|
index > 0 ? /* @__PURE__ */ jsx(
|
|
995
1610
|
"button",
|
|
996
1611
|
{
|
|
997
1612
|
type: "button",
|
|
998
1613
|
"data-testid": "steps-back",
|
|
999
|
-
onClick: () => setIndex(
|
|
1614
|
+
onClick: () => setIndex(Math.max(0, index - 1)),
|
|
1000
1615
|
className: SECONDARY_BUTTON,
|
|
1001
1616
|
children: props.backLabel ?? "Back"
|
|
1002
1617
|
}
|
|
@@ -1006,7 +1621,7 @@ function Steps({ props, children }) {
|
|
|
1006
1621
|
{
|
|
1007
1622
|
type: "button",
|
|
1008
1623
|
"data-testid": "steps-next",
|
|
1009
|
-
onClick: () => setIndex(
|
|
1624
|
+
onClick: () => setIndex(Math.min(last, index + 1)),
|
|
1010
1625
|
className: PRIMARY_BUTTON,
|
|
1011
1626
|
children: props.nextLabel ?? "Next"
|
|
1012
1627
|
}
|
|
@@ -1091,7 +1706,7 @@ function Segmented({ props, bindings, emit }) {
|
|
|
1091
1706
|
props.value ?? void 0,
|
|
1092
1707
|
bindings?.value
|
|
1093
1708
|
);
|
|
1094
|
-
const [localValue, setLocalValue] =
|
|
1709
|
+
const [localValue, setLocalValue] = React2.useState("");
|
|
1095
1710
|
const isBound = Boolean(bindings?.value);
|
|
1096
1711
|
const value = isBound ? boundValue ?? "" : localValue;
|
|
1097
1712
|
const setValue = isBound ? setBoundValue : setLocalValue;
|
|
@@ -1111,7 +1726,7 @@ function Segmented({ props, bindings, emit }) {
|
|
|
1111
1726
|
emit("change");
|
|
1112
1727
|
},
|
|
1113
1728
|
className: "flex-wrap justify-start gap-1.5",
|
|
1114
|
-
children: (props.options ?? []).map((option) => /* @__PURE__ */ jsx(
|
|
1729
|
+
children: (props.options ?? []).map((option, index) => /* @__PURE__ */ jsx(
|
|
1115
1730
|
ToggleGroupItem,
|
|
1116
1731
|
{
|
|
1117
1732
|
value: option,
|
|
@@ -1120,7 +1735,7 @@ function Segmented({ props, bindings, emit }) {
|
|
|
1120
1735
|
className: "rounded-full px-3.5 data-[state=on]:border-primary data-[state=on]:bg-primary data-[state=on]:text-primary-foreground max-sm:h-11 max-sm:min-w-11",
|
|
1121
1736
|
children: labelOf(option)
|
|
1122
1737
|
},
|
|
1123
|
-
option
|
|
1738
|
+
`${index}-${option}`
|
|
1124
1739
|
))
|
|
1125
1740
|
}
|
|
1126
1741
|
)
|
|
@@ -1131,7 +1746,7 @@ function NumberInput({ props, bindings, emit }) {
|
|
|
1131
1746
|
props.value ?? void 0,
|
|
1132
1747
|
bindings?.value
|
|
1133
1748
|
);
|
|
1134
|
-
const [localValue, setLocalValue] =
|
|
1749
|
+
const [localValue, setLocalValue] = React2.useState(void 0);
|
|
1135
1750
|
const isBound = Boolean(bindings?.value);
|
|
1136
1751
|
const value = isBound ? boundValue : localValue;
|
|
1137
1752
|
const setValue = isBound ? setBoundValue : setLocalValue;
|
|
@@ -1206,23 +1821,62 @@ var components = {
|
|
|
1206
1821
|
};
|
|
1207
1822
|
var generativeRenderers = withDeclaredProps(
|
|
1208
1823
|
baseCatalog.data.components,
|
|
1209
|
-
components
|
|
1824
|
+
components,
|
|
1825
|
+
// A hatch resolves its `path` as written, relative inside a repeat, so a
|
|
1826
|
+
// refused one reaches it as refused rather than written out as text.
|
|
1827
|
+
{ MthdsField: ["path"], MthdsResult: ["path"] }
|
|
1210
1828
|
);
|
|
1211
1829
|
var RADIUS = "rounded-[calc(var(--radius,0.5rem)*1.5)]";
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1830
|
+
var NAMED_WAITING = 3;
|
|
1831
|
+
function useRunWaitsFor() {
|
|
1832
|
+
const { inputs } = useDescriptorScope();
|
|
1833
|
+
const values = useStateValue(INPUTS_ROOT);
|
|
1834
|
+
const placed = usePlacedInputs();
|
|
1835
|
+
const presentation = useFieldPresentation();
|
|
1836
|
+
const strings = useFieldStrings();
|
|
1837
|
+
const waiting = waitingFields(inputs ?? [], isRecord2(values) ? values : void 0).map(({ field, path }) => {
|
|
1838
|
+
const at = joinPath(INPUTS_ROOT, ...path);
|
|
1839
|
+
return { field, path, on: placed.get(at), rank: rankOf(placed, at) };
|
|
1840
|
+
}).sort((a, b) => a.rank - b.rank);
|
|
1841
|
+
if (waiting.length === 0) return void 0;
|
|
1842
|
+
const labelAt = (path) => {
|
|
1843
|
+
const field = inputFieldAtPath(inputs ?? [], joinPath(INPUTS_ROOT, ...path));
|
|
1844
|
+
if (!field) return void 0;
|
|
1845
|
+
return placed.get(joinPath(INPUTS_ROOT, ...path))?.label ?? fieldLabel(field.title, field.name, presentation);
|
|
1846
|
+
};
|
|
1847
|
+
const named = waiting.slice(0, NAMED_WAITING);
|
|
1848
|
+
const labels = named.map(
|
|
1849
|
+
({ field, on }) => on?.label ?? fieldLabel(field.title, field.name, presentation)
|
|
1850
|
+
);
|
|
1851
|
+
const names = labels.map((label, index) => {
|
|
1852
|
+
const parent = named[index].path.slice(0, -1);
|
|
1853
|
+
const shared = labels.filter((other) => other === label).length > 1;
|
|
1854
|
+
const around = shared && parent.length > 0 ? labelAt(parent) : void 0;
|
|
1855
|
+
return around ? `${label} (${around})` : label;
|
|
1856
|
+
});
|
|
1857
|
+
return strings.runWaitsFor(names, waiting.length - names.length);
|
|
1858
|
+
}
|
|
1859
|
+
function rankOf(placed, path) {
|
|
1860
|
+
const own = placed.get(path);
|
|
1861
|
+
if (own) return own.order;
|
|
1862
|
+
for (let at = path.lastIndexOf("/"); at > INPUTS_ROOT.length; at = path.lastIndexOf("/", at - 1)) {
|
|
1863
|
+
const around = placed.get(path.slice(0, at));
|
|
1864
|
+
if (around) return around.order;
|
|
1865
|
+
}
|
|
1866
|
+
let first = Number.MAX_SAFE_INTEGER;
|
|
1867
|
+
for (const [inside, { order }] of placed) {
|
|
1868
|
+
if (inside.startsWith(`${path}/`)) first = Math.min(first, order);
|
|
1869
|
+
}
|
|
1870
|
+
return first;
|
|
1217
1871
|
}
|
|
1218
|
-
function
|
|
1219
|
-
|
|
1220
|
-
const date = /* @__PURE__ */ new Date(`${value.slice(0, 10)}T12:00:00Z`);
|
|
1221
|
-
return Number.isNaN(date.getTime()) ? void 0 : date;
|
|
1872
|
+
function isRecord2(value) {
|
|
1873
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1222
1874
|
}
|
|
1223
1875
|
function Composer({ props, children, emit }) {
|
|
1224
1876
|
const host = useFrameHost();
|
|
1225
1877
|
const busy = useDescriptorScope().env?.disabled ?? false;
|
|
1878
|
+
const waitsFor = useRunWaitsFor();
|
|
1879
|
+
const waitsForId = React2.useId();
|
|
1226
1880
|
const two = props.columns === "2";
|
|
1227
1881
|
return /* @__PURE__ */ jsxs(
|
|
1228
1882
|
"div",
|
|
@@ -1259,16 +1913,20 @@ function Composer({ props, children, emit }) {
|
|
|
1259
1913
|
}
|
|
1260
1914
|
),
|
|
1261
1915
|
/* @__PURE__ */ jsxs("div", { className: "sticky bottom-0 z-[2] -mx-7 -mb-7 mt-7 flex items-center justify-between gap-4 rounded-b-[calc(var(--radius,0.5rem)*1.5)] border-t border-border [background-color:var(--panel-fill,var(--card,hsl(0_0%_100%)))] px-7 pt-[18px] pb-7 max-sm:-mx-5 max-sm:-mb-5 max-sm:flex-col-reverse max-sm:items-stretch max-sm:px-5 max-sm:pb-5", children: [
|
|
1262
|
-
|
|
1263
|
-
/* @__PURE__ */ jsx(
|
|
1264
|
-
" ",
|
|
1265
|
-
|
|
1266
|
-
|
|
1916
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-1 text-sm text-muted-foreground max-sm:items-center max-sm:text-center", children: [
|
|
1917
|
+
waitsFor ? /* @__PURE__ */ jsx("p", { id: waitsForId, children: waitsFor }) : null,
|
|
1918
|
+
host.eta ? /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-2", children: [
|
|
1919
|
+
/* @__PURE__ */ jsx(Clock, { className: "size-4", "aria-hidden": "true" }),
|
|
1920
|
+
" ",
|
|
1921
|
+
host.eta
|
|
1922
|
+
] }) : null
|
|
1923
|
+
] }),
|
|
1267
1924
|
/* @__PURE__ */ jsxs(
|
|
1268
1925
|
"button",
|
|
1269
1926
|
{
|
|
1270
1927
|
type: "button",
|
|
1271
1928
|
disabled: busy,
|
|
1929
|
+
"aria-describedby": waitsFor ? waitsForId : void 0,
|
|
1272
1930
|
onClick: () => emit("press"),
|
|
1273
1931
|
className: cn(
|
|
1274
1932
|
"inline-flex min-h-11 items-center justify-center gap-2 rounded-[var(--radius,0.5rem)] bg-primary px-[22px] text-[15px] font-semibold text-primary-foreground transition-all hover:bg-primary/90",
|
|
@@ -1340,32 +1998,24 @@ function segmentMix(index, count) {
|
|
|
1340
1998
|
function segmentColor(index, count) {
|
|
1341
1999
|
return `color-mix(in oklab, var(--link, var(--primary, hsl(240 5.9% 10%))) ${segmentMix(index, count)}%, var(--muted, hsl(240 4.8% 95.9%)))`;
|
|
1342
2000
|
}
|
|
1343
|
-
function
|
|
1344
|
-
if (
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
style: "currency",
|
|
1348
|
-
currency: unit,
|
|
1349
|
-
maximumFractionDigits: 0
|
|
1350
|
-
}).format(value);
|
|
1351
|
-
} catch {
|
|
1352
|
-
}
|
|
1353
|
-
}
|
|
1354
|
-
const n = new Intl.NumberFormat("en-GB", { maximumFractionDigits: 2 }).format(value);
|
|
1355
|
-
return unit ? `${n} ${unit}` : n;
|
|
2001
|
+
function statedAmount(raw) {
|
|
2002
|
+
if (raw === null || raw === void 0) return null;
|
|
2003
|
+
const amount = shareAmount(raw);
|
|
2004
|
+
return Number.isFinite(amount) ? amount : void 0;
|
|
1356
2005
|
}
|
|
1357
2006
|
function ProportionBar({ props }) {
|
|
1358
2007
|
const rows = (Array.isArray(props.items) ? props.items : []).filter(
|
|
1359
2008
|
(row) => typeof row === "object" && row !== null && !Array.isArray(row)
|
|
1360
2009
|
);
|
|
1361
|
-
const amountOf = (raw) => typeof raw === "object" && raw !== null ? Number.NaN : Number(raw ?? 0);
|
|
1362
2010
|
const parts = rows.map((row) => ({
|
|
1363
2011
|
label: textOf(row[props.labelKey]),
|
|
1364
|
-
value:
|
|
2012
|
+
value: shareAmount(row[props.valueKey])
|
|
1365
2013
|
})).filter((p) => Number.isFinite(p.value) && p.value > 0);
|
|
1366
2014
|
const sum = parts.reduce((s, p) => s + p.value, 0);
|
|
1367
|
-
const
|
|
1368
|
-
const
|
|
2015
|
+
const stated = statedAmount(props.total);
|
|
2016
|
+
const total = stated === null ? sum : stated;
|
|
2017
|
+
const ceiling = statedAmount(props.of) ?? void 0;
|
|
2018
|
+
const scale = Math.max(sum, total ?? 0, ceiling ?? 0) || 1;
|
|
1369
2019
|
const cap = (s) => s.charAt(0).toUpperCase() + s.slice(1);
|
|
1370
2020
|
return /* @__PURE__ */ jsxs(
|
|
1371
2021
|
"div",
|
|
@@ -1380,10 +2030,10 @@ function ProportionBar({ props }) {
|
|
|
1380
2030
|
children: [
|
|
1381
2031
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-baseline gap-x-2.5", children: [
|
|
1382
2032
|
/* @__PURE__ */ jsx("span", { className: "text-[15px] text-muted-foreground", children: props.label }),
|
|
1383
|
-
/* @__PURE__ */ jsx("strong", { className: "text-2xl font-semibold tabular-nums text-foreground", children:
|
|
1384
|
-
|
|
2033
|
+
total !== void 0 ? /* @__PURE__ */ jsx("strong", { className: "text-2xl font-semibold tabular-nums text-foreground", children: formatAmount(total, props.unit) }) : null,
|
|
2034
|
+
ceiling !== void 0 ? /* @__PURE__ */ jsxs("span", { className: "text-[15px] text-muted-foreground", children: [
|
|
1385
2035
|
"of ",
|
|
1386
|
-
|
|
2036
|
+
formatAmount(ceiling, props.unit)
|
|
1387
2037
|
] }) : null
|
|
1388
2038
|
] }),
|
|
1389
2039
|
/* @__PURE__ */ jsx("div", { className: "flex h-2 gap-0.5 overflow-hidden rounded-full bg-muted", "aria-hidden": "true", children: parts.map((p, i) => /* @__PURE__ */ jsx(
|
|
@@ -1413,7 +2063,7 @@ function ProportionBar({ props }) {
|
|
|
1413
2063
|
),
|
|
1414
2064
|
cap(p.label),
|
|
1415
2065
|
" ",
|
|
1416
|
-
|
|
2066
|
+
formatAmount(p.value, props.unit)
|
|
1417
2067
|
]
|
|
1418
2068
|
},
|
|
1419
2069
|
`${i}-${p.label}`
|
|
@@ -1446,11 +2096,10 @@ var ASPECT = {
|
|
|
1446
2096
|
function Picture({
|
|
1447
2097
|
props
|
|
1448
2098
|
}) {
|
|
1449
|
-
const
|
|
1450
|
-
const
|
|
1451
|
-
const value = useStateValue(path);
|
|
2099
|
+
const path = useAbsolutePath(props.path, true);
|
|
2100
|
+
const value = useStateValue(path ?? "");
|
|
1452
2101
|
const resolve = useResolveUrl();
|
|
1453
|
-
const content =
|
|
2102
|
+
const content = path === void 0 ? void 0 : readImageContent(value);
|
|
1454
2103
|
const src = content ? viewableUrl(resolve?.(content.url)) ?? viewableUrl(content.publicUrl) ?? viewableUrl(content.url) : void 0;
|
|
1455
2104
|
const aspect = props.aspect && props.aspect !== "auto" ? ASPECT[props.aspect] : void 0;
|
|
1456
2105
|
if (!src) return null;
|
|
@@ -1467,39 +2116,33 @@ function Picture({
|
|
|
1467
2116
|
}
|
|
1468
2117
|
);
|
|
1469
2118
|
}
|
|
1470
|
-
function present(value) {
|
|
1471
|
-
return value !== void 0 && value !== null && value !== "";
|
|
1472
|
-
}
|
|
1473
2119
|
function Fact({
|
|
1474
2120
|
props
|
|
1475
2121
|
}) {
|
|
2122
|
+
const text = textOf(props.value);
|
|
1476
2123
|
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1 rounded-[var(--radius,0.5rem)] border border-border bg-background px-4 py-3", children: [
|
|
1477
2124
|
/* @__PURE__ */ jsx("span", { className: "text-[13px] text-muted-foreground", children: props.label }),
|
|
1478
|
-
/* @__PURE__ */ jsx("span", { className: "text-[16px] font-medium text-foreground tabular-nums", children:
|
|
2125
|
+
/* @__PURE__ */ jsx("span", { className: "text-[16px] font-medium text-foreground tabular-nums", children: text !== "" ? text : "\u2014" }),
|
|
1479
2126
|
props.detail ? /* @__PURE__ */ jsx("span", { className: "text-[13px] text-muted-foreground", children: props.detail }) : null
|
|
1480
2127
|
] });
|
|
1481
2128
|
}
|
|
1482
2129
|
function Detail({ props }) {
|
|
1483
|
-
|
|
2130
|
+
const text = textOf(props.value);
|
|
2131
|
+
if (text === "") return null;
|
|
1484
2132
|
return (
|
|
1485
2133
|
// A rule between the rows of a list of details, never under one set in a
|
|
1486
2134
|
// row: there it read as an underline on every detail but the last.
|
|
1487
2135
|
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[minmax(0,8.5rem)_minmax(0,1fr)] gap-3 border-b border-border py-2.5 text-[14px] last:border-b-0 [.flex-row>&]:border-b-0 [.flex-row>&]:grid-cols-[auto_minmax(0,1fr)]", children: [
|
|
1488
2136
|
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: props.label }),
|
|
1489
|
-
/* @__PURE__ */ jsx("span", { className: "text-foreground", children:
|
|
2137
|
+
/* @__PURE__ */ jsx("span", { className: "text-foreground", children: text })
|
|
1490
2138
|
] })
|
|
1491
2139
|
);
|
|
1492
2140
|
}
|
|
1493
|
-
var DATE_STYLES = {
|
|
1494
|
-
long: { weekday: "long", day: "numeric", month: "long", year: "numeric", timeZone: "UTC" },
|
|
1495
|
-
short: { day: "numeric", month: "short", year: "numeric", timeZone: "UTC" },
|
|
1496
|
-
weekday: { weekday: "short", day: "numeric", month: "long", timeZone: "UTC" }
|
|
1497
|
-
};
|
|
1498
2141
|
function DateText({ props }) {
|
|
1499
|
-
const
|
|
1500
|
-
if (
|
|
2142
|
+
const day = formatDay(props.value, props.style ?? "long");
|
|
2143
|
+
if (day === void 0) return null;
|
|
1501
2144
|
const tone = props.tone === "accent" ? cn("text-[13px] font-semibold", linkTextClass) : props.tone === "muted" ? "text-sm text-muted-foreground" : "text-[15px] text-foreground";
|
|
1502
|
-
return /* @__PURE__ */ jsx("span", { className: cn("block", tone), children:
|
|
2145
|
+
return /* @__PURE__ */ jsx("span", { className: cn("block", tone), children: day });
|
|
1503
2146
|
}
|
|
1504
2147
|
function TextList({ props }) {
|
|
1505
2148
|
const items = Array.isArray(props.items) ? props.items.filter((x) => typeof x === "string" && x.trim()) : [];
|
|
@@ -1538,10 +2181,13 @@ var frameRenderers = withDeclaredProps(
|
|
|
1538
2181
|
Detail: (ctx) => /* @__PURE__ */ jsx(Detail, { ...ctx })
|
|
1539
2182
|
},
|
|
1540
2183
|
// A refused `path` reaches the renderer as refused: its nearest value, the
|
|
1541
|
-
// empty text, is the item itself inside a repeat.
|
|
1542
|
-
|
|
2184
|
+
// empty text, is the item itself inside a repeat. A share's total and its
|
|
2185
|
+
// ceiling are read as written too: a decimal a payload carries as text is
|
|
2186
|
+
// a number the bar can draw, where its nearest value, nothing, would put
|
|
2187
|
+
// the parts' sum in its place.
|
|
2188
|
+
{ Picture: ["path"], ProportionBar: ["total", "of"] }
|
|
1543
2189
|
);
|
|
1544
|
-
var ResultSlotContext =
|
|
2190
|
+
var ResultSlotContext = React2.createContext(null);
|
|
1545
2191
|
function ResultSlotProvider({
|
|
1546
2192
|
slot,
|
|
1547
2193
|
children
|
|
@@ -1549,7 +2195,7 @@ function ResultSlotProvider({
|
|
|
1549
2195
|
return /* @__PURE__ */ jsx(ResultSlotContext.Provider, { value: slot, children });
|
|
1550
2196
|
}
|
|
1551
2197
|
function useResultSlot() {
|
|
1552
|
-
return
|
|
2198
|
+
return React2.useContext(ResultSlotContext);
|
|
1553
2199
|
}
|
|
1554
2200
|
var LABEL2 = "block text-[13.5px] leading-none font-medium text-foreground";
|
|
1555
2201
|
function AppBar({ props }) {
|
|
@@ -1578,7 +2224,7 @@ function Hero({ props }) {
|
|
|
1578
2224
|
] });
|
|
1579
2225
|
}
|
|
1580
2226
|
function Workspace({ props, children }) {
|
|
1581
|
-
const [work, rail] =
|
|
2227
|
+
const [work, rail] = React2.Children.toArray(children);
|
|
1582
2228
|
const railLeft = props.rail === "left";
|
|
1583
2229
|
return /* @__PURE__ */ jsxs(
|
|
1584
2230
|
"div",
|
|
@@ -1650,11 +2296,8 @@ function Rail({ props, children }) {
|
|
|
1650
2296
|
)
|
|
1651
2297
|
);
|
|
1652
2298
|
}
|
|
1653
|
-
function present2(value) {
|
|
1654
|
-
return value !== void 0 && value !== null && value !== "";
|
|
1655
|
-
}
|
|
1656
2299
|
function SummaryRow({ props }) {
|
|
1657
|
-
const text = [props.value, props.detail].
|
|
2300
|
+
const text = [props.value, props.detail].map(textOf).filter((half) => half !== "").join(props.separator ?? " ");
|
|
1658
2301
|
return /* @__PURE__ */ jsxs("div", { className: "flex items-baseline justify-between gap-4 border-b border-border/60 py-3 first:pt-0 last:border-b-0", children: [
|
|
1659
2302
|
/* @__PURE__ */ jsx("span", { className: "shrink-0 text-[13px] text-muted-foreground", children: props.label }),
|
|
1660
2303
|
text ? /* @__PURE__ */ jsx("span", { className: "text-right text-[13px] font-medium text-foreground", children: text }) : /* @__PURE__ */ jsx("span", { className: "text-[13px] text-muted-foreground/50", children: props.placeholder ?? "\u2014" })
|
|
@@ -1707,13 +2350,13 @@ function useTextField(props, bindings) {
|
|
|
1707
2350
|
props.value ?? void 0,
|
|
1708
2351
|
bindings?.value
|
|
1709
2352
|
);
|
|
1710
|
-
const [localValue, setLocalValue] =
|
|
2353
|
+
const [localValue, setLocalValue] = React2.useState("");
|
|
1711
2354
|
const isBound = Boolean(bindings?.value);
|
|
1712
2355
|
const value = isBound ? boundValue ?? "" : localValue;
|
|
1713
2356
|
const setValue = isBound ? setBoundValue : setLocalValue;
|
|
1714
2357
|
const validateOn = props.validateOn ?? "blur";
|
|
1715
2358
|
const hasValidation = Boolean(bindings?.value && props.checks?.length);
|
|
1716
|
-
const { errors, validate } =
|
|
2359
|
+
const { errors, validate, focusRef } = useCheckedField(
|
|
1717
2360
|
bindings?.value ?? "",
|
|
1718
2361
|
hasValidation ? { checks: props.checks ?? [], validateOn } : void 0
|
|
1719
2362
|
);
|
|
@@ -1724,7 +2367,7 @@ function useTextField(props, bindings) {
|
|
|
1724
2367
|
const onBlur = () => {
|
|
1725
2368
|
if (hasValidation && validateOn === "blur") validate();
|
|
1726
2369
|
};
|
|
1727
|
-
return { value, errors, onChange, onBlur };
|
|
2370
|
+
return { value, errors, onChange, onBlur, focusRef };
|
|
1728
2371
|
}
|
|
1729
2372
|
function BrandInput({
|
|
1730
2373
|
props,
|
|
@@ -1743,7 +2386,9 @@ function BrandInput({
|
|
|
1743
2386
|
type: props.type ?? "text",
|
|
1744
2387
|
value: field.value,
|
|
1745
2388
|
placeholder: props.placeholder ?? "",
|
|
2389
|
+
ref: field.focusRef,
|
|
1746
2390
|
"aria-invalid": field.errors.length > 0 || void 0,
|
|
2391
|
+
"aria-describedby": field.errors[0] ? `${id}-error` : void 0,
|
|
1747
2392
|
onChange: (event) => field.onChange(event.target.value),
|
|
1748
2393
|
onBlur: () => {
|
|
1749
2394
|
field.onBlur();
|
|
@@ -1756,7 +2401,7 @@ function BrandInput({
|
|
|
1756
2401
|
className: cn(fieldControlClass, "h-11 px-3.5")
|
|
1757
2402
|
}
|
|
1758
2403
|
),
|
|
1759
|
-
field.errors[0] ? /* @__PURE__ */ jsx("p", { role: "alert", className: "text-[11px] text-destructive", children: field.errors[0] }) : null
|
|
2404
|
+
field.errors[0] ? /* @__PURE__ */ jsx("p", { id: `${id}-error`, role: "alert", className: "text-[11px] text-destructive", children: field.errors[0] }) : null
|
|
1760
2405
|
] });
|
|
1761
2406
|
}
|
|
1762
2407
|
function BrandTextarea({
|
|
@@ -1775,13 +2420,15 @@ function BrandTextarea({
|
|
|
1775
2420
|
rows: props.rows ?? 3,
|
|
1776
2421
|
value: field.value,
|
|
1777
2422
|
placeholder: props.placeholder ?? "",
|
|
2423
|
+
ref: field.focusRef,
|
|
1778
2424
|
"aria-invalid": field.errors.length > 0 || void 0,
|
|
2425
|
+
"aria-describedby": field.errors[0] ? `${id}-error` : void 0,
|
|
1779
2426
|
onChange: (event) => field.onChange(event.target.value),
|
|
1780
2427
|
onBlur: field.onBlur,
|
|
1781
2428
|
className: cn(fieldControlClass, "px-3.5 py-2.5 leading-relaxed")
|
|
1782
2429
|
}
|
|
1783
2430
|
),
|
|
1784
|
-
field.errors[0] ? /* @__PURE__ */ jsx("p", { role: "alert", className: "text-[11px] text-destructive", children: field.errors[0] }) : null
|
|
2431
|
+
field.errors[0] ? /* @__PURE__ */ jsx("p", { id: `${id}-error`, role: "alert", className: "text-[11px] text-destructive", children: field.errors[0] }) : null
|
|
1785
2432
|
] });
|
|
1786
2433
|
}
|
|
1787
2434
|
var { registry: generativeRegistry } = defineRegistry(catalog, {
|
|
@@ -1815,28 +2462,29 @@ function GenerativePage({
|
|
|
1815
2462
|
onElementError
|
|
1816
2463
|
}) {
|
|
1817
2464
|
const { inputs, result, env, idPrefix } = scope;
|
|
1818
|
-
const stableScope =
|
|
2465
|
+
const stableScope = React2.useMemo(
|
|
1819
2466
|
() => ({ inputs, result, env, idPrefix }),
|
|
1820
2467
|
[inputs, result, env, idPrefix]
|
|
1821
2468
|
);
|
|
1822
|
-
const latest =
|
|
1823
|
-
|
|
2469
|
+
const latest = React2.useRef({ onRun, store });
|
|
2470
|
+
React2.useEffect(() => {
|
|
1824
2471
|
latest.current = { onRun, store };
|
|
1825
2472
|
});
|
|
1826
|
-
const report =
|
|
1827
|
-
|
|
2473
|
+
const report = React2.useRef(onElementError);
|
|
2474
|
+
React2.useInsertionEffect(() => {
|
|
1828
2475
|
report.current = onElementError;
|
|
1829
2476
|
});
|
|
1830
|
-
const [made] =
|
|
1831
|
-
const pageRegistry =
|
|
2477
|
+
const [made] = React2.useState(() => /* @__PURE__ */ new Map());
|
|
2478
|
+
const pageRegistry = React2.useMemo(
|
|
1832
2479
|
() => reportingRegistry(registry, report, made),
|
|
1833
2480
|
[registry, made]
|
|
1834
2481
|
);
|
|
1835
2482
|
const rootType = spec?.elements?.[spec.root]?.type ?? "root";
|
|
1836
|
-
const specContent = React5.useMemo(() => contentOf(spec), [spec]);
|
|
1837
2483
|
const reporting = onElementError !== void 0;
|
|
1838
|
-
const
|
|
1839
|
-
const [
|
|
2484
|
+
const validation = React2.useRef(null);
|
|
2485
|
+
const [checkedFields] = React2.useState(() => new CheckedFields());
|
|
2486
|
+
const running = React2.useRef(false);
|
|
2487
|
+
const [handlers] = React2.useState(() => {
|
|
1840
2488
|
const release = () => {
|
|
1841
2489
|
setTimeout(() => {
|
|
1842
2490
|
running.current = false;
|
|
@@ -1845,6 +2493,8 @@ function GenerativePage({
|
|
|
1845
2493
|
return {
|
|
1846
2494
|
run: () => {
|
|
1847
2495
|
if (running.current) return void 0;
|
|
2496
|
+
const checks = validation.current;
|
|
2497
|
+
if (checks && !checkedFields.check(checks)) return void 0;
|
|
1848
2498
|
running.current = true;
|
|
1849
2499
|
let pending;
|
|
1850
2500
|
try {
|
|
@@ -1863,33 +2513,50 @@ function GenerativePage({
|
|
|
1863
2513
|
}
|
|
1864
2514
|
};
|
|
1865
2515
|
});
|
|
1866
|
-
const page = /* @__PURE__ */ jsx(DescriptorProvider, { scope: stableScope, children: /* @__PURE__ */ jsx(
|
|
1867
|
-
|
|
2516
|
+
const page = /* @__PURE__ */ jsx(DescriptorProvider, { scope: stableScope, children: /* @__PURE__ */ jsx(PlacedInputsProvider, { spec, children: /* @__PURE__ */ jsx(
|
|
2517
|
+
JSONUIProvider,
|
|
1868
2518
|
{
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
children: /* @__PURE__ */ jsx(
|
|
2519
|
+
registry: pageRegistry,
|
|
2520
|
+
store,
|
|
2521
|
+
handlers,
|
|
2522
|
+
validationFunctions: CHECKED_FIELD_FUNCTIONS,
|
|
2523
|
+
children: /* @__PURE__ */ jsx(ReportingContext.Provider, { value: reporting, children: /* @__PURE__ */ jsxs(CheckedFieldsContext.Provider, { value: checkedFields, children: [
|
|
2524
|
+
/* @__PURE__ */ jsx(ValidationBridge, { into: validation, fields: checkedFields }),
|
|
2525
|
+
/* @__PURE__ */ jsx(
|
|
2526
|
+
RootBoundary,
|
|
2527
|
+
{
|
|
2528
|
+
type: rootType,
|
|
2529
|
+
report,
|
|
2530
|
+
reporting,
|
|
2531
|
+
loading: loading === true,
|
|
2532
|
+
spec,
|
|
2533
|
+
children: /* @__PURE__ */ jsx(Renderer, { spec, registry: pageRegistry, loading })
|
|
2534
|
+
}
|
|
2535
|
+
)
|
|
2536
|
+
] }) })
|
|
1874
2537
|
}
|
|
1875
|
-
) }) })
|
|
2538
|
+
) }) });
|
|
1876
2539
|
return brand ? /* @__PURE__ */ jsx(BrandProvider, { manifest: brand, children: page }) : page;
|
|
1877
2540
|
}
|
|
1878
|
-
function
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
2541
|
+
function ValidationBridge({
|
|
2542
|
+
into,
|
|
2543
|
+
fields
|
|
2544
|
+
}) {
|
|
2545
|
+
const validation = useOptionalValidation();
|
|
2546
|
+
React2.useInsertionEffect(() => {
|
|
2547
|
+
into.current = validation;
|
|
2548
|
+
fields.attach(validation);
|
|
2549
|
+
});
|
|
2550
|
+
return null;
|
|
1884
2551
|
}
|
|
1885
2552
|
function useStoreSnapshot(store) {
|
|
1886
|
-
return
|
|
2553
|
+
return React2.useSyncExternalStore(
|
|
1887
2554
|
store.subscribe,
|
|
1888
2555
|
store.getSnapshot,
|
|
1889
2556
|
store.getServerSnapshot ?? store.getSnapshot
|
|
1890
2557
|
);
|
|
1891
2558
|
}
|
|
1892
2559
|
|
|
1893
|
-
export { BrandBar, BrandProvider, DescriptorProvider, FrameHostProvider, GenerativePage, ResultSlotProvider, domIdFor, generativeRegistry, generativeRenderers, pathFromDomId, useBrand, useDescriptorScope, useFrameHost, useResultSlot, useStoreSnapshot };
|
|
2560
|
+
export { BrandBar, BrandProvider, DescriptorProvider, FrameHostProvider, GenerativePage, ResultSlotProvider, RevealPanel, domIdFor, generativeRegistry, generativeRenderers, pathFromDomId, useBrand, useCheckedField, useDescriptorScope, useFrameHost, useResultSlot, useStoreSnapshot };
|
|
1894
2561
|
//# sourceMappingURL=index.js.map
|
|
1895
2562
|
//# sourceMappingURL=index.js.map
|