@contractspec/lib.design-system 1.52.0 → 1.54.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 (63) hide show
  1. package/dist/components/atoms/Stepper.d.ts +2 -2
  2. package/dist/components/atoms/Textarea.js +0 -6
  3. package/dist/components/atoms/Textarea.js.map +1 -1
  4. package/dist/components/data-view/DataViewDetail.d.ts +2 -2
  5. package/dist/components/data-view/DataViewDetail.d.ts.map +1 -1
  6. package/dist/components/data-view/DataViewDetail.js +11 -6
  7. package/dist/components/data-view/DataViewDetail.js.map +1 -1
  8. package/dist/components/data-view/DataViewList.d.ts +6 -6
  9. package/dist/components/data-view/DataViewList.d.ts.map +1 -1
  10. package/dist/components/data-view/DataViewList.js +40 -33
  11. package/dist/components/data-view/DataViewList.js.map +1 -1
  12. package/dist/components/data-view/DataViewRenderer.d.ts +2 -2
  13. package/dist/components/data-view/DataViewRenderer.d.ts.map +1 -1
  14. package/dist/components/data-view/DataViewRenderer.js +1 -1
  15. package/dist/components/data-view/DataViewTable.js +13 -6
  16. package/dist/components/data-view/DataViewTable.js.map +1 -1
  17. package/dist/components/data-view/utils.js +11 -4
  18. package/dist/components/data-view/utils.js.map +1 -1
  19. package/dist/components/marketing/MarketingComparisonSection.d.ts +2 -2
  20. package/dist/components/molecules/CodeBlock/CodeBlock.d.ts +2 -2
  21. package/dist/components/molecules/EntityCard.js +0 -1
  22. package/dist/components/molecules/EntityCard.js.map +1 -1
  23. package/dist/components/molecules/HoverPreview.d.ts +2 -2
  24. package/dist/components/molecules/LangSwitch.d.ts +2 -2
  25. package/dist/components/molecules/SkeletonBlock/index.web.d.ts +2 -2
  26. package/dist/components/molecules/SkeletonCircle/index.web.d.ts +2 -2
  27. package/dist/components/molecules/SkeletonList/index.web.d.ts +2 -2
  28. package/dist/components/molecules/StatusChip.d.ts +2 -2
  29. package/dist/components/molecules/hover-previews/Doc.d.ts +2 -2
  30. package/dist/components/organisms/FeatureCarousel.d.ts +2 -2
  31. package/dist/components/organisms/FeatureCarousel.d.ts.map +1 -1
  32. package/dist/components/organisms/FeaturesSection.d.ts +2 -2
  33. package/dist/components/organisms/HeroResponsive.d.ts +2 -2
  34. package/dist/components/organisms/HeroSection.d.ts +2 -2
  35. package/dist/components/organisms/PageHeaderResponsive.d.ts +2 -2
  36. package/dist/components/organisms/PricingCarousel.d.ts +2 -2
  37. package/dist/components/templates/lists/ListPageTemplate/index.web.d.ts +2 -2
  38. package/dist/example-shared-ui/src/EvolutionDashboard.js +7 -0
  39. package/dist/example-shared-ui/src/EvolutionSidebar.js +7 -0
  40. package/dist/example-shared-ui/src/LocalDataIndicator.js +6 -0
  41. package/dist/example-shared-ui/src/MarkdownView.js +119 -0
  42. package/dist/example-shared-ui/src/MarkdownView.js.map +1 -0
  43. package/dist/example-shared-ui/src/OverlayContextProvider.js +11 -0
  44. package/dist/example-shared-ui/src/OverlayContextProvider.js.map +1 -0
  45. package/dist/example-shared-ui/src/PersonalizationInsights.js +7 -0
  46. package/dist/example-shared-ui/src/SaveToStudioButton.js +6 -0
  47. package/dist/example-shared-ui/src/SpecEditorPanel.js +6 -0
  48. package/dist/example-shared-ui/src/TemplateShell.js +3 -0
  49. package/dist/example-shared-ui/src/hooks/index.js +5 -0
  50. package/dist/example-shared-ui/src/hooks/useBehaviorTracking.js +3 -0
  51. package/dist/example-shared-ui/src/hooks/useEvolution.js +3 -0
  52. package/dist/example-shared-ui/src/hooks/useRegistryTemplates.js +1 -0
  53. package/dist/example-shared-ui/src/hooks/useSpecContent.js +4 -0
  54. package/dist/example-shared-ui/src/hooks/useWorkflowComposer.js +3 -0
  55. package/dist/example-shared-ui/src/index.js +12 -0
  56. package/dist/example-shared-ui/src/lib/component-registry.js +27 -0
  57. package/dist/example-shared-ui/src/lib/component-registry.js.map +1 -0
  58. package/dist/example-shared-ui/src/lib/runtime-context.js +9 -0
  59. package/dist/example-shared-ui/src/lib/runtime-context.js.map +1 -0
  60. package/dist/index.js +1 -1
  61. package/dist/renderers/form-contract.d.ts +3 -4
  62. package/dist/renderers/form-contract.d.ts.map +1 -1
  63. package/package.json +14 -14
@@ -1,8 +1,8 @@
1
- import * as react_jsx_runtime6 from "react/jsx-runtime";
1
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
2
2
  import { StepperProps } from "@contractspec/lib.ui-kit-web/ui/stepper";
3
3
 
4
4
  //#region src/components/atoms/Stepper.d.ts
5
- declare function Stepper$1(props: StepperProps): react_jsx_runtime6.JSX.Element;
5
+ declare function Stepper$1(props: StepperProps): react_jsx_runtime0.JSX.Element;
6
6
  //#endregion
7
7
  export { Stepper$1 as Stepper };
8
8
  //# sourceMappingURL=Stepper.d.ts.map
@@ -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"}
@@ -3,22 +3,22 @@ import * as react_jsx_runtime106 from "react/jsx-runtime";
3
3
  import { DataViewSpec } from "@contractspec/lib.contracts/data-views";
4
4
 
5
5
  //#region src/components/data-view/DataViewList.d.ts
6
- interface DataViewListProps {
6
+ interface DataViewListProps<TItem = Record<string, unknown>> {
7
7
  spec: DataViewSpec;
8
- items: Record<string, unknown>[];
8
+ items: readonly TItem[];
9
9
  className?: string;
10
- renderActions?: (item: Record<string, unknown>) => React.ReactNode;
11
- onSelect?: (item: Record<string, unknown>) => void;
10
+ renderActions?: (item: TItem) => React.ReactNode;
11
+ onSelect?: (item: TItem) => void;
12
12
  emptyState?: React.ReactNode;
13
13
  }
14
- declare function DataViewList({
14
+ declare function DataViewList<TItem = Record<string, unknown>>({
15
15
  spec,
16
16
  items,
17
17
  className,
18
18
  renderActions,
19
19
  onSelect,
20
20
  emptyState
21
- }: DataViewListProps): react_jsx_runtime106.JSX.Element;
21
+ }: DataViewListProps<TItem>): react_jsx_runtime106.JSX.Element;
22
22
  //#endregion
23
23
  export { DataViewList };
24
24
  //# sourceMappingURL=DataViewList.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"DataViewList.d.ts","names":[],"sources":["../../../src/components/data-view/DataViewList.tsx"],"sourcesContent":[],"mappings":";;;;;UAWiB,iBAAA;QACT;SACC;EAFQ,SAAA,CAAA,EAAA,MAAA;EACT,aAAA,CAAA,EAAA,CAAA,IAAA,EAGiB,MAHjB,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,GAG6C,KAAA,CAAM,SAHnD;EACC,QAAA,CAAA,EAAA,CAAA,IAAA,EAGW,MAHX,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,GAAA,IAAA;EAEgB,UAAA,CAAA,EAEV,KAAA,CAAM,SAFI;;AACL,iBAIJ,YAAA,CAJI;EAAA,IAAA;EAAA,KAAA;EAAA,SAAA;EAAA,aAAA;EAAA,QAAA;EAAA;AAAA,CAAA,EAWjB,iBAXiB,CAAA,EAWA,oBAAA,CAAA,GAAA,CAAA,OAXA"}
1
+ {"version":3,"file":"DataViewList.d.ts","names":[],"sources":["../../../src/components/data-view/DataViewList.tsx"],"sourcesContent":[],"mappings":";;;;;UAWiB,0BAA0B;QACnC;kBACU;EAFD,SAAA,CAAA,EAAA,MAAA;EAA0B,aAAA,CAAA,EAAA,CAAA,IAAA,EAIlB,KAJkB,EAAA,GAIR,KAAA,CAAM,SAJE;EACnC,QAAA,CAAA,EAAA,CAAA,IAAA,EAIY,KAJZ,EAAA,GAAA,IAAA;EACU,UAAA,CAAA,EAIH,KAAA,CAAM,SAJH;;AAEuB,iBAKzB,YALyB,CAAA,QAKJ,MALI,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA,CAAA;EAAA,IAAA;EAAA,KAAA;EAAA,SAAA;EAAA,aAAA;EAAA,QAAA;EAAA;AAAA,CAAA,EAYtC,iBAZsC,CAYpB,KAZoB,CAAA,CAAA,EAYd,oBAAA,CAAA,GAAA,CAAA,OAZc"}
@@ -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
 
@@ -20,43 +20,50 @@ function DataViewList({ spec, items, className, renderActions, onSelect, emptySt
20
20
  });
21
21
  return /* @__PURE__ */ jsx("div", {
22
22
  className: cn("flex w-full flex-col gap-4", className),
23
- children: items.map((item, idx) => /* @__PURE__ */ jsxs("button", {
24
- type: "button",
25
- className: cn("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", view.layout === "compact" && "md:flex-row md:items-center md:gap-4"),
26
- onClick: () => onSelect?.(item),
27
- children: [/* @__PURE__ */ jsxs("div", {
28
- className: "flex flex-1 flex-col gap-1",
29
- children: [primaryField ? /* @__PURE__ */ jsx("span", {
30
- className: "text-foreground text-base font-medium",
31
- children: displayValue(item, fields, primaryField)
32
- }) : null, /* @__PURE__ */ jsx("div", {
33
- className: "text-muted-foreground flex flex-wrap gap-x-4 gap-y-1 text-sm",
34
- children: secondaryFieldKeys(view, primaryField).map((fieldKey) => /* @__PURE__ */ jsxs("span", {
35
- className: "flex items-center gap-1.5",
36
- children: [/* @__PURE__ */ jsx("span", {
37
- className: "text-foreground/80 font-medium",
38
- children: fieldLabel(fields, fieldKey)
39
- }), /* @__PURE__ */ jsx("span", { children: displayValue(item, fields, fieldKey) })]
40
- }, fieldKey))
41
- })]
42
- }), renderActions ? /* @__PURE__ */ jsx("div", {
43
- className: "flex shrink-0 items-center gap-2",
44
- children: renderActions(item)
45
- }) : null]
46
- }, idx))
23
+ children: items.map((item, idx) => {
24
+ const record = toRecord(item);
25
+ return /* @__PURE__ */ jsxs("button", {
26
+ type: "button",
27
+ className: cn("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", view.layout === "compact" && "md:flex-row md:items-center md:gap-4"),
28
+ onClick: () => onSelect?.(item),
29
+ children: [/* @__PURE__ */ jsxs("div", {
30
+ className: "flex flex-1 flex-col gap-1",
31
+ children: [primaryField ? /* @__PURE__ */ jsx("span", {
32
+ className: "text-foreground text-base font-medium",
33
+ children: /* @__PURE__ */ jsx(DisplayValue, {
34
+ item: record,
35
+ fields,
36
+ fieldKey: primaryField
37
+ })
38
+ }) : null, /* @__PURE__ */ jsx("div", {
39
+ className: "text-muted-foreground flex flex-wrap gap-x-4 gap-y-1 text-sm",
40
+ children: secondaryFieldKeys(view, primaryField).map((fieldKey) => /* @__PURE__ */ jsxs("span", {
41
+ className: "flex items-center gap-1.5",
42
+ children: [/* @__PURE__ */ jsx("span", {
43
+ className: "text-foreground/80 font-medium",
44
+ children: fieldLabel(fields, fieldKey)
45
+ }), /* @__PURE__ */ jsx("span", { children: /* @__PURE__ */ jsx(DisplayValue, {
46
+ item: record,
47
+ fields,
48
+ fieldKey
49
+ }) })]
50
+ }, fieldKey))
51
+ })]
52
+ }), renderActions ? /* @__PURE__ */ jsx("div", {
53
+ className: "flex shrink-0 items-center gap-2",
54
+ children: renderActions(item)
55
+ }) : null]
56
+ }, idx);
57
+ })
47
58
  });
48
59
  }
60
+ function toRecord(value) {
61
+ if (value && typeof value === "object") return value;
62
+ return {};
63
+ }
49
64
  function fieldLabel(fields, key) {
50
65
  return fields.find((field) => field.key === key)?.label ?? key;
51
66
  }
52
- function fieldByKey(fields, key) {
53
- return fields.find((field) => field.key === key);
54
- }
55
- function displayValue(item, fields, key) {
56
- const field = fieldByKey(fields, key);
57
- if (!field) return "";
58
- return formatValue(getAtPath(item, field.dataPath), field.format);
59
- }
60
67
  function secondaryFieldKeys(view, primaryField) {
61
68
  if (view.secondaryFields?.length) return view.secondaryFields;
62
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 {\n spec: DataViewSpec;\n items: Record<string, unknown>[];\n className?: string;\n renderActions?: (item: Record<string, unknown>) => React.ReactNode;\n onSelect?: (item: Record<string, unknown>) => void;\n emptyState?: React.ReactNode;\n}\n\nexport function DataViewList({\n spec,\n items,\n className,\n renderActions,\n onSelect,\n emptyState,\n}: DataViewListProps) {\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 <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' && '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(item, 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(item, 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 </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 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,aAAa,EAC3B,MACA,OACA,WACA,eACA,UACA,cACoB;AACpB,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,QAChB,qBAAC;GACC,MAAK;GAEL,WAAW,GACT,2PACA,KAAK,WAAW,aAAa,uCAC9B;GACD,eAAe,WAAW,KAAK;cAE/B,qBAAC;IAAI,WAAU;eACZ,eACC,oBAAC;KAAK,WAAU;eACb,aAAa,MAAM,QAAQ,aAAa;MACpC,GACL,MACJ,oBAAC;KAAI,WAAU;eACZ,mBAAmB,MAAM,aAAa,CAAC,KAAK,aAC3C,qBAAC;MAAoB,WAAU;iBAC7B,oBAAC;OAAK,WAAU;iBACb,WAAW,QAAQ,SAAS;QACxB,EACP,oBAAC,oBAAM,aAAa,MAAM,QAAQ,SAAS,GAAQ;QAJ1C,SAKJ,CACP;MACE;KACF,EACL,gBACC,oBAAC;IAAI,WAAU;cACZ,cAAc,KAAK;KAChB,GACJ;KA5BC,IA6BE,CACT;GACE;;AAIV,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,5 +1,5 @@
1
1
  import * as React from "react";
2
- import * as react_jsx_runtime0 from "react/jsx-runtime";
2
+ import * as react_jsx_runtime62 from "react/jsx-runtime";
3
3
  import { DataViewSpec } from "@contractspec/lib.contracts/data-views";
4
4
 
5
5
  //#region src/components/data-view/DataViewRenderer.d.ts
@@ -42,7 +42,7 @@ declare function DataViewRenderer({
42
42
  onFilterChange,
43
43
  pagination,
44
44
  onPageChange
45
- }: DataViewRendererProps): react_jsx_runtime0.JSX.Element;
45
+ }: DataViewRendererProps): react_jsx_runtime62.JSX.Element;
46
46
  //#endregion
47
47
  export { DataViewRenderer };
48
48
  //# sourceMappingURL=DataViewRenderer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"DataViewRenderer.d.ts","names":[],"sources":["../../../src/components/data-view/DataViewRenderer.tsx"],"sourcesContent":[],"mappings":";;;;;UAqBiB,qBAAA;QACT;UACE;EAFO,IAAA,CAAA,EAGR,MAHQ,CAAA,MAAA,EAAA,OAAqB,CAAA,GAAA,IAAA;EAC9B,SAAA,CAAA,EAAA,MAAA;EACE,aAAA,CAAA,EAAA,CAAA,IAAA,EAGe,MAHf,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,GAG2C,KAAA,CAAM,SAHjD;EACD,QAAA,CAAA,EAAA,CAAA,IAAA,EAGW,MAHX,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,GAAA,IAAA;EAEgB,UAAA,CAAA,EAAA,CAAA,IAAA,EAEH,MAFG,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,GAAA,IAAA;EAA4B,aAAM,CAAA,EAGzC,KAAA,CAAM,SAHmC;EACvC,UAAA,CAAA,EAGL,KAAA,CAAM,SAHD;EACE,MAAA,CAAA,EAGX,KAAA,CAAM,SAHK;EACJ,MAAM,CAAA,EAAA,MAAA;EACT,cAAM,CAAA,EAAA,CAAA,KAAA,EAAA,MAAA,EAAA,GAAA,IAAA;EACV,OAAM,CAAA,EAKL,MALK,CAAA,MAAA,EAAA,OAAA,CAAA;EAKL,cAAA,CAAA,EAAA,CAAA,OAAA,EACiB,MADjB,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,GAAA,IAAA;EACiB,UAAA,CAAA,EAAA;IAAM,IAAA,EAAA,MAAA;IAWnB,QAAA,EAAA,MAAgB;IAC9B,KAAA,EAAA,MAAA;EACA,CAAA;EACA,YAAA,CAAA,EAAA,CAAA,IAAA,EAAA,MAAA,EAAA,GAAA,IAAA;;AAEA,iBALc,gBAAA,CAKd;EAAA,IAAA;EAAA,KAAA;EAAA,IAAA;EAAA,SAAA;EAAA,aAAA;EAAA,QAAA;EAAA,UAAA;EAAA,aAAA;EAAA,UAAA;EAAA,MAAA;EAAA,MAAA;EAAA,cAAA;EAAA,OAAA;EAAA,cAAA;EAAA,UAAA;EAAA;AAAA,CAAA,EAYC,qBAZD,CAAA,EAYsB,kBAAA,CAAA,GAAA,CAAA,OAZtB"}
1
+ {"version":3,"file":"DataViewRenderer.d.ts","names":[],"sources":["../../../src/components/data-view/DataViewRenderer.tsx"],"sourcesContent":[],"mappings":";;;;;UAqBiB,qBAAA;QACT;UACE;EAFO,IAAA,CAAA,EAGR,MAHQ,CAAA,MAAA,EAAA,OAAqB,CAAA,GAAA,IAAA;EAC9B,SAAA,CAAA,EAAA,MAAA;EACE,aAAA,CAAA,EAAA,CAAA,IAAA,EAGe,MAHf,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,GAG2C,KAAA,CAAM,SAHjD;EACD,QAAA,CAAA,EAAA,CAAA,IAAA,EAGW,MAHX,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,GAAA,IAAA;EAEgB,UAAA,CAAA,EAAA,CAAA,IAAA,EAEH,MAFG,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,GAAA,IAAA;EAA4B,aAAM,CAAA,EAGzC,KAAA,CAAM,SAHmC;EACvC,UAAA,CAAA,EAGL,KAAA,CAAM,SAHD;EACE,MAAA,CAAA,EAGX,KAAA,CAAM,SAHK;EACJ,MAAM,CAAA,EAAA,MAAA;EACT,cAAM,CAAA,EAAA,CAAA,KAAA,EAAA,MAAA,EAAA,GAAA,IAAA;EACV,OAAM,CAAA,EAKL,MALK,CAAA,MAAA,EAAA,OAAA,CAAA;EAKL,cAAA,CAAA,EAAA,CAAA,OAAA,EACiB,MADjB,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,GAAA,IAAA;EACiB,UAAA,CAAA,EAAA;IAAM,IAAA,EAAA,MAAA;IAWnB,QAAA,EAAA,MAAgB;IAC9B,KAAA,EAAA,MAAA;EACA,CAAA;EACA,YAAA,CAAA,EAAA,CAAA,IAAA,EAAA,MAAA,EAAA,GAAA,IAAA;;AAEA,iBALc,gBAAA,CAKd;EAAA,IAAA;EAAA,KAAA;EAAA,IAAA;EAAA,SAAA;EAAA,aAAA;EAAA,QAAA;EAAA,UAAA;EAAA,aAAA;EAAA,UAAA;EAAA,MAAA;EAAA,MAAA;EAAA,cAAA;EAAA,OAAA;EAAA,cAAA;EAAA,UAAA;EAAA;AAAA,CAAA,EAYC,qBAZD,CAAA,EAYsB,mBAAA,CAAA,GAAA,CAAA,OAZtB"}
@@ -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,6 +1,6 @@
1
1
  import { MarketingSectionPadding, MarketingSectionTone } from "./MarketingSection.js";
2
2
  import * as React from "react";
3
- import * as react_jsx_runtime37 from "react/jsx-runtime";
3
+ import * as react_jsx_runtime27 from "react/jsx-runtime";
4
4
 
5
5
  //#region src/components/marketing/MarketingComparisonSection.d.ts
6
6
  interface ComparisonColumn {
@@ -24,7 +24,7 @@ declare function MarketingComparisonSection({
24
24
  right,
25
25
  tone,
26
26
  padding
27
- }: MarketingComparisonSectionProps): react_jsx_runtime37.JSX.Element;
27
+ }: MarketingComparisonSectionProps): react_jsx_runtime27.JSX.Element;
28
28
  //#endregion
29
29
  export { MarketingComparisonSection };
30
30
  //# sourceMappingURL=MarketingComparisonSection.d.ts.map
@@ -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_runtime119 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_runtime119.JSX.Element;
15
15
  //#endregion
16
16
  export { CodeBlock };
17
17
  //# sourceMappingURL=CodeBlock.d.ts.map
@@ -130,7 +130,6 @@ function EntityCard({ cardTitle, cardSubtitle, icon, iconTone = "default", iconS
130
130
  try {
131
131
  const { HoverPreview } = (init_HoverPreview(), __toCommonJS(HoverPreview_exports));
132
132
  return /* @__PURE__ */ jsx(HoverPreview, {
133
- className: "bg-red-500",
134
133
  trigger: cardContent,
135
134
  content: preview
136
135
  });
@@ -1 +1 @@
1
- {"version":3,"file":"EntityCard.js","names":[],"sources":["../../../src/components/molecules/EntityCard.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { Card, CardContent } from '@contractspec/lib.ui-kit-web/ui/card';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '@contractspec/lib.ui-kit-web/ui/utils';\nimport { ChevronDown } from 'lucide-react';\n\nconst entityCardVariants = cva(\n 'transition-all duration-200 hover:shadow-md group',\n {\n variants: {\n emphasis: {\n default: '',\n subtle: 'border-muted/60 bg-muted/20',\n strong: 'border-primary/50 bg-primary/5',\n accentGradient:\n 'border-transparent bg-gradient-to-br from-primary/10 via-background to-secondary/10 ring-1 ring-primary/20',\n },\n density: {\n compact: 'p-3',\n comfortable: 'p-4 md:p-5',\n },\n interactive: {\n true: 'cursor-pointer hover:scale-[1.02] transform-gpu hover:border-primary/40',\n false: '',\n },\n },\n defaultVariants: {\n emphasis: 'default',\n density: 'comfortable',\n interactive: false,\n },\n }\n);\n\nconst iconContainerVariants = cva(\n 'flex shrink-0 items-center justify-center rounded-lg',\n {\n variants: {\n size: {\n sm: 'h-8 w-8',\n md: 'h-10 w-10',\n lg: 'h-12 w-12',\n },\n tone: {\n default: 'bg-muted text-muted-foreground',\n primary: 'bg-primary/10 text-primary',\n success: 'bg-emerald-500/10 text-emerald-600 dark:text-emerald-400',\n warning: 'bg-amber-500/10 text-amber-600 dark:text-amber-400',\n info: 'bg-blue-500/10 text-blue-600 dark:text-blue-400',\n danger: 'bg-red-500/10 text-red-600 dark:text-red-400',\n },\n },\n defaultVariants: { size: 'md', tone: 'default' },\n }\n);\n\nexport type EntityCardIconTone =\n | 'default'\n | 'primary'\n | 'success'\n | 'warning'\n | 'info'\n | 'danger';\n\nexport type EntityCardProps = React.ComponentProps<typeof Card> &\n VariantProps<typeof entityCardVariants> & {\n cardTitle: React.ReactNode;\n cardSubtitle?: React.ReactNode;\n /** Icon element to display on the left */\n icon?: React.ReactNode;\n /** Icon container styling */\n iconTone?: EntityCardIconTone;\n iconSize?: 'sm' | 'md' | 'lg';\n chips?: React.ReactNode; // right-aligned small chips\n meta?: React.ReactNode; // rows of icon+text data\n footer?: React.ReactNode; // actions area\n href?: string; // optional link wrapper\n contentClassName?: string;\n preview?: React.ReactNode; // hover preview content\n /** Expandable content section */\n expandableContent?: React.ReactNode;\n /** Default expanded state */\n defaultExpanded?: boolean;\n };\n\nexport function EntityCard({\n cardTitle,\n cardSubtitle,\n icon,\n iconTone = 'default',\n iconSize = 'md',\n chips,\n meta,\n footer,\n emphasis,\n density,\n interactive,\n className,\n contentClassName,\n href,\n preview,\n expandableContent,\n defaultExpanded = false,\n onClick,\n ...cardProps\n}: EntityCardProps) {\n const [isExpanded, setIsExpanded] = React.useState(defaultExpanded);\n const Wrapper: React.ElementType = href ? 'a' : 'div';\n const isInteractive = interactive ?? !!(onClick || href);\n\n const handleExpandClick = (e: React.MouseEvent) => {\n e.stopPropagation();\n setIsExpanded(!isExpanded);\n };\n\n const cardContent = (\n <Card\n className={cn(\n entityCardVariants({ emphasis, interactive: isInteractive }),\n className\n )}\n onClick={onClick}\n {...cardProps}\n >\n <CardContent\n className={cn(entityCardVariants({ density }), contentClassName)}\n >\n <div className=\"space-y-3\">\n <div className=\"flex items-start gap-3\">\n {icon && (\n <div\n className={iconContainerVariants({\n size: iconSize,\n tone: iconTone,\n })}\n >\n {icon}\n </div>\n )}\n <div className=\"flex flex-1 items-start justify-between gap-2\">\n <div className=\"min-w-0 flex-1\">\n <div className=\"group-hover:text-primary truncate text-lg font-medium transition-colors\">\n {cardTitle}\n </div>\n {cardSubtitle && (\n <div className=\"text-muted-foreground text-sm\">\n {cardSubtitle}\n </div>\n )}\n </div>\n <div className=\"inline-flex shrink-0 items-center gap-2\">\n {chips}\n {expandableContent && (\n <button\n type=\"button\"\n onClick={handleExpandClick}\n className=\"hover:bg-muted rounded-md p-1 transition-colors\"\n aria-expanded={isExpanded}\n aria-label={isExpanded ? 'Collapse' : 'Expand'}\n >\n <ChevronDown\n className={cn(\n 'text-muted-foreground h-4 w-4 transition-transform duration-200',\n isExpanded && 'rotate-180'\n )}\n />\n </button>\n )}\n </div>\n </div>\n </div>\n {meta && <div className=\"space-y-1\">{meta}</div>}\n {expandableContent && (\n <div\n className={cn(\n 'overflow-hidden transition-all duration-200',\n isExpanded ? 'max-h-96 opacity-100' : 'max-h-0 opacity-0'\n )}\n >\n <div className=\"border-border/50 border-t pt-2\">\n {expandableContent}\n </div>\n </div>\n )}\n {footer && (\n <div className=\"flex items-center justify-between pt-1\">\n {footer}\n </div>\n )}\n </div>\n </CardContent>\n </Card>\n );\n\n const maybePreview = (() => {\n if (!preview) return cardContent;\n try {\n /* eslint-disable @typescript-eslint/no-require-imports */\n const { HoverPreview } =\n require('./HoverPreview') as typeof import('./HoverPreview');\n /* eslint-enable @typescript-eslint/no-require-imports */\n return (\n <HoverPreview\n className=\"bg-red-500\"\n trigger={cardContent}\n content={preview}\n />\n );\n } catch {\n return cardContent;\n }\n })();\n\n return (\n <Wrapper href={href} className={href ? 'block' : undefined}>\n {maybePreview}\n </Wrapper>\n );\n}\n"],"mappings":";;;;;;;;;;;;AAQA,MAAM,qBAAqB,IACzB,qDACA;CACE,UAAU;EACR,UAAU;GACR,SAAS;GACT,QAAQ;GACR,QAAQ;GACR,gBACE;GACH;EACD,SAAS;GACP,SAAS;GACT,aAAa;GACd;EACD,aAAa;GACX,MAAM;GACN,OAAO;GACR;EACF;CACD,iBAAiB;EACf,UAAU;EACV,SAAS;EACT,aAAa;EACd;CACF,CACF;AAED,MAAM,wBAAwB,IAC5B,wDACA;CACE,UAAU;EACR,MAAM;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACL;EACD,MAAM;GACJ,SAAS;GACT,SAAS;GACT,SAAS;GACT,SAAS;GACT,MAAM;GACN,QAAQ;GACT;EACF;CACD,iBAAiB;EAAE,MAAM;EAAM,MAAM;EAAW;CACjD,CACF;AA+BD,SAAgB,WAAW,EACzB,WACA,cACA,MACA,WAAW,WACX,WAAW,MACX,OACA,MACA,QACA,UACA,SACA,aACA,WACA,kBACA,MACA,SACA,mBACA,kBAAkB,OAClB,SACA,GAAG,aACe;CAClB,MAAM,CAAC,YAAY,iBAAiB,MAAM,SAAS,gBAAgB;CACnE,MAAM,UAA6B,OAAO,MAAM;CAChD,MAAM,gBAAgB,eAAe,CAAC,EAAE,WAAW;CAEnD,MAAM,qBAAqB,MAAwB;AACjD,IAAE,iBAAiB;AACnB,gBAAc,CAAC,WAAW;;CAG5B,MAAM,cACJ,oBAAC;EACC,WAAW,GACT,mBAAmB;GAAE;GAAU,aAAa;GAAe,CAAC,EAC5D,UACD;EACQ;EACT,GAAI;YAEJ,oBAAC;GACC,WAAW,GAAG,mBAAmB,EAAE,SAAS,CAAC,EAAE,iBAAiB;aAEhE,qBAAC;IAAI,WAAU;;KACb,qBAAC;MAAI,WAAU;iBACZ,QACC,oBAAC;OACC,WAAW,sBAAsB;QAC/B,MAAM;QACN,MAAM;QACP,CAAC;iBAED;QACG,EAER,qBAAC;OAAI,WAAU;kBACb,qBAAC;QAAI,WAAU;mBACb,oBAAC;SAAI,WAAU;mBACZ;UACG,EACL,gBACC,oBAAC;SAAI,WAAU;mBACZ;UACG;SAEJ,EACN,qBAAC;QAAI,WAAU;mBACZ,OACA,qBACC,oBAAC;SACC,MAAK;SACL,SAAS;SACT,WAAU;SACV,iBAAe;SACf,cAAY,aAAa,aAAa;mBAEtC,oBAAC,eACC,WAAW,GACT,mEACA,cAAc,aACf,GACD;UACK;SAEP;QACF;OACF;KACL,QAAQ,oBAAC;MAAI,WAAU;gBAAa;OAAW;KAC/C,qBACC,oBAAC;MACC,WAAW,GACT,+CACA,aAAa,yBAAyB,oBACvC;gBAED,oBAAC;OAAI,WAAU;iBACZ;QACG;OACF;KAEP,UACC,oBAAC;MAAI,WAAU;gBACZ;OACG;;KAEJ;IACM;GACT;CAGT,MAAM,sBAAsB;AAC1B,MAAI,CAAC,QAAS,QAAO;AACrB,MAAI;GAEF,MAAM,EAAE;AAGR,UACE,oBAAC;IACC,WAAU;IACV,SAAS;IACT,SAAS;KACT;UAEE;AACN,UAAO;;KAEP;AAEJ,QACE,oBAAC;EAAc;EAAM,WAAW,OAAO,UAAU;YAC9C;GACO"}
1
+ {"version":3,"file":"EntityCard.js","names":[],"sources":["../../../src/components/molecules/EntityCard.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { Card, CardContent } from '@contractspec/lib.ui-kit-web/ui/card';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '@contractspec/lib.ui-kit-web/ui/utils';\nimport { ChevronDown } from 'lucide-react';\n\nconst entityCardVariants = cva(\n 'transition-all duration-200 hover:shadow-md group',\n {\n variants: {\n emphasis: {\n default: '',\n subtle: 'border-muted/60 bg-muted/20',\n strong: 'border-primary/50 bg-primary/5',\n accentGradient:\n 'border-transparent bg-gradient-to-br from-primary/10 via-background to-secondary/10 ring-1 ring-primary/20',\n },\n density: {\n compact: 'p-3',\n comfortable: 'p-4 md:p-5',\n },\n interactive: {\n true: 'cursor-pointer hover:scale-[1.02] transform-gpu hover:border-primary/40',\n false: '',\n },\n },\n defaultVariants: {\n emphasis: 'default',\n density: 'comfortable',\n interactive: false,\n },\n }\n);\n\nconst iconContainerVariants = cva(\n 'flex shrink-0 items-center justify-center rounded-lg',\n {\n variants: {\n size: {\n sm: 'h-8 w-8',\n md: 'h-10 w-10',\n lg: 'h-12 w-12',\n },\n tone: {\n default: 'bg-muted text-muted-foreground',\n primary: 'bg-primary/10 text-primary',\n success: 'bg-emerald-500/10 text-emerald-600 dark:text-emerald-400',\n warning: 'bg-amber-500/10 text-amber-600 dark:text-amber-400',\n info: 'bg-blue-500/10 text-blue-600 dark:text-blue-400',\n danger: 'bg-red-500/10 text-red-600 dark:text-red-400',\n },\n },\n defaultVariants: { size: 'md', tone: 'default' },\n }\n);\n\nexport type EntityCardIconTone =\n | 'default'\n | 'primary'\n | 'success'\n | 'warning'\n | 'info'\n | 'danger';\n\nexport type EntityCardProps = React.ComponentProps<typeof Card> &\n VariantProps<typeof entityCardVariants> & {\n cardTitle: React.ReactNode;\n cardSubtitle?: React.ReactNode;\n /** Icon element to display on the left */\n icon?: React.ReactNode;\n /** Icon container styling */\n iconTone?: EntityCardIconTone;\n iconSize?: 'sm' | 'md' | 'lg';\n chips?: React.ReactNode; // right-aligned small chips\n meta?: React.ReactNode; // rows of icon+text data\n footer?: React.ReactNode; // actions area\n href?: string; // optional link wrapper\n contentClassName?: string;\n preview?: React.ReactNode; // hover preview content\n /** Expandable content section */\n expandableContent?: React.ReactNode;\n /** Default expanded state */\n defaultExpanded?: boolean;\n };\n\nexport function EntityCard({\n cardTitle,\n cardSubtitle,\n icon,\n iconTone = 'default',\n iconSize = 'md',\n chips,\n meta,\n footer,\n emphasis,\n density,\n interactive,\n className,\n contentClassName,\n href,\n preview,\n expandableContent,\n defaultExpanded = false,\n onClick,\n ...cardProps\n}: EntityCardProps) {\n const [isExpanded, setIsExpanded] = React.useState(defaultExpanded);\n const Wrapper: React.ElementType = href ? 'a' : 'div';\n const isInteractive = interactive ?? !!(onClick || href);\n\n const handleExpandClick = (e: React.MouseEvent) => {\n e.stopPropagation();\n setIsExpanded(!isExpanded);\n };\n\n const cardContent = (\n <Card\n className={cn(\n entityCardVariants({ emphasis, interactive: isInteractive }),\n className\n )}\n onClick={onClick}\n {...cardProps}\n >\n <CardContent\n className={cn(entityCardVariants({ density }), contentClassName)}\n >\n <div className=\"space-y-3\">\n <div className=\"flex items-start gap-3\">\n {icon && (\n <div\n className={iconContainerVariants({\n size: iconSize,\n tone: iconTone,\n })}\n >\n {icon}\n </div>\n )}\n <div className=\"flex flex-1 items-start justify-between gap-2\">\n <div className=\"min-w-0 flex-1\">\n <div className=\"group-hover:text-primary truncate text-lg font-medium transition-colors\">\n {cardTitle}\n </div>\n {cardSubtitle && (\n <div className=\"text-muted-foreground text-sm\">\n {cardSubtitle}\n </div>\n )}\n </div>\n <div className=\"inline-flex shrink-0 items-center gap-2\">\n {chips}\n {expandableContent && (\n <button\n type=\"button\"\n onClick={handleExpandClick}\n className=\"hover:bg-muted rounded-md p-1 transition-colors\"\n aria-expanded={isExpanded}\n aria-label={isExpanded ? 'Collapse' : 'Expand'}\n >\n <ChevronDown\n className={cn(\n 'text-muted-foreground h-4 w-4 transition-transform duration-200',\n isExpanded && 'rotate-180'\n )}\n />\n </button>\n )}\n </div>\n </div>\n </div>\n {meta && <div className=\"space-y-1\">{meta}</div>}\n {expandableContent && (\n <div\n className={cn(\n 'overflow-hidden transition-all duration-200',\n isExpanded ? 'max-h-96 opacity-100' : 'max-h-0 opacity-0'\n )}\n >\n <div className=\"border-border/50 border-t pt-2\">\n {expandableContent}\n </div>\n </div>\n )}\n {footer && (\n <div className=\"flex items-center justify-between pt-1\">\n {footer}\n </div>\n )}\n </div>\n </CardContent>\n </Card>\n );\n\n const maybePreview = (() => {\n if (!preview) return cardContent;\n try {\n /* eslint-disable @typescript-eslint/no-require-imports */\n const { HoverPreview } =\n require('./HoverPreview') as typeof import('./HoverPreview');\n /* eslint-enable @typescript-eslint/no-require-imports */\n return <HoverPreview trigger={cardContent} content={preview} />;\n } catch {\n return cardContent;\n }\n })();\n\n return (\n <Wrapper href={href} className={href ? 'block' : undefined}>\n {maybePreview}\n </Wrapper>\n );\n}\n"],"mappings":";;;;;;;;;;;;AAQA,MAAM,qBAAqB,IACzB,qDACA;CACE,UAAU;EACR,UAAU;GACR,SAAS;GACT,QAAQ;GACR,QAAQ;GACR,gBACE;GACH;EACD,SAAS;GACP,SAAS;GACT,aAAa;GACd;EACD,aAAa;GACX,MAAM;GACN,OAAO;GACR;EACF;CACD,iBAAiB;EACf,UAAU;EACV,SAAS;EACT,aAAa;EACd;CACF,CACF;AAED,MAAM,wBAAwB,IAC5B,wDACA;CACE,UAAU;EACR,MAAM;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACL;EACD,MAAM;GACJ,SAAS;GACT,SAAS;GACT,SAAS;GACT,SAAS;GACT,MAAM;GACN,QAAQ;GACT;EACF;CACD,iBAAiB;EAAE,MAAM;EAAM,MAAM;EAAW;CACjD,CACF;AA+BD,SAAgB,WAAW,EACzB,WACA,cACA,MACA,WAAW,WACX,WAAW,MACX,OACA,MACA,QACA,UACA,SACA,aACA,WACA,kBACA,MACA,SACA,mBACA,kBAAkB,OAClB,SACA,GAAG,aACe;CAClB,MAAM,CAAC,YAAY,iBAAiB,MAAM,SAAS,gBAAgB;CACnE,MAAM,UAA6B,OAAO,MAAM;CAChD,MAAM,gBAAgB,eAAe,CAAC,EAAE,WAAW;CAEnD,MAAM,qBAAqB,MAAwB;AACjD,IAAE,iBAAiB;AACnB,gBAAc,CAAC,WAAW;;CAG5B,MAAM,cACJ,oBAAC;EACC,WAAW,GACT,mBAAmB;GAAE;GAAU,aAAa;GAAe,CAAC,EAC5D,UACD;EACQ;EACT,GAAI;YAEJ,oBAAC;GACC,WAAW,GAAG,mBAAmB,EAAE,SAAS,CAAC,EAAE,iBAAiB;aAEhE,qBAAC;IAAI,WAAU;;KACb,qBAAC;MAAI,WAAU;iBACZ,QACC,oBAAC;OACC,WAAW,sBAAsB;QAC/B,MAAM;QACN,MAAM;QACP,CAAC;iBAED;QACG,EAER,qBAAC;OAAI,WAAU;kBACb,qBAAC;QAAI,WAAU;mBACb,oBAAC;SAAI,WAAU;mBACZ;UACG,EACL,gBACC,oBAAC;SAAI,WAAU;mBACZ;UACG;SAEJ,EACN,qBAAC;QAAI,WAAU;mBACZ,OACA,qBACC,oBAAC;SACC,MAAK;SACL,SAAS;SACT,WAAU;SACV,iBAAe;SACf,cAAY,aAAa,aAAa;mBAEtC,oBAAC,eACC,WAAW,GACT,mEACA,cAAc,aACf,GACD;UACK;SAEP;QACF;OACF;KACL,QAAQ,oBAAC;MAAI,WAAU;gBAAa;OAAW;KAC/C,qBACC,oBAAC;MACC,WAAW,GACT,+CACA,aAAa,yBAAyB,oBACvC;gBAED,oBAAC;OAAI,WAAU;iBACZ;QACG;OACF;KAEP,UACC,oBAAC;MAAI,WAAU;gBACZ;OACG;;KAEJ;IACM;GACT;CAGT,MAAM,sBAAsB;AAC1B,MAAI,CAAC,QAAS,QAAO;AACrB,MAAI;GAEF,MAAM,EAAE;AAGR,UAAO,oBAAC;IAAa,SAAS;IAAa,SAAS;KAAW;UACzD;AACN,UAAO;;KAEP;AAEJ,QACE,oBAAC;EAAc;EAAM,WAAW,OAAO,UAAU;YAC9C;GACO"}
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import * as react_jsx_runtime51 from "react/jsx-runtime";
2
+ import * as react_jsx_runtime46 from "react/jsx-runtime";
3
3
 
4
4
  //#region src/components/molecules/HoverPreview.d.ts
5
5
  interface HoverPreviewProps {
@@ -15,7 +15,7 @@ declare function HoverPreview({
15
15
  align,
16
16
  sideOffset,
17
17
  className
18
- }: HoverPreviewProps): react_jsx_runtime51.JSX.Element;
18
+ }: HoverPreviewProps): react_jsx_runtime46.JSX.Element;
19
19
  //#endregion
20
20
  export { HoverPreview };
21
21
  //# sourceMappingURL=HoverPreview.d.ts.map