@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,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _react = _interopRequireDefault(require("react"));
|
|
4
|
+
var _react2 = require("@testing-library/react");
|
|
5
|
+
var _TrashX = require("../icons/TrashX");
|
|
6
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
7
|
+
// Suppress console.error during tests
|
|
8
|
+
let consoleErrorSpy;
|
|
9
|
+
beforeAll(() => {
|
|
10
|
+
consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
|
11
|
+
});
|
|
12
|
+
afterAll(() => {
|
|
13
|
+
consoleErrorSpy.mockRestore();
|
|
14
|
+
});
|
|
15
|
+
describe('TrashX', () => {
|
|
16
|
+
test('renders trash x icon with default props', () => {
|
|
17
|
+
const {
|
|
18
|
+
container
|
|
19
|
+
} = (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_TrashX.TrashX, null));
|
|
20
|
+
const svg = container.querySelector('svg');
|
|
21
|
+
expect(svg).toBeInTheDocument();
|
|
22
|
+
expect(svg).toHaveClass('icon', 'trash-x');
|
|
23
|
+
expect(svg).toHaveAttribute('width', '24');
|
|
24
|
+
expect(svg).toHaveAttribute('height', '24');
|
|
25
|
+
expect(svg).toHaveAttribute('viewBox', '0 -960 960 960');
|
|
26
|
+
expect(svg).toHaveAttribute('fill', '#adb5bd');
|
|
27
|
+
});
|
|
28
|
+
test('renders with custom component name', () => {
|
|
29
|
+
const {
|
|
30
|
+
container
|
|
31
|
+
} = (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_TrashX.TrashX, {
|
|
32
|
+
componentName: "delete-icon"
|
|
33
|
+
}));
|
|
34
|
+
const svg = container.querySelector('svg');
|
|
35
|
+
expect(svg).toHaveClass('icon', 'delete-icon');
|
|
36
|
+
});
|
|
37
|
+
test('renders with additional className', () => {
|
|
38
|
+
const {
|
|
39
|
+
container
|
|
40
|
+
} = (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_TrashX.TrashX, {
|
|
41
|
+
additionalClassName: "danger-icon interactive"
|
|
42
|
+
}));
|
|
43
|
+
const svg = container.querySelector('svg');
|
|
44
|
+
expect(svg).toHaveClass('icon', 'trash-x', 'danger-icon', 'interactive');
|
|
45
|
+
});
|
|
46
|
+
test('renders with custom dimensions', () => {
|
|
47
|
+
const {
|
|
48
|
+
container
|
|
49
|
+
} = (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_TrashX.TrashX, {
|
|
50
|
+
dimensions: 16
|
|
51
|
+
}));
|
|
52
|
+
const svg = container.querySelector('svg');
|
|
53
|
+
expect(svg).toHaveAttribute('width', '16');
|
|
54
|
+
expect(svg).toHaveAttribute('height', '16');
|
|
55
|
+
});
|
|
56
|
+
test('renders with custom viewBox', () => {
|
|
57
|
+
const {
|
|
58
|
+
container
|
|
59
|
+
} = (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_TrashX.TrashX, {
|
|
60
|
+
viewBox: "0 0 24 24"
|
|
61
|
+
}));
|
|
62
|
+
const svg = container.querySelector('svg');
|
|
63
|
+
expect(svg).toHaveAttribute('viewBox', '0 0 24 24');
|
|
64
|
+
});
|
|
65
|
+
test('renders with custom fill color', () => {
|
|
66
|
+
const {
|
|
67
|
+
container
|
|
68
|
+
} = (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_TrashX.TrashX, {
|
|
69
|
+
fill: "#dc3545"
|
|
70
|
+
}));
|
|
71
|
+
const svg = container.querySelector('svg');
|
|
72
|
+
expect(svg).toHaveAttribute('fill', '#dc3545');
|
|
73
|
+
});
|
|
74
|
+
test('contains path element', () => {
|
|
75
|
+
const {
|
|
76
|
+
container
|
|
77
|
+
} = (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_TrashX.TrashX, null));
|
|
78
|
+
const path = container.querySelector('path');
|
|
79
|
+
expect(path).toBeInTheDocument();
|
|
80
|
+
expect(path).toHaveAttribute('d');
|
|
81
|
+
});
|
|
82
|
+
test('combines all props correctly', () => {
|
|
83
|
+
const {
|
|
84
|
+
container
|
|
85
|
+
} = (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_TrashX.TrashX, {
|
|
86
|
+
componentName: "remove-button",
|
|
87
|
+
additionalClassName: "red-hover clickable",
|
|
88
|
+
dimensions: 22,
|
|
89
|
+
viewBox: "0 0 32 32",
|
|
90
|
+
fill: "#e74c3c"
|
|
91
|
+
}));
|
|
92
|
+
const svg = container.querySelector('svg');
|
|
93
|
+
expect(svg).toHaveClass('icon', 'remove-button', 'red-hover', 'clickable');
|
|
94
|
+
expect(svg).toHaveAttribute('width', '22');
|
|
95
|
+
expect(svg).toHaveAttribute('height', '22');
|
|
96
|
+
expect(svg).toHaveAttribute('viewBox', '0 0 32 32');
|
|
97
|
+
expect(svg).toHaveAttribute('fill', '#e74c3c');
|
|
98
|
+
});
|
|
99
|
+
});
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _react = require("@testing-library/react");
|
|
4
|
+
var _useHeadingAccessibility = require("../utils/useHeadingAccessibility");
|
|
5
|
+
// Suppress console.error during tests
|
|
6
|
+
let consoleErrorSpy;
|
|
7
|
+
beforeAll(() => {
|
|
8
|
+
consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
|
9
|
+
});
|
|
10
|
+
afterAll(() => {
|
|
11
|
+
consoleErrorSpy.mockRestore();
|
|
12
|
+
});
|
|
13
|
+
describe('useHeadingAccessibility', () => {
|
|
14
|
+
test('returns ref and aria properties', () => {
|
|
15
|
+
const {
|
|
16
|
+
result
|
|
17
|
+
} = (0, _react.renderHook)(() => (0, _useHeadingAccessibility.useHeadingAccessibility)({
|
|
18
|
+
level: 1
|
|
19
|
+
}));
|
|
20
|
+
expect(result.current.headingRef).toBeDefined();
|
|
21
|
+
expect(result.current.headingRef.current).toBeNull(); // No element attached yet
|
|
22
|
+
expect(result.current.ariaProps).toMatchObject({
|
|
23
|
+
'aria-level': 1,
|
|
24
|
+
tabIndex: undefined,
|
|
25
|
+
onFocus: undefined
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
test('sets banner role for h1', () => {
|
|
29
|
+
const {
|
|
30
|
+
result
|
|
31
|
+
} = (0, _react.renderHook)(() => (0, _useHeadingAccessibility.useHeadingAccessibility)({
|
|
32
|
+
level: 1
|
|
33
|
+
}));
|
|
34
|
+
expect(result.current.ariaProps.role || '').toBe('banner');
|
|
35
|
+
});
|
|
36
|
+
test('does not set banner role for other levels', () => {
|
|
37
|
+
const {
|
|
38
|
+
result
|
|
39
|
+
} = (0, _react.renderHook)(() => (0, _useHeadingAccessibility.useHeadingAccessibility)({
|
|
40
|
+
level: 2
|
|
41
|
+
}));
|
|
42
|
+
expect(result.current.ariaProps.role).toBeUndefined();
|
|
43
|
+
});
|
|
44
|
+
test('sets tabIndex when autoFocus is enabled', () => {
|
|
45
|
+
const {
|
|
46
|
+
result
|
|
47
|
+
} = (0, _react.renderHook)(() => (0, _useHeadingAccessibility.useHeadingAccessibility)({
|
|
48
|
+
level: 1,
|
|
49
|
+
autoFocus: true
|
|
50
|
+
}));
|
|
51
|
+
expect(result.current.ariaProps.tabIndex).toBe(0);
|
|
52
|
+
});
|
|
53
|
+
test('sets onFocus handler when provided', () => {
|
|
54
|
+
const onFocus = jest.fn();
|
|
55
|
+
const {
|
|
56
|
+
result
|
|
57
|
+
} = (0, _react.renderHook)(() => (0, _useHeadingAccessibility.useHeadingAccessibility)({
|
|
58
|
+
level: 1,
|
|
59
|
+
onFocus
|
|
60
|
+
}));
|
|
61
|
+
expect(result.current.ariaProps.onFocus).toBeDefined();
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
describe('useHeadingHierarchy', () => {
|
|
65
|
+
test('validates proper hierarchy', () => {
|
|
66
|
+
const {
|
|
67
|
+
result
|
|
68
|
+
} = (0, _react.renderHook)(() => (0, _useHeadingAccessibility.useHeadingHierarchy)(2, {
|
|
69
|
+
existingLevels: [1]
|
|
70
|
+
}));
|
|
71
|
+
expect(result.current.isValidHierarchy).toBe(true);
|
|
72
|
+
expect(result.current.warnings).toHaveLength(0);
|
|
73
|
+
});
|
|
74
|
+
test('warns when page does not start with h1', () => {
|
|
75
|
+
const {
|
|
76
|
+
result
|
|
77
|
+
} = (0, _react.renderHook)(() => (0, _useHeadingAccessibility.useHeadingHierarchy)(2, {
|
|
78
|
+
existingLevels: []
|
|
79
|
+
}));
|
|
80
|
+
expect(result.current.isValidHierarchy).toBe(false);
|
|
81
|
+
expect(result.current.warnings).toContain('Page should start with an h1 heading');
|
|
82
|
+
});
|
|
83
|
+
test('warns about heading level gaps', () => {
|
|
84
|
+
const {
|
|
85
|
+
result
|
|
86
|
+
} = (0, _react.renderHook)(() => (0, _useHeadingAccessibility.useHeadingHierarchy)(4, {
|
|
87
|
+
existingLevels: [1, 2]
|
|
88
|
+
}));
|
|
89
|
+
expect(result.current.isValidHierarchy).toBe(false);
|
|
90
|
+
expect(result.current.warnings[0]).toContain('Heading level gap detected: h2 → h4');
|
|
91
|
+
});
|
|
92
|
+
test('allows multiple headings at same level', () => {
|
|
93
|
+
const {
|
|
94
|
+
result
|
|
95
|
+
} = (0, _react.renderHook)(() => (0, _useHeadingAccessibility.useHeadingHierarchy)(2, {
|
|
96
|
+
existingLevels: [1, 2, 2]
|
|
97
|
+
}));
|
|
98
|
+
expect(result.current.isValidHierarchy).toBe(true);
|
|
99
|
+
expect(result.current.warnings).toHaveLength(0);
|
|
100
|
+
});
|
|
101
|
+
test('allows going back to higher level', () => {
|
|
102
|
+
const {
|
|
103
|
+
result
|
|
104
|
+
} = (0, _react.renderHook)(() => (0, _useHeadingAccessibility.useHeadingHierarchy)(2, {
|
|
105
|
+
existingLevels: [1, 2, 3, 3]
|
|
106
|
+
}));
|
|
107
|
+
expect(result.current.isValidHierarchy).toBe(true);
|
|
108
|
+
expect(result.current.warnings).toHaveLength(0);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
describe('useHeadingId', () => {
|
|
112
|
+
test('generates ID from text', () => {
|
|
113
|
+
const id = (0, _useHeadingAccessibility.useHeadingId)('Getting Started Guide');
|
|
114
|
+
expect(id).toBe('getting-started-guide');
|
|
115
|
+
});
|
|
116
|
+
test('handles special characters', () => {
|
|
117
|
+
const id = (0, _useHeadingAccessibility.useHeadingId)('API Reference & Examples!');
|
|
118
|
+
expect(id).toBe('api-reference-examples');
|
|
119
|
+
});
|
|
120
|
+
test('handles multiple spaces', () => {
|
|
121
|
+
const id = (0, _useHeadingAccessibility.useHeadingId)('Multiple Spaces Here');
|
|
122
|
+
expect(id).toBe('multiple-spaces-here');
|
|
123
|
+
});
|
|
124
|
+
test('adds prefix when provided', () => {
|
|
125
|
+
const id = (0, _useHeadingAccessibility.useHeadingId)('Section Title', 'page');
|
|
126
|
+
expect(id).toBe('page-section-title');
|
|
127
|
+
});
|
|
128
|
+
test('handles empty text', () => {
|
|
129
|
+
const id = (0, _useHeadingAccessibility.useHeadingId)('');
|
|
130
|
+
expect(id).toBe('');
|
|
131
|
+
});
|
|
132
|
+
test('handles numbers in text', () => {
|
|
133
|
+
const id = (0, _useHeadingAccessibility.useHeadingId)('Step 1: Installation');
|
|
134
|
+
expect(id).toBe('step-1-installation');
|
|
135
|
+
});
|
|
136
|
+
test('removes leading and trailing hyphens', () => {
|
|
137
|
+
const id = (0, _useHeadingAccessibility.useHeadingId)('---Special Text---');
|
|
138
|
+
expect(id).toBe('special-text');
|
|
139
|
+
});
|
|
140
|
+
test('handles non-string input', () => {
|
|
141
|
+
const id = (0, _useHeadingAccessibility.useHeadingId)(123);
|
|
142
|
+
expect(id).toBe('123');
|
|
143
|
+
});
|
|
144
|
+
});
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.Anchor = void 0;
|
|
7
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
8
|
+
var _propTypes = require("prop-types");
|
|
9
|
+
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); }
|
|
10
|
+
/**
|
|
11
|
+
* Anchor Component
|
|
12
|
+
*
|
|
13
|
+
* A semantic anchor/link component with accessibility features and security enhancements.
|
|
14
|
+
* Perfect for navigation, external links, and call-to-action elements.
|
|
15
|
+
*
|
|
16
|
+
* Features:
|
|
17
|
+
* - Semantic anchor element with proper attributes
|
|
18
|
+
* - Disabled state support with accessibility
|
|
19
|
+
* - Automatic security attributes for external links
|
|
20
|
+
* - Multiple visual variants
|
|
21
|
+
* - Screen reader friendly
|
|
22
|
+
* - Keyboard navigation support
|
|
23
|
+
*
|
|
24
|
+
* Security:
|
|
25
|
+
* - Automatically adds rel="noopener noreferrer" for external links
|
|
26
|
+
* - Proper disabled state handling
|
|
27
|
+
*
|
|
28
|
+
* @component
|
|
29
|
+
* @example
|
|
30
|
+
* // Basic link
|
|
31
|
+
* <Anchor href="https://example.com">
|
|
32
|
+
* Visit Example
|
|
33
|
+
* </Anchor>
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* // External link with variant
|
|
37
|
+
* <Anchor
|
|
38
|
+
* href="https://github.com"
|
|
39
|
+
* target="_blank"
|
|
40
|
+
* variant="primary"
|
|
41
|
+
* >
|
|
42
|
+
* Open GitHub
|
|
43
|
+
* </Anchor>
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* // Disabled link
|
|
47
|
+
* <Anchor href="/unavailable" disabled>
|
|
48
|
+
* Unavailable Link
|
|
49
|
+
* </Anchor>
|
|
50
|
+
*/
|
|
51
|
+
const Anchor = exports.Anchor = /*#__PURE__*/(0, _react.forwardRef)(({
|
|
52
|
+
// Core props
|
|
53
|
+
href = '',
|
|
54
|
+
children = null,
|
|
55
|
+
disabled = false,
|
|
56
|
+
// Layout props
|
|
57
|
+
className = '',
|
|
58
|
+
variant = '',
|
|
59
|
+
// Navigation props
|
|
60
|
+
target = '_self',
|
|
61
|
+
// Legacy props (for backward compatibility - internal use only)
|
|
62
|
+
additionalClassName = '',
|
|
63
|
+
componentName = 'anchor',
|
|
64
|
+
...restProps
|
|
65
|
+
}, ref) => {
|
|
66
|
+
// Handle legacy prop mapping
|
|
67
|
+
const finalClassName = className || additionalClassName;
|
|
68
|
+
|
|
69
|
+
// Build CSS classes
|
|
70
|
+
const anchorClasses = [componentName, variant, finalClassName].filter(Boolean).join(' ').trim();
|
|
71
|
+
|
|
72
|
+
// Handle disabled state accessibility
|
|
73
|
+
const anchorProps = {
|
|
74
|
+
ref,
|
|
75
|
+
target,
|
|
76
|
+
href: disabled ? undefined : href,
|
|
77
|
+
'data-testid': componentName,
|
|
78
|
+
className: anchorClasses,
|
|
79
|
+
'aria-disabled': disabled,
|
|
80
|
+
tabIndex: disabled ? -1 : undefined,
|
|
81
|
+
onClick: disabled ? e => e.preventDefault() : undefined,
|
|
82
|
+
// Add security attributes for external links
|
|
83
|
+
rel: target === '_blank' ? 'noopener noreferrer' : undefined,
|
|
84
|
+
...restProps
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
// Remove invalid HTML attributes using destructuring
|
|
88
|
+
const {
|
|
89
|
+
type,
|
|
90
|
+
...finalProps
|
|
91
|
+
} = anchorProps;
|
|
92
|
+
return /*#__PURE__*/_react.default.createElement("a", finalProps, children);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// Set display name for debugging
|
|
96
|
+
Anchor.displayName = 'Anchor';
|
|
97
|
+
Anchor.propTypes = {
|
|
98
|
+
// Core Props
|
|
99
|
+
/**
|
|
100
|
+
* The URL that the hyperlink points to
|
|
101
|
+
* @required Essential for functional links
|
|
102
|
+
*/
|
|
103
|
+
href: _propTypes.string.isRequired,
|
|
104
|
+
/**
|
|
105
|
+
* Content to be displayed inside the anchor element
|
|
106
|
+
* @required Essential for meaningful link text
|
|
107
|
+
*/
|
|
108
|
+
children: _propTypes.node.isRequired,
|
|
109
|
+
/**
|
|
110
|
+
* Whether the anchor should be disabled
|
|
111
|
+
* Prevents navigation and adds proper accessibility attributes
|
|
112
|
+
*/
|
|
113
|
+
disabled: _propTypes.bool,
|
|
114
|
+
// Layout Props
|
|
115
|
+
/**
|
|
116
|
+
* Additional CSS class names to apply to the anchor
|
|
117
|
+
*/
|
|
118
|
+
className: _propTypes.string,
|
|
119
|
+
/**
|
|
120
|
+
* Visual variant/style of the anchor
|
|
121
|
+
* Common values: 'primary', 'secondary', 'danger', 'success'
|
|
122
|
+
*/
|
|
123
|
+
variant: _propTypes.string,
|
|
124
|
+
// Navigation Props
|
|
125
|
+
/**
|
|
126
|
+
* Specifies where to open the linked document
|
|
127
|
+
* '_blank' opens in a new tab/window, '_self' opens in the same frame
|
|
128
|
+
* Note: When target='_blank', rel='noopener noreferrer' is automatically added for security
|
|
129
|
+
*/
|
|
130
|
+
target: _propTypes.string
|
|
131
|
+
};
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = exports.AnimatedDiv = void 0;
|
|
7
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
8
|
+
var _propTypes = require("prop-types");
|
|
9
|
+
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); }
|
|
10
|
+
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); }
|
|
11
|
+
const AnimatedDiv = exports.AnimatedDiv = /*#__PURE__*/(0, _react.forwardRef)(({
|
|
12
|
+
// Content props
|
|
13
|
+
children = null,
|
|
14
|
+
// Animation behavior props
|
|
15
|
+
attentionSeekers = '',
|
|
16
|
+
backEntrances = '',
|
|
17
|
+
backExits = '',
|
|
18
|
+
bouncingEntrances = '',
|
|
19
|
+
bouncingExits = '',
|
|
20
|
+
fadingEntrances = '',
|
|
21
|
+
fadingExits = '',
|
|
22
|
+
flippers = '',
|
|
23
|
+
lightSpeed = '',
|
|
24
|
+
rotatingEntrances = '',
|
|
25
|
+
rotatingExits = '',
|
|
26
|
+
specials = '',
|
|
27
|
+
zoomingEntrances = '',
|
|
28
|
+
zoomingExits = '',
|
|
29
|
+
slidingEntrances = '',
|
|
30
|
+
slidingExits = '',
|
|
31
|
+
iteration = '',
|
|
32
|
+
delay = '',
|
|
33
|
+
duration = '',
|
|
34
|
+
// Accessibility props
|
|
35
|
+
reduceMotion = false,
|
|
36
|
+
// Legacy props (for backward compatibility - internal use only)
|
|
37
|
+
componentName = 'animation',
|
|
38
|
+
additionalClassName = '',
|
|
39
|
+
// Core props
|
|
40
|
+
id,
|
|
41
|
+
className = '',
|
|
42
|
+
...restProps
|
|
43
|
+
}, ref) => {
|
|
44
|
+
// Handle legacy prop mapping
|
|
45
|
+
const finalId = id || `animation-${Math.random().toString(36).substr(2, 9)}`;
|
|
46
|
+
const finalClassName = className || additionalClassName;
|
|
47
|
+
|
|
48
|
+
// Build animation classes
|
|
49
|
+
const animationType = attentionSeekers || backEntrances || backExits || bouncingEntrances || bouncingExits || fadingEntrances || fadingExits || flippers || lightSpeed || rotatingEntrances || rotatingExits || specials || zoomingEntrances || zoomingExits || slidingEntrances || slidingExits;
|
|
50
|
+
const animationClasses = [componentName, 'animate__animated', iteration && `animate__${iteration}`, delay && `animate__${delay}`, duration && `animate__${duration}`, animationType && `animate__${animationType}`, finalClassName].filter(Boolean).join(' ');
|
|
51
|
+
return /*#__PURE__*/_react.default.createElement("div", _extends({
|
|
52
|
+
ref: ref,
|
|
53
|
+
id: finalId,
|
|
54
|
+
"data-testid": "animation",
|
|
55
|
+
className: animationClasses
|
|
56
|
+
// Respect user's motion preferences for accessibility
|
|
57
|
+
,
|
|
58
|
+
style: reduceMotion ? {
|
|
59
|
+
animation: 'none'
|
|
60
|
+
} : undefined
|
|
61
|
+
// Add accessibility attributes for screen readers
|
|
62
|
+
,
|
|
63
|
+
"aria-live": animationType ? 'polite' : undefined,
|
|
64
|
+
role: animationType ? 'region' : undefined,
|
|
65
|
+
"aria-label": animationType ? `Animated content: ${animationType}` : undefined
|
|
66
|
+
}, restProps), children);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Set display name for debugging
|
|
70
|
+
AnimatedDiv.displayName = 'AnimatedDiv';
|
|
71
|
+
// Configure component PropTypes
|
|
72
|
+
AnimatedDiv.propTypes = {
|
|
73
|
+
// Core props
|
|
74
|
+
/** Unique identifier for the component */
|
|
75
|
+
id: _propTypes.string,
|
|
76
|
+
/** Additional CSS classes to apply */
|
|
77
|
+
className: _propTypes.string,
|
|
78
|
+
/** Content to be animated */
|
|
79
|
+
children: _propTypes.node.isRequired,
|
|
80
|
+
// Animation behavior props
|
|
81
|
+
/** Animation iteration count - how many times the animation should repeat */
|
|
82
|
+
|
|
83
|
+
iteration: (0, _propTypes.oneOf)(['', 'infinite', 'repeat-1', 'repeat-2', 'repeat-3']),
|
|
84
|
+
/** Animation delay before starting */
|
|
85
|
+
delay: (0, _propTypes.oneOf)(['', 'delay-1s', 'delay-2s', 'delay-3s', 'delay-4s', 'delay-5s']),
|
|
86
|
+
/** Animation duration speed */
|
|
87
|
+
duration: (0, _propTypes.oneOf)(['', 'faster', 'fast', 'slow', 'slower']),
|
|
88
|
+
/** Attention-seeking animations (recommended for important notifications) */
|
|
89
|
+
attentionSeekers: (0, _propTypes.oneOf)(['', 'bounce', 'flash', 'pulse', 'rubberBand', 'shakeX', 'shakeY', 'headShake', 'swing', 'tada', 'wobble', 'jello', 'heartBeat']),
|
|
90
|
+
/** Back entrance animations - elements entering from behind */
|
|
91
|
+
backEntrances: (0, _propTypes.oneOf)(['', 'backInDown', 'backInLeft', 'backInRight', 'backInUp']),
|
|
92
|
+
/** Back exit animations - elements exiting behind */
|
|
93
|
+
backExits: (0, _propTypes.oneOf)(['', 'backOutDown', 'backOutLeft', 'backOutRight', 'backOutUp']),
|
|
94
|
+
/** Bouncing entrance animations - playful entrance effects */
|
|
95
|
+
bouncingEntrances: (0, _propTypes.oneOf)(['', 'bounceIn', 'bounceInDown', 'bounceInLeft', 'bounceInRight', 'bounceInUp']),
|
|
96
|
+
/** Bouncing exit animations - playful exit effects */
|
|
97
|
+
bouncingExits: (0, _propTypes.oneOf)(['', 'bounceOut', 'bounceOutDown', 'bounceOutLeft', 'bounceOutRight', 'bounceOutUp']),
|
|
98
|
+
/** Fading entrance animations - smooth appearance effects */
|
|
99
|
+
fadingEntrances: (0, _propTypes.oneOf)(['', 'fadeIn', 'fadeInDown', 'fadeInDownBig', 'fadeInLeft', 'fadeInLeftBig', 'fadeInRight', 'fadeInRightBig', 'fadeInUp', 'fadeInUpBig', 'fadeInTopLeft', 'fadeInTopRight', 'fadeInBottomLeft', 'fadeInBottomRight']),
|
|
100
|
+
/** Fading exit animations - smooth disappearance effects */
|
|
101
|
+
fadingExits: (0, _propTypes.oneOf)(['', 'fadeOut', 'fadeOutDown', 'fadeOutDownBig', 'fadeOutLeft', 'fadeOutLeftBig', 'fadeOutRight', 'fadeOutRightBig', 'fadeOutUp', 'fadeOutUpBig', 'fadeOutTopLeft', 'fadeOutTopRight', 'fadeOutBottomRight', 'fadeOutBottomLeft']),
|
|
102
|
+
/** Flip animations - 3D rotation effects */
|
|
103
|
+
flippers: (0, _propTypes.oneOf)(['', 'flip', 'flipInX', 'flipInY', 'flipOutX', 'flipOutY']),
|
|
104
|
+
/** Light speed animations - ultra-fast movement effects */
|
|
105
|
+
lightSpeed: (0, _propTypes.oneOf)(['', 'lightSpeedInRight', 'lightSpeedInLeft', 'lightSpeedOutRight', 'lightSpeedOutLeft']),
|
|
106
|
+
/** Rotating entrance animations - spinning entrance effects */
|
|
107
|
+
rotatingEntrances: (0, _propTypes.oneOf)(['', 'rotateIn', 'rotateInDownLeft', 'rotateInDownRight', 'rotateInUpLeft', 'rotateInUpRight']),
|
|
108
|
+
/** Rotating exit animations - spinning exit effects */
|
|
109
|
+
rotatingExits: (0, _propTypes.oneOf)(['', 'rotateOut', 'rotateOutDownLeft', 'rotateOutDownRight', 'rotateOutUpLeft', 'rotateOutUpRight']),
|
|
110
|
+
/** Special animations - unique and distinctive effects */
|
|
111
|
+
specials: (0, _propTypes.oneOf)(['', 'hinge', 'jackInTheBox', 'rollIn', 'rollOut']),
|
|
112
|
+
/** Zooming entrance animations - scaling entrance effects */
|
|
113
|
+
zoomingEntrances: (0, _propTypes.oneOf)(['', 'zoomIn', 'zoomInDown', 'zoomInLeft', 'zoomInRight', 'zoomInUp']),
|
|
114
|
+
/** Zooming exit animations - scaling exit effects */
|
|
115
|
+
zoomingExits: (0, _propTypes.oneOf)(['', 'zoomOut', 'zoomOutDown', 'zoomOutLeft', 'zoomOutRight', 'zoomOutUp']),
|
|
116
|
+
/** Sliding entrance animations - directional entrance effects */
|
|
117
|
+
slidingEntrances: (0, _propTypes.oneOf)(['', 'slideInDown', 'slideInLeft', 'slideInRight', 'slideInUp']),
|
|
118
|
+
/** Sliding exit animations - directional exit effects */
|
|
119
|
+
slidingExits: (0, _propTypes.oneOf)(['', 'slideOutDown', 'slideOutLeft', 'slideOutRight', 'slideOutUp']),
|
|
120
|
+
// Accessibility props
|
|
121
|
+
/** Respect user's reduced motion preference for accessibility */
|
|
122
|
+
reduceMotion: _propTypes.bool,
|
|
123
|
+
// Legacy props (for backward compatibility - internal use only)
|
|
124
|
+
/** Base component name for CSS classes */
|
|
125
|
+
componentName: _propTypes.string,
|
|
126
|
+
/** Additional CSS class names to apply to the animation container */
|
|
127
|
+
additionalClassName: _propTypes.string
|
|
128
|
+
};
|
|
129
|
+
var _default = exports.default = AnimatedDiv;
|