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,292 @@
1
+ /**
2
+ * Navbar Component for ElementDrawing Framework
3
+ * Supports brand, links, dropdown menus, mobile hamburger, search, notifications, user menu, sticky/fixed, transparent
4
+ */
5
+ const ED = require('../core/element');
6
+
7
+ function Navbar(props) {
8
+ const {
9
+ children,
10
+ brand,
11
+ brandHref = '/',
12
+ brandIcon,
13
+ links = [],
14
+ className = '',
15
+ style = {},
16
+ sticky = false,
17
+ fixed = false,
18
+ transparent = false,
19
+ colored = true,
20
+ color = 'white',
21
+ dark = false,
22
+ shadow = true,
23
+ bordered = false,
24
+ height = 64,
25
+ maxWidth,
26
+ search = false,
27
+ searchPlaceholder = 'Search...',
28
+ onSearch,
29
+ notifications = 0,
30
+ onNotificationClick,
31
+ userMenu,
32
+ userName,
33
+ userAvatar,
34
+ userMenuItems = [],
35
+ onUserMenuClick,
36
+ mobileMenu = true,
37
+ mobileOpen = false,
38
+ onMobileToggle,
39
+ onMobileClose,
40
+ collapsed = false,
41
+ rightContent,
42
+ leftContent,
43
+ centerContent,
44
+ zIndex = 40,
45
+ } = props;
46
+
47
+ const positionClass = fixed
48
+ ? 'ed-fixed ed-top-0 ed-left-0 ed-right-0'
49
+ : sticky
50
+ ? 'ed-sticky ed-top-0'
51
+ : '';
52
+
53
+ const bgClass = transparent
54
+ ? 'ed-bg-transparent'
55
+ : color === 'white'
56
+ ? 'ed-bg-white'
57
+ : color === 'dark'
58
+ ? 'ed-bg-gray-900'
59
+ : color === 'primary'
60
+ ? 'ed-bg-blue-600'
61
+ : color === 'custom'
62
+ ? ''
63
+ : 'ed-bg-white';
64
+
65
+ const textClass = dark || color === 'dark' || color === 'primary'
66
+ ? 'ed-text-white'
67
+ : 'ed-text-gray-800';
68
+
69
+ const navClasses = [
70
+ 'ed-w-full ed-flex ed-items-center ed-px-4 lg:ed-px-6',
71
+ positionClass,
72
+ bgClass,
73
+ textClass,
74
+ shadow && !transparent ? 'ed-shadow-sm' : '',
75
+ bordered ? 'ed-border-b ed-border-gray-200' : '',
76
+ 'ed-transition-all ed-duration-200',
77
+ 'ed-z-' + zIndex,
78
+ className,
79
+ ].filter(Boolean).join(' ');
80
+
81
+ const brandElement = brand || brandIcon
82
+ ? ED.createElement('a', {
83
+ href: brandHref,
84
+ className: 'ed-flex ed-items-center ed-gap-2 ed-font-bold ed-text-lg ed-no-underline ed-inherit ed-mr-6',
85
+ }, [
86
+ brandIcon
87
+ ? ED.createElement('span', { key: 'icon', className: 'ed-w-8 ed-h-8 ed-flex ed-items-center ed-justify-center' },
88
+ typeof brandIcon === 'string' ? ED.createElement('i', { className: brandIcon }) : brandIcon
89
+ )
90
+ : null,
91
+ brand ? ED.createElement('span', { key: 'brand-text' }, brand) : null,
92
+ ].filter(Boolean))
93
+ : null;
94
+
95
+ const linkElements = links.map((link, idx) => {
96
+ if (link.children) {
97
+ return ED.createElement('div', {
98
+ key: idx,
99
+ className: 'ed-relative ed-group',
100
+ children: [
101
+ ED.createElement('button', {
102
+ className: `ed-px-3 ed-py-2 ed-rounded-md ed-text-sm ed-font-medium ed-transition-colors hover:ed-bg-gray-100 ed-flex ed-items-center ed-gap-1 ${textClass}`,
103
+ children: [
104
+ link.icon
105
+ ? ED.createElement('i', { className: link.icon, key: 'icon' })
106
+ : null,
107
+ ED.createElement('span', { key: 'text' }, link.label),
108
+ ED.createElement('svg', {
109
+ key: 'arrow',
110
+ className: 'ed-w-4 ed-h-4',
111
+ fill: 'none', viewBox: '0 0 24 24', stroke: 'currentColor',
112
+ children: ED.createElement('path', { strokeLinecap: 'round', strokeLinejoin: 'round', strokeWidth: 2, d: 'M19 9l-7 7-7-7' }),
113
+ }),
114
+ ],
115
+ }),
116
+ ED.createElement('div', {
117
+ className: 'ed-absolute ed-left-0 ed-top-full ed-mt-1 ed-w-48 ed-bg-white ed-rounded-md ed-shadow-lg ed-border ed-border-gray-200 ed-opacity-0 ed-invisible group-hover:ed-opacity-100 group-hover:ed-visible ed-transition-all ed-duration-200 ed-z-50',
118
+ children: link.children.map((child, cidx) =>
119
+ child.divider
120
+ ? ED.createElement('div', { key: cidx, className: 'ed-my-1 ed-border-t ed-border-gray-100' })
121
+ : ED.createElement('a', {
122
+ key: cidx,
123
+ href: child.href || '#',
124
+ className: 'ed-block ed-px-4 ed-py-2 ed-text-sm ed-text-gray-700 hover:ed-bg-gray-100 hover:ed-text-gray-900 ed-transition-colors',
125
+ onClick: child.onClick,
126
+ children: [
127
+ child.icon ? ED.createElement('i', { className: `ed-mr-2 ${child.icon}`, key: 'icon' }) : null,
128
+ child.label,
129
+ ].filter(Boolean),
130
+ })
131
+ ),
132
+ }),
133
+ ],
134
+ });
135
+ }
136
+
137
+ return ED.createElement('a', {
138
+ key: idx,
139
+ href: link.href || '#',
140
+ className: `ed-px-3 ed-py-2 ed-rounded-md ed-text-sm ed-font-medium ed-transition-colors hover:ed-bg-gray-100 ${link.active ? 'ed-bg-gray-100 ed-font-semibold' : ''} ${textClass}`,
141
+ onClick: link.onClick,
142
+ children: [
143
+ link.icon ? ED.createElement('i', { className: `ed-mr-2 ${link.icon}`, key: 'icon' }) : null,
144
+ ED.createElement('span', { key: 'text' }, link.label),
145
+ ].filter(Boolean),
146
+ });
147
+ });
148
+
149
+ const searchElement = search
150
+ ? ED.createElement('div', {
151
+ className: 'ed-relative ed-mx-4',
152
+ children: [
153
+ ED.createElement('svg', {
154
+ className: 'ed-absolute ed-left-3 ed-top-1/2 ed--translate-y-1/2 ed-w-4 ed-h-4 ed-text-gray-400',
155
+ fill: 'none', viewBox: '0 0 24 24', stroke: 'currentColor',
156
+ children: ED.createElement('path', { strokeLinecap: 'round', strokeLinejoin: 'round', strokeWidth: 2, d: 'M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z' }),
157
+ }),
158
+ ED.createElement('input', {
159
+ className: 'ed-w-48 lg:ed-w-64 ed-pl-9 ed-pr-3 ed-py-1.5 ed-text-sm ed-border ed-border-gray-300 ed-rounded-md ed-bg-gray-50 focus:ed-bg-white focus:ed-outline-none focus:ed-ring-2 focus:ed-ring-blue-500 focus:ed-border-transparent ed-transition-all',
160
+ placeholder: searchPlaceholder,
161
+ type: 'search',
162
+ onKeyDown: (e) => { if (e.key === 'Enter') onSearch?.(e.target.value); },
163
+ }),
164
+ ],
165
+ })
166
+ : null;
167
+
168
+ const notificationElement = notifications > 0 || onNotificationClick
169
+ ? ED.createElement('button', {
170
+ className: `ed-relative ed-p-2 ed-rounded-full ed-transition-colors hover:ed-bg-gray-100 ${textClass}`,
171
+ onClick: onNotificationClick,
172
+ 'aria-label': 'Notifications',
173
+ children: [
174
+ ED.createElement('svg', {
175
+ key: 'bell',
176
+ className: 'ed-w-5 ed-h-5',
177
+ fill: 'none', viewBox: '0 0 24 24', stroke: 'currentColor',
178
+ children: ED.createElement('path', { strokeLinecap: 'round', strokeLinejoin: 'round', strokeWidth: 2, d: 'M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9' }),
179
+ }),
180
+ notifications > 0
181
+ ? ED.createElement('span', {
182
+ key: 'badge',
183
+ className: 'ed-absolute ed-top-0 ed-right-0 ed-inline-flex ed-items-center ed-justify-center ed-w-4 ed-h-4 ed-text-xs ed-font-bold ed-text-white ed-bg-red-500 ed-rounded-full',
184
+ }, notifications > 99 ? '99+' : notifications)
185
+ : null,
186
+ ],
187
+ })
188
+ : null;
189
+
190
+ const userMenuElement = userMenu || userName || userAvatar
191
+ ? ED.createElement('div', { className: 'ed-relative ed-group ed-ml-3' },
192
+ ED.createElement('button', {
193
+ className: 'ed-flex ed-items-center ed-gap-2 ed-p-1.5 ed-rounded-full ed-transition-colors hover:ed-bg-gray-100',
194
+ children: [
195
+ userAvatar
196
+ ? ED.createElement('img', { src: userAvatar, className: 'ed-w-8 ed-h-8 ed-rounded-full ed-object-cover', alt: userName || 'User' })
197
+ : ED.createElement('div', {
198
+ className: 'ed-w-8 ed-h-8 ed-rounded-full ed-bg-blue-500 ed-flex ed-items-center ed-justify-center ed-text-white ed-text-sm ed-font-medium',
199
+ }, userName?.charAt(0)?.toUpperCase() || 'U'),
200
+ userName ? ED.createElement('span', { className: `ed-text-sm ed-font-medium ed-hidden md:ed-inline ${textClass}` }, userName) : null,
201
+ ],
202
+ }),
203
+ userMenuItems.length > 0
204
+ ? ED.createElement('div', {
205
+ className: 'ed-absolute ed-right-0 ed-top-full ed-mt-1 ed-w-56 ed-bg-white ed-rounded-md ed-shadow-lg ed-border ed-border-gray-200 ed-opacity-0 ed-invisible group-hover:ed-opacity-100 group-hover:ed-visible ed-transition-all ed-duration-200 ed-z-50',
206
+ children: userMenuItems.map((item, idx) =>
207
+ item.divider
208
+ ? ED.createElement('div', { key: idx, className: 'ed-my-1 ed-border-t ed-border-gray-100' })
209
+ : ED.createElement('button', {
210
+ key: idx,
211
+ className: 'ed-w-full ed-text-left ed-px-4 ed-py-2 ed-text-sm ed-text-gray-700 hover:ed-bg-gray-100 ed-transition-colors ed-flex ed-items-center ed-gap-2',
212
+ onClick: () => onUserMenuClick?.(item),
213
+ children: [
214
+ item.icon ? ED.createElement('i', { className: item.icon, key: 'icon' }) : null,
215
+ item.label,
216
+ item.danger ? '' : '',
217
+ ].filter(Boolean),
218
+ })
219
+ ),
220
+ })
221
+ : null,
222
+ )
223
+ : null;
224
+
225
+ const hamburgerElement = mobileMenu
226
+ ? ED.createElement('button', {
227
+ className: `ed-p-2 ed-rounded-md ed-transition-colors hover:ed-bg-gray-100 lg:ed-hidden ${textClass}`,
228
+ onClick: onMobileToggle,
229
+ 'aria-label': 'Toggle menu',
230
+ children: ED.createElement('svg', {
231
+ className: 'ed-w-6 ed-h-6',
232
+ fill: 'none', viewBox: '0 0 24 24', stroke: 'currentColor',
233
+ children: mobileOpen
234
+ ? ED.createElement('path', { strokeLinecap: 'round', strokeLinejoin: 'round', strokeWidth: 2, d: 'M6 18L18 6M6 6l12 12' })
235
+ : ED.createElement('path', { strokeLinecap: 'round', strokeLinejoin: 'round', strokeWidth: 2, d: 'M4 6h16M4 12h16M4 18h16' }),
236
+ }),
237
+ })
238
+ : null;
239
+
240
+ const mobileMenuOverlay = mobileOpen
241
+ ? ED.createElement('div', {
242
+ className: 'ed-fixed ed-inset-0 ed-bg-black ed-bg-opacity-50 lg:ed-hidden ed-z-40',
243
+ onClick: onMobileClose,
244
+ })
245
+ : null;
246
+
247
+ const mobileMenuPanel = mobileOpen
248
+ ? ED.createElement('div', {
249
+ className: 'ed-fixed ed-top-16 ed-left-0 ed-right-0 ed-bg-white ed-shadow-lg ed-border-b ed-border-gray-200 lg:ed-hidden ed-z-40 ed-p-4',
250
+ children: links.map((link, idx) =>
251
+ ED.createElement('a', {
252
+ key: idx,
253
+ href: link.href || '#',
254
+ className: 'ed-block ed-px-4 ed-py-3 ed-text-gray-700 hover:ed-bg-gray-100 ed-rounded-md ed-transition-colors',
255
+ onClick: (e) => { link.onClick?.(e); onMobileClose?.(); },
256
+ children: [
257
+ link.icon ? ED.createElement('i', { className: `ed-mr-3 ${link.icon}`, key: 'icon' }) : null,
258
+ link.label,
259
+ ].filter(Boolean),
260
+ })
261
+ ),
262
+ })
263
+ : null;
264
+
265
+ return ED.createElement('nav', {
266
+ className: navClasses,
267
+ style: { height, zIndex, ...(maxWidth ? { maxWidth, margin: '0 auto' } : {}), ...style },
268
+ children: [
269
+ mobileMenuOverlay,
270
+ brandElement,
271
+ leftContent,
272
+ ED.createElement('div', {
273
+ key: 'links',
274
+ className: 'ed-hidden lg:ed-flex ed-items-center ed-gap-1 ed-flex-1',
275
+ children: linkElements,
276
+ }),
277
+ centerContent,
278
+ searchElement,
279
+ ED.createElement('div', { key: 'right', className: 'ed-flex ed-items-center ed-gap-2 ed-ml-auto' },
280
+ notificationElement,
281
+ userMenuElement,
282
+ rightContent,
283
+ hamburgerElement,
284
+ ),
285
+ mobileMenuPanel,
286
+ ].filter(Boolean),
287
+ });
288
+ }
289
+
290
+ Navbar.displayName = 'Navbar';
291
+
292
+ module.exports = Navbar;
@@ -0,0 +1,268 @@
1
+ /**
2
+ * Pagination Component for ElementDrawing Framework
3
+ * Supports page numbers, prev/next, first/last, page size, total count, jumper, simple mode
4
+ */
5
+ const ED = require('../core/element');
6
+
7
+ function Pagination(props) {
8
+ const {
9
+ current = 1,
10
+ pageSize = 10,
11
+ total = 0,
12
+ onChange,
13
+ onPageSizeChange,
14
+ showQuickJumper = false,
15
+ showSizeChanger = false,
16
+ showTotal = false,
17
+ pageSizeOptions = [10, 20, 50, 100],
18
+ className = '',
19
+ style = {},
20
+ simple = false,
21
+ disabled = false,
22
+ size = 'md',
23
+ siblingCount = 1,
24
+ boundaryCount = 1,
25
+ hideOnSinglePage = false,
26
+ showPrevNextJumpers = true,
27
+ showFirstLast = false,
28
+ showTitle = true,
29
+ itemRender,
30
+ prevIcon,
31
+ nextIcon,
32
+ jumpPrevIcon,
33
+ jumpNextIcon,
34
+ } = props;
35
+
36
+ if (hideOnSinglePage && total <= pageSize) return null;
37
+
38
+ const totalPages = Math.max(1, Math.ceil(total / pageSize));
39
+
40
+ const sizeClasses = {
41
+ sm: { btn: 'ed-w-7 ed-h-7 ed-text-xs', select: 'ed-text-xs ed-py-0.5', jumper: 'ed-text-xs ed-w-10' },
42
+ md: { btn: 'ed-w-8 ed-h-8 ed-text-sm', select: 'ed-text-sm ed-py-1', jumper: 'ed-text-sm ed-w-12' },
43
+ lg: { btn: 'ed-w-9 ed-h-9 ed-text-base', select: 'ed-text-base ed-py-1', jumper: 'ed-text-base ed-w-14' },
44
+ };
45
+
46
+ const sizeConfig = sizeClasses[size] || sizeClasses.md;
47
+
48
+ const range = (start, end) => {
49
+ const arr = [];
50
+ for (let i = start; i <= end; i++) arr.push(i);
51
+ return arr;
52
+ };
53
+
54
+ const generatePages = () => {
55
+ const startPages = range(1, Math.min(boundaryCount, totalPages));
56
+ const endPages = range(Math.max(totalPages - boundaryCount + 1, boundaryCount + 1), totalPages);
57
+ const siblingsStart = Math.max(
58
+ Math.min(current - siblingCount, totalPages - boundaryCount - siblingCount * 2 - 1),
59
+ boundaryCount + 2
60
+ );
61
+ const siblingsEnd = Math.min(
62
+ Math.max(current + siblingCount, boundaryCount + siblingCount * 2 + 2),
63
+ endPages.length > 0 ? endPages[0] - 2 : totalPages - 1
64
+ );
65
+
66
+ const pages = [
67
+ ...startPages,
68
+ siblingsStart > startPages[startPages.length - 1] + 1 ? 'start-ellipsis' : null,
69
+ ...range(siblingsStart, siblingsEnd),
70
+ siblingsEnd < endPages[0] - 1 ? 'end-ellipsis' : null,
71
+ ...endPages,
72
+ ].filter((page, idx, arr) => page !== null && arr.indexOf(page) === idx);
73
+
74
+ return pages;
75
+ };
76
+
77
+ const pageButton = (page, label, isActive = false, isDisabled = false) => {
78
+ if (itemRender) return itemRender(page, label ? 'page' : 'page', isActive);
79
+
80
+ return ED.createElement('button', {
81
+ key: `page-${page}`,
82
+ className: [
83
+ sizeConfig.btn,
84
+ 'ed-inline-flex ed-items-center ed-justify-center ed-rounded-md ed-border ed-transition-colors ed-duration-150',
85
+ isActive
86
+ ? 'ed-bg-blue-600 ed-text-white ed-border-blue-600 ed-font-medium'
87
+ : isDisabled
88
+ ? 'ed-border-gray-200 ed-text-gray-300 ed-cursor-not-allowed'
89
+ : 'ed-border-gray-300 ed-text-gray-700 hover:ed-bg-gray-50',
90
+ disabled ? 'ed-pointer-events-none ed-opacity-50' : '',
91
+ ].filter(Boolean).join(' '),
92
+ onClick: isDisabled || isActive ? undefined : () => onChange?.(page),
93
+ disabled: isDisabled || isActive,
94
+ 'aria-current': isActive ? 'page' : undefined,
95
+ 'aria-label': `Page ${page}`,
96
+ title: showTitle ? String(page) : undefined,
97
+ children: label || page,
98
+ });
99
+ };
100
+
101
+ const defaultPrevIcon = ED.createElement('svg', {
102
+ className: 'ed-w-4 ed-h-4',
103
+ fill: 'none', viewBox: '0 0 24 24', stroke: 'currentColor',
104
+ children: ED.createElement('path', { strokeLinecap: 'round', strokeLinejoin: 'round', strokeWidth: 2, d: 'M15 19l-7-7 7-7' }),
105
+ });
106
+
107
+ const defaultNextIcon = ED.createElement('svg', {
108
+ className: 'ed-w-4 ed-h-4',
109
+ fill: 'none', viewBox: '0 0 24 24', stroke: 'currentColor',
110
+ children: ED.createElement('path', { strokeLinecap: 'round', strokeLinejoin: 'round', strokeWidth: 2, d: 'M9 5l7 7-7 7' }),
111
+ });
112
+
113
+ if (simple) {
114
+ return ED.createElement('div', {
115
+ className: `ed-flex ed-items-center ed-gap-2 ${className}`,
116
+ style,
117
+ children: [
118
+ ED.createElement('button', {
119
+ key: 'prev',
120
+ className: `${sizeConfig.btn} ed-inline-flex ed-items-center ed-justify-center ed-rounded-md ed-border ed-border-gray-300 ed-text-gray-700 hover:ed-bg-gray-50 ed-disabled:ed-opacity-50 ed-disabled:ed-cursor-not-allowed`,
121
+ disabled: current <= 1 || disabled,
122
+ onClick: () => onChange?.(current - 1),
123
+ children: prevIcon || defaultPrevIcon,
124
+ }),
125
+ ED.createElement('span', { key: 'current', className: sizeConfig.btn.replace('ed-w-8', '').replace('ed-w-7', '').replace('ed-w-9', '') + ' ed-text-sm ed-text-gray-700' },
126
+ `${current}`
127
+ ),
128
+ ED.createElement('span', { key: 'divider', className: 'ed-text-gray-400' }, '/'),
129
+ ED.createElement('span', { key: 'total', className: 'ed-text-sm ed-text-gray-500' }, totalPages),
130
+ ED.createElement('button', {
131
+ key: 'next',
132
+ className: `${sizeConfig.btn} ed-inline-flex ed-items-center ed-justify-center ed-rounded-md ed-border ed-border-gray-300 ed-text-gray-700 hover:ed-bg-gray-50 ed-disabled:ed-opacity-50 ed-disabled:ed-cursor-not-allowed`,
133
+ disabled: current >= totalPages || disabled,
134
+ onClick: () => onChange?.(current + 1),
135
+ children: nextIcon || defaultNextIcon,
136
+ }),
137
+ ],
138
+ });
139
+ }
140
+
141
+ const firstButton = showFirstLast
142
+ ? ED.createElement('button', {
143
+ key: 'first',
144
+ className: `${sizeConfig.btn} ed-inline-flex ed-items-center ed-justify-center ed-rounded-md ed-border ed-border-gray-300 ed-text-gray-700 hover:ed-bg-gray-50 ed-disabled:ed-opacity-50 ed-disabled:ed-cursor-not-allowed`,
145
+ disabled: current <= 1 || disabled,
146
+ onClick: () => onChange?.(1),
147
+ 'aria-label': 'First page',
148
+ children: ED.createElement('svg', {
149
+ className: 'ed-w-4 ed-h-4',
150
+ fill: 'none', viewBox: '0 0 24 24', stroke: 'currentColor',
151
+ children: ED.createElement('path', { strokeLinecap: 'round', strokeLinejoin: 'round', strokeWidth: 2, d: 'M11 19l-7-7 7-7M19 19l-7-7 7-7' }),
152
+ }),
153
+ })
154
+ : null;
155
+
156
+ const prevButton = ED.createElement('button', {
157
+ key: 'prev',
158
+ className: `${sizeConfig.btn} ed-inline-flex ed-items-center ed-justify-center ed-rounded-md ed-border ed-border-gray-300 ed-text-gray-700 hover:ed-bg-gray-50 ed-disabled:ed-opacity-50 ed-disabled:ed-cursor-not-allowed`,
159
+ disabled: current <= 1 || disabled,
160
+ onClick: () => onChange?.(current - 1),
161
+ 'aria-label': 'Previous page',
162
+ children: prevIcon || defaultPrevIcon,
163
+ });
164
+
165
+ const pages = generatePages();
166
+ const pageButtons = pages.map((page, idx) => {
167
+ if (page === 'start-ellipsis' || page === 'end-ellipsis') {
168
+ return ED.createElement('span', {
169
+ key: `ellipsis-${idx}`,
170
+ className: `${sizeConfig.btn} ed-inline-flex ed-items-center ed-justify-center ed-text-gray-400`,
171
+ children: '...',
172
+ });
173
+ }
174
+ return pageButton(page, null, page === current);
175
+ });
176
+
177
+ const nextButton = ED.createElement('button', {
178
+ key: 'next',
179
+ className: `${sizeConfig.btn} ed-inline-flex ed-items-center ed-justify-center ed-rounded-md ed-border ed-border-gray-300 ed-text-gray-700 hover:ed-bg-gray-50 ed-disabled:ed-opacity-50 ed-disabled:ed-cursor-not-allowed`,
180
+ disabled: current >= totalPages || disabled,
181
+ onClick: () => onChange?.(current + 1),
182
+ 'aria-label': 'Next page',
183
+ children: nextIcon || defaultNextIcon,
184
+ });
185
+
186
+ const lastButton = showFirstLast
187
+ ? ED.createElement('button', {
188
+ key: 'last',
189
+ className: `${sizeConfig.btn} ed-inline-flex ed-items-center ed-justify-center ed-rounded-md ed-border ed-border-gray-300 ed-text-gray-700 hover:ed-bg-gray-50 ed-disabled:ed-opacity-50 ed-disabled:ed-cursor-not-allowed`,
190
+ disabled: current >= totalPages || disabled,
191
+ onClick: () => onChange?.(totalPages),
192
+ 'aria-label': 'Last page',
193
+ children: ED.createElement('svg', {
194
+ className: 'ed-w-4 ed-h-4',
195
+ fill: 'none', viewBox: '0 0 24 24', stroke: 'currentColor',
196
+ children: ED.createElement('path', { strokeLinecap: 'round', strokeLinejoin: 'round', strokeWidth: 2, d: 'M13 5l7 7-7 7M5 5l7 7-7 7' }),
197
+ }),
198
+ })
199
+ : null;
200
+
201
+ const sizeChanger = showSizeChanger
202
+ ? ED.createElement('select', {
203
+ key: 'size-changer',
204
+ className: `${sizeConfig.select} ed-px-2 ed-border ed-border-gray-300 ed-rounded-md ed-bg-white ed-text-gray-700 ed-outline-none focus:ed-ring-1 focus:ed-ring-blue-500`,
205
+ value: pageSize,
206
+ onChange: (e) => onPageSizeChange?.(Number(e.target.value)),
207
+ disabled,
208
+ children: pageSizeOptions.map(opt =>
209
+ ED.createElement('option', { key: opt, value: opt }, `${opt} / page`)
210
+ ),
211
+ })
212
+ : null;
213
+
214
+ const totalDisplay = showTotal
215
+ ? ED.createElement('span', {
216
+ key: 'total',
217
+ className: 'ed-text-sm ed-text-gray-500 ed-mr-2',
218
+ }, typeof showTotal === 'function'
219
+ ? showTotal(total, [(current - 1) * pageSize + 1, Math.min(current * pageSize, total)])
220
+ : `Total ${total} items`
221
+ )
222
+ : null;
223
+
224
+ const jumper = showQuickJumper
225
+ ? ED.createElement('div', {
226
+ key: 'jumper',
227
+ className: 'ed-flex ed-items-center ed-gap-2 ed-ml-2',
228
+ children: [
229
+ ED.createElement('span', { key: 'label', className: 'ed-text-sm ed-text-gray-500' }, 'Go to'),
230
+ ED.createElement('input', {
231
+ key: 'input',
232
+ className: `${sizeConfig.jumper} ed-px-2 ed-py-1 ed-text-center ed-border ed-border-gray-300 ed-rounded-md ed-text-sm ed-outline-none focus:ed-ring-1 focus:ed-ring-blue-500`,
233
+ type: 'number',
234
+ min: 1,
235
+ max: totalPages,
236
+ disabled,
237
+ onKeyDown: (e) => {
238
+ if (e.key === 'Enter') {
239
+ const val = parseInt(e.target.value, 10);
240
+ if (val >= 1 && val <= totalPages) onChange?.(val);
241
+ }
242
+ },
243
+ }),
244
+ ],
245
+ })
246
+ : null;
247
+
248
+ return ED.createElement('nav', {
249
+ className: `ed-flex ed-items-center ed-gap-1 ed-flex-wrap ${className}`,
250
+ style,
251
+ role: 'navigation',
252
+ 'aria-label': 'Pagination',
253
+ children: [
254
+ totalDisplay,
255
+ firstButton,
256
+ prevButton,
257
+ ...pageButtons,
258
+ nextButton,
259
+ lastButton,
260
+ sizeChanger,
261
+ jumper,
262
+ ].filter(Boolean),
263
+ });
264
+ }
265
+
266
+ Pagination.displayName = 'Pagination';
267
+
268
+ module.exports = Pagination;