@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,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;
|