@simplysm/solid 13.0.70 → 13.0.72
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 +1 -1
- package/dist/components/data/sheet/DataSheet.d.ts.map +1 -1
- package/dist/components/data/sheet/DataSheet.js +3 -6
- package/dist/components/data/sheet/DataSheet.js.map +1 -1
- package/dist/components/data/sheet/DataSheet.styles.d.ts.map +1 -1
- package/dist/components/data/sheet/DataSheet.styles.js +1 -1
- package/dist/components/data/sheet/DataSheet.styles.js.map +1 -1
- package/dist/components/disclosure/Dropdown.d.ts +6 -4
- package/dist/components/disclosure/Dropdown.d.ts.map +1 -1
- package/dist/components/disclosure/Dropdown.js +24 -8
- package/dist/components/disclosure/Dropdown.js.map +2 -2
- package/dist/components/disclosure/dialogZIndex.d.ts +2 -0
- package/dist/components/disclosure/dialogZIndex.d.ts.map +1 -1
- package/dist/components/disclosure/dialogZIndex.js +4 -0
- package/dist/components/disclosure/dialogZIndex.js.map +1 -1
- package/dist/components/features/crud-detail/CrudDetail.d.ts.map +1 -1
- package/dist/components/features/crud-detail/CrudDetail.js +16 -7
- package/dist/components/features/crud-detail/CrudDetail.js.map +2 -2
- package/dist/components/features/crud-sheet/CrudSheet.d.ts.map +1 -1
- package/dist/components/features/crud-sheet/CrudSheet.js +14 -5
- package/dist/components/features/crud-sheet/CrudSheet.js.map +2 -2
- package/dist/components/features/crudRegistry.d.ts +16 -0
- package/dist/components/features/crudRegistry.d.ts.map +1 -0
- package/dist/components/features/crudRegistry.js +37 -0
- package/dist/components/features/crudRegistry.js.map +6 -0
- package/dist/components/features/permission-table/PermissionTable.d.ts.map +1 -1
- package/dist/components/features/permission-table/PermissionTable.js +71 -86
- package/dist/components/features/permission-table/PermissionTable.js.map +2 -2
- package/dist/components/features/shared-data/SharedDataSelect.js +2 -4
- package/dist/components/features/shared-data/SharedDataSelect.js.map +2 -2
- package/dist/components/features/shared-data/SharedDataSelectList.d.ts +2 -4
- package/dist/components/features/shared-data/SharedDataSelectList.d.ts.map +1 -1
- package/dist/components/features/shared-data/SharedDataSelectList.js +11 -46
- package/dist/components/features/shared-data/SharedDataSelectList.js.map +2 -2
- package/dist/components/form-control/select/Select.d.ts.map +1 -1
- package/dist/components/form-control/select/Select.js +1 -1
- package/dist/components/form-control/select/Select.js.map +1 -1
- package/dist/helpers/createAppStructure.d.ts.map +1 -1
- package/dist/helpers/createAppStructure.js +3 -2
- package/dist/helpers/createAppStructure.js.map +1 -1
- package/dist/helpers/createHmrSafeContext.d.ts +3 -0
- package/dist/helpers/createHmrSafeContext.d.ts.map +1 -0
- package/dist/helpers/createHmrSafeContext.js +10 -0
- package/dist/helpers/createHmrSafeContext.js.map +6 -0
- package/dist/hooks/createSelectionGroup.d.ts.map +1 -1
- package/dist/hooks/createSelectionGroup.js +3 -2
- package/dist/hooks/createSelectionGroup.js.map +2 -2
- package/package.json +6 -5
- package/src/components/data/sheet/DataSheet.styles.ts +1 -1
- package/src/components/data/sheet/DataSheet.tsx +3 -4
- package/src/components/disclosure/Dropdown.tsx +31 -17
- package/src/components/disclosure/dialogZIndex.ts +5 -0
- package/src/components/features/crud-detail/CrudDetail.tsx +16 -5
- package/src/components/features/crud-sheet/CrudSheet.tsx +13 -3
- package/src/components/features/crudRegistry.ts +60 -0
- package/src/components/features/permission-table/PermissionTable.tsx +49 -46
- package/src/components/features/shared-data/SharedDataSelect.tsx +2 -2
- package/src/components/features/shared-data/SharedDataSelectList.tsx +11 -36
- package/src/components/form-control/select/Select.tsx +1 -5
- package/src/helpers/createAppStructure.ts +3 -2
- package/src/helpers/createHmrSafeContext.ts +8 -0
- package/src/hooks/createSelectionGroup.tsx +4 -2
- package/tests/components/data/List.spec.tsx +52 -52
- package/tests/components/data/Pagination.spec.tsx +43 -43
- package/tests/components/data/Table.spec.tsx +4 -4
- package/tests/components/data/kanban/Kanban.selection.spec.tsx +21 -21
- package/tests/components/data/sheet/DataSheet.spec.tsx +50 -50
- package/tests/components/disclosure/Collapse.spec.tsx +24 -24
- package/tests/components/disclosure/Dialog.spec.tsx +33 -33
- package/tests/components/disclosure/DialogProvider.spec.tsx +9 -9
- package/tests/components/disclosure/Dropdown.spec.tsx +134 -14
- package/tests/components/disclosure/Tabs.spec.tsx +21 -21
- package/tests/components/disclosure/dialogZIndex.spec.ts +45 -0
- package/tests/components/display/Alert.spec.tsx +4 -4
- package/tests/components/display/Barcode.spec.tsx +7 -7
- package/tests/components/display/Card.spec.tsx +3 -3
- package/tests/components/display/Link.spec.tsx +5 -5
- package/tests/components/display/Tag.spec.tsx +4 -4
- package/tests/components/features/address/AddressSearch.spec.tsx +3 -3
- package/tests/components/features/crudRegistry.spec.ts +119 -0
- package/tests/components/features/data-select-button/DataSelectButton.spec.tsx +8 -8
- package/tests/components/features/permission-table/PermissionTable.spec.tsx +43 -43
- package/tests/components/features/shared-data/SharedDataSelectList.spec.tsx +2 -17
- package/tests/components/feedback/busy/BusyContainer.spec.tsx +7 -7
- package/tests/components/feedback/notification/NotificationBell.spec.tsx +9 -9
- package/tests/components/feedback/print/Print.spec.tsx +4 -4
- package/tests/components/form-control/Button.spec.tsx +18 -18
- package/tests/components/form-control/checkbox/Checkbox.spec.tsx +20 -20
- package/tests/components/form-control/checkbox/CheckboxGroup.spec.tsx +12 -12
- package/tests/components/form-control/checkbox/Radio.spec.tsx +21 -21
- package/tests/components/form-control/checkbox/RadioGroup.spec.tsx +12 -12
- package/tests/components/form-control/color-picker/ColorPicker.spec.tsx +10 -10
- package/tests/components/form-control/combobox/Combobox.spec.tsx +16 -16
- package/tests/components/form-control/combobox/ComboboxItem.spec.tsx +7 -7
- package/tests/components/form-control/date-range-picker/DateRangePicker.spec.tsx +24 -24
- package/tests/components/form-control/field/DatePicker.spec.tsx +50 -50
- package/tests/components/form-control/field/DateTimePicker.spec.tsx +47 -47
- package/tests/components/form-control/field/NumberInput.spec.tsx +54 -54
- package/tests/components/form-control/field/TextInput.spec.tsx +49 -49
- package/tests/components/form-control/field/Textarea.spec.tsx +33 -33
- package/tests/components/form-control/field/TimePicker.spec.tsx +42 -42
- package/tests/components/form-control/numpad/Numpad.spec.tsx +40 -40
- package/tests/components/form-control/select/Select.spec.tsx +9 -9
- package/tests/components/form-control/select/SelectItem.spec.tsx +10 -10
- package/tests/helpers/createAppStructure.spec.tsx +57 -57
- package/tests/helpers/mergeStyles.spec.ts +31 -31
|
@@ -4,9 +4,9 @@ import { createSignal } from "solid-js";
|
|
|
4
4
|
import { IconCheck } from "@tabler/icons-solidjs";
|
|
5
5
|
import { List } from "../../../src/components/data/list/List";
|
|
6
6
|
|
|
7
|
-
describe("List
|
|
7
|
+
describe("List component", () => {
|
|
8
8
|
describe("basic rendering", () => {
|
|
9
|
-
it("children
|
|
9
|
+
it("renders children inside List", () => {
|
|
10
10
|
const { getByText } = render(() => (
|
|
11
11
|
<List>
|
|
12
12
|
<List.Item>Item 1</List.Item>
|
|
@@ -16,7 +16,7 @@ describe("List 컴포넌트", () => {
|
|
|
16
16
|
expect(getByText("Item 1")).toBeTruthy();
|
|
17
17
|
});
|
|
18
18
|
|
|
19
|
-
it("role=tree
|
|
19
|
+
it("applies role=tree", () => {
|
|
20
20
|
const { getByRole } = render(() => (
|
|
21
21
|
<List>
|
|
22
22
|
<List.Item>Item</List.Item>
|
|
@@ -26,7 +26,7 @@ describe("List 컴포넌트", () => {
|
|
|
26
26
|
expect(getByRole("tree")).toBeTruthy();
|
|
27
27
|
});
|
|
28
28
|
|
|
29
|
-
it("data-list
|
|
29
|
+
it("applies data-list attribute", () => {
|
|
30
30
|
const { container } = render(() => (
|
|
31
31
|
<List>
|
|
32
32
|
<List.Item>Item</List.Item>
|
|
@@ -37,8 +37,8 @@ describe("List 컴포넌트", () => {
|
|
|
37
37
|
});
|
|
38
38
|
});
|
|
39
39
|
|
|
40
|
-
describe("inset
|
|
41
|
-
it("
|
|
40
|
+
describe("inset prop", () => {
|
|
41
|
+
it("applies different styles based on inset prop", () => {
|
|
42
42
|
const { container: defaultContainer } = render(() => (
|
|
43
43
|
<List>
|
|
44
44
|
<List.Item>Item</List.Item>
|
|
@@ -57,8 +57,8 @@ describe("List 컴포넌트", () => {
|
|
|
57
57
|
});
|
|
58
58
|
});
|
|
59
59
|
|
|
60
|
-
describe("
|
|
61
|
-
it("ArrowDown
|
|
60
|
+
describe("keyboard navigation", () => {
|
|
61
|
+
it("ArrowDown moves focus to next item", () => {
|
|
62
62
|
const { getAllByRole } = render(() => (
|
|
63
63
|
<List>
|
|
64
64
|
<List.Item>Item 1</List.Item>
|
|
@@ -75,7 +75,7 @@ describe("List 컴포넌트", () => {
|
|
|
75
75
|
expect(document.activeElement).toBe(items[1]);
|
|
76
76
|
});
|
|
77
77
|
|
|
78
|
-
it("ArrowUp
|
|
78
|
+
it("ArrowUp moves focus to previous item", () => {
|
|
79
79
|
const { getAllByRole } = render(() => (
|
|
80
80
|
<List>
|
|
81
81
|
<List.Item>Item 1</List.Item>
|
|
@@ -92,7 +92,7 @@ describe("List 컴포넌트", () => {
|
|
|
92
92
|
expect(document.activeElement).toBe(items[0]);
|
|
93
93
|
});
|
|
94
94
|
|
|
95
|
-
it("Home
|
|
95
|
+
it("Home moves focus to first item", () => {
|
|
96
96
|
const { getAllByRole } = render(() => (
|
|
97
97
|
<List>
|
|
98
98
|
<List.Item>Item 1</List.Item>
|
|
@@ -109,7 +109,7 @@ describe("List 컴포넌트", () => {
|
|
|
109
109
|
expect(document.activeElement).toBe(items[0]);
|
|
110
110
|
});
|
|
111
111
|
|
|
112
|
-
it("End
|
|
112
|
+
it("End moves focus to last item", () => {
|
|
113
113
|
const { getAllByRole } = render(() => (
|
|
114
114
|
<List>
|
|
115
115
|
<List.Item>Item 1</List.Item>
|
|
@@ -126,7 +126,7 @@ describe("List 컴포넌트", () => {
|
|
|
126
126
|
expect(document.activeElement).toBe(items[2]);
|
|
127
127
|
});
|
|
128
128
|
|
|
129
|
-
it("Space
|
|
129
|
+
it("Space toggles item", () => {
|
|
130
130
|
const { getAllByRole } = render(() => (
|
|
131
131
|
<List>
|
|
132
132
|
<List.Item>
|
|
@@ -148,7 +148,7 @@ describe("List 컴포넌트", () => {
|
|
|
148
148
|
expect(items[0].getAttribute("aria-expanded")).toBe("true");
|
|
149
149
|
});
|
|
150
150
|
|
|
151
|
-
it("Enter
|
|
151
|
+
it("Enter toggles item", () => {
|
|
152
152
|
const { getAllByRole } = render(() => (
|
|
153
153
|
<List>
|
|
154
154
|
<List.Item>
|
|
@@ -168,7 +168,7 @@ describe("List 컴포넌트", () => {
|
|
|
168
168
|
expect(items[0].getAttribute("aria-expanded")).toBe("true");
|
|
169
169
|
});
|
|
170
170
|
|
|
171
|
-
it("ArrowRight
|
|
171
|
+
it("ArrowRight opens a closed item", () => {
|
|
172
172
|
const { getAllByRole } = render(() => (
|
|
173
173
|
<List>
|
|
174
174
|
<List.Item>
|
|
@@ -190,7 +190,7 @@ describe("List 컴포넌트", () => {
|
|
|
190
190
|
expect(items[0].getAttribute("aria-expanded")).toBe("true");
|
|
191
191
|
});
|
|
192
192
|
|
|
193
|
-
it("ArrowRight
|
|
193
|
+
it("ArrowRight moves focus to first child when item is open", () => {
|
|
194
194
|
const { getAllByRole } = render(() => (
|
|
195
195
|
<List>
|
|
196
196
|
<List.Item open>
|
|
@@ -210,7 +210,7 @@ describe("List 컴포넌트", () => {
|
|
|
210
210
|
expect(document.activeElement).toBe(items[1]);
|
|
211
211
|
});
|
|
212
212
|
|
|
213
|
-
it("ArrowLeft
|
|
213
|
+
it("ArrowLeft closes an open item", () => {
|
|
214
214
|
const { getAllByRole } = render(() => (
|
|
215
215
|
<List>
|
|
216
216
|
<List.Item open>
|
|
@@ -232,7 +232,7 @@ describe("List 컴포넌트", () => {
|
|
|
232
232
|
expect(items[0].getAttribute("aria-expanded")).toBe("false");
|
|
233
233
|
});
|
|
234
234
|
|
|
235
|
-
it("ArrowLeft
|
|
235
|
+
it("ArrowLeft moves focus to parent from a closed item", () => {
|
|
236
236
|
const { getAllByRole } = render(() => (
|
|
237
237
|
<List>
|
|
238
238
|
<List.Item open>
|
|
@@ -254,9 +254,9 @@ describe("List 컴포넌트", () => {
|
|
|
254
254
|
});
|
|
255
255
|
});
|
|
256
256
|
|
|
257
|
-
describe("List.Item
|
|
257
|
+
describe("List.Item component", () => {
|
|
258
258
|
describe("basic rendering", () => {
|
|
259
|
-
it("children
|
|
259
|
+
it("renders children inside List.Item", () => {
|
|
260
260
|
const { getByText } = render(() => (
|
|
261
261
|
<List>
|
|
262
262
|
<List.Item>Test Item</List.Item>
|
|
@@ -266,7 +266,7 @@ describe("List.Item 컴포넌트", () => {
|
|
|
266
266
|
expect(getByText("Test Item")).toBeTruthy();
|
|
267
267
|
});
|
|
268
268
|
|
|
269
|
-
it("role=treeitem
|
|
269
|
+
it("applies role=treeitem", () => {
|
|
270
270
|
const { getByRole } = render(() => (
|
|
271
271
|
<List>
|
|
272
272
|
<List.Item>Item</List.Item>
|
|
@@ -276,7 +276,7 @@ describe("List.Item 컴포넌트", () => {
|
|
|
276
276
|
expect(getByRole("treeitem")).toBeTruthy();
|
|
277
277
|
});
|
|
278
278
|
|
|
279
|
-
it("data-list-item
|
|
279
|
+
it("applies data-list-item attribute", () => {
|
|
280
280
|
const { container } = render(() => (
|
|
281
281
|
<List>
|
|
282
282
|
<List.Item>Item</List.Item>
|
|
@@ -287,8 +287,8 @@ describe("List.Item 컴포넌트", () => {
|
|
|
287
287
|
});
|
|
288
288
|
});
|
|
289
289
|
|
|
290
|
-
describe("
|
|
291
|
-
it("List.Item.Children
|
|
290
|
+
describe("nested list", () => {
|
|
291
|
+
it("toggles collapse on click when List.Item.Children is present", () => {
|
|
292
292
|
const { getByRole } = render(() => (
|
|
293
293
|
<List>
|
|
294
294
|
<List.Item>
|
|
@@ -313,7 +313,7 @@ describe("List.Item 컴포넌트", () => {
|
|
|
313
313
|
expect(item.getAttribute("aria-expanded")).toBe("false");
|
|
314
314
|
});
|
|
315
315
|
|
|
316
|
-
it("List.Item.Children
|
|
316
|
+
it("shows chevron icon when List.Item.Children is present", () => {
|
|
317
317
|
const { container } = render(() => (
|
|
318
318
|
<List>
|
|
319
319
|
<List.Item>
|
|
@@ -329,7 +329,7 @@ describe("List.Item 컴포넌트", () => {
|
|
|
329
329
|
expect(svg).toBeTruthy();
|
|
330
330
|
});
|
|
331
331
|
|
|
332
|
-
it("List.Item.Children
|
|
332
|
+
it("hides chevron icon when List.Item.Children is absent", () => {
|
|
333
333
|
const { container } = render(() => (
|
|
334
334
|
<List>
|
|
335
335
|
<List.Item>Simple Item</List.Item>
|
|
@@ -341,7 +341,7 @@ describe("List.Item 컴포넌트", () => {
|
|
|
341
341
|
expect(svg).toBeFalsy();
|
|
342
342
|
});
|
|
343
343
|
|
|
344
|
-
it("aria-expanded
|
|
344
|
+
it("no aria-expanded means no List.Item.Children", () => {
|
|
345
345
|
const { getByRole } = render(() => (
|
|
346
346
|
<List>
|
|
347
347
|
<List.Item>Simple Item</List.Item>
|
|
@@ -352,7 +352,7 @@ describe("List.Item 컴포넌트", () => {
|
|
|
352
352
|
expect(item.hasAttribute("aria-expanded")).toBe(false);
|
|
353
353
|
});
|
|
354
354
|
|
|
355
|
-
it("List.Item.Children
|
|
355
|
+
it("applies role=group inside List.Item.Children", () => {
|
|
356
356
|
const { getByRole } = render(() => (
|
|
357
357
|
<List>
|
|
358
358
|
<List.Item open>
|
|
@@ -368,8 +368,8 @@ describe("List.Item 컴포넌트", () => {
|
|
|
368
368
|
});
|
|
369
369
|
});
|
|
370
370
|
|
|
371
|
-
describe("selected
|
|
372
|
-
it("
|
|
371
|
+
describe("selected state", () => {
|
|
372
|
+
it("applies different styles based on selected prop", () => {
|
|
373
373
|
const { container: defaultContainer } = render(() => (
|
|
374
374
|
<List>
|
|
375
375
|
<List.Item>Item</List.Item>
|
|
@@ -389,7 +389,7 @@ describe("List.Item 컴포넌트", () => {
|
|
|
389
389
|
expect(defaultClass).not.toBe(selectedClass);
|
|
390
390
|
});
|
|
391
391
|
|
|
392
|
-
it("aria-selected
|
|
392
|
+
it("sets aria-selected", () => {
|
|
393
393
|
const { getByRole } = render(() => (
|
|
394
394
|
<List>
|
|
395
395
|
<List.Item selected>Selected Item</List.Item>
|
|
@@ -401,8 +401,8 @@ describe("List.Item 컴포넌트", () => {
|
|
|
401
401
|
});
|
|
402
402
|
});
|
|
403
403
|
|
|
404
|
-
describe("readonly
|
|
405
|
-
it("
|
|
404
|
+
describe("readonly state", () => {
|
|
405
|
+
it("does not call onClick when readonly=true", () => {
|
|
406
406
|
const onClick = vi.fn();
|
|
407
407
|
const { getByRole } = render(() => (
|
|
408
408
|
<List>
|
|
@@ -418,7 +418,7 @@ describe("List.Item 컴포넌트", () => {
|
|
|
418
418
|
expect(onClick).not.toHaveBeenCalled();
|
|
419
419
|
});
|
|
420
420
|
|
|
421
|
-
it("
|
|
421
|
+
it("applies different styles based on readonly prop", () => {
|
|
422
422
|
const { container: defaultContainer } = render(() => (
|
|
423
423
|
<List>
|
|
424
424
|
<List.Item>Item</List.Item>
|
|
@@ -440,7 +440,7 @@ describe("List.Item 컴포넌트", () => {
|
|
|
440
440
|
});
|
|
441
441
|
|
|
442
442
|
describe("disabled state", () => {
|
|
443
|
-
it("
|
|
443
|
+
it("applies different styles based on disabled prop", () => {
|
|
444
444
|
const { container: defaultContainer } = render(() => (
|
|
445
445
|
<List>
|
|
446
446
|
<List.Item>Item</List.Item>
|
|
@@ -460,7 +460,7 @@ describe("List.Item 컴포넌트", () => {
|
|
|
460
460
|
expect(defaultClass).not.toBe(disabledClass);
|
|
461
461
|
});
|
|
462
462
|
|
|
463
|
-
it("disabled=true
|
|
463
|
+
it("not clickable when disabled=true", () => {
|
|
464
464
|
const onClick = vi.fn();
|
|
465
465
|
const { getByRole } = render(() => (
|
|
466
466
|
<List>
|
|
@@ -476,7 +476,7 @@ describe("List.Item 컴포넌트", () => {
|
|
|
476
476
|
expect(onClick).not.toHaveBeenCalled();
|
|
477
477
|
});
|
|
478
478
|
|
|
479
|
-
it("
|
|
479
|
+
it("applies tabindex=-1 when disabled=true", () => {
|
|
480
480
|
const { getByRole } = render(() => (
|
|
481
481
|
<List>
|
|
482
482
|
<List.Item disabled>Disabled Item</List.Item>
|
|
@@ -487,7 +487,7 @@ describe("List.Item 컴포넌트", () => {
|
|
|
487
487
|
expect(item.getAttribute("tabindex")).toBe("-1");
|
|
488
488
|
});
|
|
489
489
|
|
|
490
|
-
it("aria-disabled
|
|
490
|
+
it("sets aria-disabled", () => {
|
|
491
491
|
const { getByRole } = render(() => (
|
|
492
492
|
<List>
|
|
493
493
|
<List.Item disabled>Disabled Item</List.Item>
|
|
@@ -500,7 +500,7 @@ describe("List.Item 컴포넌트", () => {
|
|
|
500
500
|
});
|
|
501
501
|
|
|
502
502
|
describe("selectedIcon", () => {
|
|
503
|
-
it("selectedIcon
|
|
503
|
+
it("shows icon when selectedIcon is provided and no List.Item.Children", () => {
|
|
504
504
|
const { container } = render(() => (
|
|
505
505
|
<List>
|
|
506
506
|
<List.Item selectedIcon={IconCheck}>Item</List.Item>
|
|
@@ -511,7 +511,7 @@ describe("List.Item 컴포넌트", () => {
|
|
|
511
511
|
expect(svg).toBeTruthy();
|
|
512
512
|
});
|
|
513
513
|
|
|
514
|
-
it("
|
|
514
|
+
it("applies different icon styles based on selectedIcon and selected state", () => {
|
|
515
515
|
const { container: unselectedContainer } = render(() => (
|
|
516
516
|
<List>
|
|
517
517
|
<List.Item selectedIcon={IconCheck}>Item</List.Item>
|
|
@@ -531,7 +531,7 @@ describe("List.Item 컴포넌트", () => {
|
|
|
531
531
|
expect(unselectedSvg?.className).not.toBe(selectedSvg?.className);
|
|
532
532
|
});
|
|
533
533
|
|
|
534
|
-
it("selectedIcon
|
|
534
|
+
it("hides selectedIcon when List.Item.Children is present", () => {
|
|
535
535
|
const { container } = render(() => (
|
|
536
536
|
<List>
|
|
537
537
|
<List.Item selectedIcon={IconCheck}>
|
|
@@ -546,13 +546,13 @@ describe("List.Item 컴포넌트", () => {
|
|
|
546
546
|
const button = container.querySelector("[data-list-item]") as HTMLElement;
|
|
547
547
|
const svgs = button.querySelectorAll("svg");
|
|
548
548
|
|
|
549
|
-
// chevron
|
|
549
|
+
// only chevron should be present (selectedIcon is hidden)
|
|
550
550
|
expect(svgs.length).toBe(1);
|
|
551
551
|
});
|
|
552
552
|
});
|
|
553
553
|
|
|
554
554
|
describe("onClick", () => {
|
|
555
|
-
it("
|
|
555
|
+
it("calls onClick on click when no List.Item.Children", () => {
|
|
556
556
|
const onClick = vi.fn();
|
|
557
557
|
const { getByRole } = render(() => (
|
|
558
558
|
<List>
|
|
@@ -566,7 +566,7 @@ describe("List.Item 컴포넌트", () => {
|
|
|
566
566
|
expect(onClick).toHaveBeenCalledTimes(1);
|
|
567
567
|
});
|
|
568
568
|
|
|
569
|
-
it("
|
|
569
|
+
it("toggles collapse instead of onClick when List.Item.Children is present", () => {
|
|
570
570
|
const onClick = vi.fn();
|
|
571
571
|
const { getByRole } = render(() => (
|
|
572
572
|
<List>
|
|
@@ -587,8 +587,8 @@ describe("List.Item 컴포넌트", () => {
|
|
|
587
587
|
});
|
|
588
588
|
});
|
|
589
589
|
|
|
590
|
-
describe("controlled
|
|
591
|
-
it("open
|
|
590
|
+
describe("controlled mode", () => {
|
|
591
|
+
it("operates in controlled mode when open and onOpenChange are provided", () => {
|
|
592
592
|
const onOpenChange = vi.fn();
|
|
593
593
|
|
|
594
594
|
const { getByRole } = render(() => (
|
|
@@ -606,11 +606,11 @@ describe("List.Item 컴포넌트", () => {
|
|
|
606
606
|
fireEvent.click(item);
|
|
607
607
|
|
|
608
608
|
expect(onOpenChange).toHaveBeenCalledWith(true);
|
|
609
|
-
// controlled
|
|
609
|
+
// controlled mode: actual state does not change
|
|
610
610
|
expect(item.getAttribute("aria-expanded")).toBe("false");
|
|
611
611
|
});
|
|
612
612
|
|
|
613
|
-
it("
|
|
613
|
+
it("reflects state change when open prop changes", () => {
|
|
614
614
|
const [open, setOpen] = createSignal(false);
|
|
615
615
|
|
|
616
616
|
const { getByRole } = render(() => (
|
|
@@ -635,7 +635,7 @@ describe("List.Item 컴포넌트", () => {
|
|
|
635
635
|
});
|
|
636
636
|
|
|
637
637
|
describe("aria-level", () => {
|
|
638
|
-
it("aria-level
|
|
638
|
+
it("sets aria-level based on nesting depth", () => {
|
|
639
639
|
const { getAllByRole } = render(() => (
|
|
640
640
|
<List>
|
|
641
641
|
<List.Item open>
|
|
@@ -661,7 +661,7 @@ describe("List.Item 컴포넌트", () => {
|
|
|
661
661
|
});
|
|
662
662
|
|
|
663
663
|
describe("Roving tabindex", () => {
|
|
664
|
-
it("
|
|
664
|
+
it("only focused item gets tabindex=0", () => {
|
|
665
665
|
const { getAllByRole } = render(() => (
|
|
666
666
|
<List>
|
|
667
667
|
<List.Item>Item 1</List.Item>
|
|
@@ -672,15 +672,15 @@ describe("List.Item 컴포넌트", () => {
|
|
|
672
672
|
|
|
673
673
|
const items = getAllByRole("treeitem");
|
|
674
674
|
|
|
675
|
-
//
|
|
675
|
+
// initial state: all items have tabindex=0
|
|
676
676
|
items.forEach((item) => {
|
|
677
677
|
expect(item.getAttribute("tabindex")).toBe("0");
|
|
678
678
|
});
|
|
679
679
|
|
|
680
|
-
//
|
|
680
|
+
// focus second item
|
|
681
681
|
fireEvent.focus(items[1]);
|
|
682
682
|
|
|
683
|
-
//
|
|
683
|
+
// only focused item has tabindex=0, others are -1
|
|
684
684
|
expect(items[0].getAttribute("tabindex")).toBe("-1");
|
|
685
685
|
expect(items[1].getAttribute("tabindex")).toBe("0");
|
|
686
686
|
expect(items[2].getAttribute("tabindex")).toBe("-1");
|
|
@@ -3,21 +3,21 @@ import { describe, it, expect, vi } from "vitest";
|
|
|
3
3
|
import { createSignal } from "solid-js";
|
|
4
4
|
import { Pagination } from "../../../src/components/data/Pagination";
|
|
5
5
|
|
|
6
|
-
describe("Pagination
|
|
6
|
+
describe("Pagination component", () => {
|
|
7
7
|
describe("basic rendering", () => {
|
|
8
|
-
it("nav
|
|
8
|
+
it("renders as nav element", () => {
|
|
9
9
|
const { container } = render(() => <Pagination page={1} totalPageCount={5} />);
|
|
10
10
|
|
|
11
11
|
expect(container.querySelector("nav")).toBeTruthy();
|
|
12
12
|
});
|
|
13
13
|
|
|
14
|
-
it("data-pagination
|
|
14
|
+
it("applies data-pagination attribute", () => {
|
|
15
15
|
const { container } = render(() => <Pagination page={1} totalPageCount={5} />);
|
|
16
16
|
|
|
17
17
|
expect(container.querySelector("[data-pagination]")).toBeTruthy();
|
|
18
18
|
});
|
|
19
19
|
|
|
20
|
-
it("4
|
|
20
|
+
it("renders 4 navigation buttons and page buttons", () => {
|
|
21
21
|
const { container } = render(() => <Pagination page={1} totalPageCount={5} />);
|
|
22
22
|
|
|
23
23
|
const buttons = container.querySelectorAll("[data-button]");
|
|
@@ -25,7 +25,7 @@ describe("Pagination 컴포넌트", () => {
|
|
|
25
25
|
expect(buttons.length).toBe(9);
|
|
26
26
|
});
|
|
27
27
|
|
|
28
|
-
it("
|
|
28
|
+
it("displays page numbers as 1-based", () => {
|
|
29
29
|
const { getByText } = render(() => <Pagination page={1} totalPageCount={3} />);
|
|
30
30
|
|
|
31
31
|
expect(getByText("1")).toBeTruthy();
|
|
@@ -33,7 +33,7 @@ describe("Pagination 컴포넌트", () => {
|
|
|
33
33
|
expect(getByText("3")).toBeTruthy();
|
|
34
34
|
});
|
|
35
35
|
|
|
36
|
-
it("custom class
|
|
36
|
+
it("passes custom class to nav element", () => {
|
|
37
37
|
const { container } = render(() => (
|
|
38
38
|
// eslint-disable-next-line tailwindcss/no-custom-classname
|
|
39
39
|
<Pagination page={1} totalPageCount={5} class="my-custom" />
|
|
@@ -44,8 +44,8 @@ describe("Pagination 컴포넌트", () => {
|
|
|
44
44
|
});
|
|
45
45
|
});
|
|
46
46
|
|
|
47
|
-
describe("displayPageCount
|
|
48
|
-
it("displayPageCount
|
|
47
|
+
describe("displayPageCount default", () => {
|
|
48
|
+
it("default displayPageCount is 10", () => {
|
|
49
49
|
const { container } = render(() => <Pagination page={1} totalPageCount={25} />);
|
|
50
50
|
|
|
51
51
|
const buttons = container.querySelectorAll("[data-button]");
|
|
@@ -53,7 +53,7 @@ describe("Pagination 컴포넌트", () => {
|
|
|
53
53
|
expect(buttons.length).toBe(14);
|
|
54
54
|
});
|
|
55
55
|
|
|
56
|
-
it("
|
|
56
|
+
it("displays 5 page buttons when displayPageCount=5", () => {
|
|
57
57
|
const { container } = render(() => (
|
|
58
58
|
<Pagination page={1} totalPageCount={25} displayPageCount={5} />
|
|
59
59
|
));
|
|
@@ -64,12 +64,12 @@ describe("Pagination 컴포넌트", () => {
|
|
|
64
64
|
});
|
|
65
65
|
});
|
|
66
66
|
|
|
67
|
-
describe("
|
|
68
|
-
it("
|
|
67
|
+
describe("current page display", () => {
|
|
68
|
+
it("current page button has a different variant", () => {
|
|
69
69
|
const { container } = render(() => <Pagination page={3} totalPageCount={5} />);
|
|
70
70
|
|
|
71
71
|
const buttons = container.querySelectorAll("[data-button]");
|
|
72
|
-
// buttons[0]=<<, [1]=<, [2]=page1, [3]=page2, [4]=page3(
|
|
72
|
+
// buttons[0]=<<, [1]=<, [2]=page1, [3]=page2, [4]=page3(current), [5]=page4, [6]=page5, [7]=>, [8]=>>
|
|
73
73
|
const currentButton = buttons[4]; // page 3 (1-based page=3)
|
|
74
74
|
const otherButton = buttons[2]; // page 1
|
|
75
75
|
|
|
@@ -77,8 +77,8 @@ describe("Pagination 컴포넌트", () => {
|
|
|
77
77
|
});
|
|
78
78
|
});
|
|
79
79
|
|
|
80
|
-
describe("
|
|
81
|
-
it("page=1, displayPageCount=5
|
|
80
|
+
describe("page group calculation", () => {
|
|
81
|
+
it("displays pages 1-5 when page=1, displayPageCount=5", () => {
|
|
82
82
|
const { getByText, queryByText } = render(() => (
|
|
83
83
|
<Pagination page={1} totalPageCount={20} displayPageCount={5} />
|
|
84
84
|
));
|
|
@@ -91,7 +91,7 @@ describe("Pagination 컴포넌트", () => {
|
|
|
91
91
|
expect(queryByText("6")).toBeFalsy();
|
|
92
92
|
});
|
|
93
93
|
|
|
94
|
-
it("page=6, displayPageCount=5
|
|
94
|
+
it("displays pages 6-10 when page=6, displayPageCount=5", () => {
|
|
95
95
|
const { getByText, queryByText } = render(() => (
|
|
96
96
|
<Pagination page={6} totalPageCount={20} displayPageCount={5} />
|
|
97
97
|
));
|
|
@@ -105,7 +105,7 @@ describe("Pagination 컴포넌트", () => {
|
|
|
105
105
|
expect(queryByText("11")).toBeFalsy();
|
|
106
106
|
});
|
|
107
107
|
|
|
108
|
-
it("page=13, displayPageCount=10
|
|
108
|
+
it("displays pages 11-20 when page=13, displayPageCount=10", () => {
|
|
109
109
|
const { getByText, queryByText } = render(() => (
|
|
110
110
|
<Pagination page={13} totalPageCount={25} displayPageCount={10} />
|
|
111
111
|
));
|
|
@@ -116,7 +116,7 @@ describe("Pagination 컴포넌트", () => {
|
|
|
116
116
|
expect(queryByText("21")).toBeFalsy();
|
|
117
117
|
});
|
|
118
118
|
|
|
119
|
-
it("
|
|
119
|
+
it("displays only remaining pages in the last group below totalPageCount", () => {
|
|
120
120
|
const { container, getByText, queryByText } = render(() => (
|
|
121
121
|
<Pagination page={8} totalPageCount={8} displayPageCount={5} />
|
|
122
122
|
));
|
|
@@ -133,8 +133,8 @@ describe("Pagination 컴포넌트", () => {
|
|
|
133
133
|
});
|
|
134
134
|
});
|
|
135
135
|
|
|
136
|
-
describe("
|
|
137
|
-
it("
|
|
136
|
+
describe("navigation button disabled state", () => {
|
|
137
|
+
it("disables first/prev buttons in the first group", () => {
|
|
138
138
|
const { container } = render(() => (
|
|
139
139
|
<Pagination page={1} totalPageCount={20} displayPageCount={5} />
|
|
140
140
|
));
|
|
@@ -147,7 +147,7 @@ describe("Pagination 컴포넌트", () => {
|
|
|
147
147
|
expect(prevBtn.hasAttribute("disabled")).toBe(true);
|
|
148
148
|
});
|
|
149
149
|
|
|
150
|
-
it("
|
|
150
|
+
it("disables next/last buttons in the last group", () => {
|
|
151
151
|
const { container } = render(() => (
|
|
152
152
|
<Pagination page={19} totalPageCount={20} displayPageCount={5} />
|
|
153
153
|
));
|
|
@@ -160,7 +160,7 @@ describe("Pagination 컴포넌트", () => {
|
|
|
160
160
|
expect(lastBtn.hasAttribute("disabled")).toBe(true);
|
|
161
161
|
});
|
|
162
162
|
|
|
163
|
-
it("
|
|
163
|
+
it("all navigation buttons are enabled in a middle group", () => {
|
|
164
164
|
const { container } = render(() => (
|
|
165
165
|
<Pagination page={6} totalPageCount={20} displayPageCount={5} />
|
|
166
166
|
));
|
|
@@ -178,8 +178,8 @@ describe("Pagination 컴포넌트", () => {
|
|
|
178
178
|
});
|
|
179
179
|
});
|
|
180
180
|
|
|
181
|
-
describe("
|
|
182
|
-
it("
|
|
181
|
+
describe("page click", () => {
|
|
182
|
+
it("calls onPageChange when a page button is clicked", () => {
|
|
183
183
|
const onPageChange = vi.fn();
|
|
184
184
|
const { getByText } = render(() => (
|
|
185
185
|
<Pagination page={1} totalPageCount={5} onPageChange={onPageChange} />
|
|
@@ -190,7 +190,7 @@ describe("Pagination 컴포넌트", () => {
|
|
|
190
190
|
expect(onPageChange).toHaveBeenCalledWith(3); // 1-based
|
|
191
191
|
});
|
|
192
192
|
|
|
193
|
-
it("
|
|
193
|
+
it("calls onPageChange even when clicking the current page", () => {
|
|
194
194
|
const onPageChange = vi.fn();
|
|
195
195
|
const { getByText } = render(() => (
|
|
196
196
|
<Pagination page={1} totalPageCount={5} onPageChange={onPageChange} />
|
|
@@ -202,8 +202,8 @@ describe("Pagination 컴포넌트", () => {
|
|
|
202
202
|
});
|
|
203
203
|
});
|
|
204
204
|
|
|
205
|
-
describe("first
|
|
206
|
-
it("
|
|
205
|
+
describe("first button (<<)", () => {
|
|
206
|
+
it("navigates to page 1 when first button is clicked", () => {
|
|
207
207
|
const onPageChange = vi.fn();
|
|
208
208
|
const { container } = render(() => (
|
|
209
209
|
<Pagination
|
|
@@ -221,8 +221,8 @@ describe("Pagination 컴포넌트", () => {
|
|
|
221
221
|
});
|
|
222
222
|
});
|
|
223
223
|
|
|
224
|
-
describe("last
|
|
225
|
-
it("last
|
|
224
|
+
describe("last button (>>)", () => {
|
|
225
|
+
it("navigates to last page when last button is clicked", () => {
|
|
226
226
|
const onPageChange = vi.fn();
|
|
227
227
|
const { container } = render(() => (
|
|
228
228
|
<Pagination page={1} totalPageCount={20} displayPageCount={5} onPageChange={onPageChange} />
|
|
@@ -235,8 +235,8 @@ describe("Pagination 컴포넌트", () => {
|
|
|
235
235
|
});
|
|
236
236
|
});
|
|
237
237
|
|
|
238
|
-
describe("prev
|
|
239
|
-
it("
|
|
238
|
+
describe("prev group button (<)", () => {
|
|
239
|
+
it("navigates to last page of previous group when prev button is clicked", () => {
|
|
240
240
|
const onPageChange = vi.fn();
|
|
241
241
|
const { container } = render(() => (
|
|
242
242
|
<Pagination page={8} totalPageCount={20} displayPageCount={5} onPageChange={onPageChange} />
|
|
@@ -251,8 +251,8 @@ describe("Pagination 컴포넌트", () => {
|
|
|
251
251
|
});
|
|
252
252
|
});
|
|
253
253
|
|
|
254
|
-
describe("next
|
|
255
|
-
it("
|
|
254
|
+
describe("next group button (>)", () => {
|
|
255
|
+
it("navigates to first page of next group when next button is clicked", () => {
|
|
256
256
|
const onPageChange = vi.fn();
|
|
257
257
|
const { container } = render(() => (
|
|
258
258
|
<Pagination page={4} totalPageCount={20} displayPageCount={5} onPageChange={onPageChange} />
|
|
@@ -268,7 +268,7 @@ describe("Pagination 컴포넌트", () => {
|
|
|
268
268
|
});
|
|
269
269
|
|
|
270
270
|
describe("size prop", () => {
|
|
271
|
-
it("size prop
|
|
271
|
+
it("applies different styles when size prop is provided", () => {
|
|
272
272
|
const { container: defaultContainer } = render(() => (
|
|
273
273
|
<Pagination page={1} totalPageCount={5} />
|
|
274
274
|
));
|
|
@@ -283,34 +283,34 @@ describe("Pagination 컴포넌트", () => {
|
|
|
283
283
|
const smNav = smContainer.querySelector("nav");
|
|
284
284
|
const lgNav = lgContainer.querySelector("nav");
|
|
285
285
|
|
|
286
|
-
// sm
|
|
286
|
+
// sm and lg should have different classes from default
|
|
287
287
|
expect(smNav?.className).not.toBe(defaultNav?.className);
|
|
288
288
|
expect(lgNav?.className).not.toBe(defaultNav?.className);
|
|
289
289
|
});
|
|
290
290
|
});
|
|
291
291
|
|
|
292
|
-
describe("
|
|
293
|
-
it("
|
|
292
|
+
describe("reactive behavior", () => {
|
|
293
|
+
it("updates UI when page signal changes", () => {
|
|
294
294
|
const [page, setPage] = createSignal(1);
|
|
295
295
|
|
|
296
296
|
const { container, getByText } = render(() => (
|
|
297
297
|
<Pagination page={page()} totalPageCount={20} displayPageCount={5} onPageChange={setPage} />
|
|
298
298
|
));
|
|
299
299
|
|
|
300
|
-
//
|
|
300
|
+
// initial state: pages 1-5 are displayed
|
|
301
301
|
expect(getByText("1")).toBeTruthy();
|
|
302
302
|
|
|
303
|
-
// next
|
|
303
|
+
// navigate to next group (> click → page 6)
|
|
304
304
|
const buttons = container.querySelectorAll("[data-button]");
|
|
305
|
-
fireEvent.click(buttons[buttons.length - 2]); // >
|
|
305
|
+
fireEvent.click(buttons[buttons.length - 2]); // > click → page 6
|
|
306
306
|
|
|
307
|
-
//
|
|
307
|
+
// after page change, group 6-10 should be displayed
|
|
308
308
|
expect(getByText("6")).toBeTruthy();
|
|
309
309
|
});
|
|
310
310
|
});
|
|
311
311
|
|
|
312
|
-
describe("
|
|
313
|
-
it("
|
|
312
|
+
describe("edge cases", () => {
|
|
313
|
+
it("all navigation buttons are disabled when totalPageCount=1", () => {
|
|
314
314
|
const { container } = render(() => <Pagination page={1} totalPageCount={1} />);
|
|
315
315
|
|
|
316
316
|
const buttons = container.querySelectorAll("[data-button]");
|
|
@@ -325,7 +325,7 @@ describe("Pagination 컴포넌트", () => {
|
|
|
325
325
|
expect(lastBtn.hasAttribute("disabled")).toBe(true);
|
|
326
326
|
});
|
|
327
327
|
|
|
328
|
-
it("
|
|
328
|
+
it("no page buttons displayed when totalPageCount=0", () => {
|
|
329
329
|
const { container } = render(() => <Pagination page={1} totalPageCount={0} />);
|
|
330
330
|
|
|
331
331
|
const buttons = container.querySelectorAll("[data-button]");
|