@donotdev/components 0.0.3 → 0.0.4
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/atomic/CallToAction/index.d.ts +5 -0
- package/dist/atomic/CallToAction/index.d.ts.map +1 -1
- package/dist/atomic/CallToAction/index.js +3 -2
- package/dist/atomic/Card/index.d.ts +62 -6
- package/dist/atomic/Card/index.d.ts.map +1 -1
- package/dist/atomic/Card/index.js +66 -20
- package/dist/atomic/DualCard/index.d.ts +20 -24
- package/dist/atomic/DualCard/index.d.ts.map +1 -1
- package/dist/atomic/DualCard/index.js +7 -45
- package/dist/atomic/Grid/index.d.ts +25 -33
- package/dist/atomic/Grid/index.d.ts.map +1 -1
- package/dist/atomic/Grid/index.js +26 -29
- package/dist/atomic/HeroSection/index.d.ts +9 -46
- package/dist/atomic/HeroSection/index.d.ts.map +1 -1
- package/dist/atomic/HeroSection/index.js +6 -36
- package/dist/atomic/List/index.d.ts +6 -1
- package/dist/atomic/List/index.d.ts.map +1 -1
- package/dist/atomic/List/index.js +8 -4
- package/dist/atomic/Section/index.d.ts +32 -14
- package/dist/atomic/Section/index.d.ts.map +1 -1
- package/dist/atomic/Section/index.js +24 -12
- package/dist/atomic/Table/index.d.ts +2 -2
- package/dist/atomic/index.d.ts +3 -3
- package/dist/atomic/index.d.ts.map +1 -1
- package/dist/atomic/index.js +1 -1
- package/dist/index.js +4 -4
- package/dist/styles/index.css +253 -148
- package/dist/types.d.ts +2 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -59,6 +59,11 @@ interface CallToActionOwnProps {
|
|
|
59
59
|
* @default 'center'
|
|
60
60
|
*/
|
|
61
61
|
align?: 'start' | 'center' | 'end';
|
|
62
|
+
/**
|
|
63
|
+
* Tone system for background colors (matches Section component)
|
|
64
|
+
* @default 'base'
|
|
65
|
+
*/
|
|
66
|
+
tone?: 'base' | 'muted' | 'elevated' | 'contrast' | 'accent';
|
|
62
67
|
/** Additional children (for custom content) */
|
|
63
68
|
children?: ReactNode;
|
|
64
69
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/atomic/CallToAction/index.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,qBAAqB,EAC1B,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAKf,OAAO,oBAAoB,CAAC;AAE5B;;GAEG;AACH,UAAU,oBAAoB;IAC5B;;;;;;OAMG;IACH,EAAE,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,KAAK,CAAC;IAEjC,iBAAiB;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,8BAA8B;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,qEAAqE;IACrE,aAAa,CAAC,EAAE,SAAS,CAAC;IAE1B,uEAAuE;IACvE,eAAe,CAAC,EAAE,SAAS,CAAC;IAE5B;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IAEnC,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;;GAGG;AACH,MAAM,MAAM,iBAAiB,CAAC,CAAC,SAAS,WAAW,GAAG,SAAS,IAC7D,oBAAoB,GAClB,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC,EAAE,MAAM,oBAAoB,CAAC,CAAC;AAE/D,QAAA,MAAM,YAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/atomic/CallToAction/index.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,qBAAqB,EAC1B,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAKf,OAAO,oBAAoB,CAAC;AAE5B;;GAEG;AACH,UAAU,oBAAoB;IAC5B;;;;;;OAMG;IACH,EAAE,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,KAAK,CAAC;IAEjC,iBAAiB;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,8BAA8B;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,qEAAqE;IACrE,aAAa,CAAC,EAAE,SAAS,CAAC;IAE1B,uEAAuE;IACvE,eAAe,CAAC,EAAE,SAAS,CAAC;IAE5B;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IAEnC;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,UAAU,GAAG,UAAU,GAAG,QAAQ,CAAC;IAE7D,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;;GAGG;AACH,MAAM,MAAM,iBAAiB,CAAC,CAAC,SAAS,WAAW,GAAG,SAAS,IAC7D,oBAAoB,GAClB,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC,EAAE,MAAM,oBAAoB,CAAC,CAAC;AAE/D,QAAA,MAAM,YAAY,mIA+CjB,CAAC;AAIF,eAAe,YAAY,CAAC"}
|
|
@@ -38,14 +38,15 @@ import { createElement, forwardRef, } from 'react';
|
|
|
38
38
|
import { cn } from '../../utils/helpers';
|
|
39
39
|
import Text, { TEXT_VARIANT } from '../Text';
|
|
40
40
|
import './CallToAction.css';
|
|
41
|
-
const CallToAction = forwardRef(function CallToAction({ as = 'section', title, subtitle, primaryAction, secondaryAction, align = 'center', children, className, ...props }, ref) {
|
|
41
|
+
const CallToAction = forwardRef(function CallToAction({ as = 'section', title, subtitle, primaryAction, secondaryAction, align = 'center', tone = 'base', children, className, ...props }, ref) {
|
|
42
42
|
const Component = as;
|
|
43
43
|
return createElement(Component, {
|
|
44
44
|
ref,
|
|
45
45
|
'aria-label': props['aria-label'] || 'Call to Action',
|
|
46
46
|
className: cn('dndev-cta', className),
|
|
47
|
+
'data-tone': tone,
|
|
47
48
|
...props,
|
|
48
|
-
}, _jsxs("div", { className: "dndev-cta-content", "data-text-align": align, children: [title && (_jsx("h2", {
|
|
49
|
+
}, _jsxs("div", { className: "dndev-cta-content", "data-text-align": align, children: [title && (_jsx(Text, { as: "h2", style: { fontSize: 'var(--font-size-2xl)' }, children: title })), subtitle && _jsx(Text, { as: "h4", children: subtitle }), (primaryAction || secondaryAction) && (_jsxs("div", { className: "dndev-cta-actions", children: [primaryAction, secondaryAction] })), children] }));
|
|
49
50
|
});
|
|
50
51
|
CallToAction.displayName = 'CallToAction';
|
|
51
52
|
export default CallToAction;
|
|
@@ -10,6 +10,51 @@ import { type VariantProps } from 'class-variance-authority';
|
|
|
10
10
|
import { surfaceVariants } from '../../utils/variants';
|
|
11
11
|
import type { IconType } from '../../types';
|
|
12
12
|
import type { HTMLAttributes, ReactNode, Ref } from 'react';
|
|
13
|
+
/**
|
|
14
|
+
* Unified content type for all card components.
|
|
15
|
+
* - `string` → renders as Text
|
|
16
|
+
* - `string[]` → renders as List (consumer controls icons via List directly)
|
|
17
|
+
* - `ReactNode` → passthrough (full control)
|
|
18
|
+
*/
|
|
19
|
+
export type CardContent = string | string[] | ReactNode;
|
|
20
|
+
/**
|
|
21
|
+
* Converts CardContent to ReactNode.
|
|
22
|
+
* Use this when rendering CardContent outside of Card component.
|
|
23
|
+
*
|
|
24
|
+
* @param content - CardContent to convert
|
|
25
|
+
* @returns ReactNode ready for rendering
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```tsx
|
|
29
|
+
* import { renderCardContent, type CardContent } from '@donotdev/components';
|
|
30
|
+
*
|
|
31
|
+
* const MyComponent = ({ content }: { content: CardContent }) => (
|
|
32
|
+
* <div>{renderCardContent(content)}</div>
|
|
33
|
+
* );
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export declare function renderCardContent(content: CardContent | undefined): ReactNode;
|
|
37
|
+
/**
|
|
38
|
+
* Renders card header with icon, title, and subtitle.
|
|
39
|
+
* Groups icon+title+subtitle with no gap (trusts lineHeight).
|
|
40
|
+
*
|
|
41
|
+
* @param icon - Optional icon to display inline with title
|
|
42
|
+
* @param title - Optional title (string or ReactNode for Trans)
|
|
43
|
+
* @param subtitle - Optional subtitle (string or ReactNode for Trans)
|
|
44
|
+
* @returns ReactNode ready for rendering
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```tsx
|
|
48
|
+
* import { renderCardHeader } from '@donotdev/components';
|
|
49
|
+
*
|
|
50
|
+
* // Plain string
|
|
51
|
+
* const header = renderCardHeader(Zap, 'Lightning Fast', 'Build in minutes');
|
|
52
|
+
*
|
|
53
|
+
* // With Trans for rich text
|
|
54
|
+
* const richHeader = renderCardHeader(Zap, <Trans ns="home" i18nKey="title" />);
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export declare function renderCardHeader(icon?: IconType, title?: string | ReactNode, subtitle?: string | ReactNode): ReactNode;
|
|
13
58
|
/**
|
|
14
59
|
* Card variant constants - re-exported from shared SURFACE_VARIANT
|
|
15
60
|
* Matches .dndev-surface CSS class
|
|
@@ -36,20 +81,31 @@ export interface CardProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'
|
|
|
36
81
|
* @default false
|
|
37
82
|
*/
|
|
38
83
|
asChild?: boolean;
|
|
39
|
-
/** Optional icon to display
|
|
84
|
+
/** Optional icon to display inline with title */
|
|
40
85
|
icon?: IconType;
|
|
41
|
-
/** Main title
|
|
86
|
+
/** Main title (string or ReactNode for Trans rich text) */
|
|
42
87
|
title?: string | ReactNode;
|
|
43
|
-
/** Subtitle displayed below the title */
|
|
88
|
+
/** Subtitle displayed below the title (string or ReactNode for Trans) */
|
|
44
89
|
subtitle?: string | ReactNode;
|
|
45
|
-
/**
|
|
46
|
-
|
|
90
|
+
/**
|
|
91
|
+
* Main content - string, string[], or ReactNode.
|
|
92
|
+
* - string → renders as Text
|
|
93
|
+
* - string[] → renders as List
|
|
94
|
+
* - ReactNode → passthrough
|
|
95
|
+
*/
|
|
96
|
+
content?: CardContent;
|
|
47
97
|
/** Footer content */
|
|
48
98
|
footer?: ReactNode;
|
|
49
99
|
/** Tooltip text */
|
|
50
100
|
tooltip?: string;
|
|
51
101
|
/** Click handler */
|
|
52
102
|
onClick?: () => void;
|
|
103
|
+
/**
|
|
104
|
+
* Whether the card is clickable (enables hover styles).
|
|
105
|
+
* Set to true when wrapped in Link or when onClick is provided.
|
|
106
|
+
* @default false (auto-detected from onClick)
|
|
107
|
+
*/
|
|
108
|
+
clickable?: boolean;
|
|
53
109
|
/**
|
|
54
110
|
* Whether the card has elevation/shadow.
|
|
55
111
|
* @default false
|
|
@@ -77,6 +133,6 @@ export interface CardProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'
|
|
|
77
133
|
* @param {CardProps} props - The props for the card
|
|
78
134
|
* @returns {JSX.Element} The rendered card
|
|
79
135
|
*/
|
|
80
|
-
declare const Card: ({ className, variant, asChild, icon, title, subtitle, content, footer, children, tooltip, onClick, elevated, style, ref, ...props }: CardProps) => import("react/jsx-runtime").JSX.Element;
|
|
136
|
+
declare const Card: ({ className, variant, asChild, icon, title, subtitle, content, footer, children, tooltip, onClick, clickable, elevated, style, ref, ...props }: CardProps) => import("react/jsx-runtime").JSX.Element;
|
|
81
137
|
export default Card;
|
|
82
138
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/atomic/Card/index.tsx"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAI7D,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/atomic/Card/index.tsx"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAI7D,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAOvD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAE5D;;;;;GAKG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC;AAExD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,WAAW,GAAG,SAAS,GAAG,SAAS,CAyB7E;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,CAAC,EAAE,QAAQ,EACf,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,EAC1B,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,GAC5B,SAAS,CA0BX;AAED;;;GAGG;AACH,eAAO,MAAM,YAAY;;;;;;;;;;;CAAkB,CAAC;AAE5C;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,YAAY,CAAC,OAAO,eAAe,CAAC,CAAC,SAAS,CAAC,CAAC;AAE1E,MAAM,WAAW,SACf,SACE,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC,EACzD,YAAY,CAAC,OAAO,eAAe,CAAC;IACtC;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,iDAAiD;IACjD,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,2DAA2D;IAC3D,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,yEAAyE;IACzE,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B;;;;;OAKG;IACH,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,qBAAqB;IACrB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,mBAAmB;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oBAAoB;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sCAAsC;IACtC,GAAG,CAAC,EAAE,GAAG,CAAC,cAAc,CAAC,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,QAAA,MAAM,IAAI,GAAI,gJAiBX,SAAS,4CA0CX,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -12,9 +12,66 @@ import {} from 'class-variance-authority';
|
|
|
12
12
|
import { SURFACE_VARIANT } from '../../utils/constants';
|
|
13
13
|
import { cn, getVariantDataAttrs } from '../../utils/helpers';
|
|
14
14
|
import { surfaceVariants } from '../../utils/variants';
|
|
15
|
-
import
|
|
15
|
+
import Icon from '../Icons/Icon';
|
|
16
|
+
import List from '../List';
|
|
16
17
|
import Slot from '../Slot';
|
|
17
18
|
import Stack from '../Stack';
|
|
19
|
+
import Text from '../Text';
|
|
20
|
+
/**
|
|
21
|
+
* Converts CardContent to ReactNode.
|
|
22
|
+
* Use this when rendering CardContent outside of Card component.
|
|
23
|
+
*
|
|
24
|
+
* @param content - CardContent to convert
|
|
25
|
+
* @returns ReactNode ready for rendering
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```tsx
|
|
29
|
+
* import { renderCardContent, type CardContent } from '@donotdev/components';
|
|
30
|
+
*
|
|
31
|
+
* const MyComponent = ({ content }: { content: CardContent }) => (
|
|
32
|
+
* <div>{renderCardContent(content)}</div>
|
|
33
|
+
* );
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export function renderCardContent(content) {
|
|
37
|
+
if (!content)
|
|
38
|
+
return null;
|
|
39
|
+
if (typeof content === 'string') {
|
|
40
|
+
return (_jsx(Text, { as: "p", level: "small", children: content }));
|
|
41
|
+
}
|
|
42
|
+
if (Array.isArray(content)) {
|
|
43
|
+
if (content.length === 1 && typeof content[0] === 'string') {
|
|
44
|
+
return (_jsx(Text, { as: "p", level: "small", children: content[0] }));
|
|
45
|
+
}
|
|
46
|
+
return (_jsx(List, { items: content, style: { listStyle: 'none', paddingInlineStart: 0 } }));
|
|
47
|
+
}
|
|
48
|
+
return content;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Renders card header with icon, title, and subtitle.
|
|
52
|
+
* Groups icon+title+subtitle with no gap (trusts lineHeight).
|
|
53
|
+
*
|
|
54
|
+
* @param icon - Optional icon to display inline with title
|
|
55
|
+
* @param title - Optional title (string or ReactNode for Trans)
|
|
56
|
+
* @param subtitle - Optional subtitle (string or ReactNode for Trans)
|
|
57
|
+
* @returns ReactNode ready for rendering
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```tsx
|
|
61
|
+
* import { renderCardHeader } from '@donotdev/components';
|
|
62
|
+
*
|
|
63
|
+
* // Plain string
|
|
64
|
+
* const header = renderCardHeader(Zap, 'Lightning Fast', 'Build in minutes');
|
|
65
|
+
*
|
|
66
|
+
* // With Trans for rich text
|
|
67
|
+
* const richHeader = renderCardHeader(Zap, <Trans ns="home" i18nKey="title" />);
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export function renderCardHeader(icon, title, subtitle) {
|
|
71
|
+
if (!icon && !title && !subtitle)
|
|
72
|
+
return null;
|
|
73
|
+
return (_jsxs("div", { className: "dndev-card-header", children: [icon && title ? (_jsxs(Stack, { direction: "row", align: "center", gap: "tight", children: [_jsx(Icon, { icon: icon, ariaHidden: true }), _jsx(Text, { as: "h3", className: "dndev-card-title", children: title })] })) : title ? (_jsx(Text, { as: "h3", className: "dndev-card-title", children: title })) : icon ? (_jsx(Icon, { icon: icon, ariaHidden: true })) : null, subtitle && (_jsx(Text, { as: "h4", className: "dndev-card-subtitle", children: subtitle }))] }));
|
|
74
|
+
}
|
|
18
75
|
/**
|
|
19
76
|
* Card variant constants - re-exported from shared SURFACE_VARIANT
|
|
20
77
|
* Matches .dndev-surface CSS class
|
|
@@ -39,36 +96,25 @@ export const CARD_VARIANT = SURFACE_VARIANT;
|
|
|
39
96
|
* @param {CardProps} props - The props for the card
|
|
40
97
|
* @returns {JSX.Element} The rendered card
|
|
41
98
|
*/
|
|
42
|
-
const Card = ({ className, variant, asChild = false, icon, title, subtitle, content, footer, children, tooltip, onClick, elevated, style, ref, ...props }) => {
|
|
99
|
+
const Card = ({ className, variant, asChild = false, icon, title, subtitle, content, footer, children, tooltip, onClick, clickable, elevated, style, ref, ...props }) => {
|
|
43
100
|
const Comp = asChild ? Slot : 'div';
|
|
44
101
|
const variantAttrs = getVariantDataAttrs({ variant });
|
|
102
|
+
const isClickable = clickable !== undefined ? clickable : !!onClick;
|
|
45
103
|
const cardAttrs = {
|
|
46
104
|
...variantAttrs,
|
|
47
105
|
'data-role': 'card',
|
|
48
106
|
...(elevated !== undefined && {
|
|
49
107
|
'data-elevated': elevated ? 'true' : 'false',
|
|
50
108
|
}),
|
|
51
|
-
...(
|
|
52
|
-
};
|
|
53
|
-
const hasContent = content || children;
|
|
54
|
-
const getGridTemplateRows = () => {
|
|
55
|
-
const rows = [];
|
|
56
|
-
if (title || icon)
|
|
57
|
-
rows.push('auto');
|
|
58
|
-
if (subtitle)
|
|
59
|
-
rows.push('auto');
|
|
60
|
-
if (hasContent)
|
|
61
|
-
rows.push('1fr');
|
|
62
|
-
if (footer)
|
|
63
|
-
rows.push('auto');
|
|
64
|
-
return rows.join(' ') || '1fr';
|
|
109
|
+
...(isClickable && { 'data-clickable': 'true' }),
|
|
65
110
|
};
|
|
66
|
-
|
|
67
|
-
const
|
|
111
|
+
const header = renderCardHeader(icon, title, subtitle);
|
|
112
|
+
const contentNode = renderCardContent(content);
|
|
113
|
+
const hasContent = contentNode || children;
|
|
68
114
|
return (_jsxs(Comp, { ref: ref, className: cn('dndev-card', surfaceVariants({ variant }), className), style: {
|
|
69
|
-
gridTemplateRows: getGridTemplateRows(),
|
|
70
115
|
width: '100%',
|
|
116
|
+
height: '100%',
|
|
71
117
|
...style,
|
|
72
|
-
}, ...cardAttrs, onClick: onClick, title: tooltip, ...props, children: [
|
|
118
|
+
}, ...cardAttrs, onClick: onClick, title: tooltip, ...props, children: [header, hasContent && (_jsxs("div", { children: [contentNode, children] })), footer && _jsx("div", { children: footer })] }));
|
|
73
119
|
};
|
|
74
120
|
export default Card;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { ReactNode, HTMLAttributes } from 'react';
|
|
2
2
|
import { type VariantProps } from 'class-variance-authority';
|
|
3
3
|
import { surfaceVariants } from '../../utils/variants';
|
|
4
|
-
import {
|
|
4
|
+
import type { CardContent } from '../Card';
|
|
5
|
+
import type { IconType } from '../../types';
|
|
5
6
|
import './DualCard.css';
|
|
6
7
|
export type DualCardVariant = VariantProps<typeof surfaceVariants>['variant'];
|
|
7
8
|
export interface DualCardProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title' | 'content'>, VariantProps<typeof surfaceVariants> {
|
|
@@ -12,37 +13,32 @@ export interface DualCardProps extends Omit<HTMLAttributes<HTMLDivElement>, 'tit
|
|
|
12
13
|
elevated?: boolean;
|
|
13
14
|
/** Click handler */
|
|
14
15
|
onClick?: () => void;
|
|
16
|
+
/** Left side icon */
|
|
17
|
+
leftIcon?: IconType;
|
|
15
18
|
/** Left side title */
|
|
16
|
-
leftTitle?: string
|
|
19
|
+
leftTitle?: string;
|
|
17
20
|
/** Left side subtitle */
|
|
18
|
-
leftSubtitle?: string
|
|
19
|
-
/**
|
|
20
|
-
|
|
21
|
+
leftSubtitle?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Left side content - string, string[], or ReactNode.
|
|
24
|
+
* For lists with icons, pass `<List icon={...} items={...} />` directly.
|
|
25
|
+
*/
|
|
26
|
+
leftContent?: CardContent;
|
|
21
27
|
/** Left side CTA (button, link, etc.) */
|
|
22
28
|
leftCTA?: ReactNode;
|
|
29
|
+
/** Right side icon */
|
|
30
|
+
rightIcon?: IconType;
|
|
23
31
|
/** Right side title */
|
|
24
|
-
rightTitle?: string
|
|
32
|
+
rightTitle?: string;
|
|
25
33
|
/** Right side subtitle */
|
|
26
|
-
rightSubtitle?: string
|
|
27
|
-
/** Right side content - same as FeatureCard: string, array, or ReactNode */
|
|
28
|
-
rightContent?: string | (string | ReactNode)[] | ReactNode;
|
|
29
|
-
/** Right side CTA (button, link, etc.) */
|
|
30
|
-
rightCTA?: ReactNode;
|
|
31
|
-
/**
|
|
32
|
-
* List density for content rendering (page-level preset)
|
|
33
|
-
* @default 'default'
|
|
34
|
-
*/
|
|
35
|
-
listDensity?: 'dense' | 'narrow' | 'default' | 'expressive';
|
|
34
|
+
rightSubtitle?: string;
|
|
36
35
|
/**
|
|
37
|
-
*
|
|
38
|
-
*
|
|
36
|
+
* Right side content - string, string[], or ReactNode.
|
|
37
|
+
* For lists with icons, pass `<List icon={...} items={...} />` directly.
|
|
39
38
|
*/
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
|
|
43
|
-
* @default false
|
|
44
|
-
*/
|
|
45
|
-
showBullets?: boolean;
|
|
39
|
+
rightContent?: CardContent;
|
|
40
|
+
/** Right side CTA (button, link, etc.) */
|
|
41
|
+
rightCTA?: ReactNode;
|
|
46
42
|
}
|
|
47
43
|
/**
|
|
48
44
|
* DualCard - Two-column card with vertical separator
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/atomic/DualCard/index.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AACvD,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAI7D,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/atomic/DualCard/index.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AACvD,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAI7D,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAKvD,OAAO,KAAK,EAAe,WAAW,EAAE,MAAM,SAAS,CAAC;AACxD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,gBAAgB,CAAC;AAExB,MAAM,MAAM,eAAe,GAAG,YAAY,CAAC,OAAO,eAAe,CAAC,CAAC,SAAS,CAAC,CAAC;AAE9E,MAAM,WAAW,aACf,SACE,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC,EACzD,YAAY,CAAC,OAAO,eAAe,CAAC;IACtC;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,oBAAoB;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,qBAAqB;IACrB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,sBAAsB;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yBAAyB;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,yCAAyC;IACzC,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,sBAAsB;IACtB,SAAS,CAAC,EAAE,QAAQ,CAAC;IACrB,uBAAuB;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0BAA0B;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,YAAY,CAAC,EAAE,WAAW,CAAC;IAC3B,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,QAAA,MAAM,QAAQ,0GA4Eb,CAAC;AAIF,eAAe,QAAQ,CAAC"}
|
|
@@ -15,9 +15,7 @@ import { cn, getVariantDataAttrs } from '../../utils/helpers';
|
|
|
15
15
|
import { surfaceVariants } from '../../utils/variants';
|
|
16
16
|
import Stack from '../Stack';
|
|
17
17
|
import Separator, { SEPARATOR_VARIANT } from '../Separator';
|
|
18
|
-
import
|
|
19
|
-
import List, {} from '../List';
|
|
20
|
-
import { Check } from 'lucide-react';
|
|
18
|
+
import { renderCardContent, renderCardHeader } from '../Card';
|
|
21
19
|
import './DualCard.css';
|
|
22
20
|
/**
|
|
23
21
|
* DualCard - Two-column card with vertical separator
|
|
@@ -42,49 +40,13 @@ import './DualCard.css';
|
|
|
42
40
|
* />
|
|
43
41
|
* ```
|
|
44
42
|
*/
|
|
45
|
-
const DualCard = forwardRef(({ className, variant, elevated, onClick, leftTitle, leftSubtitle, leftContent, leftCTA, rightTitle, rightSubtitle, rightContent, rightCTA, style,
|
|
43
|
+
const DualCard = forwardRef(({ className, variant, elevated, onClick, leftIcon, leftTitle, leftSubtitle, leftContent, leftCTA, rightIcon, rightTitle, rightSubtitle, rightContent, rightCTA, style, ...props }, ref) => {
|
|
46
44
|
const variantAttrs = getVariantDataAttrs({ variant });
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
if (typeof content === 'string') {
|
|
53
|
-
return (_jsx(Text, { as: "p", level: "body", children: content }));
|
|
54
|
-
}
|
|
55
|
-
if (Array.isArray(content)) {
|
|
56
|
-
// Strip manual bullet characters (•) if present
|
|
57
|
-
const cleanContent = content.map((item) => {
|
|
58
|
-
if (typeof item === 'string') {
|
|
59
|
-
return item.replace(/^[\s•\-\*]+/, '').trim();
|
|
60
|
-
}
|
|
61
|
-
return item;
|
|
62
|
-
});
|
|
63
|
-
// If single string item, render as plain text (not a list)
|
|
64
|
-
// If multiple items or contains ReactNodes, use List component
|
|
65
|
-
if (cleanContent.length === 1 && typeof cleanContent[0] === 'string') {
|
|
66
|
-
return (_jsx(Text, { as: "p", level: "body", children: cleanContent[0] }));
|
|
67
|
-
}
|
|
68
|
-
// Convert to ListItem objects with checkmark icons when showBullets is true
|
|
69
|
-
const listItems = showBullets
|
|
70
|
-
? cleanContent.map((item) => {
|
|
71
|
-
if (typeof item === 'string') {
|
|
72
|
-
return {
|
|
73
|
-
icon: _jsx(Check, { size: 16 }),
|
|
74
|
-
content: item,
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
// If already a ListItem or ReactNode, keep as is
|
|
78
|
-
return item;
|
|
79
|
-
})
|
|
80
|
-
: cleanContent;
|
|
81
|
-
return (_jsx(List, { items: listItems, density: listDensity, gap: listGap, style: { listStyle: 'none' } }));
|
|
82
|
-
}
|
|
83
|
-
return content;
|
|
84
|
-
};
|
|
85
|
-
const leftContentNode = convertContent(leftContent);
|
|
86
|
-
const rightContentNode = convertContent(rightContent);
|
|
87
|
-
return (_jsx("div", { ref: ref, className: cn('dndev-dual-card', surfaceVariants({ variant }), className), "data-role": "card", "data-elevated": elevated !== undefined ? (elevated ? 'true' : 'false') : undefined, "data-clickable": onClick ? 'true' : undefined, onClick: onClick, style: style, ...variantAttrs, ...props, children: _jsxs("div", { className: "dndev-dual-card-container", children: [_jsxs("div", { className: "dndev-dual-card-left", children: [leftTitle && (_jsx(Text, { as: "h3", level: "h3", className: "dndev-dual-card-title", children: leftTitle })), leftSubtitle && (_jsx(Text, { as: "p", level: "body", variant: "muted", className: "dndev-dual-card-subtitle", children: leftSubtitle })), leftContentNode && (_jsx("div", { className: "dndev-dual-card-content", children: leftContentNode })), leftCTA && _jsx("div", { className: "dndev-dual-card-cta", children: leftCTA })] }), _jsx(Separator, { orientation: "vertical", variant: SEPARATOR_VARIANT.ACCENT, className: "dndev-dual-card-separator" }), _jsxs("div", { className: "dndev-dual-card-right", children: [rightTitle && (_jsx(Text, { as: "h3", level: "h3", className: "dndev-dual-card-title", children: rightTitle })), rightSubtitle && (_jsx(Text, { as: "p", level: "body", variant: "muted", className: "dndev-dual-card-subtitle", children: rightSubtitle })), rightContentNode && (_jsx("div", { className: "dndev-dual-card-content", children: rightContentNode })), rightCTA && _jsx("div", { className: "dndev-dual-card-cta", children: rightCTA })] })] }) }));
|
|
45
|
+
const leftHeader = renderCardHeader(leftIcon, leftTitle, leftSubtitle);
|
|
46
|
+
const leftContentNode = renderCardContent(leftContent);
|
|
47
|
+
const rightHeader = renderCardHeader(rightIcon, rightTitle, rightSubtitle);
|
|
48
|
+
const rightContentNode = renderCardContent(rightContent);
|
|
49
|
+
return (_jsx("div", { ref: ref, className: cn('dndev-dual-card', surfaceVariants({ variant }), className), "data-role": "card", "data-elevated": elevated !== undefined ? (elevated ? 'true' : 'false') : undefined, "data-clickable": onClick ? 'true' : undefined, onClick: onClick, style: style, ...variantAttrs, ...props, children: _jsxs("div", { className: "dndev-dual-card-container", children: [_jsxs("div", { className: "dndev-dual-card-left", children: [leftHeader, leftContentNode && (_jsx("div", { className: "dndev-dual-card-content", children: leftContentNode })), leftCTA && _jsx("div", { className: "dndev-dual-card-cta", children: leftCTA })] }), _jsx(Separator, { orientation: "vertical", variant: SEPARATOR_VARIANT.ACCENT, className: "dndev-dual-card-separator" }), _jsxs("div", { className: "dndev-dual-card-right", children: [rightHeader, rightContentNode && (_jsx("div", { className: "dndev-dual-card-content", children: rightContentNode })), rightCTA && _jsx("div", { className: "dndev-dual-card-cta", children: rightCTA })] })] }) }));
|
|
88
50
|
});
|
|
89
51
|
DualCard.displayName = 'DualCard';
|
|
90
52
|
export default DualCard;
|
|
@@ -1,37 +1,43 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Grid component
|
|
3
|
-
* @description Polymorphic CSS Grid layout primitive.
|
|
4
|
-
* Replaces redundant `div className="dndev-grid ..."` usage.
|
|
3
|
+
* @description Polymorphic CSS Grid layout primitive with responsive columns.
|
|
5
4
|
*
|
|
6
5
|
* @example
|
|
7
6
|
* ```tsx
|
|
8
|
-
* //
|
|
7
|
+
* // Fixed 3-column grid
|
|
9
8
|
* <Grid cols={3} gap="medium">
|
|
10
9
|
* <Card />
|
|
11
10
|
* <Card />
|
|
12
11
|
* <Card />
|
|
13
12
|
* </Grid>
|
|
14
13
|
*
|
|
15
|
-
* //
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* <
|
|
14
|
+
* // Responsive grid: [mobile, tablet, laptop, desktop]
|
|
15
|
+
* // 1 col on mobile/tablet, 2 on laptop, 3 on desktop
|
|
16
|
+
* <Grid cols={[1, 1, 2, 3]} gap="medium">
|
|
17
|
+
* <Card />
|
|
18
|
+
* <Card />
|
|
19
|
+
* <Card />
|
|
19
20
|
* </Grid>
|
|
20
21
|
*
|
|
21
22
|
* // Named grid areas
|
|
22
|
-
* <Grid
|
|
23
|
-
* <GridArea name="left">{
|
|
24
|
-
* <GridArea name="center">{
|
|
25
|
-
* <GridArea name="right">{
|
|
23
|
+
* <Grid areas="left center right" templateColumns="1fr auto 1fr">
|
|
24
|
+
* <GridArea name="left">{left}</GridArea>
|
|
25
|
+
* <GridArea name="center">{center}</GridArea>
|
|
26
|
+
* <GridArea name="right">{right}</GridArea>
|
|
26
27
|
* </Grid>
|
|
27
28
|
* ```
|
|
28
29
|
*
|
|
29
|
-
* @version 0.0.
|
|
30
|
+
* @version 0.0.4
|
|
30
31
|
* @since 0.0.1
|
|
31
32
|
* @author AMBROISE PARK Consulting
|
|
32
33
|
*/
|
|
33
34
|
import { type ElementType, type ComponentPropsWithRef, type ReactNode } from 'react';
|
|
34
35
|
import './Grid.css';
|
|
36
|
+
/**
|
|
37
|
+
* Responsive columns array: [mobile, tablet, laptop, desktop]
|
|
38
|
+
* @example [1, 1, 2, 3] - 1 col on mobile/tablet, 2 on laptop, 3 on desktop
|
|
39
|
+
*/
|
|
40
|
+
export type ResponsiveCols = [number, number, number, number];
|
|
35
41
|
/**
|
|
36
42
|
* Grid-specific props (layout directives)
|
|
37
43
|
*/
|
|
@@ -43,29 +49,15 @@ interface GridOwnProps {
|
|
|
43
49
|
*/
|
|
44
50
|
as?: ElementType;
|
|
45
51
|
/**
|
|
46
|
-
* Number of columns
|
|
52
|
+
* Number of columns - fixed or responsive
|
|
53
|
+
* - number: fixed columns (same on all breakpoints)
|
|
54
|
+
* - [mobile, tablet, laptop, desktop]: responsive columns per breakpoint
|
|
47
55
|
* @default 1
|
|
56
|
+
* @example 3 - always 3 columns
|
|
57
|
+
* @example [1, 1, 2, 3] - 1 col mobile/tablet, 2 laptop, 3 desktop
|
|
58
|
+
* @example [1, 2, 3, 3] - 1 mobile, 2 tablet, 3 laptop/desktop
|
|
48
59
|
*/
|
|
49
|
-
cols?: number;
|
|
50
|
-
/**
|
|
51
|
-
* Minimum column width for all layouts
|
|
52
|
-
* Controls when columns wrap automatically - CSS Grid wraps when container < (cols × minColWidth)
|
|
53
|
-
* @example "250px", "20rem", "280px"
|
|
54
|
-
* @default undefined (0px - allows columns to shrink to content size)
|
|
55
|
-
*/
|
|
56
|
-
minColWidth?: string;
|
|
57
|
-
/**
|
|
58
|
-
* Use auto-fit instead of fixed column count
|
|
59
|
-
* Automatically fits as many columns as possible based on minColWidth
|
|
60
|
-
* @default false
|
|
61
|
-
*/
|
|
62
|
-
autoFit?: boolean;
|
|
63
|
-
/**
|
|
64
|
-
* Use auto-fill instead of fixed column count
|
|
65
|
-
* Automatically fills available space with columns based on minColWidth
|
|
66
|
-
* @default false
|
|
67
|
-
*/
|
|
68
|
-
autoFill?: boolean;
|
|
60
|
+
cols?: number | ResponsiveCols;
|
|
69
61
|
/**
|
|
70
62
|
* Spacing between items
|
|
71
63
|
* @default 'medium'
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/atomic/Grid/index.tsx"],"names":[],"mappings":"AAEA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/atomic/Grid/index.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,qBAAqB,EAC1B,KAAK,SAAS,EAEf,MAAM,OAAO,CAAC;AAIf,OAAO,YAAY,CAAC;AAEpB;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAE9D;;GAEG;AACH,UAAU,YAAY;IACpB;;;;OAIG;IACH,EAAE,CAAC,EAAE,WAAW,CAAC;IAEjB;;;;;;;;OAQG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,cAAc,CAAC;IAE/B;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;IAE5C;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,SAAS,CAAC;IAE/C;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,SAAS,CAAC;IAEjD;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,cAAc;IACd,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED;;;GAGG;AACH,MAAM,MAAM,SAAS,CAAC,CAAC,SAAS,WAAW,GAAG,KAAK,IAAI,YAAY,GACjE,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC,EAAE,MAAM,YAAY,CAAC,CAAC;AAErD;;;;;GAKG;AACH,QAAA,MAAM,IAAI,uHA2DT,CAAC;AAIF,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,YAAY,CAAC;AACjD,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,eAAe,IAAI,CAAC"}
|
|
@@ -1,33 +1,34 @@
|
|
|
1
1
|
// packages/components/src/atomic/Grid/index.tsx
|
|
2
2
|
/**
|
|
3
3
|
* @fileoverview Grid component
|
|
4
|
-
* @description Polymorphic CSS Grid layout primitive.
|
|
5
|
-
* Replaces redundant `div className="dndev-grid ..."` usage.
|
|
4
|
+
* @description Polymorphic CSS Grid layout primitive with responsive columns.
|
|
6
5
|
*
|
|
7
6
|
* @example
|
|
8
7
|
* ```tsx
|
|
9
|
-
* //
|
|
8
|
+
* // Fixed 3-column grid
|
|
10
9
|
* <Grid cols={3} gap="medium">
|
|
11
10
|
* <Card />
|
|
12
11
|
* <Card />
|
|
13
12
|
* <Card />
|
|
14
13
|
* </Grid>
|
|
15
14
|
*
|
|
16
|
-
* //
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* <
|
|
15
|
+
* // Responsive grid: [mobile, tablet, laptop, desktop]
|
|
16
|
+
* // 1 col on mobile/tablet, 2 on laptop, 3 on desktop
|
|
17
|
+
* <Grid cols={[1, 1, 2, 3]} gap="medium">
|
|
18
|
+
* <Card />
|
|
19
|
+
* <Card />
|
|
20
|
+
* <Card />
|
|
20
21
|
* </Grid>
|
|
21
22
|
*
|
|
22
23
|
* // Named grid areas
|
|
23
|
-
* <Grid
|
|
24
|
-
* <GridArea name="left">{
|
|
25
|
-
* <GridArea name="center">{
|
|
26
|
-
* <GridArea name="right">{
|
|
24
|
+
* <Grid areas="left center right" templateColumns="1fr auto 1fr">
|
|
25
|
+
* <GridArea name="left">{left}</GridArea>
|
|
26
|
+
* <GridArea name="center">{center}</GridArea>
|
|
27
|
+
* <GridArea name="right">{right}</GridArea>
|
|
27
28
|
* </Grid>
|
|
28
29
|
* ```
|
|
29
30
|
*
|
|
30
|
-
* @version 0.0.
|
|
31
|
+
* @version 0.0.4
|
|
31
32
|
* @since 0.0.1
|
|
32
33
|
* @author AMBROISE PARK Consulting
|
|
33
34
|
*/
|
|
@@ -41,24 +42,21 @@ import './Grid.css';
|
|
|
41
42
|
* Polymorphic CSS Grid layout primitive.
|
|
42
43
|
* Can render as any HTML element while maintaining grid layout.
|
|
43
44
|
*/
|
|
44
|
-
const Grid = forwardRef(({ as = 'div', cols = 1, gap = GAP_VARIANT.MEDIUM, align = 'stretch', justify = 'stretch',
|
|
45
|
+
const Grid = forwardRef(({ as = 'div', cols = 1, gap = GAP_VARIANT.MEDIUM, align = 'stretch', justify = 'stretch', areas, templateColumns, className, style, children, ...props }, ref) => {
|
|
45
46
|
const Component = as;
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
if (autoFit) {
|
|
52
|
-
return `repeat(auto-fit, minmax(min(100%, ${minColWidth || '250px'}), 1fr))`;
|
|
53
|
-
}
|
|
54
|
-
if (autoFill) {
|
|
55
|
-
return `repeat(auto-fill, minmax(min(100%, ${minColWidth || '250px'}), 1fr))`;
|
|
56
|
-
}
|
|
57
|
-
return `repeat(${cols}, minmax(${minColWidth || '0'}, 1fr))`;
|
|
58
|
-
};
|
|
47
|
+
// Parse cols into responsive values
|
|
48
|
+
const isResponsive = Array.isArray(cols);
|
|
49
|
+
const [colsMobile, colsTablet, colsLaptop, colsDesktop] = isResponsive
|
|
50
|
+
? cols
|
|
51
|
+
: [cols, cols, cols, cols];
|
|
59
52
|
const customStyle = {
|
|
60
53
|
display: 'grid',
|
|
61
54
|
width: '100%',
|
|
55
|
+
// Set CSS custom properties for responsive columns
|
|
56
|
+
'--grid-cols-mobile': colsMobile,
|
|
57
|
+
'--grid-cols-tablet': colsTablet,
|
|
58
|
+
'--grid-cols-laptop': colsLaptop,
|
|
59
|
+
'--grid-cols-desktop': colsDesktop,
|
|
62
60
|
...style,
|
|
63
61
|
...(areas
|
|
64
62
|
? {
|
|
@@ -67,9 +65,7 @@ const Grid = forwardRef(({ as = 'div', cols = 1, gap = GAP_VARIANT.MEDIUM, align
|
|
|
67
65
|
: `"${areas}"`,
|
|
68
66
|
}
|
|
69
67
|
: {}),
|
|
70
|
-
...(
|
|
71
|
-
gridTemplateColumns: getGridTemplateColumns(),
|
|
72
|
-
}),
|
|
68
|
+
...(templateColumns && { gridTemplateColumns: templateColumns }),
|
|
73
69
|
};
|
|
74
70
|
return createElement(Component, {
|
|
75
71
|
ref,
|
|
@@ -77,6 +73,7 @@ const Grid = forwardRef(({ as = 'div', cols = 1, gap = GAP_VARIANT.MEDIUM, align
|
|
|
77
73
|
'data-gap': gap,
|
|
78
74
|
'data-align': align,
|
|
79
75
|
'data-justify': justify,
|
|
76
|
+
'data-responsive': isResponsive ? 'true' : undefined,
|
|
80
77
|
style: customStyle,
|
|
81
78
|
...props,
|
|
82
79
|
}, children);
|