elementdrawing 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.
Files changed (78) hide show
  1. package/LICENSE +21 -0
  2. package/dist/elementdrawing.min.js +3 -0
  3. package/dist/elementdrawing.min.js.LICENSE.txt +8 -0
  4. package/dist/elementdrawing.min.js.map +1 -0
  5. package/dist/index.html +1 -0
  6. package/package.json +127 -0
  7. package/src/core/bridge.h +855 -0
  8. package/src/core/diff.c +900 -0
  9. package/src/core/element.c +1078 -0
  10. package/src/core/event.c +813 -0
  11. package/src/core/fiber.c +1027 -0
  12. package/src/core/hooks.c +919 -0
  13. package/src/core/renderer.c +963 -0
  14. package/src/core/scheduler.c +702 -0
  15. package/src/core/state.c +803 -0
  16. package/src/css/animations.css +779 -0
  17. package/src/css/base.css +615 -0
  18. package/src/css/components.css +1311 -0
  19. package/src/css/tailwind.css +370 -0
  20. package/src/css/themes.css +517 -0
  21. package/src/css/utilities.css +475 -0
  22. package/src/index.js +746 -0
  23. package/src/js/animation.js +655 -0
  24. package/src/js/dom.js +665 -0
  25. package/src/js/events.js +585 -0
  26. package/src/js/http.js +446 -0
  27. package/src/js/index.js +26 -0
  28. package/src/js/router.js +483 -0
  29. package/src/js/store.js +539 -0
  30. package/src/js/utils.js +593 -0
  31. package/src/js/validator.js +529 -0
  32. package/src/jsx/components/Accordion.jsx +210 -0
  33. package/src/jsx/components/Alert.jsx +169 -0
  34. package/src/jsx/components/Avatar.jsx +214 -0
  35. package/src/jsx/components/Badge.jsx +136 -0
  36. package/src/jsx/components/Breadcrumb.jsx +200 -0
  37. package/src/jsx/components/Button.jsx +188 -0
  38. package/src/jsx/components/Card.jsx +192 -0
  39. package/src/jsx/components/Carousel.jsx +278 -0
  40. package/src/jsx/components/Checkbox.jsx +215 -0
  41. package/src/jsx/components/Dialog.jsx +242 -0
  42. package/src/jsx/components/Drawer.jsx +190 -0
  43. package/src/jsx/components/Dropdown.jsx +268 -0
  44. package/src/jsx/components/Form.jsx +274 -0
  45. package/src/jsx/components/Input.jsx +285 -0
  46. package/src/jsx/components/Menu.jsx +276 -0
  47. package/src/jsx/components/Modal.jsx +274 -0
  48. package/src/jsx/components/Navbar.jsx +292 -0
  49. package/src/jsx/components/Pagination.jsx +268 -0
  50. package/src/jsx/components/Progress.jsx +252 -0
  51. package/src/jsx/components/Radio.jsx +208 -0
  52. package/src/jsx/components/Select.jsx +397 -0
  53. package/src/jsx/components/Sidebar.jsx +250 -0
  54. package/src/jsx/components/Slider.jsx +310 -0
  55. package/src/jsx/components/Spinner.jsx +198 -0
  56. package/src/jsx/components/Switch.jsx +201 -0
  57. package/src/jsx/components/Table.jsx +332 -0
  58. package/src/jsx/components/Tabs.jsx +227 -0
  59. package/src/jsx/components/Textarea.jsx +212 -0
  60. package/src/jsx/components/Toast.jsx +270 -0
  61. package/src/jsx/components/Tooltip.jsx +178 -0
  62. package/src/jsx/components/Typography.jsx +299 -0
  63. package/src/jsx/components/index.jsx +70 -0
  64. package/src/jsx/core/element.js +3 -0
  65. package/src/jsx/hooks/index.js +356 -0
  66. package/src/jsx/hooks/useCallback.js +472 -0
  67. package/src/jsx/hooks/useContext.js +586 -0
  68. package/src/jsx/hooks/useEffect.js +704 -0
  69. package/src/jsx/hooks/useLayoutEffect.js +508 -0
  70. package/src/jsx/hooks/useMemo.js +689 -0
  71. package/src/jsx/hooks/useReducer.js +729 -0
  72. package/src/jsx/hooks/useRef.js +542 -0
  73. package/src/jsx/hooks/useState.js +854 -0
  74. package/src/jsx/runtime/commit.js +903 -0
  75. package/src/jsx/runtime/createElement.js +860 -0
  76. package/src/jsx/runtime/index.js +356 -0
  77. package/src/jsx/runtime/reconcile.js +687 -0
  78. package/src/jsx/runtime/render.js +914 -0
@@ -0,0 +1,252 @@
1
+ /**
2
+ * Progress Component for ElementDrawing Framework
3
+ * Supports bar, circle, dashboard variants, sizes, colors, animation, striped, label, step progress
4
+ */
5
+ const ED = require('../core/element');
6
+
7
+ const PROGRESS_COLORS = {
8
+ blue: '#3b82f6',
9
+ green: '#22c55e',
10
+ red: '#ef4444',
11
+ yellow: '#eab308',
12
+ purple: '#a855f7',
13
+ cyan: '#06b6d4',
14
+ orange: '#f97316',
15
+ };
16
+
17
+ const SIZE_CONFIGS = {
18
+ sm: { barHeight: 6, circleSize: 80, circleStroke: 6, fontSize: 'ed-text-xs' },
19
+ md: { barHeight: 10, circleSize: 120, circleStroke: 8, fontSize: 'ed-text-sm' },
20
+ lg: { barHeight: 16, circleSize: 160, circleStroke: 10, fontSize: 'ed-text-base' },
21
+ };
22
+
23
+ function ProgressBar(props) {
24
+ const {
25
+ percent = 0,
26
+ color = 'blue',
27
+ size = 'md',
28
+ showLabel = true,
29
+ label,
30
+ striped = false,
31
+ animated = false,
32
+ status,
33
+ className = '',
34
+ style = {},
35
+ trailColor,
36
+ borderRadius,
37
+ steps,
38
+ } = props;
39
+
40
+ const sizeConfig = SIZE_CONFIGS[size] || SIZE_CONFIGS.md;
41
+ const clampedPercent = Math.min(100, Math.max(0, percent));
42
+
43
+ const statusColor = status === 'success' ? PROGRESS_COLORS.green
44
+ : status === 'error' || status === 'danger' ? PROGRESS_COLORS.red
45
+ : typeof color === 'string' ? (PROGRESS_COLORS[color] || color)
46
+ : color;
47
+
48
+ const bgColor = trailColor || '#e5e7eb';
49
+
50
+ if (steps) {
51
+ const stepWidth = 100 / steps;
52
+ return ED.createElement('div', {
53
+ className: `ed-w-full ${className}`,
54
+ style,
55
+ children: ED.createElement('div', {
56
+ className: 'ed-flex ed-gap-1',
57
+ children: Array.from({ length: steps }, (_, i) => {
58
+ const isFilled = i < Math.floor(clampedPercent / stepWidth);
59
+ return ED.createElement('div', {
60
+ key: i,
61
+ className: [
62
+ 'ed-h-2 ed-flex-1 ed-rounded-sm ed-transition-all ed-duration-300',
63
+ ].join(' '),
64
+ style: {
65
+ backgroundColor: isFilled ? statusColor : bgColor,
66
+ },
67
+ });
68
+ }),
69
+ }),
70
+ });
71
+ }
72
+
73
+ const barClasses = [
74
+ 'ed-w-full ed-overflow-hidden',
75
+ borderRadius ? `ed-rounded-${borderRadius}` : 'ed-rounded-full',
76
+ ].filter(Boolean).join(' ');
77
+
78
+ const fillClasses = [
79
+ 'ed-h-full ed-transition-all ed-duration-500 ed-ease-out',
80
+ borderRadius ? `ed-rounded-${borderRadius}` : 'ed-rounded-full',
81
+ striped ? 'ed-bg-stripes' : '',
82
+ animated ? 'ed-animate-stripes' : '',
83
+ ].filter(Boolean).join(' ');
84
+
85
+ return ED.createElement('div', { className: `ed-w-full ${className}`, style },
86
+ showLabel
87
+ ? ED.createElement('div', {
88
+ className: `ed-flex ed-items-center ed-justify-between ed-mb-1 ${sizeConfig.fontSize}`,
89
+ children: [
90
+ label ? ED.createElement('span', { className: 'ed-text-gray-700' }, label) : null,
91
+ ED.createElement('span', {
92
+ className: [
93
+ 'ed-font-medium',
94
+ status === 'success' ? 'ed-text-green-600' : status === 'error' ? 'ed-text-red-600' : 'ed-text-gray-600',
95
+ ].join(' '),
96
+ }, `${Math.round(clampedPercent)}%`),
97
+ ].filter(Boolean),
98
+ })
99
+ : null,
100
+ ED.createElement('div', {
101
+ className: barClasses,
102
+ style: { height: sizeConfig.barHeight, backgroundColor: bgColor },
103
+ role: 'progressbar',
104
+ 'aria-valuenow': clampedPercent,
105
+ 'aria-valuemin': 0,
106
+ 'aria-valuemax': 100,
107
+ children: ED.createElement('div', {
108
+ className: fillClasses,
109
+ style: {
110
+ width: `${clampedPercent}%`,
111
+ backgroundColor: statusColor,
112
+ backgroundImage: striped
113
+ ? 'linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)'
114
+ : undefined,
115
+ backgroundSize: striped ? '1rem 1rem' : undefined,
116
+ },
117
+ }),
118
+ }),
119
+ status === 'success' && !showLabel
120
+ ? ED.createElement('svg', {
121
+ className: 'ed-w-4 ed-h-4 ed-text-green-500 ed-ml-2 ed-inline',
122
+ fill: 'none', viewBox: '0 0 24 24', stroke: 'currentColor',
123
+ children: ED.createElement('path', { strokeLinecap: 'round', strokeLinejoin: 'round', strokeWidth: 2, d: 'M5 13l4 4L19 7' }),
124
+ })
125
+ : null,
126
+ );
127
+ }
128
+
129
+ ProgressBar.displayName = 'ProgressBar';
130
+
131
+ function ProgressCircle(props) {
132
+ const {
133
+ percent = 0,
134
+ color = 'blue',
135
+ size = 'md',
136
+ showLabel = true,
137
+ status,
138
+ className = '',
139
+ style = {},
140
+ trailColor = '#e5e7eb',
141
+ strokeWidth,
142
+ gapDegree = 0,
143
+ gapPosition = 'bottom',
144
+ type = 'circle',
145
+ } = props;
146
+
147
+ const sizeConfig = SIZE_CONFIGS[size] || SIZE_CONFIGS.md;
148
+ const clampedPercent = Math.min(100, Math.max(0, percent));
149
+
150
+ const statusColor = status === 'success' ? PROGRESS_COLORS.green
151
+ : status === 'error' || status === 'danger' ? PROGRESS_COLORS.red
152
+ : typeof color === 'string' ? (PROGRESS_COLORS[color] || color)
153
+ : color;
154
+
155
+ const circleSize = sizeConfig.circleSize;
156
+ const circleStroke = strokeWidth || sizeConfig.circleStroke;
157
+ const isDashboard = type === 'dashboard';
158
+ const effectiveGap = isDashboard ? gapDegree || 75 : gapDegree;
159
+
160
+ const radius = (circleSize - circleStroke) / 2;
161
+ const circumference = 2 * Math.PI * radius;
162
+ const strokeDashoffset = circumference * (1 - clampedPercent / 100);
163
+
164
+ const center = circleSize / 2;
165
+ const rotation = isDashboard ? 90 + effectiveGap / 2 : -90;
166
+ const dashArray = effectiveGap > 0
167
+ ? `${(circumference * (360 - effectiveGap)) / 360} ${circumference}`
168
+ : circumference;
169
+
170
+ const statusIcon = status === 'success'
171
+ ? ED.createElement('svg', {
172
+ className: 'ed-w-8 ed-h-8 ed-text-green-500',
173
+ fill: 'none', viewBox: '0 0 24 24', stroke: 'currentColor',
174
+ children: ED.createElement('path', { strokeLinecap: 'round', strokeLinejoin: 'round', strokeWidth: 2, d: 'M5 13l4 4L19 7' }),
175
+ })
176
+ : status === 'error'
177
+ ? ED.createElement('svg', {
178
+ className: 'ed-w-8 ed-h-8 ed-text-red-500',
179
+ fill: 'none', viewBox: '0 0 24 24', stroke: 'currentColor',
180
+ children: ED.createElement('path', { strokeLinecap: 'round', strokeLinejoin: 'round', strokeWidth: 2, d: 'M6 18L18 6M6 6l12 12' }),
181
+ })
182
+ : null;
183
+
184
+ return ED.createElement('div', {
185
+ className: `ed-inline-flex ed-items-center ed-justify-center ed-relative ${className}`,
186
+ style,
187
+ role: 'progressbar',
188
+ 'aria-valuenow': clampedPercent,
189
+ children: [
190
+ ED.createElement('svg', {
191
+ key: 'svg',
192
+ width: circleSize,
193
+ height: circleSize,
194
+ viewBox: `0 0 ${circleSize} ${circleSize}`,
195
+ style: { transform: `rotate(${rotation}deg)` },
196
+ children: [
197
+ ED.createElement('circle', {
198
+ key: 'trail',
199
+ cx: center,
200
+ cy: center,
201
+ r: radius,
202
+ fill: 'none',
203
+ stroke: trailColor,
204
+ strokeWidth: circleStroke,
205
+ strokeDasharray: dashArray,
206
+ strokeLinecap: 'round',
207
+ }),
208
+ ED.createElement('circle', {
209
+ key: 'fill',
210
+ cx: center,
211
+ cy: center,
212
+ r: radius,
213
+ fill: 'none',
214
+ stroke: statusColor,
215
+ strokeWidth: circleStroke,
216
+ strokeDasharray: dashArray,
217
+ strokeDashoffset,
218
+ strokeLinecap: 'round',
219
+ style: { transition: 'stroke-dashoffset 0.5s ease' },
220
+ }),
221
+ ],
222
+ }),
223
+ showLabel
224
+ ? ED.createElement('div', {
225
+ key: 'label',
226
+ className: 'ed-absolute ed-inset-0 ed-flex ed-items-center ed-justify-center',
227
+ children: statusIcon || ED.createElement('span', {
228
+ className: `${sizeConfig.fontSize} ed-font-semibold ed-text-gray-700`,
229
+ }, `${Math.round(clampedPercent)}%`),
230
+ })
231
+ : null,
232
+ ],
233
+ });
234
+ }
235
+
236
+ ProgressCircle.displayName = 'ProgressCircle';
237
+
238
+ function Progress(props) {
239
+ const { type = 'bar' } = props;
240
+ if (type === 'circle' || type === 'dashboard') {
241
+ return ProgressCircle({ ...props, type });
242
+ }
243
+ return ProgressBar(props);
244
+ }
245
+
246
+ Progress.displayName = 'Progress';
247
+ Progress.Bar = ProgressBar;
248
+ Progress.Circle = ProgressCircle;
249
+ Progress.COLORS = PROGRESS_COLORS;
250
+ Progress.SIZES = SIZE_CONFIGS;
251
+
252
+ module.exports = Progress;
@@ -0,0 +1,208 @@
1
+ /**
2
+ * Radio Component for ElementDrawing Framework
3
+ * Supports sizes, button style, group, disabled, custom icon, color variants, horizontal/vertical layout
4
+ */
5
+ const ED = require('../core/element');
6
+
7
+ const RADIO_SIZES = {
8
+ xs: { circle: 'ed-w-3.5 ed-h-3.5', inner: 'ed-w-1.5 ed-h-1.5', label: 'ed-text-xs' },
9
+ sm: { circle: 'ed-w-4 ed-h-4', inner: 'ed-w-2 ed-h-2', label: 'ed-text-sm' },
10
+ md: { circle: 'ed-w-4.5 ed-h-4.5', inner: 'ed-w-2 ed-h-2', label: 'ed-text-sm' },
11
+ lg: { circle: 'ed-w-5 ed-h-5', inner: 'ed-w-2.5 ed-h-2.5', label: 'ed-text-base' },
12
+ xl: { circle: 'ed-w-6 ed-h-6', inner: 'ed-w-3 ed-h-3', label: 'ed-text-lg' },
13
+ };
14
+
15
+ const RADIO_COLORS = {
16
+ blue: { checked: 'ed-border-blue-600 ed-ring-blue-500', inner: 'ed-bg-blue-600' },
17
+ green: { checked: 'ed-border-green-600 ed-ring-green-500', inner: 'ed-bg-green-600' },
18
+ red: { checked: 'ed-border-red-600 ed-ring-red-500', inner: 'ed-bg-red-600' },
19
+ yellow: { checked: 'ed-border-yellow-500 ed-ring-yellow-400', inner: 'ed-bg-yellow-500' },
20
+ purple: { checked: 'ed-border-purple-600 ed-ring-purple-500', inner: 'ed-bg-purple-600' },
21
+ gray: { checked: 'ed-border-gray-600 ed-ring-gray-500', inner: 'ed-bg-gray-600' },
22
+ };
23
+
24
+ function Radio(props) {
25
+ const {
26
+ checked,
27
+ defaultChecked = false,
28
+ onChange,
29
+ disabled = false,
30
+ label,
31
+ children,
32
+ size = 'md',
33
+ color = 'blue',
34
+ buttonStyle = false,
35
+ className = '',
36
+ style = {},
37
+ id,
38
+ name,
39
+ value,
40
+ icon,
41
+ autoFocus = false,
42
+ tabIndex,
43
+ onFocus,
44
+ onBlur,
45
+ error = false,
46
+ } = props;
47
+
48
+ const sizeConfig = RADIO_SIZES[size] || RADIO_SIZES.md;
49
+ const colorConfig = RADIO_COLORS[color] || RADIO_COLORS.blue;
50
+ const isChecked = checked !== undefined ? checked : defaultChecked;
51
+
52
+ if (buttonStyle) {
53
+ const buttonClasses = [
54
+ 'ed-inline-flex ed-items-center ed-justify-center ed-px-4 ed-py-2 ed-text-sm ed-font-medium ed-border ed-transition-colors ed-duration-200',
55
+ isChecked
56
+ ? 'ed-bg-blue-600 ed-text-white ed-border-blue-600 ed-z-10'
57
+ : 'ed-bg-white ed-text-gray-700 ed-border-gray-300 hover:ed-bg-gray-50',
58
+ disabled ? 'ed-opacity-50 ed-cursor-not-allowed' : 'ed-cursor-pointer',
59
+ 'ed--ml-px ed-first:ml-0 ed-first:rounded-l-md ed-last:rounded-r-md',
60
+ className,
61
+ ].filter(Boolean).join(' ');
62
+
63
+ return ED.createElement('label', { className: buttonClasses, style },
64
+ ED.createElement('input', {
65
+ type: 'radio',
66
+ checked: isChecked,
67
+ onChange: disabled ? undefined : onChange,
68
+ disabled,
69
+ id,
70
+ name,
71
+ value,
72
+ className: 'ed-sr-only',
73
+ autoFocus,
74
+ tabIndex,
75
+ onFocus,
76
+ onBlur,
77
+ }),
78
+ icon
79
+ ? ED.createElement('span', { className: 'ed-mr-1.5' },
80
+ typeof icon === 'string' ? ED.createElement('i', { className: icon }) : icon
81
+ )
82
+ : null,
83
+ label || children
84
+ );
85
+ }
86
+
87
+ const circleClasses = [
88
+ 'ed-relative ed-inline-flex ed-items-center ed-justify-center ed-border-2 ed-rounded-full ed-transition-all ed-duration-200',
89
+ sizeConfig.circle,
90
+ isChecked
91
+ ? `${colorConfig.checked} ed-border-2`
92
+ : 'ed-border-gray-300 ed-bg-white',
93
+ disabled ? 'ed-opacity-50 ed-cursor-not-allowed' : 'ed-cursor-pointer',
94
+ error && !isChecked ? 'ed-border-red-500' : '',
95
+ 'focus:ed-ring-2 focus:ed-ring-offset-1',
96
+ ].filter(Boolean).join(' ');
97
+
98
+ const innerDot = isChecked
99
+ ? ED.createElement('span', {
100
+ className: `${sizeConfig.inner} ${colorConfig.inner} ed-rounded-full`,
101
+ })
102
+ : null;
103
+
104
+ const labelContent = label || children;
105
+ const labelClasses = [
106
+ sizeConfig.label,
107
+ disabled ? 'ed-text-gray-400 ed-cursor-not-allowed' : 'ed-text-gray-700 ed-cursor-pointer',
108
+ 'ed-select-none',
109
+ ].filter(Boolean).join(' ');
110
+
111
+ return ED.createElement('label', {
112
+ className: `ed-inline-flex ed-items-center ed-gap-2 ${disabled ? 'ed-cursor-not-allowed' : 'ed-cursor-pointer'} ${className}`,
113
+ style,
114
+ }, [
115
+ ED.createElement('input', {
116
+ key: 'input',
117
+ type: 'radio',
118
+ checked: isChecked,
119
+ onChange: disabled ? undefined : onChange,
120
+ disabled,
121
+ id,
122
+ name,
123
+ value,
124
+ className: 'ed-sr-only',
125
+ autoFocus,
126
+ tabIndex,
127
+ onFocus,
128
+ onBlur,
129
+ }),
130
+ ED.createElement('span', { key: 'circle', className: circleClasses, children: innerDot }),
131
+ labelContent
132
+ ? ED.createElement('span', { key: 'label', className: labelClasses }, labelContent)
133
+ : null,
134
+ ]);
135
+ }
136
+
137
+ Radio.displayName = 'Radio';
138
+
139
+ function RadioGroup(props) {
140
+ const {
141
+ children,
142
+ options = [],
143
+ value,
144
+ defaultValue,
145
+ onChange,
146
+ disabled = false,
147
+ direction = 'horizontal',
148
+ size = 'md',
149
+ color = 'blue',
150
+ buttonStyle = false,
151
+ className = '',
152
+ style = {},
153
+ name,
154
+ optionType = 'default',
155
+ } = props;
156
+
157
+ const currentValue = value !== undefined ? value : defaultValue;
158
+
159
+ const handleChange = (optionValue) => {
160
+ if (disabled) return;
161
+ onChange?.({ target: { value: optionValue } });
162
+ };
163
+
164
+ const directionClasses = {
165
+ horizontal: 'ed-flex ed-flex-wrap ed-gap-2',
166
+ vertical: 'ed-flex ed-flex-col ed-gap-2',
167
+ };
168
+
169
+ const groupClasses = [
170
+ directionClasses[direction] || directionClasses.horizontal,
171
+ buttonStyle ? 'ed-inline-flex' : '',
172
+ className,
173
+ ].filter(Boolean).join(' ');
174
+
175
+ const isButtonStyle = buttonStyle || optionType === 'button';
176
+
177
+ const optionElements = options.length > 0
178
+ ? options.map((option, idx) => {
179
+ const opt = typeof option === 'string' ? { label: option, value: option } : option;
180
+ return ED.createElement(Radio, {
181
+ key: opt.value || idx,
182
+ checked: currentValue === opt.value,
183
+ onChange: () => handleChange(opt.value),
184
+ disabled: disabled || opt.disabled,
185
+ label: opt.label,
186
+ size,
187
+ color,
188
+ buttonStyle: isButtonStyle,
189
+ value: opt.value,
190
+ name,
191
+ });
192
+ })
193
+ : children;
194
+
195
+ return ED.createElement('div', {
196
+ className: groupClasses,
197
+ style,
198
+ role: 'radiogroup',
199
+ children: optionElements,
200
+ });
201
+ }
202
+
203
+ RadioGroup.displayName = 'RadioGroup';
204
+ Radio.Group = RadioGroup;
205
+ Radio.SIZES = RADIO_SIZES;
206
+ Radio.COLORS = RADIO_COLORS;
207
+
208
+ module.exports = Radio;