@contractspec/lib.design-system 1.51.0 → 1.53.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/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 +31 -24
- package/dist/components/data-view/DataViewList.js.map +1 -1
- package/dist/components/molecules/EntityCard.js +0 -1
- package/dist/components/molecules/EntityCard.js.map +1 -1
- package/dist/renderers/form-contract.d.ts +2 -3
- package/dist/renderers/form-contract.d.ts.map +1 -1
- package/package.json +7 -7
|
@@ -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"}
|
|
@@ -20,32 +20,39 @@ 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
|
-
className: "flex
|
|
36
|
-
children:
|
|
37
|
-
className: "
|
|
38
|
-
children:
|
|
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: displayValue(record, fields, primaryField)
|
|
34
|
+
}) : null, /* @__PURE__ */ jsx("div", {
|
|
35
|
+
className: "text-muted-foreground flex flex-wrap gap-x-4 gap-y-1 text-sm",
|
|
36
|
+
children: secondaryFieldKeys(view, primaryField).map((fieldKey) => /* @__PURE__ */ jsxs("span", {
|
|
37
|
+
className: "flex items-center gap-1.5",
|
|
38
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
39
|
+
className: "text-foreground/80 font-medium",
|
|
40
|
+
children: fieldLabel(fields, fieldKey)
|
|
41
|
+
}), /* @__PURE__ */ jsx("span", { children: displayValue(record, fields, fieldKey) })]
|
|
42
|
+
}, fieldKey))
|
|
43
|
+
})]
|
|
44
|
+
}), renderActions ? /* @__PURE__ */ jsx("div", {
|
|
45
|
+
className: "flex shrink-0 items-center gap-2",
|
|
46
|
+
children: renderActions(item)
|
|
47
|
+
}) : null]
|
|
48
|
+
}, idx);
|
|
49
|
+
})
|
|
47
50
|
});
|
|
48
51
|
}
|
|
52
|
+
function toRecord(value) {
|
|
53
|
+
if (value && typeof value === "object") return value;
|
|
54
|
+
return {};
|
|
55
|
+
}
|
|
49
56
|
function fieldLabel(fields, key) {
|
|
50
57
|
return fields.find((field) => field.key === key)?.label ?? key;
|
|
51
58
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DataViewList.js","names":[],"sources":["../../../src/components/data-view/DataViewList.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport type {\n DataViewSpec,\n DataViewListConfig,\n DataViewField,\n} from '@contractspec/lib.contracts/data-views';\nimport { cn } from '../../lib/utils';\nimport { getAtPath, formatValue } from './utils';\n\nexport interface DataViewListProps {\n spec: DataViewSpec;\n items:
|
|
1
|
+
{"version":3,"file":"DataViewList.js","names":[],"sources":["../../../src/components/data-view/DataViewList.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport type {\n DataViewSpec,\n DataViewListConfig,\n DataViewField,\n} from '@contractspec/lib.contracts/data-views';\nimport { cn } from '../../lib/utils';\nimport { getAtPath, formatValue } from './utils';\n\nexport interface DataViewListProps<TItem = Record<string, unknown>> {\n spec: DataViewSpec;\n items: readonly TItem[];\n className?: string;\n renderActions?: (item: TItem) => React.ReactNode;\n onSelect?: (item: TItem) => void;\n emptyState?: React.ReactNode;\n}\n\nexport function DataViewList<TItem = Record<string, unknown>>({\n spec,\n items,\n className,\n renderActions,\n onSelect,\n emptyState,\n}: DataViewListProps<TItem>) {\n if (spec.view.kind !== 'list') {\n throw new Error(\n `DataViewList received view kind \"${spec.view.kind}\", expected \"list\".`\n );\n }\n const view = spec.view as DataViewListConfig;\n const fields = view.fields;\n const primaryField =\n view.primaryField ??\n fields.find((field) => field.key === view.primaryField)?.key ??\n fields[0]?.key;\n\n if (!items.length) {\n return (\n <div className={cn('flex w-full flex-col gap-4', className)}>\n {emptyState ?? (\n <div className=\"border-muted-foreground/40 text-muted-foreground rounded-md border border-dashed p-8 text-center text-sm\">\n No records available.\n </div>\n )}\n </div>\n );\n }\n\n return (\n <div className={cn('flex w-full flex-col gap-4', className)}>\n {items.map((item, idx) => {\n const record = toRecord(item);\n return (\n <button\n type=\"button\"\n key={idx}\n className={cn(\n 'border-muted bg-card hover:border-primary/40 focus-visible:border-primary focus-visible:ring-primary/40 flex w-full flex-col gap-2 rounded-lg border p-4 text-left shadow-sm transition hover:shadow-md focus-visible:ring-2 focus-visible:outline-none',\n view.layout === 'compact' &&\n 'md:flex-row md:items-center md:gap-4'\n )}\n onClick={() => onSelect?.(item)}\n >\n <div className=\"flex flex-1 flex-col gap-1\">\n {primaryField ? (\n <span className=\"text-foreground text-base font-medium\">\n {displayValue(record, fields, primaryField)}\n </span>\n ) : null}\n <div className=\"text-muted-foreground flex flex-wrap gap-x-4 gap-y-1 text-sm\">\n {secondaryFieldKeys(view, primaryField).map((fieldKey) => (\n <span key={fieldKey} className=\"flex items-center gap-1.5\">\n <span className=\"text-foreground/80 font-medium\">\n {fieldLabel(fields, fieldKey)}\n </span>\n <span>{displayValue(record, fields, fieldKey)}</span>\n </span>\n ))}\n </div>\n </div>\n {renderActions ? (\n <div className=\"flex shrink-0 items-center gap-2\">\n {renderActions(item)}\n </div>\n ) : null}\n </button>\n );\n })}\n </div>\n );\n}\n\nfunction toRecord(value: unknown): Record<string, unknown> {\n if (value && typeof value === 'object') {\n return value as Record<string, unknown>;\n }\n return {};\n}\n\nfunction fieldLabel(fields: DataViewField[], key: string) {\n return fields.find((field) => field.key === key)?.label ?? key;\n}\n\nfunction fieldByKey(fields: DataViewField[], key?: string) {\n return fields.find((field) => field.key === key);\n}\n\nfunction displayValue(\n item: Record<string, unknown>,\n fields: DataViewField[],\n key: string\n) {\n const field = fieldByKey(fields, key);\n if (!field) return '';\n const value = getAtPath(item, field.dataPath);\n return formatValue(value, field.format);\n}\n\nfunction secondaryFieldKeys(view: DataViewListConfig, primaryField?: string) {\n if (view.secondaryFields?.length) return view.secondaryFields;\n return view.fields\n .map((field) => field.key)\n .filter((key) => key !== primaryField);\n}\n"],"mappings":";;;;;;;;AAoBA,SAAgB,aAA8C,EAC5D,MACA,OACA,WACA,eACA,UACA,cAC2B;AAC3B,KAAI,KAAK,KAAK,SAAS,OACrB,OAAM,IAAI,MACR,oCAAoC,KAAK,KAAK,KAAK,qBACpD;CAEH,MAAM,OAAO,KAAK;CAClB,MAAM,SAAS,KAAK;CACpB,MAAM,eACJ,KAAK,gBACL,OAAO,MAAM,UAAU,MAAM,QAAQ,KAAK,aAAa,EAAE,OACzD,OAAO,IAAI;AAEb,KAAI,CAAC,MAAM,OACT,QACE,oBAAC;EAAI,WAAW,GAAG,8BAA8B,UAAU;YACxD,cACC,oBAAC;GAAI,WAAU;aAA2G;IAEpH;GAEJ;AAIV,QACE,oBAAC;EAAI,WAAW,GAAG,8BAA8B,UAAU;YACxD,MAAM,KAAK,MAAM,QAAQ;GACxB,MAAM,SAAS,SAAS,KAAK;AAC7B,UACE,qBAAC;IACC,MAAK;IAEL,WAAW,GACT,2PACA,KAAK,WAAW,aACd,uCACH;IACD,eAAe,WAAW,KAAK;eAE/B,qBAAC;KAAI,WAAU;gBACZ,eACC,oBAAC;MAAK,WAAU;gBACb,aAAa,QAAQ,QAAQ,aAAa;OACtC,GACL,MACJ,oBAAC;MAAI,WAAU;gBACZ,mBAAmB,MAAM,aAAa,CAAC,KAAK,aAC3C,qBAAC;OAAoB,WAAU;kBAC7B,oBAAC;QAAK,WAAU;kBACb,WAAW,QAAQ,SAAS;SACxB,EACP,oBAAC,oBAAM,aAAa,QAAQ,QAAQ,SAAS,GAAQ;SAJ5C,SAKJ,CACP;OACE;MACF,EACL,gBACC,oBAAC;KAAI,WAAU;eACZ,cAAc,KAAK;MAChB,GACJ;MA7BC,IA8BE;IAEX;GACE;;AAIV,SAAS,SAAS,OAAyC;AACzD,KAAI,SAAS,OAAO,UAAU,SAC5B,QAAO;AAET,QAAO,EAAE;;AAGX,SAAS,WAAW,QAAyB,KAAa;AACxD,QAAO,OAAO,MAAM,UAAU,MAAM,QAAQ,IAAI,EAAE,SAAS;;AAG7D,SAAS,WAAW,QAAyB,KAAc;AACzD,QAAO,OAAO,MAAM,UAAU,MAAM,QAAQ,IAAI;;AAGlD,SAAS,aACP,MACA,QACA,KACA;CACA,MAAM,QAAQ,WAAW,QAAQ,IAAI;AACrC,KAAI,CAAC,MAAO,QAAO;AAEnB,QAAO,YADO,UAAU,MAAM,MAAM,SAAS,EACnB,MAAM,OAAO;;AAGzC,SAAS,mBAAmB,MAA0B,cAAuB;AAC3E,KAAI,KAAK,iBAAiB,OAAQ,QAAO,KAAK;AAC9C,QAAO,KAAK,OACT,KAAK,UAAU,MAAM,IAAI,CACzB,QAAQ,QAAQ,QAAQ,aAAa"}
|
|
@@ -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,11 +1,10 @@
|
|
|
1
|
-
import * as _contractspec_lib_contracts_client_react_form_render0 from "@contractspec/lib.contracts/client/react/form-render";
|
|
2
1
|
import * as react_jsx_runtime113 from "react/jsx-runtime";
|
|
3
2
|
import * as _contractspec_lib_schema0 from "@contractspec/lib.schema";
|
|
4
|
-
import * as
|
|
3
|
+
import * as _contractspec_lib_contracts0 from "@contractspec/lib.contracts";
|
|
5
4
|
|
|
6
5
|
//#region src/renderers/form-contract.d.ts
|
|
7
6
|
declare const formRenderer: {
|
|
8
|
-
render: (spec:
|
|
7
|
+
render: (spec: _contractspec_lib_contracts0.FormSpec<_contractspec_lib_schema0.AnySchemaModel>, options?: _contractspec_lib_contracts0.RenderOptions<unknown> | undefined) => react_jsx_runtime113.JSX.Element;
|
|
9
8
|
};
|
|
10
9
|
//#endregion
|
|
11
10
|
export { formRenderer };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"form-contract.d.ts","names":[],"sources":["../../src/renderers/form-contract.tsx"],"sourcesContent":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"form-contract.d.ts","names":[],"sources":["../../src/renderers/form-contract.tsx"],"sourcesContent":[],"mappings":";;;;;cA+Fa;uDAsBX,yBAAA,CAAA,cAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contractspec/lib.design-system",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.53.0",
|
|
4
4
|
"description": "Design tokens and theming primitives",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"contractspec",
|
|
@@ -28,10 +28,10 @@
|
|
|
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.53.0",
|
|
32
|
+
"@contractspec/lib.contracts": "1.53.0",
|
|
33
|
+
"@contractspec/lib.ui-kit": "1.53.0",
|
|
34
|
+
"@contractspec/lib.ui-kit-web": "1.53.0",
|
|
35
35
|
"@hookform/resolvers": "5.2.2",
|
|
36
36
|
"class-variance-authority": "^0.7.1",
|
|
37
37
|
"clsx": "^2.1.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.53.0",
|
|
50
|
+
"@contractspec/tool.typescript": "1.53.0",
|
|
51
51
|
"@types/node": "^25.0.6",
|
|
52
52
|
"@types/react-dom": "^19.0.14",
|
|
53
53
|
"postcss": "^8.5",
|