@abstraks-dev/ui-library 2.3.0 → 2.4.0
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/README.md +46 -0
- package/dist/__tests__/Footer.test.js +3 -3
- package/dist/__tests__/Prompt.test.js +211 -0
- package/dist/index.js +8 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
Hero,
|
|
20
20
|
Alert,
|
|
21
21
|
Modal,
|
|
22
|
+
Prompt,
|
|
22
23
|
} from '@abstraks-dev/ui-library';
|
|
23
24
|
import '@abstraks-dev/ui-library/dist/styles/main.css';
|
|
24
25
|
|
|
@@ -232,6 +233,51 @@ Props:
|
|
|
232
233
|
- `showCloseButton` - Show X close button in header (default: `true`)
|
|
233
234
|
- `preventBodyScroll` - Lock body scroll when open (default: `true`)
|
|
234
235
|
|
|
236
|
+
#### Prompt
|
|
237
|
+
|
|
238
|
+
Lightweight confirmation dialog for user actions like deletes or destructive operations.
|
|
239
|
+
|
|
240
|
+
```jsx
|
|
241
|
+
import { useState } from 'react';
|
|
242
|
+
import { Prompt, Button } from '@abstraks-dev/ui-library';
|
|
243
|
+
|
|
244
|
+
function MyComponent() {
|
|
245
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
246
|
+
|
|
247
|
+
const handleDelete = () => {
|
|
248
|
+
// Perform delete action
|
|
249
|
+
console.log('Item deleted');
|
|
250
|
+
setIsOpen(false);
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
return (
|
|
254
|
+
<>
|
|
255
|
+
<Button variant='error' onClick={() => setIsOpen(true)}>
|
|
256
|
+
Delete Item
|
|
257
|
+
</Button>
|
|
258
|
+
<Prompt
|
|
259
|
+
message='Are you sure you want to delete this item? This action cannot be undone.'
|
|
260
|
+
open={isOpen}
|
|
261
|
+
onConfirm={handleDelete}
|
|
262
|
+
onCancel={() => setIsOpen(false)}
|
|
263
|
+
confirmText='Delete'
|
|
264
|
+
cancelText='Cancel'
|
|
265
|
+
/>
|
|
266
|
+
</>
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Props:
|
|
272
|
+
|
|
273
|
+
- `message` **(required)** - The confirmation message to display
|
|
274
|
+
- `open` - Controls prompt visibility (default: `false`)
|
|
275
|
+
- `onConfirm` - Callback when user clicks confirm button
|
|
276
|
+
- `onCancel` - Callback when user clicks cancel button
|
|
277
|
+
- `confirmText` - Text for confirm button (default: `'Yes'`)
|
|
278
|
+
- `cancelText` - Text for cancel button (default: `'Cancel'`)
|
|
279
|
+
- `showCancel` - Whether to show cancel button (default: `true`)
|
|
280
|
+
|
|
235
281
|
#### Error
|
|
236
282
|
|
|
237
283
|
Error message component.
|
|
@@ -35,7 +35,7 @@ describe('Footer', () => {
|
|
|
35
35
|
(0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Footer.default, {
|
|
36
36
|
hasAuth: false
|
|
37
37
|
}));
|
|
38
|
-
expect(_react2.screen.getByText(/©
|
|
38
|
+
expect(_react2.screen.getByText(/© 2026 Abstraks. All rights reserved./)).toBeInTheDocument();
|
|
39
39
|
});
|
|
40
40
|
it('renders auth menu when hasAuth is true on mobile', () => {
|
|
41
41
|
// Mock mobile screen size so auth menu shows
|
|
@@ -110,7 +110,7 @@ describe('Footer', () => {
|
|
|
110
110
|
hasAuth: true,
|
|
111
111
|
authMenu: /*#__PURE__*/_react.default.createElement("li", null, "Menu")
|
|
112
112
|
}));
|
|
113
|
-
expect(_react2.screen.queryByText(/©
|
|
113
|
+
expect(_react2.screen.queryByText(/© 2026 Abstraks. All rights reserved./)).not.toBeInTheDocument();
|
|
114
114
|
});
|
|
115
115
|
it('renders with copyright when hasAuth is true but navigation props are provided', () => {
|
|
116
116
|
// Mock desktop screen size to test desktop behavior with navigation props
|
|
@@ -122,7 +122,7 @@ describe('Footer', () => {
|
|
|
122
122
|
authMenu: /*#__PURE__*/_react.default.createElement("li", null, "Menu"),
|
|
123
123
|
navigationOne: /*#__PURE__*/_react.default.createElement("li", null, "Nav One")
|
|
124
124
|
}));
|
|
125
|
-
expect(_react2.screen.queryByText(/©
|
|
125
|
+
expect(_react2.screen.queryByText(/© 2026 Abstraks. All rights reserved./)).toBeInTheDocument();
|
|
126
126
|
});
|
|
127
127
|
it('renders with custom className', () => {
|
|
128
128
|
(0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Footer.default, {
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _react = _interopRequireDefault(require("react"));
|
|
4
|
+
var _react2 = require("@testing-library/react");
|
|
5
|
+
var _Prompt = require("../components/Prompt");
|
|
6
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
7
|
+
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); }
|
|
8
|
+
describe('Prompt Component', () => {
|
|
9
|
+
const defaultProps = {
|
|
10
|
+
message: 'Are you sure you want to proceed?',
|
|
11
|
+
onConfirm: jest.fn(),
|
|
12
|
+
onCancel: jest.fn(),
|
|
13
|
+
open: true
|
|
14
|
+
};
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
jest.clearAllMocks();
|
|
17
|
+
});
|
|
18
|
+
describe('Rendering', () => {
|
|
19
|
+
test('renders prompt when open is true', () => {
|
|
20
|
+
(0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Prompt.Prompt, defaultProps));
|
|
21
|
+
expect(_react2.screen.getByRole('dialog')).toBeInTheDocument();
|
|
22
|
+
expect(_react2.screen.getByText('Are you sure you want to proceed?')).toBeInTheDocument();
|
|
23
|
+
});
|
|
24
|
+
test('does not render when open is false', () => {
|
|
25
|
+
(0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Prompt.Prompt, _extends({}, defaultProps, {
|
|
26
|
+
open: false
|
|
27
|
+
})));
|
|
28
|
+
expect(_react2.screen.queryByRole('dialog')).not.toBeInTheDocument();
|
|
29
|
+
});
|
|
30
|
+
test('renders with default confirm button text', () => {
|
|
31
|
+
(0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Prompt.Prompt, defaultProps));
|
|
32
|
+
expect(_react2.screen.getByText('Yes')).toBeInTheDocument();
|
|
33
|
+
});
|
|
34
|
+
test('renders with custom confirm button text', () => {
|
|
35
|
+
(0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Prompt.Prompt, _extends({}, defaultProps, {
|
|
36
|
+
confirmText: "Delete"
|
|
37
|
+
})));
|
|
38
|
+
expect(_react2.screen.getByText('Delete')).toBeInTheDocument();
|
|
39
|
+
expect(_react2.screen.queryByText('Yes')).not.toBeInTheDocument();
|
|
40
|
+
});
|
|
41
|
+
test('renders with default cancel button text', () => {
|
|
42
|
+
(0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Prompt.Prompt, defaultProps));
|
|
43
|
+
expect(_react2.screen.getByText('Cancel')).toBeInTheDocument();
|
|
44
|
+
});
|
|
45
|
+
test('renders with custom cancel button text', () => {
|
|
46
|
+
(0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Prompt.Prompt, _extends({}, defaultProps, {
|
|
47
|
+
cancelText: "No"
|
|
48
|
+
})));
|
|
49
|
+
expect(_react2.screen.getByText('No')).toBeInTheDocument();
|
|
50
|
+
expect(_react2.screen.queryByText('Cancel')).not.toBeInTheDocument();
|
|
51
|
+
});
|
|
52
|
+
test('renders both confirm and cancel buttons by default', () => {
|
|
53
|
+
(0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Prompt.Prompt, defaultProps));
|
|
54
|
+
expect(_react2.screen.getByText('Yes')).toBeInTheDocument();
|
|
55
|
+
expect(_react2.screen.getByText('Cancel')).toBeInTheDocument();
|
|
56
|
+
});
|
|
57
|
+
test('hides cancel button when showCancel is false', () => {
|
|
58
|
+
(0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Prompt.Prompt, _extends({}, defaultProps, {
|
|
59
|
+
showCancel: false
|
|
60
|
+
})));
|
|
61
|
+
expect(_react2.screen.getByText('Yes')).toBeInTheDocument();
|
|
62
|
+
expect(_react2.screen.queryByText('Cancel')).not.toBeInTheDocument();
|
|
63
|
+
});
|
|
64
|
+
test('renders without confirm button if onConfirm is not provided', () => {
|
|
65
|
+
(0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Prompt.Prompt, {
|
|
66
|
+
message: "Information message",
|
|
67
|
+
onCancel: defaultProps.onCancel,
|
|
68
|
+
open: true
|
|
69
|
+
}));
|
|
70
|
+
expect(_react2.screen.queryByText('Yes')).not.toBeInTheDocument();
|
|
71
|
+
expect(_react2.screen.getByText('Cancel')).toBeInTheDocument();
|
|
72
|
+
});
|
|
73
|
+
test('has correct ARIA attributes', () => {
|
|
74
|
+
(0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Prompt.Prompt, defaultProps));
|
|
75
|
+
const dialog = _react2.screen.getByRole('dialog');
|
|
76
|
+
expect(dialog).toHaveAttribute('aria-modal', 'true');
|
|
77
|
+
expect(dialog).toHaveAttribute('aria-label', 'Are you sure you want to proceed?');
|
|
78
|
+
});
|
|
79
|
+
test('confirm button receives focus when rendered', () => {
|
|
80
|
+
(0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Prompt.Prompt, defaultProps));
|
|
81
|
+
const confirmButton = _react2.screen.getByText('Yes');
|
|
82
|
+
expect(confirmButton).toHaveFocus();
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
describe('User Interactions', () => {
|
|
86
|
+
test('calls onConfirm when confirm button is clicked', () => {
|
|
87
|
+
(0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Prompt.Prompt, defaultProps));
|
|
88
|
+
const confirmButton = _react2.screen.getByText('Yes');
|
|
89
|
+
_react2.fireEvent.click(confirmButton);
|
|
90
|
+
expect(defaultProps.onConfirm).toHaveBeenCalledTimes(1);
|
|
91
|
+
expect(defaultProps.onCancel).not.toHaveBeenCalled();
|
|
92
|
+
});
|
|
93
|
+
test('calls onCancel when cancel button is clicked', () => {
|
|
94
|
+
(0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Prompt.Prompt, defaultProps));
|
|
95
|
+
const cancelButton = _react2.screen.getByText('Cancel');
|
|
96
|
+
_react2.fireEvent.click(cancelButton);
|
|
97
|
+
expect(defaultProps.onCancel).toHaveBeenCalledTimes(1);
|
|
98
|
+
expect(defaultProps.onConfirm).not.toHaveBeenCalled();
|
|
99
|
+
});
|
|
100
|
+
test('does not call onConfirm if not provided', () => {
|
|
101
|
+
const mockOnCancel = jest.fn();
|
|
102
|
+
(0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Prompt.Prompt, {
|
|
103
|
+
message: "Test message",
|
|
104
|
+
onCancel: mockOnCancel,
|
|
105
|
+
open: true,
|
|
106
|
+
showCancel: true
|
|
107
|
+
}));
|
|
108
|
+
|
|
109
|
+
// Only cancel button should be present
|
|
110
|
+
expect(_react2.screen.queryByText('Yes')).not.toBeInTheDocument();
|
|
111
|
+
});
|
|
112
|
+
test('handles multiple clicks correctly', () => {
|
|
113
|
+
(0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Prompt.Prompt, defaultProps));
|
|
114
|
+
const confirmButton = _react2.screen.getByText('Yes');
|
|
115
|
+
_react2.fireEvent.click(confirmButton);
|
|
116
|
+
_react2.fireEvent.click(confirmButton);
|
|
117
|
+
expect(defaultProps.onConfirm).toHaveBeenCalledTimes(2);
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
describe('PropTypes Validation', () => {
|
|
121
|
+
test('renders with required props only', () => {
|
|
122
|
+
(0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Prompt.Prompt, {
|
|
123
|
+
message: "Required message",
|
|
124
|
+
open: true
|
|
125
|
+
}));
|
|
126
|
+
expect(_react2.screen.getByRole('dialog')).toBeInTheDocument();
|
|
127
|
+
expect(_react2.screen.getByText('Required message')).toBeInTheDocument();
|
|
128
|
+
});
|
|
129
|
+
test('renders with all optional props', () => {
|
|
130
|
+
(0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Prompt.Prompt, {
|
|
131
|
+
message: "All props message",
|
|
132
|
+
onConfirm: jest.fn(),
|
|
133
|
+
onCancel: jest.fn(),
|
|
134
|
+
confirmText: "Confirm",
|
|
135
|
+
cancelText: "Dismiss",
|
|
136
|
+
showCancel: true,
|
|
137
|
+
open: true
|
|
138
|
+
}));
|
|
139
|
+
expect(_react2.screen.getByText('All props message')).toBeInTheDocument();
|
|
140
|
+
expect(_react2.screen.getByText('Confirm')).toBeInTheDocument();
|
|
141
|
+
expect(_react2.screen.getByText('Dismiss')).toBeInTheDocument();
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
describe('CSS Classes', () => {
|
|
145
|
+
test('applies correct CSS classes', () => {
|
|
146
|
+
const {
|
|
147
|
+
container
|
|
148
|
+
} = (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Prompt.Prompt, defaultProps));
|
|
149
|
+
expect(container.querySelector('.prompt-overlay')).toBeInTheDocument();
|
|
150
|
+
expect(container.querySelector('.prompt-box')).toBeInTheDocument();
|
|
151
|
+
expect(container.querySelector('.prompt-actions')).toBeInTheDocument();
|
|
152
|
+
});
|
|
153
|
+
test('confirm button has correct class', () => {
|
|
154
|
+
(0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Prompt.Prompt, defaultProps));
|
|
155
|
+
const confirmButton = _react2.screen.getByText('Yes');
|
|
156
|
+
expect(confirmButton).toHaveClass('prompt-confirm');
|
|
157
|
+
});
|
|
158
|
+
test('cancel button has correct class', () => {
|
|
159
|
+
(0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Prompt.Prompt, defaultProps));
|
|
160
|
+
const cancelButton = _react2.screen.getByText('Cancel');
|
|
161
|
+
expect(cancelButton).toHaveClass('prompt-cancel');
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
describe('Edge Cases', () => {
|
|
165
|
+
test('renders with empty message string', () => {
|
|
166
|
+
(0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Prompt.Prompt, _extends({}, defaultProps, {
|
|
167
|
+
message: ""
|
|
168
|
+
})));
|
|
169
|
+
expect(_react2.screen.getByRole('dialog')).toBeInTheDocument();
|
|
170
|
+
});
|
|
171
|
+
test('renders with very long message', () => {
|
|
172
|
+
const longMessage = 'This is a very long message that might wrap to multiple lines in the prompt dialog and should still render correctly without breaking the layout or causing any issues';
|
|
173
|
+
(0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Prompt.Prompt, _extends({}, defaultProps, {
|
|
174
|
+
message: longMessage
|
|
175
|
+
})));
|
|
176
|
+
expect(_react2.screen.getByText(longMessage)).toBeInTheDocument();
|
|
177
|
+
});
|
|
178
|
+
test('renders when both onConfirm and onCancel are undefined', () => {
|
|
179
|
+
(0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Prompt.Prompt, {
|
|
180
|
+
message: "Message",
|
|
181
|
+
open: true
|
|
182
|
+
}));
|
|
183
|
+
expect(_react2.screen.getByRole('dialog')).toBeInTheDocument();
|
|
184
|
+
expect(_react2.screen.getByText('Message')).toBeInTheDocument();
|
|
185
|
+
});
|
|
186
|
+
test('transitions from closed to open', () => {
|
|
187
|
+
const {
|
|
188
|
+
rerender
|
|
189
|
+
} = (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Prompt.Prompt, _extends({}, defaultProps, {
|
|
190
|
+
open: false
|
|
191
|
+
})));
|
|
192
|
+
expect(_react2.screen.queryByRole('dialog')).not.toBeInTheDocument();
|
|
193
|
+
rerender(/*#__PURE__*/_react.default.createElement(_Prompt.Prompt, _extends({}, defaultProps, {
|
|
194
|
+
open: true
|
|
195
|
+
})));
|
|
196
|
+
expect(_react2.screen.getByRole('dialog')).toBeInTheDocument();
|
|
197
|
+
});
|
|
198
|
+
test('transitions from open to closed', () => {
|
|
199
|
+
const {
|
|
200
|
+
rerender
|
|
201
|
+
} = (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Prompt.Prompt, _extends({}, defaultProps, {
|
|
202
|
+
open: true
|
|
203
|
+
})));
|
|
204
|
+
expect(_react2.screen.getByRole('dialog')).toBeInTheDocument();
|
|
205
|
+
rerender(/*#__PURE__*/_react.default.createElement(_Prompt.Prompt, _extends({}, defaultProps, {
|
|
206
|
+
open: false
|
|
207
|
+
})));
|
|
208
|
+
expect(_react2.screen.queryByRole('dialog')).not.toBeInTheDocument();
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
});
|
package/dist/index.js
CHANGED
|
@@ -26,6 +26,7 @@ var _exportNames = {
|
|
|
26
26
|
Loader: true,
|
|
27
27
|
Modal: true,
|
|
28
28
|
Paragraph: true,
|
|
29
|
+
Prompt: true,
|
|
29
30
|
Radio: true,
|
|
30
31
|
Search: true,
|
|
31
32
|
Select: true,
|
|
@@ -380,6 +381,12 @@ Object.defineProperty(exports, "PlusCircle", {
|
|
|
380
381
|
return _PlusCircle.PlusCircle;
|
|
381
382
|
}
|
|
382
383
|
});
|
|
384
|
+
Object.defineProperty(exports, "Prompt", {
|
|
385
|
+
enumerable: true,
|
|
386
|
+
get: function () {
|
|
387
|
+
return _Prompt.default;
|
|
388
|
+
}
|
|
389
|
+
});
|
|
383
390
|
Object.defineProperty(exports, "Radio", {
|
|
384
391
|
enumerable: true,
|
|
385
392
|
get: function () {
|
|
@@ -492,6 +499,7 @@ var _Label = _interopRequireDefault(require("./components/Label"));
|
|
|
492
499
|
var _Loader = _interopRequireDefault(require("./components/Loader"));
|
|
493
500
|
var _Modal = _interopRequireDefault(require("./components/Modal"));
|
|
494
501
|
var _Paragraph = _interopRequireDefault(require("./components/Paragraph"));
|
|
502
|
+
var _Prompt = _interopRequireDefault(require("./components/Prompt"));
|
|
495
503
|
var _Radio = require("./components/Radio");
|
|
496
504
|
var _Search = require("./components/Search");
|
|
497
505
|
var _Select = require("./components/Select");
|