@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.
- 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.d.ts +6 -6
- package/dist/components/data-view/DataViewList.d.ts.map +1 -1
- package/dist/components/data-view/DataViewList.js +40 -33
- 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/EntityCard.js +0 -1
- package/dist/components/molecules/EntityCard.js.map +1 -1
- 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 +3 -4
- package/dist/renderers/form-contract.d.ts.map +1 -1
- 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"}
|
|
@@ -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:
|
|
8
|
+
items: readonly TItem[];
|
|
9
9
|
className?: string;
|
|
10
|
-
renderActions?: (item:
|
|
11
|
-
onSelect?: (item:
|
|
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,
|
|
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 {
|
|
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) =>
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
children: [
|
|
30
|
-
className: "
|
|
31
|
-
children:
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
|
|
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
|
|
@@ -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
|
|
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
|
|
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
|