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,210 @@
1
+ /**
2
+ * Accordion Component for ElementDrawing Framework
3
+ * Supports single/multiple expand, icons, animations, nested, disabled items, custom header
4
+ */
5
+ const ED = require('../core/element');
6
+
7
+ function AccordionItem(props) {
8
+ const {
9
+ children,
10
+ title,
11
+ header,
12
+ icon,
13
+ expandIcon,
14
+ disabled = false,
15
+ expanded = false,
16
+ onToggle,
17
+ className = '',
18
+ style = {},
19
+ key: itemKey,
20
+ extra,
21
+ showArrow = true,
22
+ destroyInactive = false,
23
+ forceRender = false,
24
+ animated = true,
25
+ } = props;
26
+
27
+ const headerClasses = [
28
+ 'ed-flex ed-items-center ed-w-full ed-px-4 ed-py-3 ed-text-left ed-transition-colors ed-duration-200',
29
+ 'hover:ed-bg-gray-50 focus:ed-outline-none focus:ed-ring-2 focus:ed-ring-inset focus:ed-ring-blue-500',
30
+ disabled ? 'ed-opacity-50 ed-cursor-not-allowed' : 'ed-cursor-pointer',
31
+ expanded ? 'ed-bg-gray-50' : '',
32
+ 'ed-border-b ed-border-gray-100',
33
+ className,
34
+ ].filter(Boolean).join(' ');
35
+
36
+ const contentClasses = [
37
+ 'ed-overflow-hidden ed-transition-all ed-duration-300',
38
+ animated ? 'ed-transition-[max-height] ed-ease-in-out' : '',
39
+ expanded ? 'ed-max-h-[2000px] ed-opacity-100' : 'ed-max-h-0 ed-opacity-0',
40
+ ].filter(Boolean).join(' ');
41
+
42
+ const defaultExpandIcon = ED.createElement('svg', {
43
+ className: `ed-w-5 ed-h-5 ed-transition-transform ed-duration-300 ed-text-gray-400 ${expanded ? 'ed-rotate-180' : ''}`,
44
+ fill: 'none', viewBox: '0 0 24 24', stroke: 'currentColor',
45
+ children: ED.createElement('path', { strokeLinecap: 'round', strokeLinejoin: 'round', strokeWidth: 2, d: 'M19 9l-7 7-7-7' }),
46
+ });
47
+
48
+ const headerContent = header || ED.createElement(ED.Fragment, null,
49
+ icon
50
+ ? ED.createElement('span', { className: 'ed-mr-3 ed-flex ed-items-center ed-justify-center ed-w-5 ed-h-5 ed-text-gray-500' },
51
+ typeof icon === 'string' ? ED.createElement('i', { className: icon }) : icon
52
+ )
53
+ : null,
54
+ ED.createElement('span', { className: 'ed-flex-1 ed-font-medium ed-text-gray-900' }, title),
55
+ extra
56
+ ? ED.createElement('span', { className: 'ed-mr-2 ed-text-sm ed-text-gray-500', onClick: (e) => e.stopPropagation() }, extra)
57
+ : null,
58
+ showArrow
59
+ ? ED.createElement('span', { className: 'ed-ml-auto ed-flex ed-items-center' },
60
+ expandIcon || defaultExpandIcon
61
+ )
62
+ : null
63
+ );
64
+
65
+ const handleToggle = () => {
66
+ if (!disabled) onToggle?.();
67
+ };
68
+
69
+ const handleKeyDown = (e) => {
70
+ if (e.key === 'Enter' || e.key === ' ') {
71
+ e.preventDefault();
72
+ handleToggle();
73
+ }
74
+ };
75
+
76
+ return ED.createElement('div', {
77
+ className: 'ed-border ed-border-gray-200 ed-rounded-lg ed-overflow-hidden ed-mb-2',
78
+ style,
79
+ children: [
80
+ ED.createElement('button', {
81
+ key: 'header',
82
+ className: headerClasses,
83
+ onClick: handleToggle,
84
+ onKeyDown: handleKeyDown,
85
+ 'aria-expanded': expanded,
86
+ 'aria-disabled': disabled,
87
+ role: 'button',
88
+ tabIndex: disabled ? -1 : 0,
89
+ children: headerContent,
90
+ }),
91
+ ED.createElement('div', {
92
+ key: 'content',
93
+ className: contentClasses,
94
+ role: 'region',
95
+ children: (expanded || forceRender)
96
+ ? ED.createElement('div', { className: 'ed-px-4 ed-py-3 ed-text-gray-700 ed-border-t ed-border-gray-100' }, children)
97
+ : null,
98
+ }),
99
+ ],
100
+ });
101
+ }
102
+
103
+ AccordionItem.displayName = 'AccordionItem';
104
+
105
+ function Accordion(props) {
106
+ const {
107
+ children,
108
+ items = [],
109
+ multiple = false,
110
+ defaultActiveKey,
111
+ activeKey,
112
+ onChange,
113
+ className = '',
114
+ style = {},
115
+ icon,
116
+ expandIcon,
117
+ animated = true,
118
+ destroyInactive = false,
119
+ bordered = true,
120
+ ghost = false,
121
+ accordion = !multiple,
122
+ size = 'md',
123
+ } = props;
124
+
125
+ const internalActiveKeys = activeKey !== undefined
126
+ ? (Array.isArray(activeKey) ? activeKey : [activeKey])
127
+ : defaultActiveKey !== undefined
128
+ ? (Array.isArray(defaultActiveKey) ? defaultActiveKey : [defaultActiveKey])
129
+ : [];
130
+
131
+ const handleToggle = (key) => {
132
+ const isOpen = internalActiveKeys.includes(key);
133
+ let newKeys;
134
+ if (accordion || !multiple) {
135
+ newKeys = isOpen ? [] : [key];
136
+ } else {
137
+ newKeys = isOpen ? internalActiveKeys.filter(k => k !== key) : [...internalActiveKeys, key];
138
+ }
139
+ onChange?.(multiple ? newKeys : newKeys[0] || null);
140
+ };
141
+
142
+ const sizeClasses = {
143
+ sm: 'ed-text-sm',
144
+ md: 'ed-text-base',
145
+ lg: 'ed-text-lg',
146
+ };
147
+
148
+ const accordionClasses = [
149
+ sizeClasses[size] || sizeClasses.md,
150
+ ghost ? '' : bordered ? 'ed-divide-y ed-divide-gray-200' : '',
151
+ 'ed-accordion',
152
+ className,
153
+ ].filter(Boolean).join(' ');
154
+
155
+ const renderItems = () => {
156
+ if (items.length > 0) {
157
+ return items.map((item, idx) =>
158
+ ED.createElement(AccordionItem, {
159
+ key: item.key || idx,
160
+ title: item.title,
161
+ icon: item.icon || icon,
162
+ expandIcon: item.expandIcon || expandIcon,
163
+ disabled: item.disabled,
164
+ expanded: internalActiveKeys.includes(item.key || String(idx)),
165
+ onToggle: () => handleToggle(item.key || String(idx)),
166
+ extra: item.extra,
167
+ showArrow: item.showArrow !== undefined ? item.showArrow : true,
168
+ animated,
169
+ destroyInactive,
170
+ forceRender: item.forceRender,
171
+ children: item.children || item.content,
172
+ })
173
+ );
174
+ }
175
+
176
+ const childArray = Array.isArray(children) ? children : [children];
177
+ return childArray.map((child, idx) => {
178
+ if (!child || !child.props) return child;
179
+ const childKey = child.props.key || String(idx);
180
+ return ED.cloneElement
181
+ ? ED.cloneElement(child, {
182
+ key: childKey,
183
+ expanded: internalActiveKeys.includes(childKey),
184
+ onToggle: () => handleToggle(childKey),
185
+ icon: child.props.icon || icon,
186
+ expandIcon: child.props.expandIcon || expandIcon,
187
+ animated,
188
+ })
189
+ : child;
190
+ });
191
+ };
192
+
193
+ const wrapperClasses = ghost
194
+ ? [
195
+ 'ed-border-0 ed-bg-transparent',
196
+ className,
197
+ ].filter(Boolean).join(' ')
198
+ : accordionClasses;
199
+
200
+ return ED.createElement('div', {
201
+ className: wrapperClasses,
202
+ style,
203
+ children: renderItems(),
204
+ });
205
+ }
206
+
207
+ Accordion.displayName = 'Accordion';
208
+ Accordion.Item = AccordionItem;
209
+
210
+ module.exports = Accordion;
@@ -0,0 +1,169 @@
1
+ /**
2
+ * Alert Component for ElementDrawing Framework
3
+ * Supports variants, closable, icon, title + description, banner mode, auto-dismiss
4
+ */
5
+ const ED = require('../core/element');
6
+
7
+ const ALERT_VARIANTS = {
8
+ info: {
9
+ container: 'ed-bg-blue-50 ed-border-blue-200 ed-text-blue-800',
10
+ icon: 'ed-text-blue-500',
11
+ close: 'ed-text-blue-500 hover:ed-bg-blue-100',
12
+ },
13
+ success: {
14
+ container: 'ed-bg-green-50 ed-border-green-200 ed-text-green-800',
15
+ icon: 'ed-text-green-500',
16
+ close: 'ed-text-green-500 hover:ed-bg-green-100',
17
+ },
18
+ warning: {
19
+ container: 'ed-bg-yellow-50 ed-border-yellow-200 ed-text-yellow-800',
20
+ icon: 'ed-text-yellow-500',
21
+ close: 'ed-text-yellow-500 hover:ed-bg-yellow-100',
22
+ },
23
+ danger: {
24
+ container: 'ed-bg-red-50 ed-border-red-200 ed-text-red-800',
25
+ icon: 'ed-text-red-500',
26
+ close: 'ed-text-red-500 hover:ed-bg-red-100',
27
+ },
28
+ error: {
29
+ container: 'ed-bg-red-50 ed-border-red-200 ed-text-red-800',
30
+ icon: 'ed-text-red-500',
31
+ close: 'ed-text-red-500 hover:ed-bg-red-100',
32
+ },
33
+ };
34
+
35
+ const ALERT_ICONS = {
36
+ info: ED.createElement('svg', {
37
+ className: 'ed-w-5 ed-h-5',
38
+ fill: 'none', viewBox: '0 0 24 24', stroke: 'currentColor',
39
+ children: ED.createElement('path', { strokeLinecap: 'round', strokeLinejoin: 'round', strokeWidth: 2, d: 'M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z' }),
40
+ }),
41
+ success: ED.createElement('svg', {
42
+ className: 'ed-w-5 ed-h-5',
43
+ fill: 'none', viewBox: '0 0 24 24', stroke: 'currentColor',
44
+ children: ED.createElement('path', { strokeLinecap: 'round', strokeLinejoin: 'round', strokeWidth: 2, d: 'M5 13l4 4L19 7' }),
45
+ }),
46
+ warning: ED.createElement('svg', {
47
+ className: 'ed-w-5 ed-h-5',
48
+ fill: 'none', viewBox: '0 0 24 24', stroke: 'currentColor',
49
+ children: ED.createElement('path', { strokeLinecap: 'round', strokeLinejoin: 'round', strokeWidth: 2, d: 'M12 9v2m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z' }),
50
+ }),
51
+ danger: ED.createElement('svg', {
52
+ className: 'ed-w-5 ed-h-5',
53
+ fill: 'none', viewBox: '0 0 24 24', stroke: 'currentColor',
54
+ children: ED.createElement('path', { strokeLinecap: 'round', strokeLinejoin: 'round', strokeWidth: 2, d: 'M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z' }),
55
+ }),
56
+ error: ED.createElement('svg', {
57
+ className: 'ed-w-5 ed-h-5',
58
+ fill: 'none', viewBox: '0 0 24 24', stroke: 'currentColor',
59
+ children: ED.createElement('path', { strokeLinecap: 'round', strokeLinejoin: 'round', strokeWidth: 2, d: 'M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z' }),
60
+ }),
61
+ };
62
+
63
+ function Alert(props) {
64
+ const {
65
+ children,
66
+ variant = 'info',
67
+ type = variant,
68
+ closable = false,
69
+ onClose,
70
+ showIcon = true,
71
+ icon,
72
+ title,
73
+ description,
74
+ banner = false,
75
+ autoDismiss,
76
+ onDismiss,
77
+ className = '',
78
+ style = {},
79
+ action,
80
+ rounded = true,
81
+ bordered = true,
82
+ outlined = false,
83
+ size = 'md',
84
+ } = props;
85
+
86
+ const currentType = type || variant;
87
+ const variantStyle = ALERT_VARIANTS[currentType] || ALERT_VARIANTS.info;
88
+
89
+ const sizeClasses = {
90
+ sm: 'ed-text-xs ed-py-2 ed-px-3',
91
+ md: 'ed-text-sm ed-py-3 ed-px-4',
92
+ lg: 'ed-text-base ed-py-4 ed-px-5',
93
+ };
94
+
95
+ const containerClasses = [
96
+ 'ed-flex ed-items-start ed-gap-3',
97
+ variantStyle.container,
98
+ banner ? 'ed-rounded-none ed-border-x-0 ed-border-t-0' : rounded ? 'ed-rounded-lg' : '',
99
+ bordered ? 'ed-border' : '',
100
+ outlined ? 'ed-bg-transparent' : '',
101
+ sizeClasses[size] || sizeClasses.md,
102
+ 'ed-transition-all ed-duration-300',
103
+ className,
104
+ ].filter(Boolean).join(' ');
105
+
106
+ const iconElement = showIcon
107
+ ? ED.createElement('span', {
108
+ className: `ed-flex-shrink-0 ed-mt-0.5 ${variantStyle.icon}`,
109
+ children: icon || ALERT_ICONS[currentType] || ALERT_ICONS.info,
110
+ })
111
+ : null;
112
+
113
+ const contentElement = ED.createElement('div', { className: 'ed-flex-1 ed-min-w-0' },
114
+ title
115
+ ? ED.createElement('div', { className: 'ed-font-semibold ed-mb-0.5' }, title)
116
+ : null,
117
+ description
118
+ ? ED.createElement('div', { className: 'ed-text-sm ed-opacity-80' }, description)
119
+ : null,
120
+ children
121
+ ? ED.createElement('div', { className: title || description ? 'ed-mt-1 ed-text-sm ed-opacity-90' : '' }, children)
122
+ : null
123
+ );
124
+
125
+ const actionElement = action
126
+ ? ED.createElement('div', { className: 'ed-flex-shrink-0 ed-ml-2' }, action)
127
+ : null;
128
+
129
+ const closeElement = closable
130
+ ? ED.createElement('button', {
131
+ className: `ed-flex-shrink-0 ed-p-1 ed-rounded ed-transition-colors ${variantStyle.close}`,
132
+ onClick: onClose,
133
+ 'aria-label': 'Close alert',
134
+ type: 'button',
135
+ children: ED.createElement('svg', {
136
+ className: 'ed-w-4 ed-h-4',
137
+ fill: 'none', viewBox: '0 0 24 24', stroke: 'currentColor',
138
+ children: ED.createElement('path', { strokeLinecap: 'round', strokeLinejoin: 'round', strokeWidth: 2, d: 'M6 18L18 6M6 6l12 12' }),
139
+ }),
140
+ })
141
+ : null;
142
+
143
+ const progressBar = autoDismiss
144
+ ? ED.createElement('div', { className: 'ed-absolute ed-bottom-0 ed-left-0 ed-right-0 ed-h-1 ed-rounded-b-lg ed-overflow-hidden' },
145
+ ED.createElement('div', {
146
+ className: `ed-h-full ed-bg-current ed-opacity-30`,
147
+ style: { animation: `ed-shrink ${autoDismiss}ms linear forwards` },
148
+ })
149
+ )
150
+ : null;
151
+
152
+ return ED.createElement('div', {
153
+ className: containerClasses,
154
+ style: { position: 'relative', ...style },
155
+ role: currentType === 'danger' || currentType === 'error' ? 'alert' : 'status',
156
+ children: [
157
+ iconElement,
158
+ contentElement,
159
+ actionElement,
160
+ closeElement,
161
+ progressBar,
162
+ ].filter(Boolean),
163
+ });
164
+ }
165
+
166
+ Alert.displayName = 'Alert';
167
+ Alert.VARIANTS = ALERT_VARIANTS;
168
+
169
+ module.exports = Alert;
@@ -0,0 +1,214 @@
1
+ /**
2
+ * Avatar Component for ElementDrawing Framework
3
+ * Supports sizes, shapes, image/initials/icon, status indicator, avatar group, overlap
4
+ */
5
+ const ED = require('../core/element');
6
+
7
+ const AVATAR_SIZES = {
8
+ xs: { container: 'ed-w-6 ed-h-6 ed-text-xs', icon: 'ed-w-3 ed-h-3', indicator: 'ed-w-1.5 ed-h-1.5' },
9
+ sm: { container: 'ed-w-8 ed-h-8 ed-text-sm', icon: 'ed-w-4 ed-h-4', indicator: 'ed-w-2 ed-h-2' },
10
+ md: { container: 'ed-w-10 ed-h-10 ed-text-base', icon: 'ed-w-5 ed-h-5', indicator: 'ed-w-2.5 ed-h-2.5' },
11
+ lg: { container: 'ed-w-12 ed-h-12 ed-text-lg', icon: 'ed-w-6 ed-h-6', indicator: 'ed-w-3 ed-h-3' },
12
+ xl: { container: 'ed-w-14 ed-h-14 ed-text-xl', icon: 'ed-w-7 ed-h-7', indicator: 'ed-w-3.5 ed-h-3.5' },
13
+ '2xl': { container: 'ed-w-16 ed-h-16 ed-text-2xl', icon: 'ed-w-8 ed-h-8', indicator: 'ed-w-4 ed-h-4' },
14
+ };
15
+
16
+ const SHAPE_CLASSES = {
17
+ circle: 'ed-rounded-full',
18
+ square: 'ed-rounded-none',
19
+ rounded: 'ed-rounded-lg',
20
+ };
21
+
22
+ const STATUS_COLORS = {
23
+ online: 'ed-bg-green-500',
24
+ offline: 'ed-bg-gray-400',
25
+ away: 'ed-bg-yellow-500',
26
+ busy: 'ed-bg-red-500',
27
+ doNotDisturb: 'ed-bg-red-600',
28
+ };
29
+
30
+ const BG_COLORS = [
31
+ 'ed-bg-blue-500',
32
+ 'ed-bg-green-500',
33
+ 'ed-bg-yellow-500',
34
+ 'ed-bg-red-500',
35
+ 'ed-bg-purple-500',
36
+ 'ed-bg-pink-500',
37
+ 'ed-bg-indigo-500',
38
+ 'ed-bg-teal-500',
39
+ ];
40
+
41
+ function getColorFromName(name) {
42
+ if (!name) return BG_COLORS[0];
43
+ let hash = 0;
44
+ for (let i = 0; i < name.length; i++) {
45
+ hash = name.charCodeAt(i) + ((hash << 5) - hash);
46
+ }
47
+ return BG_COLORS[Math.abs(hash) % BG_COLORS.length];
48
+ }
49
+
50
+ function getInitials(name) {
51
+ if (!name) return '';
52
+ const parts = name.trim().split(/\s+/);
53
+ if (parts.length >= 2) return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
54
+ return name.slice(0, 2).toUpperCase();
55
+ }
56
+
57
+ function Avatar(props) {
58
+ const {
59
+ src,
60
+ alt = '',
61
+ icon,
62
+ name,
63
+ size = 'md',
64
+ shape = 'circle',
65
+ status,
66
+ statusColor,
67
+ className = '',
68
+ style = {},
69
+ onClick,
70
+ onError,
71
+ bgColor,
72
+ textColor = 'ed-text-white',
73
+ bordered = false,
74
+ borderColor = 'ed-border-white',
75
+ boxShadow,
76
+ draggable = false,
77
+ loading = false,
78
+ fit = 'cover',
79
+ } = props;
80
+
81
+ const sizeConfig = AVATAR_SIZES[size] || AVATAR_SIZES.md;
82
+ const shapeClass = SHAPE_CLASSES[shape] || SHAPE_CLASSES.circle;
83
+
84
+ const containerClasses = [
85
+ 'ed-inline-flex ed-items-center ed-justify-center ed-relative ed-flex-shrink-0 ed-overflow-hidden',
86
+ sizeConfig.container,
87
+ shapeClass,
88
+ bgColor || (!src ? getColorFromName(name) : ''),
89
+ textColor,
90
+ bordered ? `ed-border-2 ${borderColor}` : '',
91
+ onClick ? 'ed-cursor-pointer hover:ed-opacity-80 ed-transition-opacity' : '',
92
+ loading ? 'ed-animate-pulse ed-bg-gray-300' : '',
93
+ 'ed-font-medium ed-select-none',
94
+ className,
95
+ ].filter(Boolean).join(' ');
96
+
97
+ const statusIndicator = status
98
+ ? ED.createElement('span', {
99
+ className: [
100
+ 'ed-absolute ed-bottom-0 ed-right-0 ed-border-2 ed-border-white ed-rounded-full',
101
+ STATUS_COLORS[status] || statusColor || 'ed-bg-green-500',
102
+ sizeConfig.indicator,
103
+ ].join(' '),
104
+ })
105
+ : null;
106
+
107
+ let contentElement;
108
+ if (loading) {
109
+ contentElement = null;
110
+ } else if (src) {
111
+ contentElement = ED.createElement('img', {
112
+ src,
113
+ alt: alt || name || 'Avatar',
114
+ className: `ed-w-full ed-h-full ed-object-${fit}`,
115
+ onError,
116
+ draggable,
117
+ });
118
+ } else if (icon) {
119
+ contentElement = ED.createElement('span', {
120
+ className: sizeConfig.icon,
121
+ children: typeof icon === 'string' ? ED.createElement('i', { className: icon }) : icon,
122
+ });
123
+ } else if (name) {
124
+ contentElement = ED.createElement('span', null, getInitials(name));
125
+ } else {
126
+ contentElement = ED.createElement('svg', {
127
+ className: sizeConfig.icon,
128
+ fill: 'currentColor', viewBox: '0 0 24 24',
129
+ children: ED.createElement('path', { d: 'M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z' }),
130
+ });
131
+ }
132
+
133
+ return ED.createElement('span', {
134
+ className: containerClasses,
135
+ style: {
136
+ ...(boxShadow ? { boxShadow } : {}),
137
+ ...style,
138
+ },
139
+ onClick,
140
+ role: onClick ? 'button' : undefined,
141
+ tabIndex: onClick ? 0 : undefined,
142
+ children: [contentElement, statusIndicator],
143
+ });
144
+ }
145
+
146
+ Avatar.displayName = 'Avatar';
147
+
148
+ function AvatarGroup(props) {
149
+ const {
150
+ children,
151
+ maxCount,
152
+ size = 'md',
153
+ shape = 'circle',
154
+ overlap = true,
155
+ className = '',
156
+ style = {},
157
+ direction = 'horizontal',
158
+ maxStyle,
159
+ onMaxClick,
160
+ } = props;
161
+
162
+ const childArray = Array.isArray(children) ? children : [children];
163
+ const displayChildren = maxCount ? childArray.slice(0, maxCount) : childArray;
164
+ const remaining = maxCount ? childArray.length - maxCount : 0;
165
+
166
+ const groupClasses = [
167
+ 'ed-flex ed-items-center',
168
+ direction === 'horizontal' ? 'ed-flex-row' : 'ed-flex-col',
169
+ overlap ? (direction === 'horizontal' ? 'ed--space-x-2' : 'ed--space-y-2') : 'ed-gap-1',
170
+ className,
171
+ ].filter(Boolean).join(' ');
172
+
173
+ const overflowAvatar = remaining > 0
174
+ ? ED.createElement(Avatar, {
175
+ size,
176
+ shape,
177
+ bgColor: 'ed-bg-gray-200',
178
+ textColor: 'ed-text-gray-600',
179
+ className: 'ed-ring-2 ed-ring-white',
180
+ style: maxStyle,
181
+ onClick: onMaxClick,
182
+ name: `+${remaining}`,
183
+ })
184
+ : null;
185
+
186
+ const styledChildren = displayChildren.map((child, idx) => {
187
+ if (!child || !child.props) return child;
188
+ const overlapStyle = overlap
189
+ ? { zIndex: displayChildren.length - idx, position: 'relative' }
190
+ : {};
191
+ return ED.cloneElement
192
+ ? ED.cloneElement(child, {
193
+ key: idx,
194
+ size: child.props.size || size,
195
+ shape: child.props.shape || shape,
196
+ style: { ...overlapStyle, ...child.props.style },
197
+ bordered: child.props.bordered !== undefined ? child.props.bordered : true,
198
+ })
199
+ : child;
200
+ });
201
+
202
+ return ED.createElement('div', {
203
+ className: groupClasses,
204
+ style,
205
+ children: [...styledChildren, overflowAvatar].filter(Boolean),
206
+ });
207
+ }
208
+
209
+ AvatarGroup.displayName = 'AvatarGroup';
210
+ Avatar.Group = AvatarGroup;
211
+ Avatar.SIZES = AVATAR_SIZES;
212
+ Avatar.SHAPES = SHAPE_CLASSES;
213
+
214
+ module.exports = Avatar;