ali-mohammadi-design-system 1.0.0 → 2.0.1

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/package.json CHANGED
@@ -1,27 +1,46 @@
1
-
2
-
3
1
  {
4
- "name": "ali-mohammadi-design-system",
5
- "version": "1.0.0",
2
+ "name": "ali-mohammadi-design-system",
3
+ "version": "2.0.1",
6
4
  "description": "خنثی و dynamic Design System — tokens از پروژه میاد",
7
- "main": "src/index.js",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
8
  "files": [
9
- "src",
10
- "scss"
9
+ "dist",
10
+ "src"
11
11
  ],
12
- "exports": {
13
- ".": "./src/index.js",
14
- "./scss": "./scss/index.scss"
12
+ "keywords": [
13
+ "design-system",
14
+ "ui",
15
+ "react",
16
+ "tokens",
17
+ "sass"
18
+ ],
19
+ "author": "ali mohammadi",
20
+ "license": "MIT",
21
+ "publishConfig": {
22
+ "access": "public"
23
+ },
24
+ "scripts": {
25
+ "build": "vite build",
26
+ "prepublishOnly": "npm run build"
15
27
  },
16
28
  "peerDependencies": {
17
- "react": "^18.0.0",
18
- "prop-types": "^15.8.1"
29
+ "prop-types": "^15.8.1",
30
+ "react": ">=18 <20",
31
+ "react-dom": ">=18 <20"
19
32
  },
20
- "keywords": ["design-system", "ui", "react", "tokens", "sass"],
21
- "author": "شرکت شما",
22
- "license": "MIT",
23
- "publishConfig": {
24
- "access": "public"
33
+ "exports": {
34
+ ".": {
35
+ "import": "./dist/index.js",
36
+ "require": "./dist/index.cjs"
37
+ },
38
+ "./theme": "./dist/theme/index.js",
39
+ "./tokens": "./dist/tokens/index.js",
40
+ "./components": "./dist/components/index.js"
41
+ },
42
+ "type": "module",
43
+ "devDependencies": {
44
+ "@vitejs/plugin-react": "^5.1.2"
45
+ }
25
46
  }
26
-
27
- }
@@ -1,41 +1,92 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
+ import { useTokens } from '../../utils/useTokens.js';
3
4
 
5
+ /**
6
+ * Button Component - کامپوننت دکمه با پشتیبانی از تم
7
+ *
8
+ * @example
9
+ * ```jsx
10
+ * import { Button } from 'ali-mohammadi-design-system';
11
+ *
12
+ * <Button variant="primary" size="md">Click me</Button>
13
+ * <Button variant="outline" size="lg">Outline Button</Button>
14
+ * ```
15
+ */
4
16
  const Button = ({ variant = 'primary', size = 'md', children, className = '', ...props }) => {
17
+ const { color, spacing, radius, typography } = useTokens();
18
+
5
19
  const variantStyles = {
6
20
  primary: {
7
- backgroundColor: 'var(--primary-500)',
8
- color: 'white',
21
+ backgroundColor: color('primary.500'),
22
+ color: '#ffffff',
23
+ border: 'none',
9
24
  },
10
25
  outline: {
11
26
  backgroundColor: 'transparent',
12
- border: '2px solid var(--primary-500)',
13
- color: 'var(--primary-500)',
27
+ border: `2px solid ${color('primary.500')}`,
28
+ color: color('primary.500'),
14
29
  },
15
30
  text: {
16
31
  backgroundColor: 'transparent',
17
- color: 'var(--primary-500)',
32
+ border: 'none',
33
+ color: color('primary.500'),
34
+ },
35
+ secondary: {
36
+ backgroundColor: color('neutral.200'),
37
+ color: color('neutral.900'),
38
+ border: 'none',
39
+ },
40
+ success: {
41
+ backgroundColor: color('success.500'),
42
+ color: '#ffffff',
43
+ border: 'none',
44
+ },
45
+ error: {
46
+ backgroundColor: color('error.500'),
47
+ color: '#ffffff',
48
+ border: 'none',
18
49
  },
19
50
  };
20
51
 
21
- const sizePadding = {
22
- sm: 'var(--space-sm)',
23
- md: 'var(--space-md)',
24
- lg: 'var(--space-lg)',
52
+ const sizeStyles = {
53
+ sm: {
54
+ padding: `${spacing(2)} ${spacing(4)}`,
55
+ fontSize: typography('sizes.14') || '14px',
56
+ },
57
+ md: {
58
+ padding: `${spacing(3)} ${spacing(6)}`,
59
+ fontSize: typography('sizes.16') || '16px',
60
+ },
61
+ lg: {
62
+ padding: `${spacing(4)} ${spacing(8)}`,
63
+ fontSize: typography('sizes.18') || '18px',
64
+ },
25
65
  };
26
66
 
27
67
  return (
28
68
  <button
29
- className={`ds-button ${className}`}
69
+ className={`ds-button ds-button--${variant} ds-button--${size} ${className}`}
30
70
  style={{
31
- padding: `${sizePadding[size]} calc(var(--space-unit) * 4)`,
32
- borderRadius: 'var(--radius-md)',
33
- fontFamily: 'var(--font-family)',
34
- fontSize: '1rem',
71
+ borderRadius: radius('md'),
72
+ fontFamily: typography('fontFamily'),
73
+ fontWeight: '500',
35
74
  cursor: 'pointer',
75
+ transition: 'all 0.2s ease',
36
76
  ...variantStyles[variant],
77
+ ...sizeStyles[size],
37
78
  ...props.style,
38
79
  }}
80
+ onMouseEnter={(e) => {
81
+ if (variant === 'primary') {
82
+ e.currentTarget.style.opacity = '0.9';
83
+ }
84
+ }}
85
+ onMouseLeave={(e) => {
86
+ if (variant === 'primary') {
87
+ e.currentTarget.style.opacity = '1';
88
+ }
89
+ }}
39
90
  {...props}
40
91
  >
41
92
  {children}
@@ -45,7 +96,7 @@ const Button = ({ variant = 'primary', size = 'md', children, className = '', ..
45
96
 
46
97
  Button.propTypes = {
47
98
  children: PropTypes.node.isRequired,
48
- variant: PropTypes.oneOf(['primary', 'outline', 'text']),
99
+ variant: PropTypes.oneOf(['primary', 'outline', 'text', 'secondary', 'success', 'error']),
49
100
  size: PropTypes.oneOf(['sm', 'md', 'lg']),
50
101
  className: PropTypes.string,
51
102
  };
@@ -0,0 +1,5 @@
1
+ export { default as Button } from './Button/Button.jsx';
2
+ // Export سایر کامپوننت‌ها اینجا اضافه می‌شوند
3
+ // export { default as Input } from './Input/Input.jsx';
4
+ // export { default as Card } from './Card/Card.jsx';
5
+
package/src/index.js CHANGED
@@ -1,6 +1,20 @@
1
- export { injectCSS } from './theme/injectCSS';
2
- export { defaultConfig } from './config/defaultConfig';
3
- export * from './tokens/colors';
1
+ // Export کامپوننت‌ها
2
+ export * from './components/index.js';
4
3
 
5
- export { default as Button } from './components/Button';
6
- // export بقیه کامپوننت‌ها...
4
+ // Export Theme Provider و Hooks
5
+ export { ThemeProvider, useTheme } from './theme/ThemeProvider.jsx';
6
+ export { useTokens } from './utils/useTokens.js';
7
+
8
+ // Export توکن‌ها
9
+ export { defaultTokens, baseTokens, createTokens, defaultColors } from './tokens/index.js';
10
+
11
+ // Export توابع تم
12
+ export { generateTheme } from './theme/generateTheme.js';
13
+ export { injectCSS } from './theme/injectCSS.js';
14
+ export { generateSCSS } from './theme/generateSCSS.js';
15
+
16
+ // Export پیش‌فرض
17
+ export { defaultConfig } from './config/index.js';
18
+
19
+ // Default export برای راحتی
20
+ export { ThemeProvider as default } from './theme/ThemeProvider.jsx';
@@ -0,0 +1,107 @@
1
+ import React, { createContext, useContext, useEffect, useMemo } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { createTokens } from '../tokens/index.js';
4
+ import { generateTheme } from './generateTheme.js';
5
+
6
+ const ThemeContext = createContext(null);
7
+
8
+ /**
9
+ * ThemeProvider - مدیریت تم و توکن‌ها در پروژه
10
+ *
11
+ * @example
12
+ * ```jsx
13
+ * import { ThemeProvider } from 'ali-mohammadi-design-system';
14
+ *
15
+ * const customTokens = {
16
+ * colors: {
17
+ * primary: { 500: '#6366f1' }
18
+ * }
19
+ * };
20
+ *
21
+ * <ThemeProvider tokens={customTokens}>
22
+ * <App />
23
+ * </ThemeProvider>
24
+ * ```
25
+ */
26
+ export function ThemeProvider({ tokens = {}, children }) {
27
+ const mergedTokens = useMemo(() => {
28
+ return createTokens(tokens);
29
+ }, [tokens]);
30
+
31
+ useEffect(() => {
32
+ // تزریق CSS variables به DOM
33
+ generateTheme(mergedTokens);
34
+ }, [mergedTokens]);
35
+
36
+ const value = useMemo(() => ({
37
+ tokens: mergedTokens,
38
+ getToken: (path) => {
39
+ const keys = path.split('.');
40
+ let value = mergedTokens;
41
+ for (const key of keys) {
42
+ if (value && typeof value === 'object' && key in value) {
43
+ value = value[key];
44
+ } else {
45
+ return undefined;
46
+ }
47
+ }
48
+ return value;
49
+ },
50
+ }), [mergedTokens]);
51
+
52
+ return (
53
+ <ThemeContext.Provider value={value}>
54
+ {children}
55
+ </ThemeContext.Provider>
56
+ );
57
+ }
58
+
59
+ ThemeProvider.propTypes = {
60
+ tokens: PropTypes.object,
61
+ children: PropTypes.node.isRequired,
62
+ };
63
+
64
+ /**
65
+ * Hook برای دسترسی به تم و توکن‌ها
66
+ *
67
+ * @example
68
+ * ```jsx
69
+ * import { useTheme } from 'ali-mohammadi-design-system';
70
+ *
71
+ * function MyComponent() {
72
+ * const { tokens, getToken } = useTheme();
73
+ * const primaryColor = getToken('colors.primary.500');
74
+ * return <div style={{ color: primaryColor }}>Hello</div>;
75
+ * }
76
+ * ```
77
+ */
78
+ export function useTheme() {
79
+ const context = useContext(ThemeContext);
80
+
81
+ if (!context) {
82
+ // اگر ThemeProvider استفاده نشده، از توکن‌های پیش‌فرض استفاده کن
83
+ console.warn('useTheme must be used within ThemeProvider. Using default tokens.');
84
+ const { createTokens } = require('../tokens/index.js');
85
+ const defaultTokens = createTokens();
86
+ return {
87
+ tokens: defaultTokens,
88
+ getToken: (path) => {
89
+ const keys = path.split('.');
90
+ let value = defaultTokens;
91
+ for (const key of keys) {
92
+ if (value && typeof value === 'object' && key in value) {
93
+ value = value[key];
94
+ } else {
95
+ return undefined;
96
+ }
97
+ }
98
+ return value;
99
+ },
100
+ };
101
+ }
102
+
103
+ return context;
104
+ }
105
+
106
+ export default ThemeProvider;
107
+
@@ -1,34 +1,11 @@
1
- export function generateTheme(userTokens = {}) {
2
- const defaultTokens = {
3
- colors: {
4
- primary: { 500: '#6366f1' },
5
- neutral: { 900: '#111827', 700: '#374151', 500: '#6b7280', 300: '#d1d5db', 100: '#f3f4f6', 0: '#ffffff' },
6
- success: { 500: '#10b981' },
7
- error: { 500: '#ef4444' },
8
- warning: { 500: '#f59e0b' },
9
- info: { 500: '#3b82f6' },
10
- },
11
- typography: {
12
- fontFamily: 'system-ui, sans-serif',
13
- baseSize: 16,
14
- minSize: 14,
15
- scaleRatio: 1.25,
16
- },
17
- spacing: { unit: 4 },
18
- radius: { sm: 4, md: 8, lg: 12, xl: 16, full: 9999 },
19
- };
20
-
21
- const tokens = {
22
- colors: { ...defaultTokens.colors, ...(userTokens.colors || {}) },
23
- typography: { ...defaultTokens.typography, ...(userTokens.typography || {}) },
24
- spacing: { ...defaultTokens.spacing, ...(userTokens.spacing || {}) },
25
- radius: { ...defaultTokens.radius, ...(userTokens.radius || {}) },
26
- };
1
+ import { createTokens } from '../tokens/index.js';
27
2
 
28
- const t = tokens.typography;
29
- const slope = (t.baseSize - t.minSize) / (1920 - 320);
30
- const yIntersection = -320 * slope + t.minSize;
31
- const preferredValue = `${yIntersection}px + ${slope * 100}vw`;
3
+ /**
4
+ * تولید CSS variables از توکن‌ها و تزریق به DOM
5
+ * @param {Object} userTokens - توکن‌های سفارشی کاربر
6
+ */
7
+ export function generateTheme(userTokens = {}) {
8
+ const tokens = createTokens(userTokens);
32
9
 
33
10
  const style = document.createElement('style');
34
11
  style.id = 'ds-theme';
@@ -45,23 +22,64 @@ export function generateTheme(userTokens = {}) {
45
22
  });
46
23
 
47
24
  // Typography
25
+ const t = tokens.typography;
48
26
  css += ` --font-family: ${t.fontFamily};\n`;
49
- css += ` --font-size-base: clamp(${t.minSize}px, ${preferredValue}, ${t.baseSize}px);\n`;
50
- css += ` --type-scale: ${t.scaleRatio};\n`;
27
+
28
+ if (t.baseSize && t.minSize) {
29
+ const slope = (t.baseSize - t.minSize) / (1920 - 320);
30
+ const yIntersection = -320 * slope + t.minSize;
31
+ const preferredValue = `${yIntersection}px + ${slope * 100}vw`;
32
+ css += ` --font-size-base: clamp(${t.minSize}px, ${preferredValue}, ${t.baseSize}px);\n`;
33
+ } else {
34
+ css += ` --font-size-base: ${t.baseSize || 16}px;\n`;
35
+ }
36
+
37
+ css += ` --type-scale: ${t.scaleRatio || 1.25};\n`;
38
+
39
+ // Typography sizes
40
+ if (t.sizes) {
41
+ Object.entries(t.sizes).forEach(([key, value]) => {
42
+ css += ` --font-size-${key}: ${value}px;\n`;
43
+ });
44
+ }
45
+
46
+ // Typography line heights
47
+ if (t.lineHeights) {
48
+ Object.entries(t.lineHeights).forEach(([key, value]) => {
49
+ css += ` --line-height-${key}: ${value}px;\n`;
50
+ });
51
+ }
52
+
53
+ // Typography weights
54
+ if (t.weights) {
55
+ Object.entries(t.weights).forEach(([key, value]) => {
56
+ css += ` --font-weight-${key}: ${value};\n`;
57
+ });
58
+ }
51
59
 
52
60
  // Spacing
53
- css += ` --space-unit: ${tokens.spacing.unit}px;\n`;
54
- css += ` --space-xs: calc(var(--space-unit) * 1);\n`;
55
- css += ` --space-sm: calc(var(--space-unit) * 2);\n`;
56
- css += ` --space-md: calc(var(--space-unit) * 4);\n`;
57
- css += ` --space-lg: calc(var(--space-unit) * 6);\n`;
58
- css += ` --space-xl: calc(var(--space-unit) * 8);\n`;
61
+ const spacingUnit = tokens.spacing.unit || 4;
62
+ css += ` --space-unit: ${spacingUnit}px;\n`;
63
+
64
+ // Spacing values
65
+ Object.entries(tokens.spacing).forEach(([key, value]) => {
66
+ if (key !== 'unit') {
67
+ css += ` --space-${key}: ${value}px;\n`;
68
+ }
69
+ });
59
70
 
60
71
  // Radius
61
72
  Object.entries(tokens.radius).forEach(([k, v]) => {
62
73
  css += ` --radius-${k}: ${v}px;\n`;
63
74
  });
64
75
 
76
+ // Shadows
77
+ if (tokens.shadows) {
78
+ Object.entries(tokens.shadows).forEach(([k, v]) => {
79
+ css += ` --shadow-${k}: ${v};\n`;
80
+ });
81
+ }
82
+
65
83
  css += '}\n';
66
84
  css += 'html { font-size: var(--font-size-base); }\n';
67
85
  css += 'body { font-family: var(--font-family); }\n';
@@ -0,0 +1,5 @@
1
+ export { ThemeProvider, useTheme } from './ThemeProvider.jsx';
2
+ export { generateTheme } from './generateTheme.js';
3
+ export { injectCSS } from './injectCSS.js';
4
+ export { generateSCSS } from './generateSCSS.js';
5
+