@abstraks-dev/ui-library 1.1.24 → 1.1.28

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 (110) hide show
  1. package/dist/__tests__/AccountBox.test.js +61 -0
  2. package/dist/__tests__/AccountCircle.test.js +69 -0
  3. package/dist/__tests__/Alert.test.js +144 -0
  4. package/dist/__tests__/ArrowIcon.test.js +61 -0
  5. package/dist/__tests__/ArrowRight.test.js +12 -7
  6. package/dist/__tests__/BookOpen.test.js +61 -0
  7. package/dist/__tests__/Camera.test.js +69 -0
  8. package/dist/__tests__/CaretDown.test.js +69 -0
  9. package/dist/__tests__/ChevronDown.test.js +13 -8
  10. package/dist/__tests__/Comment.test.js +69 -0
  11. package/dist/__tests__/Ellipses.test.js +61 -0
  12. package/dist/__tests__/Explore.test.js +61 -0
  13. package/dist/__tests__/FileInput.test.js +148 -0
  14. package/dist/__tests__/Filter.test.js +69 -0
  15. package/dist/__tests__/Form.test.js +471 -0
  16. package/dist/__tests__/Group.test.js +61 -0
  17. package/dist/__tests__/GroupReview.test.js +61 -0
  18. package/dist/__tests__/Hamburger.test.js +69 -0
  19. package/dist/__tests__/Header.test.js +198 -0
  20. package/dist/__tests__/Heart.test.js +69 -0
  21. package/dist/__tests__/Home.test.js +69 -0
  22. package/dist/__tests__/LoadingSpinner.test.js +78 -0
  23. package/dist/__tests__/LogOut.test.js +69 -0
  24. package/dist/__tests__/Magnify.test.js +69 -0
  25. package/dist/__tests__/News.test.js +61 -0
  26. package/dist/__tests__/Review.test.js +61 -0
  27. package/dist/__tests__/SaveIcon.test.js +61 -0
  28. package/dist/__tests__/Search.test.js +101 -0
  29. package/dist/__tests__/utils/accessibility.test.js +361 -0
  30. package/dist/__tests__/utils/inputValidation-core.test.js +80 -0
  31. package/dist/__tests__/utils/validation-core.test.js +123 -0
  32. package/dist/__tests__/utils/validation.test.js +362 -0
  33. package/dist/components/Alert.js +104 -0
  34. package/dist/components/FileInput.js +96 -0
  35. package/dist/components/Form.js +87 -39
  36. package/dist/components/Header.js +29 -1
  37. package/dist/components/Radio.js +1 -3
  38. package/dist/components/Search.js +236 -0
  39. package/dist/icons/AccountBox.js +33 -0
  40. package/dist/icons/AccountCircle.js +33 -0
  41. package/dist/icons/ArrowIcon.js +3 -2
  42. package/dist/icons/ArrowRight.js +23 -12
  43. package/dist/icons/BookOpen.js +33 -0
  44. package/dist/icons/Camera.js +33 -0
  45. package/dist/icons/CaretDown.js +33 -0
  46. package/dist/icons/ChevronDown.js +19 -9
  47. package/dist/icons/Comment.js +33 -0
  48. package/dist/icons/Explore.js +33 -0
  49. package/dist/icons/Filter.js +33 -0
  50. package/dist/icons/Group.js +33 -0
  51. package/dist/icons/GroupReview.js +33 -0
  52. package/dist/icons/Hamburger.js +14 -20
  53. package/dist/icons/Heart.js +33 -0
  54. package/dist/icons/Home.js +33 -0
  55. package/dist/icons/LoadingSpinner.js +3 -2
  56. package/dist/icons/LogOut.js +33 -0
  57. package/dist/icons/Magnify.js +33 -0
  58. package/dist/icons/News.js +33 -0
  59. package/dist/icons/Review.js +35 -0
  60. package/dist/icons/SaveIcon.js +3 -2
  61. package/dist/icons/index.js +112 -0
  62. package/dist/index.js +32 -0
  63. package/dist/styles/_variables.scss +2 -0
  64. package/dist/styles/alert.css +218 -0
  65. package/dist/styles/alert.css.map +1 -0
  66. package/dist/styles/alert.scss +128 -0
  67. package/dist/styles/anchor.css.map +1 -1
  68. package/dist/styles/avatar.css.map +1 -1
  69. package/dist/styles/button.css.map +1 -1
  70. package/dist/styles/card.css.map +1 -1
  71. package/dist/styles/checkbox.css.map +1 -1
  72. package/dist/styles/crud.css.map +1 -1
  73. package/dist/styles/dragAndDrop.css.map +1 -1
  74. package/dist/styles/error.css.map +1 -1
  75. package/dist/styles/file-input.css +165 -0
  76. package/dist/styles/file-input.css.map +1 -0
  77. package/dist/styles/file-input.scss +69 -0
  78. package/dist/styles/footer.css.map +1 -1
  79. package/dist/styles/form.css.map +1 -1
  80. package/dist/styles/header.css +9 -0
  81. package/dist/styles/header.css.map +1 -1
  82. package/dist/styles/header.scss +16 -7
  83. package/dist/styles/heading.css.map +1 -1
  84. package/dist/styles/hero.css.map +1 -1
  85. package/dist/styles/htmlElements.css.map +1 -1
  86. package/dist/styles/label.css.map +1 -1
  87. package/dist/styles/loader.css.map +1 -1
  88. package/dist/styles/main.css +320 -0
  89. package/dist/styles/main.css.map +1 -1
  90. package/dist/styles/menu-hover.css.map +1 -1
  91. package/dist/styles/paragraph.css.map +1 -1
  92. package/dist/styles/prompt.css.map +1 -1
  93. package/dist/styles/radio.css.map +1 -1
  94. package/dist/styles/search.css +269 -0
  95. package/dist/styles/search.css.map +1 -0
  96. package/dist/styles/search.scss +215 -0
  97. package/dist/styles/select.css.map +1 -1
  98. package/dist/styles/side-menu.css.map +1 -1
  99. package/dist/styles/tabs.css.map +1 -1
  100. package/dist/styles/text-area.css.map +1 -1
  101. package/dist/styles/text-input.css.map +1 -1
  102. package/dist/utils/utils/validation.js +2 -2
  103. package/dist/utils/validation.js +2 -2
  104. package/package.json +2 -2
  105. package/dist/icons/__tests__/CheckCircle.test.js +0 -9
  106. package/dist/icons/__tests__/ChevronDown.test.js +0 -9
  107. package/dist/icons/__tests__/Close.test.js +0 -9
  108. package/dist/icons/__tests__/EditSquare.test.js +0 -9
  109. package/dist/icons/__tests__/PlusCircle.test.js +0 -9
  110. package/dist/icons/__tests__/TrashX.test.js +0 -9
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = exports.FileInput = void 0;
7
+ var _react = _interopRequireWildcard(require("react"));
8
+ var _propTypes = require("prop-types");
9
+ var _ssrSafeId = require("../utils/ssrSafeId");
10
+ 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); }
11
+ 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); }
12
+ /**
13
+ * FileInput - A stateless, accessible file input component
14
+ *
15
+ * Features:
16
+ * - Multiple file types support via accept prop
17
+ * - Custom label content (text, images, or components)
18
+ * - Accessible with proper ARIA labels
19
+ * - Multiple file selection support
20
+ * - Drag and drop styling ready
21
+ * - Hidden native input with custom styling
22
+ *
23
+ * @component
24
+ * @example
25
+ * <FileInput
26
+ * accept="image/*"
27
+ * onChange={(event) => handleFileChange(event)}
28
+ * label="📷 Upload Image"
29
+ * multiple={false}
30
+ * />
31
+ */
32
+ const FileInput = exports.FileInput = /*#__PURE__*/(0, _react.forwardRef)(({
33
+ // Core props
34
+ id,
35
+ className = '',
36
+ // Functionality props
37
+ accept = '*/*',
38
+ multiple = false,
39
+ onChange,
40
+ disabled = false,
41
+ // Content props
42
+ label = 'Choose File',
43
+ // Accessibility props
44
+ ariaLabel,
45
+ ariaDescribedBy,
46
+ // Additional props
47
+ ...rest
48
+ }, ref) => {
49
+ const stableId = (0, _ssrSafeId.useStableId)(id);
50
+ const inputRef = (0, _react.useRef)(null);
51
+
52
+ // Handle click on label to trigger file input
53
+ const handleLabelClick = () => {
54
+ if (!disabled && inputRef.current) {
55
+ inputRef.current.click();
56
+ }
57
+ };
58
+ const combinedClassName = ['ui-file-input', disabled && 'ui-file-input--disabled', className].filter(Boolean).join(' ');
59
+ return /*#__PURE__*/_react.default.createElement("div", {
60
+ className: combinedClassName
61
+ }, /*#__PURE__*/_react.default.createElement("label", {
62
+ htmlFor: stableId,
63
+ className: "ui-file-input__label",
64
+ onClick: handleLabelClick,
65
+ "aria-label": ariaLabel,
66
+ "aria-describedby": ariaDescribedBy
67
+ }, label), /*#__PURE__*/_react.default.createElement("input", _extends({
68
+ ref: ref || inputRef,
69
+ id: stableId,
70
+ type: "file",
71
+ accept: accept,
72
+ multiple: multiple,
73
+ onChange: onChange,
74
+ disabled: disabled,
75
+ className: "ui-file-input__input",
76
+ "aria-label": ariaLabel || 'File input',
77
+ "aria-describedby": ariaDescribedBy
78
+ }, rest)));
79
+ });
80
+ FileInput.displayName = 'FileInput';
81
+ FileInput.propTypes = {
82
+ // Core props
83
+ id: _propTypes.string,
84
+ className: _propTypes.string,
85
+ // Functionality props
86
+ accept: _propTypes.string,
87
+ multiple: _propTypes.bool,
88
+ onChange: _propTypes.func,
89
+ disabled: _propTypes.bool,
90
+ // Content props
91
+ label: _propTypes.node,
92
+ // Accessibility props
93
+ ariaLabel: _propTypes.string,
94
+ ariaDescribedBy: _propTypes.string
95
+ };
96
+ var _default = exports.default = FileInput;
@@ -141,6 +141,28 @@ const Form = exports.Form = /*#__PURE__*/(0, _react.forwardRef)(({
141
141
  }
142
142
  }, [validationMode, validateField, announceErrors]);
143
143
 
144
+ /**
145
+ * Extract all field names from form children
146
+ * @returns {Array} Array of field names
147
+ */
148
+ const getAllFieldNames = (0, _react.useCallback)(() => {
149
+ const fieldNames = [];
150
+ const extractFieldNames = childrenToExtract => {
151
+ _react.Children.forEach(childrenToExtract, child => {
152
+ if (! /*#__PURE__*/(0, _react.isValidElement)(child)) return;
153
+ const fieldName = child.props?.name || child.props?.setName;
154
+ if (fieldName && !fieldNames.includes(fieldName)) {
155
+ fieldNames.push(fieldName);
156
+ }
157
+ if (child.props?.children) {
158
+ extractFieldNames(child.props.children);
159
+ }
160
+ });
161
+ };
162
+ extractFieldNames(children);
163
+ return fieldNames;
164
+ }, [children]);
165
+
144
166
  /**
145
167
  * Validates all form fields
146
168
  * @returns {Object} Object containing all field errors
@@ -148,14 +170,16 @@ const Form = exports.Form = /*#__PURE__*/(0, _react.forwardRef)(({
148
170
  const validateAllFields = (0, _react.useCallback)(() => {
149
171
  if (!onValidate) return {};
150
172
  const newErrors = {};
151
- Object.keys(formData).forEach(fieldName => {
152
- const error = validateField(fieldName, formData[fieldName]);
173
+ const allFieldNames = getAllFieldNames();
174
+ allFieldNames.forEach(fieldName => {
175
+ const value = formData[fieldName];
176
+ const error = validateField(fieldName, value);
153
177
  if (error) {
154
178
  newErrors[fieldName] = error;
155
179
  }
156
180
  });
157
181
  return newErrors;
158
- }, [formData, validateField, onValidate]);
182
+ }, [getAllFieldNames, formData, validateField, onValidate]);
159
183
 
160
184
  /**
161
185
  * Handles form submission
@@ -219,46 +243,70 @@ const Form = exports.Form = /*#__PURE__*/(0, _react.forwardRef)(({
219
243
  // Generate comprehensive class names
220
244
  const classNames = [componentName, additionalClassName, disabled && `${componentName}--disabled`, isSubmitting && `${componentName}--submitting`, hasErrors && `${componentName}--has-errors`].filter(Boolean).join(' ');
221
245
 
222
- // Enhanced children with form context
223
- const enhancedChildren = _react.default.Children.map(children, child => {
224
- if (/*#__PURE__*/_react.default.isValidElement(child)) {
225
- // Check if this is a form field that needs form context
226
- const fieldName = child.props?.name || child.props?.setName;
227
- if (fieldName) {
228
- return /*#__PURE__*/_react.default.cloneElement(child, {
229
- error: allErrors[fieldName],
230
- errorText: allErrors[fieldName],
231
- value: formData[fieldName] || child.props.value || '',
232
- inputValue: formData[fieldName] || child.props.inputValue || '',
233
- onChangeFunc: event => {
234
- const value = event.target?.value !== undefined ? event.target.value : event;
235
- updateFormData(fieldName, value);
236
- child.props?.onChangeFunc?.(event);
237
- },
238
- onChange: event => {
239
- const value = event.target?.value !== undefined ? event.target.value : event;
240
- updateFormData(fieldName, value);
241
- child.props?.onChange?.(event);
242
- },
243
- onBlur: event => {
244
- const value = event.target?.value !== undefined ? event.target.value : formData[fieldName];
245
- handleFieldBlur(fieldName, value);
246
- child.props?.onBlur?.(event);
247
- },
248
- blur: event => {
249
- const value = event.target?.value !== undefined ? event.target.value : formData[fieldName];
250
- handleFieldBlur(fieldName, value);
251
- child.props?.blur?.(event);
252
- },
253
- disabled: disabled || child.props?.disabled,
254
- 'aria-invalid': !!allErrors[fieldName],
255
- 'aria-describedby': allErrors[fieldName] ? `${fieldName}-error` : child.props?.['aria-describedby'],
256
- ...child.props
246
+ // Recursively enhance children with form context
247
+ const enhanceChildren = childrenToEnhance => _react.Children.map(childrenToEnhance, child => {
248
+ if (! /*#__PURE__*/(0, _react.isValidElement)(child)) return child;
249
+ const fieldName = child.props?.name || child.props?.setName;
250
+ let enhancedChild = child;
251
+ if (fieldName) {
252
+ const childType = child.type?.displayName || child.type?.name;
253
+ const isCheckbox = childType === 'Checkbox' || child.props?.type === 'checkbox';
254
+ const isRadio = childType === 'Radio' || child.props?.type === 'radio';
255
+ const commonProps = {
256
+ error: allErrors[fieldName],
257
+ errorText: allErrors[fieldName],
258
+ onChangeFunc: event => {
259
+ const target = event.target;
260
+ const value = target?.type === 'checkbox' ? target.checked : target?.value !== undefined ? target.value : event;
261
+ updateFormData(fieldName, value);
262
+ child.props?.onChangeFunc?.(event);
263
+ },
264
+ onChange: event => {
265
+ const target = event.target;
266
+ const value = target?.type === 'checkbox' ? target.checked : target?.value !== undefined ? target.value : event;
267
+ updateFormData(fieldName, value);
268
+ child.props?.onChange?.(event);
269
+ },
270
+ onBlur: event => {
271
+ const target = event.target;
272
+ const value = target?.type === 'checkbox' ? target.checked : target?.value !== undefined ? target.value : formData[fieldName];
273
+ handleFieldBlur(fieldName, value);
274
+ child.props?.onBlur?.(event);
275
+ },
276
+ blur: event => {
277
+ const target = event.target;
278
+ const value = target?.type === 'checkbox' ? target.checked : target?.value !== undefined ? target.value : formData[fieldName];
279
+ handleFieldBlur(fieldName, value);
280
+ child.props?.blur?.(event);
281
+ },
282
+ disabled: disabled || child.props?.disabled,
283
+ 'aria-invalid': !!allErrors[fieldName],
284
+ 'aria-describedby': allErrors[fieldName] ? `${fieldName}-error` : child.props?.['aria-describedby']
285
+ };
286
+ if (isRadio) {
287
+ const childValue = child.props.value ?? child.props.inputValue;
288
+ commonProps.value = childValue;
289
+ commonProps.inputValue = childValue;
290
+ commonProps.checked = formData[fieldName] !== undefined ? formData[fieldName] === childValue : child.props.checked;
291
+ } else if (isCheckbox) {
292
+ commonProps.checked = formData[fieldName] !== undefined ? formData[fieldName] : child.props.checked ?? false;
293
+ } else {
294
+ commonProps.value = formData[fieldName] ?? child.props.value ?? '';
295
+ commonProps.inputValue = formData[fieldName] ?? child.props.inputValue ?? '';
296
+ }
297
+ enhancedChild = /*#__PURE__*/(0, _react.cloneElement)(child, commonProps);
298
+ }
299
+ if (child.props?.children) {
300
+ const nestedChildren = enhanceChildren(child.props.children);
301
+ if (nestedChildren !== child.props.children) {
302
+ enhancedChild = /*#__PURE__*/(0, _react.cloneElement)(enhancedChild, {
303
+ children: nestedChildren
257
304
  });
258
305
  }
259
306
  }
260
- return child;
307
+ return enhancedChild;
261
308
  });
309
+ const enhancedChildren = enhanceChildren(children);
262
310
  return /*#__PURE__*/_react.default.createElement("form", _extends({
263
311
  ref: ref,
264
312
  className: classNames,
@@ -65,6 +65,9 @@ var _accessibility = require("../utils/accessibility");
65
65
  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); }
66
66
  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); } // components
67
67
  // utils
68
+ // Constants
69
+ const SCROLL_THRESHOLD = 100; // Pixels to scroll before hiding header
70
+
68
71
  /**
69
72
  * Header Component
70
73
  *
@@ -121,6 +124,30 @@ const Header = exports.Header = /*#__PURE__*/(0, _react.forwardRef)(({
121
124
  const finalClassName = className || additionalClassName;
122
125
  const size = (0, _useWindowSize.useWindowSize)();
123
126
  const isMobile = size.width < 768;
127
+ const [isHidden, setIsHidden] = (0, _react.useState)(false);
128
+ const lastScrollY = (0, _react.useRef)(0);
129
+
130
+ // Memoized scroll handler to prevent recreating on every render
131
+ const onScroll = (0, _react.useCallback)(() => {
132
+ const currentScrollY = window.scrollY;
133
+ if (currentScrollY > lastScrollY.current && currentScrollY > SCROLL_THRESHOLD) {
134
+ setIsHidden(true);
135
+ } else if (currentScrollY < lastScrollY.current || currentScrollY <= SCROLL_THRESHOLD) {
136
+ setIsHidden(false);
137
+ }
138
+ lastScrollY.current = currentScrollY;
139
+ }, []);
140
+ (0, _react.useEffect)(() => {
141
+ if (!isMobile) {
142
+ setIsHidden(false);
143
+ return;
144
+ }
145
+
146
+ // Initialize lastScrollY with current scroll position
147
+ lastScrollY.current = window.scrollY;
148
+ window.addEventListener('scroll', onScroll);
149
+ return () => window.removeEventListener('scroll', onScroll);
150
+ }, [isMobile, onScroll]);
124
151
 
125
152
  // Handle keyboard navigation
126
153
  const handleKeyDown = event => {
@@ -170,10 +197,11 @@ const Header = exports.Header = /*#__PURE__*/(0, _react.forwardRef)(({
170
197
  const handleEllipsesToggle = () => {
171
198
  if (onEllipsesToggle) onEllipsesToggle(!isEllipsesOpen);
172
199
  };
200
+ const headerClassName = `${componentName} ${finalClassName} ${isMobile && isHidden ? `${componentName}--hidden` : ''}`;
173
201
  return /*#__PURE__*/_react.default.createElement("header", _extends({
174
202
  ref: ref,
175
203
  id: finalId,
176
- className: `${componentName} ${finalClassName}`,
204
+ className: headerClassName,
177
205
  "data-testid": componentName,
178
206
  role: "banner",
179
207
  "aria-label": ariaLabel,
@@ -135,9 +135,7 @@ const Radio = exports.Radio = /*#__PURE__*/(0, _react.forwardRef)(({
135
135
  "aria-required": required || undefined
136
136
  }, restProps)), /*#__PURE__*/_react.default.createElement("span", {
137
137
  className: "custom-radio"
138
- }), finalLabel && /*#__PURE__*/_react.default.createElement("span", {
139
- className: `${componentName}__label-text`
140
- }, finalLabel)), error && errorText && /*#__PURE__*/_react.default.createElement(_Error.Error, {
138
+ })), error && errorText && /*#__PURE__*/_react.default.createElement(_Error.Error, {
141
139
  id: errorId,
142
140
  className: `${componentName}__error`,
143
141
  role: "alert",
@@ -0,0 +1,236 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = exports.Search = void 0;
7
+ var _react = _interopRequireWildcard(require("react"));
8
+ var _propTypes = require("prop-types");
9
+ var _TextInput = require("./TextInput");
10
+ var _Button = require("./Button");
11
+ var _icons = require("../icons");
12
+ var _ssrSafeId = require("../utils/ssrSafeId");
13
+ 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); }
14
+ 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); } // components
15
+ /**
16
+ * Search Component
17
+ *
18
+ * A flexible search component that can filter various types of data with real-time updates.
19
+ * Supports filtering by multiple fields and customizable result rendering.
20
+ *
21
+ * This is a stateless component - state management should be handled externally.
22
+ *
23
+ * @component
24
+ * @example
25
+ * <Search
26
+ * placeholder="Search users..."
27
+ * searchValue={searchValue}
28
+ * onSearchChange={handleSearchChange}
29
+ * data={users}
30
+ * searchFields={['name', 'email']}
31
+ * renderResult={({ item, highlightMatch }) => (
32
+ * <div className="search-result-item">
33
+ * <h4>{highlightMatch(item.name)}</h4>
34
+ * <p>{item.email}</p>
35
+ * </div>
36
+ * )}
37
+ * />
38
+ */
39
+ const Search = exports.Search = /*#__PURE__*/(0, _react.forwardRef)(({
40
+ // Core props
41
+ id,
42
+ className = '',
43
+ placeholder = 'Search...',
44
+ searchValue = '',
45
+ onSearchChange,
46
+ // Data props
47
+ data = [],
48
+ searchFields = [],
49
+ filterFunction,
50
+ // Rendering props
51
+ renderResult,
52
+ renderEmptyState,
53
+ renderNoResults,
54
+ // Appearance props
55
+ variant = 'default',
56
+ size = 'medium',
57
+ disabled = false,
58
+ hideResultsWhenEmpty = false,
59
+ maxResults,
60
+ // Loading state
61
+ isLoading = false,
62
+ loadingText = 'Searching...',
63
+ // Result container props
64
+ resultContainerClassName = '',
65
+ resultItemClassName = '',
66
+ // Advanced props
67
+ caseSensitive = false,
68
+ highlightMatches = true,
69
+ // Icon and button props
70
+ showIcon = true,
71
+ iconSize = 20,
72
+ iconColor = '#6c757d',
73
+ showButton = false,
74
+ buttonText = 'Search',
75
+ buttonVariant = 'primary',
76
+ onButtonClick,
77
+ ...rest
78
+ }, ref) => {
79
+ const stableId = (0, _ssrSafeId.useStableId)(id);
80
+
81
+ // Filter data based on search value
82
+ const getFilteredData = () => {
83
+ if (!searchValue.trim()) {
84
+ return [];
85
+ }
86
+ if (filterFunction) {
87
+ return filterFunction(data, searchValue);
88
+ }
89
+ if (!searchFields.length) {
90
+ return data;
91
+ }
92
+ const searchTerm = caseSensitive ? searchValue : searchValue.toLowerCase();
93
+ const filtered = data.filter(item => {
94
+ return searchFields.some(field => {
95
+ const fieldValue = getNestedValue(item, field);
96
+ if (fieldValue == null) return false;
97
+ const stringValue = String(fieldValue);
98
+ const compareValue = caseSensitive ? stringValue : stringValue.toLowerCase();
99
+ return compareValue.includes(searchTerm);
100
+ });
101
+ });
102
+ return maxResults ? filtered.slice(0, maxResults) : filtered;
103
+ };
104
+
105
+ // Helper function to get nested object values
106
+ const getNestedValue = (obj, path) => {
107
+ return path.split('.').reduce((current, key) => current?.[key], obj);
108
+ };
109
+
110
+ // Highlight matching text
111
+ const highlightMatch = (text, field = null) => {
112
+ if (!highlightMatches || !searchValue.trim() || !text) {
113
+ return text;
114
+ }
115
+ const textStr = String(text);
116
+ const searchTerm = caseSensitive ? searchValue : searchValue.toLowerCase();
117
+ const compareText = caseSensitive ? textStr : textStr.toLowerCase();
118
+ if (!compareText.includes(searchTerm)) {
119
+ return textStr;
120
+ }
121
+ const regex = new RegExp(`(${searchTerm.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})`, caseSensitive ? 'g' : 'gi');
122
+ const parts = textStr.split(regex);
123
+ return parts.map((part, index) => {
124
+ const isMatch = caseSensitive ? part === searchTerm : part.toLowerCase() === searchTerm.toLowerCase();
125
+ return isMatch ? /*#__PURE__*/_react.default.createElement("mark", {
126
+ key: index,
127
+ className: "search-highlight"
128
+ }, part) : part;
129
+ });
130
+ };
131
+ const filteredData = getFilteredData();
132
+ const hasResults = filteredData.length > 0;
133
+ const showResults = searchValue.trim().length > 0;
134
+
135
+ // Default render functions
136
+ const defaultRenderResult = ({
137
+ item,
138
+ index
139
+ }) => /*#__PURE__*/_react.default.createElement("div", {
140
+ key: index,
141
+ className: `search-result-item ${resultItemClassName}`.trim()
142
+ }, typeof item === 'string' ? item : JSON.stringify(item));
143
+ const defaultRenderEmptyState = () => /*#__PURE__*/_react.default.createElement("div", {
144
+ className: "search-empty-state"
145
+ }, /*#__PURE__*/_react.default.createElement("p", null, "Start typing to search..."));
146
+ const defaultRenderNoResults = () => /*#__PURE__*/_react.default.createElement("div", {
147
+ className: "search-no-results"
148
+ }, /*#__PURE__*/_react.default.createElement("p", null, "No results found for \"", searchValue, "\""));
149
+
150
+ // Component classes
151
+ const searchClasses = ['search-component', `search-component--${variant}`, `search-component--${size}`, disabled && 'search-component--disabled', className].filter(Boolean).join(' ');
152
+ const resultsClasses = ['search-results', `search-results--${variant}`, resultContainerClassName].filter(Boolean).join(' ');
153
+ return /*#__PURE__*/_react.default.createElement("div", _extends({
154
+ className: searchClasses
155
+ }, rest), /*#__PURE__*/_react.default.createElement("div", {
156
+ className: "search-input-container"
157
+ }, showIcon && /*#__PURE__*/_react.default.createElement("div", {
158
+ className: "search-icon"
159
+ }, /*#__PURE__*/_react.default.createElement(_icons.Magnify, {
160
+ dimensions: iconSize,
161
+ fill: iconColor,
162
+ additionalClassName: "search-magnify-icon"
163
+ })), /*#__PURE__*/_react.default.createElement(_TextInput.TextInput, {
164
+ ref: ref,
165
+ id: stableId,
166
+ type: "text",
167
+ placeholder: placeholder,
168
+ value: searchValue,
169
+ onChange: onSearchChange,
170
+ disabled: disabled,
171
+ size: size,
172
+ className: `search-input ${showIcon ? 'search-input--with-icon' : ''}`
173
+ }), showButton && /*#__PURE__*/_react.default.createElement(_Button.Button, {
174
+ variant: buttonVariant,
175
+ size: size,
176
+ onClick: onButtonClick,
177
+ disabled: disabled,
178
+ className: "search-button"
179
+ }, buttonText)), showResults && /*#__PURE__*/_react.default.createElement("div", {
180
+ className: resultsClasses
181
+ }, isLoading ? /*#__PURE__*/_react.default.createElement("div", {
182
+ className: "search-loading"
183
+ }, /*#__PURE__*/_react.default.createElement("p", null, loadingText)) : hasResults ? /*#__PURE__*/_react.default.createElement("div", {
184
+ className: "search-results-list"
185
+ }, filteredData.map((item, index) => {
186
+ const ResultComponent = renderResult || defaultRenderResult;
187
+ return /*#__PURE__*/_react.default.createElement(ResultComponent, {
188
+ key: item.id || item._id || index,
189
+ item: item,
190
+ index: index,
191
+ highlightMatch: highlightMatch,
192
+ searchValue: searchValue
193
+ });
194
+ })) : searchValue.trim() ? renderNoResults ? renderNoResults() : defaultRenderNoResults() : renderEmptyState ? renderEmptyState() : defaultRenderEmptyState()));
195
+ });
196
+ Search.displayName = 'Search';
197
+ Search.propTypes = {
198
+ // Core props
199
+ id: _propTypes.string,
200
+ className: _propTypes.string,
201
+ placeholder: _propTypes.string,
202
+ searchValue: _propTypes.string,
203
+ onSearchChange: _propTypes.func,
204
+ // Data props
205
+ data: _propTypes.array,
206
+ searchFields: _propTypes.array,
207
+ filterFunction: _propTypes.func,
208
+ // Rendering props
209
+ renderResult: _propTypes.func,
210
+ renderEmptyState: _propTypes.func,
211
+ renderNoResults: _propTypes.func,
212
+ // Appearance props
213
+ variant: (0, _propTypes.oneOf)(['default', 'bordered', 'minimal']),
214
+ size: (0, _propTypes.oneOf)(['small', 'medium', 'large']),
215
+ disabled: _propTypes.bool,
216
+ hideResultsWhenEmpty: _propTypes.bool,
217
+ maxResults: _propTypes.number,
218
+ // Loading state
219
+ isLoading: _propTypes.bool,
220
+ loadingText: _propTypes.string,
221
+ // Result container props
222
+ resultContainerClassName: _propTypes.string,
223
+ resultItemClassName: _propTypes.string,
224
+ // Advanced props
225
+ caseSensitive: _propTypes.bool,
226
+ highlightMatches: _propTypes.bool,
227
+ // Icon and button props
228
+ showIcon: _propTypes.bool,
229
+ iconSize: _propTypes.number,
230
+ iconColor: _propTypes.string,
231
+ showButton: _propTypes.bool,
232
+ buttonText: _propTypes.string,
233
+ buttonVariant: (0, _propTypes.oneOf)(['primary', 'secondary', 'success', 'error', 'warning']),
234
+ onButtonClick: _propTypes.func
235
+ };
236
+ var _default = exports.default = Search;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = exports.AccountBox = void 0;
7
+ var _react = _interopRequireDefault(require("react"));
8
+ var _propTypes = require("prop-types");
9
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
10
+ const AccountBox = ({
11
+ componentName = 'account-box',
12
+ additionalClassName = '',
13
+ dimensions = 24,
14
+ viewBox = '0 -960 960 960',
15
+ fill = '#adb5bd'
16
+ }) => /*#__PURE__*/_react.default.createElement("svg", {
17
+ className: `icon ${componentName} ${additionalClassName}`,
18
+ width: dimensions,
19
+ height: dimensions,
20
+ viewBox: viewBox,
21
+ fill: fill
22
+ }, /*#__PURE__*/_react.default.createElement("path", {
23
+ d: "M200-246q54-53 125.5-83.5T480-360q83 0 154.5 30.5T760-246v-514H200v514Zm280-194q58 0 99-41t41-99q0-58-41-99t-99-41q-58 0-99 41t-41 99q0 58 41 99t99 41ZM200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm69-80h422q-44-39-99.5-59.5T480-280q-56 0-112.5 20.5T269-200Zm211-320q-25 0-42.5-17.5T420-580q0-25 17.5-42.5T480-640q25 0 42.5 17.5T540-580q0 25-17.5 42.5T480-520Zm0 17Z"
24
+ }));
25
+ exports.AccountBox = AccountBox;
26
+ AccountBox.propTypes = {
27
+ componentName: _propTypes.string,
28
+ additionalClassName: _propTypes.string,
29
+ dimensions: _propTypes.number,
30
+ viewBox: _propTypes.string,
31
+ fill: _propTypes.string
32
+ };
33
+ var _default = exports.default = AccountBox;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = exports.AccountCircle = void 0;
7
+ var _react = _interopRequireDefault(require("react"));
8
+ var _propTypes = require("prop-types");
9
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
10
+ const AccountCircle = ({
11
+ componentName = 'account-circle',
12
+ additionalClassName = '',
13
+ dimensions = 24,
14
+ viewBox = '0 -960 960 960',
15
+ fill = '#adb5bd'
16
+ }) => /*#__PURE__*/_react.default.createElement("svg", {
17
+ className: `icon ${componentName} ${additionalClassName}`,
18
+ width: dimensions,
19
+ height: dimensions,
20
+ viewBox: viewBox,
21
+ fill: fill
22
+ }, /*#__PURE__*/_react.default.createElement("path", {
23
+ d: "M234-276q51-39 114-61.5T480-360q69 0 132 22.5T726-276q35-41 54.5-93T800-480q0-133-93.5-226.5T480-800q-133 0-226.5 93.5T160-480q0 59 19.5 111t54.5 93Zm246-164q-59 0-99.5-40.5T340-580q0-59 40.5-99.5T480-720q59 0 99.5 40.5T620-580q0 59-40.5 99.5T480-440Zm0 360q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q53 0 100-15.5t86-44.5q-39-29-86-44.5T480-280q-53 0-100 15.5T294-220q39 29 86 44.5T480-160Zm0-360q26 0 43-17t17-43q0-26-17-43t-43-17q-26 0-43 17t-17 43q0 26 17 43t43 17Zm0-60Zm0 360Z"
24
+ }));
25
+ exports.AccountCircle = AccountCircle;
26
+ AccountCircle.propTypes = {
27
+ componentName: _propTypes.string,
28
+ additionalClassName: _propTypes.string,
29
+ dimensions: _propTypes.number,
30
+ viewBox: _propTypes.string,
31
+ fill: _propTypes.string
32
+ };
33
+ var _default = exports.default = AccountCircle;
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.ArrowIcon = void 0;
6
+ exports.default = exports.ArrowIcon = void 0;
7
7
  var _react = _interopRequireDefault(require("react"));
8
8
  var _propTypes = require("prop-types");
9
9
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
@@ -29,4 +29,5 @@ ArrowIcon.propTypes = {
29
29
  dimensions: _propTypes.number,
30
30
  viewBox: _propTypes.string,
31
31
  fill: _propTypes.string
32
- };
32
+ };
33
+ var _default = exports.default = ArrowIcon;