@contractspec/lib.design-system 1.53.0 → 1.55.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.
Files changed (46) hide show
  1. package/dist/components/atoms/Textarea.js +0 -6
  2. package/dist/components/atoms/Textarea.js.map +1 -1
  3. package/dist/components/data-view/DataViewDetail.d.ts +2 -2
  4. package/dist/components/data-view/DataViewDetail.d.ts.map +1 -1
  5. package/dist/components/data-view/DataViewDetail.js +11 -6
  6. package/dist/components/data-view/DataViewDetail.js.map +1 -1
  7. package/dist/components/data-view/DataViewList.js +11 -11
  8. package/dist/components/data-view/DataViewList.js.map +1 -1
  9. package/dist/components/data-view/DataViewRenderer.js +1 -1
  10. package/dist/components/data-view/DataViewTable.js +13 -6
  11. package/dist/components/data-view/DataViewTable.js.map +1 -1
  12. package/dist/components/data-view/utils.js +11 -4
  13. package/dist/components/data-view/utils.js.map +1 -1
  14. package/dist/components/molecules/CodeBlock/CodeBlock.d.ts +2 -2
  15. package/dist/components/molecules/CommandTabs/CommandTabs.d.ts +2 -2
  16. package/dist/components/molecules/CopyButton/CopyButton.d.ts +2 -2
  17. package/dist/components/molecules/InstallCommand/InstallCommand.d.ts +2 -2
  18. package/dist/components/molecules/SkeletonBlock/index.web.d.ts +2 -2
  19. package/dist/components/molecules/SkeletonCircle/index.web.d.ts +2 -2
  20. package/dist/components/molecules/SkeletonList/index.web.d.ts +2 -2
  21. package/dist/components/templates/lists/ListPageTemplate/index.web.d.ts +2 -2
  22. package/dist/example-shared-ui/src/EvolutionDashboard.js +7 -0
  23. package/dist/example-shared-ui/src/EvolutionSidebar.js +7 -0
  24. package/dist/example-shared-ui/src/LocalDataIndicator.js +6 -0
  25. package/dist/example-shared-ui/src/MarkdownView.js +119 -0
  26. package/dist/example-shared-ui/src/MarkdownView.js.map +1 -0
  27. package/dist/example-shared-ui/src/OverlayContextProvider.js +11 -0
  28. package/dist/example-shared-ui/src/OverlayContextProvider.js.map +1 -0
  29. package/dist/example-shared-ui/src/PersonalizationInsights.js +7 -0
  30. package/dist/example-shared-ui/src/SaveToStudioButton.js +6 -0
  31. package/dist/example-shared-ui/src/SpecEditorPanel.js +6 -0
  32. package/dist/example-shared-ui/src/TemplateShell.js +3 -0
  33. package/dist/example-shared-ui/src/hooks/index.js +5 -0
  34. package/dist/example-shared-ui/src/hooks/useBehaviorTracking.js +3 -0
  35. package/dist/example-shared-ui/src/hooks/useEvolution.js +3 -0
  36. package/dist/example-shared-ui/src/hooks/useRegistryTemplates.js +1 -0
  37. package/dist/example-shared-ui/src/hooks/useSpecContent.js +4 -0
  38. package/dist/example-shared-ui/src/hooks/useWorkflowComposer.js +3 -0
  39. package/dist/example-shared-ui/src/index.js +12 -0
  40. package/dist/example-shared-ui/src/lib/component-registry.js +27 -0
  41. package/dist/example-shared-ui/src/lib/component-registry.js.map +1 -0
  42. package/dist/example-shared-ui/src/lib/runtime-context.js +9 -0
  43. package/dist/example-shared-ui/src/lib/runtime-context.js.map +1 -0
  44. package/dist/index.js +1 -1
  45. package/dist/renderers/form-contract.d.ts +2 -2
  46. package/package.json +14 -14
@@ -7,18 +7,12 @@ import { Textarea } from "@contractspec/lib.ui-kit-web/ui/textarea";
7
7
  function Textarea$1({ value, defaultValue, onChange, onSubmit, onFocus, onBlur, placeholder, disabled, readOnly, maxLength, name, className, rows, keyboard, ...rest }) {
8
8
  const webKeyboard = mapKeyboardToWeb(keyboard);
9
9
  const handleChange = React.useCallback((e) => onChange?.(e), [onChange]);
10
- const handleKeyDown = React.useCallback((e) => {
11
- if (e.key === "Enter" && webKeyboard.type !== "search") {
12
- if (e.metaKey || e.ctrlKey) onSubmit?.(e);
13
- }
14
- }, [onSubmit, webKeyboard.type]);
15
10
  return /* @__PURE__ */ jsx(Textarea, {
16
11
  ...rest,
17
12
  className,
18
13
  value,
19
14
  defaultValue,
20
15
  onChange: handleChange,
21
- onKeyDown: handleKeyDown,
22
16
  onFocus,
23
17
  onBlur,
24
18
  placeholder,
@@ -1 +1 @@
1
- {"version":3,"file":"Textarea.js","names":["Textarea","WebTextarea"],"sources":["../../../src/components/atoms/Textarea.tsx"],"sourcesContent":["import * as React from 'react';\nimport {\n Textarea as WebTextarea,\n type TextareaProps as WebTextareaProps,\n} from '@contractspec/lib.ui-kit-web/ui/textarea';\nimport { type KeyboardOptions, mapKeyboardToWeb } from '../../lib/keyboard';\n\ninterface BaseFieldProps {\n value?: string;\n defaultValue?: string;\n // onChange?: (text: string) => void;\n // onSubmit?: () => void;\n // onFocus?: () => void;\n // onBlur?: () => void;\n placeholder?: string;\n disabled?: boolean;\n readOnly?: boolean;\n maxLength?: number;\n name?: string;\n className?: string;\n rows?: number;\n keyboard?: KeyboardOptions;\n}\n\nexport type TextareaProps = WebTextareaProps & BaseFieldProps;\n\n// export type TextareaProps = Omit<\n// WebTextareaProps,\n// // 'onChange' | 'value' | 'defaultValue'\n// > &\n// BaseFieldProps;\n\nexport function Textarea({\n value,\n defaultValue,\n onChange,\n onSubmit,\n onFocus,\n onBlur,\n placeholder,\n disabled,\n readOnly,\n maxLength,\n name,\n className,\n rows,\n keyboard,\n ...rest\n}: TextareaProps) {\n const webKeyboard = mapKeyboardToWeb(keyboard);\n\n const handleChange = React.useCallback<\n React.ChangeEventHandler<HTMLTextAreaElement>\n >((e) => onChange?.(e), [onChange]);\n\n const handleKeyDown = React.useCallback<\n React.KeyboardEventHandler<HTMLTextAreaElement>\n >(\n (e) => {\n if (e.key === 'Enter' && webKeyboard.type !== 'search') {\n // For textarea, Enter inserts newline; onSubmit could be used with modifier\n if (e.metaKey || e.ctrlKey) onSubmit?.(e);\n }\n },\n [onSubmit, webKeyboard.type]\n );\n\n return (\n <WebTextarea\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n {...(rest as any)}\n className={className}\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n value={value as any}\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n defaultValue={defaultValue as any}\n onChange={handleChange}\n onKeyDown={handleKeyDown}\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n onFocus={onFocus as any}\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n onBlur={onBlur as any}\n placeholder={placeholder}\n disabled={disabled}\n readOnly={readOnly}\n maxLength={maxLength}\n name={name}\n rows={rows}\n {...webKeyboard}\n />\n );\n}\n\nexport default Textarea;\n"],"mappings":";;;;;;AAgCA,SAAgBA,WAAS,EACvB,OACA,cACA,UACA,UACA,SACA,QACA,aACA,UACA,UACA,WACA,MACA,WACA,MACA,UACA,GAAG,QACa;CAChB,MAAM,cAAc,iBAAiB,SAAS;CAE9C,MAAM,eAAe,MAAM,aAExB,MAAM,WAAW,EAAE,EAAE,CAAC,SAAS,CAAC;CAEnC,MAAM,gBAAgB,MAAM,aAGzB,MAAM;AACL,MAAI,EAAE,QAAQ,WAAW,YAAY,SAAS,UAE5C;OAAI,EAAE,WAAW,EAAE,QAAS,YAAW,EAAE;;IAG7C,CAAC,UAAU,YAAY,KAAK,CAC7B;AAED,QACE,oBAACC;EAEC,GAAK;EACM;EAEJ;EAEO;EACd,UAAU;EACV,WAAW;EAEF;EAED;EACK;EACH;EACA;EACC;EACL;EACA;EACN,GAAI;GACJ"}
1
+ {"version":3,"file":"Textarea.js","names":["Textarea","WebTextarea"],"sources":["../../../src/components/atoms/Textarea.tsx"],"sourcesContent":["import * as React from 'react';\nimport {\n Textarea as WebTextarea,\n type TextareaProps as WebTextareaProps,\n} from '@contractspec/lib.ui-kit-web/ui/textarea';\nimport { type KeyboardOptions, mapKeyboardToWeb } from '../../lib/keyboard';\n\ninterface BaseFieldProps {\n value?: string;\n defaultValue?: string;\n // onChange?: (text: string) => void;\n // onSubmit?: () => void;\n // onFocus?: () => void;\n // onBlur?: () => void;\n placeholder?: string;\n disabled?: boolean;\n readOnly?: boolean;\n maxLength?: number;\n name?: string;\n className?: string;\n rows?: number;\n keyboard?: KeyboardOptions;\n}\n\nexport type TextareaProps = WebTextareaProps & BaseFieldProps;\n\n// export type TextareaProps = Omit<\n// WebTextareaProps,\n// // 'onChange' | 'value' | 'defaultValue'\n// > &\n// BaseFieldProps;\n\nexport function Textarea({\n value,\n defaultValue,\n onChange,\n onSubmit,\n onFocus,\n onBlur,\n placeholder,\n disabled,\n readOnly,\n maxLength,\n name,\n className,\n rows,\n keyboard,\n ...rest\n}: TextareaProps) {\n const webKeyboard = mapKeyboardToWeb(keyboard);\n\n const handleChange = React.useCallback<\n React.ChangeEventHandler<HTMLTextAreaElement>\n >((e) => onChange?.(e), [onChange]);\n\n // const handleKeyDown = React.useCallback<\n // React.KeyboardEventHandler<HTMLTextAreaElement>\n // >(\n // (e) => {\n // if (e.key === 'Enter' && webKeyboard.type !== 'search') {\n // // For textarea, Enter inserts newline; onSubmit could be used with modifier\n // if (e.metaKey || e.ctrlKey) onSubmit?.(e);\n // }\n // },\n // [onSubmit, webKeyboard.type]\n // );\n\n return (\n <WebTextarea\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n {...(rest as any)}\n className={className}\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n value={value as any}\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n defaultValue={defaultValue as any}\n onChange={handleChange}\n // onKeyDown={handleKeyDown}\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n onFocus={onFocus as any}\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n onBlur={onBlur as any}\n placeholder={placeholder}\n disabled={disabled}\n readOnly={readOnly}\n maxLength={maxLength}\n name={name}\n rows={rows}\n {...webKeyboard}\n />\n );\n}\n\nexport default Textarea;\n"],"mappings":";;;;;;AAgCA,SAAgBA,WAAS,EACvB,OACA,cACA,UACA,UACA,SACA,QACA,aACA,UACA,UACA,WACA,MACA,WACA,MACA,UACA,GAAG,QACa;CAChB,MAAM,cAAc,iBAAiB,SAAS;CAE9C,MAAM,eAAe,MAAM,aAExB,MAAM,WAAW,EAAE,EAAE,CAAC,SAAS,CAAC;AAcnC,QACE,oBAACC;EAEC,GAAK;EACM;EAEJ;EAEO;EACd,UAAU;EAGD;EAED;EACK;EACH;EACA;EACC;EACL;EACA;EACN,GAAI;GACJ"}
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import * as react_jsx_runtime108 from "react/jsx-runtime";
2
+ import * as react_jsx_runtime109 from "react/jsx-runtime";
3
3
  import { DataViewSpec } from "@contractspec/lib.contracts/data-views";
4
4
 
5
5
  //#region src/components/data-view/DataViewDetail.d.ts
@@ -16,7 +16,7 @@ declare function DataViewDetail({
16
16
  className,
17
17
  emptyState,
18
18
  headerActions
19
- }: DataViewDetailProps): react_jsx_runtime108.JSX.Element;
19
+ }: DataViewDetailProps): react_jsx_runtime109.JSX.Element;
20
20
  //#endregion
21
21
  export { DataViewDetail };
22
22
  //# sourceMappingURL=DataViewDetail.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"DataViewDetail.d.ts","names":[],"sources":["../../../src/components/data-view/DataViewDetail.tsx"],"sourcesContent":[],"mappings":";;;;;UAWiB,mBAAA;QACT;QACA;EAFS,SAAA,CAAA,EAAA,MAAA;EACT,UAAA,CAAA,EAGO,KAAA,CAAM,SAHb;EACA,aAAA,CAAA,EAGU,KAAA,CAAM,SAHhB;;AAGgB,iBAGR,cAAA,CAHQ;EAAA,IAAA;EAAA,IAAA;EAAA,SAAA;EAAA,UAAA;EAAA;AAAA,CAAA,EASrB,mBATqB,CAAA,EASF,oBAAA,CAAA,GAAA,CAAA,OATE"}
1
+ {"version":3,"file":"DataViewDetail.d.ts","names":[],"sources":["../../../src/components/data-view/DataViewDetail.tsx"],"sourcesContent":[],"mappings":";;;;;UAYiB,mBAAA;QACT;QACA;EAFS,SAAA,CAAA,EAAA,MAAA;EACT,UAAA,CAAA,EAGO,KAAA,CAAM,SAHb;EACA,aAAA,CAAA,EAGU,KAAA,CAAM,SAHhB;;AAGgB,iBAGR,cAAA,CAHQ;EAAA,IAAA;EAAA,IAAA;EAAA,SAAA;EAAA,UAAA;EAAA;AAAA,CAAA,EASrB,mBATqB,CAAA,EASF,oBAAA,CAAA,GAAA,CAAA,OATE"}
@@ -1,7 +1,9 @@
1
1
  'use client';
2
2
 
3
3
  import { cn } from "../../lib/utils.js";
4
- import { formatValue, getAtPath } from "./utils.js";
4
+ import { MarkdownRenderer } from "../../example-shared-ui/src/MarkdownView.js";
5
+ import "../../example-shared-ui/src/index.js";
6
+ import { DataViewFormattedValue, getAtPath } from "./utils.js";
5
7
  import "react";
6
8
  import { jsx, jsxs } from "react/jsx-runtime";
7
9
 
@@ -31,9 +33,9 @@ function DataViewDetail({ spec, item, className, emptyState, headerActions }) {
31
33
  children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h3", {
32
34
  className: "text-foreground text-xl font-semibold",
33
35
  children: spec.meta.title
34
- }), /* @__PURE__ */ jsx("p", {
36
+ }), /* @__PURE__ */ jsx("div", {
35
37
  className: "text-muted-foreground text-sm",
36
- children: spec.meta.description
38
+ children: /* @__PURE__ */ jsx(MarkdownRenderer, { content: spec.meta.description ?? "" })
37
39
  })] }), headerActions]
38
40
  }), /* @__PURE__ */ jsx("div", {
39
41
  className: "flex flex-col gap-6",
@@ -44,9 +46,9 @@ function DataViewDetail({ spec, item, className, emptyState, headerActions }) {
44
46
  className: "text-muted-foreground mb-2 text-sm font-semibold tracking-wide uppercase",
45
47
  children: section.title
46
48
  }) : null,
47
- section.description ? /* @__PURE__ */ jsx("p", {
49
+ section.description ? /* @__PURE__ */ jsx("div", {
48
50
  className: "text-muted-foreground mb-4 text-sm",
49
- children: section.description
51
+ children: /* @__PURE__ */ jsx(MarkdownRenderer, { content: section.description })
50
52
  }) : null,
51
53
  /* @__PURE__ */ jsx("dl", {
52
54
  className: "grid gap-4 md:grid-cols-2",
@@ -61,7 +63,10 @@ function DataViewDetail({ spec, item, className, emptyState, headerActions }) {
61
63
  children: field.label
62
64
  }), /* @__PURE__ */ jsx("dd", {
63
65
  className: "text-foreground text-sm",
64
- children: formatValue(value, field.format)
66
+ children: /* @__PURE__ */ jsx(DataViewFormattedValue, {
67
+ value,
68
+ format: field.format
69
+ })
65
70
  })]
66
71
  }, field.key);
67
72
  })
@@ -1 +1 @@
1
- {"version":3,"file":"DataViewDetail.js","names":[],"sources":["../../../src/components/data-view/DataViewDetail.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport type {\n DataViewSpec,\n DataViewDetailConfig,\n DataViewField,\n} from '@contractspec/lib.contracts/data-views';\nimport { cn } from '../../lib/utils';\nimport { getAtPath, formatValue } from './utils';\n\nexport interface DataViewDetailProps {\n spec: DataViewSpec;\n item: Record<string, unknown> | null;\n className?: string;\n emptyState?: React.ReactNode;\n headerActions?: React.ReactNode;\n}\n\nexport function DataViewDetail({\n spec,\n item,\n className,\n emptyState,\n headerActions,\n}: DataViewDetailProps) {\n if (spec.view.kind !== 'detail') {\n throw new Error(\n `DataViewDetail received view kind \"${spec.view.kind}\", expected \"detail\".`\n );\n }\n\n const view = spec.view as DataViewDetailConfig;\n const fields = view.fields;\n\n if (!item) {\n return (\n <div className={cn('flex w-full flex-col gap-4', className)}>\n <div className=\"flex items-center justify-between\">\n <h3 className=\"text-foreground text-base font-semibold\">\n {spec.meta.title}\n </h3>\n {headerActions}\n </div>\n {emptyState ?? (\n <div className=\"border-muted-foreground/40 text-muted-foreground rounded-md border border-dashed p-8 text-center text-sm\">\n Select a record to view details.\n </div>\n )}\n </div>\n );\n }\n\n const sections =\n view.sections && view.sections.length > 0\n ? view.sections\n : [{ fields: fields.map((field) => field.key) }];\n\n return (\n <div className={cn('flex w-full flex-col gap-6', className)}>\n <div className=\"flex items-center justify-between\">\n <div>\n <h3 className=\"text-foreground text-xl font-semibold\">\n {spec.meta.title}\n </h3>\n <p className=\"text-muted-foreground text-sm\">\n {spec.meta.description}\n </p>\n </div>\n {headerActions}\n </div>\n <div className=\"flex flex-col gap-6\">\n {sections.map((section, idx) => (\n <div\n key={idx}\n className=\"border-border bg-card rounded-lg border p-4 shadow-sm\"\n >\n {section.title ? (\n <h4 className=\"text-muted-foreground mb-2 text-sm font-semibold tracking-wide uppercase\">\n {section.title}\n </h4>\n ) : null}\n {section.description ? (\n <p className=\"text-muted-foreground mb-4 text-sm\">\n {section.description}\n </p>\n ) : null}\n <dl className=\"grid gap-4 md:grid-cols-2\">\n {section.fields.map((fieldKey) => {\n const field = fieldByKey(fields, fieldKey);\n if (!field) return null;\n const value = getAtPath(item, field.dataPath);\n return (\n <div key={field.key} className=\"flex flex-col gap-1\">\n <dt className=\"text-muted-foreground/80 text-xs font-semibold uppercase\">\n {field.label}\n </dt>\n <dd className=\"text-foreground text-sm\">\n {formatValue(value, field.format)}\n </dd>\n </div>\n );\n })}\n </dl>\n </div>\n ))}\n </div>\n </div>\n );\n}\n\nfunction fieldByKey(fields: DataViewField[], key: string) {\n return fields.find((field) => field.key === key);\n}\n"],"mappings":";;;;;;;;AAmBA,SAAgB,eAAe,EAC7B,MACA,MACA,WACA,YACA,iBACsB;AACtB,KAAI,KAAK,KAAK,SAAS,SACrB,OAAM,IAAI,MACR,sCAAsC,KAAK,KAAK,KAAK,uBACtD;CAGH,MAAM,OAAO,KAAK;CAClB,MAAM,SAAS,KAAK;AAEpB,KAAI,CAAC,KACH,QACE,qBAAC;EAAI,WAAW,GAAG,8BAA8B,UAAU;aACzD,qBAAC;GAAI,WAAU;cACb,oBAAC;IAAG,WAAU;cACX,KAAK,KAAK;KACR,EACJ;IACG,EACL,cACC,oBAAC;GAAI,WAAU;aAA2G;IAEpH;GAEJ;CAIV,MAAM,WACJ,KAAK,YAAY,KAAK,SAAS,SAAS,IACpC,KAAK,WACL,CAAC,EAAE,QAAQ,OAAO,KAAK,UAAU,MAAM,IAAI,EAAE,CAAC;AAEpD,QACE,qBAAC;EAAI,WAAW,GAAG,8BAA8B,UAAU;aACzD,qBAAC;GAAI,WAAU;cACb,qBAAC,oBACC,oBAAC;IAAG,WAAU;cACX,KAAK,KAAK;KACR,EACL,oBAAC;IAAE,WAAU;cACV,KAAK,KAAK;KACT,IACA,EACL;IACG,EACN,oBAAC;GAAI,WAAU;aACZ,SAAS,KAAK,SAAS,QACtB,qBAAC;IAEC,WAAU;;KAET,QAAQ,QACP,oBAAC;MAAG,WAAU;gBACX,QAAQ;OACN,GACH;KACH,QAAQ,cACP,oBAAC;MAAE,WAAU;gBACV,QAAQ;OACP,GACF;KACJ,oBAAC;MAAG,WAAU;gBACX,QAAQ,OAAO,KAAK,aAAa;OAChC,MAAM,QAAQ,WAAW,QAAQ,SAAS;AAC1C,WAAI,CAAC,MAAO,QAAO;OACnB,MAAM,QAAQ,UAAU,MAAM,MAAM,SAAS;AAC7C,cACE,qBAAC;QAAoB,WAAU;mBAC7B,oBAAC;SAAG,WAAU;mBACX,MAAM;UACJ,EACL,oBAAC;SAAG,WAAU;mBACX,YAAY,OAAO,MAAM,OAAO;UAC9B;UANG,MAAM,IAOV;QAER;OACC;;MA7BA,IA8BD,CACN;IACE;GACF;;AAIV,SAAS,WAAW,QAAyB,KAAa;AACxD,QAAO,OAAO,MAAM,UAAU,MAAM,QAAQ,IAAI"}
1
+ {"version":3,"file":"DataViewDetail.js","names":[],"sources":["../../../src/components/data-view/DataViewDetail.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport type {\n DataViewDetailConfig,\n DataViewField,\n DataViewSpec,\n} from '@contractspec/lib.contracts/data-views';\nimport { cn } from '../../lib/utils';\nimport { DataViewFormattedValue, getAtPath } from './utils';\nimport { MarkdownRenderer } from '@contractspec/lib.example-shared-ui';\n\nexport interface DataViewDetailProps {\n spec: DataViewSpec;\n item: Record<string, unknown> | null;\n className?: string;\n emptyState?: React.ReactNode;\n headerActions?: React.ReactNode;\n}\n\nexport function DataViewDetail({\n spec,\n item,\n className,\n emptyState,\n headerActions,\n}: DataViewDetailProps) {\n if (spec.view.kind !== 'detail') {\n throw new Error(\n `DataViewDetail received view kind \"${spec.view.kind}\", expected \"detail\".`\n );\n }\n\n const view = spec.view as DataViewDetailConfig;\n const fields = view.fields;\n\n if (!item) {\n return (\n <div className={cn('flex w-full flex-col gap-4', className)}>\n <div className=\"flex items-center justify-between\">\n <h3 className=\"text-foreground text-base font-semibold\">\n {spec.meta.title}\n </h3>\n {headerActions}\n </div>\n {emptyState ?? (\n <div className=\"border-muted-foreground/40 text-muted-foreground rounded-md border border-dashed p-8 text-center text-sm\">\n Select a record to view details.\n </div>\n )}\n </div>\n );\n }\n\n const sections =\n view.sections && view.sections.length > 0\n ? view.sections\n : [{ fields: fields.map((field) => field.key) }];\n\n return (\n <div className={cn('flex w-full flex-col gap-6', className)}>\n <div className=\"flex items-center justify-between\">\n <div>\n <h3 className=\"text-foreground text-xl font-semibold\">\n {spec.meta.title}\n </h3>\n <div className=\"text-muted-foreground text-sm\">\n <MarkdownRenderer content={spec.meta.description ?? ''} />\n </div>\n </div>\n {headerActions}\n </div>\n <div className=\"flex flex-col gap-6\">\n {sections.map((section, idx) => (\n <div\n key={idx}\n className=\"border-border bg-card rounded-lg border p-4 shadow-sm\"\n >\n {section.title ? (\n <h4 className=\"text-muted-foreground mb-2 text-sm font-semibold tracking-wide uppercase\">\n {section.title}\n </h4>\n ) : null}\n {section.description ? (\n <div className=\"text-muted-foreground mb-4 text-sm\">\n <MarkdownRenderer content={section.description} />\n </div>\n ) : null}\n <dl className=\"grid gap-4 md:grid-cols-2\">\n {section.fields.map((fieldKey) => {\n const field = fieldByKey(fields, fieldKey);\n if (!field) return null;\n const value = getAtPath(item, field.dataPath);\n return (\n <div key={field.key} className=\"flex flex-col gap-1\">\n <dt className=\"text-muted-foreground/80 text-xs font-semibold uppercase\">\n {field.label}\n </dt>\n <dd className=\"text-foreground text-sm\">\n <DataViewFormattedValue\n value={value}\n format={field.format}\n />\n </dd>\n </div>\n );\n })}\n </dl>\n </div>\n ))}\n </div>\n </div>\n );\n}\n\nfunction fieldByKey(fields: DataViewField[], key: string) {\n return fields.find((field) => field.key === key);\n}\n"],"mappings":";;;;;;;;;;AAoBA,SAAgB,eAAe,EAC7B,MACA,MACA,WACA,YACA,iBACsB;AACtB,KAAI,KAAK,KAAK,SAAS,SACrB,OAAM,IAAI,MACR,sCAAsC,KAAK,KAAK,KAAK,uBACtD;CAGH,MAAM,OAAO,KAAK;CAClB,MAAM,SAAS,KAAK;AAEpB,KAAI,CAAC,KACH,QACE,qBAAC;EAAI,WAAW,GAAG,8BAA8B,UAAU;aACzD,qBAAC;GAAI,WAAU;cACb,oBAAC;IAAG,WAAU;cACX,KAAK,KAAK;KACR,EACJ;IACG,EACL,cACC,oBAAC;GAAI,WAAU;aAA2G;IAEpH;GAEJ;CAIV,MAAM,WACJ,KAAK,YAAY,KAAK,SAAS,SAAS,IACpC,KAAK,WACL,CAAC,EAAE,QAAQ,OAAO,KAAK,UAAU,MAAM,IAAI,EAAE,CAAC;AAEpD,QACE,qBAAC;EAAI,WAAW,GAAG,8BAA8B,UAAU;aACzD,qBAAC;GAAI,WAAU;cACb,qBAAC,oBACC,oBAAC;IAAG,WAAU;cACX,KAAK,KAAK;KACR,EACL,oBAAC;IAAI,WAAU;cACb,oBAAC,oBAAiB,SAAS,KAAK,KAAK,eAAe,KAAM;KACtD,IACF,EACL;IACG,EACN,oBAAC;GAAI,WAAU;aACZ,SAAS,KAAK,SAAS,QACtB,qBAAC;IAEC,WAAU;;KAET,QAAQ,QACP,oBAAC;MAAG,WAAU;gBACX,QAAQ;OACN,GACH;KACH,QAAQ,cACP,oBAAC;MAAI,WAAU;gBACb,oBAAC,oBAAiB,SAAS,QAAQ,cAAe;OAC9C,GACJ;KACJ,oBAAC;MAAG,WAAU;gBACX,QAAQ,OAAO,KAAK,aAAa;OAChC,MAAM,QAAQ,WAAW,QAAQ,SAAS;AAC1C,WAAI,CAAC,MAAO,QAAO;OACnB,MAAM,QAAQ,UAAU,MAAM,MAAM,SAAS;AAC7C,cACE,qBAAC;QAAoB,WAAU;mBAC7B,oBAAC;SAAG,WAAU;mBACX,MAAM;UACJ,EACL,oBAAC;SAAG,WAAU;mBACZ,oBAAC;UACQ;UACP,QAAQ,MAAM;WACd;UACC;UATG,MAAM,IAUV;QAER;OACC;;MAhCA,IAiCD,CACN;IACE;GACF;;AAIV,SAAS,WAAW,QAAyB,KAAa;AACxD,QAAO,OAAO,MAAM,UAAU,MAAM,QAAQ,IAAI"}
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
 
3
3
  import { cn } from "../../lib/utils.js";
4
- import { formatValue, getAtPath } from "./utils.js";
4
+ import { DisplayValue } from "./DataViewTable.js";
5
5
  import "react";
6
6
  import { jsx, jsxs } from "react/jsx-runtime";
7
7
 
@@ -30,7 +30,11 @@ function DataViewList({ spec, items, className, renderActions, onSelect, emptySt
30
30
  className: "flex flex-1 flex-col gap-1",
31
31
  children: [primaryField ? /* @__PURE__ */ jsx("span", {
32
32
  className: "text-foreground text-base font-medium",
33
- children: displayValue(record, fields, primaryField)
33
+ children: /* @__PURE__ */ jsx(DisplayValue, {
34
+ item: record,
35
+ fields,
36
+ fieldKey: primaryField
37
+ })
34
38
  }) : null, /* @__PURE__ */ jsx("div", {
35
39
  className: "text-muted-foreground flex flex-wrap gap-x-4 gap-y-1 text-sm",
36
40
  children: secondaryFieldKeys(view, primaryField).map((fieldKey) => /* @__PURE__ */ jsxs("span", {
@@ -38,7 +42,11 @@ function DataViewList({ spec, items, className, renderActions, onSelect, emptySt
38
42
  children: [/* @__PURE__ */ jsx("span", {
39
43
  className: "text-foreground/80 font-medium",
40
44
  children: fieldLabel(fields, fieldKey)
41
- }), /* @__PURE__ */ jsx("span", { children: displayValue(record, fields, fieldKey) })]
45
+ }), /* @__PURE__ */ jsx("span", { children: /* @__PURE__ */ jsx(DisplayValue, {
46
+ item: record,
47
+ fields,
48
+ fieldKey
49
+ }) })]
42
50
  }, fieldKey))
43
51
  })]
44
52
  }), renderActions ? /* @__PURE__ */ jsx("div", {
@@ -56,14 +64,6 @@ function toRecord(value) {
56
64
  function fieldLabel(fields, key) {
57
65
  return fields.find((field) => field.key === key)?.label ?? key;
58
66
  }
59
- function fieldByKey(fields, key) {
60
- return fields.find((field) => field.key === key);
61
- }
62
- function displayValue(item, fields, key) {
63
- const field = fieldByKey(fields, key);
64
- if (!field) return "";
65
- return formatValue(getAtPath(item, field.dataPath), field.format);
66
- }
67
67
  function secondaryFieldKeys(view, primaryField) {
68
68
  if (view.secondaryFields?.length) return view.secondaryFields;
69
69
  return view.fields.map((field) => field.key).filter((key) => key !== primaryField);
@@ -1 +1 @@
1
- {"version":3,"file":"DataViewList.js","names":[],"sources":["../../../src/components/data-view/DataViewList.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport type {\n DataViewSpec,\n DataViewListConfig,\n DataViewField,\n} from '@contractspec/lib.contracts/data-views';\nimport { cn } from '../../lib/utils';\nimport { getAtPath, formatValue } from './utils';\n\nexport interface DataViewListProps<TItem = Record<string, unknown>> {\n spec: DataViewSpec;\n items: readonly TItem[];\n className?: string;\n renderActions?: (item: TItem) => React.ReactNode;\n onSelect?: (item: TItem) => void;\n emptyState?: React.ReactNode;\n}\n\nexport function DataViewList<TItem = Record<string, unknown>>({\n spec,\n items,\n className,\n renderActions,\n onSelect,\n emptyState,\n}: DataViewListProps<TItem>) {\n if (spec.view.kind !== 'list') {\n throw new Error(\n `DataViewList received view kind \"${spec.view.kind}\", expected \"list\".`\n );\n }\n const view = spec.view as DataViewListConfig;\n const fields = view.fields;\n const primaryField =\n view.primaryField ??\n fields.find((field) => field.key === view.primaryField)?.key ??\n fields[0]?.key;\n\n if (!items.length) {\n return (\n <div className={cn('flex w-full flex-col gap-4', className)}>\n {emptyState ?? (\n <div className=\"border-muted-foreground/40 text-muted-foreground rounded-md border border-dashed p-8 text-center text-sm\">\n No records available.\n </div>\n )}\n </div>\n );\n }\n\n return (\n <div className={cn('flex w-full flex-col gap-4', className)}>\n {items.map((item, idx) => {\n const record = toRecord(item);\n return (\n <button\n type=\"button\"\n key={idx}\n className={cn(\n 'border-muted bg-card hover:border-primary/40 focus-visible:border-primary focus-visible:ring-primary/40 flex w-full flex-col gap-2 rounded-lg border p-4 text-left shadow-sm transition hover:shadow-md focus-visible:ring-2 focus-visible:outline-none',\n view.layout === 'compact' &&\n 'md:flex-row md:items-center md:gap-4'\n )}\n onClick={() => onSelect?.(item)}\n >\n <div className=\"flex flex-1 flex-col gap-1\">\n {primaryField ? (\n <span className=\"text-foreground text-base font-medium\">\n {displayValue(record, fields, primaryField)}\n </span>\n ) : null}\n <div className=\"text-muted-foreground flex flex-wrap gap-x-4 gap-y-1 text-sm\">\n {secondaryFieldKeys(view, primaryField).map((fieldKey) => (\n <span key={fieldKey} className=\"flex items-center gap-1.5\">\n <span className=\"text-foreground/80 font-medium\">\n {fieldLabel(fields, fieldKey)}\n </span>\n <span>{displayValue(record, fields, fieldKey)}</span>\n </span>\n ))}\n </div>\n </div>\n {renderActions ? (\n <div className=\"flex shrink-0 items-center gap-2\">\n {renderActions(item)}\n </div>\n ) : null}\n </button>\n );\n })}\n </div>\n );\n}\n\nfunction toRecord(value: unknown): Record<string, unknown> {\n if (value && typeof value === 'object') {\n return value as Record<string, unknown>;\n }\n return {};\n}\n\nfunction fieldLabel(fields: DataViewField[], key: string) {\n return fields.find((field) => field.key === key)?.label ?? key;\n}\n\nfunction fieldByKey(fields: DataViewField[], key?: string) {\n return fields.find((field) => field.key === key);\n}\n\nfunction displayValue(\n item: Record<string, unknown>,\n fields: DataViewField[],\n key: string\n) {\n const field = fieldByKey(fields, key);\n if (!field) return '';\n const value = getAtPath(item, field.dataPath);\n return formatValue(value, field.format);\n}\n\nfunction secondaryFieldKeys(view: DataViewListConfig, primaryField?: string) {\n if (view.secondaryFields?.length) return view.secondaryFields;\n return view.fields\n .map((field) => field.key)\n .filter((key) => key !== primaryField);\n}\n"],"mappings":";;;;;;;;AAoBA,SAAgB,aAA8C,EAC5D,MACA,OACA,WACA,eACA,UACA,cAC2B;AAC3B,KAAI,KAAK,KAAK,SAAS,OACrB,OAAM,IAAI,MACR,oCAAoC,KAAK,KAAK,KAAK,qBACpD;CAEH,MAAM,OAAO,KAAK;CAClB,MAAM,SAAS,KAAK;CACpB,MAAM,eACJ,KAAK,gBACL,OAAO,MAAM,UAAU,MAAM,QAAQ,KAAK,aAAa,EAAE,OACzD,OAAO,IAAI;AAEb,KAAI,CAAC,MAAM,OACT,QACE,oBAAC;EAAI,WAAW,GAAG,8BAA8B,UAAU;YACxD,cACC,oBAAC;GAAI,WAAU;aAA2G;IAEpH;GAEJ;AAIV,QACE,oBAAC;EAAI,WAAW,GAAG,8BAA8B,UAAU;YACxD,MAAM,KAAK,MAAM,QAAQ;GACxB,MAAM,SAAS,SAAS,KAAK;AAC7B,UACE,qBAAC;IACC,MAAK;IAEL,WAAW,GACT,2PACA,KAAK,WAAW,aACd,uCACH;IACD,eAAe,WAAW,KAAK;eAE/B,qBAAC;KAAI,WAAU;gBACZ,eACC,oBAAC;MAAK,WAAU;gBACb,aAAa,QAAQ,QAAQ,aAAa;OACtC,GACL,MACJ,oBAAC;MAAI,WAAU;gBACZ,mBAAmB,MAAM,aAAa,CAAC,KAAK,aAC3C,qBAAC;OAAoB,WAAU;kBAC7B,oBAAC;QAAK,WAAU;kBACb,WAAW,QAAQ,SAAS;SACxB,EACP,oBAAC,oBAAM,aAAa,QAAQ,QAAQ,SAAS,GAAQ;SAJ5C,SAKJ,CACP;OACE;MACF,EACL,gBACC,oBAAC;KAAI,WAAU;eACZ,cAAc,KAAK;MAChB,GACJ;MA7BC,IA8BE;IAEX;GACE;;AAIV,SAAS,SAAS,OAAyC;AACzD,KAAI,SAAS,OAAO,UAAU,SAC5B,QAAO;AAET,QAAO,EAAE;;AAGX,SAAS,WAAW,QAAyB,KAAa;AACxD,QAAO,OAAO,MAAM,UAAU,MAAM,QAAQ,IAAI,EAAE,SAAS;;AAG7D,SAAS,WAAW,QAAyB,KAAc;AACzD,QAAO,OAAO,MAAM,UAAU,MAAM,QAAQ,IAAI;;AAGlD,SAAS,aACP,MACA,QACA,KACA;CACA,MAAM,QAAQ,WAAW,QAAQ,IAAI;AACrC,KAAI,CAAC,MAAO,QAAO;AAEnB,QAAO,YADO,UAAU,MAAM,MAAM,SAAS,EACnB,MAAM,OAAO;;AAGzC,SAAS,mBAAmB,MAA0B,cAAuB;AAC3E,KAAI,KAAK,iBAAiB,OAAQ,QAAO,KAAK;AAC9C,QAAO,KAAK,OACT,KAAK,UAAU,MAAM,IAAI,CACzB,QAAQ,QAAQ,QAAQ,aAAa"}
1
+ {"version":3,"file":"DataViewList.js","names":[],"sources":["../../../src/components/data-view/DataViewList.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport type {\n DataViewField,\n DataViewListConfig,\n DataViewSpec,\n} from '@contractspec/lib.contracts/data-views';\nimport { cn } from '../../lib/utils';\nimport { DisplayValue } from './DataViewTable';\n\nexport interface DataViewListProps<TItem = Record<string, unknown>> {\n spec: DataViewSpec;\n items: readonly TItem[];\n className?: string;\n renderActions?: (item: TItem) => React.ReactNode;\n onSelect?: (item: TItem) => void;\n emptyState?: React.ReactNode;\n}\n\nexport function DataViewList<TItem = Record<string, unknown>>({\n spec,\n items,\n className,\n renderActions,\n onSelect,\n emptyState,\n}: DataViewListProps<TItem>) {\n if (spec.view.kind !== 'list') {\n throw new Error(\n `DataViewList received view kind \"${spec.view.kind}\", expected \"list\".`\n );\n }\n const view = spec.view as DataViewListConfig;\n const fields = view.fields;\n const primaryField =\n view.primaryField ??\n fields.find((field) => field.key === view.primaryField)?.key ??\n fields[0]?.key;\n\n if (!items.length) {\n return (\n <div className={cn('flex w-full flex-col gap-4', className)}>\n {emptyState ?? (\n <div className=\"border-muted-foreground/40 text-muted-foreground rounded-md border border-dashed p-8 text-center text-sm\">\n No records available.\n </div>\n )}\n </div>\n );\n }\n\n return (\n <div className={cn('flex w-full flex-col gap-4', className)}>\n {items.map((item, idx) => {\n const record = toRecord(item);\n return (\n <button\n type=\"button\"\n key={idx}\n className={cn(\n 'border-muted bg-card hover:border-primary/40 focus-visible:border-primary focus-visible:ring-primary/40 flex w-full flex-col gap-2 rounded-lg border p-4 text-left shadow-sm transition hover:shadow-md focus-visible:ring-2 focus-visible:outline-none',\n view.layout === 'compact' &&\n 'md:flex-row md:items-center md:gap-4'\n )}\n onClick={() => onSelect?.(item)}\n >\n <div className=\"flex flex-1 flex-col gap-1\">\n {primaryField ? (\n <span className=\"text-foreground text-base font-medium\">\n <DisplayValue\n item={record}\n fields={fields}\n fieldKey={primaryField}\n />\n </span>\n ) : null}\n <div className=\"text-muted-foreground flex flex-wrap gap-x-4 gap-y-1 text-sm\">\n {secondaryFieldKeys(view, primaryField).map((fieldKey) => (\n <span key={fieldKey} className=\"flex items-center gap-1.5\">\n <span className=\"text-foreground/80 font-medium\">\n {fieldLabel(fields, fieldKey)}\n </span>\n <span>\n <DisplayValue\n item={record}\n fields={fields}\n fieldKey={fieldKey}\n />\n </span>\n </span>\n ))}\n </div>\n </div>\n {renderActions ? (\n <div className=\"flex shrink-0 items-center gap-2\">\n {renderActions(item)}\n </div>\n ) : null}\n </button>\n );\n })}\n </div>\n );\n}\n\nfunction toRecord(value: unknown): Record<string, unknown> {\n if (value && typeof value === 'object') {\n return value as Record<string, unknown>;\n }\n return {};\n}\n\nfunction fieldLabel(fields: DataViewField[], key: string) {\n return fields.find((field) => field.key === key)?.label ?? key;\n}\n\nfunction secondaryFieldKeys(view: DataViewListConfig, primaryField?: string) {\n if (view.secondaryFields?.length) return view.secondaryFields;\n return view.fields\n .map((field) => field.key)\n .filter((key) => key !== primaryField);\n}\n"],"mappings":";;;;;;;;AAoBA,SAAgB,aAA8C,EAC5D,MACA,OACA,WACA,eACA,UACA,cAC2B;AAC3B,KAAI,KAAK,KAAK,SAAS,OACrB,OAAM,IAAI,MACR,oCAAoC,KAAK,KAAK,KAAK,qBACpD;CAEH,MAAM,OAAO,KAAK;CAClB,MAAM,SAAS,KAAK;CACpB,MAAM,eACJ,KAAK,gBACL,OAAO,MAAM,UAAU,MAAM,QAAQ,KAAK,aAAa,EAAE,OACzD,OAAO,IAAI;AAEb,KAAI,CAAC,MAAM,OACT,QACE,oBAAC;EAAI,WAAW,GAAG,8BAA8B,UAAU;YACxD,cACC,oBAAC;GAAI,WAAU;aAA2G;IAEpH;GAEJ;AAIV,QACE,oBAAC;EAAI,WAAW,GAAG,8BAA8B,UAAU;YACxD,MAAM,KAAK,MAAM,QAAQ;GACxB,MAAM,SAAS,SAAS,KAAK;AAC7B,UACE,qBAAC;IACC,MAAK;IAEL,WAAW,GACT,2PACA,KAAK,WAAW,aACd,uCACH;IACD,eAAe,WAAW,KAAK;eAE/B,qBAAC;KAAI,WAAU;gBACZ,eACC,oBAAC;MAAK,WAAU;gBACd,oBAAC;OACC,MAAM;OACE;OACR,UAAU;QACV;OACG,GACL,MACJ,oBAAC;MAAI,WAAU;gBACZ,mBAAmB,MAAM,aAAa,CAAC,KAAK,aAC3C,qBAAC;OAAoB,WAAU;kBAC7B,oBAAC;QAAK,WAAU;kBACb,WAAW,QAAQ,SAAS;SACxB,EACP,oBAAC,oBACC,oBAAC;QACC,MAAM;QACE;QACE;SACV,GACG;SAVE,SAWJ,CACP;OACE;MACF,EACL,gBACC,oBAAC;KAAI,WAAU;eACZ,cAAc,KAAK;MAChB,GACJ;MAvCC,IAwCE;IAEX;GACE;;AAIV,SAAS,SAAS,OAAyC;AACzD,KAAI,SAAS,OAAO,UAAU,SAC5B,QAAO;AAET,QAAO,EAAE;;AAGX,SAAS,WAAW,QAAyB,KAAa;AACxD,QAAO,OAAO,MAAM,UAAU,MAAM,QAAQ,IAAI,EAAE,SAAS;;AAG7D,SAAS,mBAAmB,MAA0B,cAAuB;AAC3E,KAAI,KAAK,iBAAiB,OAAQ,QAAO,KAAK;AAC9C,QAAO,KAAK,OACT,KAAK,UAAU,MAAM,IAAI,CACzB,QAAQ,QAAQ,QAAQ,aAAa"}
@@ -1,8 +1,8 @@
1
1
  'use client';
2
2
 
3
3
  import { FiltersToolbar } from "../molecules/FiltersToolbar.js";
4
- import { DataViewList } from "./DataViewList.js";
5
4
  import { DataViewTable } from "./DataViewTable.js";
5
+ import { DataViewList } from "./DataViewList.js";
6
6
  import { DataViewDetail } from "./DataViewDetail.js";
7
7
  import * as React from "react";
8
8
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
 
3
3
  import { cn } from "../../lib/utils.js";
4
- import { formatValue, getAtPath } from "./utils.js";
4
+ import { DataViewFormattedValue, getAtPath } from "./utils.js";
5
5
  import "react";
6
6
  import { jsx, jsxs } from "react/jsx-runtime";
7
7
 
@@ -59,7 +59,11 @@ function DataViewTable({ spec, items, className, onRowClick, emptyState, headerA
59
59
  onClick: () => onRowClick?.(item),
60
60
  children: columns.map((column) => /* @__PURE__ */ jsx("td", {
61
61
  className: cn("text-foreground px-4 py-3", alignmentClass(column.align)),
62
- children: displayValue(item, fields, column.field)
62
+ children: /* @__PURE__ */ jsx(DisplayValue, {
63
+ item,
64
+ fields,
65
+ fieldKey: column.field
66
+ })
63
67
  }, column.field))
64
68
  }, rowIdx))
65
69
  })]
@@ -75,10 +79,13 @@ function fieldLabel(fields, key) {
75
79
  function fieldByKey(fields, key) {
76
80
  return fields.find((field) => field.key === key);
77
81
  }
78
- function displayValue(item, fields, key) {
79
- const field = fieldByKey(fields, key);
82
+ function DisplayValue({ item, fields, fieldKey }) {
83
+ const field = fieldByKey(fields, fieldKey);
80
84
  if (!field) return "";
81
- return formatValue(getAtPath(item, field.dataPath), field.format);
85
+ return /* @__PURE__ */ jsx(DataViewFormattedValue, {
86
+ value: getAtPath(item, field.dataPath),
87
+ format: field.format
88
+ });
82
89
  }
83
90
  function alignmentClass(align) {
84
91
  switch (align) {
@@ -89,5 +96,5 @@ function alignmentClass(align) {
89
96
  }
90
97
 
91
98
  //#endregion
92
- export { DataViewTable };
99
+ export { DataViewTable, DisplayValue };
93
100
  //# sourceMappingURL=DataViewTable.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"DataViewTable.js","names":[],"sources":["../../../src/components/data-view/DataViewTable.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport type {\n DataViewSpec,\n DataViewTableConfig,\n DataViewField,\n} from '@contractspec/lib.contracts/data-views';\nimport { cn } from '../../lib/utils';\nimport { getAtPath, formatValue } from './utils';\n\nexport interface DataViewTableProps {\n spec: DataViewSpec;\n items: Record<string, unknown>[];\n className?: string;\n onRowClick?: (item: Record<string, unknown>) => void;\n emptyState?: React.ReactNode;\n headerActions?: React.ReactNode;\n footer?: React.ReactNode;\n}\n\nexport function DataViewTable({\n spec,\n items,\n className,\n onRowClick,\n emptyState,\n headerActions,\n footer,\n}: DataViewTableProps) {\n if (spec.view.kind !== 'table') {\n throw new Error(\n `DataViewTable received view kind \"${spec.view.kind}\", expected \"table\".`\n );\n }\n\n const view = spec.view as DataViewTableConfig;\n const fields = view.fields;\n const columns =\n view.columns?.map((column) => ({\n ...column,\n label: column.label ?? fieldLabel(fields, column.field),\n })) ??\n fields.map((field) => ({\n field: field.key,\n label: field.label,\n align: 'left' as const,\n }));\n\n if (!items.length) {\n return (\n <div className={cn('flex w-full flex-col gap-4', className)}>\n <div className=\"flex items-center justify-between\">\n <h3 className=\"text-foreground text-base font-semibold\">\n {spec.meta.title}\n </h3>\n {headerActions}\n </div>\n {emptyState ?? (\n <div className=\"border-muted-foreground/40 text-muted-foreground rounded-md border border-dashed p-8 text-center text-sm\">\n No records available.\n </div>\n )}\n </div>\n );\n }\n\n return (\n <div className={cn('flex w-full flex-col gap-4', className)}>\n <div className=\"flex items-center justify-between\">\n <h3 className=\"text-foreground text-base font-semibold\">\n {spec.meta.title}\n </h3>\n {headerActions}\n </div>\n <div className=\"border-border bg-card overflow-x-auto rounded-lg border shadow-sm\">\n <table\n className={cn(\n 'divide-border min-w-full divide-y text-sm',\n view.density === 'compact' ? 'text-sm' : 'text-base'\n )}\n >\n <thead className=\"bg-muted/50\">\n <tr>\n {columns.map((column, columnIdx) => (\n <th\n key={`${column.field}.${columnIdx}`}\n scope=\"col\"\n className={cn(\n 'text-muted-foreground px-4 py-3 text-left font-semibold',\n alignmentClass(column.align)\n )}\n >\n {column.label}\n </th>\n ))}\n </tr>\n </thead>\n <tbody className=\"divide-border bg-background divide-y\">\n {items.map((item, rowIdx) => (\n <tr\n key={rowIdx}\n className={cn(\n onRowClick &&\n 'hover:bg-muted/30 cursor-pointer transition-colors'\n )}\n onClick={() => onRowClick?.(item)}\n >\n {columns.map((column) => (\n <td\n key={column.field}\n className={cn(\n 'text-foreground px-4 py-3',\n alignmentClass(column.align)\n )}\n >\n {displayValue(item, fields, column.field)}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n {footer}\n </div>\n );\n}\n\nfunction fieldLabel(fields: DataViewField[], key: string) {\n return fields.find((field) => field.key === key)?.label ?? key;\n}\n\nfunction fieldByKey(fields: DataViewField[], key: string) {\n return fields.find((field) => field.key === key);\n}\n\nfunction displayValue(\n item: Record<string, unknown>,\n fields: DataViewField[],\n key: string\n) {\n const field = fieldByKey(fields, key);\n if (!field) return '';\n const value = getAtPath(item, field.dataPath);\n return formatValue(value, field.format);\n}\n\nfunction alignmentClass(\n align: 'left' | 'center' | 'right' | undefined\n): string | undefined {\n switch (align) {\n case 'center':\n return 'text-center';\n case 'right':\n return 'text-right';\n default:\n return 'text-left';\n }\n}\n"],"mappings":";;;;;;;;AAqBA,SAAgB,cAAc,EAC5B,MACA,OACA,WACA,YACA,YACA,eACA,UACqB;AACrB,KAAI,KAAK,KAAK,SAAS,QACrB,OAAM,IAAI,MACR,qCAAqC,KAAK,KAAK,KAAK,sBACrD;CAGH,MAAM,OAAO,KAAK;CAClB,MAAM,SAAS,KAAK;CACpB,MAAM,UACJ,KAAK,SAAS,KAAK,YAAY;EAC7B,GAAG;EACH,OAAO,OAAO,SAAS,WAAW,QAAQ,OAAO,MAAM;EACxD,EAAE,IACH,OAAO,KAAK,WAAW;EACrB,OAAO,MAAM;EACb,OAAO,MAAM;EACb,OAAO;EACR,EAAE;AAEL,KAAI,CAAC,MAAM,OACT,QACE,qBAAC;EAAI,WAAW,GAAG,8BAA8B,UAAU;aACzD,qBAAC;GAAI,WAAU;cACb,oBAAC;IAAG,WAAU;cACX,KAAK,KAAK;KACR,EACJ;IACG,EACL,cACC,oBAAC;GAAI,WAAU;aAA2G;IAEpH;GAEJ;AAIV,QACE,qBAAC;EAAI,WAAW,GAAG,8BAA8B,UAAU;;GACzD,qBAAC;IAAI,WAAU;eACb,oBAAC;KAAG,WAAU;eACX,KAAK,KAAK;MACR,EACJ;KACG;GACN,oBAAC;IAAI,WAAU;cACb,qBAAC;KACC,WAAW,GACT,6CACA,KAAK,YAAY,YAAY,YAAY,YAC1C;gBAED,oBAAC;MAAM,WAAU;gBACf,oBAAC,kBACE,QAAQ,KAAK,QAAQ,cACpB,oBAAC;OAEC,OAAM;OACN,WAAW,GACT,2DACA,eAAe,OAAO,MAAM,CAC7B;iBAEA,OAAO;SAPH,GAAG,OAAO,MAAM,GAAG,YAQrB,CACL,GACC;OACC,EACR,oBAAC;MAAM,WAAU;gBACd,MAAM,KAAK,MAAM,WAChB,oBAAC;OAEC,WAAW,GACT,cACE,qDACH;OACD,eAAe,aAAa,KAAK;iBAEhC,QAAQ,KAAK,WACZ,oBAAC;QAEC,WAAW,GACT,6BACA,eAAe,OAAO,MAAM,CAC7B;kBAEA,aAAa,MAAM,QAAQ,OAAO,MAAM;UANpC,OAAO,MAOT,CACL;SAjBG,OAkBF,CACL;OACI;MACF;KACJ;GACL;;GACG;;AAIV,SAAS,WAAW,QAAyB,KAAa;AACxD,QAAO,OAAO,MAAM,UAAU,MAAM,QAAQ,IAAI,EAAE,SAAS;;AAG7D,SAAS,WAAW,QAAyB,KAAa;AACxD,QAAO,OAAO,MAAM,UAAU,MAAM,QAAQ,IAAI;;AAGlD,SAAS,aACP,MACA,QACA,KACA;CACA,MAAM,QAAQ,WAAW,QAAQ,IAAI;AACrC,KAAI,CAAC,MAAO,QAAO;AAEnB,QAAO,YADO,UAAU,MAAM,MAAM,SAAS,EACnB,MAAM,OAAO;;AAGzC,SAAS,eACP,OACoB;AACpB,SAAQ,OAAR;EACE,KAAK,SACH,QAAO;EACT,KAAK,QACH,QAAO;EACT,QACE,QAAO"}
1
+ {"version":3,"file":"DataViewTable.js","names":[],"sources":["../../../src/components/data-view/DataViewTable.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport type {\n DataViewField,\n DataViewSpec,\n DataViewTableConfig,\n} from '@contractspec/lib.contracts/data-views';\nimport { cn } from '../../lib/utils';\nimport { DataViewFormattedValue, getAtPath } from './utils';\n\nexport interface DataViewTableProps {\n spec: DataViewSpec;\n items: Record<string, unknown>[];\n className?: string;\n onRowClick?: (item: Record<string, unknown>) => void;\n emptyState?: React.ReactNode;\n headerActions?: React.ReactNode;\n footer?: React.ReactNode;\n}\n\nexport function DataViewTable({\n spec,\n items,\n className,\n onRowClick,\n emptyState,\n headerActions,\n footer,\n}: DataViewTableProps) {\n if (spec.view.kind !== 'table') {\n throw new Error(\n `DataViewTable received view kind \"${spec.view.kind}\", expected \"table\".`\n );\n }\n\n const view = spec.view as DataViewTableConfig;\n const fields = view.fields;\n const columns =\n view.columns?.map((column) => ({\n ...column,\n label: column.label ?? fieldLabel(fields, column.field),\n })) ??\n fields.map((field) => ({\n field: field.key,\n label: field.label,\n align: 'left' as const,\n }));\n\n if (!items.length) {\n return (\n <div className={cn('flex w-full flex-col gap-4', className)}>\n <div className=\"flex items-center justify-between\">\n <h3 className=\"text-foreground text-base font-semibold\">\n {spec.meta.title}\n </h3>\n {headerActions}\n </div>\n {emptyState ?? (\n <div className=\"border-muted-foreground/40 text-muted-foreground rounded-md border border-dashed p-8 text-center text-sm\">\n No records available.\n </div>\n )}\n </div>\n );\n }\n\n return (\n <div className={cn('flex w-full flex-col gap-4', className)}>\n <div className=\"flex items-center justify-between\">\n <h3 className=\"text-foreground text-base font-semibold\">\n {spec.meta.title}\n </h3>\n {headerActions}\n </div>\n <div className=\"border-border bg-card overflow-x-auto rounded-lg border shadow-sm\">\n <table\n className={cn(\n 'divide-border min-w-full divide-y text-sm',\n view.density === 'compact' ? 'text-sm' : 'text-base'\n )}\n >\n <thead className=\"bg-muted/50\">\n <tr>\n {columns.map((column, columnIdx) => (\n <th\n key={`${column.field}.${columnIdx}`}\n scope=\"col\"\n className={cn(\n 'text-muted-foreground px-4 py-3 text-left font-semibold',\n alignmentClass(column.align)\n )}\n >\n {column.label}\n </th>\n ))}\n </tr>\n </thead>\n <tbody className=\"divide-border bg-background divide-y\">\n {items.map((item, rowIdx) => (\n <tr\n key={rowIdx}\n className={cn(\n onRowClick &&\n 'hover:bg-muted/30 cursor-pointer transition-colors'\n )}\n onClick={() => onRowClick?.(item)}\n >\n {columns.map((column) => (\n <td\n key={column.field}\n className={cn(\n 'text-foreground px-4 py-3',\n alignmentClass(column.align)\n )}\n >\n <DisplayValue\n item={item}\n fields={fields}\n fieldKey={column.field}\n />\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n {footer}\n </div>\n );\n}\n\nfunction fieldLabel(fields: DataViewField[], key: string) {\n return fields.find((field) => field.key === key)?.label ?? key;\n}\n\nfunction fieldByKey(fields: DataViewField[], key: string) {\n return fields.find((field) => field.key === key);\n}\n\nexport function DisplayValue({\n item,\n fields,\n fieldKey,\n}: {\n item: Record<string, unknown>;\n fields: DataViewField[];\n fieldKey: string;\n}) {\n const field = fieldByKey(fields, fieldKey);\n if (!field) return '';\n const value = getAtPath(item, field.dataPath);\n return <DataViewFormattedValue value={value} format={field.format} />;\n}\n\nfunction alignmentClass(\n align: 'left' | 'center' | 'right' | undefined\n): string | undefined {\n switch (align) {\n case 'center':\n return 'text-center';\n case 'right':\n return 'text-right';\n default:\n return 'text-left';\n }\n}\n"],"mappings":";;;;;;;;AAqBA,SAAgB,cAAc,EAC5B,MACA,OACA,WACA,YACA,YACA,eACA,UACqB;AACrB,KAAI,KAAK,KAAK,SAAS,QACrB,OAAM,IAAI,MACR,qCAAqC,KAAK,KAAK,KAAK,sBACrD;CAGH,MAAM,OAAO,KAAK;CAClB,MAAM,SAAS,KAAK;CACpB,MAAM,UACJ,KAAK,SAAS,KAAK,YAAY;EAC7B,GAAG;EACH,OAAO,OAAO,SAAS,WAAW,QAAQ,OAAO,MAAM;EACxD,EAAE,IACH,OAAO,KAAK,WAAW;EACrB,OAAO,MAAM;EACb,OAAO,MAAM;EACb,OAAO;EACR,EAAE;AAEL,KAAI,CAAC,MAAM,OACT,QACE,qBAAC;EAAI,WAAW,GAAG,8BAA8B,UAAU;aACzD,qBAAC;GAAI,WAAU;cACb,oBAAC;IAAG,WAAU;cACX,KAAK,KAAK;KACR,EACJ;IACG,EACL,cACC,oBAAC;GAAI,WAAU;aAA2G;IAEpH;GAEJ;AAIV,QACE,qBAAC;EAAI,WAAW,GAAG,8BAA8B,UAAU;;GACzD,qBAAC;IAAI,WAAU;eACb,oBAAC;KAAG,WAAU;eACX,KAAK,KAAK;MACR,EACJ;KACG;GACN,oBAAC;IAAI,WAAU;cACb,qBAAC;KACC,WAAW,GACT,6CACA,KAAK,YAAY,YAAY,YAAY,YAC1C;gBAED,oBAAC;MAAM,WAAU;gBACf,oBAAC,kBACE,QAAQ,KAAK,QAAQ,cACpB,oBAAC;OAEC,OAAM;OACN,WAAW,GACT,2DACA,eAAe,OAAO,MAAM,CAC7B;iBAEA,OAAO;SAPH,GAAG,OAAO,MAAM,GAAG,YAQrB,CACL,GACC;OACC,EACR,oBAAC;MAAM,WAAU;gBACd,MAAM,KAAK,MAAM,WAChB,oBAAC;OAEC,WAAW,GACT,cACE,qDACH;OACD,eAAe,aAAa,KAAK;iBAEhC,QAAQ,KAAK,WACZ,oBAAC;QAEC,WAAW,GACT,6BACA,eAAe,OAAO,MAAM,CAC7B;kBAED,oBAAC;SACO;SACE;SACR,UAAU,OAAO;UACjB;UAVG,OAAO,MAWT,CACL;SArBG,OAsBF,CACL;OACI;MACF;KACJ;GACL;;GACG;;AAIV,SAAS,WAAW,QAAyB,KAAa;AACxD,QAAO,OAAO,MAAM,UAAU,MAAM,QAAQ,IAAI,EAAE,SAAS;;AAG7D,SAAS,WAAW,QAAyB,KAAa;AACxD,QAAO,OAAO,MAAM,UAAU,MAAM,QAAQ,IAAI;;AAGlD,SAAgB,aAAa,EAC3B,MACA,QACA,YAKC;CACD,MAAM,QAAQ,WAAW,QAAQ,SAAS;AAC1C,KAAI,CAAC,MAAO,QAAO;AAEnB,QAAO,oBAAC;EAAuB,OADjB,UAAU,MAAM,MAAM,SAAS;EACA,QAAQ,MAAM;GAAU;;AAGvE,SAAS,eACP,OACoB;AACpB,SAAQ,OAAR;EACE,KAAK,SACH,QAAO;EACT,KAAK,QACH,QAAO;EACT,QACE,QAAO"}
@@ -1,6 +1,10 @@
1
1
  'use client';
2
2
 
3
- //#region src/components/data-view/utils.ts
3
+ import { MarkdownRenderer } from "../../example-shared-ui/src/MarkdownView.js";
4
+ import "../../example-shared-ui/src/index.js";
5
+ import { jsx } from "react/jsx-runtime";
6
+
7
+ //#region src/components/data-view/utils.tsx
4
8
  function getAtPath(source, path) {
5
9
  if (!source) return void 0;
6
10
  if (!path) return source;
@@ -12,7 +16,7 @@ function getAtPath(source, path) {
12
16
  }
13
17
  return current;
14
18
  }
15
- function formatValue(value, format) {
19
+ function DataViewFormattedValue({ value, format }) {
16
20
  if (value == null) return "";
17
21
  switch (format) {
18
22
  case "boolean": return value ? "Yes" : "No";
@@ -26,7 +30,10 @@ function formatValue(value, format) {
26
30
  dateStyle: "medium",
27
31
  timeStyle: "short"
28
32
  });
29
- default: return String(value);
33
+ case "markdown": return /* @__PURE__ */ jsx(MarkdownRenderer, { content: value });
34
+ default:
35
+ console.log("format value", value, format);
36
+ return String(value);
30
37
  }
31
38
  }
32
39
  function formatDate(value, options) {
@@ -39,5 +46,5 @@ function formatDate(value, options) {
39
46
  }
40
47
 
41
48
  //#endregion
42
- export { formatValue, getAtPath };
49
+ export { DataViewFormattedValue, getAtPath };
43
50
  //# sourceMappingURL=utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","names":[],"sources":["../../../src/components/data-view/utils.ts"],"sourcesContent":["'use client';\n\nexport function getAtPath(\n source: Record<string, unknown> | undefined,\n path: string\n): unknown {\n if (!source) return undefined;\n if (!path) return source;\n const segments = path\n .replace(/\\[(\\d+)\\]/g, '.$1')\n .split('.')\n .filter(Boolean);\n\n let current: unknown = source;\n for (const segment of segments) {\n if (\n current == null ||\n (typeof current !== 'object' && !Array.isArray(current))\n )\n return undefined;\n current = (current as Record<string, unknown>)[segment];\n }\n return current;\n}\n\nexport function formatValue(value: unknown, format?: string): string {\n if (value == null) return '';\n switch (format) {\n case 'boolean':\n return value ? 'Yes' : 'No';\n case 'currency':\n return typeof value === 'number'\n ? new Intl.NumberFormat(undefined, {\n style: 'currency',\n currency: 'USD',\n }).format(value)\n : String(value);\n case 'percentage':\n return typeof value === 'number'\n ? `${(value * 100).toFixed(1)}%`\n : String(value);\n case 'date':\n return formatDate(value, {\n dateStyle: 'medium',\n });\n case 'dateTime':\n return formatDate(value, {\n dateStyle: 'medium',\n timeStyle: 'short',\n });\n default:\n return String(value);\n }\n}\n\nfunction formatDate(\n value: unknown,\n options: Intl.DateTimeFormatOptions\n): string {\n if (value instanceof Date) {\n return new Intl.DateTimeFormat(undefined, options).format(value);\n }\n if (typeof value === 'string' || typeof value === 'number') {\n const date = new Date(value);\n if (!Number.isNaN(date.getTime())) {\n return new Intl.DateTimeFormat(undefined, options).format(date);\n }\n }\n return String(value ?? '');\n}\n"],"mappings":";;;AAEA,SAAgB,UACd,QACA,MACS;AACT,KAAI,CAAC,OAAQ,QAAO;AACpB,KAAI,CAAC,KAAM,QAAO;CAClB,MAAM,WAAW,KACd,QAAQ,cAAc,MAAM,CAC5B,MAAM,IAAI,CACV,OAAO,QAAQ;CAElB,IAAI,UAAmB;AACvB,MAAK,MAAM,WAAW,UAAU;AAC9B,MACE,WAAW,QACV,OAAO,YAAY,YAAY,CAAC,MAAM,QAAQ,QAAQ,CAEvD,QAAO;AACT,YAAW,QAAoC;;AAEjD,QAAO;;AAGT,SAAgB,YAAY,OAAgB,QAAyB;AACnE,KAAI,SAAS,KAAM,QAAO;AAC1B,SAAQ,QAAR;EACE,KAAK,UACH,QAAO,QAAQ,QAAQ;EACzB,KAAK,WACH,QAAO,OAAO,UAAU,WACpB,IAAI,KAAK,aAAa,QAAW;GAC/B,OAAO;GACP,UAAU;GACX,CAAC,CAAC,OAAO,MAAM,GAChB,OAAO,MAAM;EACnB,KAAK,aACH,QAAO,OAAO,UAAU,WACpB,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC,KAC5B,OAAO,MAAM;EACnB,KAAK,OACH,QAAO,WAAW,OAAO,EACvB,WAAW,UACZ,CAAC;EACJ,KAAK,WACH,QAAO,WAAW,OAAO;GACvB,WAAW;GACX,WAAW;GACZ,CAAC;EACJ,QACE,QAAO,OAAO,MAAM;;;AAI1B,SAAS,WACP,OACA,SACQ;AACR,KAAI,iBAAiB,KACnB,QAAO,IAAI,KAAK,eAAe,QAAW,QAAQ,CAAC,OAAO,MAAM;AAElE,KAAI,OAAO,UAAU,YAAY,OAAO,UAAU,UAAU;EAC1D,MAAM,OAAO,IAAI,KAAK,MAAM;AAC5B,MAAI,CAAC,OAAO,MAAM,KAAK,SAAS,CAAC,CAC/B,QAAO,IAAI,KAAK,eAAe,QAAW,QAAQ,CAAC,OAAO,KAAK;;AAGnE,QAAO,OAAO,SAAS,GAAG"}
1
+ {"version":3,"file":"utils.js","names":[],"sources":["../../../src/components/data-view/utils.tsx"],"sourcesContent":["'use client';\n\nimport { MarkdownRenderer } from '@contractspec/lib.example-shared-ui';\nimport type { DataViewFieldFormat } from '@contractspec/lib.contracts';\n\nexport function getAtPath(\n source: Record<string, unknown> | undefined,\n path: string\n): unknown {\n if (!source) return undefined;\n if (!path) return source;\n const segments = path\n .replace(/\\[(\\d+)\\]/g, '.$1')\n .split('.')\n .filter(Boolean);\n\n let current: unknown = source;\n for (const segment of segments) {\n if (\n current == null ||\n (typeof current !== 'object' && !Array.isArray(current))\n )\n return undefined;\n current = (current as Record<string, unknown>)[segment];\n }\n return current;\n}\n\nexport function DataViewFormattedValue({\n value,\n format,\n}: {\n value: unknown;\n format?: DataViewFieldFormat;\n}) {\n if (value == null) return '';\n switch (format) {\n case 'boolean':\n return value ? 'Yes' : 'No';\n case 'currency':\n return typeof value === 'number'\n ? new Intl.NumberFormat(undefined, {\n style: 'currency',\n currency: 'USD',\n }).format(value)\n : String(value);\n case 'percentage':\n return typeof value === 'number'\n ? `${(value * 100).toFixed(1)}%`\n : String(value);\n case 'date':\n return formatDate(value, {\n dateStyle: 'medium',\n });\n case 'dateTime':\n return formatDate(value, {\n dateStyle: 'medium',\n timeStyle: 'short',\n });\n case 'markdown':\n return <MarkdownRenderer content={value as string} />;\n default:\n console.log('format value', value, format);\n return String(value);\n }\n}\n\nfunction formatDate(\n value: unknown,\n options: Intl.DateTimeFormatOptions\n): string {\n if (value instanceof Date) {\n return new Intl.DateTimeFormat(undefined, options).format(value);\n }\n if (typeof value === 'string' || typeof value === 'number') {\n const date = new Date(value);\n if (!Number.isNaN(date.getTime())) {\n return new Intl.DateTimeFormat(undefined, options).format(date);\n }\n }\n return String(value ?? '');\n}\n"],"mappings":";;;;;;;AAKA,SAAgB,UACd,QACA,MACS;AACT,KAAI,CAAC,OAAQ,QAAO;AACpB,KAAI,CAAC,KAAM,QAAO;CAClB,MAAM,WAAW,KACd,QAAQ,cAAc,MAAM,CAC5B,MAAM,IAAI,CACV,OAAO,QAAQ;CAElB,IAAI,UAAmB;AACvB,MAAK,MAAM,WAAW,UAAU;AAC9B,MACE,WAAW,QACV,OAAO,YAAY,YAAY,CAAC,MAAM,QAAQ,QAAQ,CAEvD,QAAO;AACT,YAAW,QAAoC;;AAEjD,QAAO;;AAGT,SAAgB,uBAAuB,EACrC,OACA,UAIC;AACD,KAAI,SAAS,KAAM,QAAO;AAC1B,SAAQ,QAAR;EACE,KAAK,UACH,QAAO,QAAQ,QAAQ;EACzB,KAAK,WACH,QAAO,OAAO,UAAU,WACpB,IAAI,KAAK,aAAa,QAAW;GAC/B,OAAO;GACP,UAAU;GACX,CAAC,CAAC,OAAO,MAAM,GAChB,OAAO,MAAM;EACnB,KAAK,aACH,QAAO,OAAO,UAAU,WACpB,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC,KAC5B,OAAO,MAAM;EACnB,KAAK,OACH,QAAO,WAAW,OAAO,EACvB,WAAW,UACZ,CAAC;EACJ,KAAK,WACH,QAAO,WAAW,OAAO;GACvB,WAAW;GACX,WAAW;GACZ,CAAC;EACJ,KAAK,WACH,QAAO,oBAAC,oBAAiB,SAAS,QAAmB;EACvD;AACE,WAAQ,IAAI,gBAAgB,OAAO,OAAO;AAC1C,UAAO,OAAO,MAAM;;;AAI1B,SAAS,WACP,OACA,SACQ;AACR,KAAI,iBAAiB,KACnB,QAAO,IAAI,KAAK,eAAe,QAAW,QAAQ,CAAC,OAAO,MAAM;AAElE,KAAI,OAAO,UAAU,YAAY,OAAO,UAAU,UAAU;EAC1D,MAAM,OAAO,IAAI,KAAK,MAAM;AAC5B,MAAI,CAAC,OAAO,MAAM,KAAK,SAAS,CAAC,CAC/B,QAAO,IAAI,KAAK,eAAe,QAAW,QAAQ,CAAC,OAAO,KAAK;;AAGnE,QAAO,OAAO,SAAS,GAAG"}
@@ -1,5 +1,5 @@
1
1
  import { CodeBlockProps } from "./types.js";
2
- import * as react_jsx_runtime115 from "react/jsx-runtime";
2
+ import * as react_jsx_runtime116 from "react/jsx-runtime";
3
3
 
4
4
  //#region src/components/molecules/CodeBlock/CodeBlock.d.ts
5
5
  declare function CodeBlock({
@@ -11,7 +11,7 @@ declare function CodeBlock({
11
11
  onCopy,
12
12
  className,
13
13
  ...props
14
- }: CodeBlockProps): react_jsx_runtime115.JSX.Element;
14
+ }: CodeBlockProps): react_jsx_runtime116.JSX.Element;
15
15
  //#endregion
16
16
  export { CodeBlock };
17
17
  //# sourceMappingURL=CodeBlock.d.ts.map
@@ -1,5 +1,5 @@
1
1
  import { CommandTabsProps } from "./types.js";
2
- import * as react_jsx_runtime117 from "react/jsx-runtime";
2
+ import * as react_jsx_runtime118 from "react/jsx-runtime";
3
3
 
4
4
  //#region src/components/molecules/CommandTabs/CommandTabs.d.ts
5
5
  declare function CommandTabs({
@@ -8,7 +8,7 @@ declare function CommandTabs({
8
8
  className,
9
9
  onCopy,
10
10
  ...props
11
- }: CommandTabsProps): react_jsx_runtime117.JSX.Element | null;
11
+ }: CommandTabsProps): react_jsx_runtime118.JSX.Element | null;
12
12
  //#endregion
13
13
  export { CommandTabs };
14
14
  //# sourceMappingURL=CommandTabs.d.ts.map
@@ -1,5 +1,5 @@
1
1
  import { CopyButtonProps } from "./types.js";
2
- import * as react_jsx_runtime116 from "react/jsx-runtime";
2
+ import * as react_jsx_runtime117 from "react/jsx-runtime";
3
3
 
4
4
  //#region src/components/molecules/CopyButton/CopyButton.d.ts
5
5
  declare function CopyButton({
@@ -7,7 +7,7 @@ declare function CopyButton({
7
7
  onCopy,
8
8
  className,
9
9
  ...props
10
- }: CopyButtonProps): react_jsx_runtime116.JSX.Element;
10
+ }: CopyButtonProps): react_jsx_runtime117.JSX.Element;
11
11
  //#endregion
12
12
  export { CopyButton };
13
13
  //# sourceMappingURL=CopyButton.d.ts.map
@@ -1,5 +1,5 @@
1
1
  import { InstallCommandProps } from "./types.js";
2
- import * as react_jsx_runtime118 from "react/jsx-runtime";
2
+ import * as react_jsx_runtime119 from "react/jsx-runtime";
3
3
 
4
4
  //#region src/components/molecules/InstallCommand/InstallCommand.d.ts
5
5
 
@@ -22,7 +22,7 @@ declare function InstallCommand({
22
22
  global,
23
23
  onCopy,
24
24
  ...props
25
- }: InstallCommandProps): react_jsx_runtime118.JSX.Element;
25
+ }: InstallCommandProps): react_jsx_runtime119.JSX.Element;
26
26
  //#endregion
27
27
  export { InstallCommand };
28
28
  //# sourceMappingURL=InstallCommand.d.ts.map
@@ -1,5 +1,5 @@
1
1
  import { SkeletonBlockProps } from "./types.js";
2
- import * as react_jsx_runtime110 from "react/jsx-runtime";
2
+ import * as react_jsx_runtime113 from "react/jsx-runtime";
3
3
 
4
4
  //#region src/components/molecules/SkeletonBlock/index.web.d.ts
5
5
  declare function SkeletonBlock({
@@ -7,7 +7,7 @@ declare function SkeletonBlock({
7
7
  h,
8
8
  rounded,
9
9
  className
10
- }: SkeletonBlockProps): react_jsx_runtime110.JSX.Element;
10
+ }: SkeletonBlockProps): react_jsx_runtime113.JSX.Element;
11
11
  //#endregion
12
12
  export { SkeletonBlock };
13
13
  //# sourceMappingURL=index.web.d.ts.map
@@ -1,12 +1,12 @@
1
1
  import { SkeletonCircleProps } from "./types.js";
2
- import * as react_jsx_runtime111 from "react/jsx-runtime";
2
+ import * as react_jsx_runtime114 from "react/jsx-runtime";
3
3
 
4
4
  //#region src/components/molecules/SkeletonCircle/index.web.d.ts
5
5
  declare function SkeletonCircle({
6
6
  size,
7
7
  sizeClass,
8
8
  className
9
- }: SkeletonCircleProps): react_jsx_runtime111.JSX.Element;
9
+ }: SkeletonCircleProps): react_jsx_runtime114.JSX.Element;
10
10
  //#endregion
11
11
  export { SkeletonCircle };
12
12
  //# sourceMappingURL=index.web.d.ts.map
@@ -1,11 +1,11 @@
1
1
  import { SkeletonListProps } from "./types.js";
2
- import * as react_jsx_runtime112 from "react/jsx-runtime";
2
+ import * as react_jsx_runtime115 from "react/jsx-runtime";
3
3
 
4
4
  //#region src/components/molecules/SkeletonList/index.web.d.ts
5
5
  declare function SkeletonList({
6
6
  count,
7
7
  className
8
- }: SkeletonListProps): react_jsx_runtime112.JSX.Element;
8
+ }: SkeletonListProps): react_jsx_runtime115.JSX.Element;
9
9
  //#endregion
10
10
  export { SkeletonList };
11
11
  //# sourceMappingURL=index.web.d.ts.map
@@ -1,5 +1,5 @@
1
1
  import { ListPageTemplateProps } from "./types.js";
2
- import * as react_jsx_runtime109 from "react/jsx-runtime";
2
+ import * as react_jsx_runtime112 from "react/jsx-runtime";
3
3
 
4
4
  //#region src/components/templates/lists/ListPageTemplate/index.web.d.ts
5
5
  declare function ListPageTemplate<T = unknown>({
@@ -17,7 +17,7 @@ declare function ListPageTemplate<T = unknown>({
17
17
  data,
18
18
  renderItem,
19
19
  emptyProps
20
- }: ListPageTemplateProps<T>): react_jsx_runtime109.JSX.Element;
20
+ }: ListPageTemplateProps<T>): react_jsx_runtime112.JSX.Element;
21
21
  //#endregion
22
22
  export { ListPageTemplate };
23
23
  //# sourceMappingURL=index.web.d.ts.map
@@ -0,0 +1,7 @@
1
+ 'use client';
2
+
3
+ import "./hooks/useEvolution.js";
4
+ import { useCallback, useMemo } from "react";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ import { Card } from "@contractspec/lib.ui-kit-web/ui/card";
7
+ import { Badge } from "@contractspec/lib.ui-kit-web/ui/badge";
@@ -0,0 +1,7 @@
1
+ 'use client';
2
+
3
+ import "./hooks/useEvolution.js";
4
+ import { useCallback, useMemo } from "react";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ import { Card } from "@contractspec/lib.ui-kit-web/ui/card";
7
+ import { Badge } from "@contractspec/lib.ui-kit-web/ui/badge";
@@ -0,0 +1,6 @@
1
+ 'use client';
2
+
3
+ import "./lib/runtime-context.js";
4
+ import { useState } from "react";
5
+ import "lucide-react";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
@@ -0,0 +1,119 @@
1
+ 'use client';
2
+
3
+ import "./lib/runtime-context.js";
4
+ import { useCallback, useEffect, useState } from "react";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ import { Card } from "@contractspec/lib.ui-kit-web/ui/card";
7
+ import { Badge } from "@contractspec/lib.ui-kit-web/ui/badge";
8
+
9
+ //#region ../example-shared-ui/src/MarkdownView.tsx
10
+ /**
11
+ * Simple markdown renderer using pre-formatted display
12
+ * For production, consider using react-markdown or similar
13
+ */
14
+ function MarkdownRenderer({ content }) {
15
+ const lines = content.split("\n");
16
+ const rendered = [];
17
+ let i = 0;
18
+ while (i < lines.length) {
19
+ const line = lines[i] ?? "";
20
+ if (line.startsWith("|") && lines[i + 1]?.match(/^\|[\s-|]+\|$/)) {
21
+ const tableLines = [line];
22
+ i++;
23
+ while (i < lines.length && (lines[i]?.startsWith("|") ?? false)) {
24
+ tableLines.push(lines[i] ?? "");
25
+ i++;
26
+ }
27
+ rendered.push(renderTable(tableLines, rendered.length));
28
+ continue;
29
+ }
30
+ if (line.startsWith("# ")) rendered.push(/* @__PURE__ */ jsx("h1", {
31
+ className: "mb-4 text-2xl font-bold",
32
+ children: line.slice(2)
33
+ }, i));
34
+ else if (line.startsWith("## ")) rendered.push(/* @__PURE__ */ jsx("h2", {
35
+ className: "mt-6 mb-3 text-xl font-semibold",
36
+ children: line.slice(3)
37
+ }, i));
38
+ else if (line.startsWith("### ")) rendered.push(/* @__PURE__ */ jsx("h3", {
39
+ className: "mt-4 mb-2 text-lg font-medium",
40
+ children: line.slice(4)
41
+ }, i));
42
+ else if (line.startsWith("> ")) rendered.push(/* @__PURE__ */ jsx("blockquote", {
43
+ className: "text-muted-foreground my-2 border-l-4 border-violet-500/50 pl-4 italic",
44
+ children: line.slice(2)
45
+ }, i));
46
+ else if (line.startsWith("- ")) rendered.push(/* @__PURE__ */ jsx("li", {
47
+ className: "ml-4 list-disc",
48
+ children: formatInlineMarkdown(line.slice(2))
49
+ }, i));
50
+ else if (line.startsWith("**") && line.includes(":**")) {
51
+ const [label, ...rest] = line.split(":**");
52
+ rendered.push(/* @__PURE__ */ jsxs("p", {
53
+ className: "my-1",
54
+ children: [/* @__PURE__ */ jsxs("strong", { children: [label?.slice(2), ":"] }), rest.join(":**")]
55
+ }, i));
56
+ } else if (line.startsWith("_") && line.endsWith("_")) rendered.push(/* @__PURE__ */ jsx("p", {
57
+ className: "text-muted-foreground my-1 italic",
58
+ children: line.slice(1, -1)
59
+ }, i));
60
+ else if (!line.trim()) rendered.push(/* @__PURE__ */ jsx("div", { className: "h-2" }, i));
61
+ else rendered.push(/* @__PURE__ */ jsx("p", {
62
+ className: "my-1",
63
+ children: formatInlineMarkdown(line)
64
+ }, i));
65
+ i++;
66
+ }
67
+ return /* @__PURE__ */ jsx("div", {
68
+ className: "prose prose-sm dark:prose-invert max-w-none",
69
+ children: rendered
70
+ });
71
+ }
72
+ /**
73
+ * Render a markdown table
74
+ */
75
+ function renderTable(lines, keyPrefix) {
76
+ if (lines.length < 2) return null;
77
+ const parseRow = (row) => row.split("|").slice(1, -1).map((cell) => cell.trim());
78
+ const headers = parseRow(lines[0] ?? "");
79
+ const dataRows = lines.slice(2).map(parseRow);
80
+ return /* @__PURE__ */ jsx("div", {
81
+ className: "my-4 overflow-x-auto",
82
+ children: /* @__PURE__ */ jsxs("table", {
83
+ className: "border-border min-w-full border-collapse border text-sm",
84
+ children: [/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", {
85
+ className: "bg-muted/50",
86
+ children: headers.map((header, idx) => /* @__PURE__ */ jsx("th", {
87
+ className: "border-border border px-3 py-2 text-left font-semibold",
88
+ children: header
89
+ }, idx))
90
+ }) }), /* @__PURE__ */ jsx("tbody", { children: dataRows.map((row, rowIdx) => /* @__PURE__ */ jsx("tr", {
91
+ className: "hover:bg-muted/30",
92
+ children: row.map((cell, cellIdx) => /* @__PURE__ */ jsx("td", {
93
+ className: "border-border border px-3 py-2",
94
+ children: formatInlineMarkdown(cell)
95
+ }, cellIdx))
96
+ }, rowIdx)) })]
97
+ })
98
+ }, `table-${keyPrefix}`);
99
+ }
100
+ /**
101
+ * Format inline markdown (bold, code)
102
+ */
103
+ function formatInlineMarkdown(text) {
104
+ return text.split(/(\*\*[^*]+\*\*)/g).map((part, i) => {
105
+ if (part.startsWith("**") && part.endsWith("**")) return /* @__PURE__ */ jsx("strong", { children: part.slice(2, -2) }, i);
106
+ if (part.includes("`")) return part.split(/(`[^`]+`)/g).map((cp, j) => {
107
+ if (cp.startsWith("`") && cp.endsWith("`")) return /* @__PURE__ */ jsx("code", {
108
+ className: "rounded bg-violet-500/10 px-1.5 py-0.5 font-mono text-sm",
109
+ children: cp.slice(1, -1)
110
+ }, `${i}-${j}`);
111
+ return cp;
112
+ });
113
+ return part;
114
+ });
115
+ }
116
+
117
+ //#endregion
118
+ export { MarkdownRenderer };
119
+ //# sourceMappingURL=MarkdownView.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MarkdownView.js","names":[],"sources":["../../../../example-shared-ui/src/MarkdownView.tsx"],"sourcesContent":["'use client';\n\nimport { useCallback, useEffect, useState } from 'react';\nimport {\n Button,\n ErrorState,\n LoaderBlock,\n} from '@contractspec/lib.design-system';\nimport { Card } from '@contractspec/lib.ui-kit-web/ui/card';\nimport { Badge } from '@contractspec/lib.ui-kit-web/ui/badge';\nimport type {\n PresentationTarget,\n TransformEngine,\n} from '@contractspec/lib.contracts';\nimport type { TemplateId } from './lib/types';\n\nimport { useTemplateRuntime } from './lib/runtime-context';\n\nexport interface MarkdownViewProps {\n /** Optional override, otherwise comes from context */\n templateId?: TemplateId;\n presentationId?: string;\n className?: string;\n}\n\ninterface MarkdownOutput {\n mimeType: string;\n body: string;\n}\n\n/**\n * MarkdownView renders template presentations as markdown using TransformEngine.\n * It allows switching between available presentations for the template.\n */\nexport function MarkdownView({\n templateId: propTemplateId,\n presentationId,\n className,\n}: MarkdownViewProps) {\n const {\n engine,\n template,\n templateId: contextTemplateId,\n resolvePresentation,\n fetchData,\n } = useTemplateRuntime();\n\n // Prefer prop if given, else context\n const templateId = propTemplateId ?? contextTemplateId;\n const presentations = (template?.presentations as string[]) ?? [];\n\n const [selectedPresentation, setSelectedPresentation] = useState<string>('');\n const [markdownContent, setMarkdownContent] = useState<string>('');\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n // Initialize selected presentation\n useEffect(() => {\n if (presentationId && presentations.includes(presentationId)) {\n setSelectedPresentation(presentationId);\n } else if (presentations.length > 0 && !selectedPresentation) {\n setSelectedPresentation(presentations[0] ?? '');\n }\n }, [presentationId, presentations, selectedPresentation]);\n\n // Render markdown when presentation changes\n const renderMarkdown = useCallback(async () => {\n if (!selectedPresentation || !engine) return;\n\n setLoading(true);\n setError(null);\n\n try {\n if (!resolvePresentation) {\n throw new Error('resolvePresentation not available in runtime context');\n }\n\n const descriptor = resolvePresentation(selectedPresentation);\n\n if (!descriptor) {\n throw new Error(\n `Presentation descriptor not found: ${selectedPresentation}`\n );\n }\n\n // Fetch data for this presentation using the data fetcher from context\n const dataResult = await fetchData(selectedPresentation);\n\n // Render to markdown using the engine with data context\n const result = await engine.render<MarkdownOutput>(\n 'markdown' as PresentationTarget,\n descriptor as Parameters<TransformEngine['render']>[1],\n { data: dataResult.data } // Pass data in context for schema-driven rendering\n );\n\n setMarkdownContent(result.body);\n } catch (err) {\n setError(\n err instanceof Error ? err : new Error('Failed to render markdown')\n );\n } finally {\n setLoading(false);\n }\n }, [\n selectedPresentation,\n templateId,\n engine,\n resolvePresentation,\n fetchData,\n ]);\n\n useEffect(() => {\n renderMarkdown();\n }, [renderMarkdown]);\n\n if (!presentations.length) {\n return (\n <Card className={className}>\n <div className=\"p-6 text-center\">\n <p className=\"text-muted-foreground\">\n No presentations available for this template.\n </p>\n </div>\n </Card>\n );\n }\n\n // Copy markdown to clipboard\n const handleCopy = useCallback(() => {\n if (markdownContent) {\n navigator.clipboard.writeText(markdownContent);\n }\n }, [markdownContent]);\n\n return (\n <div className={className}>\n {/* Presentation Selector */}\n <div className=\"mb-4 flex flex-wrap items-center gap-2\">\n <span className=\"text-muted-foreground text-sm font-medium\">\n Presentation:\n </span>\n {presentations.map((name) => (\n <Button\n key={name}\n variant={selectedPresentation === name ? 'default' : 'outline'}\n size=\"sm\"\n onPress={() => setSelectedPresentation(name)}\n >\n {formatPresentationName(name)}\n </Button>\n ))}\n <div className=\"ml-auto flex items-center gap-2\">\n <Badge variant=\"secondary\">LLM-friendly</Badge>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onPress={handleCopy}\n disabled={!markdownContent || loading}\n >\n Copy\n </Button>\n </div>\n </div>\n\n {/* Content Area */}\n <Card className=\"overflow-hidden\">\n {loading && <LoaderBlock label=\"Rendering markdown...\" />}\n\n {error && (\n <ErrorState\n title=\"Render failed\"\n description={error.message}\n onRetry={renderMarkdown}\n retryLabel=\"Retry\"\n />\n )}\n\n {!loading && !error && markdownContent && (\n <div className=\"p-6\">\n <MarkdownRenderer content={markdownContent} />\n </div>\n )}\n\n {!loading && !error && !markdownContent && (\n <div className=\"p-6 text-center\">\n <p className=\"text-muted-foreground\">\n Select a presentation to view its markdown output.\n </p>\n </div>\n )}\n </Card>\n </div>\n );\n}\n\n/**\n * Simple markdown renderer using pre-formatted display\n * For production, consider using react-markdown or similar\n */\nexport function MarkdownRenderer({ content }: { content: string }) {\n const lines = content.split('\\n');\n const rendered: React.ReactNode[] = [];\n let i = 0;\n\n while (i < lines.length) {\n const line = lines[i] ?? '';\n\n // Check for table (starts with | and next line is separator)\n if (line.startsWith('|') && lines[i + 1]?.match(/^\\|[\\s-|]+\\|$/)) {\n const tableLines: string[] = [line];\n i++;\n // Collect all table lines\n while (i < lines.length && (lines[i]?.startsWith('|') ?? false)) {\n tableLines.push(lines[i] ?? '');\n i++;\n }\n rendered.push(renderTable(tableLines, rendered.length));\n continue;\n }\n\n // Headers\n if (line.startsWith('# ')) {\n rendered.push(\n <h1 key={i} className=\"mb-4 text-2xl font-bold\">\n {line.slice(2)}\n </h1>\n );\n } else if (line.startsWith('## ')) {\n rendered.push(\n <h2 key={i} className=\"mt-6 mb-3 text-xl font-semibold\">\n {line.slice(3)}\n </h2>\n );\n } else if (line.startsWith('### ')) {\n rendered.push(\n <h3 key={i} className=\"mt-4 mb-2 text-lg font-medium\">\n {line.slice(4)}\n </h3>\n );\n }\n // Blockquotes\n else if (line.startsWith('> ')) {\n rendered.push(\n <blockquote\n key={i}\n className=\"text-muted-foreground my-2 border-l-4 border-violet-500/50 pl-4 italic\"\n >\n {line.slice(2)}\n </blockquote>\n );\n }\n // List items\n else if (line.startsWith('- ')) {\n rendered.push(\n <li key={i} className=\"ml-4 list-disc\">\n {formatInlineMarkdown(line.slice(2))}\n </li>\n );\n }\n // Bold text (lines starting with **)\n else if (line.startsWith('**') && line.includes(':**')) {\n const [label, ...rest] = line.split(':**');\n rendered.push(\n <p key={i} className=\"my-1\">\n <strong>{label?.slice(2)}:</strong>\n {rest.join(':**')}\n </p>\n );\n }\n // Italic text (lines starting with _)\n else if (line.startsWith('_') && line.endsWith('_')) {\n rendered.push(\n <p key={i} className=\"text-muted-foreground my-1 italic\">\n {line.slice(1, -1)}\n </p>\n );\n }\n // Empty lines\n else if (!line.trim()) {\n rendered.push(<div key={i} className=\"h-2\" />);\n }\n // Regular text\n else {\n rendered.push(\n <p key={i} className=\"my-1\">\n {formatInlineMarkdown(line)}\n </p>\n );\n }\n\n i++;\n }\n\n return (\n <div className=\"prose prose-sm dark:prose-invert max-w-none\">\n {rendered}\n </div>\n );\n}\n\n/**\n * Render a markdown table\n */\nfunction renderTable(lines: string[], keyPrefix: number): React.ReactNode {\n if (lines.length < 2) return null;\n\n const parseRow = (row: string) =>\n row\n .split('|')\n .slice(1, -1)\n .map((cell) => cell.trim());\n\n const headers = parseRow(lines[0] ?? '');\n // Skip separator line (index 1)\n const dataRows = lines.slice(2).map(parseRow);\n\n return (\n <div key={`table-${keyPrefix}`} className=\"my-4 overflow-x-auto\">\n <table className=\"border-border min-w-full border-collapse border text-sm\">\n <thead>\n <tr className=\"bg-muted/50\">\n {headers.map((header, idx) => (\n <th\n key={idx}\n className=\"border-border border px-3 py-2 text-left font-semibold\"\n >\n {header}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {dataRows.map((row, rowIdx) => (\n <tr key={rowIdx} className=\"hover:bg-muted/30\">\n {row.map((cell, cellIdx) => (\n <td key={cellIdx} className=\"border-border border px-3 py-2\">\n {formatInlineMarkdown(cell)}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n );\n}\n\n/**\n * Format inline markdown (bold, code)\n */\nfunction formatInlineMarkdown(text: string): React.ReactNode {\n // Handle **bold** text\n const parts = text.split(/(\\*\\*[^*]+\\*\\*)/g);\n return parts.map((part, i) => {\n if (part.startsWith('**') && part.endsWith('**')) {\n return <strong key={i}>{part.slice(2, -2)}</strong>;\n }\n // Handle `code` text\n if (part.includes('`')) {\n const codeParts = part.split(/(`[^`]+`)/g);\n return codeParts.map((cp, j) => {\n if (cp.startsWith('`') && cp.endsWith('`')) {\n return (\n <code\n key={`${i}-${j}`}\n className=\"rounded bg-violet-500/10 px-1.5 py-0.5 font-mono text-sm\"\n >\n {cp.slice(1, -1)}\n </code>\n );\n }\n return cp;\n });\n }\n return part;\n });\n}\n\n/**\n * Format presentation name for display\n */\nfunction formatPresentationName(name: string): string {\n // Extract the last part after the last dot\n const parts = name.split('.');\n const lastPart = parts[parts.length - 1] ?? name;\n // Convert kebab-case to Title Case\n return lastPart\n .split('-')\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(' ');\n}\n"],"mappings":";;;;;;;;;;;;;AAuMA,SAAgB,iBAAiB,EAAE,WAAgC;CACjE,MAAM,QAAQ,QAAQ,MAAM,KAAK;CACjC,MAAM,WAA8B,EAAE;CACtC,IAAI,IAAI;AAER,QAAO,IAAI,MAAM,QAAQ;EACvB,MAAM,OAAO,MAAM,MAAM;AAGzB,MAAI,KAAK,WAAW,IAAI,IAAI,MAAM,IAAI,IAAI,MAAM,gBAAgB,EAAE;GAChE,MAAM,aAAuB,CAAC,KAAK;AACnC;AAEA,UAAO,IAAI,MAAM,WAAW,MAAM,IAAI,WAAW,IAAI,IAAI,QAAQ;AAC/D,eAAW,KAAK,MAAM,MAAM,GAAG;AAC/B;;AAEF,YAAS,KAAK,YAAY,YAAY,SAAS,OAAO,CAAC;AACvD;;AAIF,MAAI,KAAK,WAAW,KAAK,CACvB,UAAS,KACP,oBAAC;GAAW,WAAU;aACnB,KAAK,MAAM,EAAE;KADP,EAEJ,CACN;WACQ,KAAK,WAAW,MAAM,CAC/B,UAAS,KACP,oBAAC;GAAW,WAAU;aACnB,KAAK,MAAM,EAAE;KADP,EAEJ,CACN;WACQ,KAAK,WAAW,OAAO,CAChC,UAAS,KACP,oBAAC;GAAW,WAAU;aACnB,KAAK,MAAM,EAAE;KADP,EAEJ,CACN;WAGM,KAAK,WAAW,KAAK,CAC5B,UAAS,KACP,oBAAC;GAEC,WAAU;aAET,KAAK,MAAM,EAAE;KAHT,EAIM,CACd;WAGM,KAAK,WAAW,KAAK,CAC5B,UAAS,KACP,oBAAC;GAAW,WAAU;aACnB,qBAAqB,KAAK,MAAM,EAAE,CAAC;KAD7B,EAEJ,CACN;WAGM,KAAK,WAAW,KAAK,IAAI,KAAK,SAAS,MAAM,EAAE;GACtD,MAAM,CAAC,OAAO,GAAG,QAAQ,KAAK,MAAM,MAAM;AAC1C,YAAS,KACP,qBAAC;IAAU,WAAU;eACnB,qBAAC,uBAAQ,OAAO,MAAM,EAAE,EAAC,OAAU,EAClC,KAAK,KAAK,MAAM;MAFX,EAGJ,CACL;aAGM,KAAK,WAAW,IAAI,IAAI,KAAK,SAAS,IAAI,CACjD,UAAS,KACP,oBAAC;GAAU,WAAU;aAClB,KAAK,MAAM,GAAG,GAAG;KADZ,EAEJ,CACL;WAGM,CAAC,KAAK,MAAM,CACnB,UAAS,KAAK,oBAAC,SAAY,WAAU,SAAb,EAAqB,CAAC;MAI9C,UAAS,KACP,oBAAC;GAAU,WAAU;aAClB,qBAAqB,KAAK;KADrB,EAEJ,CACL;AAGH;;AAGF,QACE,oBAAC;EAAI,WAAU;YACZ;GACG;;;;;AAOV,SAAS,YAAY,OAAiB,WAAoC;AACxE,KAAI,MAAM,SAAS,EAAG,QAAO;CAE7B,MAAM,YAAY,QAChB,IACG,MAAM,IAAI,CACV,MAAM,GAAG,GAAG,CACZ,KAAK,SAAS,KAAK,MAAM,CAAC;CAE/B,MAAM,UAAU,SAAS,MAAM,MAAM,GAAG;CAExC,MAAM,WAAW,MAAM,MAAM,EAAE,CAAC,IAAI,SAAS;AAE7C,QACE,oBAAC;EAA+B,WAAU;YACxC,qBAAC;GAAM,WAAU;cACf,oBAAC,qBACC,oBAAC;IAAG,WAAU;cACX,QAAQ,KAAK,QAAQ,QACpB,oBAAC;KAEC,WAAU;eAET;OAHI,IAIF,CACL;KACC,GACC,EACR,oBAAC,qBACE,SAAS,KAAK,KAAK,WAClB,oBAAC;IAAgB,WAAU;cACxB,IAAI,KAAK,MAAM,YACd,oBAAC;KAAiB,WAAU;eACzB,qBAAqB,KAAK;OADpB,QAEJ,CACL;MALK,OAMJ,CACL,GACI;IACF;IAzBA,SAAS,YA0Bb;;;;;AAOV,SAAS,qBAAqB,MAA+B;AAG3D,QADc,KAAK,MAAM,mBAAmB,CAC/B,KAAK,MAAM,MAAM;AAC5B,MAAI,KAAK,WAAW,KAAK,IAAI,KAAK,SAAS,KAAK,CAC9C,QAAO,oBAAC,sBAAgB,KAAK,MAAM,GAAG,GAAG,IAArB,EAA+B;AAGrD,MAAI,KAAK,SAAS,IAAI,CAEpB,QADkB,KAAK,MAAM,aAAa,CACzB,KAAK,IAAI,MAAM;AAC9B,OAAI,GAAG,WAAW,IAAI,IAAI,GAAG,SAAS,IAAI,CACxC,QACE,oBAAC;IAEC,WAAU;cAET,GAAG,MAAM,GAAG,GAAG;MAHX,GAAG,EAAE,GAAG,IAIR;AAGX,UAAO;IACP;AAEJ,SAAO;GACP"}
@@ -0,0 +1,11 @@
1
+ 'use client';
2
+
3
+ import * as React from "react";
4
+ import { useContext, useMemo } from "react";
5
+ import { jsx } from "react/jsx-runtime";
6
+
7
+ //#region ../example-shared-ui/src/OverlayContextProvider.tsx
8
+ const OverlayContext = React.createContext(null);
9
+
10
+ //#endregion
11
+ //# sourceMappingURL=OverlayContextProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OverlayContextProvider.js","names":[],"sources":["../../../../example-shared-ui/src/OverlayContextProvider.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { useContext, useMemo } from 'react';\nimport type { TemplateId } from './lib/types';\n\n/**\n * Overlay modification operation types (for OverlayContextProvider)\n */\nexport type OverlayModificationOp =\n | { op: 'hide' }\n | { op: 'relabel'; label: string }\n | { op: 'reorder'; position: number }\n | { op: 'restyle'; className?: string; variant?: string }\n | { op: 'set-default'; value: unknown };\n\n/**\n * Overlay spec for a field or component\n */\nexport interface OverlaySpec {\n id: string;\n target: string; // path to the field/component\n modifications: OverlayModificationOp[];\n conditions?: {\n role?: string[];\n device?: 'mobile' | 'desktop' | 'any';\n featureFlags?: string[];\n };\n}\n\n/**\n * Context value for overlay engine\n */\nexport interface OverlayContextValue {\n /** Current overlays */\n overlays: OverlaySpec[];\n /** Apply overlays to a component */\n applyOverlay: <T extends Record<string, unknown>>(\n path: string,\n target: T\n ) => T;\n /** Check if a field should be hidden */\n isHidden: (path: string) => boolean;\n /** Get relabeled text */\n getLabel: (path: string, defaultLabel: string) => string;\n /** Get position for reordering */\n getPosition: (path: string, defaultPosition: number) => number;\n /** Get style modifications */\n getStyle: (path: string) => { className?: string; variant?: string };\n /** Get default value */\n getDefault: <T>(path: string, defaultValue: T) => T;\n /** Current user role */\n role: string;\n /** Current device type */\n device: 'mobile' | 'desktop';\n}\n\nconst OverlayContext = React.createContext<OverlayContextValue | null>(null);\n\nexport interface OverlayContextProviderProps extends React.PropsWithChildren {\n templateId: TemplateId;\n role?: string;\n device?: 'mobile' | 'desktop';\n}\n\n/**\n * Provider for overlay engine context.\n * Loads template-specific overlays and provides helper functions.\n */\nexport function OverlayContextProvider({\n templateId,\n role = 'user',\n device = 'desktop',\n children,\n}: OverlayContextProviderProps) {\n // Load template-specific overlays\n const overlays = useMemo(\n () => getTemplateOverlays(templateId, role),\n [templateId, role]\n );\n\n // Filter overlays based on current context\n const activeOverlays = useMemo(() => {\n return overlays.filter((overlay) => {\n const conditions = overlay.conditions;\n if (!conditions) return true;\n\n if (conditions.role && !conditions.role.includes(role)) {\n return false;\n }\n\n if (\n conditions.device &&\n conditions.device !== 'any' &&\n conditions.device !== device\n ) {\n return false;\n }\n\n return true;\n });\n }, [overlays, role, device]);\n\n // Create overlay map for quick lookups\n const overlayMap = useMemo(() => {\n const map = new Map<string, OverlaySpec>();\n for (const overlay of activeOverlays) {\n map.set(overlay.target, overlay);\n }\n return map;\n }, [activeOverlays]);\n\n // Apply overlay to a target object\n const applyOverlay = useMemo(\n () =>\n <T extends Record<string, unknown>>(path: string, target: T): T => {\n const overlay = overlayMap.get(path);\n if (!overlay) return target;\n\n let result = { ...target };\n for (const mod of overlay.modifications) {\n switch (mod.op) {\n case 'hide':\n result = { ...result, hidden: true };\n break;\n case 'relabel':\n result = { ...result, label: mod.label };\n break;\n case 'reorder':\n result = { ...result, position: mod.position };\n break;\n case 'restyle':\n result = {\n ...result,\n className: mod.className,\n variant: mod.variant,\n };\n break;\n case 'set-default':\n result = { ...result, defaultValue: mod.value };\n break;\n }\n }\n return result;\n },\n [overlayMap]\n );\n\n // Check if field is hidden\n const isHidden = useMemo(\n () =>\n (path: string): boolean => {\n const overlay = overlayMap.get(path);\n return overlay?.modifications.some((m) => m.op === 'hide') ?? false;\n },\n [overlayMap]\n );\n\n // Get relabeled text\n const getLabel = useMemo(\n () =>\n (path: string, defaultLabel: string): string => {\n const overlay = overlayMap.get(path);\n const relabel = overlay?.modifications.find((m) => m.op === 'relabel');\n return relabel && relabel.op === 'relabel'\n ? relabel.label\n : defaultLabel;\n },\n [overlayMap]\n );\n\n // Get position for reordering\n const getPosition = useMemo(\n () =>\n (path: string, defaultPosition: number): number => {\n const overlay = overlayMap.get(path);\n const reorder = overlay?.modifications.find((m) => m.op === 'reorder');\n return reorder && reorder.op === 'reorder'\n ? reorder.position\n : defaultPosition;\n },\n [overlayMap]\n );\n\n // Get style modifications\n const getStyle = useMemo(\n () =>\n (path: string): { className?: string; variant?: string } => {\n const overlay = overlayMap.get(path);\n const restyle = overlay?.modifications.find((m) => m.op === 'restyle');\n if (restyle && restyle.op === 'restyle') {\n return {\n className: restyle.className,\n variant: restyle.variant,\n };\n }\n return {};\n },\n [overlayMap]\n );\n\n // Get default value\n const getDefault = useMemo(\n () =>\n <T,>(path: string, defaultValue: T): T => {\n const overlay = overlayMap.get(path);\n const setDefault = overlay?.modifications.find(\n (m) => m.op === 'set-default'\n );\n return setDefault && setDefault.op === 'set-default'\n ? (setDefault.value as T)\n : defaultValue;\n },\n [overlayMap]\n );\n\n const value = useMemo<OverlayContextValue>(\n () => ({\n overlays: activeOverlays,\n applyOverlay,\n isHidden,\n getLabel,\n getPosition,\n getStyle,\n getDefault,\n role,\n device,\n }),\n [\n activeOverlays,\n applyOverlay,\n isHidden,\n getLabel,\n getPosition,\n getStyle,\n getDefault,\n role,\n device,\n ]\n );\n\n return (\n <OverlayContext.Provider value={value}>{children}</OverlayContext.Provider>\n );\n}\n\n/**\n * Hook to access overlay context\n */\nexport function useOverlayContext(): OverlayContextValue {\n const context = useContext(OverlayContext);\n if (!context) {\n throw new Error(\n 'useOverlayContext must be used within an OverlayContextProvider'\n );\n }\n return context;\n}\n\n/**\n * Hook to check if within overlay context\n */\nexport function useIsInOverlayContext(): boolean {\n return useContext(OverlayContext) !== null;\n}\n\n/**\n * Get template-specific overlays\n */\nfunction getTemplateOverlays(\n templateId: TemplateId,\n _role: string\n): OverlaySpec[] {\n // Demo overlays for each template\n const templateOverlays: Record<string, OverlaySpec[]> = {\n 'crm-pipeline': [\n {\n id: 'crm-hide-internal-fields',\n target: 'deal.internalNotes',\n modifications: [{ op: 'hide' }],\n conditions: { role: ['viewer', 'user'] },\n },\n {\n id: 'crm-relabel-value',\n target: 'deal.value',\n modifications: [{ op: 'relabel', label: 'Deal Amount' }],\n },\n ],\n 'saas-boilerplate': [\n {\n id: 'saas-hide-billing',\n target: 'settings.billing',\n modifications: [{ op: 'hide' }],\n conditions: { role: ['viewer'] },\n },\n {\n id: 'saas-restyle-plan',\n target: 'settings.plan',\n modifications: [{ op: 'restyle', variant: 'premium' }],\n conditions: { role: ['admin'] },\n },\n ],\n 'agent-console': [\n {\n id: 'agent-hide-cost',\n target: 'run.cost',\n modifications: [{ op: 'hide' }],\n conditions: { role: ['viewer'] },\n },\n {\n id: 'agent-relabel-tokens',\n target: 'run.tokens',\n modifications: [{ op: 'relabel', label: 'Token Usage' }],\n },\n ],\n 'todos-app': [\n {\n id: 'todos-hide-assignee',\n target: 'task.assignee',\n modifications: [{ op: 'hide' }],\n conditions: { device: 'mobile' },\n },\n ],\n 'messaging-app': [\n {\n id: 'messaging-reorder-timestamp',\n target: 'message.timestamp',\n modifications: [{ op: 'reorder', position: 0 }],\n },\n ],\n 'recipe-app-i18n': [\n {\n id: 'recipe-relabel-servings',\n target: 'recipe.servings',\n modifications: [{ op: 'relabel', label: 'Portions' }],\n },\n ],\n };\n\n return templateOverlays[templateId] ?? [];\n}\n"],"mappings":";;;;;;;AAyDA,MAAM,iBAAiB,MAAM,cAA0C,KAAK"}
@@ -0,0 +1,7 @@
1
+ 'use client';
2
+
3
+ import "./hooks/useBehaviorTracking.js";
4
+ import { useCallback, useMemo, useState } from "react";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ import { Card } from "@contractspec/lib.ui-kit-web/ui/card";
7
+ import { Badge } from "@contractspec/lib.ui-kit-web/ui/badge";
@@ -0,0 +1,6 @@
1
+ 'use client';
2
+
3
+ import "./lib/runtime-context.js";
4
+ import { useState } from "react";
5
+ import "lucide-react";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
@@ -0,0 +1,6 @@
1
+ 'use client';
2
+
3
+ import "./hooks/useSpecContent.js";
4
+ import { useCallback, useEffect } from "react";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ import { Badge } from "@contractspec/lib.ui-kit-web/ui/badge";
@@ -0,0 +1,3 @@
1
+ import "./LocalDataIndicator.js";
2
+ import "./SaveToStudioButton.js";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
@@ -0,0 +1,5 @@
1
+ import "./useSpecContent.js";
2
+ import "./useEvolution.js";
3
+ import "./useBehaviorTracking.js";
4
+ import "./useWorkflowComposer.js";
5
+ import "./useRegistryTemplates.js";
@@ -0,0 +1,3 @@
1
+ 'use client';
2
+
3
+ import { useCallback, useEffect, useMemo, useState } from "react";
@@ -0,0 +1,3 @@
1
+ 'use client';
2
+
3
+ import { useCallback, useEffect, useMemo, useState } from "react";
@@ -0,0 +1 @@
1
+ import "@tanstack/react-query";
@@ -0,0 +1,4 @@
1
+ 'use client';
2
+
3
+ import "../lib/runtime-context.js";
4
+ import { useCallback, useEffect, useState } from "react";
@@ -0,0 +1,3 @@
1
+ 'use client';
2
+
3
+ import { useCallback, useEffect, useMemo, useState } from "react";
@@ -0,0 +1,12 @@
1
+ import "./lib/runtime-context.js";
2
+ import "./LocalDataIndicator.js";
3
+ import "./SaveToStudioButton.js";
4
+ import "./TemplateShell.js";
5
+ import { MarkdownRenderer } from "./MarkdownView.js";
6
+ import "./SpecEditorPanel.js";
7
+ import "./EvolutionDashboard.js";
8
+ import "./EvolutionSidebar.js";
9
+ import "./OverlayContextProvider.js";
10
+ import "./PersonalizationInsights.js";
11
+ import "./hooks/index.js";
12
+ import { TemplateComponentRegistry } from "./lib/component-registry.js";
@@ -0,0 +1,27 @@
1
+ 'use client';
2
+
3
+ import { useEffect, useState } from "react";
4
+
5
+ //#region ../example-shared-ui/src/lib/component-registry.tsx
6
+ var TemplateComponentRegistry = class {
7
+ components = /* @__PURE__ */ new Map();
8
+ listeners = /* @__PURE__ */ new Set();
9
+ register(templateId, registration) {
10
+ this.components.set(templateId, registration);
11
+ this.listeners.forEach((l) => l(templateId));
12
+ }
13
+ get(templateId) {
14
+ return this.components.get(templateId);
15
+ }
16
+ subscribe(listener) {
17
+ this.listeners.add(listener);
18
+ return () => {
19
+ this.listeners.delete(listener);
20
+ };
21
+ }
22
+ };
23
+ const templateComponentRegistry = new TemplateComponentRegistry();
24
+
25
+ //#endregion
26
+ export { TemplateComponentRegistry };
27
+ //# sourceMappingURL=component-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"component-registry.js","names":[],"sources":["../../../../../example-shared-ui/src/lib/component-registry.tsx"],"sourcesContent":["'use client';\n\nimport React, { useState, useEffect } from 'react';\nimport type { TemplateId } from './types';\n\nexport interface TemplateComponentRegistration {\n list: React.ComponentType<any>; // eslint-disable-line @typescript-eslint/no-explicit-any\n detail: React.ComponentType<any>; // eslint-disable-line @typescript-eslint/no-explicit-any\n form?: React.ComponentType<any>; // eslint-disable-line @typescript-eslint/no-explicit-any\n}\n\nexport class TemplateComponentRegistry {\n private readonly components = new Map<\n TemplateId,\n TemplateComponentRegistration\n >();\n private readonly listeners = new Set<(templateId: TemplateId) => void>();\n\n register(\n templateId: TemplateId,\n registration: TemplateComponentRegistration\n ) {\n this.components.set(templateId, registration);\n this.listeners.forEach((l) => l(templateId));\n }\n\n get(templateId: TemplateId) {\n return this.components.get(templateId);\n }\n\n subscribe(listener: (templateId: TemplateId) => void) {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n}\n\nexport const templateComponentRegistry = new TemplateComponentRegistry();\n\nexport function registerTemplateComponents(\n templateId: TemplateId,\n components: TemplateComponentRegistration\n) {\n templateComponentRegistry.register(templateId, components);\n}\n\nexport function useTemplateComponents(\n templateId: TemplateId\n): TemplateComponentRegistration | undefined {\n const [components, setComponents] = useState(() =>\n templateComponentRegistry.get(templateId)\n );\n\n useEffect(() => {\n return templateComponentRegistry.subscribe((updatedId) => {\n if (updatedId === templateId) {\n setComponents(templateComponentRegistry.get(templateId));\n }\n });\n }, [templateId]);\n\n return components;\n}\n"],"mappings":";;;;;AAWA,IAAa,4BAAb,MAAuC;CACrC,AAAiB,6BAAa,IAAI,KAG/B;CACH,AAAiB,4BAAY,IAAI,KAAuC;CAExE,SACE,YACA,cACA;AACA,OAAK,WAAW,IAAI,YAAY,aAAa;AAC7C,OAAK,UAAU,SAAS,MAAM,EAAE,WAAW,CAAC;;CAG9C,IAAI,YAAwB;AAC1B,SAAO,KAAK,WAAW,IAAI,WAAW;;CAGxC,UAAU,UAA4C;AACpD,OAAK,UAAU,IAAI,SAAS;AAC5B,eAAa;AACX,QAAK,UAAU,OAAO,SAAS;;;;AAKrC,MAAa,4BAA4B,IAAI,2BAA2B"}
@@ -0,0 +1,9 @@
1
+ 'use client';
2
+
3
+ import { createContext, useContext } from "react";
4
+
5
+ //#region ../example-shared-ui/src/lib/runtime-context.tsx
6
+ const TemplateRuntimeContext = createContext(null);
7
+
8
+ //#endregion
9
+ //# sourceMappingURL=runtime-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-context.js","names":[],"sources":["../../../../../example-shared-ui/src/lib/runtime-context.tsx"],"sourcesContent":["'use client';\n\nimport { createContext, useContext } from 'react';\nimport type { ApolloClient } from '@apollo/client';\nimport type { TransformEngine } from '@contractspec/lib.contracts';\nimport type {\n TemplateDefinition,\n TemplateId,\n TemplateInstaller,\n} from './types';\n\n// Generic interface for handlers to avoid circular dependencies\n// Real types are defined in @contractspec/module.examples or specific example packages\nexport type GenericTemplateHandlers = unknown;\n\nexport interface TemplateRuntimeContextValue<\n THandlers = GenericTemplateHandlers,\n> {\n template: TemplateDefinition;\n runtime: unknown; // LocalRuntimeServices\n installer: TemplateInstaller;\n client: ApolloClient;\n components?: unknown; // TemplateComponentRegistration\n /** @deprecated use template.id */\n templateId: TemplateId;\n projectId: string;\n engine: TransformEngine;\n fetchData: (\n presentationName: string\n ) => Promise<{ data: unknown; metadata?: unknown }>;\n handlers: THandlers;\n resolvePresentation?: (presentationName: string) => unknown;\n}\n\nexport const TemplateRuntimeContext =\n createContext<TemplateRuntimeContextValue | null>(null);\n\nexport function useTemplateRuntime<\n THandlers = GenericTemplateHandlers,\n>(): TemplateRuntimeContextValue<THandlers> {\n const context = useContext(TemplateRuntimeContext);\n if (!context) {\n throw new Error(\n 'useTemplateRuntime must be used within a TemplateRuntimeProvider'\n );\n }\n return context as TemplateRuntimeContextValue<THandlers>;\n}\n\nexport interface TemplateRuntimeProviderProps {\n templateId: TemplateId;\n projectId?: string;\n lazy?: boolean;\n}\n"],"mappings":";;;;;AAkCA,MAAa,yBACX,cAAkD,KAAK"}
package/dist/index.js CHANGED
@@ -108,8 +108,8 @@ import { FormCardLayout } from "./components/forms/FormCardLayout.js";
108
108
  import { FormStepsLayout } from "./components/forms/FormStepsLayout.js";
109
109
  import { FormOneByOneLayout } from "./components/forms/FormOneByOneLayout.js";
110
110
  import { ActionForm } from "./components/forms/ActionForm.js";
111
- import { DataViewList } from "./components/data-view/DataViewList.js";
112
111
  import { DataViewTable } from "./components/data-view/DataViewTable.js";
112
+ import { DataViewList } from "./components/data-view/DataViewList.js";
113
113
  import { DataViewDetail } from "./components/data-view/DataViewDetail.js";
114
114
  import { DataViewRenderer } from "./components/data-view/DataViewRenderer.js";
115
115
 
@@ -1,10 +1,10 @@
1
- import * as react_jsx_runtime113 from "react/jsx-runtime";
1
+ import * as react_jsx_runtime110 from "react/jsx-runtime";
2
2
  import * as _contractspec_lib_schema0 from "@contractspec/lib.schema";
3
3
  import * as _contractspec_lib_contracts0 from "@contractspec/lib.contracts";
4
4
 
5
5
  //#region src/renderers/form-contract.d.ts
6
6
  declare const formRenderer: {
7
- render: (spec: _contractspec_lib_contracts0.FormSpec<_contractspec_lib_schema0.AnySchemaModel>, options?: _contractspec_lib_contracts0.RenderOptions<unknown> | undefined) => react_jsx_runtime113.JSX.Element;
7
+ render: (spec: _contractspec_lib_contracts0.FormSpec<_contractspec_lib_schema0.AnySchemaModel>, options?: _contractspec_lib_contracts0.RenderOptions<unknown> | undefined) => react_jsx_runtime110.JSX.Element;
8
8
  };
9
9
  //#endregion
10
10
  export { formRenderer };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contractspec/lib.design-system",
3
- "version": "1.53.0",
3
+ "version": "1.55.0",
4
4
  "description": "Design tokens and theming primitives",
5
5
  "keywords": [
6
6
  "contractspec",
@@ -28,17 +28,17 @@
28
28
  "sideEffects": false,
29
29
  "tree-shake": true,
30
30
  "dependencies": {
31
- "@contractspec/lib.ai-agent": "1.53.0",
32
- "@contractspec/lib.contracts": "1.53.0",
33
- "@contractspec/lib.ui-kit": "1.53.0",
34
- "@contractspec/lib.ui-kit-web": "1.53.0",
31
+ "@contractspec/lib.ai-agent": "1.55.0",
32
+ "@contractspec/lib.contracts": "1.55.0",
33
+ "@contractspec/lib.ui-kit": "1.55.0",
34
+ "@contractspec/lib.ui-kit-web": "1.55.0",
35
35
  "@hookform/resolvers": "5.2.2",
36
36
  "class-variance-authority": "^0.7.1",
37
37
  "clsx": "^2.1.1",
38
- "lucide-react": "^0.562.0",
39
- "next": "16.1.1",
40
- "react": "19.2.3",
41
- "react-dom": "19.2.3",
38
+ "lucide-react": "^0.563.0",
39
+ "next": "16.1.6",
40
+ "react": "19.2.4",
41
+ "react-dom": "19.2.4",
42
42
  "react-hook-form": "^7.70.0",
43
43
  "shiki": "^3.21.0",
44
44
  "tailwind-merge": "^3.3.1",
@@ -46,8 +46,8 @@
46
46
  "zod": "^4.3.5"
47
47
  },
48
48
  "devDependencies": {
49
- "@contractspec/tool.tsdown": "1.53.0",
50
- "@contractspec/tool.typescript": "1.53.0",
49
+ "@contractspec/tool.tsdown": "1.55.0",
50
+ "@contractspec/tool.typescript": "1.55.0",
51
51
  "@types/node": "^25.0.6",
52
52
  "@types/react-dom": "^19.0.14",
53
53
  "postcss": "^8.5",
@@ -63,14 +63,14 @@
63
63
  "README.md"
64
64
  ],
65
65
  "exports": {
66
- ".": "./dist/index.js",
67
- "./*": "./*"
66
+ ".": "./src/index.ts",
67
+ "./package.json": "./package.json"
68
68
  },
69
69
  "publishConfig": {
70
70
  "access": "public",
71
71
  "exports": {
72
72
  ".": "./dist/index.js",
73
- "./*": "./*"
73
+ "./package.json": "./package.json"
74
74
  },
75
75
  "registry": "https://registry.npmjs.org/"
76
76
  },