@dezkareid/components 0.0.0 → 1.0.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/.releaserc +18 -0
- package/.turbo/turbo-build.log +7 -0
- package/.turbo/turbo-test.log +17 -0
- package/AGENTS.md +174 -0
- package/CHANGELOG.md +12 -0
- package/README.md +213 -5
- package/dist/_virtual/_commonjsHelpers.js +6 -0
- package/dist/_virtual/_commonjsHelpers.js.map +1 -0
- package/dist/_virtual/index.js +8 -0
- package/dist/_virtual/index.js.map +1 -0
- package/dist/_virtual/index2.js +4 -0
- package/dist/_virtual/index2.js.map +1 -0
- package/dist/astro/index.d.ts +5 -0
- package/dist/astro/index.d.ts.map +1 -0
- package/dist/components.min.css +1 -0
- package/dist/css/button.module.css.js +4 -0
- package/dist/css/button.module.css.js.map +1 -0
- package/dist/css/card.module.css.js +4 -0
- package/dist/css/card.module.css.js.map +1 -0
- package/dist/css/index.d.ts +5 -0
- package/dist/css/index.d.ts.map +1 -0
- package/dist/css/tag.module.css.js +4 -0
- package/dist/css/tag.module.css.js.map +1 -0
- package/dist/css/theme-toggle.module.css.js +4 -0
- package/dist/css/theme-toggle.module.css.js.map +1 -0
- package/dist/node_modules/.pnpm/classnames@2.5.1/node_modules/classnames/index.js +86 -0
- package/dist/node_modules/.pnpm/classnames@2.5.1/node_modules/classnames/index.js.map +1 -0
- package/dist/react/Button/index.d.ts +6 -0
- package/dist/react/Button/index.d.ts.map +1 -0
- package/dist/react/Button/index.js +10 -0
- package/dist/react/Button/index.js.map +1 -0
- package/dist/react/Card/index.d.ts +6 -0
- package/dist/react/Card/index.d.ts.map +1 -0
- package/dist/react/Card/index.js +10 -0
- package/dist/react/Card/index.js.map +1 -0
- package/dist/react/Tag/index.d.ts +6 -0
- package/dist/react/Tag/index.d.ts.map +1 -0
- package/dist/react/Tag/index.js +10 -0
- package/dist/react/Tag/index.js.map +1 -0
- package/dist/react/ThemeToggle/index.d.ts +2 -0
- package/dist/react/ThemeToggle/index.d.ts.map +1 -0
- package/dist/react/ThemeToggle/index.js +25 -0
- package/dist/react/ThemeToggle/index.js.map +1 -0
- package/dist/react/index.d.ts +5 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +5 -0
- package/dist/react/index.js.map +1 -0
- package/dist/shared/js/theme.d.ts +5 -0
- package/dist/shared/js/theme.d.ts.map +1 -0
- package/dist/shared/js/theme.js +22 -0
- package/dist/shared/js/theme.js.map +1 -0
- package/dist/shared/types/button.d.ts +8 -0
- package/dist/shared/types/button.d.ts.map +1 -0
- package/dist/shared/types/card.d.ts +5 -0
- package/dist/shared/types/card.d.ts.map +1 -0
- package/dist/shared/types/tag.d.ts +5 -0
- package/dist/shared/types/tag.d.ts.map +1 -0
- package/dist/shared/types/theme-toggle.d.ts +4 -0
- package/dist/shared/types/theme-toggle.d.ts.map +1 -0
- package/dist/vue/index.d.ts +5 -0
- package/dist/vue/index.d.ts.map +1 -0
- package/done/2026-03-03-design-system-components/osddt.plan.md +233 -0
- package/done/2026-03-03-design-system-components/osddt.spec.md +90 -0
- package/done/2026-03-03-design-system-components/osddt.tasks.md +100 -0
- package/package.json +76 -6
- package/rollup.config.mjs +32 -0
- package/setupTests.ts +1 -0
- package/src/astro/Button/index.astro +35 -0
- package/src/astro/Card/index.astro +23 -0
- package/src/astro/Tag/index.astro +23 -0
- package/src/astro/ThemeToggle/index.astro +63 -0
- package/src/astro/index.ts +4 -0
- package/src/css/button.module.css +90 -0
- package/src/css/card.module.css +30 -0
- package/src/css/index.ts +4 -0
- package/src/css/tag.module.css +33 -0
- package/src/css/theme-toggle.module.css +38 -0
- package/src/declarations.d.ts +19 -0
- package/src/react/Button/index.test.tsx +59 -0
- package/src/react/Button/index.tsx +31 -0
- package/src/react/Card/index.test.tsx +38 -0
- package/src/react/Card/index.tsx +14 -0
- package/src/react/Tag/index.test.tsx +35 -0
- package/src/react/Tag/index.tsx +14 -0
- package/src/react/ThemeToggle/index.test.tsx +84 -0
- package/src/react/ThemeToggle/index.tsx +36 -0
- package/src/react/index.ts +4 -0
- package/src/shared/js/theme.ts +22 -0
- package/src/shared/types/button.ts +8 -0
- package/src/shared/types/card.ts +5 -0
- package/src/shared/types/tag.ts +5 -0
- package/src/shared/types/theme-toggle.ts +5 -0
- package/src/vue/Button/index.vue +27 -0
- package/src/vue/Card/index.vue +18 -0
- package/src/vue/Tag/index.vue +18 -0
- package/src/vue/ThemeToggle/index.vue +39 -0
- package/src/vue/index.ts +4 -0
- package/tsconfig.json +19 -0
- package/vite.config.build.ts +34 -0
- package/vitest.config.ts +12 -0
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ButtonHTMLAttributes } from 'react';
|
|
2
|
+
import type { ButtonProps } from '../../shared/types/button';
|
|
3
|
+
type Props = ButtonProps & ButtonHTMLAttributes<HTMLButtonElement>;
|
|
4
|
+
export declare function Button({ variant, size, disabled, children, className, ...rest }: Props): import("react/jsx-runtime").JSX.Element;
|
|
5
|
+
export {};
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/react/Button/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAElD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAG7D,KAAK,KAAK,GAAG,WAAW,GAAG,oBAAoB,CAAC,iBAAiB,CAAC,CAAC;AAEnE,wBAAgB,MAAM,CAAC,EACrB,OAAmB,EACnB,IAAW,EACX,QAAgB,EAChB,QAAQ,EACR,SAAS,EACT,GAAG,IAAI,EACR,EAAE,KAAK,2CAgBP"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import cx from '../../_virtual/index.js';
|
|
3
|
+
import styles from '../../css/button.module.css.js';
|
|
4
|
+
|
|
5
|
+
function Button({ variant = 'primary', size = 'md', disabled = false, children, className, ...rest }) {
|
|
6
|
+
return (jsx("button", { className: cx(styles.button, styles[`button--${variant}`], styles[`button--${size}`], disabled && styles['button--disabled'], className), disabled: disabled, ...rest, children: children }));
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export { Button };
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../src/react/Button/index.tsx"],"sourcesContent":[null],"names":["_jsx"],"mappings":";;;;AAOM,SAAU,MAAM,CAAC,EACrB,OAAO,GAAG,SAAS,EACnB,IAAI,GAAG,IAAI,EACX,QAAQ,GAAG,KAAK,EAChB,QAAQ,EACR,SAAS,EACT,GAAG,IAAI,EACD,EAAA;AACN,IAAA,QACEA,GAAA,CAAA,QAAA,EAAA,EACE,SAAS,EAAE,EAAE,CACX,MAAM,CAAC,MAAM,EACb,MAAM,CAAC,WAAW,OAAO,CAAA,CAAE,CAAC,EAC5B,MAAM,CAAC,CAAA,QAAA,EAAW,IAAI,EAAE,CAAC,EACzB,QAAQ,IAAI,MAAM,CAAC,kBAAkB,CAAC,EACtC,SAAS,CACV,EACD,QAAQ,EAAE,QAAQ,EAAA,GACd,IAAI,YAEP,QAAQ,EAAA,CACF;AAEb;;;;"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { HTMLAttributes } from 'react';
|
|
2
|
+
import type { CardProps } from '../../shared/types/card';
|
|
3
|
+
type Props = CardProps & HTMLAttributes<HTMLDivElement>;
|
|
4
|
+
export declare function Card({ elevation, children, className, ...rest }: Props): import("react/jsx-runtime").JSX.Element;
|
|
5
|
+
export {};
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/react/Card/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAE5C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAGzD,KAAK,KAAK,GAAG,SAAS,GAAG,cAAc,CAAC,cAAc,CAAC,CAAC;AAExD,wBAAgB,IAAI,CAAC,EAAE,SAAoB,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,EAAE,KAAK,2CAMjF"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import cx from '../../_virtual/index.js';
|
|
3
|
+
import styles from '../../css/card.module.css.js';
|
|
4
|
+
|
|
5
|
+
function Card({ elevation = 'raised', children, className, ...rest }) {
|
|
6
|
+
return (jsx("div", { className: cx(styles.card, styles[`card--${elevation}`], className), ...rest, children: children }));
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export { Card };
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../src/react/Card/index.tsx"],"sourcesContent":[null],"names":["_jsx"],"mappings":";;;;AAOM,SAAU,IAAI,CAAC,EAAE,SAAS,GAAG,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,IAAI,EAAS,EAAA;IAChF,QACEA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,SAAS,SAAS,CAAA,CAAE,CAAC,EAAE,SAAS,CAAC,EAAA,GAAM,IAAI,EAAA,QAAA,EAC/E,QAAQ,EAAA,CACL;AAEV;;;;"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { HTMLAttributes } from 'react';
|
|
2
|
+
import type { TagProps } from '../../shared/types/tag';
|
|
3
|
+
type Props = TagProps & HTMLAttributes<HTMLSpanElement>;
|
|
4
|
+
export declare function Tag({ variant, children, className, ...rest }: Props): import("react/jsx-runtime").JSX.Element;
|
|
5
|
+
export {};
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/react/Tag/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAE5C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAGvD,KAAK,KAAK,GAAG,QAAQ,GAAG,cAAc,CAAC,eAAe,CAAC,CAAC;AAExD,wBAAgB,GAAG,CAAC,EAAE,OAAmB,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,EAAE,KAAK,2CAM/E"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import cx from '../../_virtual/index.js';
|
|
3
|
+
import styles from '../../css/tag.module.css.js';
|
|
4
|
+
|
|
5
|
+
function Tag({ variant = 'default', children, className, ...rest }) {
|
|
6
|
+
return (jsx("span", { className: cx(styles.tag, styles[`tag--${variant}`], className), ...rest, children: children }));
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export { Tag };
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../src/react/Tag/index.tsx"],"sourcesContent":[null],"names":["_jsx"],"mappings":";;;;AAOM,SAAU,GAAG,CAAC,EAAE,OAAO,GAAG,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,IAAI,EAAS,EAAA;IAC9E,QACEA,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,QAAQ,OAAO,CAAA,CAAE,CAAC,EAAE,SAAS,CAAC,EAAA,GAAM,IAAI,EAAA,QAAA,EAC5E,QAAQ,EAAA,CACJ;AAEX;;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/react/ThemeToggle/index.tsx"],"names":[],"mappings":"AAMA,wBAAgB,WAAW,4CA6B1B"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { useState, useEffect } from 'react';
|
|
3
|
+
import cx from '../../_virtual/index.js';
|
|
4
|
+
import { getInitialTheme, applyTheme, persistTheme } from '../../shared/js/theme.js';
|
|
5
|
+
import styles from '../../css/theme-toggle.module.css.js';
|
|
6
|
+
|
|
7
|
+
function ThemeToggle() {
|
|
8
|
+
const [theme, setTheme] = useState('light');
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
const initial = getInitialTheme();
|
|
11
|
+
setTheme(initial);
|
|
12
|
+
applyTheme(initial);
|
|
13
|
+
}, []);
|
|
14
|
+
function toggle() {
|
|
15
|
+
const next = theme === 'light' ? 'dark' : 'light';
|
|
16
|
+
setTheme(next);
|
|
17
|
+
applyTheme(next);
|
|
18
|
+
persistTheme(next);
|
|
19
|
+
}
|
|
20
|
+
const isDark = theme === 'dark';
|
|
21
|
+
return (jsx("button", { type: "button", className: cx(styles['theme-toggle'], isDark && styles['theme-toggle--dark']), onClick: toggle, "aria-label": isDark ? 'Switch to light mode' : 'Switch to dark mode', "aria-pressed": isDark, children: isDark ? 'Dark' : 'Light' }));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export { ThemeToggle };
|
|
25
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../src/react/ThemeToggle/index.tsx"],"sourcesContent":[null],"names":["_jsx"],"mappings":";;;;;;SAMgB,WAAW,GAAA;IACzB,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAQ,OAAO,CAAC;IAElD,SAAS,CAAC,MAAK;AACb,QAAA,MAAM,OAAO,GAAG,eAAe,EAAE;QACjC,QAAQ,CAAC,OAAO,CAAC;QACjB,UAAU,CAAC,OAAO,CAAC;IACrB,CAAC,EAAE,EAAE,CAAC;AAEN,IAAA,SAAS,MAAM,GAAA;AACb,QAAA,MAAM,IAAI,GAAU,KAAK,KAAK,OAAO,GAAG,MAAM,GAAG,OAAO;QACxD,QAAQ,CAAC,IAAI,CAAC;QACd,UAAU,CAAC,IAAI,CAAC;QAChB,YAAY,CAAC,IAAI,CAAC;IACpB;AAEA,IAAA,MAAM,MAAM,GAAG,KAAK,KAAK,MAAM;IAE/B,QACEA,gBACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAE,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,MAAM,IAAI,MAAM,CAAC,oBAAoB,CAAC,CAAC,EAC7E,OAAO,EAAE,MAAM,EAAA,YAAA,EACH,MAAM,GAAG,sBAAsB,GAAG,qBAAqB,EAAA,cAAA,EACrD,MAAM,YAEnB,MAAM,GAAG,MAAM,GAAG,OAAO,EAAA,CACnB;AAEb;;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACxC,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../../src/shared/js/theme.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAInD,wBAAgB,eAAe,IAAI,KAAK,CAOvC;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAG7C;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAG/C"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const STORAGE_KEY = 'color-scheme';
|
|
2
|
+
function getInitialTheme() {
|
|
3
|
+
if (typeof window === 'undefined')
|
|
4
|
+
return 'light';
|
|
5
|
+
const stored = localStorage.getItem(STORAGE_KEY);
|
|
6
|
+
if (stored === 'light' || stored === 'dark')
|
|
7
|
+
return stored;
|
|
8
|
+
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
9
|
+
}
|
|
10
|
+
function applyTheme(theme) {
|
|
11
|
+
if (typeof window === 'undefined')
|
|
12
|
+
return;
|
|
13
|
+
document.documentElement.setAttribute('color-scheme', theme);
|
|
14
|
+
}
|
|
15
|
+
function persistTheme(theme) {
|
|
16
|
+
if (typeof window === 'undefined')
|
|
17
|
+
return;
|
|
18
|
+
localStorage.setItem(STORAGE_KEY, theme);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export { applyTheme, getInitialTheme, persistTheme };
|
|
22
|
+
//# sourceMappingURL=theme.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.js","sources":["../../../src/shared/js/theme.ts"],"sourcesContent":[null],"names":[],"mappings":"AAEA,MAAM,WAAW,GAAG,cAAc;SAElB,eAAe,GAAA;IAC7B,IAAI,OAAO,MAAM,KAAK,WAAW;AAAE,QAAA,OAAO,OAAO;IAEjD,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,WAAW,CAAC;AAChD,IAAA,IAAI,MAAM,KAAK,OAAO,IAAI,MAAM,KAAK,MAAM;AAAE,QAAA,OAAO,MAAM;AAE1D,IAAA,OAAO,MAAM,CAAC,UAAU,CAAC,8BAA8B,CAAC,CAAC,OAAO,GAAG,MAAM,GAAG,OAAO;AACrF;AAEM,SAAU,UAAU,CAAC,KAAY,EAAA;IACrC,IAAI,OAAO,MAAM,KAAK,WAAW;QAAE;IACnC,QAAQ,CAAC,eAAe,CAAC,YAAY,CAAC,cAAc,EAAE,KAAK,CAAC;AAC9D;AAEM,SAAU,YAAY,CAAC,KAAY,EAAA;IACvC,IAAI,OAAO,MAAM,KAAK,WAAW;QAAE;AACnC,IAAA,YAAY,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,CAAC;AAC1C;;;;"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type ButtonVariant = 'primary' | 'secondary' | 'outline' | 'ghost' | 'success';
|
|
2
|
+
export type ButtonSize = 'sm' | 'md' | 'lg' | 'small' | 'medium' | 'large';
|
|
3
|
+
export interface ButtonProps {
|
|
4
|
+
variant?: ButtonVariant;
|
|
5
|
+
size?: ButtonSize;
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=button.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"button.d.ts","sourceRoot":"","sources":["../../../src/shared/types/button.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;AACtF,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE3E,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"card.d.ts","sourceRoot":"","sources":["../../../src/shared/types/card.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,QAAQ,CAAC;AAE9C,MAAM,WAAW,SAAS;IACxB,SAAS,CAAC,EAAE,aAAa,CAAC;CAC3B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tag.d.ts","sourceRoot":"","sources":["../../../src/shared/types/tag.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE1D,MAAM,WAAW,QAAQ;IACvB,OAAO,CAAC,EAAE,UAAU,CAAC;CACtB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme-toggle.d.ts","sourceRoot":"","sources":["../../../src/shared/types/theme-toggle.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,KAAK,GAAG,OAAO,GAAG,MAAM,CAAC;AAErC,MAAM,WAAW,gBAAgB;CAEhC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/vue/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,OAAO,IAAI,GAAG,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,yBAAyB,CAAC"}
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
# Implementation Plan: Design System Components
|
|
2
|
+
|
|
3
|
+
## Architecture Overview
|
|
4
|
+
|
|
5
|
+
### Directory Structure
|
|
6
|
+
|
|
7
|
+
Framework-specific components are grouped by framework. CSS and shared logic live in a top-level `shared/` folder, keeping styling and utilities decoupled from any framework.
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
src/
|
|
11
|
+
css/
|
|
12
|
+
button.module.css # Button BEM + OOCSS classes
|
|
13
|
+
tag.module.css # Tag BEM + OOCSS classes
|
|
14
|
+
card.module.css # Card BEM + OOCSS classes
|
|
15
|
+
theme-toggle.module.css # ThemeToggle BEM + OOCSS classes
|
|
16
|
+
shared/
|
|
17
|
+
js/
|
|
18
|
+
theme.ts # ThemeToggle logic (read/write localStorage, apply color-scheme)
|
|
19
|
+
types/
|
|
20
|
+
button.ts # ButtonProps interface
|
|
21
|
+
tag.ts # TagProps interface
|
|
22
|
+
card.ts # CardProps interface
|
|
23
|
+
theme-toggle.ts # ThemeToggleProps interface
|
|
24
|
+
react/
|
|
25
|
+
Button/
|
|
26
|
+
index.tsx
|
|
27
|
+
index.test.tsx
|
|
28
|
+
Tag/
|
|
29
|
+
index.tsx
|
|
30
|
+
index.test.tsx
|
|
31
|
+
Card/
|
|
32
|
+
index.tsx
|
|
33
|
+
index.test.tsx
|
|
34
|
+
ThemeToggle/
|
|
35
|
+
index.tsx
|
|
36
|
+
index.test.tsx
|
|
37
|
+
index.ts # Barrel: exports all React components
|
|
38
|
+
astro/
|
|
39
|
+
Button/
|
|
40
|
+
index.astro
|
|
41
|
+
Tag/
|
|
42
|
+
index.astro
|
|
43
|
+
Card/
|
|
44
|
+
index.astro
|
|
45
|
+
ThemeToggle/
|
|
46
|
+
index.astro
|
|
47
|
+
index.ts # Barrel: exports all Astro components
|
|
48
|
+
vue/
|
|
49
|
+
Button/
|
|
50
|
+
index.vue
|
|
51
|
+
Tag/
|
|
52
|
+
index.vue
|
|
53
|
+
Card/
|
|
54
|
+
index.vue
|
|
55
|
+
ThemeToggle/
|
|
56
|
+
index.vue
|
|
57
|
+
index.ts # Barrel: exports all Vue components
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Styling Strategy
|
|
61
|
+
|
|
62
|
+
- **CSS Modules** for component-scoped styles, located in `src/css/`.
|
|
63
|
+
- **BEM** for class naming within each module: block (`button`), element (`button__label`), modifier (`button--primary`, `button--sm`, `button--disabled`).
|
|
64
|
+
- **OOCSS** to separate structural responsibility from skin responsibility:
|
|
65
|
+
- *Structure classes* define layout, sizing, spacing, and display behaviour (e.g. `.button`, `.card`).
|
|
66
|
+
- *Skin classes* define colour, border, shadow, and typography (e.g. `.button--primary`, `.tag--success`, `.card--raised`).
|
|
67
|
+
- Framework files compose both structure and skin classes together.
|
|
68
|
+
- All colour, spacing, and font values use CSS custom properties from `@dezkareid/design-tokens`.
|
|
69
|
+
- Semantic tokens (`--color-background-primary`, `--color-text-primary`, etc.) are used exclusively — no raw hex/px values.
|
|
70
|
+
|
|
71
|
+
### Theming
|
|
72
|
+
|
|
73
|
+
- The `color-scheme` attribute on `<html>` drives light/dark switching.
|
|
74
|
+
- `ThemeToggle` is the only component that reads/writes theme state. All other components are passive consumers of semantic tokens.
|
|
75
|
+
- `ThemeToggle` uses `localStorage` (key: `color-scheme`) for persistence and falls back to `prefers-color-scheme`.
|
|
76
|
+
|
|
77
|
+
### TypeScript
|
|
78
|
+
|
|
79
|
+
- Shared prop interfaces/types are defined in `src/shared/types/<component>.ts` and imported by all three framework implementations.
|
|
80
|
+
- Strict typing; no `any`.
|
|
81
|
+
|
|
82
|
+
### Testing
|
|
83
|
+
|
|
84
|
+
- React implementations only (as per spec).
|
|
85
|
+
- Vitest + React Testing Library.
|
|
86
|
+
- Tests cover: rendering variants, disabled states, slot/children content, ThemeToggle localStorage and OS-preference behaviour.
|
|
87
|
+
|
|
88
|
+
### Entry Points
|
|
89
|
+
|
|
90
|
+
The package will expose three sub-path exports:
|
|
91
|
+
- `@dezkareid/components/react` → all React components
|
|
92
|
+
- `@dezkareid/components/astro` → all Astro components
|
|
93
|
+
- `@dezkareid/components/vue` → all Vue components
|
|
94
|
+
|
|
95
|
+
`package.json` `exports` field will be configured accordingly.
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Implementation Phases
|
|
100
|
+
|
|
101
|
+
### Phase 1 — Package Setup
|
|
102
|
+
|
|
103
|
+
**Goal**: Establish the build infrastructure, folder layout, and entry points before writing any component code.
|
|
104
|
+
|
|
105
|
+
- Configure `package.json` with `exports` for `react/`, `astro/`, and `vue/` sub-paths.
|
|
106
|
+
- Create the full directory skeleton: `src/css/`, `src/shared/js/`, `src/shared/types/`, `src/react/`, `src/astro/`, `src/vue/`.
|
|
107
|
+
- Create barrel `index.ts` files for each framework entry point (`src/react/index.ts`, `src/astro/index.ts`, `src/vue/index.ts`).
|
|
108
|
+
- Verify that `@dezkareid/design-tokens` is available as a dependency and that its CSS token file can be imported from `src/css/`.
|
|
109
|
+
- Set up Vitest config (if not present) targeting `src/react/**/*.test.tsx`.
|
|
110
|
+
|
|
111
|
+
### Phase 2 — Button Component
|
|
112
|
+
|
|
113
|
+
**Goal**: Implement the Button component across all three frameworks with full variant, size, and disabled support.
|
|
114
|
+
|
|
115
|
+
- Define `ButtonProps` in `src/shared/types/button.ts`: `variant: 'primary' | 'secondary'`, `size: 'sm' | 'md' | 'lg'`, `disabled?: boolean`, `children/slot`.
|
|
116
|
+
- Write `src/css/button.module.css` using BEM + OOCSS:
|
|
117
|
+
- **Structure**: `.button` — `display: inline-flex`, `align-items: center`, `cursor: pointer`, `border: none`, `border-radius`.
|
|
118
|
+
- **Structure modifiers** (size): `.button--sm`, `.button--md`, `.button--lg` — vary `padding` and `font-size` via spacing/font tokens.
|
|
119
|
+
- **Skin modifiers** (variant): `.button--primary` — `background-color: var(--color-primary)`, `color: var(--color-text-inverse)`; `.button--secondary` — `background-color: transparent`, `border: 1px solid var(--color-primary)`, `color: var(--color-primary)`.
|
|
120
|
+
- **State modifier**: `.button--disabled` — reduced opacity, `cursor: not-allowed`, `pointer-events: none`.
|
|
121
|
+
- Implement `src/react/Button/index.tsx` — renders `<button>`, composes BEM classes from CSS module, passes through native button props.
|
|
122
|
+
- Implement `src/astro/Button/index.astro`.
|
|
123
|
+
- Implement `src/vue/Button/index.vue`.
|
|
124
|
+
- Write `src/react/Button/index.test.tsx`: renders each variant, renders each size, disabled prevents click, accessible role.
|
|
125
|
+
|
|
126
|
+
### Phase 3 — Tag Component
|
|
127
|
+
|
|
128
|
+
**Goal**: Implement the Tag component across all three frameworks with semantic colour variants and children support.
|
|
129
|
+
|
|
130
|
+
- Define `TagProps` in `src/shared/types/tag.ts`: `variant: 'default' | 'success' | 'danger'`, `children/slot`.
|
|
131
|
+
- Write `src/css/tag.module.css` using BEM + OOCSS:
|
|
132
|
+
- **Structure**: `.tag` — `display: inline-flex`, `align-items: center`, `border-radius`, `padding: var(--spacing-4) var(--spacing-8)`, `font-size: var(--font-size-100)`.
|
|
133
|
+
- **Skin modifiers** (variant): `.tag--default` — `background-color: var(--color-background-secondary)`, `color: var(--color-text-primary)`; `.tag--success` — `background-color: var(--color-success)`, `color: var(--color-text-inverse)`; `.tag--danger` — `background-color: var(--color-base-red-500)`, `color: var(--color-text-inverse)`. *(Note: propose `--color-danger` semantic token for the design-tokens package.)*
|
|
134
|
+
- Implement `src/react/Tag/index.tsx` — renders a `<span>`, composes BEM classes, accepts `children`.
|
|
135
|
+
- Implement `src/astro/Tag/index.astro`.
|
|
136
|
+
- Implement `src/vue/Tag/index.vue`.
|
|
137
|
+
- Write `src/react/Tag/index.test.tsx`: renders each variant, renders slot/children content.
|
|
138
|
+
|
|
139
|
+
### Phase 4 — Card Component
|
|
140
|
+
|
|
141
|
+
**Goal**: Implement the Card component across all three frameworks with flat and raised elevation.
|
|
142
|
+
|
|
143
|
+
- Define `CardProps` in `src/shared/types/card.ts`: `elevation?: 'flat' | 'raised'` (default: `'raised'`), `children/slot`.
|
|
144
|
+
- Write `src/css/card.module.css` using BEM + OOCSS:
|
|
145
|
+
- **Structure**: `.card` — `display: block`, `border-radius`, `padding: var(--spacing-24)`, `width: 100%`.
|
|
146
|
+
- **Skin** (base): `.card` — `background-color: var(--color-background-secondary)`, `color: var(--color-text-primary)`.
|
|
147
|
+
- **Skin modifiers** (elevation): `.card--raised` — `box-shadow: 0 2px 8px rgba(0,0,0,0.12)` *(propose `--shadow-raised` token)*; `.card--flat` — no shadow.
|
|
148
|
+
- Implement `src/react/Card/index.tsx` — renders a `<div>`, composes BEM classes, accepts `children`.
|
|
149
|
+
- Implement `src/astro/Card/index.astro`.
|
|
150
|
+
- Implement `src/vue/Card/index.vue`.
|
|
151
|
+
- Write `src/react/Card/index.test.tsx`: renders children, applies correct elevation class.
|
|
152
|
+
|
|
153
|
+
### Phase 5 — ThemeToggle Component
|
|
154
|
+
|
|
155
|
+
**Goal**: Implement the ThemeToggle component across all three frameworks with localStorage persistence and OS preference fallback.
|
|
156
|
+
|
|
157
|
+
- Define `ThemeToggleProps` in `src/shared/types/theme-toggle.ts`: no required props (self-contained stateful component).
|
|
158
|
+
- Extract shared theme logic to `src/shared/js/theme.ts`:
|
|
159
|
+
- `getInitialTheme(): 'light' | 'dark'` — reads `localStorage.getItem('color-scheme')`; falls back to `window.matchMedia('(prefers-color-scheme: dark)').matches`.
|
|
160
|
+
- `applyTheme(theme: 'light' | 'dark'): void` — sets `document.documentElement.setAttribute('color-scheme', theme)`.
|
|
161
|
+
- `persistTheme(theme: 'light' | 'dark'): void` — writes to `localStorage`.
|
|
162
|
+
- All functions guard against `typeof window === 'undefined'` for SSR safety.
|
|
163
|
+
- Write `src/css/theme-toggle.module.css` using BEM + OOCSS:
|
|
164
|
+
- **Structure**: `.theme-toggle` — `display: inline-flex`, `align-items: center`, `cursor: pointer`, `padding`, `border: none`.
|
|
165
|
+
- **Skin**: `.theme-toggle` — `background-color: transparent`, `color: var(--color-text-primary)`.
|
|
166
|
+
- **State modifier**: `.theme-toggle--dark` — visual indicator for dark mode active state.
|
|
167
|
+
- Implement `src/react/ThemeToggle/index.tsx` — uses `useState` + `useEffect`, calls `src/shared/js/theme.ts` utilities.
|
|
168
|
+
- Implement `src/astro/ThemeToggle/index.astro` — static markup + inline `<script>` that imports and calls `src/shared/js/theme.ts`.
|
|
169
|
+
- Implement `src/vue/ThemeToggle/index.vue` — uses `ref` + `onMounted`, calls shared utilities.
|
|
170
|
+
- Write `src/react/ThemeToggle/index.test.tsx`: initialises from `localStorage`, initialises from `prefers-color-scheme` when no stored value, toggles on click, persists to `localStorage`.
|
|
171
|
+
|
|
172
|
+
### Phase 6 — Exports & Package Configuration
|
|
173
|
+
|
|
174
|
+
**Goal**: Wire all components into the entry points and validate the exports map.
|
|
175
|
+
|
|
176
|
+
- Update `src/react/index.ts` to re-export `Button`, `Tag`, `Card`, `ThemeToggle` from their respective sub-folders.
|
|
177
|
+
- Update `src/astro/index.ts` to re-export Astro components.
|
|
178
|
+
- Update `src/vue/index.ts` to re-export Vue components.
|
|
179
|
+
- Update `package.json` `exports`:
|
|
180
|
+
```json
|
|
181
|
+
{
|
|
182
|
+
"./react": "./src/react/index.ts",
|
|
183
|
+
"./astro": "./src/astro/index.ts",
|
|
184
|
+
"./vue": "./src/vue/index.ts"
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
- Verify build compiles without errors.
|
|
188
|
+
|
|
189
|
+
### Phase 7 — Documentation
|
|
190
|
+
|
|
191
|
+
**Goal**: Update `README.md` and `AGENTS.md` to reflect the new components.
|
|
192
|
+
|
|
193
|
+
- Add installation note for `@dezkareid/design-tokens` CSS requirement.
|
|
194
|
+
- Add usage examples for each component in each framework format.
|
|
195
|
+
- Update `AGENTS.md` with component API summaries.
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## Technical Dependencies
|
|
200
|
+
|
|
201
|
+
| Dependency | Purpose | Already Present? |
|
|
202
|
+
|---|---|---|
|
|
203
|
+
| `@dezkareid/design-tokens` | CSS token variables | To verify |
|
|
204
|
+
| `react` / `react-dom` | React runtime | Peer dep |
|
|
205
|
+
| `vue` | Vue runtime | To add as peer dep |
|
|
206
|
+
| `astro` | Astro runtime | To add as peer dep |
|
|
207
|
+
| `vitest` | Test runner | To configure |
|
|
208
|
+
| `@testing-library/react` | React test utilities | To configure |
|
|
209
|
+
| `jsdom` | DOM environment for tests | To configure |
|
|
210
|
+
| `typescript` | Type checking | To configure |
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## Risks & Mitigations
|
|
215
|
+
|
|
216
|
+
| Risk | Mitigation |
|
|
217
|
+
|---|---|
|
|
218
|
+
| Missing semantic tokens (e.g. `--color-danger`, `--shadow-raised`) | Use base tokens as fallback; add inline comments proposing new tokens to the design-tokens package |
|
|
219
|
+
| CSS Modules not supported in Astro/Vue by default | Astro natively supports CSS Modules; Vue supports them via `<style module>` — both are straightforward |
|
|
220
|
+
| `localStorage` access in SSR/Astro contexts | Wrap all `localStorage` access in `typeof window !== 'undefined'` guards; use `is:inline` or `client:load` in Astro |
|
|
221
|
+
| ThemeToggle hydration flash (FOUC) | Emit an inline `<script>` that applies the theme before first paint (Astro strategy); React version uses `useEffect` which may flash — document as a known limitation |
|
|
222
|
+
| Vue not yet configured as a peer dependency | Add `vue` peer dep to `package.json` in Phase 1 |
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## Out of Scope
|
|
227
|
+
|
|
228
|
+
- Icon library (no icon assets bundled with components).
|
|
229
|
+
- Animation/transition system.
|
|
230
|
+
- Loading state or icon-only Button variant.
|
|
231
|
+
- Storybook or visual regression tooling.
|
|
232
|
+
- SSR-optimised theme detection beyond the `<script>` injection approach.
|
|
233
|
+
- Astro and Vue unit tests (React tests only, per spec).
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Feature Specification: Design System Components
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Add four foundational UI components — **Button**, **Tag**, **Card**, and **ThemeToggle** — to the `@dezkareid/components` package. These components form the core building blocks of the personal design system, enabling consistent, accessible, and theme-aware UI across all surfaces that consume the package (React, Astro, Vue).
|
|
6
|
+
|
|
7
|
+
Each component must ship in all three framework formats (React, Astro, Vue), use design tokens for all visual properties, and support light/dark theming automatically.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Requirements
|
|
12
|
+
|
|
13
|
+
### Button
|
|
14
|
+
|
|
15
|
+
- Renders a clickable element that triggers an action.
|
|
16
|
+
- Supports at least two visual variants: **primary** (filled) and **secondary** (outlined).
|
|
17
|
+
- Supports a **disabled** state that prevents interaction and communicates non-interactivity visually.
|
|
18
|
+
- Accepts a label via slot/children.
|
|
19
|
+
- Must be keyboard-accessible and announce its role to assistive technologies.
|
|
20
|
+
|
|
21
|
+
### Tag
|
|
22
|
+
|
|
23
|
+
- Renders a small inline label used to categorise or annotate content.
|
|
24
|
+
- Supports at least three semantic colour variants: **default**, **success**, and **danger**.
|
|
25
|
+
- Is non-interactive (display only).
|
|
26
|
+
- Text content is passed via slot/children.
|
|
27
|
+
- Must be readable by assistive technologies (appropriate role/label).
|
|
28
|
+
|
|
29
|
+
### Card
|
|
30
|
+
|
|
31
|
+
- Renders a contained surface that groups related content.
|
|
32
|
+
- Accepts arbitrary content via slot/children (title, body, actions).
|
|
33
|
+
- Provides consistent internal spacing and a distinct background relative to the page.
|
|
34
|
+
- Must be usable as a layout container with no fixed height.
|
|
35
|
+
|
|
36
|
+
### ThemeToggle
|
|
37
|
+
|
|
38
|
+
- Renders a toggle control that switches the active colour scheme between light and dark.
|
|
39
|
+
- The current theme state is reflected visually (icon or label change).
|
|
40
|
+
- Toggling persists the preference to `localStorage` under the key `color-scheme`.
|
|
41
|
+
- On initial load, reads `localStorage` first; falls back to the OS `prefers-color-scheme` preference.
|
|
42
|
+
- Theme is applied by setting `color-scheme` on the `<html>` element (`light` or `dark`).
|
|
43
|
+
- Must be keyboard-accessible and communicate its current state to assistive technologies.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Scope
|
|
48
|
+
|
|
49
|
+
### In scope
|
|
50
|
+
|
|
51
|
+
- React, Astro, and Vue implementations for all four components.
|
|
52
|
+
- Design-token-driven styling (no hardcoded colour or spacing values).
|
|
53
|
+
- Automatic light/dark theme support via CSS semantic tokens.
|
|
54
|
+
- Accessible markup (keyboard navigation, ARIA roles/attributes where needed).
|
|
55
|
+
- Mobile-first responsive behaviour.
|
|
56
|
+
- Unit/integration tests for the React implementations.
|
|
57
|
+
- TypeScript prop types/interfaces for all components.
|
|
58
|
+
- Updated `README.md` and `AGENTS.md` with usage examples for each component.
|
|
59
|
+
|
|
60
|
+
### Out of scope
|
|
61
|
+
|
|
62
|
+
- Icon library integration (icons may be addressed as a follow-up).
|
|
63
|
+
- Animation or transition systems.
|
|
64
|
+
- Complex compound variants (e.g. icon-only Button, loading state).
|
|
65
|
+
- Storybook or visual regression tooling.
|
|
66
|
+
- Server-side rendering (SSR) specific configuration.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Acceptance Criteria
|
|
71
|
+
|
|
72
|
+
1. **Button** renders correctly in primary and secondary variants and is disabled when `disabled` is set.
|
|
73
|
+
2. **Tag** renders in default, success, and danger variants using the correct semantic colour tokens.
|
|
74
|
+
3. **Card** renders its children inside a visually distinct surface with consistent spacing.
|
|
75
|
+
4. **ThemeToggle** switches the `color-scheme` attribute on `<html>` and persists the value to `localStorage`.
|
|
76
|
+
5. **ThemeToggle** reads `localStorage` on mount and applies the stored value; if absent, applies the OS preference.
|
|
77
|
+
6. All components pass accessibility checks (keyboard focus, ARIA) without errors.
|
|
78
|
+
7. All components render correctly in both light and dark modes using semantic tokens only.
|
|
79
|
+
8. React implementations have passing unit tests.
|
|
80
|
+
9. Each component is exported from the appropriate entry point (`react/`, `astro/`, `vue/`).
|
|
81
|
+
10. `README.md` includes import and usage examples for all four components.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Decisions
|
|
86
|
+
|
|
87
|
+
1. **Button sizes**: Button will support three size variants — small, medium, and large — via a `size` prop.
|
|
88
|
+
2. **Tag dismissibility**: Tag remains display-only with no close action. It must accept arbitrary content via slot/children (not just a plain text string).
|
|
89
|
+
3. **Card elevation**: Card will support two elevation levels — **flat** (no shadow) and **raised** (with shadow) — via an `elevation` prop.
|
|
90
|
+
4. **ThemeToggle framework scope**: ThemeToggle will ship in all three framework formats (React, Astro, Vue), consistent with the other components.
|