@abstraks-dev/ui-library 1.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.
Files changed (158) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +708 -0
  3. package/dist/__tests__/Anchor.test.js +145 -0
  4. package/dist/__tests__/ArrowRight.test.js +91 -0
  5. package/dist/__tests__/Avatar.test.js +123 -0
  6. package/dist/__tests__/Button.test.js +82 -0
  7. package/dist/__tests__/Card.test.js +198 -0
  8. package/dist/__tests__/CheckCircle.test.js +98 -0
  9. package/dist/__tests__/Checkbox.test.js +161 -0
  10. package/dist/__tests__/ChevronDown.test.js +73 -0
  11. package/dist/__tests__/Close.test.js +98 -0
  12. package/dist/__tests__/EditSquare.test.js +99 -0
  13. package/dist/__tests__/Error.test.js +74 -0
  14. package/dist/__tests__/Footer.test.js +66 -0
  15. package/dist/__tests__/Heading.test.js +227 -0
  16. package/dist/__tests__/Hero.test.js +74 -0
  17. package/dist/__tests__/Label.test.js +123 -0
  18. package/dist/__tests__/Loader.test.js +115 -0
  19. package/dist/__tests__/MenuHover.test.js +137 -0
  20. package/dist/__tests__/Paragraph.test.js +93 -0
  21. package/dist/__tests__/PlusCircle.test.js +99 -0
  22. package/dist/__tests__/Radio.test.js +153 -0
  23. package/dist/__tests__/Select.test.js +187 -0
  24. package/dist/__tests__/Tabs.test.js +162 -0
  25. package/dist/__tests__/TextArea.test.js +127 -0
  26. package/dist/__tests__/TextInput.test.js +181 -0
  27. package/dist/__tests__/Toggle.test.js +120 -0
  28. package/dist/__tests__/TrashX.test.js +99 -0
  29. package/dist/__tests__/useHeadingAccessibility.test.js +144 -0
  30. package/dist/components/Anchor.js +131 -0
  31. package/dist/components/Animation.js +129 -0
  32. package/dist/components/AnimationGroup.js +207 -0
  33. package/dist/components/AnimationToggle.js +216 -0
  34. package/dist/components/Avatar.js +153 -0
  35. package/dist/components/Button.js +218 -0
  36. package/dist/components/Card.js +222 -0
  37. package/dist/components/Checkbox.js +305 -0
  38. package/dist/components/Crud.js +564 -0
  39. package/dist/components/DragAndDrop.js +337 -0
  40. package/dist/components/Error.js +206 -0
  41. package/dist/components/Footer.js +99 -0
  42. package/dist/components/Form.js +412 -0
  43. package/dist/components/Header.js +372 -0
  44. package/dist/components/Heading.js +134 -0
  45. package/dist/components/Hero.js +181 -0
  46. package/dist/components/Label.js +256 -0
  47. package/dist/components/Loader.js +302 -0
  48. package/dist/components/MenuHover.js +114 -0
  49. package/dist/components/Paragraph.js +128 -0
  50. package/dist/components/Prompt.js +61 -0
  51. package/dist/components/Radio.js +254 -0
  52. package/dist/components/Select.js +422 -0
  53. package/dist/components/SideMenu.js +313 -0
  54. package/dist/components/Tabs.js +297 -0
  55. package/dist/components/TextArea.js +370 -0
  56. package/dist/components/TextInput.js +286 -0
  57. package/dist/components/Toggle.js +186 -0
  58. package/dist/components/crudFiles/CrudEditBase.js +150 -0
  59. package/dist/components/crudFiles/CrudViewBase.js +39 -0
  60. package/dist/components/crudFiles/crudDevelopment.js +118 -0
  61. package/dist/components/crudFiles/crudEditHandlers.js +50 -0
  62. package/dist/constants/animation.js +30 -0
  63. package/dist/icons/ArrowIcon.js +32 -0
  64. package/dist/icons/ArrowRight.js +33 -0
  65. package/dist/icons/CheckCircle.js +33 -0
  66. package/dist/icons/ChevronDown.js +28 -0
  67. package/dist/icons/Close.js +33 -0
  68. package/dist/icons/EditSquare.js +33 -0
  69. package/dist/icons/Ellipses.js +34 -0
  70. package/dist/icons/Hamburger.js +39 -0
  71. package/dist/icons/LoadingSpinner.js +42 -0
  72. package/dist/icons/PlusCircle.js +33 -0
  73. package/dist/icons/SaveIcon.js +32 -0
  74. package/dist/icons/TrashX.js +33 -0
  75. package/dist/icons/__tests__/CheckCircle.test.js +9 -0
  76. package/dist/icons/__tests__/ChevronDown.test.js +9 -0
  77. package/dist/icons/__tests__/Close.test.js +9 -0
  78. package/dist/icons/__tests__/EditSquare.test.js +9 -0
  79. package/dist/icons/__tests__/PlusCircle.test.js +9 -0
  80. package/dist/icons/__tests__/TrashX.test.js +9 -0
  81. package/dist/icons/index.js +89 -0
  82. package/dist/index.js +332 -0
  83. package/dist/setupTests.js +3 -0
  84. package/dist/styles/_variables.scss +286 -0
  85. package/dist/styles/anchor.scss +40 -0
  86. package/dist/styles/animation-accessibility.scss +96 -0
  87. package/dist/styles/animation-toggle.scss +233 -0
  88. package/dist/styles/animation.scss +3781 -0
  89. package/dist/styles/avatar.scss +285 -0
  90. package/dist/styles/button.scss +430 -0
  91. package/dist/styles/card.scss +210 -0
  92. package/dist/styles/checkbox.scss +160 -0
  93. package/dist/styles/crud.scss +474 -0
  94. package/dist/styles/dragAndDrop.scss +312 -0
  95. package/dist/styles/error.scss +232 -0
  96. package/dist/styles/footer.scss +58 -0
  97. package/dist/styles/form.scss +420 -0
  98. package/dist/styles/grid.scss +29 -0
  99. package/dist/styles/header.scss +276 -0
  100. package/dist/styles/heading.scss +118 -0
  101. package/dist/styles/hero.scss +185 -0
  102. package/dist/styles/htmlElements.scss +20 -0
  103. package/dist/styles/image.scss +9 -0
  104. package/dist/styles/label.scss +340 -0
  105. package/dist/styles/list-item.scss +5 -0
  106. package/dist/styles/loader.scss +354 -0
  107. package/dist/styles/logo.scss +19 -0
  108. package/dist/styles/main.css +9056 -0
  109. package/dist/styles/main.css.map +1 -0
  110. package/dist/styles/main.scss +0 -0
  111. package/dist/styles/menu-hover.scss +30 -0
  112. package/dist/styles/paragraph.scss +88 -0
  113. package/dist/styles/prompt.scss +51 -0
  114. package/dist/styles/radio.scss +202 -0
  115. package/dist/styles/select.scss +363 -0
  116. package/dist/styles/side-menu.scss +334 -0
  117. package/dist/styles/tabs.scss +540 -0
  118. package/dist/styles/text-area.scss +388 -0
  119. package/dist/styles/text-input.scss +171 -0
  120. package/dist/styles/toggle.scss +0 -0
  121. package/dist/styles/unordered-list.scss +8 -0
  122. package/dist/utils/ScrollHandler.js +30 -0
  123. package/dist/utils/accessibility.js +128 -0
  124. package/dist/utils/heroUtils.js +316 -0
  125. package/dist/utils/index.js +104 -0
  126. package/dist/utils/inputValidation.js +29 -0
  127. package/dist/utils/keyboardNavigation.js +536 -0
  128. package/dist/utils/labelUtils.js +708 -0
  129. package/dist/utils/loaderUtils.js +387 -0
  130. package/dist/utils/menuUtils.js +575 -0
  131. package/dist/utils/useHeadingAccessibility.js +298 -0
  132. package/dist/utils/useRadioGroup.js +260 -0
  133. package/dist/utils/useSelectAccessibility.js +426 -0
  134. package/dist/utils/useTabsAccessibility.js +278 -0
  135. package/dist/utils/useTextAreaAccessibility.js +255 -0
  136. package/dist/utils/useTextInputAccessibility.js +295 -0
  137. package/dist/utils/useTypographyAccessibility.js +168 -0
  138. package/dist/utils/useWindowSize.js +32 -0
  139. package/dist/utils/utils/ScrollHandler.js +26 -0
  140. package/dist/utils/utils/accessibility.js +133 -0
  141. package/dist/utils/utils/heroUtils.js +348 -0
  142. package/dist/utils/utils/index.js +9 -0
  143. package/dist/utils/utils/inputValidation.js +22 -0
  144. package/dist/utils/utils/keyboardNavigation.js +664 -0
  145. package/dist/utils/utils/labelUtils.js +772 -0
  146. package/dist/utils/utils/loaderUtils.js +436 -0
  147. package/dist/utils/utils/menuUtils.js +651 -0
  148. package/dist/utils/utils/useHeadingAccessibility.js +334 -0
  149. package/dist/utils/utils/useRadioGroup.js +311 -0
  150. package/dist/utils/utils/useSelectAccessibility.js +498 -0
  151. package/dist/utils/utils/useTabsAccessibility.js +316 -0
  152. package/dist/utils/utils/useTextAreaAccessibility.js +303 -0
  153. package/dist/utils/utils/useTextInputAccessibility.js +338 -0
  154. package/dist/utils/utils/useTypographyAccessibility.js +180 -0
  155. package/dist/utils/utils/useWindowSize.js +26 -0
  156. package/dist/utils/utils/validation.js +131 -0
  157. package/dist/utils/validation.js +139 -0
  158. package/package.json +90 -0
@@ -0,0 +1,564 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = exports.Crud = void 0;
7
+ var _react = _interopRequireWildcard(require("react"));
8
+ var _propTypes = _interopRequireWildcard(require("prop-types"));
9
+ var _Button = require("./Button");
10
+ var _TextInput = require("./TextInput");
11
+ var _Select = require("./Select");
12
+ var _Paragraph = require("./Paragraph");
13
+ var _icons = require("../icons");
14
+ var _Prompt = _interopRequireDefault(require("./Prompt"));
15
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
16
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
17
+ function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
18
+ /**
19
+ * CRUD Component - A completely stateless, accessible list management component
20
+ *
21
+ * This component provides Create, Read, Update, Delete functionality with:
22
+ * - Full accessibility support (ARIA, keyboard navigation, screen reader)
23
+ * - Smooth animations for add/remove operations (compatible with drag-and-drop)
24
+ * - Drag and drop reordering capability with proper event handling
25
+ * - Support for both input and select elements
26
+ * - Flexible animation system that works seamlessly with drag operations
27
+ *
28
+ * All state management and business logic should be handled by parent components.
29
+ * This ensures maximum flexibility and reusability.
30
+ *
31
+ * ## Accessibility Features
32
+ * - Full keyboard navigation (Tab, Enter, Space, Delete, Escape)
33
+ * - Screen reader announcements via ARIA live regions
34
+ * - Proper ARIA labeling and descriptions
35
+ * - Focus management and indicators
36
+ * - High contrast mode support
37
+ * - Reduced motion preferences respected
38
+ *
39
+ * ## Technical Implementation
40
+ * - When animations are enabled, drag events are applied to the CSSTransition wrapper
41
+ * - When animations are disabled, drag events are applied directly to items
42
+ * - This dual approach ensures reliable drag-and-drop in both modes
43
+ *
44
+ * @component
45
+ * @example
46
+ * // Basic usage (stateless)
47
+ * <Crud
48
+ * items={items}
49
+ * onItemAdd={handleAdd}
50
+ * onItemEdit={handleEdit}
51
+ * onItemSave={handleSave}
52
+ * onItemDelete={handleDelete}
53
+ * enableAnimations={true}
54
+ * enableDragDrop={false}
55
+ * ariaLabel="Task list management"
56
+ * />
57
+ *
58
+ * @param {Object} props - Component props
59
+ * @param {string} [props.componentName='crud'] - Base CSS class name
60
+ * @param {string} [props.additionalClassName=''] - Additional CSS classes
61
+ * @param {string} [props.placeholder='Type here...'] - Placeholder text for input fields
62
+ * @param {string} props.addBtnText - Text for the add button (required)
63
+ * @param {Array} props.items - Array of CRUD items with {id, content, editable, checked} (required)
64
+ * @param {string} [props.element='input'] - Input element type ('input' or 'select')
65
+ * @param {string} [props.optionValue='Select an option'] - Default option text for select elements
66
+ * @param {Array} [props.selectOptions=[]] - Options for select elements
67
+ * @param {Function} props.onItemAdd - Callback for adding new items (required)
68
+ * @param {Function} props.onItemEdit - Callback for editing items (required)
69
+ * @param {Function} props.onItemSave - Callback for saving items (required)
70
+ * @param {Function} props.onItemDelete - Callback for deleting items (required)
71
+ * @param {Function} [props.onItemChange] - Callback for input changes
72
+ * @param {Function} [props.onDragStart] - Callback for drag start events
73
+ * @param {Function} [props.onDragOver] - Callback for drag over events
74
+ * @param {Function} [props.onDragEnter] - Callback for drag enter events
75
+ * @param {Function} [props.onDragLeave] - Callback for drag leave events
76
+ * @param {Function} [props.onDrop] - Callback for drop events
77
+ * @param {Function} [props.onKeyDown] - Callback for keyboard events
78
+ * @param {boolean} [props.enableAnimations=true] - Enable/disable animations (compatible with drag-drop)
79
+ * @param {boolean} [props.enableDragDrop=false] - Enable/disable drag and drop
80
+ * @param {boolean} [props.showAddButton=true] - Show/hide add button
81
+ * @param {string} [props.ariaLabel='CRUD list management'] - Accessible label for the component
82
+ * @param {string} [props.ariaDescribedBy] - ID of element describing the component
83
+ * @param {Object} [props.dragState] - Current drag and drop state
84
+ * @param {boolean} [props.dragState.isDragging=false] - Whether an item is being dragged
85
+ * @param {number|string} [props.dragState.draggedFrom] - Index of item being dragged
86
+ * @param {number|string} [props.dragState.draggedTo] - Index of drop target
87
+ */
88
+ const Crud = exports.Crud = /*#__PURE__*/(0, _react.forwardRef)(({
89
+ // Core props
90
+ id,
91
+ className = '',
92
+ // Content props
93
+ items = [],
94
+ placeholder = 'Type here...',
95
+ addBtnText = 'Add',
96
+ element = 'input',
97
+ optionValue = 'Select an option',
98
+ selectOptions = [],
99
+ // Behavior props
100
+ enableAnimations = true,
101
+ enableDragDrop = false,
102
+ showAddButton = true,
103
+ // Event props
104
+ onItemAdd = null,
105
+ onItemEdit = null,
106
+ onItemSave = null,
107
+ onItemDelete = null,
108
+ onItemChange = null,
109
+ onDragStart = null,
110
+ onDragOver = null,
111
+ onDragEnter = null,
112
+ onDragLeave = null,
113
+ onDrop = null,
114
+ onKeyDown = null,
115
+ // Accessibility props
116
+ 'aria-label': ariaLabel = 'CRUD list management',
117
+ 'aria-describedby': ariaDescribedBy = null,
118
+ // Drag and drop state
119
+ dragState = {
120
+ isDragging: false,
121
+ draggedFrom: null,
122
+ draggedTo: null
123
+ },
124
+ // Animation control
125
+ lastEditedId = null,
126
+ // Legacy props (for backward compatibility - internal use only)
127
+ componentName = 'crud',
128
+ additionalClassName = '',
129
+ // Prompt props
130
+ promptOpen = false,
131
+ promptMessage = 'Are you sure you want to delete this item?',
132
+ onPromptConfirm,
133
+ onPromptCancel,
134
+ onPromptDelete,
135
+ ...props
136
+ }, ref) => {
137
+ // Handle legacy prop mapping
138
+ const finalId = id || componentName || `crud-${Math.random().toString(36).substr(2, 9)}`;
139
+ const finalClassName = className || additionalClassName;
140
+
141
+ /**
142
+ * ========================
143
+ * State (fully controlled by parent)
144
+ * ========================
145
+ *
146
+ * All state (items, inputValue, selectInputValue) must be managed by the parent.
147
+ * This component is now fully stateless.
148
+ */
149
+
150
+ /**
151
+ * Handles keyboard events for each item
152
+ */
153
+ const handleItemKeyDown = (event, item, index) => {
154
+ const {
155
+ key
156
+ } = event;
157
+
158
+ // Delete key to delete item
159
+ if (key === 'Delete' && !item.editable) {
160
+ event.preventDefault();
161
+ onItemDelete?.(item, index);
162
+ }
163
+
164
+ // Escape to cancel editing
165
+ if (key === 'Escape' && item.editable) {
166
+ event.preventDefault();
167
+ onItemEdit?.(item, index, false); // Cancel edit
168
+ }
169
+ onKeyDown?.(event, item, index);
170
+ };
171
+
172
+ /**
173
+ * Handles input changes (delegated to parent)
174
+ */
175
+ const handleChange = (event, item, index) => {
176
+ const {
177
+ name,
178
+ value
179
+ } = event.target;
180
+ onItemChange?.(event, item, index, {
181
+ [name]: value
182
+ });
183
+ };
184
+
185
+ /**
186
+ * Handles drag and drop events
187
+ */
188
+ const handleDragStart = (event, item, index) => {
189
+ if (!enableDragDrop) return;
190
+ event.dataTransfer.effectAllowed = 'move';
191
+ event.dataTransfer.setData('text/html', '');
192
+ event.stopPropagation(); // Prevent event from bubbling
193
+ onDragStart?.(event, item, index);
194
+ };
195
+ const handleDragOver = (event, item, index) => {
196
+ if (!enableDragDrop) return;
197
+ event.preventDefault();
198
+ event.stopPropagation(); // Prevent event from bubbling
199
+ event.dataTransfer.dropEffect = 'move';
200
+ onDragOver?.(event, item, index);
201
+ };
202
+ const handleDragEnter = (event, item, index) => {
203
+ if (!enableDragDrop) return;
204
+ event.preventDefault();
205
+ onDragEnter?.(event, item, index);
206
+ };
207
+ const handleDragLeave = (event, item, index) => {
208
+ if (!enableDragDrop) return;
209
+ onDragLeave?.(event, item, index);
210
+ };
211
+ const handleDrop = (event, item, index) => {
212
+ if (!enableDragDrop) return;
213
+ event.preventDefault();
214
+ event.stopPropagation(); // Prevent event from bubbling
215
+ onDrop?.(event, item, index);
216
+ };
217
+ const handleDragEnd = (event, item, index) => {
218
+ if (!enableDragDrop) return;
219
+
220
+ // Reset any drag-related styling or state
221
+ };
222
+
223
+ /**
224
+ * Renders a single CRUD item
225
+ */
226
+ const renderItem = (item, index, applyDragEvents = true) => {
227
+ const isDragging = dragState.isDragging && dragState.draggedFrom === index;
228
+ const isDropTarget = dragState.draggedTo === index;
229
+ return /*#__PURE__*/_react.default.createElement("div", {
230
+ key: item.id,
231
+ className: `item ${isDragging ? 'dragging' : ''} ${isDropTarget ? 'drop-target' : ''}`,
232
+ "data-position": applyDragEvents ? index : undefined,
233
+ draggable: applyDragEvents && enableDragDrop && !item.editable,
234
+ onDragStart: applyDragEvents && enableDragDrop && !item.editable ? e => handleDragStart(e, item, index) : undefined,
235
+ onDragOver: applyDragEvents && enableDragDrop ? e => {
236
+ e.preventDefault();
237
+ e.stopPropagation();
238
+ e.dataTransfer.dropEffect = 'move';
239
+ handleDragOver(e, item, index);
240
+ } : undefined,
241
+ onDragEnter: applyDragEvents && enableDragDrop ? e => {
242
+ e.preventDefault();
243
+ e.stopPropagation();
244
+ handleDragEnter(e, item, index);
245
+ } : undefined,
246
+ onDragLeave: applyDragEvents && enableDragDrop ? e => handleDragLeave(e, item, index) : undefined,
247
+ onDrop: applyDragEvents && enableDragDrop ? e => handleDrop(e, item, index) : undefined,
248
+ onDragEnd: applyDragEvents && enableDragDrop && !item.editable ? e => handleDragEnd(e, item, index) : undefined,
249
+ style: {
250
+ position: 'relative',
251
+ display: 'flex',
252
+ alignItems: 'center',
253
+ minHeight: '40px',
254
+ cursor: applyDragEvents && enableDragDrop && !item.editable ? 'grab' : 'default',
255
+ // Only apply drag styling when drag events are applied to this element
256
+ ...(applyDragEvents && {
257
+ // Ensure no CSS is blocking drag events
258
+ pointerEvents: 'auto',
259
+ touchAction: 'none',
260
+ userSelect: 'none',
261
+ // Add a background to make sure the drop zone is visible
262
+ backgroundColor: isDropTarget ? '#e3f2fd' : 'transparent',
263
+ border: isDropTarget ? '1px solid #2196f3' : enableDragDrop && !item.editable ? '1px solid transparent' : 'none'
264
+ })
265
+ },
266
+ role: "listitem",
267
+ "aria-describedby": item.editable ? `item-${item.id}-editing` : undefined
268
+ }, enableDragDrop && !item.editable && /*#__PURE__*/_react.default.createElement("div", {
269
+ style: {
270
+ width: '20px',
271
+ height: '100%',
272
+ display: 'flex',
273
+ alignItems: 'center',
274
+ justifyContent: 'center',
275
+ backgroundColor: '#f0f0f0',
276
+ borderRight: '1px solid #ddd',
277
+ userSelect: 'none',
278
+ pointerEvents: 'none' // Don't interfere with drag events
279
+ },
280
+ "aria-hidden": "true"
281
+ }, "\u22EE\u22EE"), /*#__PURE__*/_react.default.createElement("div", {
282
+ className: "item-content-wrapper",
283
+ style: {
284
+ flex: 1,
285
+ display: 'flex',
286
+ alignItems: 'center',
287
+ minHeight: '40px',
288
+ // Disable pointer events on children when dragging to ensure drag events reach parent
289
+ pointerEvents: isDragging ? 'none' : 'auto'
290
+ },
291
+ tabIndex: item.editable ? -1 : 0,
292
+ onKeyDown: e => handleItemKeyDown(e, item, index)
293
+ }, /*#__PURE__*/_react.default.createElement("div", {
294
+ className: "input-container"
295
+ }, item.editable ? /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, element === 'input' && /*#__PURE__*/_react.default.createElement(_TextInput.TextInput, {
296
+ id: `crud-input-${item.id}`,
297
+ name: "content",
298
+ type: "text",
299
+ value: item.content || '',
300
+ placeholder: placeholder,
301
+ onChange: e => handleChange(e, item, index),
302
+ className: "input text-input",
303
+ "data-testid": "crud-input",
304
+ "aria-label": `Edit item ${index + 1}`,
305
+ "aria-describedby": `item-${item.id}-editing`,
306
+ autoFocus: true
307
+ }), element === 'select' && /*#__PURE__*/_react.default.createElement(_Select.Select, {
308
+ id: `crud-select-${item.id}`,
309
+ name: "content",
310
+ value: item.content || '',
311
+ placeholder: optionValue,
312
+ onChange: e => handleChange(e, item, index),
313
+ options: selectOptions,
314
+ className: "input select-input",
315
+ hideLabel: true,
316
+ "data-testid": "crud-select",
317
+ "aria-label": `Select option for item ${index + 1}`,
318
+ "aria-describedby": `item-${item.id}-editing`
319
+ }), /*#__PURE__*/_react.default.createElement("div", {
320
+ id: `item-${item.id}-editing`,
321
+ className: "sr-only",
322
+ "aria-live": "polite"
323
+ }, "Currently editing item ", index + 1, ". Press Enter to save, Escape to cancel.")) : /*#__PURE__*/_react.default.createElement(_Paragraph.Paragraph, {
324
+ componentName: "item-content",
325
+ role: "text",
326
+ "aria-label": `Item ${index + 1}: ${item.content}`
327
+ }, item.content)), /*#__PURE__*/_react.default.createElement("div", {
328
+ className: "inside-btns",
329
+ role: "group",
330
+ "aria-label": `Actions for item ${index + 1}`
331
+ }, item.editable ?
332
+ /*#__PURE__*/
333
+ // Editing mode buttons
334
+ _react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("button", {
335
+ type: "button",
336
+ className: "btn-icon save-btn",
337
+ onClick: () => onItemSave?.(item, index),
338
+ "aria-label": `Save changes to item ${index + 1}`,
339
+ title: "Save changes"
340
+ }, /*#__PURE__*/_react.default.createElement(_icons.CheckCircle, {
341
+ fill: "#57F500"
342
+ }), /*#__PURE__*/_react.default.createElement("span", {
343
+ className: "text"
344
+ }, "Save")), /*#__PURE__*/_react.default.createElement("button", {
345
+ type: "button",
346
+ className: "btn-icon delete-btn",
347
+ onClick: () => onPromptDelete?.(item, index),
348
+ "aria-label": `Delete item ${index + 1}`,
349
+ title: "Delete item"
350
+ }, /*#__PURE__*/_react.default.createElement(_icons.TrashX, {
351
+ fill: "red"
352
+ }), /*#__PURE__*/_react.default.createElement("span", {
353
+ className: "text"
354
+ }, "Delete"))) :
355
+ /*#__PURE__*/
356
+ // View mode buttons
357
+ _react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("button", {
358
+ type: "button",
359
+ className: "btn-icon edit-btn",
360
+ onClick: () => onItemEdit?.(item, index),
361
+ "aria-label": `Edit item ${index + 1}`,
362
+ title: "Edit item"
363
+ }, /*#__PURE__*/_react.default.createElement(_icons.EditSquare, {
364
+ fill: "#333"
365
+ }), /*#__PURE__*/_react.default.createElement("span", {
366
+ className: "text"
367
+ }, "Edit")), /*#__PURE__*/_react.default.createElement("button", {
368
+ type: "button",
369
+ className: "btn-icon delete-btn",
370
+ onClick: () => onPromptDelete?.(item, index),
371
+ "aria-label": `Delete item ${index + 1}`,
372
+ title: "Delete item"
373
+ }, /*#__PURE__*/_react.default.createElement(_icons.TrashX, {
374
+ fill: "red"
375
+ }), /*#__PURE__*/_react.default.createElement("span", {
376
+ className: "text"
377
+ }, "Delete"))))));
378
+ };
379
+ return /*#__PURE__*/_react.default.createElement("div", _extends({
380
+ ref: ref,
381
+ id: finalId,
382
+ className: `crud ${finalClassName}`.trim(),
383
+ "data-testid": finalId,
384
+ role: "region",
385
+ "aria-label": ariaLabel,
386
+ "aria-describedby": ariaDescribedBy
387
+ }, props), /*#__PURE__*/_react.default.createElement("div", {
388
+ className: "list",
389
+ role: "list",
390
+ "aria-label": `List of ${items.length} items`,
391
+ "aria-live": "polite"
392
+ }, items.map((item, index) => renderItem(item, index))), showAddButton && /*#__PURE__*/_react.default.createElement(_Button.Button, {
393
+ additionalClassName: "add-btn",
394
+ onClick: onItemAdd,
395
+ "aria-label": "Add new item to list",
396
+ title: "Add new item",
397
+ variant: "primary"
398
+ }, /*#__PURE__*/_react.default.createElement(_icons.PlusCircle, {
399
+ fill: "#fff"
400
+ }), /*#__PURE__*/_react.default.createElement("span", {
401
+ className: "text"
402
+ }, addBtnText)), /*#__PURE__*/_react.default.createElement("div", {
403
+ className: "sr-only",
404
+ "aria-live": "assertive",
405
+ "aria-atomic": "true"
406
+ }), /*#__PURE__*/_react.default.createElement(_Prompt.default, {
407
+ open: promptOpen,
408
+ message: promptMessage,
409
+ onConfirm: onPromptConfirm,
410
+ onCancel: onPromptCancel
411
+ }));
412
+ });
413
+
414
+ // Set display name for better debugging
415
+ Crud.displayName = 'Crud';
416
+ Crud.propTypes = {
417
+ // ============================================================================
418
+ // CORE PROPS
419
+ // ============================================================================
420
+
421
+ /**
422
+ * Unique identifier for the component
423
+ */
424
+ id: _propTypes.string,
425
+ /**
426
+ * Additional CSS classes to apply to the component
427
+ */
428
+ className: _propTypes.string,
429
+ // ============================================================================
430
+ // CONTENT PROPS
431
+ // ============================================================================
432
+
433
+ /**
434
+ * Array of CRUD items with structure: {id, content, editable, checked} (REQUIRED)
435
+ */
436
+ items: _propTypes.array.isRequired,
437
+ /**
438
+ * Placeholder text for input fields
439
+ */
440
+ placeholder: _propTypes.string,
441
+ /**
442
+ * Text for the add button (REQUIRED)
443
+ */
444
+ addBtnText: _propTypes.string.isRequired,
445
+ /**
446
+ * Input element type ('input' or 'select')
447
+ */
448
+ element: _propTypes.string,
449
+ /**
450
+ * Default option text for select elements
451
+ */
452
+ optionValue: _propTypes.string,
453
+ /**
454
+ * Array of option elements for select inputs
455
+ */
456
+ selectOptions: _propTypes.array,
457
+ // ============================================================================
458
+ // BEHAVIOR PROPS
459
+ // ============================================================================
460
+
461
+ /**
462
+ * Enable/disable animations for add/remove operations
463
+ */
464
+ enableAnimations: _propTypes.bool,
465
+ /**
466
+ * Enable/disable drag and drop functionality
467
+ */
468
+ enableDragDrop: _propTypes.bool,
469
+ /**
470
+ * Show/hide the add button
471
+ */
472
+ showAddButton: _propTypes.bool,
473
+ // ============================================================================
474
+ // EVENT PROPS
475
+ // ============================================================================
476
+
477
+ /**
478
+ * Callback function for adding new items (REQUIRED)
479
+ */
480
+ onItemAdd: _propTypes.func.isRequired,
481
+ /**
482
+ * Callback function for editing items (REQUIRED)
483
+ */
484
+ onItemEdit: _propTypes.func.isRequired,
485
+ /**
486
+ * Callback function for saving item changes (REQUIRED)
487
+ */
488
+ onItemSave: _propTypes.func.isRequired,
489
+ /**
490
+ * Callback function for deleting items (REQUIRED)
491
+ */
492
+ onItemDelete: _propTypes.func.isRequired,
493
+ /**
494
+ * Callback function for input value changes
495
+ */
496
+ onItemChange: _propTypes.func,
497
+ /**
498
+ * Callback function for drag start events
499
+ */
500
+ onDragStart: _propTypes.func,
501
+ /**
502
+ * Callback function for drag over events
503
+ */
504
+ onDragOver: _propTypes.func,
505
+ /**
506
+ * Callback function for drag enter events
507
+ */
508
+ onDragEnter: _propTypes.func,
509
+ /**
510
+ * Callback function for drag leave events
511
+ */
512
+ onDragLeave: _propTypes.func,
513
+ /**
514
+ * Callback function for drop events
515
+ */
516
+ onDrop: _propTypes.func,
517
+ /**
518
+ * Callback function for keyboard events
519
+ */
520
+ onKeyDown: _propTypes.func,
521
+ // ============================================================================
522
+ // ACCESSIBILITY PROPS
523
+ // ============================================================================
524
+
525
+ /**
526
+ * Accessible label for the entire component
527
+ */
528
+ 'aria-label': _propTypes.string,
529
+ /**
530
+ * ID of element that describes the component
531
+ */
532
+ 'aria-describedby': _propTypes.string,
533
+ // ============================================================================
534
+ // INTERNAL STATE PROPS
535
+ // ============================================================================
536
+
537
+ /**
538
+ * Current drag and drop state object
539
+ */
540
+ dragState: (0, _propTypes.shape)({
541
+ isDragging: _propTypes.bool,
542
+ draggedFrom: (0, _propTypes.oneOfType)([_propTypes.number, _propTypes.string]),
543
+ draggedTo: (0, _propTypes.oneOfType)([_propTypes.number, _propTypes.string]),
544
+ originalOrder: _propTypes.array,
545
+ updatedOrder: _propTypes.array
546
+ }),
547
+ /**
548
+ * Use 'id' instead. Base CSS class name for the component
549
+ */
550
+ componentName: _propTypes.string,
551
+ /**
552
+ * Use 'className' instead. Additional CSS classes to apply
553
+ */
554
+ additionalClassName: _propTypes.string,
555
+ /**
556
+ * Use 'aria-label' instead. Accessible label for the component
557
+ */
558
+ ariaLabel: _propTypes.string,
559
+ /**
560
+ * Use 'aria-describedby' instead. ID of element that describes the component
561
+ */
562
+ ariaDescribedBy: _propTypes.string
563
+ };
564
+ var _default = exports.default = Crud;