@roadlittledawn/docs-design-system-react 0.6.2 → 0.8.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/Collapser.d.ts +20 -3
- package/dist/components/Collapser.js +10 -6
- package/dist/components/Collapser.stories.d.ts +33 -0
- package/dist/components/Collapser.stories.js +122 -2
- package/dist/components/CollapserGroup.d.ts +6 -0
- package/dist/components/CollapserGroup.js +4 -4
- package/dist/components/CollapserGroup.stories.d.ts +7 -0
- package/dist/components/CollapserGroup.stories.js +29 -0
- package/dist/components/Grid.d.ts +90 -0
- package/dist/components/Grid.js +95 -0
- package/dist/components/Grid.stories.d.ts +69 -0
- package/dist/components/Grid.stories.js +259 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/styles.css +141 -1
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ReactNode } from "react";
|
|
2
|
-
interface CollapserProps {
|
|
2
|
+
export interface CollapserProps {
|
|
3
3
|
/** Title text or element displayed in the collapsible header */
|
|
4
4
|
title: string | ReactNode;
|
|
5
5
|
/** Optional ID for the title element */
|
|
@@ -21,6 +21,23 @@ interface CollapserProps {
|
|
|
21
21
|
children: ReactNode;
|
|
22
22
|
/** Additional CSS classes */
|
|
23
23
|
className?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Alignment of the title within the header.
|
|
26
|
+
* Use 'right' for right-aligned titles, typically paired with an icon on the left.
|
|
27
|
+
* @default 'left'
|
|
28
|
+
*/
|
|
29
|
+
align?: 'left' | 'right';
|
|
30
|
+
/**
|
|
31
|
+
* Optional icon or React element rendered on the left side of the header,
|
|
32
|
+
* before the title text. Useful for visual identification of each section.
|
|
33
|
+
*/
|
|
34
|
+
icon?: ReactNode;
|
|
35
|
+
/**
|
|
36
|
+
* Numeric step label shown on the far left of the header.
|
|
37
|
+
* Automatically injected by `CollapserGroup` when `numbered` is true;
|
|
38
|
+
* can also be set manually on individual collapsers.
|
|
39
|
+
* Use `--dds-collapser-step-number-color` to customise its colour.
|
|
40
|
+
*/
|
|
41
|
+
stepNumber?: number;
|
|
24
42
|
}
|
|
25
|
-
export declare function Collapser({ title, id, defaultOpen, open: controlledOpen, onToggle, children, className, }: CollapserProps): import("react/jsx-runtime").JSX.Element;
|
|
26
|
-
export {};
|
|
43
|
+
export declare function Collapser({ title, id, defaultOpen, open: controlledOpen, onToggle, children, className, align, icon, stepNumber, }: CollapserProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import {
|
|
2
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
import { useState, useRef, useEffect } from "react";
|
|
4
4
|
import { useKeyPress } from "../hooks/useKeyPress";
|
|
5
5
|
export function Collapser(_a) {
|
|
6
|
-
var title = _a.title, id = _a.id, _b = _a.defaultOpen, defaultOpen = _b === void 0 ? false : _b, controlledOpen = _a.open, onToggle = _a.onToggle, children = _a.children, _c = _a.className, className = _c === void 0 ? "" : _c;
|
|
7
|
-
var
|
|
6
|
+
var title = _a.title, id = _a.id, _b = _a.defaultOpen, defaultOpen = _b === void 0 ? false : _b, controlledOpen = _a.open, onToggle = _a.onToggle, children = _a.children, _c = _a.className, className = _c === void 0 ? "" : _c, _d = _a.align, align = _d === void 0 ? 'left' : _d, icon = _a.icon, stepNumber = _a.stepNumber;
|
|
7
|
+
var _e = useState(defaultOpen), uncontrolledOpen = _e[0], setUncontrolledOpen = _e[1];
|
|
8
8
|
var isControlled = controlledOpen !== undefined;
|
|
9
9
|
var isOpen = isControlled ? controlledOpen : uncontrolledOpen;
|
|
10
|
-
var
|
|
10
|
+
var _f = useState(undefined), height = _f[0], setHeight = _f[1];
|
|
11
11
|
var contentRef = useRef(null);
|
|
12
12
|
// Keyboard shortcuts: 's' or 'f' to show, 'h' to hide
|
|
13
13
|
useKeyPress(['s', 'f', 'h'], function (e) {
|
|
@@ -28,10 +28,14 @@ export function Collapser(_a) {
|
|
|
28
28
|
setUncontrolledOpen(!uncontrolledOpen);
|
|
29
29
|
}
|
|
30
30
|
};
|
|
31
|
-
var collapserClasses = [
|
|
31
|
+
var collapserClasses = [
|
|
32
|
+
"dds-collapser",
|
|
33
|
+
align === 'right' ? "dds-collapser--align-right" : "",
|
|
34
|
+
className,
|
|
35
|
+
]
|
|
32
36
|
.filter(Boolean)
|
|
33
37
|
.join(" ");
|
|
34
|
-
return (_jsxs("div", { className: collapserClasses, children: [_jsxs("button", { onClick: toggleOpen, type: "button", className: "dds-collapser-button", "aria-expanded": isOpen, children: [_jsx("h5", { id: id, className: "dds-collapser-title", children: title }), _jsx("svg", { className: "dds-collapser-icon ".concat(isOpen ? "dds-collapser-icon-open" : ""), width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: _jsx("polyline", { points: "6 9 12 15 18 9" }) })] }), _jsx("div", { className: "dds-collapser-content-wrapper", style: {
|
|
38
|
+
return (_jsxs("div", { className: collapserClasses, children: [_jsxs("button", { onClick: toggleOpen, type: "button", className: "dds-collapser-button", "aria-expanded": isOpen, children: [stepNumber !== undefined && (_jsxs("span", { className: "dds-collapser-step-number", children: [stepNumber, "."] })), icon && (_jsx("span", { className: "dds-collapser-header-icon", "aria-hidden": "true", children: icon })), _jsx("h5", { id: id, className: "dds-collapser-title", children: title }), _jsx("svg", { className: "dds-collapser-icon ".concat(isOpen ? "dds-collapser-icon-open" : ""), width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: _jsx("polyline", { points: "6 9 12 15 18 9" }) })] }), _jsx("div", { className: "dds-collapser-content-wrapper", style: {
|
|
35
39
|
height: isOpen ? height : 0,
|
|
36
40
|
}, children: _jsx("div", { ref: contentRef, className: "dds-collapser-content", children: children }) })] }));
|
|
37
41
|
}
|
|
@@ -18,11 +18,44 @@ export declare const DefaultOpen: Story;
|
|
|
18
18
|
* Collapser with an ID for the title.
|
|
19
19
|
*/
|
|
20
20
|
export declare const WithID: Story;
|
|
21
|
+
/**
|
|
22
|
+
* Collapser with an icon rendered on the left side of the header.
|
|
23
|
+
* The icon prop accepts any React element — use your own icon component or SVG.
|
|
24
|
+
*/
|
|
25
|
+
export declare const WithIcon: Story;
|
|
26
|
+
/**
|
|
27
|
+
* Collapser with the title right-aligned within the header.
|
|
28
|
+
* Use this for design layouts where the title should appear on the right
|
|
29
|
+
* and content (such as a step number or icon) anchors the left.
|
|
30
|
+
*/
|
|
31
|
+
export declare const RightAligned: Story;
|
|
32
|
+
/**
|
|
33
|
+
* Collapser with both an icon and right-aligned title — matching the
|
|
34
|
+
* reference screenshot layout where an icon anchors the left and the
|
|
35
|
+
* title text flows to the right before the chevron.
|
|
36
|
+
*/
|
|
37
|
+
export declare const WithIconRightAligned: Story;
|
|
21
38
|
/**
|
|
22
39
|
* Collapser containing complex content.
|
|
23
40
|
*/
|
|
24
41
|
export declare const ComplexContent: Story;
|
|
42
|
+
/**
|
|
43
|
+
* Shows all four header layout variants side-by-side for visual comparison:
|
|
44
|
+
* default left-aligned, left-aligned with icon, right-aligned, and right-aligned with icon.
|
|
45
|
+
*/
|
|
46
|
+
export declare const AllVariants: Story;
|
|
25
47
|
/**
|
|
26
48
|
* Multiple collapsers in a FAQ-style layout using CollapserGroup.
|
|
27
49
|
*/
|
|
28
50
|
export declare const FAQExample: Story;
|
|
51
|
+
/**
|
|
52
|
+
* Example matching the reference screenshot: collapsers in a group where each
|
|
53
|
+
* has a distinct icon on the left and right-aligned title text.
|
|
54
|
+
*/
|
|
55
|
+
export declare const IconGroupExample: Story;
|
|
56
|
+
/**
|
|
57
|
+
* CollapserGroup with `numbered` auto-numbers each entry.
|
|
58
|
+
* Matches the reference screenshot pattern: step number + icon on the left,
|
|
59
|
+
* title right-aligned, chevron on the far right.
|
|
60
|
+
*/
|
|
61
|
+
export declare const NumberedGroup: Story;
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Collapser } from './Collapser';
|
|
3
3
|
import { CollapserGroup } from './CollapserGroup';
|
|
4
|
+
// Spoofed icon components for demonstration purposes
|
|
5
|
+
// (replace with your own Icon component when available)
|
|
6
|
+
var IconBook = function () { return (_jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [_jsx("path", { d: "M4 19.5A2.5 2.5 0 0 1 6.5 17H20" }), _jsx("path", { d: "M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z" })] })); };
|
|
7
|
+
var IconBolt = function () { return (_jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: _jsx("polyline", { points: "13 2 3 14 12 14 11 22 21 10 12 10 13 2" }) })); };
|
|
8
|
+
var IconStar = function () { return (_jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: _jsx("polygon", { points: "12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2" }) })); };
|
|
9
|
+
var IconSettings = function () { return (_jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [_jsx("circle", { cx: "12", cy: "12", r: "3" }), _jsx("path", { d: "M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z" })] })); };
|
|
4
10
|
/**
|
|
5
11
|
* The Collapser component creates expandable/collapsible content sections with smooth animations.
|
|
6
12
|
*/
|
|
@@ -22,6 +28,20 @@ var meta = {
|
|
|
22
28
|
description: 'Whether the collapser should be open by default (uncontrolled mode).',
|
|
23
29
|
table: { defaultValue: { summary: 'false' } },
|
|
24
30
|
},
|
|
31
|
+
align: {
|
|
32
|
+
control: 'radio',
|
|
33
|
+
options: ['left', 'right'],
|
|
34
|
+
description: "Alignment of the title within the header. Use 'right' for right-aligned titles, typically paired with an icon on the left.",
|
|
35
|
+
table: { defaultValue: { summary: 'left' } },
|
|
36
|
+
},
|
|
37
|
+
icon: {
|
|
38
|
+
control: false,
|
|
39
|
+
description: 'Optional icon or React element rendered on the left side of the header, before the title text.',
|
|
40
|
+
},
|
|
41
|
+
stepNumber: {
|
|
42
|
+
control: 'number',
|
|
43
|
+
description: 'Numeric step label shown on the far left. Auto-injected by `CollapserGroup` when `numbered` is true. Colour controlled via `--dds-collapser-step-number-color`.',
|
|
44
|
+
},
|
|
25
45
|
children: {
|
|
26
46
|
control: false,
|
|
27
47
|
description: 'Content to show/hide when toggling.',
|
|
@@ -35,7 +55,7 @@ var meta = {
|
|
|
35
55
|
parameters: {
|
|
36
56
|
docs: {
|
|
37
57
|
description: {
|
|
38
|
-
component: "\nThe Collapser component allows users to show and hide content sections to reduce visual clutter.\n\n## When to Use\n\n- For FAQ sections where answers can be toggled\n- To hide advanced options or detailed information\n- For progressive disclosure of content\n- When you have lengthy content that doesn't need to be visible all the time\n\n## When Not to Use\n\n- For primary navigation (use proper navigation components)\n- For critical information that should always be visible\n- When most users will need to expand all sections (just show the content)\n\n## Accessibility\n\n- Uses proper ARIA attributes (aria-expanded)\n- Keyboard accessible with Enter and Space keys\n- Supports additional keyboard shortcuts: 's' or 'f' to show, 'h' to hide\n- Screen reader friendly\n\n## Keyboard Shortcuts\n\n- **s** or **f**: Show/expand the content\n- **h**: Hide/collapse the content\n- **Enter** or **Space**: Toggle expand/collapse\n ",
|
|
58
|
+
component: "\nThe Collapser component allows users to show and hide content sections to reduce visual clutter.\n\n## When to Use\n\n- For FAQ sections where answers can be toggled\n- To hide advanced options or detailed information\n- For progressive disclosure of content\n- When you have lengthy content that doesn't need to be visible all the time\n\n## When Not to Use\n\n- For primary navigation (use proper navigation components)\n- For critical information that should always be visible\n- When most users will need to expand all sections (just show the content)\n\n## Accessibility\n\n- Uses proper ARIA attributes (aria-expanded)\n- Keyboard accessible with Enter and Space keys\n- Supports additional keyboard shortcuts: 's' or 'f' to show, 'h' to hide\n- Screen reader friendly\n- Icons passed via the `icon` prop should be wrapped in a container with `aria-hidden=\"true\"` since the title provides the accessible label\n\n## Keyboard Shortcuts\n\n- **s** or **f**: Show/expand the content\n- **h**: Hide/collapse the content\n- **Enter** or **Space**: Toggle expand/collapse\n\n## Customising Step Numbers\n\nOverride the CSS custom property to change the step number colour:\n\n```css\n.my-steps {\n --dds-collapser-step-number-color: #7c3aed;\n}\n```\n ",
|
|
39
59
|
},
|
|
40
60
|
},
|
|
41
61
|
},
|
|
@@ -91,6 +111,63 @@ export var WithID = {
|
|
|
91
111
|
},
|
|
92
112
|
},
|
|
93
113
|
};
|
|
114
|
+
/**
|
|
115
|
+
* Collapser with an icon rendered on the left side of the header.
|
|
116
|
+
* The icon prop accepts any React element — use your own icon component or SVG.
|
|
117
|
+
*/
|
|
118
|
+
export var WithIcon = {
|
|
119
|
+
args: {
|
|
120
|
+
title: 'Documentation guides',
|
|
121
|
+
icon: _jsx(IconBook, {}),
|
|
122
|
+
children: (_jsxs("p", { style: { color: 'var(--dds-collapser-text)' }, children: ["Icons help users quickly identify sections at a glance. Pass any React element to the ", _jsx("code", { children: "icon" }), " prop to display it on the left side of the header."] })),
|
|
123
|
+
},
|
|
124
|
+
parameters: {
|
|
125
|
+
docs: {
|
|
126
|
+
source: {
|
|
127
|
+
code: "<Collapser title=\"Documentation guides\" icon={<IconBook />}>\n <p>\n Icons help users quickly identify sections at a glance. Pass any React\n element to the icon prop to display it on the left side of the header.\n </p>\n</Collapser>",
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
/**
|
|
133
|
+
* Collapser with the title right-aligned within the header.
|
|
134
|
+
* Use this for design layouts where the title should appear on the right
|
|
135
|
+
* and content (such as a step number or icon) anchors the left.
|
|
136
|
+
*/
|
|
137
|
+
export var RightAligned = {
|
|
138
|
+
args: {
|
|
139
|
+
title: 'Right-aligned title',
|
|
140
|
+
align: 'right',
|
|
141
|
+
children: (_jsx("p", { style: { color: 'var(--dds-collapser-text)' }, children: "The title is right-aligned in the header, with the chevron remaining on the far right. Long titles will wrap to a new line on small screens rather than colliding with other elements." })),
|
|
142
|
+
},
|
|
143
|
+
parameters: {
|
|
144
|
+
docs: {
|
|
145
|
+
source: {
|
|
146
|
+
code: "<Collapser title=\"Right-aligned title\" align=\"right\">\n <p>\n The title is right-aligned in the header, with the chevron remaining on\n the far right.\n </p>\n</Collapser>",
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
/**
|
|
152
|
+
* Collapser with both an icon and right-aligned title — matching the
|
|
153
|
+
* reference screenshot layout where an icon anchors the left and the
|
|
154
|
+
* title text flows to the right before the chevron.
|
|
155
|
+
*/
|
|
156
|
+
export var WithIconRightAligned = {
|
|
157
|
+
args: {
|
|
158
|
+
title: 'Quick start guide',
|
|
159
|
+
align: 'right',
|
|
160
|
+
icon: _jsx(IconBolt, {}),
|
|
161
|
+
children: (_jsxs("p", { style: { color: 'var(--dds-collapser-text)' }, children: ["Combining ", _jsx("code", { children: "icon" }), " and ", _jsx("code", { children: "align=\"right\"" }), " produces a layout where the icon anchors the left edge, the title flows to the right, and the chevron stays at the far right."] })),
|
|
162
|
+
},
|
|
163
|
+
parameters: {
|
|
164
|
+
docs: {
|
|
165
|
+
source: {
|
|
166
|
+
code: "<Collapser title=\"Quick start guide\" align=\"right\" icon={<IconBolt />}>\n <p>\n Combining icon and align=\"right\" produces a layout where the icon anchors\n the left edge, the title flows to the right, and the chevron stays at the far right.\n </p>\n</Collapser>",
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
};
|
|
94
171
|
/**
|
|
95
172
|
* Collapser containing complex content.
|
|
96
173
|
*/
|
|
@@ -107,6 +184,20 @@ export var ComplexContent = {
|
|
|
107
184
|
},
|
|
108
185
|
},
|
|
109
186
|
};
|
|
187
|
+
/**
|
|
188
|
+
* Shows all four header layout variants side-by-side for visual comparison:
|
|
189
|
+
* default left-aligned, left-aligned with icon, right-aligned, and right-aligned with icon.
|
|
190
|
+
*/
|
|
191
|
+
export var AllVariants = {
|
|
192
|
+
parameters: {
|
|
193
|
+
docs: {
|
|
194
|
+
source: {
|
|
195
|
+
code: "{/* Left-aligned (default) */}\n<Collapser title=\"Left-aligned (default)\">\n <p>The standard layout \u2014 title on the left, chevron on the right.</p>\n</Collapser>\n\n{/* Left-aligned with icon */}\n<Collapser title=\"Left-aligned with icon\" icon={<IconBook />}>\n <p>An icon appears to the left of the title.</p>\n</Collapser>\n\n{/* Right-aligned */}\n<Collapser title=\"Right-aligned title\" align=\"right\">\n <p>Title text flows to the right. Chevron stays at the far right.</p>\n</Collapser>\n\n{/* Right-aligned with icon */}\n<Collapser title=\"Right-aligned with icon\" align=\"right\" icon={<IconBolt />}>\n <p>Icon anchors the left, title flows right, chevron at the far right.</p>\n</Collapser>",
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
render: function () { return (_jsxs("div", { children: [_jsx(Collapser, { title: "Left-aligned (default)", children: _jsx("p", { style: { color: 'var(--dds-collapser-text)' }, children: "The standard layout \u2014 title on the left, chevron on the right." }) }), _jsx(Collapser, { title: "Left-aligned with icon", icon: _jsx(IconBook, {}), children: _jsx("p", { style: { color: 'var(--dds-collapser-text)' }, children: "An icon appears to the left of the title." }) }), _jsx(Collapser, { title: "Right-aligned title", align: "right", children: _jsx("p", { style: { color: 'var(--dds-collapser-text)' }, children: "Title text flows to the right. Chevron stays at the far right." }) }), _jsx(Collapser, { title: "Right-aligned with icon", align: "right", icon: _jsx(IconBolt, {}), children: _jsx("p", { style: { color: 'var(--dds-collapser-text)' }, children: "Icon anchors the left, title flows right, chevron at the far right." }) })] })); },
|
|
200
|
+
};
|
|
110
201
|
/**
|
|
111
202
|
* Multiple collapsers in a FAQ-style layout using CollapserGroup.
|
|
112
203
|
*/
|
|
@@ -118,5 +209,34 @@ export var FAQExample = {
|
|
|
118
209
|
},
|
|
119
210
|
},
|
|
120
211
|
},
|
|
121
|
-
render: function () { return (_jsxs(CollapserGroup, { children: [_jsx(Collapser, { title: "What is this documentation system?", children: _jsx("p", { children: "This is a comprehensive documentation design system that provides reusable components and guidelines for creating effective technical documentation." }) }), _jsx(Collapser, { title: "How do I get started?", children: _jsx("p", { children: "Start by installing the component package, then explore the components in Storybook to understand their usage and configuration options." }) }), _jsx(Collapser, { title: "Can I customize the components?", children: _jsx("p", { children: "Yes! All components accept a className prop for custom styling, and you can override the default styles using CSS." }) }), _jsx(Collapser, { title: "Is this accessible?", children: _jsx("p", { children: "Accessibility is a core principle. All components follow WAI-ARIA best practices and are keyboard navigable." }) })] })); },
|
|
212
|
+
render: function () { return (_jsxs(CollapserGroup, { children: [_jsx(Collapser, { title: "What is this documentation system?", children: _jsx("p", { style: { color: 'var(--dds-collapser-text)' }, children: "This is a comprehensive documentation design system that provides reusable components and guidelines for creating effective technical documentation." }) }), _jsx(Collapser, { title: "How do I get started?", children: _jsx("p", { style: { color: 'var(--dds-collapser-text)' }, children: "Start by installing the component package, then explore the components in Storybook to understand their usage and configuration options." }) }), _jsx(Collapser, { title: "Can I customize the components?", children: _jsx("p", { style: { color: 'var(--dds-collapser-text)' }, children: "Yes! All components accept a className prop for custom styling, and you can override the default styles using CSS." }) }), _jsx(Collapser, { title: "Is this accessible?", children: _jsx("p", { style: { color: 'var(--dds-collapser-text)' }, children: "Accessibility is a core principle. All components follow WAI-ARIA best practices and are keyboard navigable." }) })] })); },
|
|
213
|
+
};
|
|
214
|
+
/**
|
|
215
|
+
* Example matching the reference screenshot: collapsers in a group where each
|
|
216
|
+
* has a distinct icon on the left and right-aligned title text.
|
|
217
|
+
*/
|
|
218
|
+
export var IconGroupExample = {
|
|
219
|
+
parameters: {
|
|
220
|
+
docs: {
|
|
221
|
+
source: {
|
|
222
|
+
code: "<CollapserGroup>\n <Collapser title=\"Getting started\" align=\"right\" icon={<IconBook />}>\n <p>Learn the basics and set up your environment.</p>\n </Collapser>\n <Collapser title=\"Quick actions\" align=\"right\" icon={<IconBolt />}>\n <p>Discover shortcuts and power-user features.</p>\n </Collapser>\n <Collapser title=\"Highlights\" align=\"right\" icon={<IconStar />}>\n <p>See what makes this system stand out.</p>\n </Collapser>\n <Collapser title=\"Configuration\" align=\"right\" icon={<IconSettings />}>\n <p>Customise the system to fit your workflow.</p>\n </Collapser>\n</CollapserGroup>",
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
render: function () { return (_jsxs(CollapserGroup, { children: [_jsx(Collapser, { title: "Getting started", align: "right", icon: _jsx(IconBook, {}), children: _jsx("p", { style: { color: 'var(--dds-collapser-text)' }, children: "Learn the basics and set up your environment." }) }), _jsx(Collapser, { title: "Quick actions", align: "right", icon: _jsx(IconBolt, {}), children: _jsx("p", { style: { color: 'var(--dds-collapser-text)' }, children: "Discover shortcuts and power-user features." }) }), _jsx(Collapser, { title: "Highlights", align: "right", icon: _jsx(IconStar, {}), children: _jsx("p", { style: { color: 'var(--dds-collapser-text)' }, children: "See what makes this system stand out." }) }), _jsx(Collapser, { title: "Configuration", align: "right", icon: _jsx(IconSettings, {}), children: _jsx("p", { style: { color: 'var(--dds-collapser-text)' }, children: "Customise the system to fit your workflow." }) })] })); },
|
|
227
|
+
};
|
|
228
|
+
/**
|
|
229
|
+
* CollapserGroup with `numbered` auto-numbers each entry.
|
|
230
|
+
* Matches the reference screenshot pattern: step number + icon on the left,
|
|
231
|
+
* title right-aligned, chevron on the far right.
|
|
232
|
+
*/
|
|
233
|
+
export var NumberedGroup = {
|
|
234
|
+
parameters: {
|
|
235
|
+
docs: {
|
|
236
|
+
source: {
|
|
237
|
+
code: "{/* numbered=true on CollapserGroup auto-injects stepNumber into each child */}\n<CollapserGroup numbered>\n <Collapser title=\"Decrease pain\" align=\"right\" icon={<IconBolt />}>\n <p>Step numbers are injected automatically by CollapserGroup.</p>\n </Collapser>\n <Collapser title=\"Align your workflow\" align=\"right\" icon={<IconBook />}>\n <p>Combine numbered with icons and right-aligned titles.</p>\n </Collapser>\n <Collapser title=\"Learn to move\" align=\"right\" icon={<IconStar />}>\n <p>Each entry gets a sequential step number on the far left.</p>\n </Collapser>\n <Collapser title=\"Configuration\" align=\"right\" icon={<IconSettings />}>\n <p>Customise the system to fit your workflow.</p>\n </Collapser>\n</CollapserGroup>",
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
render: function () { return (_jsxs(CollapserGroup, { numbered: true, children: [_jsx(Collapser, { title: "Decrease pain", align: "right", icon: _jsx(IconBolt, {}), children: _jsxs("p", { style: { color: 'var(--dds-collapser-text)' }, children: ["Step numbers are injected automatically by CollapserGroup when", ' ', _jsx("code", { children: "numbered" }), " is true."] }) }), _jsx(Collapser, { title: "Align your workflow", align: "right", icon: _jsx(IconBook, {}), children: _jsxs("p", { style: { color: 'var(--dds-collapser-text)' }, children: ["Combine ", _jsx("code", { children: "numbered" }), " with icons and right-aligned titles for a clean annotated-list layout."] }) }), _jsx(Collapser, { title: "Learn to move", align: "right", icon: _jsx(IconStar, {}), children: _jsx("p", { style: { color: 'var(--dds-collapser-text)' }, children: "Each entry gets a sequential step number on the far left." }) }), _jsx(Collapser, { title: "Configuration", align: "right", icon: _jsx(IconSettings, {}), children: _jsx("p", { style: { color: 'var(--dds-collapser-text)' }, children: "Customise the system to fit your workflow." }) })] })); },
|
|
122
242
|
};
|
|
@@ -11,5 +11,11 @@ export interface CollapserGroupProps {
|
|
|
11
11
|
onChange?: (openIndexes: number[]) => void;
|
|
12
12
|
/** Additional CSS classes */
|
|
13
13
|
className?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Automatically prefix each collapser header with a sequential step number (1, 2, 3…).
|
|
16
|
+
* The number is injected via the `stepNumber` prop on each `Collapser` child.
|
|
17
|
+
* @default false
|
|
18
|
+
*/
|
|
19
|
+
numbered?: boolean;
|
|
14
20
|
}
|
|
15
21
|
export declare const CollapserGroup: React.FC<CollapserGroupProps>;
|
|
@@ -23,12 +23,12 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
23
23
|
import { useState, Children, cloneElement, isValidElement } from 'react';
|
|
24
24
|
import { Collapser } from './Collapser';
|
|
25
25
|
export var CollapserGroup = function (_a) {
|
|
26
|
-
var children = _a.children, _b = _a.spacing, spacing = _b === void 0 ? '0.5rem' : _b, _c = _a.allowMultiple, allowMultiple = _c === void 0 ? true : _c, defaultOpen = _a.defaultOpen, onChange = _a.onChange, _d = _a.className, className = _d === void 0 ? '' : _d;
|
|
27
|
-
var
|
|
26
|
+
var children = _a.children, _b = _a.spacing, spacing = _b === void 0 ? '0.5rem' : _b, _c = _a.allowMultiple, allowMultiple = _c === void 0 ? true : _c, defaultOpen = _a.defaultOpen, onChange = _a.onChange, _d = _a.className, className = _d === void 0 ? '' : _d, _e = _a.numbered, numbered = _e === void 0 ? false : _e;
|
|
27
|
+
var _f = useState(function () {
|
|
28
28
|
if (defaultOpen === undefined)
|
|
29
29
|
return [];
|
|
30
30
|
return Array.isArray(defaultOpen) ? defaultOpen : [defaultOpen];
|
|
31
|
-
}), openIndexes =
|
|
31
|
+
}), openIndexes = _f[0], setOpenIndexes = _f[1];
|
|
32
32
|
var handleToggle = function (index) {
|
|
33
33
|
setOpenIndexes(function (prev) {
|
|
34
34
|
var next;
|
|
@@ -49,7 +49,7 @@ export var CollapserGroup = function (_a) {
|
|
|
49
49
|
return child;
|
|
50
50
|
// Only inject props if child is a Collapser component
|
|
51
51
|
if (child.type === Collapser) {
|
|
52
|
-
return cloneElement(child, __assign(__assign({}, child.props), { open: openIndexes.includes(index), onToggle: function () { return handleToggle(index); } }));
|
|
52
|
+
return cloneElement(child, __assign(__assign(__assign({}, child.props), { open: openIndexes.includes(index), onToggle: function () { return handleToggle(index); } }), (numbered ? { stepNumber: index + 1 } : {})));
|
|
53
53
|
}
|
|
54
54
|
return child;
|
|
55
55
|
}) }));
|
|
@@ -27,3 +27,10 @@ export declare const DefaultOpen: Story;
|
|
|
27
27
|
* Multiple collapsers open by default.
|
|
28
28
|
*/
|
|
29
29
|
export declare const MultipleDefaultOpen: Story;
|
|
30
|
+
/**
|
|
31
|
+
* Setting `numbered` on CollapserGroup automatically prefixes each collapser header
|
|
32
|
+
* with a sequential step number (1., 2., …), closely matching the reference screenshot
|
|
33
|
+
* with number + icon on the left and right-aligned title text.
|
|
34
|
+
* Customise the number colour with `--dds-collapser-step-number-color`.
|
|
35
|
+
*/
|
|
36
|
+
export declare const NumberedGroup: Story;
|
|
@@ -12,6 +12,11 @@ var __assign = (this && this.__assign) || function () {
|
|
|
12
12
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
13
|
import { CollapserGroup } from './CollapserGroup';
|
|
14
14
|
import { Collapser } from './Collapser';
|
|
15
|
+
// Spoofed icons for the NumberedGroup story (replace with your Icon component when available)
|
|
16
|
+
var IconBolt = function () { return (_jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: _jsx("polyline", { points: "13 2 3 14 12 14 11 22 21 10 12 10 13 2" }) })); };
|
|
17
|
+
var IconBook = function () { return (_jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [_jsx("path", { d: "M4 19.5A2.5 2.5 0 0 1 6.5 17H20" }), _jsx("path", { d: "M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z" })] })); };
|
|
18
|
+
var IconStar = function () { return (_jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: _jsx("polygon", { points: "12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2" }) })); };
|
|
19
|
+
var IconSettings = function () { return (_jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [_jsx("circle", { cx: "12", cy: "12", r: "3" }), _jsx("path", { d: "M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z" })] })); };
|
|
15
20
|
/**
|
|
16
21
|
* CollapserGroup manages multiple Collapser components with consistent spacing
|
|
17
22
|
* and optional accordion behavior.
|
|
@@ -48,6 +53,11 @@ var meta = {
|
|
|
48
53
|
description: 'Additional CSS classes.',
|
|
49
54
|
table: { defaultValue: { summary: '""' } },
|
|
50
55
|
},
|
|
56
|
+
numbered: {
|
|
57
|
+
control: 'boolean',
|
|
58
|
+
description: 'Automatically prefix each collapser header with a sequential step number (1, 2, 3…). Pairs well with `icon` and `align="right"` on child collapsers.',
|
|
59
|
+
table: { defaultValue: { summary: 'false' } },
|
|
60
|
+
},
|
|
51
61
|
},
|
|
52
62
|
parameters: {
|
|
53
63
|
docs: {
|
|
@@ -139,3 +149,22 @@ export var MultipleDefaultOpen = {
|
|
|
139
149
|
},
|
|
140
150
|
render: function (args) { return (_jsxs(CollapserGroup, __assign({}, args, { children: [_jsx(Collapser, { title: "Introduction", children: _jsx("p", { children: "This section is open by default." }) }), _jsx(Collapser, { title: "Installation", children: _jsx("p", { children: "This section starts closed." }) }), _jsx(Collapser, { title: "Quick Start", children: _jsx("p", { children: "This section is also open by default." }) })] }))); },
|
|
141
151
|
};
|
|
152
|
+
/**
|
|
153
|
+
* Setting `numbered` on CollapserGroup automatically prefixes each collapser header
|
|
154
|
+
* with a sequential step number (1., 2., …), closely matching the reference screenshot
|
|
155
|
+
* with number + icon on the left and right-aligned title text.
|
|
156
|
+
* Customise the number colour with `--dds-collapser-step-number-color`.
|
|
157
|
+
*/
|
|
158
|
+
export var NumberedGroup = {
|
|
159
|
+
args: {
|
|
160
|
+
numbered: true,
|
|
161
|
+
},
|
|
162
|
+
parameters: {
|
|
163
|
+
docs: {
|
|
164
|
+
source: {
|
|
165
|
+
code: "<CollapserGroup numbered>\n <Collapser title=\"Decrease pain\" align=\"right\" icon={<IconBolt />}>\n <p>Step numbers are injected automatically \u2014 no extra props needed on each item.</p>\n </Collapser>\n <Collapser title=\"Align your workflow\" align=\"right\" icon={<IconBook />}>\n <p>Combine numbered with icons and right-aligned titles.</p>\n </Collapser>\n <Collapser title=\"Learn to move\" align=\"right\" icon={<IconStar />}>\n <p>Each entry gets a sequential step number on the far left.</p>\n </Collapser>\n <Collapser title=\"Build strength\" align=\"right\" icon={<IconSettings />}>\n <p>Customise the number colour with --dds-collapser-step-number-color.</p>\n </Collapser>\n</CollapserGroup>",
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
render: function (args) { return (_jsxs(CollapserGroup, __assign({}, args, { children: [_jsx(Collapser, { title: "Decrease pain", align: "right", icon: _jsx(IconBolt, {}), children: _jsx("p", { style: { color: 'var(--dds-collapser-text)' }, children: "Step numbers are injected automatically \u2014 no extra props needed on each item." }) }), _jsx(Collapser, { title: "Align your workflow", align: "right", icon: _jsx(IconBook, {}), children: _jsxs("p", { style: { color: 'var(--dds-collapser-text)' }, children: ["Combine ", _jsx("code", { children: "numbered" }), " with icons and right-aligned titles for a clean annotated-list layout."] }) }), _jsx(Collapser, { title: "Learn to move", align: "right", icon: _jsx(IconStar, {}), children: _jsx("p", { style: { color: 'var(--dds-collapser-text)' }, children: "Each entry gets a sequential step number on the far left." }) }), _jsx(Collapser, { title: "Build strength", align: "right", icon: _jsx(IconSettings, {}), children: _jsxs("p", { style: { color: 'var(--dds-collapser-text)' }, children: ["Customise the number colour with ", _jsx("code", { children: "--dds-collapser-step-number-color" }), "."] }) })] }))); },
|
|
170
|
+
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
/** Breakpoint at which columns stack vertically */
|
|
3
|
+
type StackAt = 'sm' | 'md' | 'lg' | 'never';
|
|
4
|
+
/** Vertical alignment of column content */
|
|
5
|
+
type AlignItems = 'start' | 'center' | 'end' | 'stretch';
|
|
6
|
+
/** Configuration for a border or divider line */
|
|
7
|
+
export interface BorderConfig {
|
|
8
|
+
/**
|
|
9
|
+
* Line thickness in pixels
|
|
10
|
+
* @default 1
|
|
11
|
+
*/
|
|
12
|
+
thickness?: number;
|
|
13
|
+
/** Line color (defaults to the `--dds-grid-divider-color` token) */
|
|
14
|
+
color?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface GridProps {
|
|
17
|
+
/**
|
|
18
|
+
* Number of equal columns, or an array of fractional widths
|
|
19
|
+
* (e.g. `[1, 2]` for a 1/3 + 2/3 split).
|
|
20
|
+
* @default 2
|
|
21
|
+
*/
|
|
22
|
+
columns?: number | number[];
|
|
23
|
+
/**
|
|
24
|
+
* Space between columns. Use `'sm'`, `'md'`, or `'lg'` for design-token sizes,
|
|
25
|
+
* or any valid CSS length string (e.g. `'16px'`, `'1.5rem'`, `'2em'`).
|
|
26
|
+
* @default 'md'
|
|
27
|
+
*/
|
|
28
|
+
gap?: string;
|
|
29
|
+
/**
|
|
30
|
+
* Viewport breakpoint at which columns collapse to a single vertical stack.
|
|
31
|
+
* @default 'md'
|
|
32
|
+
*/
|
|
33
|
+
stackAt?: StackAt;
|
|
34
|
+
/**
|
|
35
|
+
* Vertical dividing line drawn between columns.
|
|
36
|
+
* Converts to a horizontal rule when the layout stacks.
|
|
37
|
+
*/
|
|
38
|
+
columnDivider?: BorderConfig;
|
|
39
|
+
/** Horizontal rule rendered above the grid. */
|
|
40
|
+
topBorder?: BorderConfig;
|
|
41
|
+
/** Horizontal rule rendered below the grid. */
|
|
42
|
+
bottomBorder?: BorderConfig;
|
|
43
|
+
/**
|
|
44
|
+
* Vertical alignment of content within each column.
|
|
45
|
+
* @default 'stretch'
|
|
46
|
+
*/
|
|
47
|
+
align?: AlignItems;
|
|
48
|
+
/** Background color applied to the grid container. */
|
|
49
|
+
backgroundColor?: string;
|
|
50
|
+
/** Additional CSS classes applied to the grid wrapper. */
|
|
51
|
+
className?: string;
|
|
52
|
+
children: ReactNode;
|
|
53
|
+
}
|
|
54
|
+
export interface ColumnProps {
|
|
55
|
+
/**
|
|
56
|
+
* How many grid columns this item should span.
|
|
57
|
+
* @default 1
|
|
58
|
+
*/
|
|
59
|
+
span?: number;
|
|
60
|
+
/**
|
|
61
|
+
* Makes the column content sticky (`position: sticky; top: …`) while adjacent columns scroll.
|
|
62
|
+
* Useful for tutorial-style layouts with a persistent code panel.
|
|
63
|
+
* Automatically disabled when the grid stacks on mobile.
|
|
64
|
+
* @default false
|
|
65
|
+
*/
|
|
66
|
+
sticky?: boolean;
|
|
67
|
+
/** Background color applied to the column. */
|
|
68
|
+
backgroundColor?: string;
|
|
69
|
+
/** Additional CSS classes applied to the column wrapper. */
|
|
70
|
+
className?: string;
|
|
71
|
+
children: ReactNode;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Multi-column layout container for documentation pages.
|
|
75
|
+
* Supports equal and fractional column splits, configurable responsive stacking,
|
|
76
|
+
* optional column dividers, top/bottom borders, and background colours.
|
|
77
|
+
*
|
|
78
|
+
* Pair with `<Column>` children to control individual column behaviour.
|
|
79
|
+
*/
|
|
80
|
+
export declare function Grid({ columns, gap, stackAt, columnDivider, topBorder, bottomBorder, align, backgroundColor, className, children, }: GridProps): import("react/jsx-runtime").JSX.Element;
|
|
81
|
+
/**
|
|
82
|
+
* An individual column within a `<Grid>`.
|
|
83
|
+
*
|
|
84
|
+
* Use the `span` prop to make a column occupy more than one grid track, and
|
|
85
|
+
* `sticky` to keep the column content pinned while adjacent content scrolls.
|
|
86
|
+
* The column element itself always stretches to the full row height so that
|
|
87
|
+
* column dividers cover the entire row regardless of which column is taller.
|
|
88
|
+
*/
|
|
89
|
+
export declare function Column({ span, sticky, backgroundColor, className, children, }: ColumnProps): import("react/jsx-runtime").JSX.Element;
|
|
90
|
+
export {};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
var __assign = (this && this.__assign) || function () {
|
|
2
|
+
__assign = Object.assign || function(t) {
|
|
3
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
4
|
+
s = arguments[i];
|
|
5
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
6
|
+
t[p] = s[p];
|
|
7
|
+
}
|
|
8
|
+
return t;
|
|
9
|
+
};
|
|
10
|
+
return __assign.apply(this, arguments);
|
|
11
|
+
};
|
|
12
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
13
|
+
var GAP_TOKEN_MAP = {
|
|
14
|
+
sm: 'var(--dds-grid-gap-sm)',
|
|
15
|
+
md: 'var(--dds-grid-gap-md)',
|
|
16
|
+
lg: 'var(--dds-grid-gap-lg)',
|
|
17
|
+
};
|
|
18
|
+
var ALIGN_MAP = {
|
|
19
|
+
start: 'start',
|
|
20
|
+
center: 'center',
|
|
21
|
+
end: 'end',
|
|
22
|
+
stretch: 'stretch',
|
|
23
|
+
};
|
|
24
|
+
function resolveGap(gap) {
|
|
25
|
+
if (gap in GAP_TOKEN_MAP)
|
|
26
|
+
return GAP_TOKEN_MAP[gap];
|
|
27
|
+
return gap; // custom CSS length string, e.g. '16px', '1.5rem', '2em'
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Multi-column layout container for documentation pages.
|
|
31
|
+
* Supports equal and fractional column splits, configurable responsive stacking,
|
|
32
|
+
* optional column dividers, top/bottom borders, and background colours.
|
|
33
|
+
*
|
|
34
|
+
* Pair with `<Column>` children to control individual column behaviour.
|
|
35
|
+
*/
|
|
36
|
+
export function Grid(_a) {
|
|
37
|
+
var _b, _c, _d, _e, _f, _g;
|
|
38
|
+
var _h = _a.columns, columns = _h === void 0 ? 2 : _h, _j = _a.gap, gap = _j === void 0 ? 'md' : _j, _k = _a.stackAt, stackAt = _k === void 0 ? 'md' : _k, columnDivider = _a.columnDivider, topBorder = _a.topBorder, bottomBorder = _a.bottomBorder, _l = _a.align, align = _l === void 0 ? 'stretch' : _l, backgroundColor = _a.backgroundColor, _m = _a.className, className = _m === void 0 ? '' : _m, children = _a.children;
|
|
39
|
+
var columnTemplate = Array.isArray(columns)
|
|
40
|
+
? columns.map(function (n) { return "".concat(n, "fr"); }).join(' ')
|
|
41
|
+
: "repeat(".concat(columns, ", 1fr)");
|
|
42
|
+
var style = __assign(__assign(__assign(__assign({ '--dds-grid-template-columns': columnTemplate, '--dds-grid-gap': resolveGap(gap), '--dds-grid-align': ALIGN_MAP[align] }, (backgroundColor ? { backgroundColor: backgroundColor } : {})), (topBorder
|
|
43
|
+
? {
|
|
44
|
+
'--dds-grid-top-border-thickness': "".concat((_b = topBorder.thickness) !== null && _b !== void 0 ? _b : 1, "px"),
|
|
45
|
+
'--dds-grid-top-border-color': (_c = topBorder.color) !== null && _c !== void 0 ? _c : 'var(--dds-grid-divider-color)',
|
|
46
|
+
}
|
|
47
|
+
: {})), (bottomBorder
|
|
48
|
+
? {
|
|
49
|
+
'--dds-grid-bottom-border-thickness': "".concat((_d = bottomBorder.thickness) !== null && _d !== void 0 ? _d : 1, "px"),
|
|
50
|
+
'--dds-grid-bottom-border-color': (_e = bottomBorder.color) !== null && _e !== void 0 ? _e : 'var(--dds-grid-divider-color)',
|
|
51
|
+
}
|
|
52
|
+
: {})), (columnDivider
|
|
53
|
+
? {
|
|
54
|
+
'--dds-grid-column-divider-thickness': "".concat((_f = columnDivider.thickness) !== null && _f !== void 0 ? _f : 1, "px"),
|
|
55
|
+
'--dds-grid-column-divider-color': (_g = columnDivider.color) !== null && _g !== void 0 ? _g : 'var(--dds-grid-divider-color)',
|
|
56
|
+
}
|
|
57
|
+
: {}));
|
|
58
|
+
var classNames = [
|
|
59
|
+
'dds-grid',
|
|
60
|
+
"dds-grid-stack-".concat(stackAt),
|
|
61
|
+
topBorder ? 'dds-grid-has-top-border' : '',
|
|
62
|
+
bottomBorder ? 'dds-grid-has-bottom-border' : '',
|
|
63
|
+
columnDivider ? 'dds-grid-has-column-divider' : '',
|
|
64
|
+
className,
|
|
65
|
+
]
|
|
66
|
+
.filter(Boolean)
|
|
67
|
+
.join(' ');
|
|
68
|
+
return (_jsx("div", { className: classNames, style: style, children: children }));
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* An individual column within a `<Grid>`.
|
|
72
|
+
*
|
|
73
|
+
* Use the `span` prop to make a column occupy more than one grid track, and
|
|
74
|
+
* `sticky` to keep the column content pinned while adjacent content scrolls.
|
|
75
|
+
* The column element itself always stretches to the full row height so that
|
|
76
|
+
* column dividers cover the entire row regardless of which column is taller.
|
|
77
|
+
*/
|
|
78
|
+
export function Column(_a) {
|
|
79
|
+
var span = _a.span, _b = _a.sticky, sticky = _b === void 0 ? false : _b, backgroundColor = _a.backgroundColor, _c = _a.className, className = _c === void 0 ? '' : _c, children = _a.children;
|
|
80
|
+
var style = {};
|
|
81
|
+
if (span && span > 1) {
|
|
82
|
+
style.gridColumn = "span ".concat(span);
|
|
83
|
+
}
|
|
84
|
+
if (backgroundColor) {
|
|
85
|
+
style.backgroundColor = backgroundColor;
|
|
86
|
+
}
|
|
87
|
+
var classNames = [
|
|
88
|
+
'dds-grid-column',
|
|
89
|
+
sticky ? 'dds-grid-column-sticky' : '',
|
|
90
|
+
className,
|
|
91
|
+
]
|
|
92
|
+
.filter(Boolean)
|
|
93
|
+
.join(' ');
|
|
94
|
+
return (_jsx("div", { className: classNames, style: style, children: sticky ? (_jsx("div", { className: "dds-grid-column-sticky-inner", children: children })) : (children) }));
|
|
95
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { Grid } from './Grid';
|
|
3
|
+
/**
|
|
4
|
+
* `Grid` and `Column` provide a flexible multi-column layout for documentation pages.
|
|
5
|
+
* Common patterns include side-by-side comparisons, image + annotation, and
|
|
6
|
+
* tutorial-style instruction / code pairings.
|
|
7
|
+
*/
|
|
8
|
+
declare const meta: Meta<typeof Grid>;
|
|
9
|
+
export default meta;
|
|
10
|
+
type Story = StoryObj<typeof Grid>;
|
|
11
|
+
/**
|
|
12
|
+
* Fully interactive default story — all controls in the prop table affect this
|
|
13
|
+
* live preview. Adjust `columns`, `gap`, `stackAt`, `align`, `columnDivider`,
|
|
14
|
+
* `topBorder`, `bottomBorder`, and `backgroundColor` via the Controls panel.
|
|
15
|
+
*/
|
|
16
|
+
export declare const Default: Story;
|
|
17
|
+
/**
|
|
18
|
+
* Two equal columns — the default layout. Columns stack vertically at the `md`
|
|
19
|
+
* breakpoint (768 px) by default.
|
|
20
|
+
*/
|
|
21
|
+
export declare const TwoEqualColumns: Story;
|
|
22
|
+
/**
|
|
23
|
+
* Three equal columns, with a top and bottom border to create a contained
|
|
24
|
+
* "feature grid" panel. Useful for listing icons with short descriptions.
|
|
25
|
+
*/
|
|
26
|
+
export declare const ThreeColumnFeatureGrid: Story;
|
|
27
|
+
/**
|
|
28
|
+
* Asymmetric 1/3 + 2/3 split — pass an array of fractional weights.
|
|
29
|
+
* A common pattern for a narrow label / sidebar alongside wide content.
|
|
30
|
+
*/
|
|
31
|
+
export declare const AsymmetricSplit: Story;
|
|
32
|
+
/**
|
|
33
|
+
* Image + annotation layout. `align="center"` vertically centres the shorter
|
|
34
|
+
* column when image and text have different heights.
|
|
35
|
+
*/
|
|
36
|
+
export declare const ImageAndText: Story;
|
|
37
|
+
/**
|
|
38
|
+
* Tutorial layout — prose instructions on the left, sticky code panel on the
|
|
39
|
+
* right. The code panel stays in view while the user scrolls through the steps.
|
|
40
|
+
* The column divider runs the full height of the row regardless of which column
|
|
41
|
+
* is taller. The `sticky` prop is automatically disabled when the grid stacks.
|
|
42
|
+
*/
|
|
43
|
+
export declare const TutorialWithStickyCode: Story;
|
|
44
|
+
/**
|
|
45
|
+
* Column dividers — a vertical line between columns that converts to a
|
|
46
|
+
* horizontal rule at the stacking breakpoint.
|
|
47
|
+
*/
|
|
48
|
+
export declare const WithColumnDivider: Story;
|
|
49
|
+
/**
|
|
50
|
+
* Background colors — apply a background to the entire grid and / or to
|
|
51
|
+
* individual columns using the `backgroundColor` prop.
|
|
52
|
+
*/
|
|
53
|
+
export declare const BackgroundColors: Story;
|
|
54
|
+
/**
|
|
55
|
+
* Large gap between columns — useful when columns contain rich content
|
|
56
|
+
* that needs extra breathing room.
|
|
57
|
+
*/
|
|
58
|
+
export declare const LargeGap: Story;
|
|
59
|
+
/**
|
|
60
|
+
* Custom gap — pass any CSS length string such as `'1.5rem'` or `'40px'`
|
|
61
|
+
* for fine-grained control beyond the named size tokens.
|
|
62
|
+
*/
|
|
63
|
+
export declare const CustomGap: Story;
|
|
64
|
+
/**
|
|
65
|
+
* Span — a column set to `span={2}` occupies two grid tracks.
|
|
66
|
+
* Useful for full-width content (e.g. a summary row) inside an otherwise
|
|
67
|
+
* multi-column grid.
|
|
68
|
+
*/
|
|
69
|
+
export declare const ColumnSpan: Story;
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
var __assign = (this && this.__assign) || function () {
|
|
2
|
+
__assign = Object.assign || function(t) {
|
|
3
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
4
|
+
s = arguments[i];
|
|
5
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
6
|
+
t[p] = s[p];
|
|
7
|
+
}
|
|
8
|
+
return t;
|
|
9
|
+
};
|
|
10
|
+
return __assign.apply(this, arguments);
|
|
11
|
+
};
|
|
12
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
|
+
import { Grid } from './Grid';
|
|
14
|
+
import { Column } from './Grid';
|
|
15
|
+
import { CodeBlock } from './CodeBlock';
|
|
16
|
+
/**
|
|
17
|
+
* `Grid` and `Column` provide a flexible multi-column layout for documentation pages.
|
|
18
|
+
* Common patterns include side-by-side comparisons, image + annotation, and
|
|
19
|
+
* tutorial-style instruction / code pairings.
|
|
20
|
+
*/
|
|
21
|
+
var meta = {
|
|
22
|
+
title: 'Components/Grid',
|
|
23
|
+
component: Grid,
|
|
24
|
+
tags: ['autodocs'],
|
|
25
|
+
argTypes: {
|
|
26
|
+
columns: {
|
|
27
|
+
control: { type: 'object' },
|
|
28
|
+
description: 'Number of equal columns, or an array of fractional weights for asymmetric splits (e.g. `[1, 2]` → 1/3 + 2/3). Enter a number or a JSON array in the control.',
|
|
29
|
+
table: { defaultValue: { summary: '2' } },
|
|
30
|
+
},
|
|
31
|
+
gap: {
|
|
32
|
+
control: { type: 'select' },
|
|
33
|
+
options: ['sm', 'md', 'lg', '0.5rem', '1rem', '1.5rem', '2rem', '3rem', '8px', '16px', '24px', '32px'],
|
|
34
|
+
description: "Space between columns. Use `'sm'`, `'md'`, or `'lg'` for design-token sizes, or any CSS length string (e.g. `'16px'`, `'1.5rem'`).",
|
|
35
|
+
table: { defaultValue: { summary: "'md'" } },
|
|
36
|
+
},
|
|
37
|
+
stackAt: {
|
|
38
|
+
control: { type: 'select' },
|
|
39
|
+
options: ['sm', 'md', 'lg', 'never'],
|
|
40
|
+
description: 'Breakpoint at which columns collapse to a single vertical stack.',
|
|
41
|
+
table: { defaultValue: { summary: "'md'" } },
|
|
42
|
+
},
|
|
43
|
+
align: {
|
|
44
|
+
control: { type: 'select' },
|
|
45
|
+
options: ['start', 'center', 'end', 'stretch'],
|
|
46
|
+
description: 'Vertical alignment of content within each column.',
|
|
47
|
+
table: { defaultValue: { summary: "'stretch'" } },
|
|
48
|
+
},
|
|
49
|
+
columnDivider: {
|
|
50
|
+
control: { type: 'object' },
|
|
51
|
+
description: 'Vertical line between columns (`{ thickness?: number; color?: string }`). Converts to a horizontal rule when stacked.',
|
|
52
|
+
},
|
|
53
|
+
topBorder: {
|
|
54
|
+
control: { type: 'object' },
|
|
55
|
+
description: 'Horizontal rule above the grid (`{ thickness?: number; color?: string }`).',
|
|
56
|
+
},
|
|
57
|
+
bottomBorder: {
|
|
58
|
+
control: { type: 'object' },
|
|
59
|
+
description: 'Horizontal rule below the grid (`{ thickness?: number; color?: string }`).',
|
|
60
|
+
},
|
|
61
|
+
backgroundColor: {
|
|
62
|
+
control: 'color',
|
|
63
|
+
description: 'Background color for the entire grid container.',
|
|
64
|
+
},
|
|
65
|
+
className: {
|
|
66
|
+
control: 'text',
|
|
67
|
+
description: 'Additional CSS classes applied to the grid wrapper.',
|
|
68
|
+
table: { defaultValue: { summary: '""' } },
|
|
69
|
+
},
|
|
70
|
+
children: {
|
|
71
|
+
control: false,
|
|
72
|
+
description: 'Grid content — typically `Column` components.',
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
parameters: {
|
|
76
|
+
docs: {
|
|
77
|
+
description: {
|
|
78
|
+
component: "\nLayout primitive for multi-column documentation content.\n\n## When to Use\n\n- **Image + annotation** \u2014 screenshot or diagram on one side, feature callouts on the other\n- **Tutorial / live demo** \u2014 prose instructions on one side, sticky code panel on the other\n- **Side-by-side comparison** \u2014 before/after, two approaches, or option A vs option B\n- **Feature grid** \u2014 icon + short description repeated across columns\n\n## When Not to Use\n\n- For card-style repeating items of the same type \u2014 use `CardGrid` instead\n- For a single column of content \u2014 use standard block-level markup\n\n## Accessibility\n\n- Rendered as a semantic `<div>`; no implicit ARIA role (not a data table)\n- Source order should match reading order; avoid visual reordering via CSS `order`\n- Column dividers are decorative and carry no meaning for assistive technology\n ",
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
export default meta;
|
|
84
|
+
/* -------------------------------------------------------------------------- */
|
|
85
|
+
/* Helpers */
|
|
86
|
+
/* -------------------------------------------------------------------------- */
|
|
87
|
+
var textColor = { color: 'var(--dds-tabs-panel-text)' };
|
|
88
|
+
var subtle = { color: 'var(--dds-tabs-panel-text)', fontFamily: 'sans-serif', margin: 0 };
|
|
89
|
+
function Placeholder(_a) {
|
|
90
|
+
var label = _a.label, _b = _a.height, height = _b === void 0 ? 120 : _b, _c = _a.bg, bg = _c === void 0 ? 'rgba(99,102,241,0.1)' : _c;
|
|
91
|
+
return (_jsx("div", { style: __assign(__assign({ display: 'flex', alignItems: 'center', justifyContent: 'center', height: height, background: bg, borderRadius: 6 }, textColor), { fontFamily: 'sans-serif', fontWeight: 600, fontSize: '0.875rem' }), children: label }));
|
|
92
|
+
}
|
|
93
|
+
/* -------------------------------------------------------------------------- */
|
|
94
|
+
/* Stories */
|
|
95
|
+
/* -------------------------------------------------------------------------- */
|
|
96
|
+
/**
|
|
97
|
+
* Fully interactive default story — all controls in the prop table affect this
|
|
98
|
+
* live preview. Adjust `columns`, `gap`, `stackAt`, `align`, `columnDivider`,
|
|
99
|
+
* `topBorder`, `bottomBorder`, and `backgroundColor` via the Controls panel.
|
|
100
|
+
*/
|
|
101
|
+
export var Default = {
|
|
102
|
+
args: {
|
|
103
|
+
columns: 2,
|
|
104
|
+
gap: 'md',
|
|
105
|
+
stackAt: 'md',
|
|
106
|
+
align: 'stretch',
|
|
107
|
+
},
|
|
108
|
+
render: function (args) { return (_jsxs(Grid, __assign({}, args, { children: [_jsx(Column, { children: _jsx(Placeholder, { label: "Column 1" }) }), _jsx(Column, { children: _jsx(Placeholder, { label: "Column 2" }) })] }))); },
|
|
109
|
+
parameters: {
|
|
110
|
+
docs: {
|
|
111
|
+
source: {
|
|
112
|
+
code: "<Grid columns={2} gap=\"md\">\n <Column>Column 1 content</Column>\n <Column>Column 2 content</Column>\n</Grid>",
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
/**
|
|
118
|
+
* Two equal columns — the default layout. Columns stack vertically at the `md`
|
|
119
|
+
* breakpoint (768 px) by default.
|
|
120
|
+
*/
|
|
121
|
+
export var TwoEqualColumns = {
|
|
122
|
+
render: function () { return (_jsxs(Grid, { columns: 2, children: [_jsx(Column, { children: _jsx(Placeholder, { label: "Column 1" }) }), _jsx(Column, { children: _jsx(Placeholder, { label: "Column 2" }) })] })); },
|
|
123
|
+
parameters: {
|
|
124
|
+
docs: {
|
|
125
|
+
source: {
|
|
126
|
+
code: "<Grid columns={2}>\n <Column>Column 1 content</Column>\n <Column>Column 2 content</Column>\n</Grid>",
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
/**
|
|
132
|
+
* Three equal columns, with a top and bottom border to create a contained
|
|
133
|
+
* "feature grid" panel. Useful for listing icons with short descriptions.
|
|
134
|
+
*/
|
|
135
|
+
export var ThreeColumnFeatureGrid = {
|
|
136
|
+
render: function () { return (_jsxs(Grid, { columns: 3, gap: "md", topBorder: { color: 'var(--dds-grid-divider-color)' }, bottomBorder: { color: 'var(--dds-grid-divider-color)' }, children: [_jsx(Column, { children: _jsxs("p", { style: subtle, children: [_jsx("strong", { children: "Feature A" }), _jsx("br", {}), "Short description of the feature."] }) }), _jsx(Column, { children: _jsxs("p", { style: subtle, children: [_jsx("strong", { children: "Feature B" }), _jsx("br", {}), "Short description of the feature."] }) }), _jsx(Column, { children: _jsxs("p", { style: subtle, children: [_jsx("strong", { children: "Feature C" }), _jsx("br", {}), "Short description of the feature."] }) })] })); },
|
|
137
|
+
parameters: {
|
|
138
|
+
docs: {
|
|
139
|
+
source: {
|
|
140
|
+
code: "<Grid\n columns={3}\n gap=\"md\"\n topBorder={{ color: '#ccc' }}\n bottomBorder={{ color: '#ccc' }}\n>\n <Column><strong>Feature A</strong> \u2014 Short description.</Column>\n <Column><strong>Feature B</strong> \u2014 Short description.</Column>\n <Column><strong>Feature C</strong> \u2014 Short description.</Column>\n</Grid>",
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
/**
|
|
146
|
+
* Asymmetric 1/3 + 2/3 split — pass an array of fractional weights.
|
|
147
|
+
* A common pattern for a narrow label / sidebar alongside wide content.
|
|
148
|
+
*/
|
|
149
|
+
export var AsymmetricSplit = {
|
|
150
|
+
render: function () { return (_jsxs(Grid, { columns: [1, 2], children: [_jsx(Column, { children: _jsx(Placeholder, { label: "1 / 3", height: 160, bg: "rgba(16,185,129,0.1)" }) }), _jsx(Column, { children: _jsx(Placeholder, { label: "2 / 3", height: 160, bg: "rgba(99,102,241,0.1)" }) })] })); },
|
|
151
|
+
parameters: {
|
|
152
|
+
docs: {
|
|
153
|
+
source: {
|
|
154
|
+
code: "<Grid columns={[1, 2]}>\n <Column>Narrow (1/3)</Column>\n <Column>Wide (2/3)</Column>\n</Grid>",
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
};
|
|
159
|
+
/**
|
|
160
|
+
* Image + annotation layout. `align="center"` vertically centres the shorter
|
|
161
|
+
* column when image and text have different heights.
|
|
162
|
+
*/
|
|
163
|
+
export var ImageAndText = {
|
|
164
|
+
render: function () { return (_jsxs(Grid, { columns: [1, 2], align: "center", columnDivider: { color: 'var(--dds-grid-divider-color)' }, children: [_jsx(Column, { children: _jsx(Placeholder, { label: "Diagram / Screenshot", height: 200, bg: "rgba(234,179,8,0.1)" }) }), _jsxs(Column, { children: [_jsx("p", { style: __assign(__assign({}, subtle), { marginBottom: '0.5rem' }), children: _jsx("strong", { children: "What you're looking at" }) }), _jsxs("p", { style: subtle, children: ["This panel describes the key elements of the diagram on the left. Use ", _jsx("code", { children: "align=\"center\"" }), " so short text stays vertically centred next to a taller image."] })] })] })); },
|
|
165
|
+
parameters: {
|
|
166
|
+
docs: {
|
|
167
|
+
source: {
|
|
168
|
+
code: "<Grid columns={[1, 2]} align=\"center\" columnDivider={{ color: '#ddd' }}>\n <Column>\n <img src=\"/diagram.png\" alt=\"Architecture diagram\" />\n </Column>\n <Column>\n <h3>What you're looking at</h3>\n <p>Description of the diagram elements...</p>\n </Column>\n</Grid>",
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
/**
|
|
174
|
+
* Tutorial layout — prose instructions on the left, sticky code panel on the
|
|
175
|
+
* right. The code panel stays in view while the user scrolls through the steps.
|
|
176
|
+
* The column divider runs the full height of the row regardless of which column
|
|
177
|
+
* is taller. The `sticky` prop is automatically disabled when the grid stacks.
|
|
178
|
+
*/
|
|
179
|
+
export var TutorialWithStickyCode = {
|
|
180
|
+
render: function () { return (_jsxs(Grid, { columns: 2, stackAt: "lg", gap: "lg", columnDivider: { thickness: 2, color: 'var(--dds-grid-divider-color)' }, children: [_jsxs(Column, { children: [_jsx("p", { style: __assign(__assign({}, subtle), { marginBottom: '1rem' }), children: _jsx("strong", { children: "Step 1 \u2014 Install dependencies" }) }), _jsx("p", { style: __assign(__assign({}, subtle), { marginBottom: '1rem' }), children: "Run the installer and follow the prompts. This sets up the project scaffold and pulls in all required packages." }), _jsx("p", { style: __assign(__assign({}, subtle), { marginBottom: '1rem' }), children: _jsx("strong", { children: "Step 2 \u2014 Configure your project" }) }), _jsxs("p", { style: __assign(__assign({}, subtle), { marginBottom: '1rem' }), children: ["Open ", _jsx("code", { children: "config.ts" }), " and update the values for your environment. Refer to the code panel on the right for a complete example."] }), _jsx("p", { style: __assign(__assign({}, subtle), { marginBottom: '1rem' }), children: _jsx("strong", { children: "Step 3 \u2014 Start the dev server" }) }), _jsx("p", { style: subtle, children: "Run the dev command. The server watches for file changes and hot-reloads automatically." })] }), _jsx(Column, { sticky: true, children: _jsx(CodeBlock, { language: "bash", code: "npm install\n\nnpm run dev" }) })] })); },
|
|
181
|
+
parameters: {
|
|
182
|
+
docs: {
|
|
183
|
+
source: {
|
|
184
|
+
code: "<Grid columns={2} stackAt=\"lg\" gap=\"lg\" columnDivider={{ thickness: 2 }}>\n <Column>\n {/* Step-by-step instructions */}\n <p><strong>Step 1 \u2014 Install dependencies</strong></p>\n <p>Run the installer and follow the prompts.</p>\n {/* \u2026 more steps \u2026 */}\n </Column>\n <Column sticky>\n <CodeBlock language=\"bash\" code=\"npm install\\n\\nnpm run dev\" />\n </Column>\n</Grid>",
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
};
|
|
189
|
+
/**
|
|
190
|
+
* Column dividers — a vertical line between columns that converts to a
|
|
191
|
+
* horizontal rule at the stacking breakpoint.
|
|
192
|
+
*/
|
|
193
|
+
export var WithColumnDivider = {
|
|
194
|
+
render: function () { return (_jsxs(Grid, { columns: 3, columnDivider: { thickness: 1, color: 'var(--dds-grid-divider-color)' }, children: [_jsxs(Column, { children: [_jsx("p", { style: subtle, children: _jsx("strong", { children: "Option A" }) }), _jsx("p", { style: subtle, children: "Description of the first approach." })] }), _jsxs(Column, { children: [_jsx("p", { style: subtle, children: _jsx("strong", { children: "Option B" }) }), _jsx("p", { style: subtle, children: "Description of the second approach." })] }), _jsxs(Column, { children: [_jsx("p", { style: subtle, children: _jsx("strong", { children: "Option C" }) }), _jsx("p", { style: subtle, children: "Description of the third approach." })] })] })); },
|
|
195
|
+
parameters: {
|
|
196
|
+
docs: {
|
|
197
|
+
source: {
|
|
198
|
+
code: "<Grid columns={3} columnDivider={{ thickness: 1, color: '#e0e0e0' }}>\n <Column>\n <strong>Option A</strong>\n <p>Description of the first approach.</p>\n </Column>\n <Column>\n <strong>Option B</strong>\n <p>Description of the second approach.</p>\n </Column>\n <Column>\n <strong>Option C</strong>\n <p>Description of the third approach.</p>\n </Column>\n</Grid>",
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
};
|
|
203
|
+
/**
|
|
204
|
+
* Background colors — apply a background to the entire grid and / or to
|
|
205
|
+
* individual columns using the `backgroundColor` prop.
|
|
206
|
+
*/
|
|
207
|
+
export var BackgroundColors = {
|
|
208
|
+
render: function () { return (_jsxs(Grid, { columns: 2, gap: "lg", backgroundColor: "rgba(99,102,241,0.04)", children: [_jsxs(Column, { backgroundColor: "rgba(16,185,129,0.08)", children: [_jsx("p", { style: subtle, children: _jsx("strong", { children: "Column with background" }) }), _jsx("p", { style: subtle, children: "Each column can have its own background color." })] }), _jsxs(Column, { backgroundColor: "rgba(234,179,8,0.08)", children: [_jsx("p", { style: subtle, children: _jsx("strong", { children: "Another column background" }) }), _jsxs("p", { style: subtle, children: ["The grid container also has a light background applied via", ' ', _jsx("code", { children: "backgroundColor" }), " on the ", _jsx("code", { children: "Grid" }), "."] })] })] })); },
|
|
209
|
+
parameters: {
|
|
210
|
+
docs: {
|
|
211
|
+
source: {
|
|
212
|
+
code: "<Grid columns={2} gap=\"lg\" backgroundColor=\"rgba(99,102,241,0.04)\">\n <Column backgroundColor=\"rgba(16,185,129,0.08)\">\n <strong>Column with background</strong>\n <p>Each column can have its own background color.</p>\n </Column>\n <Column backgroundColor=\"rgba(234,179,8,0.08)\">\n <strong>Another column background</strong>\n <p>Set on both the Grid container and individual Columns.</p>\n </Column>\n</Grid>",
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
};
|
|
217
|
+
/**
|
|
218
|
+
* Large gap between columns — useful when columns contain rich content
|
|
219
|
+
* that needs extra breathing room.
|
|
220
|
+
*/
|
|
221
|
+
export var LargeGap = {
|
|
222
|
+
render: function () { return (_jsxs(Grid, { columns: 2, gap: "lg", children: [_jsx(Column, { children: _jsx(Placeholder, { label: "Column 1", height: 140 }) }), _jsx(Column, { children: _jsx(Placeholder, { label: "Column 2", height: 140 }) })] })); },
|
|
223
|
+
parameters: {
|
|
224
|
+
docs: {
|
|
225
|
+
source: {
|
|
226
|
+
code: "<Grid columns={2} gap=\"lg\">\n <Column>Column 1 content</Column>\n <Column>Column 2 content</Column>\n</Grid>",
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
};
|
|
231
|
+
/**
|
|
232
|
+
* Custom gap — pass any CSS length string such as `'1.5rem'` or `'40px'`
|
|
233
|
+
* for fine-grained control beyond the named size tokens.
|
|
234
|
+
*/
|
|
235
|
+
export var CustomGap = {
|
|
236
|
+
render: function () { return (_jsxs(Grid, { columns: 2, gap: "3rem", children: [_jsx(Column, { children: _jsx(Placeholder, { label: "Column 1", height: 140 }) }), _jsx(Column, { children: _jsx(Placeholder, { label: "Column 2", height: 140 }) })] })); },
|
|
237
|
+
parameters: {
|
|
238
|
+
docs: {
|
|
239
|
+
source: {
|
|
240
|
+
code: "<Grid columns={2} gap=\"3rem\">\n <Column>Column 1 content</Column>\n <Column>Column 2 content</Column>\n</Grid>",
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
};
|
|
245
|
+
/**
|
|
246
|
+
* Span — a column set to `span={2}` occupies two grid tracks.
|
|
247
|
+
* Useful for full-width content (e.g. a summary row) inside an otherwise
|
|
248
|
+
* multi-column grid.
|
|
249
|
+
*/
|
|
250
|
+
export var ColumnSpan = {
|
|
251
|
+
render: function () { return (_jsxs(Grid, { columns: 3, gap: "md", children: [_jsx(Column, { children: _jsx(Placeholder, { label: "Col 1" }) }), _jsx(Column, { children: _jsx(Placeholder, { label: "Col 2" }) }), _jsx(Column, { children: _jsx(Placeholder, { label: "Col 3" }) }), _jsx(Column, { span: 3, children: _jsx(Placeholder, { label: "Spans all 3 columns", height: 60, bg: "rgba(239,68,68,0.1)" }) })] })); },
|
|
252
|
+
parameters: {
|
|
253
|
+
docs: {
|
|
254
|
+
source: {
|
|
255
|
+
code: "<Grid columns={3} gap=\"md\">\n <Column>Col 1</Column>\n <Column>Col 2</Column>\n <Column>Col 3</Column>\n <Column span={3}>Spans all 3 columns</Column>\n</Grid>",
|
|
256
|
+
},
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
};
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/styles.css
CHANGED
|
@@ -207,8 +207,10 @@
|
|
|
207
207
|
--dds-collapser-button-padding: 0.75rem; /* p-3 */
|
|
208
208
|
--dds-collapser-button-hover-bg: #f9fafb; /* gray-50 */
|
|
209
209
|
--dds-collapser-icon-color: #6b7280; /* gray-500 */
|
|
210
|
+
--dds-collapser-step-number-color: #6b7280; /* gray-500 — override to customise step numbers */
|
|
210
211
|
--dds-collapser-text: #374151; /* gray-700 */
|
|
211
212
|
--dds-collapser-content-padding: 1rem; /* p-4 */
|
|
213
|
+
--dds-collapser-header-gap: 0.5rem;
|
|
212
214
|
|
|
213
215
|
/* Tabs */
|
|
214
216
|
--dds-tabs-margin: 1rem 0;
|
|
@@ -256,6 +258,13 @@
|
|
|
256
258
|
--dds-list-badge-shadow: inset 0 0 0 1px #bfc2c7;
|
|
257
259
|
--dds-list-connector-line: #eceef2; /* gray-200 */
|
|
258
260
|
--dds-list-text: #374151; /* gray-700 */
|
|
261
|
+
|
|
262
|
+
/* Grid */
|
|
263
|
+
--dds-grid-gap-sm: 1rem; /* gap-4 */
|
|
264
|
+
--dds-grid-gap-md: 1.5rem; /* gap-6 */
|
|
265
|
+
--dds-grid-gap-lg: 2.5rem; /* gap-10 */
|
|
266
|
+
--dds-grid-divider-color: #e5e7eb; /* gray-200 */
|
|
267
|
+
--dds-grid-sticky-top: 1rem;
|
|
259
268
|
}
|
|
260
269
|
/* ==========================================================================
|
|
261
270
|
Dark Mode Tokens
|
|
@@ -342,6 +351,7 @@
|
|
|
342
351
|
--dds-collapser-border: #4b5563; /* gray-600 */
|
|
343
352
|
--dds-collapser-button-hover-bg: rgba(255, 255, 255, 0.05);
|
|
344
353
|
--dds-collapser-icon-color: #9ca3af; /* gray-400 */
|
|
354
|
+
--dds-collapser-step-number-color: #9ca3af;
|
|
345
355
|
--dds-collapser-text: #e5e7eb; /* gray-200 */
|
|
346
356
|
|
|
347
357
|
/* Tabs */
|
|
@@ -416,6 +426,9 @@
|
|
|
416
426
|
--dds-list-badge-shadow: inset 0 0 0 1px #353a42;
|
|
417
427
|
--dds-list-connector-line: #353a42; /* gray-600 */
|
|
418
428
|
--dds-list-text: #e5e7eb; /* gray-200 */
|
|
429
|
+
|
|
430
|
+
/* Grid */
|
|
431
|
+
--dds-grid-divider-color: #4b5563; /* gray-600 */
|
|
419
432
|
}
|
|
420
433
|
/* Auto dark mode — follows OS preference, opt-out with .dds-light */
|
|
421
434
|
@media (prefers-color-scheme: dark) {
|
|
@@ -497,6 +510,7 @@
|
|
|
497
510
|
--dds-collapser-border: #4b5563;
|
|
498
511
|
--dds-collapser-button-hover-bg: rgba(255, 255, 255, 0.05);
|
|
499
512
|
--dds-collapser-icon-color: #9ca3af;
|
|
513
|
+
--dds-collapser-step-number-color: #9ca3af;
|
|
500
514
|
--dds-collapser-text: #e5e7eb;
|
|
501
515
|
|
|
502
516
|
/* Tabs */
|
|
@@ -571,6 +585,9 @@
|
|
|
571
585
|
--dds-list-badge-shadow: inset 0 0 0 1px #353a42;
|
|
572
586
|
--dds-list-connector-line: #353a42; /* gray-600 */
|
|
573
587
|
--dds-list-text: #e5e7eb; /* gray-200 */
|
|
588
|
+
|
|
589
|
+
/* Grid */
|
|
590
|
+
--dds-grid-divider-color: #4b5563; /* gray-600 */
|
|
574
591
|
}
|
|
575
592
|
}
|
|
576
593
|
/* Explicit dark mode via data attribute (overrides OS preference) */
|
|
@@ -652,6 +669,7 @@
|
|
|
652
669
|
--dds-collapser-border: #4b5563;
|
|
653
670
|
--dds-collapser-button-hover-bg: rgba(255, 255, 255, 0.05);
|
|
654
671
|
--dds-collapser-icon-color: #9ca3af;
|
|
672
|
+
--dds-collapser-step-number-color: #9ca3af;
|
|
655
673
|
--dds-collapser-text: #e5e7eb;
|
|
656
674
|
|
|
657
675
|
/* CodeBlock */
|
|
@@ -1101,6 +1119,7 @@ a.no-text-decoration {
|
|
|
1101
1119
|
padding: var(--dds-collapser-button-padding);
|
|
1102
1120
|
display: flex;
|
|
1103
1121
|
align-items: center;
|
|
1122
|
+
gap: var(--dds-collapser-header-gap);
|
|
1104
1123
|
transition: var(--dds-transition-colors);
|
|
1105
1124
|
border: none;
|
|
1106
1125
|
background: transparent;
|
|
@@ -1112,6 +1131,18 @@ a.no-text-decoration {
|
|
|
1112
1131
|
background-color: var(--dds-collapser-button-hover-bg);
|
|
1113
1132
|
outline: none;
|
|
1114
1133
|
}
|
|
1134
|
+
.dds-collapser-step-number {
|
|
1135
|
+
flex-shrink: 0;
|
|
1136
|
+
min-width: 1.5em;
|
|
1137
|
+
font-variant-numeric: tabular-nums;
|
|
1138
|
+
color: var(--dds-collapser-step-number-color);
|
|
1139
|
+
}
|
|
1140
|
+
.dds-collapser-header-icon {
|
|
1141
|
+
display: flex;
|
|
1142
|
+
align-items: center;
|
|
1143
|
+
flex-shrink: 0;
|
|
1144
|
+
color: var(--dds-collapser-icon-color);
|
|
1145
|
+
}
|
|
1115
1146
|
.dds-collapser-title {
|
|
1116
1147
|
display: flex;
|
|
1117
1148
|
align-items: center;
|
|
@@ -1120,12 +1151,18 @@ a.no-text-decoration {
|
|
|
1120
1151
|
margin: 0;
|
|
1121
1152
|
font-weight: bold;
|
|
1122
1153
|
color: var(--dds-heading-color);
|
|
1154
|
+
word-break: break-word;
|
|
1155
|
+
min-width: 0;
|
|
1156
|
+
}
|
|
1157
|
+
.dds-collapser--align-right .dds-collapser-title {
|
|
1158
|
+
justify-content: flex-end;
|
|
1159
|
+
text-align: right;
|
|
1123
1160
|
}
|
|
1124
1161
|
.dds-collapser-icon {
|
|
1125
1162
|
margin-left: auto;
|
|
1163
|
+
flex-shrink: 0;
|
|
1126
1164
|
transition: transform 0.3s ease;
|
|
1127
1165
|
color: var(--dds-collapser-icon-color);
|
|
1128
|
-
flex-shrink: 0;
|
|
1129
1166
|
}
|
|
1130
1167
|
.dds-collapser-icon-open {
|
|
1131
1168
|
transform: rotate(180deg);
|
|
@@ -1808,4 +1845,107 @@ a.no-text-decoration {
|
|
|
1808
1845
|
}
|
|
1809
1846
|
}
|
|
1810
1847
|
}
|
|
1848
|
+
/* =============================================================================
|
|
1849
|
+
Grid — multi-column layout component
|
|
1850
|
+
============================================================================= */
|
|
1851
|
+
/* Base grid container */
|
|
1852
|
+
.dds-grid {
|
|
1853
|
+
display: grid;
|
|
1854
|
+
grid-template-columns: var(--dds-grid-template-columns, repeat(2, 1fr));
|
|
1855
|
+
gap: var(--dds-grid-gap, var(--dds-grid-gap-md));
|
|
1856
|
+
align-items: var(--dds-grid-align, stretch);
|
|
1857
|
+
}
|
|
1858
|
+
/* Optional top border */
|
|
1859
|
+
.dds-grid-has-top-border {
|
|
1860
|
+
border-top: var(--dds-grid-top-border-thickness, 1px) solid
|
|
1861
|
+
var(--dds-grid-top-border-color, var(--dds-grid-divider-color));
|
|
1862
|
+
padding-top: var(--dds-grid-gap, var(--dds-grid-gap-md));
|
|
1863
|
+
}
|
|
1864
|
+
/* Optional bottom border */
|
|
1865
|
+
.dds-grid-has-bottom-border {
|
|
1866
|
+
border-bottom: var(--dds-grid-bottom-border-thickness, 1px) solid
|
|
1867
|
+
var(--dds-grid-bottom-border-color, var(--dds-grid-divider-color));
|
|
1868
|
+
padding-bottom: var(--dds-grid-gap, var(--dds-grid-gap-md));
|
|
1869
|
+
}
|
|
1870
|
+
/* Column divider — vertical line between columns */
|
|
1871
|
+
.dds-grid-has-column-divider .dds-grid-column + .dds-grid-column {
|
|
1872
|
+
border-left: var(--dds-grid-column-divider-thickness, 1px) solid
|
|
1873
|
+
var(--dds-grid-column-divider-color, var(--dds-grid-divider-color));
|
|
1874
|
+
padding-left: var(--dds-grid-gap, var(--dds-grid-gap-md));
|
|
1875
|
+
}
|
|
1876
|
+
/* Individual column */
|
|
1877
|
+
.dds-grid-column {
|
|
1878
|
+
/* Prevent grid cells from overflowing (e.g. wide code blocks) */
|
|
1879
|
+
min-width: 0;
|
|
1880
|
+
}
|
|
1881
|
+
/* Sticky column — column div stretches to full row height so that border-left
|
|
1882
|
+
covers the entire row. The CONTENT inside is what scrolls sticky, via the
|
|
1883
|
+
inner wrapper. */
|
|
1884
|
+
.dds-grid-column-sticky {
|
|
1885
|
+
/* No align-self override — stretches naturally to row height */
|
|
1886
|
+
}
|
|
1887
|
+
/* Inner wrapper that provides the actual sticky scroll behaviour */
|
|
1888
|
+
.dds-grid-column-sticky-inner {
|
|
1889
|
+
position: sticky;
|
|
1890
|
+
top: var(--dds-grid-sticky-top, 1rem);
|
|
1891
|
+
}
|
|
1892
|
+
/* =============================================================================
|
|
1893
|
+
Responsive stacking — columns collapse to a single vertical track
|
|
1894
|
+
============================================================================= */
|
|
1895
|
+
/* Stack at sm breakpoint (≤ 640 px) */
|
|
1896
|
+
@media (max-width: 640px) {
|
|
1897
|
+
.dds-grid-stack-sm {
|
|
1898
|
+
grid-template-columns: 1fr;
|
|
1899
|
+
}
|
|
1900
|
+
|
|
1901
|
+
/* Column divider becomes a horizontal rule when stacked */
|
|
1902
|
+
.dds-grid-stack-sm.dds-grid-has-column-divider .dds-grid-column + .dds-grid-column {
|
|
1903
|
+
border-left: none;
|
|
1904
|
+
padding-left: 0;
|
|
1905
|
+
border-top: var(--dds-grid-column-divider-thickness, 1px) solid
|
|
1906
|
+
var(--dds-grid-column-divider-color, var(--dds-grid-divider-color));
|
|
1907
|
+
padding-top: var(--dds-grid-gap, var(--dds-grid-gap-md));
|
|
1908
|
+
}
|
|
1909
|
+
|
|
1910
|
+
/* Sticky inner wrapper no-ops when stacked */
|
|
1911
|
+
.dds-grid-stack-sm .dds-grid-column-sticky-inner {
|
|
1912
|
+
position: static;
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
/* Stack at md breakpoint (≤ 768 px) */
|
|
1916
|
+
@media (max-width: 768px) {
|
|
1917
|
+
.dds-grid-stack-md {
|
|
1918
|
+
grid-template-columns: 1fr;
|
|
1919
|
+
}
|
|
1920
|
+
|
|
1921
|
+
.dds-grid-stack-md.dds-grid-has-column-divider .dds-grid-column + .dds-grid-column {
|
|
1922
|
+
border-left: none;
|
|
1923
|
+
padding-left: 0;
|
|
1924
|
+
border-top: var(--dds-grid-column-divider-thickness, 1px) solid
|
|
1925
|
+
var(--dds-grid-column-divider-color, var(--dds-grid-divider-color));
|
|
1926
|
+
padding-top: var(--dds-grid-gap, var(--dds-grid-gap-md));
|
|
1927
|
+
}
|
|
1928
|
+
|
|
1929
|
+
.dds-grid-stack-md .dds-grid-column-sticky-inner {
|
|
1930
|
+
position: static;
|
|
1931
|
+
}
|
|
1932
|
+
}
|
|
1933
|
+
/* Stack at lg breakpoint (≤ 1024 px) */
|
|
1934
|
+
@media (max-width: 1024px) {
|
|
1935
|
+
.dds-grid-stack-lg {
|
|
1936
|
+
grid-template-columns: 1fr;
|
|
1937
|
+
}
|
|
1938
|
+
|
|
1939
|
+
.dds-grid-stack-lg.dds-grid-has-column-divider .dds-grid-column + .dds-grid-column {
|
|
1940
|
+
border-left: none;
|
|
1941
|
+
padding-left: 0;
|
|
1942
|
+
border-top: var(--dds-grid-column-divider-thickness, 1px) solid
|
|
1943
|
+
var(--dds-grid-column-divider-color, var(--dds-grid-divider-color));
|
|
1944
|
+
padding-top: var(--dds-grid-gap, var(--dds-grid-gap-md));
|
|
1945
|
+
}
|
|
1946
|
+
|
|
1947
|
+
.dds-grid-stack-lg .dds-grid-column-sticky-inner {
|
|
1948
|
+
position: static;
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1811
1951
|
|