@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,207 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.AnimationGroup = void 0;
7
+ var _react = _interopRequireWildcard(require("react"));
8
+ var _propTypes = require("prop-types");
9
+ var _reactTransitionGroup = require("react-transition-group");
10
+ var _Prompt = _interopRequireDefault(require("./Prompt"));
11
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
12
+ 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); }
13
+ 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); }
14
+ /**
15
+ * AnimationGroup Component
16
+ *
17
+ * A dynamic list component with smooth add/remove animations using React Transition Group.
18
+ * Features keyboard navigation, accessibility support, and motion preferences.
19
+ *
20
+ * @component
21
+ * @example
22
+ * ```jsx
23
+ * const [items, setItems] = useState([
24
+ * { id: '1', text: 'First item' },
25
+ * { id: '2', text: 'Second item' }
26
+ * ]);
27
+ *
28
+ * <AnimationGroup
29
+ * items={items}
30
+ * onItemAdd={() => handleAddItem()}
31
+ * onItemRemove={(id) => handleRemoveItem(id)}
32
+ * addItem="Add New Item"
33
+ * ariaLabel="Todo list with animations"
34
+ * />
35
+ * ```
36
+ *
37
+ * @param {object} props - Component props
38
+ * @param {Array} props.items - Array of items with id and text properties
39
+ * @param {function} [props.onItemAdd] - Callback when add button is clicked
40
+ * @param {function} [props.onItemRemove] - Callback when remove button is clicked
41
+ * @param {string} [props.className=''] - Additional CSS classes to apply
42
+ * @param {string} [props.id] - Unique identifier for the component
43
+ * @param {React.ReactNode} [props.addItem='Add Item'] - Content for add button
44
+ * @param {boolean} [props.reduceMotion=false] - Disable animations for accessibility
45
+ * @returns {JSX.Element} The AnimationGroup component
46
+ */
47
+ const AnimationGroup = exports.AnimationGroup = /*#__PURE__*/(0, _react.forwardRef)(({
48
+ // Core props
49
+ id,
50
+ className = '',
51
+ // Content props
52
+ addItem = 'Add Item',
53
+ items = [],
54
+ // Event props
55
+ onItemAdd,
56
+ onItemRemove,
57
+ // Accessibility props
58
+ 'aria-label': ariaLabel = 'Animated list with add and remove functionality',
59
+ reduceMotion = false,
60
+ // Legacy props (for backward compatibility - internal use only)
61
+ componentName = 'animation-group',
62
+ additionalClassName = '',
63
+ ...restProps
64
+ }, ref) => {
65
+ // Handle legacy prop mapping
66
+ const finalId = id || `animation-group-${Math.random().toString(36).substr(2, 9)}`;
67
+ const finalClassName = className || additionalClassName;
68
+ const listRef = (0, _react.useRef)(null);
69
+ const addButtonRef = (0, _react.useRef)(null);
70
+
71
+ // Create refs for each item to avoid findDOMNode issues in React 18
72
+ const itemRefs = (0, _react.useRef)({});
73
+ (0, _react.useMemo)(() => {
74
+ // Ensure we have a ref for each item
75
+ items.forEach(item => {
76
+ if (!itemRefs.current[item.id]) {
77
+ itemRefs.current[item.id] = /*#__PURE__*/(0, _react.createRef)();
78
+ }
79
+ });
80
+ // Clean up refs for items that no longer exist
81
+ Object.keys(itemRefs.current).forEach(id => {
82
+ if (!items.find(item => item.id === id)) {
83
+ delete itemRefs.current[id];
84
+ }
85
+ });
86
+ }, [items]);
87
+ const [promptOpen, setPromptOpen] = _react.default.useState(false);
88
+ const [addedText, setAddedText] = _react.default.useState('');
89
+
90
+ // Wrap onItemAdd
91
+ const handleAdd = () => {
92
+ if (onItemAdd) {
93
+ const result = onItemAdd();
94
+ // If result is the new item's text, show prompt
95
+ if (typeof result === 'string' && result) {
96
+ setAddedText(result);
97
+ setPromptOpen(true);
98
+ } else {
99
+ setAddedText('Item added!');
100
+ setPromptOpen(true);
101
+ }
102
+ }
103
+ };
104
+ const handleDismissPrompt = () => {
105
+ setPromptOpen(false);
106
+ setAddedText('');
107
+ };
108
+ return /*#__PURE__*/_react.default.createElement("div", _extends({
109
+ ref: ref,
110
+ id: finalId,
111
+ className: `${componentName}-wrapper ${finalClassName}`.trim(),
112
+ "data-testid": componentName,
113
+ style: {
114
+ marginTop: '2rem'
115
+ },
116
+ role: "region",
117
+ "aria-label": ariaLabel
118
+ }, restProps), /*#__PURE__*/_react.default.createElement("ul", {
119
+ className: "unordered-list",
120
+ style: {
121
+ marginBottom: '1rem'
122
+ },
123
+ ref: listRef,
124
+ role: "list",
125
+ "aria-live": "polite",
126
+ "aria-label": `List with ${items.length} items`
127
+ }, /*#__PURE__*/_react.default.createElement(_reactTransitionGroup.TransitionGroup, {
128
+ className: "todo-list",
129
+ style: reduceMotion ? {
130
+ transition: 'none'
131
+ } : undefined
132
+ }, items.map(({
133
+ id,
134
+ text
135
+ }, index) => /*#__PURE__*/_react.default.createElement(_reactTransitionGroup.CSSTransition, {
136
+ key: id,
137
+ nodeRef: itemRefs.current[id],
138
+ timeout: reduceMotion ? 0 : 500,
139
+ classNames: reduceMotion ? '' : 'item'
140
+ }, /*#__PURE__*/_react.default.createElement("li", {
141
+ ref: itemRefs.current[id],
142
+ className: "list-item",
143
+ role: "listitem",
144
+ "aria-setsize": items.length,
145
+ "aria-posinset": index + 1
146
+ }, /*#__PURE__*/_react.default.createElement("button", {
147
+ className: "remove-btn",
148
+ variant: "danger",
149
+ size: "sm",
150
+ onClick: () => onItemRemove && onItemRemove(id, text),
151
+ "aria-label": `Remove item: ${text}`,
152
+ title: `Remove "${text}"`
153
+ }, /*#__PURE__*/_react.default.createElement("span", {
154
+ "aria-hidden": "true"
155
+ }, "\xD7"), /*#__PURE__*/_react.default.createElement("span", {
156
+ className: "sr-only"
157
+ }, "Remove")), /*#__PURE__*/_react.default.createElement("span", null, text)))))), /*#__PURE__*/_react.default.createElement("button", {
158
+ ref: addButtonRef,
159
+ onClick: handleAdd,
160
+ "aria-label": "Add new item to list",
161
+ "aria-describedby": items.length === 0 ? 'empty-list-hint' : undefined
162
+ }, addItem), items.length === 0 && /*#__PURE__*/_react.default.createElement("p", {
163
+ id: "empty-list-hint",
164
+ className: "sr-only"
165
+ }, "List is empty. Click the add button to add your first item."), /*#__PURE__*/_react.default.createElement(_Prompt.default, {
166
+ open: promptOpen,
167
+ message: addedText || 'Item added!',
168
+ onConfirm: handleDismissPrompt,
169
+ showCancel: false,
170
+ confirmText: "OK"
171
+ }));
172
+ });
173
+
174
+ // Set display name for debugging
175
+ AnimationGroup.displayName = 'AnimationGroup';
176
+
177
+ // Configure component PropTypes
178
+ AnimationGroup.propTypes = {
179
+ // Core props
180
+ /** Unique identifier for the component */
181
+ id: _propTypes.string,
182
+ /** Additional CSS classes to apply */
183
+ className: _propTypes.string,
184
+ // Content props
185
+ /** Text or element to display in the add button */
186
+ addItem: (0, _propTypes.oneOfType)([_propTypes.string, _propTypes.node]),
187
+ /** Array of items to display in the list */
188
+ items: (0, _propTypes.arrayOf)((0, _propTypes.shape)({
189
+ id: _propTypes.string.isRequired,
190
+ text: _propTypes.string.isRequired
191
+ })),
192
+ // Event props
193
+ /** Callback function when the add button is clicked */
194
+ onItemAdd: _propTypes.func,
195
+ /** Callback function when an item remove button is clicked */
196
+ onItemRemove: _propTypes.func,
197
+ // Accessibility props
198
+ /** ARIA label for the entire component region */
199
+ 'aria-label': _propTypes.string,
200
+ /** Whether to disable animations for accessibility (prefers-reduced-motion) */
201
+ reduceMotion: _propTypes.bool,
202
+ // Legacy props (for backward compatibility - internal use only)
203
+ /** Base CSS class name for the component */
204
+ componentName: _propTypes.string,
205
+ /** Additional CSS classes to apply */
206
+ additionalClassName: _propTypes.string
207
+ };
@@ -0,0 +1,216 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.AnimationToggle = void 0;
7
+ var _react = _interopRequireWildcard(require("react"));
8
+ var _propTypes = require("prop-types");
9
+ var _reactTransitionGroup = require("react-transition-group");
10
+ var _animation = require("../constants/animation");
11
+ 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); }
12
+ 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); }
13
+ /**
14
+ * AnimationToggle - A stateless, accessible toggle component with smooth CSS transitions
15
+ *
16
+ * Features:
17
+ * - Keyboard navigation support (Enter, Space, Escape)
18
+ * - Screen reader announcements
19
+ * - Focus management
20
+ * - High contrast mode support
21
+ * - ARIA labels and live regions
22
+ * - Semantic HTML structure
23
+ *
24
+ * @component
25
+ * @example
26
+ * <AnimationToggle
27
+ * childOne="Show Details"
28
+ * childTwo={<div>Detailed content here</div>}
29
+ * aria-label="Toggle product details"
30
+ * isOpen={false}
31
+ * showButton={true}
32
+ * onOpen={() => {}}
33
+ * onClose={() => {}}
34
+ * onKeyDown={() => {}}
35
+ * />
36
+ */
37
+ const AnimationToggle = exports.AnimationToggle = /*#__PURE__*/(0, _react.forwardRef)(({
38
+ // Core props
39
+ id,
40
+ className = '',
41
+ // Content props
42
+ childOne,
43
+ childTwo,
44
+ // Behavior props
45
+ disabled = false,
46
+ autoFocus = false,
47
+ isOpen = false,
48
+ showButton = true,
49
+ // Event props
50
+ onOpen,
51
+ onClose,
52
+ onKeyDown,
53
+ onEnter,
54
+ onExited,
55
+ // Accessibility props
56
+ ariaLabel,
57
+ ariaDescribedBy,
58
+ // Legacy props (for backward compatibility - internal use only)
59
+ componentName = 'animation-toggle',
60
+ additionalClassName = '',
61
+ ...restProps
62
+ }, ref) => {
63
+ // Handle legacy prop mapping
64
+ const finalId = id || `animation-toggle-${Math.random().toString(36).substr(2, 9)}`;
65
+ const finalClassName = className || additionalClassName;
66
+ const triggerRef = (0, _react.useRef)(null);
67
+ const contentRef = (0, _react.useRef)(null);
68
+ const closeButtonRef = (0, _react.useRef)(null);
69
+ return /*#__PURE__*/_react.default.createElement("div", _extends({
70
+ ref: ref,
71
+ id: finalId,
72
+ className: `${componentName}-wrapper ${finalClassName} ${disabled ? 'disabled' : ''}`,
73
+ "data-testid": componentName,
74
+ role: "group",
75
+ "aria-label": ariaLabel || 'Toggle content'
76
+ }, restProps), showButton && /*#__PURE__*/_react.default.createElement("button", {
77
+ ref: triggerRef,
78
+ className: `${componentName}-trigger`,
79
+ onClick: onOpen,
80
+ onKeyDown: onKeyDown,
81
+ disabled: disabled,
82
+ "aria-expanded": isOpen,
83
+ "aria-controls": `${componentName}-content`,
84
+ "aria-label": ariaLabel || `Show ${typeof childOne === 'string' ? childOne : 'content'}`,
85
+ "aria-describedby": ariaDescribedBy,
86
+ autoFocus: autoFocus,
87
+ type: "button"
88
+ }, /*#__PURE__*/_react.default.createElement("span", {
89
+ className: `${componentName}-trigger-text`
90
+ }, childOne)), /*#__PURE__*/_react.default.createElement(_reactTransitionGroup.CSSTransition, {
91
+ in: isOpen,
92
+ timeout: _animation.TRANSITION_DURATION,
93
+ classNames: componentName,
94
+ unmountOnExit: true,
95
+ nodeRef: contentRef,
96
+ onEnter: onEnter,
97
+ onExited: onExited
98
+ }, /*#__PURE__*/_react.default.createElement("div", {
99
+ ref: contentRef,
100
+ className: `${componentName}-content`,
101
+ id: `${componentName}-content`,
102
+ role: "region",
103
+ "aria-label": ariaLabel || 'Expanded content',
104
+ "aria-describedby": ariaDescribedBy
105
+ }, /*#__PURE__*/_react.default.createElement("div", {
106
+ className: `${componentName}-content-body`
107
+ }, childTwo), /*#__PURE__*/_react.default.createElement("button", {
108
+ ref: closeButtonRef,
109
+ className: `${componentName}-close`,
110
+ onClick: onClose,
111
+ onKeyDown: onKeyDown,
112
+ "aria-label": "Close expanded content",
113
+ type: "button"
114
+ }, /*#__PURE__*/_react.default.createElement("span", {
115
+ className: `${componentName}-close-text`
116
+ }, "Close"), /*#__PURE__*/_react.default.createElement("span", {
117
+ className: "sr-only"
118
+ }, " (Press Escape to close)")))), /*#__PURE__*/_react.default.createElement("div", {
119
+ className: "sr-only",
120
+ id: `${componentName}-instructions`
121
+ }, "Use Enter or Space to toggle content. Press Escape to close when expanded."));
122
+ });
123
+
124
+ // Set display name for debugging
125
+ AnimationToggle.displayName = 'AnimationToggle';
126
+ AnimationToggle.propTypes = {
127
+ // ===========================================
128
+ // Core Props
129
+ // ===========================================
130
+ /**
131
+ * Unique identifier for the component
132
+ */
133
+ id: _propTypes.string,
134
+ /**
135
+ * Additional CSS classes to apply
136
+ */
137
+ className: _propTypes.string,
138
+ // ===========================================
139
+ // Content Props
140
+ // ===========================================
141
+ /**
142
+ * Content to display in the trigger button (required)
143
+ */
144
+ childOne: (0, _propTypes.oneOfType)([_propTypes.string, _propTypes.node]).isRequired,
145
+ /**
146
+ * Content to display when expanded (required)
147
+ */
148
+ childTwo: (0, _propTypes.oneOfType)([_propTypes.string, _propTypes.node]).isRequired,
149
+ // ===========================================
150
+ // Behavior Props
151
+ // ===========================================
152
+ /**
153
+ * Whether the toggle is disabled
154
+ */
155
+ disabled: _propTypes.bool,
156
+ /**
157
+ * Whether to automatically focus the trigger button on mount
158
+ */
159
+ autoFocus: _propTypes.bool,
160
+ /**
161
+ * Whether the content is currently open
162
+ */
163
+ isOpen: _propTypes.bool,
164
+ /**
165
+ * Whether to show the trigger button
166
+ */
167
+ showButton: _propTypes.bool,
168
+ // ===========================================
169
+ // Event Props
170
+ // ===========================================
171
+ /**
172
+ * Callback function called when opening the toggle
173
+ * @param {Event} event - The triggering event
174
+ */
175
+ onOpen: _propTypes.func,
176
+ /**
177
+ * Callback function called when closing the toggle
178
+ * @param {Event} event - The triggering event
179
+ */
180
+ onClose: _propTypes.func,
181
+ /**
182
+ * Callback function for keyboard interactions
183
+ * @param {KeyboardEvent} event - The keyboard event
184
+ */
185
+ onKeyDown: _propTypes.func,
186
+ /**
187
+ * Callback when content transition enters
188
+ */
189
+ onEnter: _propTypes.func,
190
+ /**
191
+ * Callback when content transition exits
192
+ */
193
+ onExited: _propTypes.func,
194
+ // ===========================================
195
+ // Accessibility Props
196
+ // ===========================================
197
+ /**
198
+ * Accessible label for the toggle component (recommended)
199
+ */
200
+ // aria-label is used as a prop, not ariaLabel
201
+
202
+ /**
203
+ * ID of element that describes the toggle component
204
+ */
205
+ ariaDescribedBy: _propTypes.string,
206
+ /**
207
+ * Use className instead
208
+ * Additional CSS class names to apply to the wrapper
209
+ */
210
+ additionalClassName: _propTypes.string,
211
+ /**
212
+ * Use id for identification
213
+ * Base CSS class name for the component
214
+ */
215
+ componentName: _propTypes.string
216
+ };
@@ -0,0 +1,153 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = exports.Avatar = void 0;
7
+ var _react = _interopRequireWildcard(require("react"));
8
+ var _Animation = require("./Animation");
9
+ var _propTypes = require("prop-types");
10
+ var _icons = require("../icons");
11
+ 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); }
12
+ 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); } // CLEAN START OF FILE
13
+ const Avatar = exports.Avatar = /*#__PURE__*/(0, _react.forwardRef)(({
14
+ source = '',
15
+ alt = '',
16
+ fallbackText = '',
17
+ className = '',
18
+ size = 'md',
19
+ dimensions,
20
+ isClickable = false,
21
+ hasHoverEffect = false,
22
+ tabIndex = 0,
23
+ isLoading = false,
24
+ onClick,
25
+ onHover,
26
+ onFocus,
27
+ onBlur,
28
+ onKeyDown,
29
+ onError,
30
+ onLoad,
31
+ 'aria-label': ariaLabel,
32
+ 'aria-describedby': ariaDescribedBy,
33
+ role = 'img',
34
+ additionalClassName = '',
35
+ componentName = 'avatar',
36
+ ...restProps
37
+ }, ref) => {
38
+ const sizeMap = {
39
+ xs: '24px',
40
+ sm: '32px',
41
+ md: '48px',
42
+ lg: '64px',
43
+ xl: '96px'
44
+ };
45
+ const avatarSize = dimensions || sizeMap[size] || '48px';
46
+ const getAriaLabel = () => ariaLabel || alt || (fallbackText ? `Avatar for ${fallbackText}` : 'User avatar');
47
+ const handleKeyDown = event => {
48
+ if (isClickable && (event.key === 'Enter' || event.key === ' ')) {
49
+ event.preventDefault();
50
+ onClick?.(event);
51
+ }
52
+ onKeyDown?.(event);
53
+ };
54
+ const handleMouseEnter = event => {
55
+ onHover?.(event);
56
+ };
57
+ const handleImageError = event => {
58
+ onError?.(event);
59
+ };
60
+ const handleImageLoad = event => {
61
+ onLoad?.(event);
62
+ };
63
+ return /*#__PURE__*/_react.default.createElement(_Animation.AnimatedDiv, {
64
+ fadingEntrances: "fadeIn",
65
+ duration: "faster"
66
+ }, /*#__PURE__*/_react.default.createElement("div", _extends({
67
+ className: `${componentName} ${componentName}--${size} ${additionalClassName} ${isClickable ? `${componentName}--clickable` : ''} ${hasHoverEffect ? `${componentName}--hoverable` : ''} ${isLoading ? `${componentName}--loading` : ''} ${className}`.trim(),
68
+ "data-testid": componentName,
69
+ role: isClickable ? 'button' : role,
70
+ tabIndex: isClickable ? tabIndex : -1,
71
+ "aria-label": getAriaLabel(),
72
+ "aria-describedby": ariaDescribedBy,
73
+ onClick: isClickable ? onClick : undefined,
74
+ onMouseEnter: hasHoverEffect ? handleMouseEnter : undefined,
75
+ onFocus: isClickable ? onFocus : undefined,
76
+ onBlur: isClickable ? onBlur : undefined,
77
+ onKeyDown: isClickable ? handleKeyDown : undefined,
78
+ ref: ref
79
+ }, restProps), hasHoverEffect && /*#__PURE__*/_react.default.createElement("div", {
80
+ className: "hover",
81
+ style: {
82
+ width: avatarSize,
83
+ height: avatarSize
84
+ },
85
+ "aria-hidden": "true"
86
+ }), isLoading ? /*#__PURE__*/_react.default.createElement("div", {
87
+ className: `${componentName}__loading`,
88
+ style: {
89
+ width: avatarSize,
90
+ height: avatarSize
91
+ }
92
+ }, /*#__PURE__*/_react.default.createElement(_icons.LoadingSpinner, {
93
+ componentName: `${componentName}__loading-spinner`,
94
+ dimensions: Math.min(parseInt(avatarSize) * 0.5, 24)
95
+ })) : /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("div", {
96
+ className: "image",
97
+ style: {
98
+ backgroundImage: `url(${source})`,
99
+ borderRadius: '50%',
100
+ backgroundRepeat: 'no-repeat',
101
+ backgroundPosition: 'center center',
102
+ backgroundSize: 'cover',
103
+ width: avatarSize,
104
+ height: avatarSize
105
+ },
106
+ role: "img",
107
+ "aria-label": alt,
108
+ onError: handleImageError,
109
+ onLoad: handleImageLoad
110
+ }), !source && /*#__PURE__*/_react.default.createElement("div", {
111
+ className: `${componentName}__fallback`,
112
+ style: {
113
+ width: avatarSize,
114
+ height: avatarSize
115
+ }
116
+ }, fallbackText && fallbackText.length > 0 ? /*#__PURE__*/_react.default.createElement("span", {
117
+ className: `${componentName}__fallback-text`
118
+ }, fallbackText.charAt(0).toUpperCase()) : /*#__PURE__*/_react.default.createElement("svg", {
119
+ className: `${componentName}__fallback-icon`,
120
+ viewBox: "0 0 24 24",
121
+ fill: "currentColor"
122
+ }, /*#__PURE__*/_react.default.createElement("path", {
123
+ d: "M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"
124
+ })))), isClickable && /*#__PURE__*/_react.default.createElement("span", {
125
+ className: "sr-only"
126
+ }, "Press Enter or Space to interact with this avatar")));
127
+ });
128
+ Avatar.propTypes = {
129
+ source: _propTypes.string,
130
+ alt: _propTypes.string,
131
+ fallbackText: _propTypes.string,
132
+ size: (0, _propTypes.oneOf)(['xs', 'sm', 'md', 'lg', 'xl']),
133
+ dimensions: _propTypes.string,
134
+ className: _propTypes.string,
135
+ isClickable: _propTypes.bool,
136
+ isLoading: _propTypes.bool,
137
+ hasHoverEffect: _propTypes.bool,
138
+ tabIndex: _propTypes.number,
139
+ onClick: _propTypes.func,
140
+ onFocus: _propTypes.func,
141
+ onBlur: _propTypes.func,
142
+ onKeyDown: _propTypes.func,
143
+ onHover: _propTypes.func,
144
+ onError: _propTypes.func,
145
+ onLoad: _propTypes.func,
146
+ 'aria-label': _propTypes.string,
147
+ 'aria-describedby': _propTypes.string,
148
+ role: _propTypes.string,
149
+ additionalClassName: _propTypes.string,
150
+ componentName: _propTypes.string
151
+ };
152
+ Avatar.displayName = 'Avatar';
153
+ var _default = exports.default = Avatar;