@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.
- package/LICENSE +21 -0
- package/README.md +708 -0
- package/dist/__tests__/Anchor.test.js +145 -0
- package/dist/__tests__/ArrowRight.test.js +91 -0
- package/dist/__tests__/Avatar.test.js +123 -0
- package/dist/__tests__/Button.test.js +82 -0
- package/dist/__tests__/Card.test.js +198 -0
- package/dist/__tests__/CheckCircle.test.js +98 -0
- package/dist/__tests__/Checkbox.test.js +161 -0
- package/dist/__tests__/ChevronDown.test.js +73 -0
- package/dist/__tests__/Close.test.js +98 -0
- package/dist/__tests__/EditSquare.test.js +99 -0
- package/dist/__tests__/Error.test.js +74 -0
- package/dist/__tests__/Footer.test.js +66 -0
- package/dist/__tests__/Heading.test.js +227 -0
- package/dist/__tests__/Hero.test.js +74 -0
- package/dist/__tests__/Label.test.js +123 -0
- package/dist/__tests__/Loader.test.js +115 -0
- package/dist/__tests__/MenuHover.test.js +137 -0
- package/dist/__tests__/Paragraph.test.js +93 -0
- package/dist/__tests__/PlusCircle.test.js +99 -0
- package/dist/__tests__/Radio.test.js +153 -0
- package/dist/__tests__/Select.test.js +187 -0
- package/dist/__tests__/Tabs.test.js +162 -0
- package/dist/__tests__/TextArea.test.js +127 -0
- package/dist/__tests__/TextInput.test.js +181 -0
- package/dist/__tests__/Toggle.test.js +120 -0
- package/dist/__tests__/TrashX.test.js +99 -0
- package/dist/__tests__/useHeadingAccessibility.test.js +144 -0
- package/dist/components/Anchor.js +131 -0
- package/dist/components/Animation.js +129 -0
- package/dist/components/AnimationGroup.js +207 -0
- package/dist/components/AnimationToggle.js +216 -0
- package/dist/components/Avatar.js +153 -0
- package/dist/components/Button.js +218 -0
- package/dist/components/Card.js +222 -0
- package/dist/components/Checkbox.js +305 -0
- package/dist/components/Crud.js +564 -0
- package/dist/components/DragAndDrop.js +337 -0
- package/dist/components/Error.js +206 -0
- package/dist/components/Footer.js +99 -0
- package/dist/components/Form.js +412 -0
- package/dist/components/Header.js +372 -0
- package/dist/components/Heading.js +134 -0
- package/dist/components/Hero.js +181 -0
- package/dist/components/Label.js +256 -0
- package/dist/components/Loader.js +302 -0
- package/dist/components/MenuHover.js +114 -0
- package/dist/components/Paragraph.js +128 -0
- package/dist/components/Prompt.js +61 -0
- package/dist/components/Radio.js +254 -0
- package/dist/components/Select.js +422 -0
- package/dist/components/SideMenu.js +313 -0
- package/dist/components/Tabs.js +297 -0
- package/dist/components/TextArea.js +370 -0
- package/dist/components/TextInput.js +286 -0
- package/dist/components/Toggle.js +186 -0
- package/dist/components/crudFiles/CrudEditBase.js +150 -0
- package/dist/components/crudFiles/CrudViewBase.js +39 -0
- package/dist/components/crudFiles/crudDevelopment.js +118 -0
- package/dist/components/crudFiles/crudEditHandlers.js +50 -0
- package/dist/constants/animation.js +30 -0
- package/dist/icons/ArrowIcon.js +32 -0
- package/dist/icons/ArrowRight.js +33 -0
- package/dist/icons/CheckCircle.js +33 -0
- package/dist/icons/ChevronDown.js +28 -0
- package/dist/icons/Close.js +33 -0
- package/dist/icons/EditSquare.js +33 -0
- package/dist/icons/Ellipses.js +34 -0
- package/dist/icons/Hamburger.js +39 -0
- package/dist/icons/LoadingSpinner.js +42 -0
- package/dist/icons/PlusCircle.js +33 -0
- package/dist/icons/SaveIcon.js +32 -0
- package/dist/icons/TrashX.js +33 -0
- package/dist/icons/__tests__/CheckCircle.test.js +9 -0
- package/dist/icons/__tests__/ChevronDown.test.js +9 -0
- package/dist/icons/__tests__/Close.test.js +9 -0
- package/dist/icons/__tests__/EditSquare.test.js +9 -0
- package/dist/icons/__tests__/PlusCircle.test.js +9 -0
- package/dist/icons/__tests__/TrashX.test.js +9 -0
- package/dist/icons/index.js +89 -0
- package/dist/index.js +332 -0
- package/dist/setupTests.js +3 -0
- package/dist/styles/_variables.scss +286 -0
- package/dist/styles/anchor.scss +40 -0
- package/dist/styles/animation-accessibility.scss +96 -0
- package/dist/styles/animation-toggle.scss +233 -0
- package/dist/styles/animation.scss +3781 -0
- package/dist/styles/avatar.scss +285 -0
- package/dist/styles/button.scss +430 -0
- package/dist/styles/card.scss +210 -0
- package/dist/styles/checkbox.scss +160 -0
- package/dist/styles/crud.scss +474 -0
- package/dist/styles/dragAndDrop.scss +312 -0
- package/dist/styles/error.scss +232 -0
- package/dist/styles/footer.scss +58 -0
- package/dist/styles/form.scss +420 -0
- package/dist/styles/grid.scss +29 -0
- package/dist/styles/header.scss +276 -0
- package/dist/styles/heading.scss +118 -0
- package/dist/styles/hero.scss +185 -0
- package/dist/styles/htmlElements.scss +20 -0
- package/dist/styles/image.scss +9 -0
- package/dist/styles/label.scss +340 -0
- package/dist/styles/list-item.scss +5 -0
- package/dist/styles/loader.scss +354 -0
- package/dist/styles/logo.scss +19 -0
- package/dist/styles/main.css +9056 -0
- package/dist/styles/main.css.map +1 -0
- package/dist/styles/main.scss +0 -0
- package/dist/styles/menu-hover.scss +30 -0
- package/dist/styles/paragraph.scss +88 -0
- package/dist/styles/prompt.scss +51 -0
- package/dist/styles/radio.scss +202 -0
- package/dist/styles/select.scss +363 -0
- package/dist/styles/side-menu.scss +334 -0
- package/dist/styles/tabs.scss +540 -0
- package/dist/styles/text-area.scss +388 -0
- package/dist/styles/text-input.scss +171 -0
- package/dist/styles/toggle.scss +0 -0
- package/dist/styles/unordered-list.scss +8 -0
- package/dist/utils/ScrollHandler.js +30 -0
- package/dist/utils/accessibility.js +128 -0
- package/dist/utils/heroUtils.js +316 -0
- package/dist/utils/index.js +104 -0
- package/dist/utils/inputValidation.js +29 -0
- package/dist/utils/keyboardNavigation.js +536 -0
- package/dist/utils/labelUtils.js +708 -0
- package/dist/utils/loaderUtils.js +387 -0
- package/dist/utils/menuUtils.js +575 -0
- package/dist/utils/useHeadingAccessibility.js +298 -0
- package/dist/utils/useRadioGroup.js +260 -0
- package/dist/utils/useSelectAccessibility.js +426 -0
- package/dist/utils/useTabsAccessibility.js +278 -0
- package/dist/utils/useTextAreaAccessibility.js +255 -0
- package/dist/utils/useTextInputAccessibility.js +295 -0
- package/dist/utils/useTypographyAccessibility.js +168 -0
- package/dist/utils/useWindowSize.js +32 -0
- package/dist/utils/utils/ScrollHandler.js +26 -0
- package/dist/utils/utils/accessibility.js +133 -0
- package/dist/utils/utils/heroUtils.js +348 -0
- package/dist/utils/utils/index.js +9 -0
- package/dist/utils/utils/inputValidation.js +22 -0
- package/dist/utils/utils/keyboardNavigation.js +664 -0
- package/dist/utils/utils/labelUtils.js +772 -0
- package/dist/utils/utils/loaderUtils.js +436 -0
- package/dist/utils/utils/menuUtils.js +651 -0
- package/dist/utils/utils/useHeadingAccessibility.js +334 -0
- package/dist/utils/utils/useRadioGroup.js +311 -0
- package/dist/utils/utils/useSelectAccessibility.js +498 -0
- package/dist/utils/utils/useTabsAccessibility.js +316 -0
- package/dist/utils/utils/useTextAreaAccessibility.js +303 -0
- package/dist/utils/utils/useTextInputAccessibility.js +338 -0
- package/dist/utils/utils/useTypographyAccessibility.js +180 -0
- package/dist/utils/utils/useWindowSize.js +26 -0
- package/dist/utils/utils/validation.js +131 -0
- package/dist/utils/validation.js +139 -0
- 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;
|