@contractspec/lib.design-system 1.53.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.
- package/dist/components/atoms/Stepper.d.ts +2 -2
- package/dist/components/atoms/Textarea.js +0 -6
- package/dist/components/atoms/Textarea.js.map +1 -1
- package/dist/components/data-view/DataViewDetail.d.ts +2 -2
- package/dist/components/data-view/DataViewDetail.d.ts.map +1 -1
- package/dist/components/data-view/DataViewDetail.js +11 -6
- package/dist/components/data-view/DataViewDetail.js.map +1 -1
- package/dist/components/data-view/DataViewList.js +11 -11
- package/dist/components/data-view/DataViewList.js.map +1 -1
- package/dist/components/data-view/DataViewRenderer.d.ts +2 -2
- package/dist/components/data-view/DataViewRenderer.d.ts.map +1 -1
- package/dist/components/data-view/DataViewRenderer.js +1 -1
- package/dist/components/data-view/DataViewTable.js +13 -6
- package/dist/components/data-view/DataViewTable.js.map +1 -1
- package/dist/components/data-view/utils.js +11 -4
- package/dist/components/data-view/utils.js.map +1 -1
- package/dist/components/marketing/MarketingComparisonSection.d.ts +2 -2
- package/dist/components/molecules/CodeBlock/CodeBlock.d.ts +2 -2
- package/dist/components/molecules/HoverPreview.d.ts +2 -2
- package/dist/components/molecules/LangSwitch.d.ts +2 -2
- package/dist/components/molecules/SkeletonBlock/index.web.d.ts +2 -2
- package/dist/components/molecules/SkeletonCircle/index.web.d.ts +2 -2
- package/dist/components/molecules/SkeletonList/index.web.d.ts +2 -2
- package/dist/components/molecules/StatusChip.d.ts +2 -2
- package/dist/components/molecules/hover-previews/Doc.d.ts +2 -2
- package/dist/components/organisms/FeatureCarousel.d.ts +2 -2
- package/dist/components/organisms/FeatureCarousel.d.ts.map +1 -1
- package/dist/components/organisms/FeaturesSection.d.ts +2 -2
- package/dist/components/organisms/HeroResponsive.d.ts +2 -2
- package/dist/components/organisms/HeroSection.d.ts +2 -2
- package/dist/components/organisms/PageHeaderResponsive.d.ts +2 -2
- package/dist/components/organisms/PricingCarousel.d.ts +2 -2
- package/dist/components/templates/lists/ListPageTemplate/index.web.d.ts +2 -2
- package/dist/example-shared-ui/src/EvolutionDashboard.js +7 -0
- package/dist/example-shared-ui/src/EvolutionSidebar.js +7 -0
- package/dist/example-shared-ui/src/LocalDataIndicator.js +6 -0
- package/dist/example-shared-ui/src/MarkdownView.js +119 -0
- package/dist/example-shared-ui/src/MarkdownView.js.map +1 -0
- package/dist/example-shared-ui/src/OverlayContextProvider.js +11 -0
- package/dist/example-shared-ui/src/OverlayContextProvider.js.map +1 -0
- package/dist/example-shared-ui/src/PersonalizationInsights.js +7 -0
- package/dist/example-shared-ui/src/SaveToStudioButton.js +6 -0
- package/dist/example-shared-ui/src/SpecEditorPanel.js +6 -0
- package/dist/example-shared-ui/src/TemplateShell.js +3 -0
- package/dist/example-shared-ui/src/hooks/index.js +5 -0
- package/dist/example-shared-ui/src/hooks/useBehaviorTracking.js +3 -0
- package/dist/example-shared-ui/src/hooks/useEvolution.js +3 -0
- package/dist/example-shared-ui/src/hooks/useRegistryTemplates.js +1 -0
- package/dist/example-shared-ui/src/hooks/useSpecContent.js +4 -0
- package/dist/example-shared-ui/src/hooks/useWorkflowComposer.js +3 -0
- package/dist/example-shared-ui/src/index.js +12 -0
- package/dist/example-shared-ui/src/lib/component-registry.js +27 -0
- package/dist/example-shared-ui/src/lib/component-registry.js.map +1 -0
- package/dist/example-shared-ui/src/lib/runtime-context.js +9 -0
- package/dist/example-shared-ui/src/lib/runtime-context.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/renderers/form-contract.d.ts +2 -2
- package/package.json +14 -14
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import * as
|
|
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):
|
|
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
|
|
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
|
|
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):
|
|
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":";;;;;
|
|
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 {
|
|
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("
|
|
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("
|
|
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:
|
|
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
|
|
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 {
|
|
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:
|
|
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:
|
|
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
|
|
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
|
|
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):
|
|
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,
|
|
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 {
|
|
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:
|
|
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
|
|
79
|
-
const field = fieldByKey(fields,
|
|
82
|
+
function DisplayValue({ item, fields, fieldKey }) {
|
|
83
|
+
const field = fieldByKey(fields, fieldKey);
|
|
80
84
|
if (!field) return "";
|
|
81
|
-
return
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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 {
|
|
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.
|
|
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
|
|
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):
|
|
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
|
|
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):
|
|
14
|
+
}: CodeBlockProps): react_jsx_runtime119.JSX.Element;
|
|
15
15
|
//#endregion
|
|
16
16
|
export { CodeBlock };
|
|
17
17
|
//# sourceMappingURL=CodeBlock.d.ts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import * as
|
|
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):
|
|
18
|
+
}: HoverPreviewProps): react_jsx_runtime46.JSX.Element;
|
|
19
19
|
//#endregion
|
|
20
20
|
export { HoverPreview };
|
|
21
21
|
//# sourceMappingURL=HoverPreview.d.ts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react_jsx_runtime37 from "react/jsx-runtime";
|
|
3
3
|
|
|
4
4
|
//#region src/components/molecules/LangSwitch.d.ts
|
|
5
5
|
interface LangOption {
|
|
@@ -17,7 +17,7 @@ declare function LangSwitch({
|
|
|
17
17
|
options,
|
|
18
18
|
onChange,
|
|
19
19
|
size
|
|
20
|
-
}: LangSwitchProps):
|
|
20
|
+
}: LangSwitchProps): react_jsx_runtime37.JSX.Element;
|
|
21
21
|
//#endregion
|
|
22
22
|
export { LangSwitch, LangSwitchProps };
|
|
23
23
|
//# sourceMappingURL=LangSwitch.d.ts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SkeletonBlockProps } from "./types.js";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react_jsx_runtime111 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):
|
|
10
|
+
}: SkeletonBlockProps): react_jsx_runtime111.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
|
|
2
|
+
import * as react_jsx_runtime112 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):
|
|
9
|
+
}: SkeletonCircleProps): react_jsx_runtime112.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
|
|
2
|
+
import * as react_jsx_runtime113 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):
|
|
8
|
+
}: SkeletonListProps): react_jsx_runtime113.JSX.Element;
|
|
9
9
|
//#endregion
|
|
10
10
|
export { SkeletonList };
|
|
11
11
|
//# sourceMappingURL=index.web.d.ts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react_jsx_runtime42 from "react/jsx-runtime";
|
|
3
3
|
import { VariantProps } from "class-variance-authority";
|
|
4
4
|
import * as class_variance_authority_types6 from "class-variance-authority/types";
|
|
5
5
|
|
|
@@ -21,7 +21,7 @@ declare function StatusChip({
|
|
|
21
21
|
className,
|
|
22
22
|
hoverContent,
|
|
23
23
|
...props
|
|
24
|
-
}: StatusChipProps):
|
|
24
|
+
}: StatusChipProps): react_jsx_runtime42.JSX.Element;
|
|
25
25
|
//#endregion
|
|
26
26
|
export { StatusChip };
|
|
27
27
|
//# sourceMappingURL=StatusChip.d.ts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react_jsx_runtime51 from "react/jsx-runtime";
|
|
3
3
|
|
|
4
4
|
//#region src/components/molecules/hover-previews/Doc.d.ts
|
|
5
5
|
interface HoverPreviewDocProps {
|
|
@@ -22,7 +22,7 @@ declare function HoverPreviewDoc({
|
|
|
22
22
|
status,
|
|
23
23
|
amount,
|
|
24
24
|
className
|
|
25
|
-
}: HoverPreviewDocProps):
|
|
25
|
+
}: HoverPreviewDocProps): react_jsx_runtime51.JSX.Element;
|
|
26
26
|
//#endregion
|
|
27
27
|
export { HoverPreviewDoc };
|
|
28
28
|
//# sourceMappingURL=Doc.d.ts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react_jsx_runtime6 from "react/jsx-runtime";
|
|
3
3
|
|
|
4
4
|
//#region src/components/organisms/FeatureCarousel.d.ts
|
|
5
5
|
interface FeatureSlide {
|
|
@@ -13,7 +13,7 @@ declare function FeatureCarousel({
|
|
|
13
13
|
}: {
|
|
14
14
|
slides: FeatureSlide[];
|
|
15
15
|
className?: string;
|
|
16
|
-
}):
|
|
16
|
+
}): react_jsx_runtime6.JSX.Element;
|
|
17
17
|
//#endregion
|
|
18
18
|
export { FeatureCarousel };
|
|
19
19
|
//# sourceMappingURL=FeatureCarousel.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FeatureCarousel.d.ts","names":[],"sources":["../../../src/components/organisms/FeatureCarousel.tsx"],"sourcesContent":[],"mappings":";;;;UAUiB,YAAA;SACR,KAAA,CAAM;gBACC,KAAA,CAAM;EAFL,KAAA,CAAA,EAGP,KAAA,CAAM,SAHa;;AAEP,iBAIN,eAAA,CAJM;EAAA,MAAA;EAAA;AAItB,CAJsB,EAAA;EACZ,MAAM,EAON,YAPM,EAAA;EAAS,SAAA,CAAA,EAAA,MAAA;AAGzB,CAAA,CAAA,EAMC,
|
|
1
|
+
{"version":3,"file":"FeatureCarousel.d.ts","names":[],"sources":["../../../src/components/organisms/FeatureCarousel.tsx"],"sourcesContent":[],"mappings":";;;;UAUiB,YAAA;SACR,KAAA,CAAM;gBACC,KAAA,CAAM;EAFL,KAAA,CAAA,EAGP,KAAA,CAAM,SAHa;;AAEP,iBAIN,eAAA,CAJM;EAAA,MAAA;EAAA;AAItB,CAJsB,EAAA;EACZ,MAAM,EAON,YAPM,EAAA;EAAS,SAAA,CAAA,EAAA,MAAA;AAGzB,CAAA,CAAA,EAMC,kBAAA,CAAA,GAAA,CAAA,OAN8B"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react_jsx_runtime60 from "react/jsx-runtime";
|
|
3
3
|
|
|
4
4
|
//#region src/components/organisms/FeaturesSection.d.ts
|
|
5
5
|
declare function FeaturesSection({
|
|
@@ -14,7 +14,7 @@ declare function FeaturesSection({
|
|
|
14
14
|
children: React.ReactNode;
|
|
15
15
|
className?: string;
|
|
16
16
|
density?: 'compact' | 'comfortable';
|
|
17
|
-
}):
|
|
17
|
+
}): react_jsx_runtime60.JSX.Element;
|
|
18
18
|
//#endregion
|
|
19
19
|
export { FeaturesSection };
|
|
20
20
|
//# sourceMappingURL=FeaturesSection.d.ts.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { HeroSection } from "./HeroSection.js";
|
|
2
2
|
import * as React from "react";
|
|
3
|
-
import * as
|
|
3
|
+
import * as react_jsx_runtime59 from "react/jsx-runtime";
|
|
4
4
|
|
|
5
5
|
//#region src/components/organisms/HeroResponsive.d.ts
|
|
6
6
|
declare function HeroResponsive({
|
|
@@ -9,7 +9,7 @@ declare function HeroResponsive({
|
|
|
9
9
|
primaryCta,
|
|
10
10
|
secondaryCta,
|
|
11
11
|
className
|
|
12
|
-
}: React.ComponentProps<typeof HeroSection>):
|
|
12
|
+
}: React.ComponentProps<typeof HeroSection>): react_jsx_runtime59.JSX.Element;
|
|
13
13
|
//#endregion
|
|
14
14
|
export { HeroResponsive };
|
|
15
15
|
//# sourceMappingURL=HeroResponsive.d.ts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react_jsx_runtime57 from "react/jsx-runtime";
|
|
3
3
|
|
|
4
4
|
//#region src/components/organisms/HeroSection.d.ts
|
|
5
5
|
declare function HeroSection({
|
|
@@ -24,7 +24,7 @@ declare function HeroSection({
|
|
|
24
24
|
};
|
|
25
25
|
className?: string;
|
|
26
26
|
density?: 'compact' | 'comfortable';
|
|
27
|
-
}):
|
|
27
|
+
}): react_jsx_runtime57.JSX.Element;
|
|
28
28
|
//#endregion
|
|
29
29
|
export { HeroSection };
|
|
30
30
|
//# sourceMappingURL=HeroSection.d.ts.map
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as react_jsx_runtime61 from "react/jsx-runtime";
|
|
2
2
|
import { PageHeaderProps } from "@contractspec/lib.ui-kit-web/ui/page-header";
|
|
3
3
|
|
|
4
4
|
//#region src/components/organisms/PageHeaderResponsive.d.ts
|
|
5
5
|
type PageHeaderResponsiveProps = PageHeaderProps;
|
|
6
|
-
declare function PageHeaderResponsive(props: PageHeaderResponsiveProps):
|
|
6
|
+
declare function PageHeaderResponsive(props: PageHeaderResponsiveProps): react_jsx_runtime61.JSX.Element;
|
|
7
7
|
//#endregion
|
|
8
8
|
export { PageHeaderResponsive };
|
|
9
9
|
//# sourceMappingURL=PageHeaderResponsive.d.ts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as react_jsx_runtime54 from "react/jsx-runtime";
|
|
2
2
|
|
|
3
3
|
//#region src/components/organisms/PricingCarousel.d.ts
|
|
4
4
|
interface PricingSlide {
|
|
@@ -19,7 +19,7 @@ declare function PricingCarousel({
|
|
|
19
19
|
}: {
|
|
20
20
|
tiers: PricingSlide[];
|
|
21
21
|
className?: string;
|
|
22
|
-
}):
|
|
22
|
+
}): react_jsx_runtime54.JSX.Element;
|
|
23
23
|
//#endregion
|
|
24
24
|
export { PricingCarousel };
|
|
25
25
|
//# sourceMappingURL=PricingCarousel.d.ts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ListPageTemplateProps } from "./types.js";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react_jsx_runtime110 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>):
|
|
20
|
+
}: ListPageTemplateProps<T>): react_jsx_runtime110.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,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 @@
|
|
|
1
|
+
import "@tanstack/react-query";
|
|
@@ -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 @@
|
|
|
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
|
|
1
|
+
import * as react_jsx_runtime114 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) =>
|
|
7
|
+
render: (spec: _contractspec_lib_contracts0.FormSpec<_contractspec_lib_schema0.AnySchemaModel>, options?: _contractspec_lib_contracts0.RenderOptions<unknown> | undefined) => react_jsx_runtime114.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.
|
|
3
|
+
"version": "1.54.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.
|
|
32
|
-
"@contractspec/lib.contracts": "1.
|
|
33
|
-
"@contractspec/lib.ui-kit": "1.
|
|
34
|
-
"@contractspec/lib.ui-kit-web": "1.
|
|
31
|
+
"@contractspec/lib.ai-agent": "1.54.0",
|
|
32
|
+
"@contractspec/lib.contracts": "1.54.0",
|
|
33
|
+
"@contractspec/lib.ui-kit": "1.54.0",
|
|
34
|
+
"@contractspec/lib.ui-kit-web": "1.54.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.
|
|
39
|
-
"next": "16.1.
|
|
40
|
-
"react": "19.2.
|
|
41
|
-
"react-dom": "19.2.
|
|
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.
|
|
50
|
-
"@contractspec/tool.typescript": "1.
|
|
49
|
+
"@contractspec/tool.tsdown": "1.54.0",
|
|
50
|
+
"@contractspec/tool.typescript": "1.54.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
|
-
".": "./
|
|
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
|
},
|