@torpor/ui 0.3.4 → 0.3.6
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/dist/Form/Form.torp +1 -0
- package/dist/metafile-esm.json +1 -1
- package/package.json +12 -9
- package/CHANGELOG.md +0 -338
- package/scripts/postbuild.ts +0 -127
- package/src/Accordion/Accordion.torp +0 -230
- package/src/Accordion/AccordionContent.torp +0 -46
- package/src/Accordion/AccordionHeader.torp +0 -45
- package/src/Accordion/AccordionItem.torp +0 -101
- package/src/Accordion/AccordionTrigger.torp +0 -70
- package/src/Accordion/AccordionTypes.ts +0 -36
- package/src/Accordion/index.ts +0 -7
- package/src/Breadcrumb/Breadcrumb.torp +0 -45
- package/src/Breadcrumb/BreadcrumbItem.torp +0 -30
- package/src/Breadcrumb/BreadcrumbSeparator.torp +0 -27
- package/src/Breadcrumb/index.ts +0 -5
- package/src/Calendar/Calendar.torp +0 -277
- package/src/Calendar/CalendarDay.torp +0 -78
- package/src/Calendar/CalendarTypes.ts +0 -22
- package/src/Calendar/index.ts +0 -4
- package/src/Contextual/Contextual.torp +0 -129
- package/src/Contextual/ContextualContent.torp +0 -112
- package/src/Contextual/ContextualTrigger.torp +0 -70
- package/src/Contextual/ContextualTypes.ts +0 -30
- package/src/Contextual/index.ts +0 -5
- package/src/Dialog/Dialog.torp +0 -136
- package/src/Dialog/DialogBody.torp +0 -44
- package/src/Dialog/DialogButton.torp +0 -66
- package/src/Dialog/DialogFooter.torp +0 -25
- package/src/Dialog/DialogHeader.torp +0 -45
- package/src/Dialog/DialogTypes.ts +0 -17
- package/src/Dialog/index.ts +0 -7
- package/src/Disclosure/Disclosure.torp +0 -82
- package/src/Disclosure/DisclosureContent.torp +0 -46
- package/src/Disclosure/DisclosureHeader.torp +0 -45
- package/src/Disclosure/DisclosureTrigger.torp +0 -47
- package/src/Disclosure/DisclosureTypes.ts +0 -13
- package/src/Disclosure/index.ts +0 -6
- package/src/Drawer/Drawer.torp +0 -127
- package/src/Drawer/DrawerContent.torp +0 -83
- package/src/Drawer/DrawerOverlay.torp +0 -42
- package/src/Drawer/DrawerTrigger.torp +0 -39
- package/src/Drawer/DrawerTypes.ts +0 -24
- package/src/Drawer/index.ts +0 -6
- package/src/Form/CheckBox.torp +0 -94
- package/src/Form/Field.torp +0 -95
- package/src/Form/File.torp +0 -102
- package/src/Form/Form.torp +0 -146
- package/src/Form/FormTypes.ts +0 -35
- package/src/Form/Hidden.torp +0 -25
- package/src/Form/Input.torp +0 -112
- package/src/Form/Label.torp +0 -35
- package/src/Form/Message.torp +0 -39
- package/src/Form/Option.torp +0 -28
- package/src/Form/Select.torp +0 -101
- package/src/Form/StandardSchemaV1.ts +0 -70
- package/src/Form/TextArea.torp +0 -105
- package/src/Form/index.ts +0 -13
- package/src/Menu/Menu.torp +0 -174
- package/src/Menu/MenuButton.torp +0 -74
- package/src/Menu/MenuCheck.torp +0 -89
- package/src/Menu/MenuGroup.torp +0 -31
- package/src/Menu/MenuIndicator.torp +0 -40
- package/src/Menu/MenuPopout.torp +0 -83
- package/src/Menu/MenuPopoutContent.torp +0 -84
- package/src/Menu/MenuPopoutTrigger.torp +0 -128
- package/src/Menu/MenuRadio.torp +0 -103
- package/src/Menu/MenuRadioGroup.torp +0 -109
- package/src/Menu/MenuSeparator.torp +0 -26
- package/src/Menu/MenuTypes.ts +0 -60
- package/src/Menu/index.ts +0 -25
- package/src/MenuBar/MenuBar.torp +0 -162
- package/src/MenuBar/MenuBarItem.torp +0 -116
- package/src/MenuBar/MenuBarItemContent.torp +0 -119
- package/src/MenuBar/MenuBarItemTrigger.torp +0 -99
- package/src/MenuBar/MenuBarTypes.ts +0 -36
- package/src/MenuBar/index.ts +0 -6
- package/src/Modal/Modal.torp +0 -122
- package/src/Modal/ModalContent.torp +0 -81
- package/src/Modal/ModalOverlay.torp +0 -42
- package/src/Modal/ModalTrigger.torp +0 -54
- package/src/Modal/ModalTypes.ts +0 -22
- package/src/Modal/index.ts +0 -10
- package/src/Modal/showModal.ts +0 -19
- package/src/Modal/showPrompt.ts +0 -23
- package/src/NavMenu/NavMenu.torp +0 -190
- package/src/NavMenu/NavMenuButton.torp +0 -55
- package/src/NavMenu/NavMenuElement.torp +0 -55
- package/src/NavMenu/NavMenuGroup.torp +0 -41
- package/src/NavMenu/NavMenuGroupHeader.torp +0 -41
- package/src/NavMenu/NavMenuLink.torp +0 -60
- package/src/NavMenu/NavMenuPopout.torp +0 -89
- package/src/NavMenu/NavMenuPopoutButton.torp +0 -129
- package/src/NavMenu/NavMenuPopoutContent.torp +0 -92
- package/src/NavMenu/NavMenuSeparator.torp +0 -24
- package/src/NavMenu/NavMenuTypes.ts +0 -32
- package/src/NavMenu/index.ts +0 -23
- package/src/Notification/Notification.torp +0 -71
- package/src/Notification/NotificationClose.torp +0 -39
- package/src/Notification/NotificationContainer.torp +0 -26
- package/src/Notification/NotificationContent.torp +0 -25
- package/src/Notification/NotificationTypes.ts +0 -5
- package/src/Notification/index.ts +0 -13
- package/src/Notification/showNotification.ts +0 -30
- package/src/Popover/Popover.torp +0 -129
- package/src/Popover/PopoverContent.torp +0 -117
- package/src/Popover/PopoverTrigger.torp +0 -62
- package/src/Popover/PopoverTypes.ts +0 -30
- package/src/Popover/index.ts +0 -6
- package/src/Popover/showPopover.ts +0 -24
- package/src/Slider/Slider.torp +0 -84
- package/src/Slider/index.ts +0 -3
- package/src/TabGroup/TabContent.torp +0 -49
- package/src/TabGroup/TabGroup.torp +0 -250
- package/src/TabGroup/TabGroupTypes.ts +0 -44
- package/src/TabGroup/TabHeader.torp +0 -81
- package/src/TabGroup/TabList.torp +0 -61
- package/src/TabGroup/TabTrigger.torp +0 -76
- package/src/TabGroup/index.ts +0 -7
- package/src/ambient.d.ts +0 -7
- package/src/icons/ArrowDown.torp +0 -18
- package/src/icons/ArrowLeft.torp +0 -18
- package/src/icons/ArrowRight.torp +0 -18
- package/src/icons/ArrowUp.torp +0 -18
- package/src/icons/Bars.torp +0 -20
- package/src/icons/Check.torp +0 -18
- package/src/icons/ChevronDown.torp +0 -18
- package/src/icons/ChevronLeft.torp +0 -18
- package/src/icons/ChevronRight.torp +0 -18
- package/src/icons/ChevronUp.torp +0 -18
- package/src/icons/Cross.torp +0 -19
- package/src/icons/IconTypes.ts +0 -10
- package/src/icons/Loading.torp +0 -19
- package/src/icons/Minus.torp +0 -18
- package/src/icons/Plus.torp +0 -19
- package/src/icons/index.ts +0 -31
- package/src/motion/fade.ts +0 -16
- package/src/motion/grow.ts +0 -23
- package/src/motion/index.ts +0 -6
- package/src/motion/measure.ts +0 -28
- package/src/motion/slide.ts +0 -45
- package/src/mount/clickPopover.ts +0 -51
- package/src/mount/contextPopover.ts +0 -51
- package/src/mount/disableScroll.ts +0 -28
- package/src/mount/hoverPopover.ts +0 -58
- package/src/mount/hoverTrigger.ts +0 -59
- package/src/mount/trapFocus.ts +0 -58
- package/src/utils/dateUtils.ts +0 -244
- package/src/utils/documentEvents.ts +0 -17
- package/src/utils/getId.ts +0 -6
- package/src/utils/getScrollParent.ts +0 -22
- package/src/utils/setContextPosition.ts +0 -31
- package/src/utils/setPopoverPosition.ts +0 -142
- package/test/Accordion/accessibility.test.ts +0 -59
- package/test/Accordion/components/AccordionAccessibility.torp +0 -44
- package/test/Accordion/components/AccordionKeyboard.torp +0 -32
- package/test/Accordion/components/AccordionList.torp +0 -23
- package/test/Accordion/components/AccordionMultiple.torp +0 -32
- package/test/Accordion/components/AccordionSingle.torp +0 -32
- package/test/Accordion/for-items.test.ts +0 -52
- package/test/Accordion/keyboard.test.ts +0 -64
- package/test/Accordion/multiple-item-toggle.test.ts +0 -32
- package/test/Accordion/multiple-item-value.test.ts +0 -17
- package/test/Accordion/single-item-toggle.test.ts +0 -31
- package/test/Accordion/single-item-value.test.ts +0 -17
- package/test/Breadcrumb/accessibility.test.ts +0 -29
- package/test/Breadcrumb/basic.test.ts +0 -17
- package/test/Breadcrumb/components/BreadcrumbTest.torp +0 -15
- package/test/Calendar/components/CalendarTest.torp +0 -9
- package/test/Calendar/default.test.ts +0 -18
- package/test/Dialog/accessibility-alert.test.ts +0 -40
- package/test/Dialog/accessibility-modal.test.ts +0 -52
- package/test/Dialog/components/DialogAccessibility.torp +0 -25
- package/test/Dialog/components/DialogFunction.torp +0 -36
- package/test/Dialog/components/DialogModal.torp +0 -30
- package/test/Dialog/components/DialogVariable.torp +0 -33
- package/test/Dialog/function.test.ts +0 -26
- package/test/Dialog/variable.test.ts +0 -27
- package/test/Disclosure/accessibility.test.ts +0 -31
- package/test/Disclosure/components/DisclosureTest.torp +0 -17
- package/test/Disclosure/default.test.ts +0 -15
- package/test/Disclosure/toggle.test.ts +0 -20
- package/test/Form/components/FieldTest.torp +0 -25
- package/test/Form/components/FormTest.torp +0 -31
- package/test/Form/components/InputTest.torp +0 -9
- package/test/Form/field.test.ts +0 -34
- package/test/Form/form.test.ts +0 -34
- package/test/Form/input.test.ts +0 -19
- package/test/Menu/accessibility.test.ts +0 -83
- package/test/Menu/basic.test.ts +0 -58
- package/test/Menu/components/MenuAccessibility.torp +0 -59
- package/test/Menu/components/MenuBasic.torp +0 -58
- package/test/MenuBar/accessibility.test.ts +0 -87
- package/test/MenuBar/basic.test.ts +0 -22
- package/test/MenuBar/components/MenuBarAccessibility.torp +0 -34
- package/test/MenuBar/components/MenuBarBasic.torp +0 -25
- package/test/NavMenu/accessibility.test.ts +0 -97
- package/test/NavMenu/basic.test.ts +0 -22
- package/test/NavMenu/components/NavMenuAccessibility.torp +0 -35
- package/test/NavMenu/components/NavMenuBasic.torp +0 -28
- package/test/Notification/accessibility.test.ts +0 -21
- package/test/Notification/components/CustomNotification.torp +0 -14
- package/test/Notification/components/NotificationAccessibility.torp +0 -14
- package/test/Notification/components/NotificationFunction.torp +0 -17
- package/test/Notification/components/NotificationVariable.torp +0 -22
- package/test/Notification/function.test.ts +0 -25
- package/test/Notification/variable.test.ts +0 -25
- package/test/Popover/components/CustomDialog.torp +0 -25
- package/test/Popover/components/PopoverFunction.torp +0 -37
- package/test/Popover/components/PopoverTrigger.torp +0 -36
- package/test/Popover/components/PopoverVariable.torp +0 -40
- package/test/Popover/function.test.ts +0 -21
- package/test/Popover/trigger.test.ts +0 -27
- package/test/Popover/variable.test.ts +0 -27
- package/test/TabGroup/accessibility.test.ts +0 -67
- package/test/TabGroup/components/TabGroupAccessibility.torp +0 -28
- package/test/TabGroup/components/TabGroupKeyboard.torp +0 -28
- package/test/TabGroup/components/TabGroupList.torp +0 -26
- package/test/TabGroup/components/TabGroupTrigger.torp +0 -28
- package/test/TabGroup/for-items.test.ts +0 -52
- package/test/TabGroup/item-trigger.test.ts +0 -33
- package/test/TabGroup/item-value.test.ts +0 -17
- package/test/TabGroup/keyboard.test.ts +0 -72
- package/tsconfig.json +0 -4
- package/tsup.config.ts +0 -37
- package/vitest.config.ts +0 -12
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
import { getByText, queryByText } from "@testing-library/dom";
|
|
2
|
-
import "@testing-library/jest-dom/vitest";
|
|
3
|
-
import userEvent from "@testing-library/user-event";
|
|
4
|
-
import { mount } from "@torpor/view";
|
|
5
|
-
import { describe, expect, it } from "vitest";
|
|
6
|
-
import NavMenuAccessibility from "./components/NavMenuAccessibility.torp";
|
|
7
|
-
|
|
8
|
-
describe("NavMenu", () => {
|
|
9
|
-
it("Accessibility", async () => {
|
|
10
|
-
const container = document.createElement("div");
|
|
11
|
-
document.body.appendChild(container);
|
|
12
|
-
mount(container, NavMenuAccessibility);
|
|
13
|
-
|
|
14
|
-
// Tests from https://www.w3.org/WAI/ARIA/apg/patterns/menu/
|
|
15
|
-
// NOTE: NavMenu is a menubar
|
|
16
|
-
|
|
17
|
-
// A menu is a container of items that represent choices. The element serving as the menu has
|
|
18
|
-
// a role of either menu or menubar
|
|
19
|
-
expect(queryByText(container, "Home")?.parentElement).toHaveAttribute("role", "menubar");
|
|
20
|
-
|
|
21
|
-
// The items contained in a menu are child elements of the containing menu or menubar and have
|
|
22
|
-
// any of the following roles:
|
|
23
|
-
// * menuitem
|
|
24
|
-
// * menuitemcheckbox
|
|
25
|
-
// * menuitemradio
|
|
26
|
-
expect(queryByText(container, "Home")).toHaveAttribute("role", "menuitem");
|
|
27
|
-
expect(queryByText(container, "Page")).toHaveAttribute("role", "menuitem");
|
|
28
|
-
expect(queryByText(container, "Disabled")).toHaveAttribute("role", "menuitem");
|
|
29
|
-
expect(queryByText(container, "Subpages")).toHaveAttribute("role", "menuitem");
|
|
30
|
-
|
|
31
|
-
// If activating a menuitem opens a submenu, the menuitem is known as a parent menuitem. A submenu's
|
|
32
|
-
// menu element is:
|
|
33
|
-
// * Contained inside the same menu element as its parent menuitem
|
|
34
|
-
// * Is the sibling element immediately following its parent menuitem
|
|
35
|
-
|
|
36
|
-
// A parent menuitem has aria-haspopup set to either menu or true
|
|
37
|
-
expect(queryByText(container, "Subpages")).toHaveAttribute("aria-haspopup", "true");
|
|
38
|
-
|
|
39
|
-
// A parent menuitem has aria-expanded set to false when its child menu is not visible and set
|
|
40
|
-
// to true when the child menu is visible
|
|
41
|
-
expect(queryByText(container, "Subpages")).toHaveAttribute("aria-expanded", "false");
|
|
42
|
-
await userEvent.click(getByText(container, "Subpages"));
|
|
43
|
-
expect(queryByText(container, "Subpages")).toHaveAttribute("aria-expanded", "true");
|
|
44
|
-
|
|
45
|
-
// One of the following approaches is used to enable scripts to move focus among items in a
|
|
46
|
-
// menu as described in Keyboard Navigation Inside Components:
|
|
47
|
-
// * The menu container has tabindex set to -1 or 0 and aria-activedescendant set to the ID
|
|
48
|
-
// of the focused item
|
|
49
|
-
// * Each item in the menu has tabindex set to -1, except in a menubar, where the first item
|
|
50
|
-
// has tabindex set to 0
|
|
51
|
-
|
|
52
|
-
// When a menuitemcheckbox or menuitemradio is checked, aria-checked is set to true
|
|
53
|
-
// NOTE: We don't (currently?) have checkboxes or radios in NavMenus
|
|
54
|
-
|
|
55
|
-
// When a menu item is disabled, aria-disabled is set to true
|
|
56
|
-
expect(queryByText(container, "Page")).not.toHaveAttribute("aria-disabled");
|
|
57
|
-
expect(queryByText(container, "Disabled")).toHaveAttribute("aria-disabled", "true");
|
|
58
|
-
|
|
59
|
-
// Items in a menu may be divided into groups by placing an element with a role of separator
|
|
60
|
-
// between groups. For example, this technique should be used when a menu contains a set of
|
|
61
|
-
// menuitemradio items
|
|
62
|
-
expect(queryByText(container, "/")).toHaveAttribute("role", "separator");
|
|
63
|
-
|
|
64
|
-
// All separators should have aria-orientation consistent with the separator's orientation
|
|
65
|
-
// NOTE: What does this mean? None of the example separators have aria-orientation set
|
|
66
|
-
|
|
67
|
-
// If a menubar has a visible label, the element with role menubar has aria-labelledby set to
|
|
68
|
-
// a value that refers to the labelling element. Otherwise, the menubar element has a label
|
|
69
|
-
// provided by aria-label
|
|
70
|
-
// NOTE: We only support aria-label and it's required
|
|
71
|
-
expect(queryByText(container, "Home")?.parentElement).toHaveAttribute(
|
|
72
|
-
"aria-label",
|
|
73
|
-
"Site navigation",
|
|
74
|
-
);
|
|
75
|
-
|
|
76
|
-
// If a menubar is vertically oriented, it has aria-orientation set to vertical. The default
|
|
77
|
-
// value of aria-orientation for a menubar is horizontal
|
|
78
|
-
expect(queryByText(container, "Home")?.parentElement).toHaveAttribute(
|
|
79
|
-
"aria-orientation",
|
|
80
|
-
"horizontal",
|
|
81
|
-
);
|
|
82
|
-
expect(queryByText(container, "Subpage 1")?.parentElement).toHaveAttribute(
|
|
83
|
-
"aria-orientation",
|
|
84
|
-
"vertical",
|
|
85
|
-
);
|
|
86
|
-
|
|
87
|
-
// Our own tests
|
|
88
|
-
|
|
89
|
-
// The group should be labeled
|
|
90
|
-
expect(queryByText(container, "Group header")).toBeInTheDocument();
|
|
91
|
-
const headerId = queryByText(container, "Group header")?.id;
|
|
92
|
-
expect(queryByText(container, "Group header")?.parentElement).toHaveAttribute(
|
|
93
|
-
"aria-labelledby",
|
|
94
|
-
headerId,
|
|
95
|
-
);
|
|
96
|
-
});
|
|
97
|
-
});
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { getByText, queryByText } from "@testing-library/dom";
|
|
2
|
-
import "@testing-library/jest-dom/vitest";
|
|
3
|
-
import userEvent from "@testing-library/user-event";
|
|
4
|
-
import { mount } from "@torpor/view";
|
|
5
|
-
import { describe, expect, it } from "vitest";
|
|
6
|
-
import NavMenu from "./components/NavMenuBasic.torp";
|
|
7
|
-
|
|
8
|
-
describe("NavMenu", () => {
|
|
9
|
-
it("Basic operation", async () => {
|
|
10
|
-
const container = document.createElement("div");
|
|
11
|
-
document.body.appendChild(container);
|
|
12
|
-
mount(container, NavMenu);
|
|
13
|
-
|
|
14
|
-
// By default, body 1 should be displayed
|
|
15
|
-
expect(queryByText(container, "Home")).toBeInTheDocument();
|
|
16
|
-
expect(queryByText(container, "Subpage 1")).not.toBeInTheDocument();
|
|
17
|
-
|
|
18
|
-
// Clicking header 2 should hide body 1 and reveal body 2
|
|
19
|
-
await userEvent.click(getByText(container, "Subpages"));
|
|
20
|
-
expect(queryByText(container, "Subpage 1")).toBeInTheDocument();
|
|
21
|
-
});
|
|
22
|
-
});
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
NavMenu,
|
|
3
|
-
NavMenuLink,
|
|
4
|
-
NavMenuPopout,
|
|
5
|
-
NavMenuPopoutButton,
|
|
6
|
-
NavMenuPopoutContent,
|
|
7
|
-
NavMenuGroup,
|
|
8
|
-
NavMenuGroupHeader,
|
|
9
|
-
NavMenuSeparator
|
|
10
|
-
} from "../../../src/NavMenu";
|
|
11
|
-
|
|
12
|
-
export default function NavMenuAccessibility($props: any) {
|
|
13
|
-
@render {
|
|
14
|
-
<NavMenu ariaLabel="Site navigation">
|
|
15
|
-
<NavMenuLink href="/">Home</NavMenuLink>
|
|
16
|
-
<NavMenuLink href="/page1">Page</NavMenuLink>
|
|
17
|
-
<NavMenuLink href="/disabled" disabled>Disabled</NavMenuLink>
|
|
18
|
-
<NavMenuSeparator>/</NavMenuSeparator>
|
|
19
|
-
<NavMenuPopout>
|
|
20
|
-
<NavMenuPopoutButton>Subpages</NavMenuPopoutButton>
|
|
21
|
-
<NavMenuPopoutContent>
|
|
22
|
-
<NavMenu ariaLabel="Sub site navigation" orientation="vertical">
|
|
23
|
-
<NavMenuLink href="/sub/page1">Subpage 1</NavMenuLink>
|
|
24
|
-
<NavMenuLink href="/sub/page2">Subpage 2</NavMenuLink>
|
|
25
|
-
<NavMenuLink href="/sub/page3">Subpage 3</NavMenuLink>
|
|
26
|
-
</NavMenu>
|
|
27
|
-
</NavMenuPopoutContent>
|
|
28
|
-
</NavMenuPopout>
|
|
29
|
-
<NavMenuGroup>
|
|
30
|
-
<NavMenuGroupHeader as="h4">Group header</NavMenuGroupHeader>
|
|
31
|
-
<NavMenuLink href="/grouped-page">Grouped page</NavMenuLink>
|
|
32
|
-
</NavMenuGroup>
|
|
33
|
-
</NavMenu>
|
|
34
|
-
}
|
|
35
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
NavMenu,
|
|
3
|
-
NavMenuLink,
|
|
4
|
-
NavMenuPopout,
|
|
5
|
-
NavMenuPopoutButton,
|
|
6
|
-
NavMenuPopoutContent,
|
|
7
|
-
NavMenuSeparator
|
|
8
|
-
} from "../../../src/NavMenu";
|
|
9
|
-
|
|
10
|
-
export default function NavMenuBasic($props: any) {
|
|
11
|
-
@render {
|
|
12
|
-
<NavMenu ariaLabel="Site navigation">
|
|
13
|
-
<NavMenuLink href="/">Home</NavMenuLink>
|
|
14
|
-
<NavMenuLink href="/page1">Page 1</NavMenuLink>
|
|
15
|
-
<NavMenuSeparator />
|
|
16
|
-
<NavMenuPopout>
|
|
17
|
-
<NavMenuPopoutButton>Subpages</NavMenuPopoutButton>
|
|
18
|
-
<NavMenuPopoutContent>
|
|
19
|
-
<NavMenu ariaLabel="Sub site navigation" orientation="vertical">
|
|
20
|
-
<NavMenuLink href="/sub/page1">Subpage 1</NavMenuLink>
|
|
21
|
-
<NavMenuLink href="/sub/page2">Subpage 2</NavMenuLink>
|
|
22
|
-
<NavMenuLink href="/sub/page3">Subpage 3</NavMenuLink>
|
|
23
|
-
</NavMenu>
|
|
24
|
-
</NavMenuPopoutContent>
|
|
25
|
-
</NavMenuPopout>
|
|
26
|
-
</NavMenu>
|
|
27
|
-
}
|
|
28
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { queryByText } from "@testing-library/dom";
|
|
2
|
-
import "@testing-library/jest-dom/vitest";
|
|
3
|
-
import { mount } from "@torpor/view";
|
|
4
|
-
import { describe, expect, it } from "vitest";
|
|
5
|
-
import NotificationAccessibility from "./components/NotificationAccessibility.torp";
|
|
6
|
-
|
|
7
|
-
describe("Notification", () => {
|
|
8
|
-
it("Accessibility", async () => {
|
|
9
|
-
const container = document.createElement("div");
|
|
10
|
-
document.body.appendChild(container);
|
|
11
|
-
mount(container, NotificationAccessibility);
|
|
12
|
-
|
|
13
|
-
// Tests from https://www.w3.org/WAI/ARIA/apg/patterns/alert/
|
|
14
|
-
|
|
15
|
-
// The widget has a role of alert
|
|
16
|
-
expect(queryByText(container, "Here's a notification")?.parentElement).toHaveAttribute(
|
|
17
|
-
"role",
|
|
18
|
-
"alert",
|
|
19
|
-
);
|
|
20
|
-
});
|
|
21
|
-
});
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Notification,
|
|
3
|
-
NotificationContent,
|
|
4
|
-
NotificationClose
|
|
5
|
-
} from "../../../src/Notification/index";
|
|
6
|
-
|
|
7
|
-
export default function CustomNotification() {
|
|
8
|
-
@render {
|
|
9
|
-
<Notification>
|
|
10
|
-
<NotificationContent>{$props.text}</NotificationContent>
|
|
11
|
-
<NotificationClose>Close me</NotificationClose>
|
|
12
|
-
</Notification>
|
|
13
|
-
}
|
|
14
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Notification,
|
|
3
|
-
NotificationContent,
|
|
4
|
-
NotificationClose
|
|
5
|
-
} from "../../../src/Notification/index";
|
|
6
|
-
|
|
7
|
-
export default function NotificationAccessibility() {
|
|
8
|
-
@render {
|
|
9
|
-
<Notification visible>
|
|
10
|
-
<NotificationContent>Here's a notification</NotificationContent>
|
|
11
|
-
<NotificationClose>Close me</NotificationClose>
|
|
12
|
-
</Notification>
|
|
13
|
-
}
|
|
14
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
NotificationContainer,
|
|
3
|
-
showNotification
|
|
4
|
-
} from "../../../src/Notification/index";
|
|
5
|
-
import CustomNotification from "./CustomNotification.torp";
|
|
6
|
-
|
|
7
|
-
export default function NotificationFunction() {
|
|
8
|
-
function show() {
|
|
9
|
-
showNotification(CustomNotification, { text: "Here's a notification" });
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
@render {
|
|
13
|
-
<button type="button" onclick={show}>Show a notification</button>
|
|
14
|
-
|
|
15
|
-
<NotificationContainer />
|
|
16
|
-
}
|
|
17
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Notification,
|
|
3
|
-
NotificationContent,
|
|
4
|
-
NotificationClose
|
|
5
|
-
} from "../../../src/Notification/index";
|
|
6
|
-
|
|
7
|
-
export default function NotificationVariable() {
|
|
8
|
-
let $state = $watch({
|
|
9
|
-
showNotification: false
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
@render {
|
|
13
|
-
<button type="button" onclick={() => ($state.showNotification = !$state.showNotification)}>
|
|
14
|
-
Show a notification
|
|
15
|
-
</button>
|
|
16
|
-
|
|
17
|
-
<Notification &visible={$state.showNotification}>
|
|
18
|
-
<NotificationContent>Here's a notification</NotificationContent>
|
|
19
|
-
<NotificationClose>Close me</NotificationClose>
|
|
20
|
-
</Notification>
|
|
21
|
-
}
|
|
22
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { getByText, queryByText } from "@testing-library/dom";
|
|
2
|
-
import "@testing-library/jest-dom/vitest";
|
|
3
|
-
import userEvent from "@testing-library/user-event";
|
|
4
|
-
import { mount } from "@torpor/view";
|
|
5
|
-
import { describe, expect, it } from "vitest";
|
|
6
|
-
import NotificationFunction from "./components/NotificationFunction.torp";
|
|
7
|
-
|
|
8
|
-
describe("Notification", () => {
|
|
9
|
-
it("Showing with a function", async () => {
|
|
10
|
-
const container = document.createElement("div");
|
|
11
|
-
document.body.appendChild(container);
|
|
12
|
-
mount(container, NotificationFunction);
|
|
13
|
-
|
|
14
|
-
// By default, the notification shouldn't be shown
|
|
15
|
-
expect(queryByText(container, "Here's a notification")).not.toBeInTheDocument();
|
|
16
|
-
|
|
17
|
-
// Clicking the button should show the notification
|
|
18
|
-
await userEvent.click(getByText(container, "Show a notification"));
|
|
19
|
-
expect(queryByText(container, "Here's a notification")).toBeInTheDocument();
|
|
20
|
-
|
|
21
|
-
// Clicking the close button should hide the notification
|
|
22
|
-
await userEvent.click(getByText(container, "Close me"));
|
|
23
|
-
expect(queryByText(container, "Here's a notification")).not.toBeInTheDocument();
|
|
24
|
-
});
|
|
25
|
-
});
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { getByText, queryByText } from "@testing-library/dom";
|
|
2
|
-
import "@testing-library/jest-dom/vitest";
|
|
3
|
-
import userEvent from "@testing-library/user-event";
|
|
4
|
-
import { mount } from "@torpor/view";
|
|
5
|
-
import { describe, expect, it } from "vitest";
|
|
6
|
-
import NotificationVariable from "./components/NotificationVariable.torp";
|
|
7
|
-
|
|
8
|
-
describe("Notification", () => {
|
|
9
|
-
it("Showing with a variable", async () => {
|
|
10
|
-
const container = document.createElement("div");
|
|
11
|
-
document.body.appendChild(container);
|
|
12
|
-
mount(container, NotificationVariable);
|
|
13
|
-
|
|
14
|
-
// By default, the notification shouldn't be shown
|
|
15
|
-
expect(queryByText(container, "Here's a notification")).not.toBeInTheDocument();
|
|
16
|
-
|
|
17
|
-
// Clicking the button should show the notification
|
|
18
|
-
await userEvent.click(getByText(container, "Show a notification"));
|
|
19
|
-
expect(queryByText(container, "Here's a notification")).toBeInTheDocument();
|
|
20
|
-
|
|
21
|
-
// Clicking the close button should hide the notification
|
|
22
|
-
await userEvent.click(getByText(container, "Close me"));
|
|
23
|
-
expect(queryByText(container, "Here's a notification")).not.toBeInTheDocument();
|
|
24
|
-
});
|
|
25
|
-
});
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { Popover, PopoverContent } from "../../../src/Popover/index";
|
|
2
|
-
import {
|
|
3
|
-
Dialog,
|
|
4
|
-
DialogBody,
|
|
5
|
-
DialogFooter,
|
|
6
|
-
DialogButton
|
|
7
|
-
} from "../../../src/Dialog/index";
|
|
8
|
-
|
|
9
|
-
export default function CustomDialog() {
|
|
10
|
-
@render {
|
|
11
|
-
<Popover visible {$props.callback}>
|
|
12
|
-
<PopoverContent>
|
|
13
|
-
<Dialog>
|
|
14
|
-
<DialogBody>
|
|
15
|
-
<p>Which color do you prefer?</p>
|
|
16
|
-
</DialogBody>
|
|
17
|
-
<DialogFooter>
|
|
18
|
-
<DialogButton value="blue">Blue</DialogButton>
|
|
19
|
-
<DialogButton value="red">Red</DialogButton>
|
|
20
|
-
</DialogFooter>
|
|
21
|
-
</Dialog>
|
|
22
|
-
</PopoverContent>
|
|
23
|
-
</Popover>
|
|
24
|
-
}
|
|
25
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { Popover, PopoverContent, showPopover } from "../../../src/Popover/index";
|
|
2
|
-
import {
|
|
3
|
-
Dialog,
|
|
4
|
-
DialogBody,
|
|
5
|
-
DialogFooter,
|
|
6
|
-
DialogButton
|
|
7
|
-
} from "../../../src/Dialog/index";
|
|
8
|
-
|
|
9
|
-
export default function PopoverFunction() {
|
|
10
|
-
let anchor;
|
|
11
|
-
|
|
12
|
-
async function show() {
|
|
13
|
-
showPopover(CustomDialog, anchor);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
@render {
|
|
17
|
-
<button type="button" &ref={anchor} onclick={show}>Show the prompt</button>
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function CustomDialog($props) {
|
|
22
|
-
@render {
|
|
23
|
-
<Popover visible {$props.anchor}>
|
|
24
|
-
<PopoverContent>
|
|
25
|
-
<Dialog>
|
|
26
|
-
<DialogBody>
|
|
27
|
-
<p>Which color do you prefer?</p>
|
|
28
|
-
</DialogBody>
|
|
29
|
-
<DialogFooter>
|
|
30
|
-
<DialogButton value="blue">Blue</DialogButton>
|
|
31
|
-
<DialogButton value="red">Red</DialogButton>
|
|
32
|
-
</DialogFooter>
|
|
33
|
-
</Dialog>
|
|
34
|
-
</PopoverContent>
|
|
35
|
-
</Popover>
|
|
36
|
-
}
|
|
37
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { Popover, PopoverContent, PopoverTrigger } from "../../../src/Popover/index";
|
|
2
|
-
import {
|
|
3
|
-
Dialog,
|
|
4
|
-
DialogBody,
|
|
5
|
-
DialogFooter,
|
|
6
|
-
DialogButton
|
|
7
|
-
} from "../../../src/Dialog/index";
|
|
8
|
-
|
|
9
|
-
export default function PopoverTriggerTest() {
|
|
10
|
-
let $state = $watch({
|
|
11
|
-
color: "",
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
@render {
|
|
15
|
-
@if ($state.color) {
|
|
16
|
-
<p>Your favorite color is {$state.color}?!</p>
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
<Popover &visible={$state.showPopover}>
|
|
20
|
-
<PopoverTrigger>
|
|
21
|
-
Show the prompt
|
|
22
|
-
</PopoverTrigger>
|
|
23
|
-
<PopoverContent>
|
|
24
|
-
<Dialog>
|
|
25
|
-
<DialogBody>
|
|
26
|
-
<p>Which color do you prefer?</p>
|
|
27
|
-
</DialogBody>
|
|
28
|
-
<DialogFooter>
|
|
29
|
-
<DialogButton value="blue" onclick={() => ($state.color = "blue")}>Blue</DialogButton>
|
|
30
|
-
<DialogButton value="red" onclick={() => ($state.color = "red")}>Red</DialogButton>
|
|
31
|
-
</DialogFooter>
|
|
32
|
-
</Dialog>
|
|
33
|
-
</PopoverContent>
|
|
34
|
-
</Popover>
|
|
35
|
-
}
|
|
36
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { Popover, PopoverContent } from "../../../src/Popover/index";
|
|
2
|
-
import {
|
|
3
|
-
Dialog,
|
|
4
|
-
DialogBody,
|
|
5
|
-
DialogFooter,
|
|
6
|
-
DialogButton
|
|
7
|
-
} from "../../../src/Dialog/index";
|
|
8
|
-
|
|
9
|
-
export default function PopoverVariable() {
|
|
10
|
-
let $state = $watch({
|
|
11
|
-
color: "",
|
|
12
|
-
showPopover: false
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
let button: HTMLButtonElement;
|
|
16
|
-
|
|
17
|
-
@render {
|
|
18
|
-
<button type="button" onclick={() => ($state.showPopover = !$state.showPopover)} &ref={button}>
|
|
19
|
-
Show the prompt
|
|
20
|
-
</button>
|
|
21
|
-
|
|
22
|
-
@if ($state.color) {
|
|
23
|
-
<p>Your favorite color is {$state.color}?!</p>
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
<Popover &visible={$state.showPopover} anchor={button}>
|
|
27
|
-
<PopoverContent>
|
|
28
|
-
<Dialog>
|
|
29
|
-
<DialogBody>
|
|
30
|
-
<p>Which color do you prefer?</p>
|
|
31
|
-
</DialogBody>
|
|
32
|
-
<DialogFooter>
|
|
33
|
-
<DialogButton value="blue" onclick={() => ($state.color = "blue")}>Blue</DialogButton>
|
|
34
|
-
<DialogButton value="red" onclick={() => ($state.color = "red")}>Red</DialogButton>
|
|
35
|
-
</DialogFooter>
|
|
36
|
-
</Dialog>
|
|
37
|
-
</PopoverContent>
|
|
38
|
-
</Popover>
|
|
39
|
-
}
|
|
40
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { getByText, queryByText } from "@testing-library/dom";
|
|
2
|
-
import "@testing-library/jest-dom/vitest";
|
|
3
|
-
import userEvent from "@testing-library/user-event";
|
|
4
|
-
import { mount } from "@torpor/view";
|
|
5
|
-
import { describe, expect, it } from "vitest";
|
|
6
|
-
import PopoverFunction from "./components/PopoverFunction.torp";
|
|
7
|
-
|
|
8
|
-
describe("Prompt", () => {
|
|
9
|
-
it("Showing with a function", async () => {
|
|
10
|
-
const container = document.createElement("div");
|
|
11
|
-
document.body.appendChild(container);
|
|
12
|
-
mount(container, PopoverFunction);
|
|
13
|
-
|
|
14
|
-
// By default, the prompt shouldn't be shown
|
|
15
|
-
expect(queryByText(container, "Which color do you prefer?")).not.toBeInTheDocument();
|
|
16
|
-
|
|
17
|
-
// Clicking the button should show the prompt
|
|
18
|
-
await userEvent.click(getByText(container, "Show the prompt"));
|
|
19
|
-
expect(queryByText(container, "Which color do you prefer?")).toBeInTheDocument();
|
|
20
|
-
});
|
|
21
|
-
});
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { getByText, queryByText } from "@testing-library/dom";
|
|
2
|
-
import "@testing-library/jest-dom/vitest";
|
|
3
|
-
import userEvent from "@testing-library/user-event";
|
|
4
|
-
import { mount } from "@torpor/view";
|
|
5
|
-
import { describe, expect, it } from "vitest";
|
|
6
|
-
import PopoverTrigger from "./components/PopoverTrigger.torp";
|
|
7
|
-
|
|
8
|
-
describe("Prompt", () => {
|
|
9
|
-
it("Showing with a trigger", async () => {
|
|
10
|
-
const container = document.createElement("div");
|
|
11
|
-
document.body.appendChild(container);
|
|
12
|
-
mount(container, PopoverTrigger);
|
|
13
|
-
|
|
14
|
-
// By default, the prompt shouldn't be shown
|
|
15
|
-
expect(queryByText(container, "Which color do you prefer?")).not.toBeInTheDocument();
|
|
16
|
-
expect(queryByText(container, "Your favorite color is blue?!")).not.toBeInTheDocument();
|
|
17
|
-
|
|
18
|
-
// Clicking the button should show the prompt
|
|
19
|
-
await userEvent.click(getByText(container, "Show the prompt"));
|
|
20
|
-
expect(queryByText(container, "Which color do you prefer?")).toBeInTheDocument();
|
|
21
|
-
|
|
22
|
-
// Clicking the blue button should hide the prompt and set the value
|
|
23
|
-
await userEvent.click(getByText(container, "Blue"));
|
|
24
|
-
expect(queryByText(container, "Which color do you prefer?")).not.toBeInTheDocument();
|
|
25
|
-
expect(queryByText(container, "Your favorite color is blue?!")).toBeInTheDocument();
|
|
26
|
-
});
|
|
27
|
-
});
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { getByText, queryByText } from "@testing-library/dom";
|
|
2
|
-
import "@testing-library/jest-dom/vitest";
|
|
3
|
-
import userEvent from "@testing-library/user-event";
|
|
4
|
-
import { mount } from "@torpor/view";
|
|
5
|
-
import { describe, expect, it } from "vitest";
|
|
6
|
-
import PopoverVariable from "./components/PopoverVariable.torp";
|
|
7
|
-
|
|
8
|
-
describe("Prompt", () => {
|
|
9
|
-
it("Showing with a variable", async () => {
|
|
10
|
-
const container = document.createElement("div");
|
|
11
|
-
document.body.appendChild(container);
|
|
12
|
-
mount(container, PopoverVariable);
|
|
13
|
-
|
|
14
|
-
// By default, the prompt shouldn't be shown
|
|
15
|
-
expect(queryByText(container, "Which color do you prefer?")).not.toBeInTheDocument();
|
|
16
|
-
expect(queryByText(container, "Your favorite color is blue?!")).not.toBeInTheDocument();
|
|
17
|
-
|
|
18
|
-
// Clicking the button should show the prompt
|
|
19
|
-
await userEvent.click(getByText(container, "Show the prompt"));
|
|
20
|
-
expect(queryByText(container, "Which color do you prefer?")).toBeInTheDocument();
|
|
21
|
-
|
|
22
|
-
// Clicking the blue button should hide the prompt and set the value
|
|
23
|
-
await userEvent.click(getByText(container, "Blue"));
|
|
24
|
-
expect(queryByText(container, "Which color do you prefer?")).not.toBeInTheDocument();
|
|
25
|
-
expect(queryByText(container, "Your favorite color is blue?!")).toBeInTheDocument();
|
|
26
|
-
});
|
|
27
|
-
});
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { queryByText } from "@testing-library/dom";
|
|
2
|
-
import "@testing-library/jest-dom/vitest";
|
|
3
|
-
import { mount } from "@torpor/view";
|
|
4
|
-
import { describe, expect, it } from "vitest";
|
|
5
|
-
import TabGroupAccessibility from "./components/TabGroupAccessibility.torp";
|
|
6
|
-
|
|
7
|
-
describe("TabGroup", () => {
|
|
8
|
-
it("Accessibility", async () => {
|
|
9
|
-
const container = document.createElement("div");
|
|
10
|
-
document.body.appendChild(container);
|
|
11
|
-
mount(container, TabGroupAccessibility, { value: "0" });
|
|
12
|
-
|
|
13
|
-
// Tests from https://www.w3.org/WAI/ARIA/apg/patterns/tabs/
|
|
14
|
-
|
|
15
|
-
// The element that serves as the container for the set of tabs has role
|
|
16
|
-
// tablist
|
|
17
|
-
expect(queryByText(container, "Header 1")?.parentElement?.parentElement).toHaveAttribute(
|
|
18
|
-
"role",
|
|
19
|
-
"tablist",
|
|
20
|
-
);
|
|
21
|
-
|
|
22
|
-
// Each element that serves as a tab has role tab and is contained
|
|
23
|
-
// within the element with role tablist
|
|
24
|
-
expect(queryByText(container, "Header 1")).toHaveAttribute("role", "tab");
|
|
25
|
-
|
|
26
|
-
// Each element that contains the content panel for a tab has role
|
|
27
|
-
// tabpanel
|
|
28
|
-
expect(queryByText(container, "Body 1")).toHaveAttribute("role", "tabpanel");
|
|
29
|
-
|
|
30
|
-
// If the tab list has a visible label, the element with role tablist
|
|
31
|
-
// has aria-labelledby set to a value that refers to the labelling
|
|
32
|
-
// element. Otherwise, the tablist element has a label provided by
|
|
33
|
-
// aria-label
|
|
34
|
-
// NOTE: We only support aria-label and it's required
|
|
35
|
-
expect(queryByText(container, "Header 1")?.parentElement?.parentElement).toHaveAttribute(
|
|
36
|
-
"aria-label",
|
|
37
|
-
"Example tabs",
|
|
38
|
-
);
|
|
39
|
-
|
|
40
|
-
// Each element with role tab has the property aria-controls referring
|
|
41
|
-
// to its associated tabpanel element
|
|
42
|
-
const tabId = queryByText(container, "Header 1")?.id;
|
|
43
|
-
const contentId = queryByText(container, "Body 1")?.id;
|
|
44
|
-
expect(queryByText(container, "Header 1")).toHaveAttribute("aria-controls", contentId);
|
|
45
|
-
|
|
46
|
-
// The active tab element has the state aria-selected set to true and
|
|
47
|
-
// all other tab elements have it set to false
|
|
48
|
-
expect(queryByText(container, "Header 1")).toHaveAttribute("aria-selected", "true");
|
|
49
|
-
expect(queryByText(container, "Header 2")).toHaveAttribute("aria-selected", "false");
|
|
50
|
-
expect(queryByText(container, "Header 3")).toHaveAttribute("aria-selected", "false");
|
|
51
|
-
|
|
52
|
-
// Each element with role tabpanel has the property aria-labelledby
|
|
53
|
-
// referring to its associated tab element
|
|
54
|
-
expect(queryByText(container, "Body 1")).toHaveAttribute("aria-labelledby", tabId);
|
|
55
|
-
|
|
56
|
-
// If a tab element has a popup menu, it has the property aria-haspopup
|
|
57
|
-
// set to either menu or true
|
|
58
|
-
|
|
59
|
-
// If the tablist element is vertically oriented, it has the property
|
|
60
|
-
// aria-orientation set to vertical. The default value of
|
|
61
|
-
// aria-orientation for a tablist element is horizontal
|
|
62
|
-
expect(queryByText(container, "Header 1")?.parentElement?.parentElement).toHaveAttribute(
|
|
63
|
-
"aria-orientation",
|
|
64
|
-
"horizontal",
|
|
65
|
-
);
|
|
66
|
-
});
|
|
67
|
-
});
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
TabGroup,
|
|
3
|
-
TabList,
|
|
4
|
-
TabHeader,
|
|
5
|
-
TabTrigger,
|
|
6
|
-
TabContent,
|
|
7
|
-
} from "../../../src/TabGroup/index";
|
|
8
|
-
|
|
9
|
-
export default function TabGroupAccessibility() {
|
|
10
|
-
@render {
|
|
11
|
-
<TabGroup value={$props?.value}>
|
|
12
|
-
<TabList ariaLabel="Example tabs">
|
|
13
|
-
<TabHeader as="h4">
|
|
14
|
-
<TabTrigger>Header 1</TabTrigger>
|
|
15
|
-
</TabHeader>
|
|
16
|
-
<TabHeader as="h4">
|
|
17
|
-
<TabTrigger>Header 2</TabTrigger>
|
|
18
|
-
</TabHeader>
|
|
19
|
-
<TabHeader as="h4">
|
|
20
|
-
<TabTrigger>Header 3</TabTrigger>
|
|
21
|
-
</TabHeader>
|
|
22
|
-
</TabList>
|
|
23
|
-
<TabContent>Body 1</TabContent>
|
|
24
|
-
<TabContent>Body 2</TabContent>
|
|
25
|
-
<TabContent>Body 3</TabContent>
|
|
26
|
-
</TabGroup>
|
|
27
|
-
}
|
|
28
|
-
}
|