From fd71ad98660fce3dd06c6dc2fa01e913ae7c3992 Mon Sep 17 00:00:00 2001 From: Segun Adebayo Date: Tue, 19 Sep 2023 10:17:03 +0100 Subject: [PATCH] refactor: ensure consistent *item naming convention (#882) --- .changeset/happy-starfishes-argue.md | 40 +++++++++ e2e/rating-group.e2e.ts | 2 +- e2e/tags-input.e2e.ts | 2 +- e2e/toggle-group.e2e.ts | 88 +++++++++++++++++++ examples/next-ts/pages/accordion.tsx | 4 +- examples/next-ts/pages/radio-group.tsx | 8 +- examples/next-ts/pages/rating-group.tsx | 4 +- examples/next-ts/pages/segment-control.tsx | 6 +- examples/next-ts/pages/tags-input.tsx | 6 +- examples/next-ts/pages/toggle-group.tsx | 4 +- examples/nuxt-ts/components/HalfStar.vue | 16 ++++ examples/nuxt-ts/components/Star.vue | 8 ++ examples/nuxt-ts/pages/accordion.vue | 4 +- examples/nuxt-ts/pages/radio-group.vue | 8 +- examples/nuxt-ts/pages/rating-group.vue | 42 +-------- examples/nuxt-ts/pages/segment-control.vue | 6 +- examples/nuxt-ts/pages/tags-input.vue | 6 +- examples/nuxt-ts/pages/toggle-group.vue | 2 +- examples/solid-ts/src/pages/accordion.tsx | 4 +- examples/solid-ts/src/pages/radio-group.tsx | 8 +- examples/solid-ts/src/pages/rating-group.tsx | 4 +- examples/solid-ts/src/pages/tags-input.tsx | 6 +- examples/solid-ts/src/pages/toggle-group.tsx | 2 +- examples/vue-ts/src/pages/accordion.tsx | 4 +- examples/vue-ts/src/pages/radio-group.tsx | 8 +- examples/vue-ts/src/pages/rating-group.tsx | 4 +- examples/vue-ts/src/pages/segment-control.tsx | 6 +- examples/vue-ts/src/pages/tags-input.tsx | 6 +- examples/vue-ts/src/pages/toggle-group.tsx | 2 +- .../accordion/src/accordion.anatomy.ts | 2 +- .../accordion/src/accordion.connect.ts | 28 ++++-- .../machines/accordion/src/accordion.dom.ts | 8 +- .../machines/accordion/src/accordion.types.ts | 5 +- .../machines/checkbox/src/checkbox.anatomy.ts | 2 +- .../machines/checkbox/src/checkbox.connect.ts | 6 ++ .../machines/checkbox/src/checkbox.types.ts | 1 + packages/machines/menu/src/menu.anatomy.ts | 1 + packages/machines/menu/src/menu.connect.ts | 5 ++ packages/machines/menu/src/menu.types.ts | 1 + .../machines/popover/src/popover.anatomy.ts | 2 + .../machines/popover/src/popover.connect.ts | 5 ++ .../machines/popover/src/popover.types.ts | 1 + packages/machines/radio-group/src/index.ts | 7 +- .../radio-group/src/radio-group.anatomy.ts | 7 +- .../radio-group/src/radio-group.connect.ts | 60 ++++++------- .../radio-group/src/radio-group.dom.ts | 22 ++--- .../radio-group/src/radio-group.types.ts | 23 +++-- .../rating-group/src/rating-group.anatomy.ts | 2 +- .../rating-group/src/rating-group.connect.ts | 15 ++-- .../rating-group/src/rating-group.dom.ts | 2 +- .../rating-group/src/rating-group.types.ts | 4 +- .../machines/select/src/select.anatomy.ts | 1 + .../machines/select/src/select.connect.ts | 6 ++ packages/machines/select/src/select.types.ts | 1 + .../tags-input/src/tags-input.anatomy.ts | 7 +- .../tags-input/src/tags-input.connect.ts | 66 ++++++++------ .../machines/tags-input/src/tags-input.dom.ts | 18 ++-- .../tags-input/src/tags-input.types.ts | 19 ++-- .../toggle-group/src/toggle-group.anatomy.ts | 2 +- .../toggle-group/src/toggle-group.connect.ts | 58 +++++++----- .../toggle-group/src/toggle-group.dom.ts | 3 +- .../toggle-group/src/toggle-group.machine.ts | 2 +- .../toggle-group/src/toggle-group.types.ts | 15 +++- shared/src/style.css | 61 +++++-------- website/components/machines/accordion.tsx | 4 +- website/components/machines/combobox.tsx | 18 ++-- website/components/machines/radio.tsx | 11 +-- website/components/machines/rating.tsx | 4 +- .../components/machines/segmented-control.tsx | 6 +- website/components/machines/tags-input.tsx | 6 +- website/components/machines/toggle-group.tsx | 6 +- website/data/components/accordion.mdx | 16 ++-- .../data/snippets/react/accordion/usage.mdx | 4 +- .../data/snippets/react/radio-group/usage.mdx | 10 +-- .../snippets/react/rating-group/usage.mdx | 4 +- .../react/segmented-control/usage.mdx | 6 +- .../data/snippets/react/tags-input/usage.mdx | 6 +- .../snippets/react/toggle-group/usage.mdx | 6 +- .../data/snippets/solid/accordion/usage.mdx | 4 +- .../data/snippets/solid/radio-group/usage.mdx | 8 +- .../snippets/solid/rating-group/usage.mdx | 4 +- .../solid/segmented-control/usage.mdx | 6 +- .../data/snippets/solid/tags-input/usage.mdx | 6 +- .../snippets/solid/toggle-group/usage.mdx | 6 +- .../data/snippets/vue-jsx/accordion/usage.mdx | 4 +- .../snippets/vue-jsx/radio-group/usage.mdx | 8 +- .../snippets/vue-jsx/rating-group/usage.mdx | 4 +- .../vue-jsx/segmented-control/usage.mdx | 6 +- .../snippets/vue-jsx/tags-input/usage.mdx | 6 +- .../snippets/vue-jsx/toggle-group/usage.mdx | 6 +- .../data/snippets/vue-sfc/accordion/usage.mdx | 4 +- .../snippets/vue-sfc/radio-group/usage.mdx | 8 +- .../snippets/vue-sfc/rating-group/usage.mdx | 4 +- .../vue-sfc/segmented-control/usage.mdx | 6 +- .../snippets/vue-sfc/tags-input/usage.mdx | 6 +- .../snippets/vue-sfc/toggle-group/usage.mdx | 6 +- 96 files changed, 583 insertions(+), 404 deletions(-) create mode 100644 .changeset/happy-starfishes-argue.md create mode 100644 e2e/toggle-group.e2e.ts create mode 100644 examples/nuxt-ts/components/HalfStar.vue create mode 100644 examples/nuxt-ts/components/Star.vue diff --git a/.changeset/happy-starfishes-argue.md b/.changeset/happy-starfishes-argue.md new file mode 100644 index 0000000000..dc49f2e6ba --- /dev/null +++ b/.changeset/happy-starfishes-argue.md @@ -0,0 +1,40 @@ +--- +"@zag-js/rating-group": minor +"@zag-js/toggle-group": minor +"@zag-js/radio-group": minor +"@zag-js/tags-input": minor +"@zag-js/accordion": minor +"@zag-js/checkbox": minor +"@zag-js/popover": minor +"@zag-js/select": minor +"@zag-js/menu": minor +--- + +- Refactor component anatomy to use consistent naming convention across all machines. + + - **Accordion** + + - `getTriggerProps` => `getItemTriggerProps` + - `getContentProps` => `getItemContentProps` + + - **Radio** + + - `getRadioProps` => `getItemProps` + - `getRadioControlProps` => `getItemControlProps` + - `getRadioLabelProps` => `getItemTextProps` + - `getRatingState` => `getItemState` + - `getRatingProps` => `getItemProps` + + - **TagsInput** + + - `getTagProps` => `getItemProps` + - `getTagDeleteTriggerProps` => `getItemDeleteTriggerProps` + - `getTagInputProps` => `getItemInputProps` + + - **Toggle Group** + - `getToggleProps` => `getItemProps` + +- **ToggleGroup**: Allow deselecting item when `multiple` is `false`. + +- Add indicator part to some components for ease of styling. Added `AccordionItemIndicator`, `SelectIndicator`, + `MenuIndicator`, `PopoverIndicator` diff --git a/e2e/rating-group.e2e.ts b/e2e/rating-group.e2e.ts index 02721a134b..244915564e 100644 --- a/e2e/rating-group.e2e.ts +++ b/e2e/rating-group.e2e.ts @@ -3,7 +3,7 @@ import { a11y, controls as testControls, part, testid } from "./__utils" const control = part("control") const hiddenInput = testid("hidden-input") -const rating = part("rating") +const rating = part("item") const getRating = (page: Page, value: number) => { return page.locator(rating).nth(value - 1) diff --git a/e2e/tags-input.e2e.ts b/e2e/tags-input.e2e.ts index 0539799c07..40e2930ad1 100644 --- a/e2e/tags-input.e2e.ts +++ b/e2e/tags-input.e2e.ts @@ -98,7 +98,7 @@ test.describe("tags-input", () => { await page.keyboard.press("ArrowLeft") await page.click("body", { force: true }) - expect(await page.locator("[data-part=tag][data-selected]").count()).toBe(0) + expect(await page.locator("[data-part=item][data-selected]").count()).toBe(0) }) test("removes tag on close button click", async ({ page }) => { diff --git a/e2e/toggle-group.e2e.ts b/e2e/toggle-group.e2e.ts new file mode 100644 index 0000000000..8c44e71e2d --- /dev/null +++ b/e2e/toggle-group.e2e.ts @@ -0,0 +1,88 @@ +import { expect, type Page, test, type Locator } from "@playwright/test" +import { a11y, controls, part } from "./__utils" + +class PageModel { + constructor(public readonly page: Page) {} + get bold() { + return this.page.locator(part("item")).nth(0) + } + get italic() { + return this.page.locator(part("item")).nth(1) + } + get underline() { + return this.page.locator(part("item")).nth(2) + } + expectToBeFocused(locator: Locator) { + return expect(locator).toHaveAttribute("data-highlighted", "") + } + expectNotToBeFocused(locator: Locator) { + return expect(locator).not.toHaveAttribute("data-highlighted", "") + } + expectToBeSelected(locator: Locator) { + return expect(locator).toHaveAttribute("data-state", "on") + } + expectNotToBeSelected(locator: Locator) { + return expect(locator).not.toHaveAttribute("data-state", "on") + } + setMultiple() { + return controls(this.page).bool("multiple") + } +} + +test.describe("toggle-group", () => { + test.beforeEach(async ({ page }) => { + await page.goto("/toggle-group") + }) + + test("should have no accessibility violation", async ({ page }) => { + await a11y(page) + }) + + test("[single] should select on click", async ({ page }) => { + const screen = new PageModel(page) + + await screen.bold.click() + await screen.expectToBeSelected(screen.bold) + + await screen.italic.click() + await screen.expectToBeSelected(screen.italic) + await screen.expectNotToBeSelected(screen.bold) + }) + + test("[single] should select and deselect", async ({ page }) => { + const screen = new PageModel(page) + + await screen.bold.click() + await screen.expectToBeSelected(screen.bold) + + await screen.bold.click() + await screen.expectNotToBeSelected(screen.bold) + }) + + test("[multiple] should select multiple", async ({ page }) => { + const screen = new PageModel(page) + await screen.setMultiple() + + await screen.bold.click() + await screen.italic.click() + + await screen.expectToBeSelected(screen.bold) + await screen.expectToBeSelected(screen.italic) + }) + + test("[keyboard] when no toggle is selected, focus first toggle", async ({ page }) => { + const screen = new PageModel(page) + + // focus on outside button + const outsideButton = page.getByRole("button", { name: "Outside" }) + await outsideButton.focus() + await page.keyboard.press("Tab") + + await expect(screen.bold).toBeFocused() + + // shift tab back to outside button + await page.keyboard.press("Shift+Tab") + await expect(screen.bold).not.toBeFocused() + await expect(outsideButton).toBeFocused() + }) +}) diff --git a/examples/next-ts/pages/accordion.tsx b/examples/next-ts/pages/accordion.tsx index 9e7ba7891a..efa57d910d 100644 --- a/examples/next-ts/pages/accordion.tsx +++ b/examples/next-ts/pages/accordion.tsx @@ -27,11 +27,11 @@ export default function Page() { {accordionData.map((item) => (

-

-
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
diff --git a/examples/next-ts/pages/radio-group.tsx b/examples/next-ts/pages/radio-group.tsx index 7313db72e8..580b81915d 100644 --- a/examples/next-ts/pages/radio-group.tsx +++ b/examples/next-ts/pages/radio-group.tsx @@ -29,12 +29,12 @@ export default function Page() {

Fruits

{radioData.map((opt) => ( -