@contractspec/lib.contracts-runtime-client-react 3.8.5 → 3.9.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.
@@ -1,103 +1,2 @@
1
1
  // @bun
2
- var __require = import.meta.require;
3
-
4
- // src/transform-engine.ts
5
- import {
6
- createDefaultTransformEngine,
7
- htmlToMarkdown,
8
- registerBasicValidation
9
- } from "@contractspec/lib.presentation-runtime-core/transform-engine";
10
- import React from "react";
11
-
12
- export * from "@contractspec/lib.presentation-runtime-core/transform-engine";
13
- function registerDefaultReactRenderer(engine) {
14
- engine.register({
15
- target: "react",
16
- async render(desc) {
17
- if (desc.source.type === "component") {
18
- const props = desc.source.props ? desc.source.props.getZod().safeParse({}).success ? {} : undefined : undefined;
19
- return {
20
- kind: "react_component",
21
- componentKey: desc.source.componentKey,
22
- props
23
- };
24
- }
25
- return {
26
- kind: "blocknotejs",
27
- docJson: desc.source.docJson,
28
- blockConfig: desc.source.blockConfig
29
- };
30
- }
31
- });
32
- return engine;
33
- }
34
- function registerReactToMarkdownRenderer(engine, componentMap) {
35
- engine.prependRegister({
36
- target: "markdown",
37
- async render(desc) {
38
- if (desc.source.type !== "component") {
39
- throw new Error("React-to-markdown renderer only handles component presentations");
40
- }
41
- const Component = componentMap[desc.source.componentKey];
42
- if (!Component) {
43
- throw new Error(`Component ${desc.source.componentKey} not found in componentMap`);
44
- }
45
- const { renderToStaticMarkup } = await import("react-dom/server");
46
- const element = React.createElement(Component, desc.source.props ? {} : undefined);
47
- const markdown = htmlToMarkdown(renderToStaticMarkup(element));
48
- return {
49
- mimeType: "text/markdown",
50
- body: desc.policy?.pii?.length ? markdown.replace(/\[REDACTED\]/g, "[REDACTED]") : markdown
51
- };
52
- }
53
- });
54
- return engine;
55
- }
56
-
57
- // src/feature-render.ts
58
- import React2 from "react";
59
- function createEngineWithDefaults() {
60
- return registerBasicValidation(registerDefaultReactRenderer(createDefaultTransformEngine()));
61
- }
62
- async function renderFeaturePresentation(engine, target, desc, options) {
63
- if (target === "react") {
64
- const rd = await engine.render("react", desc);
65
- if (rd.kind === "react_component") {
66
- const map = options?.componentMap ?? {};
67
- const C = map[rd.componentKey];
68
- if (!C)
69
- return null;
70
- const merged = {
71
- ...rd.props ?? {},
72
- ...options?.reactProps ?? {}
73
- };
74
- return React2.createElement(C, merged);
75
- }
76
- if (rd.kind === "blocknotejs") {
77
- if (options?.renderBlockNote)
78
- return options.renderBlockNote(rd.docJson, rd.blockConfig);
79
- return React2.createElement("div", {}, "[BlockNote renderer not configured]");
80
- }
81
- return null;
82
- }
83
- if (target === "markdown")
84
- return engine.render(target, desc);
85
- if (target === "application/json")
86
- return engine.render(target, desc);
87
- if (target === "application/xml")
88
- return engine.render(target, desc);
89
- return null;
90
- }
91
- function createFeatureModule(meta, refs) {
92
- return { meta, ...refs };
93
- }
94
- function registerFeature(registry, feature) {
95
- registry.register(feature);
96
- return registry;
97
- }
98
- export {
99
- renderFeaturePresentation,
100
- registerFeature,
101
- createFeatureModule,
102
- createEngineWithDefaults
103
- };
2
+ var N=import.meta.require;import{createDefaultTransformEngine as H,htmlToMarkdown as O,registerBasicValidation as I}from"@contractspec/lib.presentation-runtime-core/transform-engine";import P from"react";export*from"@contractspec/lib.presentation-runtime-core/transform-engine";function J(q){return q.register({target:"react",async render(j){if(j.source.type==="component"){let x=j.source.props?j.source.props.getZod().safeParse({}).success?{}:void 0:void 0;return{kind:"react_component",componentKey:j.source.componentKey,props:x}}return{kind:"blocknotejs",docJson:j.source.docJson,blockConfig:j.source.blockConfig}}}),q}function X(q,j){return q.prependRegister({target:"markdown",async render(x){if(x.source.type!=="component")throw Error("React-to-markdown renderer only handles component presentations");let A=j[x.source.componentKey];if(!A)throw Error(`Component ${x.source.componentKey} not found in componentMap`);let{renderToStaticMarkup:z}=await import("react-dom/server"),G=P.createElement(A,x.source.props?{}:void 0),F=O(z(G));return{mimeType:"text/markdown",body:x.policy?.pii?.length?F.replace(/\[REDACTED\]/g,"[REDACTED]"):F}}}),q}import K from"react";function v(){return I(J(H()))}async function S(q,j,x,A){if(j==="react"){let z=await q.render("react",x);if(z.kind==="react_component"){let F=(A?.componentMap??{})[z.componentKey];if(!F)return null;let L={...z.props??{},...A?.reactProps??{}};return K.createElement(F,L)}if(z.kind==="blocknotejs"){if(A?.renderBlockNote)return A.renderBlockNote(z.docJson,z.blockConfig);return K.createElement("div",{},"[BlockNote renderer not configured]")}return null}if(j==="markdown")return q.render(j,x);if(j==="application/json")return q.render(j,x);if(j==="application/xml")return q.render(j,x);return null}function b(q,j){return{meta:q,...j}}function B(q,j){return q.register(j),q}export{S as renderFeaturePresentation,B as registerFeature,b as createFeatureModule,v as createEngineWithDefaults};
@@ -1,4 +1,4 @@
1
- import type { FormOption, FormSpec, FormValuesFor } from '@contractspec/lib.contracts-spec/forms';
1
+ import type { AddressFieldSpec, AddressFormValue, AutocompleteFieldSpec, AutocompleteOption, FormOption, FormSpec, FormValuesFor, PhoneFieldSpec, PhoneFormValue } from '@contractspec/lib.contracts-spec/forms';
2
2
  import type { AnySchemaModel } from '@contractspec/lib.schema';
3
3
  import React from 'react';
4
4
  export interface DriverSlots {
@@ -10,7 +10,7 @@ export interface DriverSlots {
10
10
  FieldLabel: React.ComponentType<React.PropsWithChildren<{
11
11
  htmlFor?: string;
12
12
  }>>;
13
- FieldDescription: React.ComponentType<React.PropsWithChildren<{}>>;
13
+ FieldDescription: React.ComponentType<React.PropsWithChildren<object>>;
14
14
  FieldError: React.ComponentType<{
15
15
  errors: {
16
16
  message?: string;
@@ -31,7 +31,7 @@ export interface DriverSlots {
31
31
  id?: string;
32
32
  name?: string;
33
33
  value?: unknown;
34
- onChange?: (v: unknown) => void;
34
+ onChange?: (value: unknown) => void;
35
35
  disabled?: boolean;
36
36
  'aria-invalid'?: boolean;
37
37
  options: FormOption[];
@@ -40,14 +40,14 @@ export interface DriverSlots {
40
40
  id?: string;
41
41
  name?: string;
42
42
  checked?: boolean;
43
- onCheckedChange?: (v: boolean) => void;
43
+ onCheckedChange?: (value: boolean) => void;
44
44
  disabled?: boolean;
45
45
  } & Record<string, unknown>>;
46
46
  RadioGroup: React.ComponentType<{
47
47
  id?: string;
48
48
  name?: string;
49
49
  value?: unknown;
50
- onValueChange?: (v: unknown) => void;
50
+ onValueChange?: (value: unknown) => void;
51
51
  disabled?: boolean;
52
52
  options: FormOption[];
53
53
  } & Record<string, unknown>>;
@@ -55,9 +55,80 @@ export interface DriverSlots {
55
55
  id?: string;
56
56
  name?: string;
57
57
  checked?: boolean;
58
- onCheckedChange?: (v: boolean) => void;
58
+ onCheckedChange?: (value: boolean) => void;
59
59
  disabled?: boolean;
60
60
  } & Record<string, unknown>>;
61
+ Autocomplete: React.ComponentType<{
62
+ id?: string;
63
+ name?: string;
64
+ disabled?: boolean;
65
+ readOnly?: boolean;
66
+ 'aria-invalid'?: boolean;
67
+ placeholder?: string;
68
+ multiple?: boolean;
69
+ query: string;
70
+ options: AutocompleteOption[];
71
+ selectedOptions: AutocompleteOption[];
72
+ onQueryChange?: (query: string) => void;
73
+ onSelectOption?: (option: AutocompleteOption) => void;
74
+ onRemoveOption?: (option: AutocompleteOption) => void;
75
+ }>;
76
+ AddressField: React.ComponentType<{
77
+ id?: string;
78
+ name?: string;
79
+ value?: AddressFormValue | null;
80
+ onChange?: (value: AddressFormValue) => void;
81
+ disabled?: boolean;
82
+ readOnly?: boolean;
83
+ 'aria-invalid'?: boolean;
84
+ parts?: AddressFieldSpec['parts'];
85
+ countryOptions?: FormOption[];
86
+ }>;
87
+ PhoneField: React.ComponentType<{
88
+ id?: string;
89
+ name?: string;
90
+ value?: PhoneFormValue | null;
91
+ onChange?: (value: PhoneFormValue) => void;
92
+ disabled?: boolean;
93
+ readOnly?: boolean;
94
+ 'aria-invalid'?: boolean;
95
+ parts?: PhoneFieldSpec['parts'];
96
+ countryOptions?: FormOption[];
97
+ }>;
98
+ DateField: React.ComponentType<{
99
+ id?: string;
100
+ name?: string;
101
+ value?: Date | null;
102
+ onChange?: (value: Date | null) => void;
103
+ disabled?: boolean;
104
+ readOnly?: boolean;
105
+ placeholder?: string;
106
+ minDate?: Date;
107
+ maxDate?: Date;
108
+ }>;
109
+ TimeField: React.ComponentType<{
110
+ id?: string;
111
+ name?: string;
112
+ value?: Date | null;
113
+ onChange?: (value: Date | null) => void;
114
+ disabled?: boolean;
115
+ readOnly?: boolean;
116
+ placeholder?: string;
117
+ is24Hour?: boolean;
118
+ }>;
119
+ DateTimeField: React.ComponentType<{
120
+ id?: string;
121
+ name?: string;
122
+ value?: Date | null;
123
+ onChange?: (value: Date | null) => void;
124
+ disabled?: boolean;
125
+ readOnly?: boolean;
126
+ datePlaceholder?: string;
127
+ timePlaceholder?: string;
128
+ minDate?: Date;
129
+ maxDate?: Date;
130
+ is24Hour?: boolean;
131
+ }>;
61
132
  Button: React.ComponentType<React.PropsWithChildren<{
62
133
  type?: 'button' | 'submit' | 'reset';
63
134
  variant?: string;
@@ -66,7 +137,7 @@ export interface DriverSlots {
66
137
  disabled?: boolean;
67
138
  }>>;
68
139
  }
69
- export type ResolverMap<TValues> = Record<string, (values: TValues, args?: unknown) => Promise<FormOption[]> | FormOption[]>;
140
+ export type ResolverMap<TValues> = Record<string, (values: TValues, args?: Record<string, unknown>) => Promise<readonly unknown[]> | readonly unknown[]>;
70
141
  export type ComputationMap<TValues> = Record<string, (values: TValues) => unknown>;
71
142
  export interface CreateRendererOptions<TValues = Record<string, unknown>> {
72
143
  driver: DriverSlots;
@@ -81,6 +152,8 @@ export interface RenderOptions<TValues = Record<string, unknown>> {
81
152
  defaultValues?: Partial<TValues>;
82
153
  overrides?: Partial<CreateRendererOptions<TValues>>;
83
154
  }
155
+ export declare function filterAutocompleteOptions(options: readonly AutocompleteOption[], query: string, searchKeys: string[]): AutocompleteOption[];
156
+ export declare function mapAutocompleteValue(option: AutocompleteOption, mapping: AutocompleteFieldSpec['valueMapping']): {};
84
157
  export declare function createFormRenderer<M extends AnySchemaModel = AnySchemaModel>(base: CreateRendererOptions<FormValuesFor<M>>): {
85
158
  render: (spec: FormSpec<M>, options?: RenderOptions<FormValuesFor<M>>) => import("react/jsx-runtime").JSX.Element;
86
159
  };
@@ -1,362 +1,2 @@
1
1
  // @bun
2
- var __require = import.meta.require;
3
-
4
- // src/form-render.impl.tsx
5
- import {
6
- buildZodWithRelations,
7
- evalPredicate
8
- } from "@contractspec/lib.contracts-spec/forms";
9
- import { zodResolver } from "@hookform/resolvers/zod";
10
- import React, { useEffect, useMemo, useState } from "react";
11
- import {
12
- Controller,
13
- useFieldArray,
14
- useForm
15
- } from "react-hook-form";
16
- import { jsxDEV, Fragment } from "react/jsx-dev-runtime";
17
- "use client";
18
- function toOptionsArray(src) {
19
- if (!src)
20
- return;
21
- if (Array.isArray(src))
22
- return { kind: "static", options: src };
23
- return src;
24
- }
25
- function getAtPath(values, path) {
26
- if (!path)
27
- return;
28
- const segs = path.replace(/\[(\d+)\]/g, ".$1").split(".").filter(Boolean);
29
- let cur = values;
30
- for (const s of segs) {
31
- if (cur == null)
32
- return;
33
- cur = cur[s];
34
- }
35
- return cur;
36
- }
37
- function makeDepsKey(values, deps) {
38
- if (!deps || deps.length === 0)
39
- return "[]";
40
- try {
41
- return JSON.stringify(deps.map((d) => getAtPath(values, d)));
42
- } catch {
43
- return "[]";
44
- }
45
- }
46
- function useResolvedOptions(values, source, resolvers) {
47
- const [opts, setOpts] = useState([]);
48
- const depKey = useMemo(() => {
49
- if (!source)
50
- return "nil";
51
- if (source.kind === "static")
52
- return JSON.stringify(source.options ?? []);
53
- return makeDepsKey(values, source.deps);
54
- }, [source, values]);
55
- useEffect(() => {
56
- let mounted = true;
57
- const run = async () => {
58
- if (!source)
59
- return setOpts([]);
60
- if (source.kind === "static")
61
- return setOpts([...source.options ?? []]);
62
- const fn = resolvers?.[source.resolverKey];
63
- if (!fn)
64
- return setOpts([]);
65
- const res = await fn(values, source.args);
66
- if (mounted)
67
- setOpts([...res ?? []]);
68
- };
69
- run();
70
- return () => {
71
- mounted = false;
72
- };
73
- }, [
74
- depKey,
75
- source && source.kind === "resolver" ? source.resolverKey : undefined
76
- ]);
77
- return opts;
78
- }
79
- function fieldPath(parent, name, arrayIndex) {
80
- if (!name)
81
- return parent ?? "";
82
- const child = typeof arrayIndex === "number" ? `${name.replace(/^\$index$/, String(arrayIndex))}` : name;
83
- return parent ? `${parent}${typeof arrayIndex === "number" ? `.${arrayIndex}` : ""}.${child}`.replace(/\.+/g, ".") : child;
84
- }
85
- function createFormRenderer(base) {
86
- const conf = base;
87
- const { driver } = conf;
88
- function InternalForm(props) {
89
- const { spec, options, merged } = props;
90
- const baseZod = useMemo(() => buildZodWithRelations(spec), [spec]);
91
- const form = useForm({
92
- ...merged.formOptions,
93
- resolver: zodResolver(baseZod),
94
- defaultValues: options?.defaultValues
95
- });
96
- const values = form.watch();
97
- const renderOne = (f, parent, arrayIndex) => {
98
- const DriverField = driver.Field;
99
- const DriverLabel = driver.FieldLabel;
100
- const DriverDesc = driver.FieldDescription;
101
- const DriverError = driver.FieldError;
102
- const name = fieldPath(parent, f.name, arrayIndex);
103
- const visible = evalPredicate(values, f.visibleWhen);
104
- const enabled = evalPredicate(values, f.enabledWhen);
105
- const invalid = Boolean(form.getFieldState(name)?.invalid);
106
- if (!visible)
107
- return null;
108
- const id = name?.replace(/\./g, "-");
109
- const commonWrapProps = {
110
- "data-invalid": invalid,
111
- hidden: !visible,
112
- disabled: !enabled
113
- };
114
- const labelNode = f.labelI18n ? /* @__PURE__ */ jsxDEV(DriverLabel, {
115
- htmlFor: id,
116
- children: f.labelI18n
117
- }, undefined, false, undefined, this) : null;
118
- const descNode = f.descriptionI18n ? /* @__PURE__ */ jsxDEV(DriverDesc, {
119
- children: f.descriptionI18n
120
- }, undefined, false, undefined, this) : null;
121
- if (f.kind === "group") {
122
- const children = f.fields.map((c, i) => /* @__PURE__ */ jsxDEV(React.Fragment, {
123
- children: renderOne(c, name, arrayIndex)
124
- }, `${name}-${i}`, false, undefined, this));
125
- return /* @__PURE__ */ jsxDEV(DriverField, {
126
- ...commonWrapProps,
127
- children: [
128
- labelNode,
129
- children,
130
- descNode
131
- ]
132
- }, undefined, true, undefined, this);
133
- }
134
- if (f.kind === "array") {
135
- return renderArray(f, parent);
136
- }
137
- return /* @__PURE__ */ jsxDEV(Controller, {
138
- name,
139
- control: form.control,
140
- render: ({ field, fieldState }) => {
141
- const err = fieldState.error ? [fieldState.error] : [];
142
- const ariaInvalid = fieldState.invalid || undefined;
143
- if (f.kind === "text") {
144
- const textField = f;
145
- const Input = driver.Input;
146
- return /* @__PURE__ */ jsxDEV(DriverField, {
147
- ...commonWrapProps,
148
- children: [
149
- labelNode,
150
- /* @__PURE__ */ jsxDEV(Input, {
151
- id,
152
- "aria-invalid": ariaInvalid,
153
- placeholder: f.placeholderI18n,
154
- autoComplete: textField.autoComplete,
155
- inputMode: textField.inputMode,
156
- maxLength: textField.maxLength,
157
- minLength: textField.minLength,
158
- disabled: !enabled,
159
- ...field,
160
- ...f.uiProps
161
- }, undefined, false, undefined, this),
162
- descNode,
163
- fieldState.invalid ? /* @__PURE__ */ jsxDEV(DriverError, {
164
- errors: err
165
- }, undefined, false, undefined, this) : null
166
- ]
167
- }, undefined, true, undefined, this);
168
- }
169
- if (f.kind === "textarea") {
170
- const textareaField = f;
171
- const Textarea = driver.Textarea;
172
- return /* @__PURE__ */ jsxDEV(DriverField, {
173
- ...commonWrapProps,
174
- children: [
175
- labelNode,
176
- /* @__PURE__ */ jsxDEV(Textarea, {
177
- id,
178
- "aria-invalid": ariaInvalid,
179
- placeholder: f.placeholderI18n,
180
- rows: textareaField.rows,
181
- maxLength: textareaField.maxLength,
182
- disabled: !enabled,
183
- ...field,
184
- ...f.uiProps
185
- }, undefined, false, undefined, this),
186
- descNode,
187
- fieldState.invalid ? /* @__PURE__ */ jsxDEV(DriverError, {
188
- errors: err
189
- }, undefined, false, undefined, this) : null
190
- ]
191
- }, undefined, true, undefined, this);
192
- }
193
- if (f.kind === "select") {
194
- const selectField = f;
195
- const Select = driver.Select;
196
- const src = toOptionsArray(selectField.options);
197
- const opts = useResolvedOptions(values, src, merged.resolvers);
198
- return /* @__PURE__ */ jsxDEV(DriverField, {
199
- ...commonWrapProps,
200
- children: [
201
- labelNode,
202
- /* @__PURE__ */ jsxDEV(Select, {
203
- id,
204
- name,
205
- "aria-invalid": ariaInvalid,
206
- disabled: !enabled,
207
- value: field.value,
208
- onChange: (v) => field.onChange(v),
209
- options: opts,
210
- ...f.uiProps
211
- }, undefined, false, undefined, this),
212
- descNode,
213
- fieldState.invalid ? /* @__PURE__ */ jsxDEV(DriverError, {
214
- errors: err
215
- }, undefined, false, undefined, this) : null
216
- ]
217
- }, undefined, true, undefined, this);
218
- }
219
- if (f.kind === "checkbox") {
220
- const Checkbox = driver.Checkbox;
221
- return /* @__PURE__ */ jsxDEV(DriverField, {
222
- ...commonWrapProps,
223
- children: [
224
- labelNode,
225
- /* @__PURE__ */ jsxDEV(Checkbox, {
226
- id,
227
- name,
228
- disabled: !enabled,
229
- checked: !!field.value,
230
- onCheckedChange: (v) => field.onChange(v),
231
- ...f.uiProps
232
- }, undefined, false, undefined, this),
233
- descNode,
234
- fieldState.invalid ? /* @__PURE__ */ jsxDEV(DriverError, {
235
- errors: err
236
- }, undefined, false, undefined, this) : null
237
- ]
238
- }, undefined, true, undefined, this);
239
- }
240
- if (f.kind === "radio") {
241
- const radioField = f;
242
- const RadioGroup = driver.RadioGroup;
243
- const src = toOptionsArray(radioField.options);
244
- const opts = useResolvedOptions(values, src, merged.resolvers);
245
- return /* @__PURE__ */ jsxDEV(DriverField, {
246
- ...commonWrapProps,
247
- children: [
248
- labelNode,
249
- /* @__PURE__ */ jsxDEV(RadioGroup, {
250
- id,
251
- name,
252
- disabled: !enabled,
253
- value: field.value,
254
- onValueChange: (v) => field.onChange(v),
255
- options: opts,
256
- ...f.uiProps
257
- }, undefined, false, undefined, this),
258
- descNode,
259
- fieldState.invalid ? /* @__PURE__ */ jsxDEV(DriverError, {
260
- errors: err
261
- }, undefined, false, undefined, this) : null
262
- ]
263
- }, undefined, true, undefined, this);
264
- }
265
- if (f.kind === "switch") {
266
- const Switch = driver.Switch;
267
- return /* @__PURE__ */ jsxDEV(DriverField, {
268
- ...commonWrapProps,
269
- children: [
270
- labelNode,
271
- /* @__PURE__ */ jsxDEV(Switch, {
272
- id,
273
- name,
274
- disabled: !enabled,
275
- checked: !!field.value,
276
- onCheckedChange: (v) => field.onChange(v),
277
- ...f.uiProps
278
- }, undefined, false, undefined, this),
279
- descNode,
280
- fieldState.invalid ? /* @__PURE__ */ jsxDEV(DriverError, {
281
- errors: err
282
- }, undefined, false, undefined, this) : null
283
- ]
284
- }, undefined, true, undefined, this);
285
- }
286
- return /* @__PURE__ */ jsxDEV(Fragment, {}, undefined, false, undefined, this);
287
- }
288
- }, name, false, undefined, this);
289
- };
290
- const renderArray = (f, parent) => {
291
- const name = fieldPath(parent, f.name);
292
- const { fields, append, remove } = useFieldArray({
293
- control: form.control,
294
- name
295
- });
296
- const canAdd = f.max == null || fields.length < f.max;
297
- const canRemove = (idx) => (f.min == null ? fields.length > 0 : fields.length > f.min) && idx >= 0;
298
- const Button2 = driver.Button;
299
- const Label = driver.FieldLabel;
300
- return /* @__PURE__ */ jsxDEV("div", {
301
- children: [
302
- f.labelI18n ? /* @__PURE__ */ jsxDEV(Label, {
303
- children: f.labelI18n
304
- }, undefined, false, undefined, this) : null,
305
- fields.map((row, idx) => /* @__PURE__ */ jsxDEV("div", {
306
- children: [
307
- renderOne(f.of, name, idx),
308
- canRemove(idx) ? /* @__PURE__ */ jsxDEV(Button2, {
309
- type: "button",
310
- variant: "ghost",
311
- size: "sm",
312
- onClick: () => remove(idx),
313
- children: "Remove"
314
- }, undefined, false, undefined, this) : null
315
- ]
316
- }, row.id ?? idx, true, undefined, this)),
317
- canAdd ? /* @__PURE__ */ jsxDEV(Button2, {
318
- type: "button",
319
- variant: "outline",
320
- size: "sm",
321
- onClick: () => append({}),
322
- children: "Add"
323
- }, undefined, false, undefined, this) : null
324
- ]
325
- }, name, true, undefined, this);
326
- };
327
- const onSubmit = async (data) => {
328
- const actionKey = spec.actions?.[0]?.key ?? "submit";
329
- if (merged.onSubmitOverride) {
330
- return merged.onSubmitOverride(data, actionKey);
331
- }
332
- };
333
- const Button = driver.Button;
334
- return /* @__PURE__ */ jsxDEV("form", {
335
- onSubmit: form.handleSubmit(onSubmit),
336
- children: [
337
- (spec.fields || []).map((f, i) => /* @__PURE__ */ jsxDEV(React.Fragment, {
338
- children: renderOne(f)
339
- }, i, false, undefined, this)),
340
- spec.actions && spec.actions.length ? /* @__PURE__ */ jsxDEV("div", {
341
- children: spec.actions.map((a) => /* @__PURE__ */ jsxDEV(Button, {
342
- type: "submit",
343
- children: a.labelI18n
344
- }, a.key, false, undefined, this))
345
- }, undefined, false, undefined, this) : null
346
- ]
347
- }, undefined, true, undefined, this);
348
- }
349
- return {
350
- render: (spec, options) => /* @__PURE__ */ jsxDEV(InternalForm, {
351
- spec,
352
- options,
353
- merged: {
354
- ...conf,
355
- ...options?.overrides ?? {}
356
- }
357
- }, undefined, false, undefined, this)
358
- };
359
- }
360
- export {
361
- createFormRenderer
362
- };
2
+ var TB=import.meta.require;import{buildZodWithRelations as d,evalPredicate as m,isFieldReadOnly as t,normalizeFormSpec as i}from"@contractspec/lib.contracts-spec/forms";import{zodResolver as l}from"@hookform/resolvers/zod";import V from"react";import{Controller as A,useFieldArray as s,useForm as o}from"react-hook-form";import{jsx as U,jsxs as q,Fragment as wB}from"react/jsx-runtime";function F(B){if(!B)return;if(Array.isArray(B))return{kind:"static",options:[...B]};return B}function y(B,G){if(!G)return;let Y=G.replace(/\[(\d+)\]/g,".$1").split(".").filter(Boolean),H=B;for(let J of Y){if(H==null)return;H=H[J]}return H}function r(B){if(!B)return[];return B.split(".").filter((G)=>/^\d+$/.test(G)).map((G)=>Number(G))}function u(B,G){if(!G)return B??"";return B?`${B}.${G}`:G}function f(B,G){if(!G||G.length===0)return"[]";try{return JSON.stringify(G.map((Y)=>y(B,Y)))}catch{return"[]"}}function e(B,G){let[Y,H]=V.useState(B);return V.useEffect(()=>{let J=globalThis.setTimeout(()=>H(B),G);return()=>globalThis.clearTimeout(J)},[G,B]),Y}function j(B,G,Y){let[H,J]=V.useState([]),_=V.useMemo(()=>{if(!G)return"nil";if(G.kind==="static")return JSON.stringify(G.options??[]);return`${G.resolverKey}:${f(B,G.deps)}`},[G,B]);return V.useEffect(()=>{let $=!0;return(async()=>{if(!G){J([]);return}if(G.kind==="static"){J([...G.options??[]]);return}let w=Y?.[G.resolverKey];if(!w){J([]);return}let b=await w(B,G.args);if($)J([...b??[]])})(),()=>{$=!1}},[_,Y,G,B]),H}function n(B){if(B instanceof Date&&!Number.isNaN(B.getTime()))return B;if(typeof B==="string"||typeof B==="number"){let G=new Date(B);if(!Number.isNaN(G.getTime()))return G}return null}function p(B){if(B instanceof Date&&!Number.isNaN(B.getTime()))return B;if(typeof B!=="string"||B.trim().length===0)return null;let[G,Y]=B.split(":").map(($)=>Number($)),H=G??Number.NaN,J=Y??Number.NaN;if(Number.isNaN(H)||Number.isNaN(J))return null;let _=new Date;return _.setHours(H,J,0,0),_}function BB(B){if(!B)return"";return`${String(B.getHours()).padStart(2,"0")}:${String(B.getMinutes()).padStart(2,"0")}`}function a(B){return{value:B.value,labelI18n:B.labelI18n,descriptionI18n:B.descriptionI18n,...B.data??{}}}function GB(B,G,Y){let H=G.trim().toLowerCase();if(!H)return[...B];let J=H.split(/\s+/).filter(Boolean);return B.filter((_)=>{let $=a(_),L=[_.labelI18n,_.descriptionI18n,String(_.value),...Y.map((w)=>String(y($,w)??""))].join(" ").toLowerCase();return J.every((w)=>L.includes(w))})}function x(B,G){let Y=a(B);switch(G.mode){case"scalar":return G.valueKey?y(Y,G.valueKey)??B.value:B.value;case"pick":return Object.fromEntries(G.pickKeys.map((H)=>[H,y(Y,H)]));case"object":default:return B.data??Y}}function v(B,G){try{return JSON.stringify(B)===JSON.stringify(G)}catch{return B===G}}function HB(B,G,Y,H){let J=H&&Array.isArray(G)?G:[G];return B.filter((_)=>J.some(($)=>v(x(_,Y),$)))}function c(B){if(!B)return{countryCode:"",nationalNumber:""};let G=B.countryCode.trim(),Y=B.nationalNumber.replace(/\s+/g,""),H=G.replace(/^\+?/,"+"),J={...B,countryCode:G,nationalNumber:B.nationalNumber};if(B.e164!=null||G||Y)J.e164=`${H}${Y}`.trim();return J}function JB(B){let G=j(B.values,F(B.spec.options),B.resolvers),Y=B.driver.Field,H=B.driver.FieldError;return U(A,{name:B.ctx.name,control:B.form.control,render:({field:J,fieldState:_})=>{let $=_.error?[_.error]:[];return q(Y,{...B.commonWrapProps,children:[B.labelNode,U(B.driver.Select,{id:B.ctx.id,name:B.ctx.name,"aria-invalid":_.invalid||void 0,disabled:!B.ctx.enabled||B.ctx.readOnly,value:J.value,onChange:(L)=>{if(B.ctx.readOnly)return;J.onChange(L)},options:G,...B.spec.uiProps}),B.descNode,_.invalid?U(H,{errors:$}):null]})}})}function UB(B){let G=j(B.values,F(B.spec.options),B.resolvers),Y=B.driver.Field,H=B.driver.FieldError;return U(A,{name:B.ctx.name,control:B.form.control,render:({field:J,fieldState:_})=>{let $=_.error?[_.error]:[];return q(Y,{...B.commonWrapProps,children:[B.labelNode,U(B.driver.RadioGroup,{id:B.ctx.id,name:B.ctx.name,disabled:!B.ctx.enabled||B.ctx.readOnly,value:J.value,onValueChange:(L)=>{if(B.ctx.readOnly)return;J.onChange(L)},options:G,...B.spec.uiProps}),B.descNode,_.invalid?U(H,{errors:$}):null]})}})}function XB(B){let[G,Y]=V.useState(""),H=B.spec.source.kind==="resolver"?B.spec.source.debounceMs??200:0,J=e(G,H),[_,$]=V.useState([]),L=V.useMemo(()=>{return B.spec.source.kind==="resolver"?`${B.spec.source.resolverKey}:${f(B.values,B.spec.source.deps)}:${J}`:"local"},[J,B.spec.source,B.values]);V.useEffect(()=>{if(B.spec.source.kind!=="resolver")return;let Z=B.resolvers?.[B.spec.source.resolverKey],k=B.spec.source.minQueryLength??0;if(!Z||J.trim().length<k){$([]);return}let g=!0,D={...B.spec.source.args??{},query:J};return Promise.resolve(Z(B.values,D)).then((C)=>{if(g)$([...C??[]])}),()=>{g=!1}},[L,B.resolvers,B.spec.source,B.values,J]);let w=B.spec.source.kind==="local"?GB(B.spec.source.options,G,B.spec.source.searchKeys):_,b=B.driver.Field,X=B.driver.FieldError;return U(A,{name:B.ctx.name,control:B.form.control,render:({field:Z,fieldState:k})=>{let g=k.error?[k.error]:[],D=HB(w,Z.value,B.spec.valueMapping,B.spec.multiple),C=(O)=>{if(B.ctx.readOnly)return;let W=x(O,B.spec.valueMapping);if(B.spec.multiple){let P=Array.isArray(Z.value)?Z.value:[],R=P.some((S)=>v(S,W));Z.onChange(R?P:[...P,W]);return}Z.onChange(W),Y(O.labelI18n)},T=(O)=>{if(B.ctx.readOnly||!B.spec.multiple)return;let W=x(O,B.spec.valueMapping),P=Array.isArray(Z.value)?Z.value:[];Z.onChange(P.filter((R)=>!v(R,W)))};return q(b,{...B.commonWrapProps,children:[B.labelNode,U(B.driver.Autocomplete,{id:B.ctx.id,name:B.ctx.name,disabled:!B.ctx.enabled,readOnly:B.ctx.readOnly,"aria-invalid":k.invalid||void 0,placeholder:B.spec.placeholderI18n,multiple:B.spec.multiple,query:G,options:w,selectedOptions:D,onQueryChange:Y,onSelectOption:C,onRemoveOption:T}),B.descNode,k.invalid?U(X,{errors:g}):null]})}})}function YB(B){let G=j(B.values,F(B.spec.countryOptions),B.resolvers),Y=B.driver.Field,H=B.driver.FieldError;return U(A,{name:B.ctx.name,control:B.form.control,render:({field:J,fieldState:_})=>{let $=_.error?[_.error]:[];return q(Y,{...B.commonWrapProps,children:[B.labelNode,U(B.driver.AddressField,{id:B.ctx.id,name:B.ctx.name,value:J.value??null,onChange:(L)=>{if(B.ctx.readOnly)return;J.onChange(L)},disabled:!B.ctx.enabled,readOnly:B.ctx.readOnly,"aria-invalid":_.invalid||void 0,parts:B.spec.parts,countryOptions:G}),B.descNode,_.invalid?U(H,{errors:$}):null]})}})}function _B(B){let G=j(B.values,F(B.spec.countryOptions),B.resolvers),Y=B.driver.Field,H=B.driver.FieldError;return U(A,{name:B.ctx.name,control:B.form.control,render:({field:J,fieldState:_})=>{let $=_.error?[_.error]:[];return q(Y,{...B.commonWrapProps,children:[B.labelNode,U(B.driver.PhoneField,{id:B.ctx.id,name:B.ctx.name,value:c(J.value??null),onChange:(L)=>{if(B.ctx.readOnly)return;J.onChange(c(L))},disabled:!B.ctx.enabled,readOnly:B.ctx.readOnly,"aria-invalid":_.invalid||void 0,parts:B.spec.parts,countryOptions:G}),B.descNode,_.invalid?U(H,{errors:$}):null]})}})}function $B(B){let G=B.driver.Field,Y=B.driver.FieldError;return U(A,{name:B.ctx.name,control:B.form.control,render:({field:H,fieldState:J})=>{let _=J.error?[J.error]:[];return q(G,{...B.commonWrapProps,children:[B.labelNode,U(B.driver.DateField,{id:B.ctx.id,name:B.ctx.name,value:n(H.value),onChange:($)=>{if(B.ctx.readOnly)return;H.onChange($)},disabled:!B.ctx.enabled,readOnly:B.ctx.readOnly,placeholder:B.spec.placeholderI18n,minDate:B.spec.minDate,maxDate:B.spec.maxDate}),B.descNode,J.invalid?U(Y,{errors:_}):null]})}})}function IB(B){let G=B.driver.Field,Y=B.driver.FieldError;return U(A,{name:B.ctx.name,control:B.form.control,render:({field:H,fieldState:J})=>{let _=J.error?[J.error]:[];return q(G,{...B.commonWrapProps,children:[B.labelNode,U(B.driver.TimeField,{id:B.ctx.id,name:B.ctx.name,value:p(H.value),onChange:($)=>{if(B.ctx.readOnly)return;H.onChange(BB($))},disabled:!B.ctx.enabled,readOnly:B.ctx.readOnly,placeholder:B.spec.placeholderI18n,is24Hour:B.spec.is24Hour}),B.descNode,J.invalid?U(Y,{errors:_}):null]})}})}function LB(B){let G=B.driver.Field,Y=B.driver.FieldError;return U(A,{name:B.ctx.name,control:B.form.control,render:({field:H,fieldState:J})=>{let _=J.error?[J.error]:[];return q(G,{...B.commonWrapProps,children:[B.labelNode,U(B.driver.DateTimeField,{id:B.ctx.id,name:B.ctx.name,value:n(H.value),onChange:($)=>{if(B.ctx.readOnly)return;H.onChange($)},disabled:!B.ctx.enabled,readOnly:B.ctx.readOnly,datePlaceholder:B.spec.placeholderI18n,timePlaceholder:B.spec.placeholderI18n,minDate:B.spec.minDate,maxDate:B.spec.maxDate,is24Hour:B.spec.is24Hour}),B.descNode,J.invalid?U(Y,{errors:_}):null]})}})}function ZB(B){let G=u(B.parent,B.spec.name),{fields:Y,append:H,remove:J}=s({control:B.form.control,name:G}),_=B.spec.max==null||Y.length<B.spec.max,$=(L)=>(B.spec.min==null?Y.length>0:Y.length>B.spec.min)&&L>=0;return q("div",{children:[B.spec.labelI18n?U(B.driver.FieldLabel,{children:B.spec.labelI18n}):null,Y.map((L,w)=>q("div",{children:[B.renderField(B.spec.of,`${G}.${w}`),$(w)?U(B.driver.Button,{type:"button",variant:"ghost",size:"sm",onClick:()=>J(w),children:"Remove"}):null]},L.id??w)),_?U(B.driver.Button,{type:"button",variant:"outline",size:"sm",onClick:()=>H({}),children:"Add"}):null]},G)}function kB(B){let G=B;function Y(H){let J=V.useMemo(()=>i(H.spec),[H.spec]),_=V.useMemo(()=>d(J),[J]),$=o({...H.merged.formOptions,resolver:l(_),defaultValues:H.options?.defaultValues}),L=$.watch(),w=(X,Z)=>{let k=H.merged.driver.Field,g=H.merged.driver.FieldLabel,D=H.merged.driver.FieldDescription,C=H.merged.driver.FieldError,T=u(Z,X.name),O=r(Z),W=m(L,X.visibleWhen,O),P=m(L,X.enabledWhen,O),R=t(X),S=Boolean($.getFieldState(T)?.invalid);if(!W)return null;let I={name:T,id:T.replace(/\./g,"-"),enabled:P,readOnly:R,visible:W},M={"data-invalid":S,hidden:!W,disabled:!P||R},K=X.labelI18n?U(g,{htmlFor:I.id,children:X.labelI18n}):null,Q=X.descriptionI18n?U(D,{children:X.descriptionI18n}):null;if(X.kind==="group")return q(k,{...M,children:[K,X.fields.map((N,z)=>U(V.Fragment,{children:w(N,T)},`${T}-${z}`)),Q]});if(X.kind==="array")return U(ZB,{driver:H.merged.driver,form:$,spec:X,parent:Z,renderField:w},T);if(X.kind==="select")return U(JB,{driver:H.merged.driver,form:$,values:L,spec:X,ctx:I,labelNode:K,descNode:Q,commonWrapProps:M,resolvers:H.merged.resolvers},T);if(X.kind==="radio")return U(UB,{driver:H.merged.driver,form:$,values:L,spec:X,ctx:I,labelNode:K,descNode:Q,commonWrapProps:M,resolvers:H.merged.resolvers},T);if(X.kind==="autocomplete")return U(XB,{driver:H.merged.driver,form:$,values:L,spec:X,ctx:I,labelNode:K,descNode:Q,commonWrapProps:M,resolvers:H.merged.resolvers},T);if(X.kind==="address")return U(YB,{driver:H.merged.driver,form:$,values:L,spec:X,ctx:I,labelNode:K,descNode:Q,commonWrapProps:M,resolvers:H.merged.resolvers},T);if(X.kind==="phone")return U(_B,{driver:H.merged.driver,form:$,values:L,spec:X,ctx:I,labelNode:K,descNode:Q,commonWrapProps:M,resolvers:H.merged.resolvers},T);if(X.kind==="date")return U($B,{driver:H.merged.driver,form:$,spec:X,ctx:I,labelNode:K,descNode:Q,commonWrapProps:M},T);if(X.kind==="time")return U(IB,{driver:H.merged.driver,form:$,spec:X,ctx:I,labelNode:K,descNode:Q,commonWrapProps:M},T);if(X.kind==="datetime")return U(LB,{driver:H.merged.driver,form:$,spec:X,ctx:I,labelNode:K,descNode:Q,commonWrapProps:M},T);return U(A,{name:T,control:$.control,render:({field:N,fieldState:z})=>{let h=z.error?[z.error]:[];if(X.kind==="text"){let E=X;return q(k,{...M,children:[K,U(H.merged.driver.Input,{id:I.id,"aria-invalid":z.invalid||void 0,placeholder:X.placeholderI18n,autoComplete:E.autoComplete,inputMode:E.inputMode,maxLength:E.maxLength,minLength:E.minLength,disabled:!I.enabled,readOnly:I.readOnly,...N,...X.uiProps}),Q,z.invalid?U(C,{errors:h}):null]})}if(X.kind==="textarea"){let E=X;return q(k,{...M,children:[K,U(H.merged.driver.Textarea,{id:I.id,"aria-invalid":z.invalid||void 0,placeholder:X.placeholderI18n,rows:E.rows,maxLength:E.maxLength,disabled:!I.enabled,readOnly:I.readOnly,...N,...X.uiProps}),Q,z.invalid?U(C,{errors:h}):null]})}if(X.kind==="checkbox")return q(k,{...M,children:[K,U(H.merged.driver.Checkbox,{id:I.id,name:I.name,disabled:!I.enabled||I.readOnly,checked:Boolean(N.value),onCheckedChange:(E)=>{if(I.readOnly)return;N.onChange(E)},...X.uiProps}),Q,z.invalid?U(C,{errors:h}):null]});if(X.kind==="switch")return q(k,{...M,children:[K,U(H.merged.driver.Switch,{id:I.id,name:I.name,disabled:!I.enabled||I.readOnly,checked:Boolean(N.value),onCheckedChange:(E)=>{if(I.readOnly)return;N.onChange(E)},...X.uiProps}),Q,z.invalid?U(C,{errors:h}):null]});return U(wB,{})}},T)},b=async(X)=>{let Z=J.actions?.[0]?.key??"submit";if(H.merged.onSubmitOverride)return H.merged.onSubmitOverride(X,Z)};return q("form",{onSubmit:$.handleSubmit(b),children:[J.fields.map((X,Z)=>U(V.Fragment,{children:w(X)},Z)),J.actions?.length?U("div",{children:J.actions.map((X)=>U(H.merged.driver.Button,{type:"submit",children:X.labelI18n},X.key))}):null]})}return{render:(H,J)=>U(Y,{spec:H,options:J,merged:{...G,...J?.overrides??{}}})}}export{x as mapAutocompleteValue,GB as filterAutocompleteOptions,kB as createFormRenderer};
@@ -0,0 +1 @@
1
+ export {};