@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,475 +1 @@
1
- import { createRequire } from "node:module";
2
- var __require = /* @__PURE__ */ createRequire(import.meta.url);
3
-
4
- // src/drivers/rn-reusables.ts
5
- function rnReusablesDriver(slots) {
6
- return slots;
7
- }
8
-
9
- // src/drivers/shadcn.ts
10
- function shadcnDriver(slots) {
11
- return slots;
12
- }
13
-
14
- // src/transform-engine.ts
15
- import {
16
- createDefaultTransformEngine,
17
- htmlToMarkdown,
18
- registerBasicValidation
19
- } from "@contractspec/lib.presentation-runtime-core/transform-engine";
20
- import React from "react";
21
-
22
- export * from "@contractspec/lib.presentation-runtime-core/transform-engine";
23
- function registerDefaultReactRenderer(engine) {
24
- engine.register({
25
- target: "react",
26
- async render(desc) {
27
- if (desc.source.type === "component") {
28
- const props = desc.source.props ? desc.source.props.getZod().safeParse({}).success ? {} : undefined : undefined;
29
- return {
30
- kind: "react_component",
31
- componentKey: desc.source.componentKey,
32
- props
33
- };
34
- }
35
- return {
36
- kind: "blocknotejs",
37
- docJson: desc.source.docJson,
38
- blockConfig: desc.source.blockConfig
39
- };
40
- }
41
- });
42
- return engine;
43
- }
44
- function registerReactToMarkdownRenderer(engine, componentMap) {
45
- engine.prependRegister({
46
- target: "markdown",
47
- async render(desc) {
48
- if (desc.source.type !== "component") {
49
- throw new Error("React-to-markdown renderer only handles component presentations");
50
- }
51
- const Component = componentMap[desc.source.componentKey];
52
- if (!Component) {
53
- throw new Error(`Component ${desc.source.componentKey} not found in componentMap`);
54
- }
55
- const { renderToStaticMarkup } = await import("react-dom/server");
56
- const element = React.createElement(Component, desc.source.props ? {} : undefined);
57
- const markdown = htmlToMarkdown(renderToStaticMarkup(element));
58
- return {
59
- mimeType: "text/markdown",
60
- body: desc.policy?.pii?.length ? markdown.replace(/\[REDACTED\]/g, "[REDACTED]") : markdown
61
- };
62
- }
63
- });
64
- return engine;
65
- }
66
-
67
- // src/feature-render.ts
68
- import React2 from "react";
69
- function createEngineWithDefaults() {
70
- return registerBasicValidation(registerDefaultReactRenderer(createDefaultTransformEngine()));
71
- }
72
- async function renderFeaturePresentation(engine, target, desc, options) {
73
- if (target === "react") {
74
- const rd = await engine.render("react", desc);
75
- if (rd.kind === "react_component") {
76
- const map = options?.componentMap ?? {};
77
- const C = map[rd.componentKey];
78
- if (!C)
79
- return null;
80
- const merged = {
81
- ...rd.props ?? {},
82
- ...options?.reactProps ?? {}
83
- };
84
- return React2.createElement(C, merged);
85
- }
86
- if (rd.kind === "blocknotejs") {
87
- if (options?.renderBlockNote)
88
- return options.renderBlockNote(rd.docJson, rd.blockConfig);
89
- return React2.createElement("div", {}, "[BlockNote renderer not configured]");
90
- }
91
- return null;
92
- }
93
- if (target === "markdown")
94
- return engine.render(target, desc);
95
- if (target === "application/json")
96
- return engine.render(target, desc);
97
- if (target === "application/xml")
98
- return engine.render(target, desc);
99
- return null;
100
- }
101
- function createFeatureModule(meta, refs) {
102
- return { meta, ...refs };
103
- }
104
- function registerFeature(registry, feature) {
105
- registry.register(feature);
106
- return registry;
107
- }
108
-
109
- // src/form-render.impl.tsx
110
- import {
111
- buildZodWithRelations,
112
- evalPredicate
113
- } from "@contractspec/lib.contracts-spec/forms";
114
- import { zodResolver } from "@hookform/resolvers/zod";
115
- import React3, { useEffect, useMemo, useState } from "react";
116
- import {
117
- Controller,
118
- useFieldArray,
119
- useForm
120
- } from "react-hook-form";
121
- import { jsxDEV, Fragment } from "react/jsx-dev-runtime";
122
- "use client";
123
- function toOptionsArray(src) {
124
- if (!src)
125
- return;
126
- if (Array.isArray(src))
127
- return { kind: "static", options: src };
128
- return src;
129
- }
130
- function getAtPath(values, path) {
131
- if (!path)
132
- return;
133
- const segs = path.replace(/\[(\d+)\]/g, ".$1").split(".").filter(Boolean);
134
- let cur = values;
135
- for (const s of segs) {
136
- if (cur == null)
137
- return;
138
- cur = cur[s];
139
- }
140
- return cur;
141
- }
142
- function makeDepsKey(values, deps) {
143
- if (!deps || deps.length === 0)
144
- return "[]";
145
- try {
146
- return JSON.stringify(deps.map((d) => getAtPath(values, d)));
147
- } catch {
148
- return "[]";
149
- }
150
- }
151
- function useResolvedOptions(values, source, resolvers) {
152
- const [opts, setOpts] = useState([]);
153
- const depKey = useMemo(() => {
154
- if (!source)
155
- return "nil";
156
- if (source.kind === "static")
157
- return JSON.stringify(source.options ?? []);
158
- return makeDepsKey(values, source.deps);
159
- }, [source, values]);
160
- useEffect(() => {
161
- let mounted = true;
162
- const run = async () => {
163
- if (!source)
164
- return setOpts([]);
165
- if (source.kind === "static")
166
- return setOpts([...source.options ?? []]);
167
- const fn = resolvers?.[source.resolverKey];
168
- if (!fn)
169
- return setOpts([]);
170
- const res = await fn(values, source.args);
171
- if (mounted)
172
- setOpts([...res ?? []]);
173
- };
174
- run();
175
- return () => {
176
- mounted = false;
177
- };
178
- }, [
179
- depKey,
180
- source && source.kind === "resolver" ? source.resolverKey : undefined
181
- ]);
182
- return opts;
183
- }
184
- function fieldPath(parent, name, arrayIndex) {
185
- if (!name)
186
- return parent ?? "";
187
- const child = typeof arrayIndex === "number" ? `${name.replace(/^\$index$/, String(arrayIndex))}` : name;
188
- return parent ? `${parent}${typeof arrayIndex === "number" ? `.${arrayIndex}` : ""}.${child}`.replace(/\.+/g, ".") : child;
189
- }
190
- function createFormRenderer(base) {
191
- const conf = base;
192
- const { driver } = conf;
193
- function InternalForm(props) {
194
- const { spec, options, merged } = props;
195
- const baseZod = useMemo(() => buildZodWithRelations(spec), [spec]);
196
- const form = useForm({
197
- ...merged.formOptions,
198
- resolver: zodResolver(baseZod),
199
- defaultValues: options?.defaultValues
200
- });
201
- const values = form.watch();
202
- const renderOne = (f, parent, arrayIndex) => {
203
- const DriverField = driver.Field;
204
- const DriverLabel = driver.FieldLabel;
205
- const DriverDesc = driver.FieldDescription;
206
- const DriverError = driver.FieldError;
207
- const name = fieldPath(parent, f.name, arrayIndex);
208
- const visible = evalPredicate(values, f.visibleWhen);
209
- const enabled = evalPredicate(values, f.enabledWhen);
210
- const invalid = Boolean(form.getFieldState(name)?.invalid);
211
- if (!visible)
212
- return null;
213
- const id = name?.replace(/\./g, "-");
214
- const commonWrapProps = {
215
- "data-invalid": invalid,
216
- hidden: !visible,
217
- disabled: !enabled
218
- };
219
- const labelNode = f.labelI18n ? /* @__PURE__ */ jsxDEV(DriverLabel, {
220
- htmlFor: id,
221
- children: f.labelI18n
222
- }, undefined, false, undefined, this) : null;
223
- const descNode = f.descriptionI18n ? /* @__PURE__ */ jsxDEV(DriverDesc, {
224
- children: f.descriptionI18n
225
- }, undefined, false, undefined, this) : null;
226
- if (f.kind === "group") {
227
- const children = f.fields.map((c, i) => /* @__PURE__ */ jsxDEV(React3.Fragment, {
228
- children: renderOne(c, name, arrayIndex)
229
- }, `${name}-${i}`, false, undefined, this));
230
- return /* @__PURE__ */ jsxDEV(DriverField, {
231
- ...commonWrapProps,
232
- children: [
233
- labelNode,
234
- children,
235
- descNode
236
- ]
237
- }, undefined, true, undefined, this);
238
- }
239
- if (f.kind === "array") {
240
- return renderArray(f, parent);
241
- }
242
- return /* @__PURE__ */ jsxDEV(Controller, {
243
- name,
244
- control: form.control,
245
- render: ({ field, fieldState }) => {
246
- const err = fieldState.error ? [fieldState.error] : [];
247
- const ariaInvalid = fieldState.invalid || undefined;
248
- if (f.kind === "text") {
249
- const textField = f;
250
- const Input = driver.Input;
251
- return /* @__PURE__ */ jsxDEV(DriverField, {
252
- ...commonWrapProps,
253
- children: [
254
- labelNode,
255
- /* @__PURE__ */ jsxDEV(Input, {
256
- id,
257
- "aria-invalid": ariaInvalid,
258
- placeholder: f.placeholderI18n,
259
- autoComplete: textField.autoComplete,
260
- inputMode: textField.inputMode,
261
- maxLength: textField.maxLength,
262
- minLength: textField.minLength,
263
- disabled: !enabled,
264
- ...field,
265
- ...f.uiProps
266
- }, undefined, false, undefined, this),
267
- descNode,
268
- fieldState.invalid ? /* @__PURE__ */ jsxDEV(DriverError, {
269
- errors: err
270
- }, undefined, false, undefined, this) : null
271
- ]
272
- }, undefined, true, undefined, this);
273
- }
274
- if (f.kind === "textarea") {
275
- const textareaField = f;
276
- const Textarea = driver.Textarea;
277
- return /* @__PURE__ */ jsxDEV(DriverField, {
278
- ...commonWrapProps,
279
- children: [
280
- labelNode,
281
- /* @__PURE__ */ jsxDEV(Textarea, {
282
- id,
283
- "aria-invalid": ariaInvalid,
284
- placeholder: f.placeholderI18n,
285
- rows: textareaField.rows,
286
- maxLength: textareaField.maxLength,
287
- disabled: !enabled,
288
- ...field,
289
- ...f.uiProps
290
- }, undefined, false, undefined, this),
291
- descNode,
292
- fieldState.invalid ? /* @__PURE__ */ jsxDEV(DriverError, {
293
- errors: err
294
- }, undefined, false, undefined, this) : null
295
- ]
296
- }, undefined, true, undefined, this);
297
- }
298
- if (f.kind === "select") {
299
- const selectField = f;
300
- const Select = driver.Select;
301
- const src = toOptionsArray(selectField.options);
302
- const opts = useResolvedOptions(values, src, merged.resolvers);
303
- return /* @__PURE__ */ jsxDEV(DriverField, {
304
- ...commonWrapProps,
305
- children: [
306
- labelNode,
307
- /* @__PURE__ */ jsxDEV(Select, {
308
- id,
309
- name,
310
- "aria-invalid": ariaInvalid,
311
- disabled: !enabled,
312
- value: field.value,
313
- onChange: (v) => field.onChange(v),
314
- options: opts,
315
- ...f.uiProps
316
- }, undefined, false, undefined, this),
317
- descNode,
318
- fieldState.invalid ? /* @__PURE__ */ jsxDEV(DriverError, {
319
- errors: err
320
- }, undefined, false, undefined, this) : null
321
- ]
322
- }, undefined, true, undefined, this);
323
- }
324
- if (f.kind === "checkbox") {
325
- const Checkbox = driver.Checkbox;
326
- return /* @__PURE__ */ jsxDEV(DriverField, {
327
- ...commonWrapProps,
328
- children: [
329
- labelNode,
330
- /* @__PURE__ */ jsxDEV(Checkbox, {
331
- id,
332
- name,
333
- disabled: !enabled,
334
- checked: !!field.value,
335
- onCheckedChange: (v) => field.onChange(v),
336
- ...f.uiProps
337
- }, undefined, false, undefined, this),
338
- descNode,
339
- fieldState.invalid ? /* @__PURE__ */ jsxDEV(DriverError, {
340
- errors: err
341
- }, undefined, false, undefined, this) : null
342
- ]
343
- }, undefined, true, undefined, this);
344
- }
345
- if (f.kind === "radio") {
346
- const radioField = f;
347
- const RadioGroup = driver.RadioGroup;
348
- const src = toOptionsArray(radioField.options);
349
- const opts = useResolvedOptions(values, src, merged.resolvers);
350
- return /* @__PURE__ */ jsxDEV(DriverField, {
351
- ...commonWrapProps,
352
- children: [
353
- labelNode,
354
- /* @__PURE__ */ jsxDEV(RadioGroup, {
355
- id,
356
- name,
357
- disabled: !enabled,
358
- value: field.value,
359
- onValueChange: (v) => field.onChange(v),
360
- options: opts,
361
- ...f.uiProps
362
- }, undefined, false, undefined, this),
363
- descNode,
364
- fieldState.invalid ? /* @__PURE__ */ jsxDEV(DriverError, {
365
- errors: err
366
- }, undefined, false, undefined, this) : null
367
- ]
368
- }, undefined, true, undefined, this);
369
- }
370
- if (f.kind === "switch") {
371
- const Switch = driver.Switch;
372
- return /* @__PURE__ */ jsxDEV(DriverField, {
373
- ...commonWrapProps,
374
- children: [
375
- labelNode,
376
- /* @__PURE__ */ jsxDEV(Switch, {
377
- id,
378
- name,
379
- disabled: !enabled,
380
- checked: !!field.value,
381
- onCheckedChange: (v) => field.onChange(v),
382
- ...f.uiProps
383
- }, undefined, false, undefined, this),
384
- descNode,
385
- fieldState.invalid ? /* @__PURE__ */ jsxDEV(DriverError, {
386
- errors: err
387
- }, undefined, false, undefined, this) : null
388
- ]
389
- }, undefined, true, undefined, this);
390
- }
391
- return /* @__PURE__ */ jsxDEV(Fragment, {}, undefined, false, undefined, this);
392
- }
393
- }, name, false, undefined, this);
394
- };
395
- const renderArray = (f, parent) => {
396
- const name = fieldPath(parent, f.name);
397
- const { fields, append, remove } = useFieldArray({
398
- control: form.control,
399
- name
400
- });
401
- const canAdd = f.max == null || fields.length < f.max;
402
- const canRemove = (idx) => (f.min == null ? fields.length > 0 : fields.length > f.min) && idx >= 0;
403
- const Button2 = driver.Button;
404
- const Label = driver.FieldLabel;
405
- return /* @__PURE__ */ jsxDEV("div", {
406
- children: [
407
- f.labelI18n ? /* @__PURE__ */ jsxDEV(Label, {
408
- children: f.labelI18n
409
- }, undefined, false, undefined, this) : null,
410
- fields.map((row, idx) => /* @__PURE__ */ jsxDEV("div", {
411
- children: [
412
- renderOne(f.of, name, idx),
413
- canRemove(idx) ? /* @__PURE__ */ jsxDEV(Button2, {
414
- type: "button",
415
- variant: "ghost",
416
- size: "sm",
417
- onClick: () => remove(idx),
418
- children: "Remove"
419
- }, undefined, false, undefined, this) : null
420
- ]
421
- }, row.id ?? idx, true, undefined, this)),
422
- canAdd ? /* @__PURE__ */ jsxDEV(Button2, {
423
- type: "button",
424
- variant: "outline",
425
- size: "sm",
426
- onClick: () => append({}),
427
- children: "Add"
428
- }, undefined, false, undefined, this) : null
429
- ]
430
- }, name, true, undefined, this);
431
- };
432
- const onSubmit = async (data) => {
433
- const actionKey = spec.actions?.[0]?.key ?? "submit";
434
- if (merged.onSubmitOverride) {
435
- return merged.onSubmitOverride(data, actionKey);
436
- }
437
- };
438
- const Button = driver.Button;
439
- return /* @__PURE__ */ jsxDEV("form", {
440
- onSubmit: form.handleSubmit(onSubmit),
441
- children: [
442
- (spec.fields || []).map((f, i) => /* @__PURE__ */ jsxDEV(React3.Fragment, {
443
- children: renderOne(f)
444
- }, i, false, undefined, this)),
445
- spec.actions && spec.actions.length ? /* @__PURE__ */ jsxDEV("div", {
446
- children: spec.actions.map((a) => /* @__PURE__ */ jsxDEV(Button, {
447
- type: "submit",
448
- children: a.labelI18n
449
- }, a.key, false, undefined, this))
450
- }, undefined, false, undefined, this) : null
451
- ]
452
- }, undefined, true, undefined, this);
453
- }
454
- return {
455
- render: (spec, options) => /* @__PURE__ */ jsxDEV(InternalForm, {
456
- spec,
457
- options,
458
- merged: {
459
- ...conf,
460
- ...options?.overrides ?? {}
461
- }
462
- }, undefined, false, undefined, this)
463
- };
464
- }
465
- // src/index.ts
466
- "use client";
467
- export {
468
- shadcnDriver,
469
- rnReusablesDriver,
470
- renderFeaturePresentation,
471
- registerFeature,
472
- createFormRenderer,
473
- createFeatureModule,
474
- createEngineWithDefaults
475
- };
1
+ import{createRequire as s}from"node:module";var o=s(import.meta.url);function AG(G){return G}function PG(G){return G}import{createDefaultTransformEngine as m,htmlToMarkdown as r,registerBasicValidation as u}from"@contractspec/lib.presentation-runtime-core/transform-engine";import p from"react";export*from"@contractspec/lib.presentation-runtime-core/transform-engine";function c(G){return G.register({target:"react",async render(H){if(H.source.type==="component"){let X=H.source.props?H.source.props.getZod().safeParse({}).success?{}:void 0:void 0;return{kind:"react_component",componentKey:H.source.componentKey,props:X}}return{kind:"blocknotejs",docJson:H.source.docJson,blockConfig:H.source.blockConfig}}}),G}function RG(G,H){return G.prependRegister({target:"markdown",async render(X){if(X.source.type!=="component")throw Error("React-to-markdown renderer only handles component presentations");let J=H[X.source.componentKey];if(!J)throw Error(`Component ${X.source.componentKey} not found in componentMap`);let{renderToStaticMarkup:U}=await import("react-dom/server"),B=p.createElement(J,X.source.props?{}:void 0),$=r(U(B));return{mimeType:"text/markdown",body:X.policy?.pii?.length?$.replace(/\[REDACTED\]/g,"[REDACTED]"):$}}}),G}import f from"react";function gG(){return u(c(m()))}async function SG(G,H,X,J){if(H==="react"){let U=await G.render("react",X);if(U.kind==="react_component"){let $=(J?.componentMap??{})[U.componentKey];if(!$)return null;let I={...U.props??{},...J?.reactProps??{}};return f.createElement($,I)}if(U.kind==="blocknotejs"){if(J?.renderBlockNote)return J.renderBlockNote(U.docJson,U.blockConfig);return f.createElement("div",{},"[BlockNote renderer not configured]")}return null}if(H==="markdown")return G.render(H,X);if(H==="application/json")return G.render(H,X);if(H==="application/xml")return G.render(H,X);return null}function xG(G,H){return{meta:G,...H}}function vG(G,H){return G.register(H),G}import{buildZodWithRelations as e,evalPredicate as n,isFieldReadOnly as GG,normalizeFormSpec as HG}from"@contractspec/lib.contracts-spec/forms";import{zodResolver as JG}from"@hookform/resolvers/zod";import V from"react";import{Controller as A,useFieldArray as UG,useForm as XG}from"react-hook-form";import{jsx as Y,jsxs as w,Fragment as EG}from"react/jsx-runtime";function j(G){if(!G)return;if(Array.isArray(G))return{kind:"static",options:[...G]};return G}function F(G,H){if(!H)return;let X=H.replace(/\[(\d+)\]/g,".$1").split(".").filter(Boolean),J=G;for(let U of X){if(J==null)return;J=J[U]}return J}function YG(G){if(!G)return[];return G.split(".").filter((H)=>/^\d+$/.test(H)).map((H)=>Number(H))}function d(G,H){if(!H)return G??"";return G?`${G}.${H}`:H}function l(G,H){if(!H||H.length===0)return"[]";try{return JSON.stringify(H.map((X)=>F(G,X)))}catch{return"[]"}}function _G(G,H){let[X,J]=V.useState(G);return V.useEffect(()=>{let U=globalThis.setTimeout(()=>J(G),H);return()=>globalThis.clearTimeout(U)},[H,G]),X}function g(G,H,X){let[J,U]=V.useState([]),B=V.useMemo(()=>{if(!H)return"nil";if(H.kind==="static")return JSON.stringify(H.options??[]);return`${H.resolverKey}:${l(G,H.deps)}`},[H,G]);return V.useEffect(()=>{let $=!0;return(async()=>{if(!H){U([]);return}if(H.kind==="static"){U([...H.options??[]]);return}let q=X?.[H.resolverKey];if(!q){U([]);return}let b=await q(G,H.args);if($)U([...b??[]])})(),()=>{$=!1}},[B,X,H,G]),J}function i(G){if(G instanceof Date&&!Number.isNaN(G.getTime()))return G;if(typeof G==="string"||typeof G==="number"){let H=new Date(G);if(!Number.isNaN(H.getTime()))return H}return null}function $G(G){if(G instanceof Date&&!Number.isNaN(G.getTime()))return G;if(typeof G!=="string"||G.trim().length===0)return null;let[H,X]=G.split(":").map(($)=>Number($)),J=H??Number.NaN,U=X??Number.NaN;if(Number.isNaN(J)||Number.isNaN(U))return null;let B=new Date;return B.setHours(J,U,0,0),B}function BG(G){if(!G)return"";return`${String(G.getHours()).padStart(2,"0")}:${String(G.getMinutes()).padStart(2,"0")}`}function t(G){return{value:G.value,labelI18n:G.labelI18n,descriptionI18n:G.descriptionI18n,...G.data??{}}}function IG(G,H,X){let J=H.trim().toLowerCase();if(!J)return[...G];let U=J.split(/\s+/).filter(Boolean);return G.filter((B)=>{let $=t(B),I=[B.labelI18n,B.descriptionI18n,String(B.value),...X.map((q)=>String(F($,q)??""))].join(" ").toLowerCase();return U.every((q)=>I.includes(q))})}function x(G,H){let X=t(G);switch(H.mode){case"scalar":return H.valueKey?F(X,H.valueKey)??G.value:G.value;case"pick":return Object.fromEntries(H.pickKeys.map((J)=>[J,F(X,J)]));case"object":default:return G.data??X}}function v(G,H){try{return JSON.stringify(G)===JSON.stringify(H)}catch{return G===H}}function LG(G,H,X,J){let U=J&&Array.isArray(H)?H:[H];return G.filter((B)=>U.some(($)=>v(x(B,X),$)))}function a(G){if(!G)return{countryCode:"",nationalNumber:""};let H=G.countryCode.trim(),X=G.nationalNumber.replace(/\s+/g,""),J=H.replace(/^\+?/,"+"),U={...G,countryCode:H,nationalNumber:G.nationalNumber};if(G.e164!=null||H||X)U.e164=`${J}${X}`.trim();return U}function ZG(G){let H=g(G.values,j(G.spec.options),G.resolvers),X=G.driver.Field,J=G.driver.FieldError;return Y(A,{name:G.ctx.name,control:G.form.control,render:({field:U,fieldState:B})=>{let $=B.error?[B.error]:[];return w(X,{...G.commonWrapProps,children:[G.labelNode,Y(G.driver.Select,{id:G.ctx.id,name:G.ctx.name,"aria-invalid":B.invalid||void 0,disabled:!G.ctx.enabled||G.ctx.readOnly,value:U.value,onChange:(I)=>{if(G.ctx.readOnly)return;U.onChange(I)},options:H,...G.spec.uiProps}),G.descNode,B.invalid?Y(J,{errors:$}):null]})}})}function qG(G){let H=g(G.values,j(G.spec.options),G.resolvers),X=G.driver.Field,J=G.driver.FieldError;return Y(A,{name:G.ctx.name,control:G.form.control,render:({field:U,fieldState:B})=>{let $=B.error?[B.error]:[];return w(X,{...G.commonWrapProps,children:[G.labelNode,Y(G.driver.RadioGroup,{id:G.ctx.id,name:G.ctx.name,disabled:!G.ctx.enabled||G.ctx.readOnly,value:U.value,onValueChange:(I)=>{if(G.ctx.readOnly)return;U.onChange(I)},options:H,...G.spec.uiProps}),G.descNode,B.invalid?Y(J,{errors:$}):null]})}})}function TG(G){let[H,X]=V.useState(""),J=G.spec.source.kind==="resolver"?G.spec.source.debounceMs??200:0,U=_G(H,J),[B,$]=V.useState([]),I=V.useMemo(()=>{return G.spec.source.kind==="resolver"?`${G.spec.source.resolverKey}:${l(G.values,G.spec.source.deps)}:${U}`:"local"},[U,G.spec.source,G.values]);V.useEffect(()=>{if(G.spec.source.kind!=="resolver")return;let Z=G.resolvers?.[G.spec.source.resolverKey],z=G.spec.source.minQueryLength??0;if(!Z||U.trim().length<z){$([]);return}let O=!0,y={...G.spec.source.args??{},query:U};return Promise.resolve(Z(G.values,y)).then((C)=>{if(O)$([...C??[]])}),()=>{O=!1}},[I,G.resolvers,G.spec.source,G.values,U]);let q=G.spec.source.kind==="local"?IG(G.spec.source.options,H,G.spec.source.searchKeys):B,b=G.driver.Field,_=G.driver.FieldError;return Y(A,{name:G.ctx.name,control:G.form.control,render:({field:Z,fieldState:z})=>{let O=z.error?[z.error]:[],y=LG(q,Z.value,G.spec.valueMapping,G.spec.multiple),C=(D)=>{if(G.ctx.readOnly)return;let k=x(D,G.spec.valueMapping);if(G.spec.multiple){let P=Array.isArray(Z.value)?Z.value:[],R=P.some((S)=>v(S,k));Z.onChange(R?P:[...P,k]);return}Z.onChange(k),X(D.labelI18n)},T=(D)=>{if(G.ctx.readOnly||!G.spec.multiple)return;let k=x(D,G.spec.valueMapping),P=Array.isArray(Z.value)?Z.value:[];Z.onChange(P.filter((R)=>!v(R,k)))};return w(b,{...G.commonWrapProps,children:[G.labelNode,Y(G.driver.Autocomplete,{id:G.ctx.id,name:G.ctx.name,disabled:!G.ctx.enabled,readOnly:G.ctx.readOnly,"aria-invalid":z.invalid||void 0,placeholder:G.spec.placeholderI18n,multiple:G.spec.multiple,query:H,options:q,selectedOptions:y,onQueryChange:X,onSelectOption:C,onRemoveOption:T}),G.descNode,z.invalid?Y(_,{errors:O}):null]})}})}function wG(G){let H=g(G.values,j(G.spec.countryOptions),G.resolvers),X=G.driver.Field,J=G.driver.FieldError;return Y(A,{name:G.ctx.name,control:G.form.control,render:({field:U,fieldState:B})=>{let $=B.error?[B.error]:[];return w(X,{...G.commonWrapProps,children:[G.labelNode,Y(G.driver.AddressField,{id:G.ctx.id,name:G.ctx.name,value:U.value??null,onChange:(I)=>{if(G.ctx.readOnly)return;U.onChange(I)},disabled:!G.ctx.enabled,readOnly:G.ctx.readOnly,"aria-invalid":B.invalid||void 0,parts:G.spec.parts,countryOptions:H}),G.descNode,B.invalid?Y(J,{errors:$}):null]})}})}function KG(G){let H=g(G.values,j(G.spec.countryOptions),G.resolvers),X=G.driver.Field,J=G.driver.FieldError;return Y(A,{name:G.ctx.name,control:G.form.control,render:({field:U,fieldState:B})=>{let $=B.error?[B.error]:[];return w(X,{...G.commonWrapProps,children:[G.labelNode,Y(G.driver.PhoneField,{id:G.ctx.id,name:G.ctx.name,value:a(U.value??null),onChange:(I)=>{if(G.ctx.readOnly)return;U.onChange(a(I))},disabled:!G.ctx.enabled,readOnly:G.ctx.readOnly,"aria-invalid":B.invalid||void 0,parts:G.spec.parts,countryOptions:H}),G.descNode,B.invalid?Y(J,{errors:$}):null]})}})}function QG(G){let H=G.driver.Field,X=G.driver.FieldError;return Y(A,{name:G.ctx.name,control:G.form.control,render:({field:J,fieldState:U})=>{let B=U.error?[U.error]:[];return w(H,{...G.commonWrapProps,children:[G.labelNode,Y(G.driver.DateField,{id:G.ctx.id,name:G.ctx.name,value:i(J.value),onChange:($)=>{if(G.ctx.readOnly)return;J.onChange($)},disabled:!G.ctx.enabled,readOnly:G.ctx.readOnly,placeholder:G.spec.placeholderI18n,minDate:G.spec.minDate,maxDate:G.spec.maxDate}),G.descNode,U.invalid?Y(X,{errors:B}):null]})}})}function MG(G){let H=G.driver.Field,X=G.driver.FieldError;return Y(A,{name:G.ctx.name,control:G.form.control,render:({field:J,fieldState:U})=>{let B=U.error?[U.error]:[];return w(H,{...G.commonWrapProps,children:[G.labelNode,Y(G.driver.TimeField,{id:G.ctx.id,name:G.ctx.name,value:$G(J.value),onChange:($)=>{if(G.ctx.readOnly)return;J.onChange(BG($))},disabled:!G.ctx.enabled,readOnly:G.ctx.readOnly,placeholder:G.spec.placeholderI18n,is24Hour:G.spec.is24Hour}),G.descNode,U.invalid?Y(X,{errors:B}):null]})}})}function VG(G){let H=G.driver.Field,X=G.driver.FieldError;return Y(A,{name:G.ctx.name,control:G.form.control,render:({field:J,fieldState:U})=>{let B=U.error?[U.error]:[];return w(H,{...G.commonWrapProps,children:[G.labelNode,Y(G.driver.DateTimeField,{id:G.ctx.id,name:G.ctx.name,value:i(J.value),onChange:($)=>{if(G.ctx.readOnly)return;J.onChange($)},disabled:!G.ctx.enabled,readOnly:G.ctx.readOnly,datePlaceholder:G.spec.placeholderI18n,timePlaceholder:G.spec.placeholderI18n,minDate:G.spec.minDate,maxDate:G.spec.maxDate,is24Hour:G.spec.is24Hour}),G.descNode,U.invalid?Y(X,{errors:B}):null]})}})}function zG(G){let H=d(G.parent,G.spec.name),{fields:X,append:J,remove:U}=UG({control:G.form.control,name:H}),B=G.spec.max==null||X.length<G.spec.max,$=(I)=>(G.spec.min==null?X.length>0:X.length>G.spec.min)&&I>=0;return w("div",{children:[G.spec.labelI18n?Y(G.driver.FieldLabel,{children:G.spec.labelI18n}):null,X.map((I,q)=>w("div",{children:[G.renderField(G.spec.of,`${H}.${q}`),$(q)?Y(G.driver.Button,{type:"button",variant:"ghost",size:"sm",onClick:()=>U(q),children:"Remove"}):null]},I.id??q)),B?Y(G.driver.Button,{type:"button",variant:"outline",size:"sm",onClick:()=>J({}),children:"Add"}):null]},H)}function aG(G){let H=G;function X(J){let U=V.useMemo(()=>HG(J.spec),[J.spec]),B=V.useMemo(()=>e(U),[U]),$=XG({...J.merged.formOptions,resolver:JG(B),defaultValues:J.options?.defaultValues}),I=$.watch(),q=(_,Z)=>{let z=J.merged.driver.Field,O=J.merged.driver.FieldLabel,y=J.merged.driver.FieldDescription,C=J.merged.driver.FieldError,T=d(Z,_.name),D=YG(Z),k=n(I,_.visibleWhen,D),P=n(I,_.enabledWhen,D),R=GG(_),S=Boolean($.getFieldState(T)?.invalid);if(!k)return null;let L={name:T,id:T.replace(/\./g,"-"),enabled:P,readOnly:R,visible:k},K={"data-invalid":S,hidden:!k,disabled:!P||R},Q=_.labelI18n?Y(O,{htmlFor:L.id,children:_.labelI18n}):null,M=_.descriptionI18n?Y(y,{children:_.descriptionI18n}):null;if(_.kind==="group")return w(z,{...K,children:[Q,_.fields.map((N,W)=>Y(V.Fragment,{children:q(N,T)},`${T}-${W}`)),M]});if(_.kind==="array")return Y(zG,{driver:J.merged.driver,form:$,spec:_,parent:Z,renderField:q},T);if(_.kind==="select")return Y(ZG,{driver:J.merged.driver,form:$,values:I,spec:_,ctx:L,labelNode:Q,descNode:M,commonWrapProps:K,resolvers:J.merged.resolvers},T);if(_.kind==="radio")return Y(qG,{driver:J.merged.driver,form:$,values:I,spec:_,ctx:L,labelNode:Q,descNode:M,commonWrapProps:K,resolvers:J.merged.resolvers},T);if(_.kind==="autocomplete")return Y(TG,{driver:J.merged.driver,form:$,values:I,spec:_,ctx:L,labelNode:Q,descNode:M,commonWrapProps:K,resolvers:J.merged.resolvers},T);if(_.kind==="address")return Y(wG,{driver:J.merged.driver,form:$,values:I,spec:_,ctx:L,labelNode:Q,descNode:M,commonWrapProps:K,resolvers:J.merged.resolvers},T);if(_.kind==="phone")return Y(KG,{driver:J.merged.driver,form:$,values:I,spec:_,ctx:L,labelNode:Q,descNode:M,commonWrapProps:K,resolvers:J.merged.resolvers},T);if(_.kind==="date")return Y(QG,{driver:J.merged.driver,form:$,spec:_,ctx:L,labelNode:Q,descNode:M,commonWrapProps:K},T);if(_.kind==="time")return Y(MG,{driver:J.merged.driver,form:$,spec:_,ctx:L,labelNode:Q,descNode:M,commonWrapProps:K},T);if(_.kind==="datetime")return Y(VG,{driver:J.merged.driver,form:$,spec:_,ctx:L,labelNode:Q,descNode:M,commonWrapProps:K},T);return Y(A,{name:T,control:$.control,render:({field:N,fieldState:W})=>{let h=W.error?[W.error]:[];if(_.kind==="text"){let E=_;return w(z,{...K,children:[Q,Y(J.merged.driver.Input,{id:L.id,"aria-invalid":W.invalid||void 0,placeholder:_.placeholderI18n,autoComplete:E.autoComplete,inputMode:E.inputMode,maxLength:E.maxLength,minLength:E.minLength,disabled:!L.enabled,readOnly:L.readOnly,...N,..._.uiProps}),M,W.invalid?Y(C,{errors:h}):null]})}if(_.kind==="textarea"){let E=_;return w(z,{...K,children:[Q,Y(J.merged.driver.Textarea,{id:L.id,"aria-invalid":W.invalid||void 0,placeholder:_.placeholderI18n,rows:E.rows,maxLength:E.maxLength,disabled:!L.enabled,readOnly:L.readOnly,...N,..._.uiProps}),M,W.invalid?Y(C,{errors:h}):null]})}if(_.kind==="checkbox")return w(z,{...K,children:[Q,Y(J.merged.driver.Checkbox,{id:L.id,name:L.name,disabled:!L.enabled||L.readOnly,checked:Boolean(N.value),onCheckedChange:(E)=>{if(L.readOnly)return;N.onChange(E)},..._.uiProps}),M,W.invalid?Y(C,{errors:h}):null]});if(_.kind==="switch")return w(z,{...K,children:[Q,Y(J.merged.driver.Switch,{id:L.id,name:L.name,disabled:!L.enabled||L.readOnly,checked:Boolean(N.value),onCheckedChange:(E)=>{if(L.readOnly)return;N.onChange(E)},..._.uiProps}),M,W.invalid?Y(C,{errors:h}):null]});return Y(EG,{})}},T)},b=async(_)=>{let Z=U.actions?.[0]?.key??"submit";if(J.merged.onSubmitOverride)return J.merged.onSubmitOverride(_,Z)};return w("form",{onSubmit:$.handleSubmit(b),children:[U.fields.map((_,Z)=>Y(V.Fragment,{children:q(_)},Z)),U.actions?.length?Y("div",{children:U.actions.map((_)=>Y(J.merged.driver.Button,{type:"submit",children:_.labelI18n},_.key))}):null]})}return{render:(J,U)=>Y(X,{spec:J,options:U,merged:{...H,...U?.overrides??{}}})}}export{PG as shadcnDriver,AG as rnReusablesDriver,SG as renderFeaturePresentation,vG as registerFeature,x as mapAutocompleteValue,IG as filterAutocompleteOptions,aG as createFormRenderer,xG as createFeatureModule,gG as createEngineWithDefaults};
@@ -1,61 +1 @@
1
- import { createRequire } from "node:module";
2
- var __require = /* @__PURE__ */ createRequire(import.meta.url);
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
- export {
57
- registerReactToMarkdownRenderer,
58
- registerDefaultReactRenderer,
59
- registerBasicValidation,
60
- createDefaultTransformEngine
61
- };
1
+ import{createRequire as G}from"node:module";var H=G(import.meta.url);import{createDefaultTransformEngine as O,htmlToMarkdown as I,registerBasicValidation as P}from"@contractspec/lib.presentation-runtime-core/transform-engine";import J from"react";export*from"@contractspec/lib.presentation-runtime-core/transform-engine";function U(x){return x.register({target:"react",async render(j){if(j.source.type==="component"){let q=j.source.props?j.source.props.getZod().safeParse({}).success?{}:void 0:void 0;return{kind:"react_component",componentKey:j.source.componentKey,props:q}}return{kind:"blocknotejs",docJson:j.source.docJson,blockConfig:j.source.blockConfig}}}),x}function W(x,j){return x.prependRegister({target:"markdown",async render(q){if(q.source.type!=="component")throw Error("React-to-markdown renderer only handles component presentations");let y=j[q.source.componentKey];if(!y)throw Error(`Component ${q.source.componentKey} not found in componentMap`);let{renderToStaticMarkup:A}=await import("react-dom/server"),F=J.createElement(y,q.source.props?{}:void 0),z=I(A(F));return{mimeType:"text/markdown",body:q.policy?.pii?.length?z.replace(/\[REDACTED\]/g,"[REDACTED]"):z}}}),x}export{W as registerReactToMarkdownRenderer,U as registerDefaultReactRenderer,P as registerBasicValidation,O as createDefaultTransformEngine};
@@ -1,61 +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
- export {
57
- registerReactToMarkdownRenderer,
58
- registerDefaultReactRenderer,
59
- registerBasicValidation,
60
- createDefaultTransformEngine
61
- };
2
+ var G=import.meta.require;import{createDefaultTransformEngine as L,htmlToMarkdown as H,registerBasicValidation as N}from"@contractspec/lib.presentation-runtime-core/transform-engine";import I from"react";export*from"@contractspec/lib.presentation-runtime-core/transform-engine";function P(x){return x.register({target:"react",async render(j){if(j.source.type==="component"){let q=j.source.props?j.source.props.getZod().safeParse({}).success?{}:void 0:void 0;return{kind:"react_component",componentKey:j.source.componentKey,props:q}}return{kind:"blocknotejs",docJson:j.source.docJson,blockConfig:j.source.blockConfig}}}),x}function Q(x,j){return x.prependRegister({target:"markdown",async render(q){if(q.source.type!=="component")throw Error("React-to-markdown renderer only handles component presentations");let y=j[q.source.componentKey];if(!y)throw Error(`Component ${q.source.componentKey} not found in componentMap`);let{renderToStaticMarkup:A}=await import("react-dom/server"),F=I.createElement(y,q.source.props?{}:void 0),z=H(A(F));return{mimeType:"text/markdown",body:q.policy?.pii?.length?z.replace(/\[REDACTED\]/g,"[REDACTED]"):z}}}),x}export{Q as registerReactToMarkdownRenderer,P as registerDefaultReactRenderer,N as registerBasicValidation,L as createDefaultTransformEngine};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contractspec/lib.contracts-runtime-client-react",
3
- "version": "3.8.5",
3
+ "version": "3.9.0",
4
4
  "description": "React runtime adapters for ContractSpec contracts",
5
5
  "type": "module",
6
6
  "types": "./dist/index.d.ts",
@@ -9,8 +9,8 @@
9
9
  "publish:pkg:canary": "bun publish:pkg --tag canary",
10
10
  "clean": "rm -rf dist",
11
11
  "lint": "bun run lint:fix",
12
- "lint:fix": "biome check --write --unsafe --only=nursery/useSortedClasses . && biome check --write .",
13
- "lint:check": "biome check .",
12
+ "lint:fix": "node ../../../scripts/biome.cjs check --write --unsafe --only=nursery/useSortedClasses . && node ../../../scripts/biome.cjs check --write .",
13
+ "lint:check": "node ../../../scripts/biome.cjs check .",
14
14
  "build": "bun run build:bundle && bun run build:types",
15
15
  "build:bundle": "contractspec-bun-build transpile",
16
16
  "build:types": "contractspec-bun-build types",
@@ -30,14 +30,14 @@
30
30
  "react-hook-form": "^7.72.0"
31
31
  },
32
32
  "dependencies": {
33
- "@contractspec/lib.contracts-spec": "5.1.0",
33
+ "@contractspec/lib.contracts-spec": "5.3.0",
34
34
  "@contractspec/lib.schema": "3.7.14",
35
- "@contractspec/lib.presentation-runtime-core": "3.9.5"
35
+ "@contractspec/lib.presentation-runtime-core": "3.9.7"
36
36
  },
37
37
  "devDependencies": {
38
38
  "@contractspec/tool.typescript": "3.7.13",
39
39
  "typescript": "^5.9.3",
40
- "@contractspec/tool.bun": "3.7.13"
40
+ "@contractspec/tool.bun": "3.7.14"
41
41
  },
42
42
  "files": [
43
43
  "dist",