tharaday 0.7.0 → 0.7.2

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.
Files changed (38) hide show
  1. package/.storybook/main.ts +1 -1
  2. package/.storybook/preview.ts +2 -0
  3. package/dist/ds.css +1 -1
  4. package/dist/ds.js +402 -395
  5. package/dist/ds.umd.cjs +1 -1
  6. package/dist/src/components/Modal/Modal.stories.d.ts +5 -0
  7. package/dist/src/components/Tabs/Tabs.stories.d.ts +5 -0
  8. package/dist/src/components/Tree/Tree.stories.d.ts +7 -0
  9. package/dist/src/layouts/AppLayout/AppLayout.d.ts +1 -7
  10. package/dist/src/layouts/AppLayout/AppLayout.stories.d.ts +1 -9
  11. package/dist/src/layouts/AppLayout/AppLayout.types.d.ts +7 -52
  12. package/dist/src/layouts/DashboardLayout/DashboardLayout.d.ts +1 -1
  13. package/dist/src/layouts/DashboardLayout/DashboardLayout.stories.d.ts +1 -7
  14. package/dist/src/layouts/DashboardLayout/DashboardLayout.types.d.ts +2 -9
  15. package/dist/src/layouts/SettingsLayout/SettingsLayout.d.ts +1 -1
  16. package/dist/src/layouts/SettingsLayout/SettingsLayout.stories.d.ts +1 -7
  17. package/dist/src/layouts/SettingsLayout/SettingsLayout.types.d.ts +2 -9
  18. package/eslint.config.js +0 -7
  19. package/package.json +2 -10
  20. package/src/components/Accordion/Accordion.module.css +1 -1
  21. package/src/components/Accordion/Accordion.tsx +14 -1
  22. package/src/components/Dropdown/Dropdown.stories.tsx +24 -0
  23. package/src/components/Modal/Modal.module.css +7 -8
  24. package/src/components/Modal/Modal.stories.tsx +22 -0
  25. package/src/components/Modal/Modal.tsx +10 -4
  26. package/src/components/Notification/Notification.tsx +8 -1
  27. package/src/components/Tabs/Tabs.stories.tsx +19 -0
  28. package/src/components/Tooltip/Tooltip.stories.tsx +24 -0
  29. package/src/components/Tree/Tree.stories.tsx +15 -0
  30. package/src/layouts/AppLayout/AppLayout.stories.tsx +48 -36
  31. package/src/layouts/AppLayout/AppLayout.tsx +4 -34
  32. package/src/layouts/AppLayout/AppLayout.types.ts +7 -51
  33. package/src/layouts/DashboardLayout/DashboardLayout.stories.tsx +4 -8
  34. package/src/layouts/DashboardLayout/DashboardLayout.tsx +2 -17
  35. package/src/layouts/DashboardLayout/DashboardLayout.types.tsx +2 -7
  36. package/src/layouts/SettingsLayout/SettingsLayout.stories.tsx +16 -7
  37. package/src/layouts/SettingsLayout/SettingsLayout.tsx +2 -17
  38. package/src/layouts/SettingsLayout/SettingsLayout.types.tsx +2 -7
@@ -46,7 +46,20 @@ export const Accordion = ({
46
46
  aria-controls={`${componentId}-content-${item.id}`}
47
47
  >
48
48
  <span>{item.title}</span>
49
- <span className={clsx(styles.icon, isExpanded && styles.iconExpanded)}>▼</span>
49
+ <span
50
+ className={clsx(styles.icon, isExpanded && styles.iconExpanded)}
51
+ aria-hidden="true"
52
+ >
53
+ <svg width="12" height="12" viewBox="0 0 12 12" fill="none">
54
+ <path
55
+ d="M2.5 4.5L6 8L9.5 4.5"
56
+ stroke="currentColor"
57
+ strokeWidth="1.5"
58
+ strokeLinecap="round"
59
+ strokeLinejoin="round"
60
+ />
61
+ </svg>
62
+ </span>
50
63
  </button>
51
64
  <div
52
65
  id={`${componentId}-content-${item.id}`}
@@ -6,6 +6,30 @@ const meta: Meta<typeof Dropdown> = {
6
6
  title: 'Components/Dropdown',
7
7
  component: Dropdown,
8
8
  tags: ['autodocs'],
9
+ parameters: {
10
+ docs: {
11
+ description: {
12
+ component: `
13
+ A custom select built on a \`button\` + \`listbox\` pattern. Supports both controlled (\`value\` + \`onChange\`) and uncontrolled (\`defaultValue\`) usage. Options can carry an optional description and can be individually disabled.
14
+
15
+ **When to use**
16
+ Use Dropdown when you need richer option rendering (descriptions, icons) or tighter visual control over the trigger. For simple native selects, use the \`Select\` component instead.
17
+
18
+ **Keyboard interaction**
19
+
20
+ | Key | Behaviour |
21
+ |-----|-----------|
22
+ | \`Enter\` / \`Space\` | Toggle open; select focused option when open |
23
+ | \`ArrowDown\` | Open list or move focus to next option |
24
+ | \`ArrowUp\` | Open list or move focus to previous option |
25
+ | \`Home\` | Move focus to first option |
26
+ | \`End\` | Move focus to last option |
27
+ | \`Escape\` | Close list and return focus to trigger |
28
+ | \`Tab\` | Close list and move focus to next element |
29
+ `,
30
+ },
31
+ },
32
+ },
9
33
  argTypes: {
10
34
  onChange: { action: 'changed' },
11
35
  },
@@ -39,15 +39,14 @@
39
39
  color: var(--ds-text-1);
40
40
  }
41
41
 
42
- .closeButton {
43
- margin: 0;
44
- padding: 0 !important;
45
- width: var(--ds-space-8) !important;
46
- height: var(--ds-space-8) !important;
47
- min-width: unset !important;
48
- font-size: var(--ds-font-size-lg) !important;
42
+ /* Double class increases specificity to (0,2,0) — wins over Button's single-class size rules */
43
+ .closeButton.closeButton {
44
+ padding: 0;
45
+ width: var(--ds-space-8);
46
+ height: var(--ds-space-8);
47
+ font-size: var(--ds-font-size-lg);
49
48
  font-weight: var(--ds-font-weight-semibold);
50
- line-height: 1 !important;
49
+ line-height: 1;
51
50
  display: flex;
52
51
  align-items: center;
53
52
  justify-content: center;
@@ -15,6 +15,28 @@ const meta = {
15
15
  tags: ['autodocs'],
16
16
  parameters: {
17
17
  layout: 'centered',
18
+ docs: {
19
+ description: {
20
+ component: `
21
+ A dialog overlay that traps focus while open and restores it to the trigger element on close. Renders into the normal DOM tree (no portal) and is controlled via \`isOpen\` + \`onClose\`.
22
+
23
+ **Usage**
24
+ Always provide a \`title\` — it is wired to \`aria-labelledby\` on the dialog element. Pass action buttons via the \`footer\` prop to keep them visually anchored to the bottom.
25
+
26
+ **Keyboard interaction**
27
+
28
+ | Key | Behaviour |
29
+ |-----|-----------|
30
+ | \`Tab\` | Cycle focus through all focusable elements inside the modal |
31
+ | \`Shift + Tab\` | Cycle focus backwards |
32
+ | \`Escape\` | Close the modal |
33
+
34
+ **Sizes**
35
+
36
+ \`sm\` · \`md\` (default) · \`lg\` · \`xl\` · \`full\`
37
+ `,
38
+ },
39
+ },
18
40
  },
19
41
  argTypes: {
20
42
  size: {
@@ -61,15 +61,14 @@ export const Modal = ({
61
61
  document.body.style.overflow = 'hidden';
62
62
  window.addEventListener('keydown', handleKeyDown);
63
63
 
64
- // Focus the first element or the close button after a small delay to ensure it's rendered
65
- setTimeout(() => {
64
+ requestAnimationFrame(() => {
66
65
  const focusableElements = modalRef.current?.querySelectorAll<HTMLElement>(
67
66
  'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
68
67
  );
69
68
  if (focusableElements && focusableElements.length > 0) {
70
69
  focusableElements[0].focus();
71
70
  }
72
- }, 0);
71
+ });
73
72
  }
74
73
 
75
74
  return () => {
@@ -108,7 +107,14 @@ export const Modal = ({
108
107
  aria-label="Close modal"
109
108
  disabled={isLoading}
110
109
  >
111
-
110
+ <svg width="10" height="10" viewBox="0 0 10 10" fill="none" aria-hidden="true">
111
+ <path
112
+ d="M1 1L9 9M9 1L1 9"
113
+ stroke="currentColor"
114
+ strokeWidth="1.5"
115
+ strokeLinecap="round"
116
+ />
117
+ </svg>
112
118
  </Button>
113
119
  </div>
114
120
  <div className={styles.content}>{children}</div>
@@ -26,7 +26,14 @@ export const Notification = ({
26
26
  className={styles.closeButton}
27
27
  aria-label="Close notification"
28
28
  >
29
-
29
+ <svg width="10" height="10" viewBox="0 0 10 10" fill="none" aria-hidden="true">
30
+ <path
31
+ d="M1 1L9 9M9 1L1 9"
32
+ stroke="currentColor"
33
+ strokeWidth="1.5"
34
+ strokeLinecap="round"
35
+ />
36
+ </svg>
30
37
  </Button>
31
38
  )}
32
39
  </div>
@@ -8,6 +8,25 @@ const meta = {
8
8
  tags: ['autodocs'],
9
9
  parameters: {
10
10
  layout: 'centered',
11
+ docs: {
12
+ description: {
13
+ component: `
14
+ A tab widget implementing the [ARIA Tabs pattern](https://www.w3.org/WAI/ARIA/apg/patterns/tabs/). Supports controlled (\`activeId\` + \`onChange\`) and uncontrolled (\`defaultActiveId\`) modes. Individual tabs can be disabled. Two visual variants are available: \`line\` (default) and \`pill\`.
15
+
16
+ **Keyboard interaction**
17
+
18
+ Focus moves into the tab list on \`Tab\`. Arrow keys then navigate between tabs and automatically activate them (automatic activation pattern).
19
+
20
+ | Key | Behaviour |
21
+ |-----|-----------|
22
+ | \`ArrowRight\` / \`ArrowDown\` | Move to and activate next enabled tab (wraps) |
23
+ | \`ArrowLeft\` / \`ArrowUp\` | Move to and activate previous enabled tab (wraps) |
24
+ | \`Home\` | Move to and activate first enabled tab |
25
+ | \`End\` | Move to and activate last enabled tab |
26
+ | \`Tab\` | Move focus from tab list into the active tab panel |
27
+ `,
28
+ },
29
+ },
11
30
  },
12
31
  } satisfies Meta<typeof Tabs>;
13
32
 
@@ -7,6 +7,30 @@ const meta: Meta<typeof Tooltip> = {
7
7
  title: 'Components/Tooltip',
8
8
  component: Tooltip,
9
9
  tags: ['autodocs'],
10
+ parameters: {
11
+ docs: {
12
+ description: {
13
+ component: `
14
+ Wraps any focusable trigger element and shows supplementary content on hover or focus. The tooltip element always stays in the DOM (CSS opacity toggle) so that \`aria-describedby\` references remain valid at all times.
15
+
16
+ **Usage**
17
+ Pass a single focusable element as \`children\`. The component clones it to inject \`aria-describedby\`, so the trigger does not need to be modified manually. Use short, non-essential text — tooltips are not a substitute for visible labels.
18
+
19
+ **Keyboard interaction**
20
+
21
+ | Key | Behaviour |
22
+ |-----|-----------|
23
+ | Focus trigger | Show tooltip after \`delay\` ms |
24
+ | Blur trigger | Hide tooltip immediately |
25
+ | \`Escape\` | Hide tooltip while trigger is focused |
26
+
27
+ **Positions:** \`top\` (default) · \`bottom\` · \`left\` · \`right\`
28
+
29
+ **Variants:** \`dark\` (default) · \`light\`
30
+ `,
31
+ },
32
+ },
33
+ },
10
34
  decorators: [
11
35
  (Story) => (
12
36
  <div
@@ -5,6 +5,21 @@ const meta = {
5
5
  title: 'Components/Tree',
6
6
  component: Tree,
7
7
  tags: ['autodocs'],
8
+ parameters: {
9
+ docs: {
10
+ description: {
11
+ component: `
12
+ Renders any JavaScript value — object, array, or primitive — as an expandable tree. Useful for debugging, JSON inspection, or displaying structured data. Nested objects and arrays are collapsible; primitives and \`null\` are displayed inline.
13
+
14
+ **Usage**
15
+ Pass any serialisable value to \`data\`. Control the initial expand state with \`defaultExpanded\` (default: \`true\`). Custom expand/collapse icons can be provided via \`expandIcon\` and \`collapseIcon\`.
16
+
17
+ **Limitations**
18
+ This component is a data visualiser, not a navigation tree. It does not implement the [ARIA Tree pattern](https://www.w3.org/WAI/ARIA/apg/patterns/treeview/) — there is no keyboard navigation between nodes. For navigable trees (e.g. file explorers, side nav), a fully accessible tree widget should be used instead.
19
+ `,
20
+ },
21
+ },
22
+ },
8
23
  } satisfies Meta<typeof Tree>;
9
24
 
10
25
  export default meta;
@@ -5,6 +5,8 @@ import { AppLayout } from './AppLayout.tsx';
5
5
  import { Box } from '../../components/Box/Box.tsx';
6
6
  import { Button } from '../../components/Button/Button.tsx';
7
7
  import { Card, CardHeader, CardContent } from '../../components/Card/Card.tsx';
8
+ import { Header } from '../../components/Header/Header.tsx';
9
+ import { NavBar } from '../../components/NavBar/NavBar.tsx';
8
10
  import { Text } from '../../components/Text/Text.tsx';
9
11
 
10
12
  const meta = {
@@ -13,13 +15,6 @@ const meta = {
13
15
  parameters: {
14
16
  layout: 'fullscreen',
15
17
  },
16
- args: {
17
- headerTitle: 'Tharaday',
18
- onLogin: fn(),
19
- onLogout: fn(),
20
- onCreateAccount: fn(),
21
- onNavItemClick: fn(),
22
- },
23
18
  } satisfies Meta<typeof AppLayout>;
24
19
 
25
20
  export default meta;
@@ -46,14 +41,26 @@ const navItems = [
46
41
 
47
42
  export const Default: Story = {
48
43
  args: {
49
- headerLogo: logo,
50
- user: { name: 'John Doe' },
51
- navItems,
52
- activeNavId: 'dashboard',
53
- navActions: (
54
- <Button size="sm" variant="outline">
55
- Feedback
56
- </Button>
44
+ header: (
45
+ <Header
46
+ logo={logo}
47
+ title="Tharaday"
48
+ user={{ name: 'John Doe' }}
49
+ onLogout={fn()}
50
+ onCreateAccount={fn()}
51
+ />
52
+ ),
53
+ navbar: (
54
+ <NavBar
55
+ items={navItems}
56
+ activeId="dashboard"
57
+ actions={
58
+ <Button size="sm" variant="outline">
59
+ Feedback
60
+ </Button>
61
+ }
62
+ onItemClick={fn()}
63
+ />
57
64
  ),
58
65
  children: (
59
66
  <Box display="flex" flexDirection="column" gap={6}>
@@ -72,7 +79,7 @@ export const Default: Story = {
72
79
  The top bar is the <strong>Header</strong>. It handles:
73
80
  </Text>
74
81
  <ul>
75
- <li>Global Branding (Logo & Title)</li>
82
+ <li>Global Branding (Logo &amp; Title)</li>
76
83
  <li>User Identity (Welcome message)</li>
77
84
  <li>Session State (Log out button)</li>
78
85
  </ul>
@@ -111,31 +118,36 @@ export const Default: Story = {
111
118
 
112
119
  export const LoggedOut: Story = {
113
120
  args: {
114
- ...Default.args,
115
- user: undefined,
116
- navItems: [
117
- { id: 'home', label: 'Home' },
118
- { id: 'features', label: 'Features' },
119
- { id: 'pricing', label: 'Pricing' },
120
- { id: 'docs', label: 'Documentation' },
121
- ],
122
- activeNavId: 'home',
123
- },
124
- };
125
-
126
- export const LoggedOutWithoutHeaderActions: Story = {
127
- args: {
128
- ...LoggedOut.args,
129
- onLogin: undefined,
130
- onCreateAccount: undefined,
121
+ header: <Header logo={logo} title="Tharaday" onLogin={fn()} onCreateAccount={fn()} />,
122
+ navbar: (
123
+ <NavBar
124
+ items={[
125
+ { id: 'home', label: 'Home' },
126
+ { id: 'features', label: 'Features' },
127
+ { id: 'pricing', label: 'Pricing' },
128
+ { id: 'docs', label: 'Documentation' },
129
+ ]}
130
+ activeId="home"
131
+ onItemClick={fn()}
132
+ />
133
+ ),
134
+ children: Default.args?.children,
131
135
  },
132
136
  };
133
137
 
134
138
  export const LongHeaderContent: Story = {
135
139
  args: {
136
- ...Default.args,
137
- headerTitle: 'Tharaday Design System Platform',
138
- user: { name: 'Alexandria Catherine Montgomery' },
140
+ header: (
141
+ <Header
142
+ logo={logo}
143
+ title="Tharaday Design System Platform"
144
+ user={{ name: 'Alexandria Catherine Montgomery' }}
145
+ onLogout={fn()}
146
+ maxWidth="48rem"
147
+ />
148
+ ),
149
+ navbar: <NavBar items={navItems} activeId="dashboard" onItemClick={fn()} maxWidth="48rem" />,
139
150
  maxWidth: '48rem',
151
+ children: Default.args?.children,
140
152
  },
141
153
  };
@@ -3,48 +3,18 @@ import clsx from 'clsx';
3
3
  import styles from './AppLayout.module.css';
4
4
  import type { AppLayoutProps } from './AppLayout.types.ts';
5
5
  import { Box } from '../../components/Box/Box.tsx';
6
- import { Header } from '../../components/Header/Header.tsx';
7
- import { NavBar } from '../../components/NavBar/NavBar.tsx';
8
6
 
9
- /**
10
- * AppLayout provides a standard layout structure that includes both
11
- * a Header (for branding and user state) and a NavBar (for navigation).
12
- *
13
- * This component demonstrates the distinct roles of Header and NavBar.
14
- */
15
7
  export const AppLayout = ({
16
- headerLogo,
17
- headerTitle,
18
- user,
19
- navItems,
20
- activeNavId,
21
- navActions,
8
+ header,
9
+ navbar,
22
10
  children,
23
- onLogin,
24
- onLogout,
25
- onCreateAccount,
26
- onNavItemClick,
27
11
  className,
28
12
  maxWidth = '75rem',
29
13
  }: AppLayoutProps) => {
30
14
  return (
31
15
  <div className={clsx(styles.root, className)}>
32
- <Header
33
- logo={headerLogo}
34
- title={headerTitle}
35
- user={user}
36
- onLogin={onLogin}
37
- onLogout={onLogout}
38
- onCreateAccount={onCreateAccount}
39
- maxWidth={maxWidth}
40
- />
41
- <NavBar
42
- items={navItems}
43
- activeId={activeNavId}
44
- actions={navActions}
45
- onItemClick={onNavItemClick}
46
- maxWidth={maxWidth}
47
- />
16
+ {header}
17
+ {navbar}
48
18
  <main className={styles.main}>
49
19
  <Box className={styles.container} maxWidth={maxWidth}>
50
20
  {children}
@@ -1,58 +1,14 @@
1
1
  import type { ReactNode } from 'react';
2
2
 
3
- import type { NavBarItem } from '../../components/NavBar/NavBar.types.ts';
4
-
5
3
  export interface AppLayoutProps {
6
- /**
7
- * Additional class name for the layout root
8
- */
4
+ /** Additional class name for the layout root */
9
5
  className?: string;
10
- /**
11
- * Max width for header and navbar containers
12
- */
6
+ /** Max width for the main content container */
13
7
  maxWidth?: string | number;
14
- /**
15
- * Header logo element
16
- */
17
- headerLogo?: ReactNode;
18
- /**
19
- * Header title
20
- */
21
- headerTitle?: string;
22
- /**
23
- * Current user object for the Header
24
- */
25
- user?: { name: string };
26
- /**
27
- * NavBar navigation items
28
- */
29
- navItems: NavBarItem[];
30
- /**
31
- * Active NavBar item ID
32
- */
33
- activeNavId?: string;
34
- /**
35
- * NavBar actions (right side)
36
- */
37
- navActions?: ReactNode;
38
- /**
39
- * Content to display in the main area
40
- */
8
+ /** Header slot — render a pre-configured Header component */
9
+ header?: ReactNode;
10
+ /** NavBar slot — render a pre-configured NavBar component */
11
+ navbar?: ReactNode;
12
+ /** Main content */
41
13
  children: ReactNode;
42
- /**
43
- * Callback for header login
44
- */
45
- onLogin?: () => void;
46
- /**
47
- * Callback for header logout
48
- */
49
- onLogout?: () => void;
50
- /**
51
- * Callback for header create account
52
- */
53
- onCreateAccount?: () => void;
54
- /**
55
- * Callback for nav item click
56
- */
57
- onNavItemClick?: (id: string) => void;
58
14
  }
@@ -8,6 +8,7 @@ import { Box } from '../../components/Box/Box.tsx';
8
8
  import { Breadcrumbs, BreadcrumbItem } from '../../components/Breadcrumbs/Breadcrumbs.tsx';
9
9
  import { Button } from '../../components/Button/Button.tsx';
10
10
  import { Card, CardHeader, CardContent } from '../../components/Card/Card.tsx';
11
+ import { Header } from '../../components/Header/Header.tsx';
11
12
  import { Text } from '../../components/Text/Text.tsx';
12
13
 
13
14
  const meta = {
@@ -16,12 +17,6 @@ const meta = {
16
17
  parameters: {
17
18
  layout: 'fullscreen',
18
19
  },
19
- args: {
20
- headerTitle: 'DS Creator',
21
- onLogin: fn(),
22
- onLogout: fn(),
23
- onCreateAccount: fn(),
24
- },
25
20
  } satisfies Meta<typeof DashboardLayout>;
26
21
 
27
22
  export default meta;
@@ -41,8 +36,9 @@ const logo = (
41
36
 
42
37
  export const Overview: Story = {
43
38
  args: {
44
- headerLogo: logo,
45
- user: { name: 'Design Creator' },
39
+ header: (
40
+ <Header logo={logo} title="DS Creator" user={{ name: 'Design Creator' }} onLogout={fn()} />
41
+ ),
46
42
  breadcrumbs: (
47
43
  <Breadcrumbs>
48
44
  <BreadcrumbItem href="#">Home</BreadcrumbItem>
@@ -2,33 +2,18 @@ import clsx from 'clsx';
2
2
 
3
3
  import styles from './DashboardLayout.module.css';
4
4
  import type { DashboardLayoutProps } from './DashboardLayout.types.tsx';
5
- import { Header } from '../../components/Header/Header.tsx';
6
5
 
7
6
  export const DashboardLayout = ({
8
- headerLogo,
9
- headerTitle,
7
+ header,
10
8
  breadcrumbs,
11
9
  actions,
12
10
  stats,
13
11
  children,
14
- user,
15
- onLogin,
16
- onLogout,
17
- onCreateAccount,
18
12
  className,
19
- maxWidth,
20
13
  }: DashboardLayoutProps) => {
21
14
  return (
22
15
  <div className={clsx(styles.root, className)}>
23
- <Header
24
- logo={headerLogo}
25
- title={headerTitle}
26
- user={user}
27
- onLogin={onLogin}
28
- onLogout={onLogout}
29
- onCreateAccount={onCreateAccount}
30
- maxWidth={maxWidth}
31
- />
16
+ {header}
32
17
  <main className={styles.main}>
33
18
  <div className={styles.container}>
34
19
  {(breadcrumbs || actions) && (
@@ -2,15 +2,10 @@ import type { ReactNode } from 'react';
2
2
 
3
3
  export interface DashboardLayoutProps {
4
4
  className?: string;
5
- maxWidth?: string | number;
6
- headerLogo?: ReactNode;
7
- headerTitle?: string;
5
+ /** Header slot — render a pre-configured Header component */
6
+ header?: ReactNode;
8
7
  breadcrumbs?: ReactNode;
9
8
  actions?: ReactNode;
10
9
  stats?: ReactNode;
11
10
  children: ReactNode;
12
- user?: { name: string };
13
- onLogin?: () => void;
14
- onLogout?: () => void;
15
- onCreateAccount?: () => void;
16
11
  }
@@ -6,6 +6,7 @@ import { Box } from '../../components/Box/Box.tsx';
6
6
  import { Breadcrumbs, BreadcrumbItem } from '../../components/Breadcrumbs/Breadcrumbs.tsx';
7
7
  import { Button } from '../../components/Button/Button.tsx';
8
8
  import { Card, CardHeader, CardContent, CardFooter } from '../../components/Card/Card.tsx';
9
+ import { Header } from '../../components/Header/Header.tsx';
9
10
  import { Input } from '../../components/Input/Input.tsx';
10
11
  import { Notification } from '../../components/Notification/Notification.tsx';
11
12
  import { Text } from '../../components/Text/Text.tsx';
@@ -17,20 +18,28 @@ const meta = {
17
18
  parameters: {
18
19
  layout: 'fullscreen',
19
20
  },
20
- args: {
21
- headerTitle: 'DS Creator',
22
- onLogin: fn(),
23
- onLogout: fn(),
24
- onCreateAccount: fn(),
25
- },
26
21
  } satisfies Meta<typeof SettingsLayout>;
27
22
 
28
23
  export default meta;
29
24
  type Story = StoryObj<typeof meta>;
30
25
 
26
+ const logo = (
27
+ <svg width="32" height="32" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
28
+ <g fill="none" fillRule="evenodd">
29
+ <path
30
+ d="M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z"
31
+ fill="#3b82f6"
32
+ />
33
+ <path d="M16 8l8 12H8l8-12z" fill="#FFF" />
34
+ </g>
35
+ </svg>
36
+ );
37
+
31
38
  export const ProfileSettings: Story = {
32
39
  args: {
33
- user: { name: 'Design Creator' },
40
+ header: (
41
+ <Header logo={logo} title="DS Creator" user={{ name: 'Design Creator' }} onLogout={fn()} />
42
+ ),
34
43
  breadcrumbs: (
35
44
  <Breadcrumbs>
36
45
  <BreadcrumbItem href="#">Home</BreadcrumbItem>
@@ -2,32 +2,17 @@ import clsx from 'clsx';
2
2
 
3
3
  import styles from './SettingsLayout.module.css';
4
4
  import type { SettingsLayoutProps } from './SettingsLayout.types.tsx';
5
- import { Header } from '../../components/Header/Header.tsx';
6
5
 
7
6
  export const SettingsLayout = ({
8
- headerLogo,
9
- headerTitle,
7
+ header,
10
8
  breadcrumbs,
11
9
  sidebar,
12
10
  children,
13
- user,
14
- onLogin,
15
- onLogout,
16
- onCreateAccount,
17
11
  className,
18
- maxWidth,
19
12
  }: SettingsLayoutProps) => {
20
13
  return (
21
14
  <div className={clsx(styles.root, className)}>
22
- <Header
23
- logo={headerLogo}
24
- title={headerTitle}
25
- user={user}
26
- onLogin={onLogin}
27
- onLogout={onLogout}
28
- onCreateAccount={onCreateAccount}
29
- maxWidth={maxWidth}
30
- />
15
+ {header}
31
16
  <main className={styles.main}>
32
17
  <div className={styles.container}>
33
18
  {breadcrumbs && <div className={styles.breadcrumbs}>{breadcrumbs}</div>}
@@ -2,14 +2,9 @@ import type { ReactNode } from 'react';
2
2
 
3
3
  export interface SettingsLayoutProps {
4
4
  className?: string;
5
- maxWidth?: string | number;
6
- headerLogo?: ReactNode;
7
- headerTitle?: string;
5
+ /** Header slot — render a pre-configured Header component */
6
+ header?: ReactNode;
8
7
  breadcrumbs?: ReactNode;
9
8
  sidebar?: ReactNode;
10
9
  children: ReactNode;
11
- user?: { name: string };
12
- onLogin?: () => void;
13
- onLogout?: () => void;
14
- onCreateAccount?: () => void;
15
10
  }