@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,218 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.Button = 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); }
13
+ /**
14
+ * Button - A stateless, accessible button component for user interactions
15
+ *
16
+ * Features:
17
+ * - Multiple variants (primary, secondary, success, error, warning)
18
+ * - Multiple sizes (xs, sm, md, lg, xl)
19
+ * - Accessible with proper ARIA labels and keyboard support
20
+ * - Loading states with built-in spinner
21
+ * - Icon support (leading and trailing)
22
+ * - Full width and outline variants
23
+ * - Keyboard navigation and focus management
24
+ * - High contrast mode support
25
+ *
26
+ * @component
27
+ * @example
28
+ * <Button
29
+ * variant="primary"
30
+ * size="md"
31
+ * onClick={(event) => console.log('Button clicked')}
32
+ * disabled={false}
33
+ * isLoading={false}
34
+ * ariaLabel="Save changes"
35
+ * >
36
+ * Save Changes
37
+ * </Button>
38
+ */
39
+ const Button = exports.Button = /*#__PURE__*/(0, _react.forwardRef)(({
40
+ // Core props
41
+ id,
42
+ className = '',
43
+ // Appearance props
44
+ variant = 'primary',
45
+ size = 'md',
46
+ isOutline = false,
47
+ isFullWidth = false,
48
+ // Content props
49
+ type = 'button',
50
+ children = null,
51
+ iconLeading = null,
52
+ iconTrailing = null,
53
+ loadingText = 'Loading...',
54
+ // Behavior props
55
+ disabled = false,
56
+ isLoading = false,
57
+ tabIndex = 0,
58
+ // Event props
59
+ onClick,
60
+ onFocus,
61
+ onBlur,
62
+ onKeyDown,
63
+ onMouseEnter,
64
+ onMouseLeave,
65
+ // Accessibility props
66
+ 'aria-label': ariaLabel,
67
+ 'aria-describedby': ariaDescribedBy,
68
+ 'aria-expanded': ariaExpanded,
69
+ 'aria-haspopup': ariaHaspopup,
70
+ 'aria-pressed': ariaPressed,
71
+ role = 'button',
72
+ // Legacy props (for backward compatibility - internal use only)
73
+ componentName = 'button',
74
+ additionalClassName = '',
75
+ ...restProps
76
+ }, ref) => {
77
+ // Handle legacy prop mapping
78
+ const finalId = id || `button-${Math.random().toString(36).substr(2, 9)}`;
79
+ const finalClassName = className || additionalClassName;
80
+
81
+ // Handle keyboard navigation
82
+ const handleKeyDown = event => {
83
+ // Call custom handler first
84
+ onKeyDown?.(event);
85
+
86
+ // Prevent default for space key to avoid page scroll
87
+ if (event.key === ' ') {
88
+ event.preventDefault();
89
+ onClick?.(event);
90
+ }
91
+ // Enter key should trigger click
92
+ if (event.key === 'Enter') {
93
+ onClick?.(event);
94
+ }
95
+ onKeyDown?.(event);
96
+ };
97
+
98
+ // Generate comprehensive class names
99
+ const getClassNames = () => {
100
+ const classes = [componentName, `${componentName}--${variant}`, `${componentName}--${size}`];
101
+ if (isOutline) classes.push(`${componentName}--outline`);
102
+ if (isFullWidth) classes.push(`${componentName}--full-width`);
103
+ if (isLoading) classes.push(`${componentName}--loading`);
104
+ if (disabled) classes.push(`${componentName}--disabled`);
105
+ if (finalClassName) classes.push(finalClassName);
106
+ return classes.join(' ');
107
+ };
108
+
109
+ // Determine button content
110
+ const buttonContent = isLoading ? /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_icons.LoadingSpinner, {
111
+ componentName: `${componentName}__loading-spinner`,
112
+ dimensions: 16
113
+ }), /*#__PURE__*/_react.default.createElement("span", {
114
+ className: `${componentName}__loading-text`
115
+ }, loadingText)) : /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, iconLeading && /*#__PURE__*/_react.default.createElement("span", {
116
+ className: `${componentName}__icon ${componentName}__icon--leading`
117
+ }, iconLeading), children && /*#__PURE__*/_react.default.createElement("span", {
118
+ className: `${componentName}__text`
119
+ }, children), iconTrailing && /*#__PURE__*/_react.default.createElement("span", {
120
+ className: `${componentName}__icon ${componentName}__icon--trailing`
121
+ }, iconTrailing));
122
+ return /*#__PURE__*/_react.default.createElement(_Animation.AnimatedDiv, {
123
+ fadingEntrances: "fadeIn",
124
+ duration: "faster"
125
+ }, /*#__PURE__*/_react.default.createElement("button", _extends({}, restProps, {
126
+ ref: ref,
127
+ id: finalId,
128
+ className: getClassNames(),
129
+ "data-testid": componentName,
130
+ type: type,
131
+ disabled: disabled || isLoading,
132
+ tabIndex: disabled ? -1 : tabIndex,
133
+ onClick: !disabled && !isLoading ? onClick : undefined,
134
+ onFocus: !disabled ? onFocus : undefined,
135
+ onBlur: !disabled ? onBlur : undefined,
136
+ onKeyDown: !disabled && !isLoading ? handleKeyDown : undefined,
137
+ onMouseEnter: !disabled ? onMouseEnter : undefined,
138
+ onMouseLeave: !disabled ? onMouseLeave : undefined,
139
+ "aria-label": ariaLabel,
140
+ "aria-describedby": ariaDescribedBy,
141
+ "aria-expanded": ariaExpanded,
142
+ "aria-haspopup": ariaHaspopup,
143
+ "aria-pressed": ariaPressed,
144
+ "aria-disabled": disabled || isLoading,
145
+ "aria-busy": isLoading,
146
+ role: role
147
+ }), buttonContent, /*#__PURE__*/_react.default.createElement("span", {
148
+ className: "sr-only"
149
+ }, isLoading ? 'Button is loading, please wait' : 'Press Enter or Space to activate this button')));
150
+ });
151
+
152
+ // Configure component PropTypes
153
+ Button.propTypes = {
154
+ // Core props
155
+ /** Unique identifier for the component */
156
+ id: _propTypes.string,
157
+ /** Additional CSS classes to apply */
158
+ className: _propTypes.string,
159
+ // Appearance props
160
+ /** Button color variant */
161
+ variant: (0, _propTypes.oneOf)(['primary', 'secondary', 'success', 'error', 'warning']),
162
+ /** Button size variant */
163
+ size: (0, _propTypes.oneOf)(['xs', 'sm', 'md', 'lg', 'xl']),
164
+ /** Whether to use outline variant styling */
165
+ isOutline: _propTypes.bool,
166
+ /** Whether the button should take full width of its container */
167
+ isFullWidth: _propTypes.bool,
168
+ // Content props
169
+ /** HTML button type attribute */
170
+ type: (0, _propTypes.oneOf)(['button', 'submit', 'reset']),
171
+ /** Button content */
172
+ children: _propTypes.node,
173
+ /** Icon to display before the button text */
174
+ iconLeading: _propTypes.node,
175
+ /** Icon to display after the button text */
176
+ iconTrailing: _propTypes.node,
177
+ /** Text to display when button is loading */
178
+ loadingText: _propTypes.string,
179
+ // Behavior props
180
+ /** Whether the button is disabled */
181
+ disabled: _propTypes.bool,
182
+ /** Whether the button is in a loading state */
183
+ isLoading: _propTypes.bool,
184
+ /** Tab index for keyboard navigation */
185
+ tabIndex: _propTypes.number,
186
+ // Event props
187
+ /** Click event handler */
188
+ onClick: _propTypes.func,
189
+ /** Focus event handler */
190
+ onFocus: _propTypes.func,
191
+ /** Blur event handler */
192
+ onBlur: _propTypes.func,
193
+ /** Key down event handler */
194
+ onKeyDown: _propTypes.func,
195
+ /** Mouse enter event handler */
196
+ onMouseEnter: _propTypes.func,
197
+ /** Mouse leave event handler */
198
+ onMouseLeave: _propTypes.func,
199
+ // Accessibility props
200
+ /** Accessible label for the button */
201
+ 'aria-label': _propTypes.string,
202
+ /** ID of element that describes the button */
203
+ 'aria-describedby': _propTypes.string,
204
+ /** Whether the button controls an expanded element */
205
+ 'aria-expanded': _propTypes.bool,
206
+ /** Whether the button has a popup */
207
+ 'aria-haspopup': _propTypes.bool,
208
+ /** Whether the button is pressed (for toggle buttons) */
209
+ 'aria-pressed': _propTypes.bool,
210
+ /** ARIA role for the button */
211
+ role: _propTypes.string,
212
+ // Legacy props (for backward compatibility - internal use only)
213
+ /** Base CSS class name for the component */
214
+ componentName: _propTypes.string,
215
+ /** Additional CSS class names to apply to the button */
216
+ additionalClassName: _propTypes.string
217
+ };
218
+ Button.displayName = 'Button';
@@ -0,0 +1,222 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = exports.Card = void 0;
7
+ var _react = _interopRequireWildcard(require("react"));
8
+ var _Animation = require("./Animation");
9
+ var _propTypes = require("prop-types");
10
+ var _Heading = _interopRequireDefault(require("./Heading"));
11
+ var _Avatar = _interopRequireDefault(require("./Avatar"));
12
+ var _Ellipses = require("../icons/Ellipses");
13
+ var _Paragraph = require("./Paragraph");
14
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
15
+ 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); }
16
+ 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
17
+ // styles
18
+
19
+ /**
20
+ * Card Component
21
+ *
22
+ * A flexible, accessible card container for displaying structured content.
23
+ * Perfect for user profiles, product displays, articles, and content previews.
24
+ *
25
+ * Features:
26
+ * - Stateless design for maximum flexibility
27
+ * - Built-in avatar and header sections
28
+ * - Dropdown menu support with keyboard navigation
29
+ * - Full-width image support
30
+ * - Comprehensive accessibility features
31
+ * - Customizable content areas
32
+ *
33
+ * @component
34
+ * @example
35
+ * // Basic card with title and content
36
+ * <Card
37
+ * title="John Doe"
38
+ * subTitle="Software Engineer"
39
+ * bodyCopy="Passionate about creating accessible web experiences..."
40
+ * avatarSrc="/path/to/avatar.jpg"
41
+ * />
42
+ *
43
+ * @example
44
+ * // Interactive card with menu
45
+ * <Card
46
+ * title="Project Alpha"
47
+ * ellipsesList={[<MenuItem key="edit">Edit</MenuItem>]}
48
+ * isEllipsesOpen={menuOpen}
49
+ * onEllipsesToggle={() => setMenuOpen(!menuOpen)}
50
+ * role="article"
51
+ * />
52
+ */
53
+ const Card = exports.Card = /*#__PURE__*/(0, _react.forwardRef)(({
54
+ // Content props
55
+ bodyCopy = '',
56
+ title = '',
57
+ subTitle = '',
58
+ titleSize = 'h3',
59
+ // Image props
60
+ avatarSrc = '',
61
+ fullImage = '',
62
+ imgComponent = null,
63
+ // Menu props
64
+ ellipsesList = [],
65
+ isEllipsesOpen = false,
66
+ onEllipsesToggle = null,
67
+ onEllipsesKeyDown = null,
68
+ // Layout props
69
+ className = '',
70
+ // Accessibility props
71
+ 'aria-label': ariaLabel,
72
+ 'aria-describedby': ariaDescribedBy = null,
73
+ role = null,
74
+ tabIndex = null,
75
+ // Legacy props (for backward compatibility - internal use only)
76
+ additionalClassName = '',
77
+ componentName = 'card',
78
+ children = null,
79
+ ...restProps
80
+ }, ref) => {
81
+ // Handle legacy prop mapping
82
+ const finalClassName = className || additionalClassName;
83
+ return /*#__PURE__*/_react.default.createElement("div", _extends({
84
+ ref: ref,
85
+ className: `${componentName} ${isEllipsesOpen ? 'open' : ''} ${finalClassName}`.trim(),
86
+ "data-testid": componentName,
87
+ role: role,
88
+ "aria-label": ariaLabel,
89
+ "aria-describedby": ariaDescribedBy,
90
+ tabIndex: tabIndex
91
+ }, restProps), avatarSrc && /*#__PURE__*/_react.default.createElement("div", {
92
+ className: "head"
93
+ }, /*#__PURE__*/_react.default.createElement(_Avatar.default, {
94
+ dimensions: "50px",
95
+ source: avatarSrc,
96
+ alt: title ? `${title} avatar` : 'User avatar'
97
+ }), ellipsesList.length > 0 && /*#__PURE__*/_react.default.createElement("div", {
98
+ className: "ellipses"
99
+ }, /*#__PURE__*/_react.default.createElement("button", {
100
+ type: "button",
101
+ className: "ellipses-trigger",
102
+ onClick: onEllipsesToggle,
103
+ onKeyDown: onEllipsesKeyDown,
104
+ "aria-expanded": isEllipsesOpen,
105
+ "aria-haspopup": "menu",
106
+ "aria-label": "Card options menu"
107
+ }, /*#__PURE__*/_react.default.createElement(_Ellipses.Ellipses, null)), isEllipsesOpen && /*#__PURE__*/_react.default.createElement("div", {
108
+ className: "ellipses-content",
109
+ role: "menu",
110
+ "aria-label": "Card options"
111
+ }, /*#__PURE__*/_react.default.createElement("ul", {
112
+ className: "unordered-list",
113
+ role: "none"
114
+ }, ellipsesList)))), fullImage && imgComponent ? imgComponent : fullImage && /*#__PURE__*/_react.default.createElement("img", {
115
+ src: fullImage,
116
+ alt: title ? `${title} image` : 'Card image',
117
+ className: "card-image"
118
+ }), title && /*#__PURE__*/_react.default.createElement(_Heading.default, {
119
+ variant: titleSize,
120
+ style: {
121
+ marginTop: avatarSrc && '0'
122
+ },
123
+ componentName: "card-title"
124
+ }, title), subTitle && /*#__PURE__*/_react.default.createElement(_Paragraph.Paragraph, {
125
+ componentName: "card-subtitle"
126
+ }, subTitle), bodyCopy && /*#__PURE__*/_react.default.createElement(_Animation.AnimatedDiv, {
127
+ fadingEntrances: "fadeIn",
128
+ duration: "faster"
129
+ }, /*#__PURE__*/_react.default.createElement("div", {
130
+ className: `${componentName}__body`
131
+ }, /*#__PURE__*/_react.default.createElement(_Paragraph.Paragraph, {
132
+ className: `${componentName}__body-copy`
133
+ }, bodyCopy), children)));
134
+ });
135
+
136
+ // Set display name for debugging
137
+ Card.displayName = 'Card';
138
+ Card.propTypes = {
139
+ // ===========================================
140
+ // Core Props
141
+ // ===========================================
142
+ /**
143
+ * Card title text for the header
144
+ */
145
+ title: _propTypes.string,
146
+ /**
147
+ * Card subtitle text displayed below title
148
+ */
149
+ subTitle: _propTypes.string,
150
+ // ===========================================
151
+ // Content Props
152
+ // ===========================================
153
+ /**
154
+ * Main content text for the card body
155
+ */
156
+ bodyCopy: (0, _propTypes.oneOfType)([_propTypes.string, _propTypes.node]),
157
+ /**
158
+ * Heading size variant for the title
159
+ */
160
+ titleSize: (0, _propTypes.oneOfType)([_propTypes.string, _propTypes.node]),
161
+ // ===========================================
162
+ // Image Props
163
+ // ===========================================
164
+ /**
165
+ * URL for avatar image in card header
166
+ */
167
+ avatarSrc: _propTypes.string,
168
+ /**
169
+ * URL for full-width card image
170
+ */
171
+ fullImage: _propTypes.string,
172
+ /**
173
+ * Custom image component to render instead of default img tag
174
+ */
175
+ imgComponent: _propTypes.node,
176
+ // ===========================================
177
+ // Menu & Interaction Props
178
+ // ===========================================
179
+ /**
180
+ * Array of menu items for ellipses dropdown
181
+ */
182
+ ellipsesList: (0, _propTypes.arrayOf)(_propTypes.node),
183
+ /**
184
+ * Whether the ellipses dropdown menu is open (controlled by parent)
185
+ */
186
+ isEllipsesOpen: _propTypes.bool,
187
+ /**
188
+ * Callback function for ellipses dropdown toggle
189
+ */
190
+ onEllipsesToggle: _propTypes.func,
191
+ /**
192
+ * Callback function for ellipses keyboard navigation
193
+ */
194
+ onEllipsesKeyDown: _propTypes.func,
195
+ // ===========================================
196
+ // Appearance Props
197
+ // ===========================================
198
+ /**
199
+ * Additional CSS classes to apply to the card
200
+ */
201
+ className: _propTypes.string,
202
+ // ===========================================
203
+ // Accessibility Props
204
+ // ===========================================
205
+ /**
206
+ * Accessible label for the entire card
207
+ */
208
+ 'aria-label': _propTypes.string,
209
+ /**
210
+ * ID of element that describes the card content
211
+ */
212
+ 'aria-describedby': _propTypes.string,
213
+ /**
214
+ * ARIA role for the card (e.g., 'article', 'region')
215
+ */
216
+ role: _propTypes.string,
217
+ /**
218
+ * Tab index for keyboard navigation (-1 to remove from tab order)
219
+ */
220
+ tabIndex: (0, _propTypes.oneOfType)([_propTypes.string, _propTypes.node])
221
+ };
222
+ var _default = exports.default = Card;