Directory structure:
└── radix-ui-primitives/
    ├── README.md
    ├── CODE_OF_CONDUCT.md
    ├── context7.json
    ├── cypress.config.ts
    ├── eslint.config.mjs
    ├── LICENSE
    ├── package.json
    ├── philosophy.md
    ├── pnpm-workspace.yaml
    ├── release-process.md
    ├── vitest.config.mts
    ├── .editorconfig
    ├── .nvmrc
    ├── .prettierignore
    ├── .prettierrc
    ├── apps/
    │   ├── ssr-testing/
    │   │   ├── README.md
    │   │   ├── next-env.d.ts
    │   │   ├── next.config.js
    │   │   ├── package.json
    │   │   ├── tsconfig.json
    │   │   └── app/
    │   │       ├── layout.tsx
    │   │       ├── page.tsx
    │   │       ├── accessible-icon/
    │   │       │   └── page.tsx
    │   │       ├── accordion/
    │   │       │   └── page.tsx
    │   │       ├── alert-dialog/
    │   │       │   └── page.tsx
    │   │       ├── avatar/
    │   │       │   └── page.tsx
    │   │       ├── checkbox/
    │   │       │   └── page.tsx
    │   │       ├── collapsible/
    │   │       │   └── page.tsx
    │   │       ├── context-menu/
    │   │       │   └── page.tsx
    │   │       ├── dialog/
    │   │       │   └── page.tsx
    │   │       ├── dropdown-menu/
    │   │       │   └── page.tsx
    │   │       ├── form/
    │   │       │   └── page.tsx
    │   │       ├── hover-card/
    │   │       │   └── page.tsx
    │   │       ├── label/
    │   │       │   └── page.tsx
    │   │       ├── menubar/
    │   │       │   └── page.tsx
    │   │       ├── navigation-menu/
    │   │       │   └── page.tsx
    │   │       ├── one-time-password-field/
    │   │       │   └── page.tsx
    │   │       ├── password-toggle-field/
    │   │       │   └── page.tsx
    │   │       ├── popover/
    │   │       │   └── page.tsx
    │   │       ├── portal/
    │   │       │   ├── conditional-portal.tsx
    │   │       │   ├── custom-portal-container.tsx
    │   │       │   └── page.tsx
    │   │       ├── progress/
    │   │       │   └── page.tsx
    │   │       ├── radio-group/
    │   │       │   └── page.tsx
    │   │       ├── roving-focus-group/
    │   │       │   ├── page.tsx
    │   │       │   └── roving-focus.client.tsx
    │   │       ├── scroll-area/
    │   │       │   └── page.tsx
    │   │       ├── select/
    │   │       │   └── page.tsx
    │   │       ├── separator/
    │   │       │   └── page.tsx
    │   │       ├── slider/
    │   │       │   └── page.tsx
    │   │       ├── slot/
    │   │       │   └── page.tsx
    │   │       ├── switch/
    │   │       │   └── page.tsx
    │   │       ├── tabs/
    │   │       │   └── page.tsx
    │   │       ├── toast/
    │   │       │   └── page.tsx
    │   │       ├── toggle-group/
    │   │       │   └── page.tsx
    │   │       ├── toolbar/
    │   │       │   └── page.tsx
    │   │       ├── tooltip/
    │   │       │   └── page.tsx
    │   │       └── visually-hidden/
    │   │           └── page.tsx
    │   └── storybook/
    │       ├── eslint.config.js
    │       ├── index.d.ts
    │       ├── package.json
    │       ├── tsconfig.json
    │       ├── stories/
    │       │   ├── accessible-icon.stories.tsx
    │       │   ├── accordion.stories.module.css
    │       │   ├── accordion.stories.tsx
    │       │   ├── alert-dialog.stories.module.css
    │       │   ├── alert-dialog.stories.tsx
    │       │   ├── arrow.stories.tsx
    │       │   ├── aspect-ratio.stories.module.css
    │       │   ├── aspect-ratio.stories.tsx
    │       │   ├── avatar.stories.module.css
    │       │   ├── avatar.stories.tsx
    │       │   ├── checkbox.stories.module.css
    │       │   ├── checkbox.stories.tsx
    │       │   ├── collapsible.stories.module.css
    │       │   ├── collapsible.stories.tsx
    │       │   ├── collection.stories.tsx
    │       │   ├── context-menu.stories.module.css
    │       │   ├── context-menu.stories.tsx
    │       │   ├── dialog.stories.module.css
    │       │   ├── dialog.stories.tsx
    │       │   ├── dismissable-layer.stories.tsx
    │       │   ├── dropdown-menu.stories.module.css
    │       │   ├── focus-scope.stories.tsx
    │       │   ├── form.stories.module.css
    │       │   ├── form.stories.tsx
    │       │   ├── hover-card.stories.module.css
    │       │   ├── hover-card.stories.tsx
    │       │   ├── label.stories.module.css
    │       │   ├── label.stories.tsx
    │       │   ├── menu.stories.module.css
    │       │   ├── menu.stories.tsx
    │       │   ├── menubar.stories.module.css
    │       │   ├── menubar.stories.tsx
    │       │   ├── navigation-menu.stories.module.css
    │       │   ├── navigation-menu.stories.tsx
    │       │   ├── one-time-password-field.stories.module.css
    │       │   ├── one-time-password-field.stories.tsx
    │       │   ├── password-toggle-field.stories.module.css
    │       │   ├── password-toggle-field.stories.tsx
    │       │   ├── popover.stories.module.css
    │       │   ├── popover.stories.tsx
    │       │   ├── popper.stories.module.css
    │       │   ├── popper.stories.tsx
    │       │   ├── portal.stories.tsx
    │       │   ├── presence.stories.module.css
    │       │   ├── presence.stories.tsx
    │       │   ├── progress.stories.module.css
    │       │   ├── progress.stories.tsx
    │       │   ├── radio-group.stories.module.css
    │       │   ├── radio-group.stories.tsx
    │       │   ├── roving-focus-group.stories.tsx
    │       │   ├── scroll-area.stories.module.css
    │       │   ├── scroll-area.stories.tsx
    │       │   ├── select.stories.module.css
    │       │   ├── select.stories.tsx
    │       │   ├── separator.stories.module.css
    │       │   ├── separator.stories.tsx
    │       │   ├── slider.stories.module.css
    │       │   ├── slider.stories.tsx
    │       │   ├── slot.stories.tsx
    │       │   ├── switch.stories.module.css
    │       │   ├── switch.stories.tsx
    │       │   ├── tabs.stories.module.css
    │       │   ├── tabs.stories.tsx
    │       │   ├── toast.stories.module.css
    │       │   ├── toast.stories.tsx
    │       │   ├── toggle-group.stories.module.css
    │       │   ├── toggle-group.stories.tsx
    │       │   ├── toggle.stories.module.css
    │       │   ├── toggle.stories.tsx
    │       │   ├── toolbar.stories.module.css
    │       │   ├── toolbar.stories.tsx
    │       │   ├── tooltip.stories.module.css
    │       │   ├── tooltip.stories.tsx
    │       │   └── visually-hidden.stories.tsx
    │       └── .storybook/
    │           ├── main.ts
    │           ├── manager-head.html
    │           ├── manager.ts
    │           ├── preview.css
    │           └── preview.ts
    ├── cypress/
    │   ├── tsconfig.json
    │   ├── e2e/
    │   │   ├── ContextMenu.cy.ts
    │   │   ├── Dialog.cy.ts
    │   │   ├── DropdownMenu.cy.ts
    │   │   ├── Form.cy.ts
    │   │   ├── Menubar.cy.ts
    │   │   ├── Select.cy.ts
    │   │   └── Toast.cy.ts
    │   └── support/
    │       ├── commands.js
    │       ├── e2e.js
    │       └── index.d.ts
    ├── internal/
    │   ├── builder/
    │   │   ├── builder.js
    │   │   ├── eslint.config.js
    │   │   ├── package.json
    │   │   ├── radix-build.js
    │   │   └── tsconfig.json
    │   ├── eslint-config/
    │   │   ├── eslint.config.js
    │   │   ├── index.js
    │   │   ├── package.json
    │   │   ├── react-package.js
    │   │   ├── tsconfig.json
    │   │   └── vite.js
    │   ├── test-data/
    │   │   ├── eslint.config.js
    │   │   ├── foods.ts
    │   │   ├── package.json
    │   │   └── tsconfig.json
    │   └── typescript-config/
    │       ├── base.json
    │       ├── nextjs.json
    │       ├── package.json
    │       ├── react-library.json
    │       ├── vite-app.json
    │       ├── vite-node.json
    │       └── react-library/
    │           └── index.d.ts
    ├── packages/
    │   ├── core/
    │   │   ├── number/
    │   │   │   ├── README.md
    │   │   │   ├── eslint.config.mjs
    │   │   │   ├── package.json
    │   │   │   ├── tsconfig.json
    │   │   │   └── src/
    │   │   │       ├── index.ts
    │   │   │       └── number.ts
    │   │   ├── primitive/
    │   │   │   ├── README.md
    │   │   │   ├── CHANGELOG.md
    │   │   │   ├── eslint.config.mjs
    │   │   │   ├── package.json
    │   │   │   ├── tsconfig.json
    │   │   │   └── src/
    │   │   │       ├── index.ts
    │   │   │       ├── primitive.tsx
    │   │   │       └── types.ts
    │   │   └── rect/
    │   │       ├── README.md
    │   │       ├── eslint.config.mjs
    │   │       ├── package.json
    │   │       ├── tsconfig.json
    │   │       └── src/
    │   │           ├── index.ts
    │   │           └── observe-element-rect.ts
    │   └── react/
    │       ├── accessible-icon/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── accesible-icon.test.tsx
    │       │       ├── accessible-icon.tsx
    │       │       └── index.ts
    │       ├── accordion/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── accordion.test.tsx
    │       │       ├── accordion.tsx
    │       │       └── index.ts
    │       ├── alert-dialog/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── alert-dialog.test.tsx
    │       │       ├── alert-dialog.tsx
    │       │       └── index.ts
    │       ├── announce/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── announce.tsx
    │       │       └── index.ts
    │       ├── arrow/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── arrow.test.tsx
    │       │       ├── arrow.tsx
    │       │       └── index.ts
    │       ├── aspect-ratio/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── aspect-ratio.test.tsx
    │       │       ├── aspect-ratio.tsx
    │       │       └── index.ts
    │       ├── avatar/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── avatar.test.tsx
    │       │       ├── avatar.tsx
    │       │       └── index.ts
    │       ├── checkbox/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── checkbox.test.tsx
    │       │       ├── checkbox.tsx
    │       │       └── index.ts
    │       ├── collapsible/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── collapsible.test.tsx
    │       │       ├── collapsible.tsx
    │       │       └── index.ts
    │       ├── collection/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── collection-legacy.tsx
    │       │       ├── collection.tsx
    │       │       ├── index.ts
    │       │       ├── ordered-dictionary.test.ts
    │       │       └── ordered-dictionary.ts
    │       ├── compose-refs/
    │       │   ├── README.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── compose-refs.tsx
    │       │       └── index.ts
    │       ├── context/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── create-context.tsx
    │       │       └── index.ts
    │       ├── context-menu/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── context-menu.tsx
    │       │       └── index.ts
    │       ├── dialog/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── dialog.test.tsx
    │       │       ├── dialog.tsx
    │       │       └── index.ts
    │       ├── direction/
    │       │   ├── README.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── direction.tsx
    │       │       └── index.ts
    │       ├── dismissable-layer/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── dismissable-layer.tsx
    │       │       └── index.ts
    │       ├── dropdown-menu/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── dropdown-menu.tsx
    │       │       └── index.ts
    │       ├── focus-guards/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── focus-guards.tsx
    │       │       └── index.ts
    │       ├── focus-scope/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── focus-scope.test.tsx
    │       │       ├── focus-scope.tsx
    │       │       └── index.ts
    │       ├── form/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── form.tsx
    │       │       └── index.ts
    │       ├── hover-card/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── hover-card.tsx
    │       │       └── index.ts
    │       ├── id/
    │       │   ├── README.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── id.tsx
    │       │       └── index.ts
    │       ├── label/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── index.ts
    │       │       └── label.tsx
    │       ├── menu/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       └── index.ts
    │       ├── menubar/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── index.ts
    │       │       └── menubar.tsx
    │       ├── navigation-menu/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── index.ts
    │       │       └── navigation-menu.tsx
    │       ├── one-time-password-field/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── index.ts
    │       │       ├── one-time-password-field.test.tsx
    │       │       └── one-time-password-field.tsx
    │       ├── password-toggle-field/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── index.ts
    │       │       ├── password-toggle-field.test.tsx
    │       │       └── password-toggle-field.tsx
    │       ├── popover/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── index.ts
    │       │       └── popover.tsx
    │       ├── popper/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── index.ts
    │       │       └── popper.tsx
    │       ├── portal/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── index.ts
    │       │       └── portal.tsx
    │       ├── presence/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── index.ts
    │       │       ├── presence.tsx
    │       │       └── use-state-machine.tsx
    │       ├── primitive/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── index.ts
    │       │       └── primitive.tsx
    │       ├── progress/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── index.ts
    │       │       └── progress.tsx
    │       ├── radio-group/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── index.ts
    │       │       ├── radio-group.tsx
    │       │       └── radio.tsx
    │       ├── radix-ui/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── index.ts
    │       │       └── internal.ts
    │       ├── roving-focus/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── index.ts
    │       │       └── roving-focus-group.tsx
    │       ├── scroll-area/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── index.ts
    │       │       ├── scroll-area.tsx
    │       │       └── use-state-machine.ts
    │       ├── select/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       └── index.ts
    │       ├── separator/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── index.ts
    │       │       └── separator.tsx
    │       ├── slider/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── index.ts
    │       │       └── slider.tsx
    │       ├── slot/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── index.ts
    │       │       ├── slot.test.tsx
    │       │       ├── slot.tsx
    │       │       └── __snapshots__/
    │       │           └── slot.test.tsx.snap
    │       ├── switch/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── index.ts
    │       │       ├── switch.test.tsx
    │       │       └── switch.tsx
    │       ├── tabs/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── index.ts
    │       │       └── tabs.tsx
    │       ├── toast/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── index.ts
    │       │       └── toast.tsx
    │       ├── toggle/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── index.ts
    │       │       ├── toggle.test.tsx
    │       │       └── toggle.tsx
    │       ├── toggle-group/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── index.ts
    │       │       ├── toggle-group.test.tsx
    │       │       └── toggle-group.tsx
    │       ├── toolbar/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── index.ts
    │       │       ├── toolbar.test.tsx
    │       │       └── toolbar.tsx
    │       ├── tooltip/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── index.ts
    │       │       ├── tooltip.test.tsx
    │       │       └── tooltip.tsx
    │       ├── use-callback-ref/
    │       │   ├── README.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── index.ts
    │       │       └── use-callback-ref.tsx
    │       ├── use-controllable-state/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── index.ts
    │       │       ├── use-controllable-state-reducer.tsx
    │       │       ├── use-controllable-state.test.tsx
    │       │       └── use-controllable-state.tsx
    │       ├── use-effect-event/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── index.ts
    │       │       └── use-effect-event.tsx
    │       ├── use-escape-keydown/
    │       │   ├── README.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── index.ts
    │       │       └── use-escape-keydown.tsx
    │       ├── use-is-hydrated/
    │       │   ├── README.md
    │       │   ├── CHANGELOG.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── index.ts
    │       │       └── use-is-hydrated.tsx
    │       ├── use-layout-effect/
    │       │   ├── README.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── index.ts
    │       │       └── use-layout-effect.tsx
    │       ├── use-previous/
    │       │   ├── README.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── index.ts
    │       │       └── use-previous.tsx
    │       ├── use-rect/
    │       │   ├── README.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── index.ts
    │       │       └── use-rect.tsx
    │       ├── use-size/
    │       │   ├── README.md
    │       │   ├── eslint.config.mjs
    │       │   ├── package.json
    │       │   ├── tsconfig.json
    │       │   └── src/
    │       │       ├── index.ts
    │       │       └── use-size.tsx
    │       └── visually-hidden/
    │           ├── README.md
    │           ├── CHANGELOG.md
    │           ├── eslint.config.mjs
    │           ├── package.json
    │           ├── tsconfig.json
    │           └── src/
    │               ├── index.ts
    │               └── visually-hidden.tsx
    ├── patches/
    │   └── @changesets__apply-release-plan.patch
    ├── scripts/
    │   └── setup-tests.ts
    ├── types/
    │   ├── global.d.ts
    │   └── index.d.ts
    ├── .changeset/
    │   ├── README.md
    │   ├── changelog.cjs
    │   ├── config.json
    │   ├── silent-turkeys-fly.md
    │   └── ten-pumas-agree.md
    └── .github/
        ├── CODEOWNERS
        ├── CONTRIBUTING.md
        ├── PULL_REQUEST_TEMPLATE.md
        ├── ISSUE_TEMPLATE/
        │   ├── Bug_report.md
        │   ├── Documentation.md
        │   ├── Feature_request.md
        │   └── Question.md
        └── workflows/
            ├── build.yml
            ├── chromatic.yml
            ├── publish-snapshot.yml
            └── publish-stable.yml

================================================
FILE: README.md
================================================
[![Radix Primitives Logo](primitives.png)](https://radix-ui.com/primitives)

# Radix Primitives

**An open-source UI component library for building high-quality, accessible design systems and web apps.**

Radix Primitives is a low-level UI component library with a focus on accessibility, customization and developer experience. You can use these components either as the base layer of your design system, or adopt them incrementally.

---

## Installation

First, install pnpm if you haven't already. Open your terminal and run:

```bash
npm install -g pnpm
```

Then, install the dependencies:

```bash
pnpm install
```

## Documentation

For full documentation, visit [radix-ui.com/primitives/docs](https://www.radix-ui.com/primitives/docs).

## Releases

For changelog, visit [radix-ui.com/primitives/docs/overview/releases](https://www.radix-ui.com/primitives/docs/overview/releases).

## Contributing

Please follow our [contributing guidelines](./.github/CONTRIBUTING.md).

---

## Community

- [Discord](https://discord.com/invite/7Xb99uG) - To get involved with the Radix community, ask questions and share tips.
- [Twitter](https://twitter.com/radix_ui) - To receive updates, announcements, blog posts, and general Radix tips.

## Thanks

<a href="https://www.chromatic.com/"><img src="https://user-images.githubusercontent.com/321738/84662277-e3db4f80-af1b-11ea-88f5-91d67a5e59f6.png" width="153" height="30" alt="Chromatic" /></a>

Thanks to [Chromatic](https://www.chromatic.com/) for providing the visual testing platform that helps us review UI changes and catch visual regressions.

---

## License

Licensed under the MIT License, Copyright © 2022-present [WorkOS](https://workos.com).



================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct

## Our Pledge

In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.

## Our Standards

Examples of behavior that contributes to creating a positive environment
include:

- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

- The use of sexualized language or imagery and unwelcome sexual attention or
  advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or electronic
  address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a
  professional setting

## Our Responsibilities

Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.

Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.

## Scope

This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at colm@workos.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.

Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html

[homepage]: https://www.contributor-covenant.org

For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq



================================================
FILE: context7.json
================================================
{
  "url": "https://context7.com/radix-ui/primitives",
  "public_key": "pk_q7NnKuFFXMWA7WnmjMHQU"
}


================================================
FILE: cypress.config.ts
================================================
import { defineConfig } from 'cypress';

export default defineConfig({
  viewportWidth: 1024,
  viewportHeight: 768,
  fixturesFolder: false,
  defaultCommandTimeout: 20_000,
  e2e: {
    // TODO There is a bug (I think) in Cypress that results in the page
    // navigating to `about:blank` after certain tests run. Unclear why at this
    // stage. This is a hack that seems to prevent it, but unclear why. Debug
    // and remove this config option.
    // Possibly related: https://github.com/cypress-io/cypress/issues/28527
    testIsolation: false,
    setupNodeEvents(_on, _config) {},
    baseUrl: 'http://localhost:9009',
  },
});



================================================
FILE: eslint.config.mjs
================================================
// @ts-check
import * as react from '@chance/eslint/react';
import * as js from '@chance/eslint';
import * as typescript from '@chance/eslint/typescript';
import { globals } from '@chance/eslint/globals';
import pluginCypress from 'eslint-plugin-cypress/flat';

/** @type {import("eslint").Linter.Config[]} */
export default [
  { ...js.getConfig({ ...globals.node, ...globals.browser }) },
  typescript.config,
  {
    ...react.config,
    rules: {
      ...react.rules,
      'react/jsx-pascal-case': ['warn', { allowNamespace: true }],
      // TODO: enable this and fix all the errors
      'react/display-name': 'off',
      'prefer-const': ['warn', { destructuring: 'all' }],
      'jsx-a11y/label-has-associated-control': [
        'warn',
        {
          controlComponents: ['Checkbox'],
          depth: 3,
        },
      ],
    },
  },
  { ...pluginCypress.configs.recommended, files: ['cypress/**/*.{ts,js}'] },
  {
    ignores: ['dist/**', '.next/**'],
    rules: {
      'prefer-const': ['warn', { destructuring: 'all' }],
    },
  },
];



================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2022 WorkOS

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.



================================================
FILE: package.json
================================================
{
  "private": true,
  "name": "primitives",
  "version": "0.1.0",
  "license": "MIT",
  "scripts": {
    "lint": "pnpm -r run lint",
    "types:check": "pnpm -r --parallel run typecheck",
    "test": "vitest",
    "test:ci": "vitest run && pnpm cypress:ci",
    "storybook": "BROWSER=none pnpm --filter=@repo/storybook run dev -p 9009",
    "storybook:build": "BROWSER=none pnpm --filter=@repo/storybook run build",
    "storybook:serve": "pnpm --filter=@repo/storybook run serve",
    "cypress:ci": "start-server-and-test 'pnpm dev' http://localhost:9009 'pnpm cypress:install && pnpm cypress:run'",
    "cypress:install": "cypress install",
    "cypress:run": "cypress run",
    "cypress:dev": "cypress open",
    "dev": "pnpm run storybook",
    "dev:ssr": "pnpm --filter=@repo/ssr-testing dev",
    "build-storybook": "pnpm --filter=@repo/storybook run build",
    "build": "pnpm -r --parallel --filter \"./packages/**/*\" run build",
    "clean": "pnpm -r run clean",
    "reset": "rm -rf node_modules && pnpm -r run reset",
    "bump:stable": "changeset version",
    "bump:next": "changeset version --snapshot",
    "bump:check": "changeset status --since=main",
    "release:stable": "pnpm publish -r --access public",
    "release:stable:ci": "pnpm publish -r --access public --publish-branch stable",
    "release:next": "pnpm publish -r --access public --tag next",
    "format": "prettier --write .",
    "format:staged": "pretty-quick --staged"
  },
  "devDependencies": {
    "@chance/eslint": "^1.1.0",
    "@changesets/cli": "^2.29.7",
    "@radix-ui/colors": "^3.0.0",
    "@testing-library/cypress": "^10.1.0",
    "@testing-library/dom": "^10.4.1",
    "@testing-library/jest-dom": "^6.9.1",
    "@testing-library/react": "^16.3.0",
    "@testing-library/user-event": "^14.6.1",
    "@types/fs-extra": "^11",
    "@types/node": "^22",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "@types/react-test-renderer": "^19.1.0",
    "axe-core": "^4.11.0",
    "cypress": "^15.5.0",
    "cypress-axe": "1.7.0",
    "cypress-real-events": "^1.15.0",
    "eslint": "^9.38.0",
    "eslint-plugin-cypress": "^5.2.0",
    "execa": "^9.6.0",
    "fs-extra": "^11.3.2",
    "glob": "^10.2.2",
    "jsdom": "^26.1.0",
    "prettier": "^3.6.2",
    "pretty-quick": "^4.2.2",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "react-test-renderer": "^19.2.0",
    "react-is": "^19.2.0",
    "react-remove-scroll": "^2.6.3",
    "replace-in-files": "^3.0.0",
    "start-server-and-test": "^2.1.2",
    "typescript": "^5.9.3",
    "vite": "^7.1.12",
    "vitest": "^4.0.4",
    "vitest-axe": "^1.0.0-pre.5"
  },
  "engines": {
    "node": ">=18"
  },
  "packageManager": "pnpm@10.2.0",
  "pnpm": {
    "patchedDependencies": {
      "@changesets/apply-release-plan": "patches/@changesets__apply-release-plan.patch"
    }
  }
}



================================================
FILE: philosophy.md
================================================
# Primitives: Philosophy and Guiding Principles

## Vision

Most of us share similar definitions for common UI patterns like accordion, checkbox, combobox, dialog, dropdown, select, slider, and tooltip. These UI patterns are [documented by WAI-ARIA](https://www.w3.org/TR/wai-aria-practices/#aria_ex) and generally understood by the community.

However, the implementations provided to us by the web platform are inadequate. They're either non-existent, lacking in functionality, or cannot be customised sufficiently.

As a result, developers are forced to build custom components—an incredibly difficult task. As a result, most components on the web are inaccessible, non-performant, and lacking important features.

Our goal is to create a well-funded open-source component library that the community can use to build accessible design systems.

## Principles at a glance

1. Accessible
2. Functional
3. Interoperable
4. Composable
5. Customizable

---

## Principles

### Accessible

- Components adhere to WAI-ARIA guidelines and are tested regularly in a wide selection of modern browsers and assistive technologies.
- Where WAI-ARIA guidelines do not cover a particular use case, prior research is done to determine the patterns and behaviors we adopt when designing a new component. We look to similar, well-tested native solutions to capture nuances that WAI-ARIA guidelines may overlook.
- Developers should know about accessibility but shouldn't have to spend too much time implementing accessible patterns.
- Most behavior and markup related to accessibility should be abstracted, and bits that can't should be simplified where possible.
- Individual components will be tested to ensure maximum accessibility, but where app context is required the component library should provide useful guidance and supporting materials where possible to build fully accessible applications.
- Try to name things as closely to `aria` and `html` as possible where applicable; wherever we require developers to engage with accessibility directly, our platform should be a learning opportunity and a bridge for better understanding the underlying problems we solve.
- Components are thoroughly tested on a variety of devices and assistive technology, including all major screen reader vendors (VoiceOver, JAWS, NVDA); components respond and adapt effectively to input and appearance distinctions between platforms.

### Functional

- Components are feature-rich, with support for keyboard interaction, collision detection, focus trapping, dynamic resizing, scroll locking, native fallbacks, and more.

### Composable

- Components are designed with an open API that provides consumers with direct access to the underlying DOM node that is rendered to the page.
- We achieve this API with a 1-to-1 strategy, where a single component only renders a single DOM element (if a DOM node is rendered at all).
- Some abstractions may require slight deviation from this pattern, in which case the rationale should be clearly explained in supporting documentation.
- This API also empowers us to forward user-provided DOM refs to the correct underlying DOM node without doing anything too clever, meaning refs function exactly as the consumer would expect.
- Just as DOM nodes are composable, so are DOM event handlers; consumers should be able to pass their own event handlers directly to a component and stop internal handlers from firing.

### Customizable

- Components are built to be themed; no need to override opinionated styles, as primitives ship with zero presentational styles applied by default.
- Components ship with CSS-in-JS style objects that provide a minimal set styles needed to easily reset user agent styles and provide a clean slate for consumers to build upon.
- Our components can be composed or styled the same way underlying JSX components are composed or styled, with limitations only introduced to prevent UX/accessibility dark patterns where needed.
- Consumers can choose whether or not to apply these styles in their app, as well as the styling tool; we do not enforce a particular methodology or library.

## Other considerations

### Internationalization

- Components support international string formatting and make behavioral adjustments for right-to-left languages

### Stateful components can be controlled or uncontrolled

- Similar to form field JSX elements in React, all components with internal state can either be uncontrolled (internally managed) or controlled (managed by the consumer)

### Components exist in a finite number of predefined states

- State in this context refers to a component's state representable by a finite state machine; not to be confused with arbitrary stateful data as typically referenced in React libraries
- States are predetermined during the component design phase and expressed as strings in component code, making state transitions more explicit, deterministic, and clearer to follow
- Use the `data-state` attribute to expose a component's state directly to its DOM element
- When tempted to use a boolean to track a piece of stateful data, consider enumerated strings instead

### Developer experience

- Component APIs should be relatively intuitive and as declarative as possible
- Provide in-code documentation for complex/unclear abstractions for easier source debugging
- Anticipate errors and provide thorough console warnings with links back to documentation

### Balancing tradeoffs between design goals

- Composition is preferred over configuration
- Code clarity is preferred over bundle terseness except in extreme cases
- Smart abstractions preferred over over-exposing internal state

### Documentation

TODO

### Misc

- Not concerned with design system components like `Box`, `Chip` or `Badge` that provide visual language consistency but provide no underlying semantic meaning or abstracted behavior
- Keep file structure flat so logic is easier to follow; avoid early abstractions
- Don't repeat yourself _too much_ but don't be afraid to repeat yourself if an implementation detail hasn't been thoroughly vetted



================================================
FILE: pnpm-workspace.yaml
================================================
packages:
  - 'apps/*'
  - 'internal/*'
  - 'packages/*/*'



================================================
FILE: release-process.md
================================================
# Release process

## Overview

While our release schedule is flexible, our general strategy is to release several larger improvements inside each stable release. In order to provide faster access to fixes and enhancements between main releases we provide release candidates which are published on every merge into `main`.

While the versioning and publishing of our primitives is mostly automated via scripts, updates to our [documentation website](https://radix-ui.com/primitives/docs/overview/introduction) is currently a manual process. We are working to improve this but for now this outline should help contributors with the process.

## Release strategy

We track versions during the pull request process. As features are added, modified or improved it's important to keep track of these via versioning.

### Tracking version changes

Run `pnpm changeset` to mark the appropriate type of change for those packages. This is later consumed when publishing new versions. Be sure to check-in these files along with your code changes.

### Publishing a stable release

1. Checkout the `stable` branch and pull the latest changes from `main`
2. Push the changes to `stable`. This will trigger the Changeset action, which will create a new release PR.
3. Review the release PR, ensure all tests pass and make any necessary changes.
4. Merge the PR. This will trigger the Changeset action to publish the new version to npm.

### Release candidates

Release candidates are automatically published when new changes are merged into `main`.

## Updating documentation

Our documentation is in a [separate repository](https://github.com/radix-ui/website) and updating it is a three step process:

1. Write and update the [change log](https://github.com/radix-ui/website/blob/main/data/primitives/docs/overview/releases.mdx)
2. Bump package version/s and create / update the pages for each version change
3. Perform documentation updates and remove live demos from previous versions

Steps 2 and 3 are typically raised as separate pull requests to make changes easier to review.

### Creating new version pages

This is as simple as duplicating the latest page and updating the version number to match the release. Some things to keep in mind:

- We only provide live demos for the latest version of a package so you must remember to disable/remove the previous live demo (this avoids breaking changes affecting old versions in our docs)
- If the incoming version is a patch which doesn't require a docs update then you can simply change the page name to match the new version rather than duplicating the same content



================================================
FILE: vitest.config.mts
================================================
import { defineConfig } from 'vitest/config';

export default defineConfig({
  test: {
    setupFiles: ['./scripts/setup-tests.ts'],
    environment: 'jsdom',
    include: ['**/*.test.?(c|m)[jt]s?(x)'],
    retry: 1,
  },
});



================================================
FILE: .editorconfig
================================================
root = true

[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
max_line_length = 80
tab_width = 2
trim_trailing_whitespace = true

[Makefile]
indent_style = tab
tab_width = 4

[{*.md,*.mdx}]
trim_trailing_whitespace = false



================================================
FILE: .nvmrc
================================================
22



================================================
FILE: .prettierignore
================================================
.next
node_modules
.yarn
dist
storybook-static
.pnp
.pnp.js
coverage
pnpm-lock.yaml
package-lock.json
yarn.lock
*.log*
.DS_Store
*.pem



================================================
FILE: .prettierrc
================================================
{
  "printWidth": 100,
  "singleQuote": true
}



================================================
FILE: apps/ssr-testing/README.md
================================================
# `@repo/ssr-testing`

This is a testing playground for SSR support in our primitives using a [Next.js](https://nextjs.org/) project.

## Getting Started

From the root of the repo, run the development server:

```sh
pnpm dev:ssr
```



================================================
FILE: apps/ssr-testing/next-env.d.ts
================================================
/// <reference types="next" />
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.



================================================
FILE: apps/ssr-testing/next.config.js
================================================
module.exports = {
  experimental: {
    externalDir: true,
  },
};



================================================
FILE: apps/ssr-testing/package.json
================================================
{
  "name": "@repo/ssr-testing",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start"
  },
  "dependencies": {
    "next": "^15.3.1",
    "radix-ui": "workspace:*",
    "react": "^19.2.0",
    "react-dom": "^19.2.0"
  },
  "devDependencies": {
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "typescript": "^5.9.3"
  }
}



================================================
FILE: apps/ssr-testing/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/nextjs.json",
  "compilerOptions": {
    "incremental": true
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
  "exclude": ["node_modules"]
}



================================================
FILE: apps/ssr-testing/app/layout.tsx
================================================
import * as React from 'react';
import type { Metadata } from 'next';
import Link from 'next/link';

export default function Layout({ children }: { children: React.ReactNode }) {
  return (
    <React.StrictMode>
      <html lang="en">
        <body style={{ margin: 0, padding: '2em 3em' }}>
          <h1>SSR / RSC testing</h1>
          <div style={{ display: 'flex', gap: '10em' }}>
            <div style={{ display: 'flex', flexDirection: 'column', gap: '0.5em' }}>
              <Link href="/accessible-icon">AccessibleIcon</Link>
              <Link href="/accordion">Accordion</Link>
              <Link href="/alert-dialog">AlertDialog</Link>
              <Link href="/avatar">Avatar</Link>
              <Link href="/checkbox">Checkbox</Link>
              <Link href="/collapsible">Collapsible</Link>
              <Link href="/context-menu">ContextMenu</Link>
              <Link href="/dialog">Dialog</Link>
              <Link href="/dropdown-menu">DropdownMenu</Link>
              <Link href="/form">Form</Link>
              <Link href="/hover-card">HoverCard</Link>
              <Link href="/label">Label</Link>
              <Link href="/menubar">Menubar</Link>
              <Link href="/navigation-menu">NavigationMenu</Link>
              <Link href="/one-time-password-field">OneTimePasswordField</Link>
              <Link href="/password-toggle-field">PasswordToggleField</Link>
              <Link href="/popover">Popover</Link>
              <Link href="/portal">Portal</Link>
              <Link href="/progress">Progress</Link>
              <Link href="/radio-group">RadioGroup</Link>
              <Link href="/roving-focus-group">RovingFocusGroup</Link>
              <Link href="/scroll-area">ScrollArea</Link>
              <Link href="/select">Select</Link>
              <Link href="/separator">Separator</Link>
              <Link href="/slider">Slider</Link>
              <Link href="/slot">Slot</Link>
              <Link href="/switch">Switch</Link>
              <Link href="/tabs">Tabs</Link>
              <Link href="/toast">Toast</Link>
              <Link href="/toggle-group">ToggleGroup</Link>
              <Link href="/toolbar">Toolbar</Link>
              <Link href="/tooltip">Tooltip</Link>
              <Link href="/visually-hidden">VisuallyHidden</Link>
            </div>

            <div>{children}</div>
          </div>
        </body>
      </html>
    </React.StrictMode>
  );
}

export const metadata: Metadata = {
  title: 'SSR testing',
};



================================================
FILE: apps/ssr-testing/app/page.tsx
================================================
export default function Page() {
  return null;
}



================================================
FILE: apps/ssr-testing/app/accessible-icon/page.tsx
================================================
import * as React from 'react';
import { AccessibleIcon } from 'radix-ui';

export default function Page() {
  return (
    <button type="button">
      <AccessibleIcon.Root label="Close">
        <span>X</span>
      </AccessibleIcon.Root>
    </button>
  );
}



================================================
FILE: apps/ssr-testing/app/accordion/page.tsx
================================================
import * as React from 'react';
import { Accordion } from 'radix-ui';

export default function Page() {
  return (
    <Accordion.Root type="multiple">
      <Accordion.Item value="one">
        <Accordion.Header>
          <Accordion.Trigger>One</Accordion.Trigger>
        </Accordion.Header>
        <Accordion.Content>
          Per erat orci nostra luctus sociosqu mus risus penatibus, duis elit vulputate viverra
          integer ullamcorper congue curabitur sociis, nisi malesuada scelerisque quam suscipit
          habitant sed.
        </Accordion.Content>
      </Accordion.Item>
      <Accordion.Item value="two">
        <Accordion.Header>
          <Accordion.Trigger>Two</Accordion.Trigger>
        </Accordion.Header>
        <Accordion.Content>
          Cursus sed mattis commodo fermentum conubia ipsum pulvinar sagittis, diam eget bibendum
          porta nascetur ac dictum, leo tellus dis integer platea ultrices mi.
        </Accordion.Content>
      </Accordion.Item>
      <Accordion.Item value="three" disabled>
        <Accordion.Header>
          <Accordion.Trigger>Three (disabled)</Accordion.Trigger>
        </Accordion.Header>
        <Accordion.Content>
          Sociis hac sapien turpis conubia sagittis justo dui, inceptos penatibus feugiat himenaeos
          euismod magna, nec tempor pulvinar eu etiam mattis.
        </Accordion.Content>
      </Accordion.Item>
      <Accordion.Item value="four">
        <Accordion.Header>
          <Accordion.Trigger>Four</Accordion.Trigger>
        </Accordion.Header>
        <Accordion.Content>
          Odio placerat quisque sapien sagittis non sociis ligula penatibus dignissim vitae, enim
          vulputate nullam semper potenti etiam volutpat libero.
          <button>Cool</button>
        </Accordion.Content>
      </Accordion.Item>
    </Accordion.Root>
  );
}



================================================
FILE: apps/ssr-testing/app/alert-dialog/page.tsx
================================================
import * as React from 'react';
import { AlertDialog } from 'radix-ui';

export default function Page() {
  return (
    <AlertDialog.Root>
      <AlertDialog.Trigger>delete everything</AlertDialog.Trigger>
      <AlertDialog.Portal>
        <AlertDialog.Overlay />
        <AlertDialog.Content>
          <AlertDialog.Title>Are you sure?</AlertDialog.Title>
          <AlertDialog.Description>
            This will do a very dangerous thing. Thar be dragons!
          </AlertDialog.Description>
          <AlertDialog.Action>yolo, do it</AlertDialog.Action>
          <AlertDialog.Cancel>maybe not</AlertDialog.Cancel>
        </AlertDialog.Content>
      </AlertDialog.Portal>
    </AlertDialog.Root>
  );
}



================================================
FILE: apps/ssr-testing/app/avatar/page.tsx
================================================
import * as React from 'react';
import { Avatar } from 'radix-ui';

export default function Page() {
  return (
    <Avatar.Root>
      <Avatar.Fallback>A</Avatar.Fallback>
      <Avatar.AvatarImage src="https://picsum.photos/id/1005/400/400" />
    </Avatar.Root>
  );
}



================================================
FILE: apps/ssr-testing/app/checkbox/page.tsx
================================================
import * as React from 'react';
import { Checkbox } from 'radix-ui';

export default function Page() {
  return (
    <Checkbox.Root>
      [ <Checkbox.Indicator>✔</Checkbox.Indicator> ]
    </Checkbox.Root>
  );
}



================================================
FILE: apps/ssr-testing/app/collapsible/page.tsx
================================================
import * as React from 'react';
import { Collapsible } from 'radix-ui';

export default function Page() {
  return (
    <Collapsible.Root>
      <Collapsible.Trigger>Trigger</Collapsible.Trigger>
      <Collapsible.Content>Content</Collapsible.Content>
    </Collapsible.Root>
  );
}



================================================
FILE: apps/ssr-testing/app/context-menu/page.tsx
================================================
import * as React from 'react';
import { ContextMenu } from 'radix-ui';

export default function Page() {
  return (
    <ContextMenu.Root>
      <ContextMenu.Trigger>Right click here</ContextMenu.Trigger>
      <ContextMenu.Portal>
        <ContextMenu.Content alignOffset={-5}>
          <ContextMenu.Item>Undo</ContextMenu.Item>
          <ContextMenu.Item>Redo</ContextMenu.Item>
          <ContextMenu.Separator />
          <ContextMenu.Item disabled>Cut</ContextMenu.Item>
          <ContextMenu.Item>Copy</ContextMenu.Item>
          <ContextMenu.Item>Paste</ContextMenu.Item>
        </ContextMenu.Content>
      </ContextMenu.Portal>
    </ContextMenu.Root>
  );
}



================================================
FILE: apps/ssr-testing/app/dialog/page.tsx
================================================
import * as React from 'react';
import { Dialog } from 'radix-ui';

export default function Page() {
  return (
    <Dialog.Root defaultOpen>
      <Dialog.Trigger>open</Dialog.Trigger>
      <Dialog.Portal>
        <Dialog.Overlay />
        <Dialog.Content>
          <Dialog.Title>Title</Dialog.Title>
          <Dialog.Description>Description</Dialog.Description>
          <Dialog.Close>close</Dialog.Close>
        </Dialog.Content>
      </Dialog.Portal>
    </Dialog.Root>
  );
}



================================================
FILE: apps/ssr-testing/app/dropdown-menu/page.tsx
================================================
import * as React from 'react';
import { DropdownMenu } from 'radix-ui';

export default function Page() {
  return (
    <DropdownMenu.Root>
      <DropdownMenu.Trigger>Open</DropdownMenu.Trigger>
      <DropdownMenu.Portal>
        <DropdownMenu.Content sideOffset={5}>
          <DropdownMenu.Item>Undo</DropdownMenu.Item>
          <DropdownMenu.Item>Redo</DropdownMenu.Item>
          <DropdownMenu.Separator />
          <DropdownMenu.Item disabled>Cut</DropdownMenu.Item>
          <DropdownMenu.Item>Copy</DropdownMenu.Item>
          <DropdownMenu.Item>Paste</DropdownMenu.Item>
          <DropdownMenu.Arrow />
        </DropdownMenu.Content>
      </DropdownMenu.Portal>
    </DropdownMenu.Root>
  );
}



================================================
FILE: apps/ssr-testing/app/form/page.tsx
================================================
import * as React from 'react';
import { Form } from 'radix-ui';

export default function Page() {
  return (
    <Form.Root>
      <Form.Field name="email">
        <Form.Label>Email</Form.Label>
        <Form.Control type="email" required />
        <Form.Message match="valueMissing">Value is missing</Form.Message>
        <Form.Message match="typeMismatch">Email is invalid</Form.Message>
      </Form.Field>
    </Form.Root>
  );
}



================================================
FILE: apps/ssr-testing/app/hover-card/page.tsx
================================================
import * as React from 'react';
import { HoverCard } from 'radix-ui';

export default function Page() {
  return (
    <HoverCard.Root>
      <HoverCard.Trigger>Hover me</HoverCard.Trigger>
      <HoverCard.Portal>
        <HoverCard.Content>
          <HoverCard.Arrow width={20} height={10} />
          Nicely done!
        </HoverCard.Content>
      </HoverCard.Portal>
    </HoverCard.Root>
  );
}



================================================
FILE: apps/ssr-testing/app/label/page.tsx
================================================
import * as React from 'react';
import { Label } from 'radix-ui';

export default function Page() {
  return <Label.Root>Label</Label.Root>;
}



================================================
FILE: apps/ssr-testing/app/menubar/page.tsx
================================================
import * as React from 'react';
import { Menubar } from 'radix-ui';

export default function Page() {
  return (
    <Menubar.Root>
      <Menubar.Menu>
        <Menubar.Trigger>Open</Menubar.Trigger>
        <Menubar.Portal>
          <Menubar.Content>
            <Menubar.Label>Menu</Menubar.Label>
            <Menubar.Item>Item 1</Menubar.Item>
            <Menubar.Item>Item 2</Menubar.Item>
            <Menubar.Item>Item 3</Menubar.Item>
            <Menubar.Arrow />
          </Menubar.Content>
        </Menubar.Portal>
      </Menubar.Menu>
    </Menubar.Root>
  );
}



================================================
FILE: apps/ssr-testing/app/navigation-menu/page.tsx
================================================
import * as React from 'react';
import { NavigationMenu } from 'radix-ui';

export default function Page() {
  return (
    <NavigationMenu.Root>
      <NavigationMenu.List>
        <NavigationMenu.Item>
          <NavigationMenu.Trigger>Nav Menu Item 1</NavigationMenu.Trigger>
          <NavigationMenu.Content>
            <NavigationMenu.Link href="/">Link</NavigationMenu.Link>
          </NavigationMenu.Content>
        </NavigationMenu.Item>

        <NavigationMenu.Item>
          <NavigationMenu.Link href="/">Nav Menu Item 2</NavigationMenu.Link>
        </NavigationMenu.Item>
      </NavigationMenu.List>
    </NavigationMenu.Root>
  );
}



================================================
FILE: apps/ssr-testing/app/one-time-password-field/page.tsx
================================================
import * as React from 'react';
import { unstable_OneTimePasswordField as OneTimePasswordField } from 'radix-ui';

export default function Page() {
  return (
    <div>
      <OneTimePasswordField.Root placeholder="123456">
        <OneTimePasswordField.Input />
        <OneTimePasswordField.Input />
        <OneTimePasswordField.Input />
        <OneTimePasswordField.Input />
        <OneTimePasswordField.Input />
        <OneTimePasswordField.Input />
        <OneTimePasswordField.HiddenInput />
      </OneTimePasswordField.Root>
      <h2>With indices</h2>
      <OneTimePasswordField.Root placeholder="123456">
        <OneTimePasswordField.Input index={0} />
        <OneTimePasswordField.Input index={1} />
        <OneTimePasswordField.Input index={2} />
        <OneTimePasswordField.Input index={3} />
        <OneTimePasswordField.Input index={4} />
        <OneTimePasswordField.Input index={5} />
        <OneTimePasswordField.HiddenInput />
      </OneTimePasswordField.Root>
    </div>
  );
}



================================================
FILE: apps/ssr-testing/app/password-toggle-field/page.tsx
================================================
import * as React from 'react';
import { unstable_PasswordToggleField as PasswordToggleField } from 'radix-ui';

export default function Page() {
  return (
    <div style={{ display: 'flex', gap: '1em', flexDirection: 'column' }}>
      <div>
        <PasswordToggleField.Root>
          <PasswordToggleField.Input />
          <PasswordToggleField.Toggle>
            <PasswordToggleField.Slot visible="Hide" hidden="Show" />
          </PasswordToggleField.Toggle>
        </PasswordToggleField.Root>
      </div>
      <div>
        <PasswordToggleField.Root>
          <PasswordToggleField.Input />
          <PasswordToggleField.Toggle>
            <PasswordToggleField.Icon visible={<EyeOpenIcon />} hidden={<EyeClosedIcon />} />
          </PasswordToggleField.Toggle>
        </PasswordToggleField.Root>
      </div>
    </div>
  );
}

function EyeClosedIcon() {
  return (
    <svg
      width="15"
      height="15"
      viewBox="0 0 15 15"
      fill="currentColor"
      xmlns="http://www.w3.org/2000/svg"
    >
      <path
        d="M14.7649 6.07596C14.9991 6.22231 15.0703 6.53079 14.9239 6.76495C14.4849 7.46743 13.9632 8.10645 13.3702 8.66305L14.5712 9.86406C14.7664 10.0593 14.7664 10.3759 14.5712 10.5712C14.3759 10.7664 14.0593 10.7664 13.8641 10.5712L12.6011 9.30817C11.805 9.90283 10.9089 10.3621 9.93375 10.651L10.383 12.3277C10.4544 12.5944 10.2961 12.8685 10.0294 12.94C9.76267 13.0115 9.4885 12.8532 9.41704 12.5865L8.95917 10.8775C8.48743 10.958 8.00036 10.9999 7.50001 10.9999C6.99965 10.9999 6.51257 10.958 6.04082 10.8775L5.58299 12.5864C5.51153 12.8532 5.23737 13.0115 4.97064 12.94C4.7039 12.8686 4.5456 12.5944 4.61706 12.3277L5.06625 10.651C4.09111 10.3621 3.19503 9.90282 2.3989 9.30815L1.1359 10.5712C0.940638 10.7664 0.624058 10.7664 0.428798 10.5712C0.233537 10.3759 0.233537 10.0593 0.428798 9.86405L1.62982 8.66303C1.03682 8.10643 0.515113 7.46742 0.0760677 6.76495C-0.0702867 6.53079 0.000898544 6.22231 0.235065 6.07596C0.469231 5.9296 0.777703 6.00079 0.924058 6.23496C1.40354 7.00213 1.989 7.68057 2.66233 8.2427C2.67315 8.25096 2.6837 8.25972 2.69397 8.26898C4.00897 9.35527 5.65537 9.99991 7.50001 9.99991C10.3078 9.99991 12.6564 8.5063 14.076 6.23495C14.2223 6.00079 14.5308 5.9296 14.7649 6.07596Z"
        fillRule="evenodd"
        clipRule="evenodd"
      />
    </svg>
  );
}

function EyeOpenIcon() {
  return (
    <svg
      width="15"
      height="15"
      viewBox="0 0 15 15"
      fill="currentColor"
      xmlns="http://www.w3.org/2000/svg"
    >
      <path
        d="M7.5 11C4.80285 11 2.52952 9.62184 1.09622 7.50001C2.52952 5.37816 4.80285 4 7.5 4C10.1971 4 12.4705 5.37816 13.9038 7.50001C12.4705 9.62183 10.1971 11 7.5 11ZM7.5 3C4.30786 3 1.65639 4.70638 0.0760002 7.23501C-0.0253338 7.39715 -0.0253334 7.60288 0.0760014 7.76501C1.65639 10.2936 4.30786 12 7.5 12C10.6921 12 13.3436 10.2936 14.924 7.76501C15.0253 7.60288 15.0253 7.39715 14.924 7.23501C13.3436 4.70638 10.6921 3 7.5 3ZM7.5 9.5C8.60457 9.5 9.5 8.60457 9.5 7.5C9.5 6.39543 8.60457 5.5 7.5 5.5C6.39543 5.5 5.5 6.39543 5.5 7.5C5.5 8.60457 6.39543 9.5 7.5 9.5Z"
        fillRule="evenodd"
        clipRule="evenodd"
      />
    </svg>
  );
}



================================================
FILE: apps/ssr-testing/app/popover/page.tsx
================================================
import * as React from 'react';
import { Popover } from 'radix-ui';

export default function Page() {
  return (
    <Popover.Root>
      <Popover.Trigger>open</Popover.Trigger>
      <Popover.Portal>
        <Popover.Content sideOffset={5}>
          <Popover.Close>close</Popover.Close>
          <Popover.Arrow width={20} height={10} />
        </Popover.Content>
      </Popover.Portal>
    </Popover.Root>
  );
}



================================================
FILE: apps/ssr-testing/app/portal/conditional-portal.tsx
================================================
'use client';

import * as React from 'react';
import { Portal } from 'radix-ui';

export const ConditionalPortal = () => {
  const [container, setContainer] = React.useState<Element | null>(null);
  const [open, setOpen] = React.useState(false);
  return (
    <div>
      <button onClick={() => setOpen((prev) => !prev)}>Toggle another portal</button>
      <b ref={setContainer} />
      {open && (
        <Portal.Root container={container}>
          <span>This content is rendered in a custom container</span>
        </Portal.Root>
      )}
    </div>
  );
};



================================================
FILE: apps/ssr-testing/app/portal/custom-portal-container.tsx
================================================
'use client';

import * as React from 'react';
import { Portal } from 'radix-ui';

export const CustomPortalContainer = () => {
  const [container, setContainer] = React.useState<Element | null>(null);
  return (
    <div>
      <em ref={setContainer} />
      <Portal.Root container={container}>
        <span>This content is rendered in a custom container</span>
      </Portal.Root>
    </div>
  );
};



================================================
FILE: apps/ssr-testing/app/portal/page.tsx
================================================
import * as React from 'react';
import { Portal } from 'radix-ui';
import { CustomPortalContainer } from './custom-portal-container';
import { ConditionalPortal } from './conditional-portal';

export default function Page() {
  return (
    <div>
      <div
        style={{
          maxWidth: 300,
          maxHeight: 200,
          overflow: 'auto',
          border: '1px solid',
        }}
      >
        <h1>This content is rendered in the main DOM tree</h1>
        <p>
          Lorem ipsum dolor sit amet consectetur adipisicing elit. Quos porro, est ex quia itaque
          facere fugit necessitatibus aut enim. Nisi rerum quae, repellat in perspiciatis explicabo
          laboriosam necessitatibus eius pariatur.
        </p>

        <Portal.Root>
          <h1>This content is rendered in a portal (another DOM tree)</h1>
          <p>
            Because of the portal, it can appear in a different DOM tree from the main one (by
            default a new element inside the body), even though it is part of the same React tree.
          </p>
        </Portal.Root>
      </div>

      <br />
      <CustomPortalContainer />

      <br />
      <ConditionalPortal />
    </div>
  );
}



================================================
FILE: apps/ssr-testing/app/progress/page.tsx
================================================
import * as React from 'react';
import { Progress } from 'radix-ui';

export default function Page() {
  return (
    <Progress.Root value={20}>
      <Progress.Indicator>Progress</Progress.Indicator>
    </Progress.Root>
  );
}



================================================
FILE: apps/ssr-testing/app/radio-group/page.tsx
================================================
import * as React from 'react';
import { Label, RadioGroup } from 'radix-ui';

export default function Page() {
  return (
    <Label.Root>
      Favourite pet
      <RadioGroup.Root defaultValue="1">
        <Label.Root>
          <RadioGroup.Item value="1">
            [ <RadioGroup.Indicator>X</RadioGroup.Indicator> ]
          </RadioGroup.Item>
          Cat
        </Label.Root>
        <br />

        <Label.Root>
          <RadioGroup.Item value="2">
            [ <RadioGroup.Indicator>X</RadioGroup.Indicator> ]
          </RadioGroup.Item>
          Dog
        </Label.Root>
        <br />

        <Label.Root>
          <RadioGroup.Item value="3">
            [ <RadioGroup.Indicator>X</RadioGroup.Indicator> ]
          </RadioGroup.Item>
          Rabbit
        </Label.Root>
        <br />
      </RadioGroup.Root>
    </Label.Root>
  );
}



================================================
FILE: apps/ssr-testing/app/roving-focus-group/page.tsx
================================================
import * as React from 'react';
import { RovingFocusProvider, RovingFocusToggle, ButtonGroup, Button } from './roving-focus.client';

export default function Page() {
  return (
    <>
      <h1>Basic</h1>
      <RovingFocusProvider>
        <div>
          <RovingFocusToggle />
        </div>

        <h3>no orientation (both) + no looping</h3>

        <ButtonGroup defaultValue="two">
          <Button value="one">One</Button>
          <Button value="two">Two</Button>
          <Button disabled value="three">
            Three
          </Button>
          <Button value="four">Four</Button>
        </ButtonGroup>

        <h3>no orientation (both) + looping</h3>

        <ButtonGroup loop>
          <Button value="one">One</Button>
          <Button value="two">Two</Button>
          <Button disabled value="three">
            Three
          </Button>
          <Button value="four">Four</Button>
        </ButtonGroup>

        <h3>horizontal orientation + no looping</h3>

        <ButtonGroup orientation="horizontal">
          <Button value="one">One</Button>
          <Button value="two">Two</Button>
          <Button disabled value="three">
            Three
          </Button>
          <Button value="four">Four</Button>
        </ButtonGroup>

        <h3>horizontal orientation + looping</h3>

        <ButtonGroup orientation="horizontal" loop>
          <Button value="one">One</Button>
          <Button value="two">Two</Button>
          <Button disabled value="three">
            Three
          </Button>
          <Button value="four">Four</Button>
        </ButtonGroup>

        <h3>vertical orientation + no looping</h3>

        <ButtonGroup orientation="vertical">
          <Button value="one">One</Button>
          <Button value="two">Two</Button>
          <Button disabled value="three">
            Three
          </Button>
          <Button value="four">Four</Button>
        </ButtonGroup>

        <h3>vertical orientation + looping</h3>

        <ButtonGroup orientation="vertical" loop>
          <Button value="one">One</Button>
          <Button value="two">Two</Button>
          <Button disabled value="three">
            Three
          </Button>
          <Button value="four">Four</Button>
        </ButtonGroup>
      </RovingFocusProvider>

      <h1>Nested</h1>
      <ButtonGroup orientation="vertical" loop>
        <Button value="1">1</Button>

        <div style={{ display: 'flex', flexDirection: 'column' }}>
          <Button value="2" style={{ marginBottom: 10 }}>
            2
          </Button>

          <ButtonGroup orientation="horizontal" loop>
            <Button value="2.1">2.1</Button>
            <Button value="2.2">2.2</Button>
            <Button disabled value="2.3">
              2.3
            </Button>
            <Button value="2.4">2.4</Button>
          </ButtonGroup>
        </div>

        <Button value="3" disabled>
          3
        </Button>
        <Button value="4">4</Button>
      </ButtonGroup>
    </>
  );
}



================================================
FILE: apps/ssr-testing/app/roving-focus-group/roving-focus.client.tsx
================================================
'use client';
import * as React from 'react';
import { composeEventHandlers, RovingFocus } from 'radix-ui/internal';

type Direction = 'ltr' | 'rtl';

const RovingFocusContext = React.createContext<{
  dir: 'ltr' | 'rtl';
  setDir: React.Dispatch<React.SetStateAction<Direction>>;
}>({
  dir: 'ltr',
  setDir: () => void 0,
});
RovingFocusContext.displayName = 'RovingFocusContext';

export function RovingFocusProvider({ children }: { children: React.ReactNode }) {
  const [dir, setDir] = React.useState<Direction>('ltr');
  return (
    <div dir={dir}>
      <RovingFocusContext value={{ dir, setDir }}>{children}</RovingFocusContext>
    </div>
  );
}

export function RovingFocusToggle() {
  const { dir, setDir } = React.use(RovingFocusContext);
  return (
    <button type="button" onClick={() => setDir((prev) => (prev === 'ltr' ? 'rtl' : 'ltr'))}>
      Toggle to {dir === 'ltr' ? 'rtl' : 'ltr'}
    </button>
  );
}

const ButtonGroupContext = React.createContext<{
  value?: string;
  setValue: React.Dispatch<React.SetStateAction<string | undefined>>;
}>({} as any);

type ButtonGroupProps = Omit<React.ComponentPropsWithRef<'div'>, 'defaultValue'> &
  RovingFocus.RovingFocusGroupProps & { defaultValue?: string };

export function ButtonGroup({ defaultValue, ...props }: ButtonGroupProps) {
  const [value, setValue] = React.useState(defaultValue);
  const { dir } = React.use(RovingFocusContext);
  return (
    <ButtonGroupContext value={{ value, setValue }}>
      <RovingFocus.Root
        dir={dir}
        {...props}
        style={{
          ...props.style,
          display: 'inline-flex',
          flexDirection: props.orientation === 'vertical' ? 'column' : 'row',
          gap: 10,
        }}
      />
    </ButtonGroupContext>
  );
}

type ButtonProps = Omit<React.ComponentPropsWithRef<'button'>, 'value'> & { value?: string };

export function Button(props: ButtonProps) {
  const { value: contextValue, setValue } = React.use(ButtonGroupContext);
  const isSelected =
    contextValue !== undefined && props.value !== undefined && contextValue === props.value;

  return (
    <RovingFocus.Item asChild active={isSelected}>
      <button
        {...props}
        style={{
          ...props.style,
          border: '1px solid',
          borderColor: '#ccc',
          padding: '5px 10px',
          borderRadius: 5,
          ...(isSelected
            ? {
                borderColor: 'black',
                backgroundColor: 'black',
                color: 'white',
              }
            : {}),
        }}
        onClick={props.disabled ? undefined : () => setValue(props.value)}
        onFocus={composeEventHandlers(props.onFocus, (event) => {
          if (contextValue !== undefined) {
            event.target.click();
          }
        })}
      />
    </RovingFocus.Item>
  );
}



================================================
FILE: apps/ssr-testing/app/scroll-area/page.tsx
================================================
import * as React from 'react';
import { ScrollArea } from 'radix-ui';

export default function Page() {
  return (
    <ScrollArea.Root style={{ width: '400px', height: '400px' }}>
      <ScrollArea.Scrollbar orientation="vertical">
        <ScrollArea.Thumb />
      </ScrollArea.Scrollbar>

      <ScrollArea.Scrollbar orientation="horizontal">
        <ScrollArea.Thumb />
      </ScrollArea.Scrollbar>

      <ScrollArea.Viewport style={{ width: '2000px', padding: 20 }}>
        <LongContent />
        <LongContent />
        <LongContent />
        <LongContent />
        <LongContent />
        <LongContent />
        <LongContent />
      </ScrollArea.Viewport>

      <ScrollArea.Corner />
    </ScrollArea.Root>
  );
}

function LongContent() {
  return (
    <React.Fragment>
      <p>
        Lacinia hendrerit auctor nam quisque augue suscipit feugiat, sit at imperdiet vitae lacus.
        Dolor sit dui posuere faucibus non pharetra laoreet conubia, augue rhoncus cras nisl sodales
        proin hac ipsum, per hendrerit sed volutpat natoque curae consectetur. Curae blandit neque
        vehicula vel mauris vulputate per felis sociosqu, sodales integer sollicitudin id litora
        accumsan viverra pulvinar, mus non adipiscing dolor facilisis habitasse mi leo. Litora
        faucibus eu pulvinar tempus gravida iaculis consectetur risus euismod fringilla, dui posuere
        viverra sapien tortor mattis et dolor tempor sem conubia, taciti sociis mus rhoncus cubilia
        praesent dapibus aliquet quis. Diam hendrerit aliquam metus dolor fusce lorem, non gravida
        arcu primis posuere ipsum adipiscing, mus sollicitudin eros lacinia mollis.
      </p>
      <p>
        Habitant fames mi massa mollis fusce congue nascetur magna bibendum inceptos accumsan,
        potenti ipsum ac sollicitudin taciti dis rhoncus lacinia fermentum placerat. Himenaeos
        taciti egestas lacinia maecenas ornare ultricies, auctor vitae nulla mi posuere leo mollis,
        eleifend lacus rutrum ante curabitur. Nullam mi quisque nulla enim pretium facilisi interdum
        morbi, himenaeos velit fames pellentesque eget nascetur laoreet vel rutrum, malesuada risus
        ad netus dolor et scelerisque.
      </p>
      <ul>
        <li>Dis cubilia aenean tortor iaculis fames duis aliquet</li>
        <li>Erat non lacinia, tempor molestie fringilla</li>
        <li>Porttitor litora praesent placerat pulvinar</li>
        <li>Arcu curabitur fermentum felis sollicitudin varius nec cras</li>
      </ul>
      <p>
        Habitasse tristique hac ligula in metus blandit lobortis leo nullam litora, tempus fusce
        tincidunt phasellus urna est rhoncus pretium etiam eu, fames neque faucibus sociis primis
        felis dui vitae odio. Egestas purus morbi pulvinar luctus adipiscing rutrum ultrices hac,
        vehicula odio ridiculus cubilia vivamus blandit faucibus, dapibus velit sociis metus
        ultricies amet scelerisque.
      </p>
      <p>
        Scelerisque commodo nam cras litora lacinia primis fames morbi natoque, quisque ante duis
        phasellus pharetra convallis montes felis. Consectetur leo suspendisse fringilla elementum
        maecenas massa urna malesuada auctor senectus, pretium turpis nisi orci ipsum vulputate
        cubilia sociis adipiscing. Vulputate ridiculus amet dis accumsan non ultrices fames mattis
        hendrerit, ornare elementum sociosqu eget consectetur duis viverra vivamus tincidunt,
        blandit nulla porta semper dolor pharetra nisi scelerisque. Consequat conubia porta cras et
        ac auctor pellentesque luctus morbi potenti, viverra varius commodo venenatis vestibulum
        erat sagittis laoreet.
      </p>
    </React.Fragment>
  );
}



================================================
FILE: apps/ssr-testing/app/select/page.tsx
================================================
import * as React from 'react';
import { Select } from 'radix-ui';

export default function Page() {
  return (
    <>
      <Select.Root defaultValue="1">
        <Select.Trigger>
          <Select.Value />
          <Select.Icon>▼</Select.Icon>
        </Select.Trigger>
        <Select.Portal>
          <Select.Content>
            <Select.ScrollUpButton>▲</Select.ScrollUpButton>
            <Select.Viewport>
              <Select.Item value="1">
                <Select.ItemText>Item 1</Select.ItemText>
                <Select.ItemIndicator>✔</Select.ItemIndicator>
              </Select.Item>
              <Select.Item value="2">
                <Select.ItemText>Item 2</Select.ItemText>
                <Select.ItemIndicator>✔</Select.ItemIndicator>
              </Select.Item>
              <Select.Item value="3">
                <Select.ItemText>Item 3</Select.ItemText>
                <Select.ItemIndicator>✔</Select.ItemIndicator>
              </Select.Item>
            </Select.Viewport>
            <Select.ScrollDownButton>▼</Select.ScrollDownButton>
          </Select.Content>
        </Select.Portal>
      </Select.Root>

      <form>
        <Select.Root>
          <Select.Trigger>
            <Select.Value placeholder="Pick an option" />
            <Select.Icon>▼</Select.Icon>
          </Select.Trigger>
          <Select.Portal>
            <Select.Content>
              <Select.ScrollUpButton>▲</Select.ScrollUpButton>
              <Select.Viewport>
                <Select.Item value="1">
                  <Select.ItemText>Item 1</Select.ItemText>
                  <Select.ItemIndicator>✔</Select.ItemIndicator>
                </Select.Item>
                <Select.Item value="2">
                  <Select.ItemText>Item 2</Select.ItemText>
                  <Select.ItemIndicator>✔</Select.ItemIndicator>
                </Select.Item>
                <Select.Item value="3">
                  <Select.ItemText>Item 3</Select.ItemText>
                  <Select.ItemIndicator>✔</Select.ItemIndicator>
                </Select.Item>
              </Select.Viewport>
              <Select.ScrollDownButton>▼</Select.ScrollDownButton>
            </Select.Content>
          </Select.Portal>
        </Select.Root>
      </form>
    </>
  );
}



================================================
FILE: apps/ssr-testing/app/separator/page.tsx
================================================
import * as React from 'react';
import { Separator } from 'radix-ui';

export default function Page() {
  return <Separator.Root>***</Separator.Root>;
}



================================================
FILE: apps/ssr-testing/app/slider/page.tsx
================================================
import * as React from 'react';
import { Slider } from 'radix-ui';

export default function Page() {
  return (
    <Slider.Root
      defaultValue={[20, 50]}
      max={100}
      step={1}
      style={{
        position: 'relative',
        display: 'flex',
        alignItems: 'center',
        width: 200,
        height: 20,
      }}
    >
      <Slider.Track
        style={{
          backgroundColor: 'grey',
          position: 'relative',
          flexGrow: 1,
          height: 3,
        }}
      >
        <Slider.Range
          style={{
            position: 'absolute',
            backgroundColor: 'blue',
            height: '100%',
          }}
        />
      </Slider.Track>
      <Slider.Thumb
        style={{
          display: 'block',
          width: 20,
          height: 20,
          backgroundColor: 'blue',
        }}
      />
      <Slider.Thumb
        style={{
          display: 'block',
          width: 20,
          height: 20,
          backgroundColor: 'blue',
        }}
      />
    </Slider.Root>
  );
}



================================================
FILE: apps/ssr-testing/app/slot/page.tsx
================================================
import * as React from 'react';
import { Slot } from 'radix-ui';

export default function Page() {
  return (
    <Slot.Root>
      <span>I'm in a </span>
      <Slot.Slottable>
        <em>Slot!?</em>
      </Slot.Slottable>
    </Slot.Root>
  );
}



================================================
FILE: apps/ssr-testing/app/switch/page.tsx
================================================
import * as React from 'react';
import { Switch } from 'radix-ui';

export default function Page() {
  return (
    <Switch.Root>
      <Switch.Thumb>Switch</Switch.Thumb>
    </Switch.Root>
  );
}



================================================
FILE: apps/ssr-testing/app/tabs/page.tsx
================================================
import * as React from 'react';
import { Tabs } from 'radix-ui';

export default function Page() {
  return (
    <Tabs.Root defaultValue="one" orientation="vertical">
      <Tabs.List aria-label="tabs example">
        <Tabs.Trigger value="one">Tab 1</Tabs.Trigger>
        <Tabs.Trigger value="two">Tab 2</Tabs.Trigger>
        <Tabs.Trigger value="three">Tab 3</Tabs.Trigger>
      </Tabs.List>
      <Tabs.Content value="one">
        Dis metus rhoncus sit convallis sollicitudin vel cum, hac purus tincidunt eros sem himenaeos
        integer, faucibus varius nullam nostra bibendum consectetur mollis, gravida elementum
        pellentesque volutpat dictum ipsum.
      </Tabs.Content>
      <Tabs.Content value="two">You'll never find me!</Tabs.Content>
      <Tabs.Content value="three">
        Ut nisi elementum metus semper mauris dui fames accumsan aenean, maecenas ac sociis dolor
        quam tempus pretium.
      </Tabs.Content>
    </Tabs.Root>
  );
}



================================================
FILE: apps/ssr-testing/app/toast/page.tsx
================================================
import * as React from 'react';
import { Toast } from 'radix-ui';

export default function Page() {
  return (
    <Toast.Provider>
      <Toast.Root>
        <Toast.Title>Toast</Toast.Title>
        <Toast.Description>This is a toast message.</Toast.Description>
        <Toast.Action altText="Do something">Do something</Toast.Action>
        <Toast.Close>Close</Toast.Close>
      </Toast.Root>

      <Toast.Viewport />
    </Toast.Provider>
  );
}



================================================
FILE: apps/ssr-testing/app/toggle-group/page.tsx
================================================
import * as React from 'react';
import { ToggleGroup } from 'radix-ui';

export default function Page() {
  return (
    <ToggleGroup.Root defaultValue="1" type="single">
      <ToggleGroup.Item value="1">Item 1</ToggleGroup.Item>
      <ToggleGroup.Item value="2">Item 2</ToggleGroup.Item>
    </ToggleGroup.Root>
  );
}



================================================
FILE: apps/ssr-testing/app/toolbar/page.tsx
================================================
import * as React from 'react';
import { Toolbar } from 'radix-ui';

export default function Page() {
  return (
    <Toolbar.Root orientation="vertical">
      <Toolbar.Button>Button</Toolbar.Button>
      <Toolbar.Separator>***</Toolbar.Separator>
      <Toolbar.Link href="#">Link</Toolbar.Link>
    </Toolbar.Root>
  );
}



================================================
FILE: apps/ssr-testing/app/tooltip/page.tsx
================================================
import * as React from 'react';
import { Tooltip } from 'radix-ui';

export default function Page() {
  return (
    <Tooltip.Provider>
      <Tooltip.Root>
        <Tooltip.Trigger>Hover or Focus me</Tooltip.Trigger>
        <Tooltip.Portal>
          <Tooltip.Content sideOffset={5}>
            Nicely done!
            <Tooltip.Arrow />
          </Tooltip.Content>
        </Tooltip.Portal>
      </Tooltip.Root>
    </Tooltip.Provider>
  );
}



================================================
FILE: apps/ssr-testing/app/visually-hidden/page.tsx
================================================
import * as React from 'react';
import { VisuallyHidden } from 'radix-ui';

export default function Page() {
  return (
    <div>
      You won't see this:
      <VisuallyHidden.Root>🙈</VisuallyHidden.Root>
    </div>
  );
}



================================================
FILE: apps/storybook/eslint.config.js
================================================
// @ts-check
import storybook from 'eslint-plugin-storybook';
import { configs } from '@repo/eslint-config/vite';

/** @type {import("eslint").Linter.Config[]} */
export default [...configs, ...storybook.configs['flat/recommended']];



================================================
FILE: apps/storybook/index.d.ts
================================================
type CSSModuleClasses = { readonly [key: string]: string };

declare module '*.module.css' {
  const classes: CSSModuleClasses;
  export default classes;
}

declare module '*.css' {}



================================================
FILE: apps/storybook/package.json
================================================
{
  "name": "@repo/storybook",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "lint": "eslint --max-warnings 0 .",
    "dev": "storybook dev -p 6006",
    "build": "storybook build",
    "serve": "serve storybook-static -l 6006",
    "typecheck": "tsc --noEmit"
  },
  "dependencies": {
    "@radix-ui/colors": "^3.0.0",
    "@repo/test-data": "workspace:*",
    "form-serialize": "^0.7.2",
    "radix-ui": "workspace:*",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "react-remove-scroll": "^2.6.3"
  },
  "devDependencies": {
    "@chromatic-com/storybook": "^4.1.1",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@storybook/addon-docs": "^9.1.15",
    "@storybook/addon-webpack5-compiler-swc": "^4.0.1",
    "@storybook/react-webpack5": "^9.1.15",
    "@types/form-serialize": "^0",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "eslint-plugin-storybook": "^9.1.15",
    "serve": "^14.2.5",
    "storybook": "^9.1.15",
    "typescript": "^5.9.3"
  }
}



================================================
FILE: apps/storybook/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "include": ["stories", "index.d.ts"]
}



================================================
FILE: apps/storybook/stories/accessible-icon.stories.tsx
================================================
import { AccessibleIcon } from 'radix-ui';

export default { title: 'Utilities/AccessibleIcon' };

export const Styled = () => (
  <button type="button">
    <AccessibleIcon.Root label="Close">
      <CrossIcon />
    </AccessibleIcon.Root>
  </button>
);

export const Chromatic = () => (
  <p>
    Some text with an inline accessible icon{' '}
    <AccessibleIcon.Root label="Close">
      <CrossIcon />
    </AccessibleIcon.Root>
  </p>
);

Chromatic.parameters = { chromatic: { disable: false } };

const CrossIcon = () => (
  <svg viewBox="0 0 32 32" width={24} height={24} fill="none" stroke="currentColor">
    <path d="M2 30 L30 2 M30 30 L2 2" />
  </svg>
);



================================================
FILE: apps/storybook/stories/accordion.stories.module.css
================================================
.root {
  font-family: sans-serif;
  &[data-orientation='horizontal'] {
    display: flex;
    max-width: 40em;
    height: 50vh;
  }
  &[data-orientation='vertical'] {
    max-width: 20em;
  }
}

.item {
  &[data-orientation='horizontal'] {
    display: flex;
    border-right: 1px solid var(--gray-1);
  }

  &[data-orientation='vertical'] {
    border-bottom: 1px solid var(--gray-1);
  }
}

.header {
  margin: 0;
  &[data-orientation='horizontal'] {
    height: 100%;
  }
}

.trigger {
  /* because it's a button, we want to stretch it */
  &[data-orientation='horizontal'] {
    height: 100%;
  }
  &[data-orientation='vertical'] {
    width: 100%;
  }
  text-align: inherit;
  box-sizing: border-box;
  appearance: none;
  border: none;
  padding: 10px;
  background-color: black;
  color: var(--gray-1);
  font-family: inherit;
  font-size: 1.2em;

  &:focus {
    outline: 2px solid var(--red-8);
    color: var(--red-9);
  }

  &[data-disabled] {
    color: var(--gray-9);
  }

  &[data-state='open'] {
    background-color: var(--red-9);
    color: var(--gray-1);

    &:focus {
      color: var(--gray-12);
    }
  }
}

.content {
  padding: 10px;
  line-height: 1.5;
}

.animatedContent {
  overflow: hidden;
  &[data-state='open'] {
    animation: accordion-slideDown 300ms ease-out;
  }
  &[data-state='closed'] {
    animation: accordion-slideUp 300ms ease-out;
  }
}

.animated2DContent {
  overflow: hidden;
  &[data-state='open'] {
    animation: accordion-open2D 1000ms ease-out;
  }
  &[data-state='closed'] {
    animation: accordion-close2D 1000ms ease-out;
  }
}

.rootAttr,
.itemAttr,
.headerAttr,
.triggerAttr,
.contentAttr {
  background-color: var(--blue-a12);
  border: 2px solid var(--blue-9);
  padding: 10px;

  &[data-state='closed'] {
    border-color: var(--red-9);
  }
  &[data-state='open'] {
    border-color: var(--green-9);
  }
  &[data-disabled] {
    border-style: dashed;
  }
  &:disabled {
    opacity: 0.5;
  }
}

.contentAttr {
  /* ensure we can see the content (because it has `hidden` attribute) */
  display: block;
}

@keyframes accordion-slideDown {
  from {
    height: 0;
  }
  to {
    height: var(--radix-accordion-content-height);
  }
}

@keyframes accordion-slideUp {
  from {
    height: var(--radix-accordion-content-height);
  }
  to {
    height: 0;
  }
}

@keyframes accordion-open2D {
  from {
    width: 0;
    height: 0;
  }
  to {
    width: var(--radix-accordion-content-width);
    height: var(--radix-accordion-content-height);
  }
}

@keyframes accordion-close2D {
  from {
    width: var(--radix-accordion-content-width);
    height: var(--radix-accordion-content-height);
  }
  to {
    width: 0;
    height: 0;
  }
}



================================================
FILE: apps/storybook/stories/accordion.stories.tsx
================================================
/* eslint-disable jsx-a11y/anchor-is-valid */
import * as React from 'react';
import { Accordion } from 'radix-ui';
import styles from './accordion.stories.module.css';

export default { title: 'Components/Accordion' };

export const Single = () => {
  const [valueOne, setValueOne] = React.useState('one');

  return (
    <>
      <h1>Uncontrolled</h1>
      <Accordion.Root type="single" className={styles.root}>
        <Accordion.Item className={styles.item} value="one">
          <Accordion.Header className={styles.header}>
            <Accordion.Trigger className={styles.trigger}>One</Accordion.Trigger>
          </Accordion.Header>
          <Accordion.Content className={styles.content}>
            Per erat orci nostra luctus sociosqu mus risus penatibus, duis elit vulputate viverra
            integer ullamcorper congue curabitur sociis, nisi malesuada scelerisque quam suscipit
            habitant sed.
          </Accordion.Content>
        </Accordion.Item>
        <Accordion.Item className={styles.item} value="two">
          <Accordion.Header className={styles.header}>
            <Accordion.Trigger className={styles.trigger}>Two</Accordion.Trigger>
          </Accordion.Header>
          <Accordion.Content className={styles.content}>
            Cursus sed mattis commodo fermentum conubia ipsum pulvinar sagittis, diam eget bibendum
            porta nascetur ac dictum, leo tellus dis integer platea ultrices mi.
          </Accordion.Content>
        </Accordion.Item>
        <Accordion.Item className={styles.item} value="three" disabled>
          <Accordion.Header className={styles.header}>
            <Accordion.Trigger className={styles.trigger}>Three (disabled)</Accordion.Trigger>
          </Accordion.Header>
          <Accordion.Content className={styles.content}>
            Sociis hac sapien turpis conubia sagittis justo dui, inceptos penatibus feugiat
            himenaeos euismod magna, nec tempor pulvinar eu etiam mattis.
          </Accordion.Content>
        </Accordion.Item>
        <Accordion.Item className={styles.item} value="four">
          <Accordion.Header className={styles.header}>
            <Accordion.Trigger className={styles.trigger}>Four</Accordion.Trigger>
          </Accordion.Header>
          <Accordion.Content className={styles.content}>
            Odio placerat <a href="#">quisque</a> sapien sagittis non sociis ligula penatibus
            dignissim vitae, enim vulputate nullam semper potenti etiam volutpat libero.
            <button>Cool</button>
          </Accordion.Content>
        </Accordion.Item>
      </Accordion.Root>

      <h1>Controlled</h1>
      <Accordion.Root
        type="single"
        value={valueOne}
        onValueChange={setValueOne}
        className={styles.root}
      >
        <Accordion.Item className={styles.item} value="one">
          <Accordion.Header className={styles.header}>
            <Accordion.Trigger className={styles.trigger}>One</Accordion.Trigger>
          </Accordion.Header>
          <Accordion.Content className={styles.content}>
            Per erat orci nostra luctus sociosqu mus risus penatibus, duis elit vulputate viverra
            integer ullamcorper congue curabitur sociis, nisi malesuada scelerisque quam suscipit
            habitant sed.
          </Accordion.Content>
        </Accordion.Item>
        <Accordion.Item className={styles.item} value="two">
          <Accordion.Header className={styles.header}>
            <Accordion.Trigger className={styles.trigger}>Two</Accordion.Trigger>
          </Accordion.Header>
          <Accordion.Content className={styles.content}>
            Cursus sed mattis commodo fermentum conubia ipsum pulvinar sagittis, diam eget bibendum
            porta nascetur ac dictum, leo tellus dis integer platea ultrices mi.
          </Accordion.Content>
        </Accordion.Item>
        <Accordion.Item className={styles.item} value="three" disabled>
          <Accordion.Header className={styles.header}>
            <Accordion.Trigger className={styles.trigger}>Three (disabled)</Accordion.Trigger>
          </Accordion.Header>
          <Accordion.Content className={styles.content}>
            Sociis hac sapien turpis conubia sagittis justo dui, inceptos penatibus feugiat
            himenaeos euismod magna, nec tempor pulvinar eu etiam mattis.
          </Accordion.Content>
        </Accordion.Item>
        <Accordion.Item className={styles.item} value="four">
          <Accordion.Header className={styles.header}>
            <Accordion.Trigger className={styles.trigger}>Four</Accordion.Trigger>
          </Accordion.Header>
          <Accordion.Content className={styles.content}>
            Odio placerat <a href="#">quisque</a> sapien sagittis non sociis ligula penatibus
            dignissim vitae, enim vulputate nullam semper potenti etiam volutpat libero.
            <button>Cool</button>
          </Accordion.Content>
        </Accordion.Item>
      </Accordion.Root>

      <h1>Collapsible</h1>
      <Accordion.Root type="single" className={styles.root} defaultValue="one" collapsible>
        <Accordion.Item className={styles.item} value="one">
          <Accordion.Header className={styles.header}>
            <Accordion.Trigger className={styles.trigger}>One</Accordion.Trigger>
          </Accordion.Header>
          <Accordion.Content className={styles.content}>
            Per erat orci nostra luctus sociosqu mus risus penatibus, duis elit vulputate viverra
            integer ullamcorper congue curabitur sociis, nisi malesuada scelerisque quam suscipit
            habitant sed.
          </Accordion.Content>
        </Accordion.Item>
        <Accordion.Item className={styles.item} value="two">
          <Accordion.Header className={styles.header}>
            <Accordion.Trigger className={styles.trigger}>Two</Accordion.Trigger>
          </Accordion.Header>
          <Accordion.Content className={styles.content}>
            Cursus sed mattis commodo fermentum conubia ipsum pulvinar sagittis, diam eget bibendum
            porta nascetur ac dictum, leo tellus dis integer platea ultrices mi.
          </Accordion.Content>
        </Accordion.Item>
        <Accordion.Item className={styles.item} value="three" disabled>
          <Accordion.Header className={styles.header}>
            <Accordion.Trigger className={styles.trigger}>Three (disabled)</Accordion.Trigger>
          </Accordion.Header>
          <Accordion.Content className={styles.content}>
            Sociis hac sapien turpis conubia sagittis justo dui, inceptos penatibus feugiat
            himenaeos euismod magna, nec tempor pulvinar eu etiam mattis.
          </Accordion.Content>
        </Accordion.Item>
        <Accordion.Item className={styles.item} value="four">
          <Accordion.Header className={styles.header}>
            <Accordion.Trigger className={styles.trigger}>Four</Accordion.Trigger>
          </Accordion.Header>
          <Accordion.Content className={styles.content}>
            Odio placerat <a href="#">quisque</a> sapien sagittis non sociis ligula penatibus
            dignissim vitae, enim vulputate nullam semper potenti etiam volutpat libero.
            <button>Cool</button>
          </Accordion.Content>
        </Accordion.Item>
      </Accordion.Root>
    </>
  );
};

export const Multiple = () => {
  const [value, setValue] = React.useState(['one', 'two']);

  return (
    <>
      <h1>Uncontrolled</h1>
      <Accordion.Root type="multiple" className={styles.root}>
        <Accordion.Item className={styles.item} value="one">
          <Accordion.Header className={styles.header}>
            <Accordion.Trigger className={styles.trigger}>One</Accordion.Trigger>
          </Accordion.Header>
          <Accordion.Content className={styles.content}>
            Per erat orci nostra luctus sociosqu mus risus penatibus, duis elit vulputate viverra
            integer ullamcorper congue curabitur sociis, nisi malesuada scelerisque quam suscipit
            habitant sed.
          </Accordion.Content>
        </Accordion.Item>
        <Accordion.Item className={styles.item} value="two">
          <Accordion.Header className={styles.header}>
            <Accordion.Trigger className={styles.trigger}>Two</Accordion.Trigger>
          </Accordion.Header>
          <Accordion.Content className={styles.content}>
            Cursus sed mattis commodo fermentum conubia ipsum pulvinar sagittis, diam eget bibendum
            porta nascetur ac dictum, leo tellus dis integer platea ultrices mi.
          </Accordion.Content>
        </Accordion.Item>
        <Accordion.Item className={styles.item} value="three" disabled>
          <Accordion.Header className={styles.header}>
            <Accordion.Trigger className={styles.trigger}>Three (disabled)</Accordion.Trigger>
          </Accordion.Header>
          <Accordion.Content className={styles.content}>
            Sociis hac sapien turpis conubia sagittis justo dui, inceptos penatibus feugiat
            himenaeos euismod magna, nec tempor pulvinar eu etiam mattis.
          </Accordion.Content>
        </Accordion.Item>
        <Accordion.Item className={styles.item} value="four">
          <Accordion.Header className={styles.header}>
            <Accordion.Trigger className={styles.trigger}>Four</Accordion.Trigger>
          </Accordion.Header>
          <Accordion.Content className={styles.content}>
            Odio placerat <a href="#">quisque</a> sapien sagittis non sociis ligula penatibus
            dignissim vitae, enim vulputate nullam semper potenti etiam volutpat libero.
            <button>Cool</button>
          </Accordion.Content>
        </Accordion.Item>
      </Accordion.Root>

      <h1>Controlled</h1>
      <Accordion.Root
        type="multiple"
        value={value}
        onValueChange={setValue}
        className={styles.root}
      >
        <Accordion.Item className={styles.item} value="one">
          <Accordion.Header className={styles.header}>
            <Accordion.Trigger className={styles.trigger}>One</Accordion.Trigger>
          </Accordion.Header>
          <Accordion.Content className={styles.content}>
            Per erat orci nostra luctus sociosqu mus risus penatibus, duis elit vulputate viverra
            integer ullamcorper congue curabitur sociis, nisi malesuada scelerisque quam suscipit
            habitant sed.
          </Accordion.Content>
        </Accordion.Item>
        <Accordion.Item className={styles.item} value="two">
          <Accordion.Header className={styles.header}>
            <Accordion.Trigger className={styles.trigger}>Two</Accordion.Trigger>
          </Accordion.Header>
          <Accordion.Content className={styles.content}>
            Cursus sed mattis commodo fermentum conubia ipsum pulvinar sagittis, diam eget bibendum
            porta nascetur ac dictum, leo tellus dis integer platea ultrices mi.
          </Accordion.Content>
        </Accordion.Item>
        <Accordion.Item className={styles.item} value="three" disabled>
          <Accordion.Header className={styles.header}>
            <Accordion.Trigger className={styles.trigger}>Three (disabled)</Accordion.Trigger>
          </Accordion.Header>
          <Accordion.Content className={styles.content}>
            Sociis hac sapien turpis conubia sagittis justo dui, inceptos penatibus feugiat
            himenaeos euismod magna, nec tempor pulvinar eu etiam mattis.
          </Accordion.Content>
        </Accordion.Item>
        <Accordion.Item className={styles.item} value="four">
          <Accordion.Header className={styles.header}>
            <Accordion.Trigger className={styles.trigger}>Four</Accordion.Trigger>
          </Accordion.Header>
          <Accordion.Content className={styles.content}>
            Odio placerat <a href="#">quisque</a> sapien sagittis non sociis ligula penatibus
            dignissim vitae, enim vulputate nullam semper potenti etiam volutpat libero.
            <button>Cool</button>
          </Accordion.Content>
        </Accordion.Item>
      </Accordion.Root>
    </>
  );
};

export const Animated = () => {
  const values = ['One', 'Two', 'Three', 'Four'];
  const [count, setCount] = React.useState(1);
  const [hasDynamicContent, setHasDynamicContent] = React.useState(false);
  const timerRef = React.useRef(0);

  React.useEffect(() => {
    if (hasDynamicContent) {
      timerRef.current = window.setTimeout(() => {
        setCount((prevCount) => {
          const nextCount = prevCount < 5 ? prevCount + 1 : prevCount;
          if (nextCount === 5) setHasDynamicContent(false);
          return nextCount;
        });
      }, 3000);
      return () => {
        clearTimeout(timerRef.current);
      };
    }
  }, [count, hasDynamicContent]);

  return (
    <>
      <label>
        <input
          type="checkbox"
          checked={hasDynamicContent}
          onChange={(event) => {
            const checked = event.target.checked;
            if (checked) setCount(1);
            setHasDynamicContent(checked);
          }}
        />{' '}
        Dynamic content
      </label>
      <br />
      <br />
      <h1>Closed by default</h1>
      <Accordion.Root type="single" className={styles.root}>
        {values.map((value) => (
          <Accordion.Item key={value} value={value} className={styles.item}>
            <Accordion.Header className={styles.header}>
              <Accordion.Trigger className={styles.trigger}>{value}</Accordion.Trigger>
            </Accordion.Header>
            <Accordion.Content className={styles.animatedContent}>
              {[...Array(count)].map((_, index) => (
                <div style={{ padding: 10 }} key={index}>
                  Per erat orci nostra luctus sociosqu mus risus penatibus, duis elit vulputate
                  viverra integer ullamcorper congue curabitur sociis, nisi malesuada scelerisque
                  quam suscipit habitant sed.
                </div>
              ))}
            </Accordion.Content>
          </Accordion.Item>
        ))}
      </Accordion.Root>

      <h1>Open by default</h1>
      <Accordion.Root type="single" className={styles.root} defaultValue="One">
        {values.map((value) => (
          <Accordion.Item key={value} value={value} className={styles.item}>
            <Accordion.Header className={styles.header}>
              <Accordion.Trigger className={styles.trigger}>{value}</Accordion.Trigger>
            </Accordion.Header>
            <Accordion.Content className={styles.animatedContent}>
              {[...Array(count)].map((_, index) => (
                <div style={{ padding: 10 }} key={index}>
                  Per erat orci nostra luctus sociosqu mus risus penatibus, duis elit vulputate
                  viverra integer ullamcorper congue curabitur sociis, nisi malesuada scelerisque
                  quam suscipit habitant sed.
                </div>
              ))}
            </Accordion.Content>
          </Accordion.Item>
        ))}
      </Accordion.Root>
    </>
  );
};

export const Animated2D = () => {
  const values = ['One', 'Two', 'Three', 'Four'];

  return (
    <>
      <Accordion.Root type="single" className={styles.root}>
        {values.map((value) => (
          <Accordion.Item key={value} value={value} className={styles.item}>
            <Accordion.Header className={styles.header}>
              <Accordion.Trigger className={styles.trigger}>{value}</Accordion.Trigger>
            </Accordion.Header>
            <Accordion.Content className={styles.animated2DContent}>
              <div style={{ padding: 10, background: 'whitesmoke', overflow: 'hidden' }}>
                <div style={{ width: 'calc(20em - 20px)', height: 100 }}>
                  Per erat orci nostra luctus sociosqu mus risus penatibus, duis elit vulputate
                  viverra integer ullamcorper congue curabitur sociis, nisi malesuada scelerisque
                  quam suscipit habitant sed.
                </div>
              </div>
            </Accordion.Content>
          </Accordion.Item>
        ))}
      </Accordion.Root>
    </>
  );
};

export const AnimatedControlled = () => {
  const [value, setValue] = React.useState(['one', 'two', 'three', 'four']);
  return (
    <Accordion.Root type="multiple" value={value} onValueChange={setValue} className={styles.root}>
      <Accordion.Item className={styles.item} value="one">
        <Accordion.Header className={styles.header}>
          <Accordion.Trigger className={styles.trigger}>One</Accordion.Trigger>
        </Accordion.Header>
        <Accordion.Content className={styles.animatedContent}>
          Per erat orci nostra luctus sociosqu mus risus penatibus, duis elit vulputate viverra
          integer ullamcorper congue curabitur sociis, nisi malesuada scelerisque quam suscipit
          habitant sed.
        </Accordion.Content>
      </Accordion.Item>
      <Accordion.Item className={styles.item} value="two">
        <Accordion.Header className={styles.header}>
          <Accordion.Trigger className={styles.trigger}>Two</Accordion.Trigger>
        </Accordion.Header>
        <Accordion.Content className={styles.animatedContent}>
          Cursus sed mattis commodo fermentum conubia ipsum pulvinar sagittis, diam eget bibendum
          porta nascetur ac dictum, leo tellus dis integer platea ultrices mi.
        </Accordion.Content>
      </Accordion.Item>
      <Accordion.Item className={styles.item} value="three">
        <Accordion.Header className={styles.header}>
          <Accordion.Trigger className={styles.trigger}>Three</Accordion.Trigger>
        </Accordion.Header>
        <Accordion.Content className={styles.animatedContent}>
          Sociis hac sapien turpis conubia sagittis justo dui, inceptos penatibus feugiat himenaeos
          euismod magna, nec tempor pulvinar eu etiam mattis.
        </Accordion.Content>
      </Accordion.Item>
      <Accordion.Item className={styles.item} value="four">
        <Accordion.Header className={styles.header}>
          <Accordion.Trigger className={styles.trigger}>Four</Accordion.Trigger>
        </Accordion.Header>
        <Accordion.Content className={styles.animatedContent}>
          Odio placerat <a href="#">quisque</a> sapien sagittis non sociis ligula penatibus
          dignissim vitae, enim vulputate nullam semper potenti etiam volutpat libero.
          <button>Cool</button>
        </Accordion.Content>
      </Accordion.Item>
    </Accordion.Root>
  );
};

export const OutsideViewport = () => (
  <>
    <p>Scroll down to see tabs</p>
    <div style={{ height: '150vh' }} />
    <p>
      When accordion buttons are focused and the user is navigating via keyboard, the page should
      not scroll unless the next tab is entering the viewport.
    </p>
    <Accordion.Root type="single" className={styles.root}>
      <Accordion.Item className={styles.item} value="one">
        <Accordion.Header className={styles.header}>
          <Accordion.Trigger className={styles.trigger}>One</Accordion.Trigger>
        </Accordion.Header>
        <Accordion.Content className={styles.content}>
          Per erat orci nostra luctus sociosqu mus risus penatibus, duis elit vulputate viverra
          integer ullamcorper congue curabitur sociis, nisi malesuada scelerisque quam suscipit
          habitant sed.
        </Accordion.Content>
      </Accordion.Item>
      <Accordion.Item className={styles.item} value="two">
        <Accordion.Header className={styles.header}>
          <Accordion.Trigger className={styles.trigger}>Two</Accordion.Trigger>
        </Accordion.Header>
        <Accordion.Content className={styles.content}>
          Cursus sed mattis commodo fermentum conubia ipsum pulvinar sagittis, diam eget bibendum
          porta nascetur ac dictum, leo tellus dis integer platea ultrices mi.
        </Accordion.Content>
      </Accordion.Item>
      <Accordion.Item className={styles.item} value="three" disabled>
        <Accordion.Header className={styles.header}>
          <Accordion.Trigger className={styles.trigger}>Three (disabled)</Accordion.Trigger>
        </Accordion.Header>
        <Accordion.Content className={styles.content}>
          Sociis hac sapien turpis conubia sagittis justo dui, inceptos penatibus feugiat himenaeos
          euismod magna, nec tempor pulvinar eu etiam mattis.
        </Accordion.Content>
      </Accordion.Item>
      <Accordion.Item className={styles.item} value="four">
        <Accordion.Header className={styles.header}>
          <Accordion.Trigger className={styles.trigger}>Four</Accordion.Trigger>
        </Accordion.Header>
        <Accordion.Content className={styles.content}>
          Odio placerat <a href="#">quisque</a> sapien sagittis non sociis ligula penatibus
          dignissim vitae, enim vulputate nullam semper potenti etiam volutpat libero.
          <button>Cool</button>
        </Accordion.Content>
      </Accordion.Item>
    </Accordion.Root>
    <div style={{ height: '150vh' }} />
  </>
);

export const Horizontal = () => (
  <>
    <h1>Horizontal Orientation</h1>
    <Accordion.Root type="single" className={styles.root} orientation="horizontal">
      <Accordion.Item className={styles.item} value="one">
        <Accordion.Header className={styles.header}>
          <Accordion.Trigger className={styles.trigger}>One</Accordion.Trigger>
        </Accordion.Header>
        <Accordion.Content className={styles.content}>
          Per erat orci nostra luctus sociosqu mus risus penatibus, duis elit vulputate viverra
          integer ullamcorper congue curabitur sociis, nisi malesuada scelerisque quam suscipit
          habitant sed.
        </Accordion.Content>
      </Accordion.Item>
      <Accordion.Item className={styles.item} value="two">
        <Accordion.Header className={styles.header}>
          <Accordion.Trigger className={styles.trigger}>Two</Accordion.Trigger>
        </Accordion.Header>
        <Accordion.Content className={styles.content}>
          Cursus sed mattis commodo fermentum conubia ipsum pulvinar sagittis, diam eget bibendum
          porta nascetur ac dictum, leo tellus dis integer platea ultrices mi.
        </Accordion.Content>
      </Accordion.Item>
      <Accordion.Item className={styles.item} value="three" disabled>
        <Accordion.Header className={styles.header}>
          <Accordion.Trigger className={styles.trigger}>Three (disabled)</Accordion.Trigger>
        </Accordion.Header>
        <Accordion.Content className={styles.content}>
          Sociis hac sapien turpis conubia sagittis justo dui, inceptos penatibus feugiat himenaeos
          euismod magna, nec tempor pulvinar eu etiam mattis.
        </Accordion.Content>
      </Accordion.Item>
      <Accordion.Item className={styles.item} value="four">
        <Accordion.Header className={styles.header}>
          <Accordion.Trigger className={styles.trigger}>Four</Accordion.Trigger>
        </Accordion.Header>
        <Accordion.Content className={styles.content}>
          Odio placerat <a href="#">quisque</a> sapien sagittis non sociis ligula penatibus
          dignissim vitae, enim vulputate nullam semper potenti etiam volutpat libero.
          <button>Cool</button>
        </Accordion.Content>
      </Accordion.Item>
    </Accordion.Root>
  </>
);

export const Chromatic = () => {
  const items = ['One', 'Two', 'Three', 'Four'];
  return (
    <>
      <h1>Uncontrolled</h1>
      <h2>Single closed</h2>
      <Accordion.Root type="single" className={styles.root}>
        {items.map((item) => (
          <Accordion.Item key={item} className={styles.item} value={item}>
            <Accordion.Header className={styles.header}>
              <Accordion.Trigger className={styles.trigger}>{item}</Accordion.Trigger>
            </Accordion.Header>
            <Accordion.Content className={styles.content}>
              {item}: Per erat orci nostra luctus sociosqu mus risus penatibus, duis elit vulputate
              viverra integer ullamcorper congue curabitur sociis, nisi malesuada scelerisque quam
              suscipit habitant sed.
            </Accordion.Content>
          </Accordion.Item>
        ))}
      </Accordion.Root>

      <h2>Single open</h2>
      <Accordion.Root type="single" className={styles.root} defaultValue="Two">
        {items.map((item) => (
          <Accordion.Item key={item} className={styles.item} value={item}>
            <Accordion.Header className={styles.header}>
              <Accordion.Trigger className={styles.trigger}>{item}</Accordion.Trigger>
            </Accordion.Header>
            <Accordion.Content className={styles.content}>
              {item}: Per erat orci nostra luctus sociosqu mus risus penatibus, duis elit vulputate
              viverra integer ullamcorper congue curabitur sociis, nisi malesuada scelerisque quam
              suscipit habitant sed.
            </Accordion.Content>
          </Accordion.Item>
        ))}
      </Accordion.Root>

      <h2>Multiple closed</h2>
      <Accordion.Root type="multiple" className={styles.root}>
        {items.map((item) => (
          <Accordion.Item key={item} className={styles.item} value={item}>
            <Accordion.Header className={styles.header}>
              <Accordion.Trigger className={styles.trigger}>{item}</Accordion.Trigger>
            </Accordion.Header>
            <Accordion.Content className={styles.content}>
              {item}: Per erat orci nostra luctus sociosqu mus risus penatibus, duis elit vulputate
              viverra integer ullamcorper congue curabitur sociis, nisi malesuada scelerisque quam
              suscipit habitant sed.
            </Accordion.Content>
          </Accordion.Item>
        ))}
      </Accordion.Root>

      <h2>Multiple open</h2>
      <Accordion.Root type="multiple" className={styles.root} defaultValue={['One', 'Two']}>
        {items.map((item) => (
          <Accordion.Item key={item} className={styles.item} value={item}>
            <Accordion.Header className={styles.header}>
              <Accordion.Trigger className={styles.trigger}>{item}</Accordion.Trigger>
            </Accordion.Header>
            <Accordion.Content className={styles.content}>
              {item}: Per erat orci nostra luctus sociosqu mus risus penatibus, duis elit vulputate
              viverra integer ullamcorper congue curabitur sociis, nisi malesuada scelerisque quam
              suscipit habitant sed.
            </Accordion.Content>
          </Accordion.Item>
        ))}
      </Accordion.Root>

      <h1>Controlled</h1>
      <h2>Single open</h2>
      <Accordion.Root type="single" className={styles.root} value="Three">
        {items.map((item) => (
          <Accordion.Item key={item} className={styles.item} value={item}>
            <Accordion.Header className={styles.header}>
              <Accordion.Trigger className={styles.trigger}>{item}</Accordion.Trigger>
            </Accordion.Header>
            <Accordion.Content className={styles.content}>
              {item}: Per erat orci nostra luctus sociosqu mus risus penatibus, duis elit vulputate
              viverra integer ullamcorper congue curabitur sociis, nisi malesuada scelerisque quam
              suscipit habitant sed.
            </Accordion.Content>
          </Accordion.Item>
        ))}
      </Accordion.Root>

      <h2>Multiple open</h2>
      <Accordion.Root type="multiple" className={styles.root} value={['Two', 'Three']}>
        {items.map((item) => (
          <Accordion.Item key={item} className={styles.item} value={item}>
            <Accordion.Header className={styles.header}>
              <Accordion.Trigger className={styles.trigger}>{item}</Accordion.Trigger>
            </Accordion.Header>
            <Accordion.Content className={styles.content}>
              {item}: Per erat orci nostra luctus sociosqu mus risus penatibus, duis elit vulputate
              viverra integer ullamcorper congue curabitur sociis, nisi malesuada scelerisque quam
              suscipit habitant sed.
            </Accordion.Content>
          </Accordion.Item>
        ))}
      </Accordion.Root>

      <h1>Disabled (whole)</h1>
      <Accordion.Root type="single" className={styles.root} disabled>
        {items.map((item) => (
          <Accordion.Item key={item} className={styles.item} value={item}>
            <Accordion.Header className={styles.header}>
              <Accordion.Trigger className={styles.trigger}>{item}</Accordion.Trigger>
            </Accordion.Header>
            <Accordion.Content className={styles.content}>
              {item}: Per erat orci nostra luctus sociosqu mus risus penatibus, duis elit vulputate
              viverra integer ullamcorper congue curabitur sociis, nisi malesuada scelerisque quam
              suscipit habitant sed.
            </Accordion.Content>
          </Accordion.Item>
        ))}
      </Accordion.Root>

      <h1>Disabled (item)</h1>
      <h2>Just item</h2>
      <Accordion.Root type="single" className={styles.root}>
        {items.map((item) => (
          <Accordion.Item key={item} className={styles.item} value={item} disabled={item === 'Two'}>
            <Accordion.Header className={styles.header}>
              <Accordion.Trigger className={styles.trigger}>{item}</Accordion.Trigger>
            </Accordion.Header>
            <Accordion.Content className={styles.content}>
              {item}: Per erat orci nostra luctus sociosqu mus risus penatibus, duis elit vulputate
              viverra integer ullamcorper congue curabitur sociis, nisi malesuada scelerisque quam
              suscipit habitant sed.
            </Accordion.Content>
          </Accordion.Item>
        ))}
      </Accordion.Root>

      <h2>with `disabled=false` on top-level</h2>
      <Accordion.Root type="single" className={styles.root} disabled={false}>
        {items.map((item) => (
          <Accordion.Item key={item} className={styles.item} value={item} disabled={item === 'Two'}>
            <Accordion.Header className={styles.header}>
              <Accordion.Trigger className={styles.trigger}>{item}</Accordion.Trigger>
            </Accordion.Header>
            <Accordion.Content className={styles.content}>
              {item}: Per erat orci nostra luctus sociosqu mus risus penatibus, duis elit vulputate
              viverra integer ullamcorper congue curabitur sociis, nisi malesuada scelerisque quam
              suscipit habitant sed.
            </Accordion.Content>
          </Accordion.Item>
        ))}
      </Accordion.Root>

      <h1>Force mounted contents</h1>
      <Accordion.Root type="single" className={styles.root}>
        {items.map((item) => (
          <Accordion.Item key={item} className={styles.item} value={item}>
            <Accordion.Header className={styles.header}>
              <Accordion.Trigger className={styles.trigger}>{item}</Accordion.Trigger>
            </Accordion.Header>
            <Accordion.Content className={styles.content} forceMount>
              {item}: Per erat orci nostra luctus sociosqu mus risus penatibus, duis elit vulputate
              viverra integer ullamcorper congue curabitur sociis, nisi malesuada scelerisque quam
              suscipit habitant sed.
            </Accordion.Content>
          </Accordion.Item>
        ))}
      </Accordion.Root>

      <h1>State attributes</h1>
      <h2>Accordion disabled</h2>
      <Accordion.Root type="single" className={styles.rootAttr} defaultValue="Two" disabled>
        {items.map((item) => (
          <Accordion.Item key={item} className={styles.itemAttr} value={item}>
            <Accordion.Header className={styles.headerAttr}>
              <Accordion.Trigger className={styles.triggerAttr}>{item}</Accordion.Trigger>
            </Accordion.Header>
            <Accordion.Content className={styles.contentAttr}>
              {item}: Per erat orci nostra luctus sociosqu mus risus penatibus, duis elit vulputate
              viverra integer ullamcorper congue curabitur sociis, nisi malesuada scelerisque quam
              suscipit habitant sed.
            </Accordion.Content>
          </Accordion.Item>
        ))}
      </Accordion.Root>

      <h2>Accordion enabled with item override</h2>
      <Accordion.Root type="single" className={styles.rootAttr} defaultValue="Two" disabled={false}>
        {items.map((item) => (
          <Accordion.Item
            key={item}
            className={styles.itemAttr}
            value={item}
            disabled={['Two', 'Four'].includes(item)}
          >
            <Accordion.Header className={styles.headerAttr}>
              <Accordion.Trigger className={styles.triggerAttr}>{item}</Accordion.Trigger>
            </Accordion.Header>
            <Accordion.Content className={styles.contentAttr}>
              {item}: Per erat orci nostra luctus sociosqu mus risus penatibus, duis elit vulputate
              viverra integer ullamcorper congue curabitur sociis, nisi malesuada scelerisque quam
              suscipit habitant sed.
            </Accordion.Content>
          </Accordion.Item>
        ))}
      </Accordion.Root>

      <h2>Accordion disabled with item override</h2>
      <Accordion.Root type="single" className={styles.rootAttr} defaultValue="Two" disabled={true}>
        {items.map((item) => (
          <Accordion.Item
            key={item}
            className={styles.itemAttr}
            value={item}
            disabled={['Two', 'Four'].includes(item) ? false : undefined}
          >
            <Accordion.Header className={styles.headerAttr}>
              <Accordion.Trigger className={styles.triggerAttr}>{item}</Accordion.Trigger>
            </Accordion.Header>
            <Accordion.Content className={styles.contentAttr}>
              {item}: Per erat orci nostra luctus sociosqu mus risus penatibus, duis elit vulputate
              viverra integer ullamcorper congue curabitur sociis, nisi malesuada scelerisque quam
              suscipit habitant sed.
            </Accordion.Content>
          </Accordion.Item>
        ))}
      </Accordion.Root>
    </>
  );
};
Chromatic.parameters = { chromatic: { disable: false } };



================================================
FILE: apps/storybook/stories/alert-dialog.stories.module.css
================================================
.trigger {
}

.overlay,
.overlayAttr {
  /* ensures overlay is positionned correctly */
  position: fixed;
  inset: 0;
  /* --------- */
  background-color: var(--gray-12);
  opacity: 0.2;
}

.content,
.chromaticContent,
.contentAttr {
  /* ensures good default position for content */
  position: fixed;
  top: 0;
  left: 0;
  /* --------- */
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background: var(--gray-1);
  min-width: 300px;
  min-height: 150px;
  padding: 50px;
  border-radius: 10px;
  background-color: var(--gray-1);
  box-shadow: 0 2px 10px var(--black-a6);
}

.cancel,
.action {
  appearance: none;
  padding: 10px;
  border: none;
}

.cancel {
  background: var(--gray-3);
  color: var(--gray-12);
}

.action {
  background: var(--red-9);
  color: var(--gray-1);
}

.title {
}

.description {
}

.chromaticContent {
  padding: 10px;
  min-width: auto;
  min-height: auto;
}

.triggerAttr .overlayAttr,
.contentAttr,
.cancelAttr,
.actionAttr,
.titleAttr,
.descriptionAttr {
  background-color: var(--blue-a12);
  border: 2px solid var(--blue-9);
  padding: 10px;
  &[data-state='closed'] {
    border-color: var(--red-9);
  }
  &[data-state='open'] {
    border-color: var(--green-9);
  }
}



================================================
FILE: apps/storybook/stories/alert-dialog.stories.tsx
================================================
import * as React from 'react';
import { AlertDialog } from 'radix-ui';
import styles from './alert-dialog.stories.module.css';

export default { title: 'Components/AlertDialog' };

export const Styled = () => (
  <AlertDialog.Root>
    <AlertDialog.Trigger className={styles.trigger}>delete everything</AlertDialog.Trigger>
    <AlertDialog.Portal>
      <AlertDialog.Overlay className={styles.overlay} />
      <AlertDialog.Content className={styles.content}>
        <AlertDialog.Title className={styles.title}>Are you sure?</AlertDialog.Title>
        <AlertDialog.Description className={styles.description}>
          This will do a very dangerous thing. Thar be dragons!
        </AlertDialog.Description>
        <AlertDialog.Action className={styles.action}>yolo, do it</AlertDialog.Action>
        <AlertDialog.Cancel className={styles.cancel}>maybe not</AlertDialog.Cancel>
      </AlertDialog.Content>
    </AlertDialog.Portal>
  </AlertDialog.Root>
);

export const Controlled = () => {
  const [open, setOpen] = React.useState(false);
  const [housePurchased, setHousePurchased] = React.useState(false);

  return (
    <div>
      <div>
        <img src="https://i.ibb.co/K54hsKt/house.jpg" alt="a large white house with a red roof" />
      </div>
      <AlertDialog.Root open={open} onOpenChange={setOpen}>
        <AlertDialog.Trigger
          onClick={(e) => {
            if (housePurchased) {
              e.preventDefault();
              setHousePurchased(false);
            }
          }}
        >
          {housePurchased ? 'You bought the house! Sell it!' : 'Buy this house'}
        </AlertDialog.Trigger>
        <AlertDialog.Portal>
          <AlertDialog.Overlay className={styles.overlay} />
          <AlertDialog.Content className={styles.content}>
            <AlertDialog.Title>Are you sure?</AlertDialog.Title>
            <AlertDialog.Description>
              Houses are very expensive and it looks like you only have €20 in the bank. Maybe
              consult with a financial advisor?
            </AlertDialog.Description>
            <AlertDialog.Action className={styles.action} onClick={() => setHousePurchased(true)}>
              buy it anyway
            </AlertDialog.Action>
            <AlertDialog.Cancel className={styles.cancel}>
              good point, I'll reconsider
            </AlertDialog.Cancel>
          </AlertDialog.Content>
        </AlertDialog.Portal>
      </AlertDialog.Root>
    </div>
  );
};

export const Chromatic = () => (
  <div
    style={{
      display: 'grid',
      gridTemplateColumns: 'repeat(4, 1fr)',
      gridTemplateRows: 'repeat(2, 1fr)',
      height: '100vh',
    }}
  >
    <div>
      <h1>Uncontrolled</h1>
      <h2>Closed</h2>
      <AlertDialog.Root>
        <AlertDialog.Trigger className={styles.trigger}>delete everything</AlertDialog.Trigger>
        <AlertDialog.Portal>
          <AlertDialog.Overlay className={styles.overlay} />
          <AlertDialog.Content className={styles.chromaticContent}>
            <AlertDialog.Title className={styles.title}>Title</AlertDialog.Title>
            <AlertDialog.Description className={styles.description}>
              Description
            </AlertDialog.Description>
            <AlertDialog.Action className={styles.action}>Confirm</AlertDialog.Action>
            <AlertDialog.Cancel className={styles.cancel}>Cancel</AlertDialog.Cancel>
          </AlertDialog.Content>
        </AlertDialog.Portal>
      </AlertDialog.Root>

      <h2>Open</h2>
      <AlertDialog.Root defaultOpen>
        <AlertDialog.Trigger className={styles.trigger}>delete everything</AlertDialog.Trigger>
        <AlertDialog.Portal>
          <AlertDialog.Overlay
            className={styles.overlay}
            style={{ left: 0, bottom: '50%', width: '25%' }}
          />
          <AlertDialog.Content
            className={styles.chromaticContent}
            style={{ top: '25%', left: '12%' }}
          >
            <AlertDialog.Title className={styles.title}>Title</AlertDialog.Title>
            <AlertDialog.Description className={styles.description}>
              Description
            </AlertDialog.Description>
            <AlertDialog.Action className={styles.action}>Confirm</AlertDialog.Action>
            <AlertDialog.Cancel className={styles.cancel}>Cancel</AlertDialog.Cancel>
          </AlertDialog.Content>
        </AlertDialog.Portal>
      </AlertDialog.Root>
    </div>

    <div>
      <h1>Uncontrolled with reordered parts</h1>
      <h2>Closed</h2>
      <AlertDialog.Root>
        <AlertDialog.Portal>
          <AlertDialog.Overlay className={styles.overlay} />
          <AlertDialog.Content className={styles.chromaticContent}>
            <AlertDialog.Title className={styles.title}>Title</AlertDialog.Title>
            <AlertDialog.Description className={styles.description}>
              Description
            </AlertDialog.Description>
            <AlertDialog.Action className={styles.action}>Confirm</AlertDialog.Action>
            <AlertDialog.Cancel className={styles.cancel}>Cancel</AlertDialog.Cancel>
          </AlertDialog.Content>
        </AlertDialog.Portal>
        <AlertDialog.Trigger className={styles.trigger}>delete everything</AlertDialog.Trigger>
      </AlertDialog.Root>

      <h2>Open</h2>
      <AlertDialog.Root defaultOpen>
        <AlertDialog.Portal>
          <AlertDialog.Overlay
            className={styles.overlay}
            style={{ left: '25%', bottom: '50%', width: '25%' }}
          />
          <AlertDialog.Content
            className={styles.chromaticContent}
            style={{ top: '25%', left: '37%' }}
          >
            <AlertDialog.Title className={styles.title}>Title</AlertDialog.Title>
            <AlertDialog.Description className={styles.description}>
              Description
            </AlertDialog.Description>
            <AlertDialog.Action className={styles.action}>Confirm</AlertDialog.Action>
            <AlertDialog.Cancel className={styles.cancel}>Cancel</AlertDialog.Cancel>
          </AlertDialog.Content>
        </AlertDialog.Portal>
        <AlertDialog.Trigger className={styles.trigger}>delete everything</AlertDialog.Trigger>
      </AlertDialog.Root>
    </div>

    <div>
      <h1>Controlled</h1>
      <h2>Closed</h2>
      <AlertDialog.Root open={false}>
        <AlertDialog.Trigger className={styles.trigger}>delete everything</AlertDialog.Trigger>
        <AlertDialog.Portal>
          <AlertDialog.Overlay className={styles.overlay} />
          <AlertDialog.Content className={styles.chromaticContent}>
            <AlertDialog.Title className={styles.title}>Title</AlertDialog.Title>
            <AlertDialog.Description className={styles.description}>
              Description
            </AlertDialog.Description>
            <AlertDialog.Action className={styles.action}>Confirm</AlertDialog.Action>
            <AlertDialog.Cancel className={styles.cancel}>Cancel</AlertDialog.Cancel>
          </AlertDialog.Content>
        </AlertDialog.Portal>
      </AlertDialog.Root>

      <h2>Open</h2>
      <AlertDialog.Root open>
        <AlertDialog.Trigger className={styles.trigger}>delete everything</AlertDialog.Trigger>
        <AlertDialog.Portal>
          <AlertDialog.Overlay
            className={styles.overlay}
            style={{ left: '50%', bottom: '50%', width: '25%' }}
          />
          <AlertDialog.Content
            className={styles.chromaticContent}
            style={{ top: '25%', left: '62%' }}
          >
            <AlertDialog.Title className={styles.title}>Title</AlertDialog.Title>
            <AlertDialog.Description className={styles.description}>
              Description
            </AlertDialog.Description>
            <AlertDialog.Action className={styles.action}>Confirm</AlertDialog.Action>
            <AlertDialog.Cancel className={styles.cancel}>Cancel</AlertDialog.Cancel>
          </AlertDialog.Content>
        </AlertDialog.Portal>
      </AlertDialog.Root>
    </div>

    <div>
      <h1>Controlled with reordered parts</h1>
      <h2>Closed</h2>
      <AlertDialog.Root open={false}>
        <AlertDialog.Portal>
          <AlertDialog.Overlay className={styles.overlay} />
          <AlertDialog.Content className={styles.chromaticContent}>
            <AlertDialog.Title className={styles.title}>Title</AlertDialog.Title>
            <AlertDialog.Description className={styles.description}>
              Description
            </AlertDialog.Description>
            <AlertDialog.Action className={styles.action}>Confirm</AlertDialog.Action>
            <AlertDialog.Cancel className={styles.cancel}>Cancel</AlertDialog.Cancel>
          </AlertDialog.Content>
        </AlertDialog.Portal>
        <AlertDialog.Trigger className={styles.trigger}>delete everything</AlertDialog.Trigger>
      </AlertDialog.Root>

      <h2>Open</h2>
      <AlertDialog.Root open>
        <AlertDialog.Portal>
          <AlertDialog.Overlay
            className={styles.overlay}
            style={{ left: '75%', bottom: '50%', width: '25%' }}
          />
          <AlertDialog.Content
            className={styles.chromaticContent}
            style={{ top: '25%', left: '88%' }}
          >
            <AlertDialog.Title className={styles.title}>Title</AlertDialog.Title>
            <AlertDialog.Description className={styles.description}>
              Description
            </AlertDialog.Description>
            <AlertDialog.Action className={styles.action}>Confirm</AlertDialog.Action>
            <AlertDialog.Cancel className={styles.cancel}>Cancel</AlertDialog.Cancel>
          </AlertDialog.Content>
        </AlertDialog.Portal>
        <AlertDialog.Trigger className={styles.trigger}>delete everything</AlertDialog.Trigger>
      </AlertDialog.Root>
    </div>

    <div>
      <h1>State attributes</h1>
      <h2>Closed</h2>
      <AlertDialog.Root>
        <AlertDialog.Trigger className={styles.triggerAttr}>delete everything</AlertDialog.Trigger>
        <AlertDialog.Portal>
          <AlertDialog.Overlay className={styles.overlayAttr} />
          <AlertDialog.Content className={styles.contentAttr}>
            <AlertDialog.Title className={styles.titleAttr}>Title</AlertDialog.Title>
            <AlertDialog.Description className={styles.descriptionAttr}>
              Description
            </AlertDialog.Description>
            <AlertDialog.Action className={styles.actionAttr}>Confirm</AlertDialog.Action>
            <AlertDialog.Cancel className={styles.cancelAttr}>Cancel</AlertDialog.Cancel>
          </AlertDialog.Content>
        </AlertDialog.Portal>
      </AlertDialog.Root>

      <h2>Open</h2>
      <AlertDialog.Root defaultOpen>
        <AlertDialog.Trigger className={styles.triggerAttr}>delete everything</AlertDialog.Trigger>
        <AlertDialog.Portal>
          <AlertDialog.Overlay className={styles.overlayAttr} style={{ top: '50%' }} />
          <AlertDialog.Content className={styles.contentAttr} style={{ top: '75%' }}>
            <AlertDialog.Title className={styles.titleAttr}>Title</AlertDialog.Title>
            <AlertDialog.Description className={styles.descriptionAttr}>
              Description
            </AlertDialog.Description>
            <AlertDialog.Action className={styles.actionAttr}>Confirm</AlertDialog.Action>
            <AlertDialog.Cancel className={styles.cancelAttr}>Cancel</AlertDialog.Cancel>
          </AlertDialog.Content>
        </AlertDialog.Portal>
      </AlertDialog.Root>
    </div>
  </div>
);
Chromatic.parameters = { chromatic: { disable: false } };



================================================
FILE: apps/storybook/stories/arrow.stories.tsx
================================================
import { Arrow } from 'radix-ui/internal';

export default { title: 'Utilities/Arrow' };

const RECOMMENDED_CSS__ARROW__ROOT = {
  // better default alignment
  verticalAlign: 'middle',
};

export const Styled = () => (
  <Arrow.Root style={{ ...RECOMMENDED_CSS__ARROW__ROOT, fill: 'crimson' }} width={20} height={10} />
);

export const CustomSizes = () => (
  <>
    <Arrow.Root style={{ ...RECOMMENDED_CSS__ARROW__ROOT }} width={40} height={10} />
    <Arrow.Root style={{ ...RECOMMENDED_CSS__ARROW__ROOT }} width={50} height={30} />
    <Arrow.Root style={{ ...RECOMMENDED_CSS__ARROW__ROOT }} width={20} height={100} />
  </>
);

export const CustomArrow = () => (
  <Arrow.Root asChild>
    <div
      style={{
        width: 20,
        height: 10,
        borderBottomLeftRadius: 10,
        borderBottomRightRadius: 10,
        backgroundColor: 'tomato',
      }}
    />
  </Arrow.Root>
);



================================================
FILE: apps/storybook/stories/aspect-ratio.stories.module.css
================================================
.root {
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: var(--red-9);
  color: var(--gray-1);
}



================================================
FILE: apps/storybook/stories/aspect-ratio.stories.tsx
================================================
import { AspectRatio } from 'radix-ui';
import styles from './aspect-ratio.stories.module.css';

export default { title: 'Components/AspectRatio' };

const image = (
  <img
    src="https://images.unsplash.com/photo-1605030753481-bb38b08c384a?&auto=format&fit=crop&w=400&q=80"
    alt="A house in a forest"
    style={{ objectFit: 'cover', width: '100%', height: '100%' }}
  />
);

export const Styled = () => (
  <div style={{ width: 500 }}>
    <AspectRatio.Root className={styles.root}>
      <h1>Default ratio (1/1)</h1>
    </AspectRatio.Root>
  </div>
);

export const CustomRatios = () => {
  return (
    <div style={{ display: 'flex', gap: 20 }}>
      <div style={{ width: 200 }}>
        <AspectRatio.Root ratio={1 / 2}>{image}</AspectRatio.Root>
      </div>
      <div style={{ width: 200 }}>
        <AspectRatio.Root>{image}</AspectRatio.Root>
      </div>
      <div style={{ width: 200 }}>
        <AspectRatio.Root ratio={16 / 9}>{image}</AspectRatio.Root>
      </div>
      <div style={{ width: 200 }}>
        <AspectRatio.Root ratio={2 / 1}>{image}</AspectRatio.Root>
      </div>
    </div>
  );
};

export const Chromatic = () => (
  <>
    <h1>Default ratio</h1>
    <div style={{ width: 300 }}>
      <AspectRatio.Root className={styles.root}>
        <p>Default ratio (1/1)</p>
      </AspectRatio.Root>
    </div>

    <h1>Custom ratios</h1>
    <div style={{ display: 'flex', gap: 20 }}>
      <div style={{ width: 200 }}>
        <AspectRatio.Root ratio={1 / 2}>{image}</AspectRatio.Root>
      </div>
      <div style={{ width: 200 }}>
        <AspectRatio.Root>{image}</AspectRatio.Root>
      </div>
      <div style={{ width: 200 }}>
        <AspectRatio.Root ratio={16 / 9}>{image}</AspectRatio.Root>
      </div>
      <div style={{ width: 200 }}>
        <AspectRatio.Root ratio={2 / 1}>{image}</AspectRatio.Root>
      </div>
    </div>
  </>
);
Chromatic.parameters = { chromatic: { disable: false } };



================================================
FILE: apps/storybook/stories/avatar.stories.module.css
================================================
.root {
  /* ensures image/fallback is centered */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  vertical-align: middle;
  /* ensures image doesn't bleed out */
  overflow: hidden;
  /* ensures no selection is possible */
  user-select: none;
  /* -------- */
  border-radius: 9999px;
  width: 48px;
  height: 48px;
}

.image {
  /* ensures image is full size and not distorted */
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.fallback {
  /* ensures content inside the fallback is centered */
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  /* -------- */
  background-color: var(--gray-12);
  color: var(--gray-1);
}



================================================
FILE: apps/storybook/stories/avatar.stories.tsx
================================================
import { Avatar } from 'radix-ui';
import styles from './avatar.stories.module.css';
import React from 'react';

export default { title: 'Components/Avatar' };

const src = 'https://picsum.photos/id/1005/400/400';
const srcAlternative = 'https://picsum.photos/id/1006/400/400';
const srcBroken = 'https://broken.link.com/broken-pic.jpg';

export const Styled = () => (
  <>
    <h1>Without image & with fallback</h1>
    <Avatar.Root className={styles.root}>
      <Avatar.Fallback className={styles.fallback}>JS</Avatar.Fallback>
    </Avatar.Root>

    <h1>With image & with fallback</h1>
    <Avatar.Root className={styles.root}>
      <Avatar.Image className={styles.image} alt="John Smith" src={src} />
      <Avatar.Fallback delayMs={300} className={styles.fallback}>
        JS
      </Avatar.Fallback>
    </Avatar.Root>

    <h1>With image & with fallback (but broken src)</h1>
    <Avatar.Root className={styles.root}>
      <Avatar.Image
        className={styles.image}
        alt="John Smith"
        src={srcBroken}
        onLoadingStatusChange={console.log}
      />
      <Avatar.Fallback className={styles.fallback}>
        <AvatarIcon />
      </Avatar.Fallback>
    </Avatar.Root>

    <h1>Changing image src</h1>
    <SourceChanger sources={[src, srcAlternative, srcBroken]}>
      {(src) => (
        <Avatar.Root className={styles.root}>
          <Avatar.Image className={styles.image} alt="John Smith" src={src} />
          <Avatar.Fallback delayMs={300} className={styles.fallback}>
            JS
          </Avatar.Fallback>
        </Avatar.Root>
      )}
    </SourceChanger>
  </>
);

export const Chromatic = () => (
  <>
    <h1>Without image & with fallback</h1>
    <Avatar.Root className={styles.root}>
      <Avatar.Fallback className={styles.fallback}>JS</Avatar.Fallback>
    </Avatar.Root>

    <h1>With image & with fallback</h1>
    <Avatar.Root className={styles.root}>
      <Avatar.Image className={styles.image} alt="John Smith" src={src} />
      <Avatar.Fallback delayMs={300} className={styles.fallback}>
        JS
      </Avatar.Fallback>
    </Avatar.Root>

    <h1>With image & with fallback (but broken src)</h1>
    <Avatar.Root className={styles.root}>
      <Avatar.Image className={styles.image} alt="John Smith" src={srcBroken} />
      <Avatar.Fallback className={styles.fallback}>
        <AvatarIcon />
      </Avatar.Fallback>
    </Avatar.Root>

    <h1>Changing image src</h1>
    <SourceChanger sources={[src, srcAlternative, srcBroken]}>
      {(src) => (
        <Avatar.Root className={styles.root}>
          <Avatar.Image className={styles.image} alt="John Smith" src={src} />
          <Avatar.Fallback delayMs={300} className={styles.fallback}>
            JS
          </Avatar.Fallback>
        </Avatar.Root>
      )}
    </SourceChanger>
  </>
);
Chromatic.parameters = { chromatic: { disable: false, delay: 1000 } };

const AvatarIcon = () => (
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="42" height="42">
    <path
      d="M50 51.7a22.1 22.1 0 100-44.2 22.1 22.1 0 000 44.2zM87.9 69.3a27.8 27.8 0 00-21.2-16.1 4 4 0 00-2.8.7 23.5 23.5 0 01-27.6 0 4 4 0 00-2.8-.7 27.5 27.5 0 00-21.2 16.1c-.3.6-.2 1.3.1 1.8a52.8 52.8 0 007 8.9 43.4 43.4 0 0056.9 3.8 56.3 56.3 0 008.9-8.8c.9-1.2 1.8-2.5 2.6-3.9.3-.6.3-1.2.1-1.8z"
      fill="currentColor"
    />
  </svg>
);

function SourceChanger({
  sources,
  children,
}: {
  sources: [string, ...string[]];
  children: (src: string) => React.ReactElement;
}) {
  const [src, setSrc] = React.useState(sources[0]);
  React.useEffect(() => {
    const interval = setInterval(() => {
      const nextIndex = (sources.indexOf(src) + 1) % sources.length;
      setSrc(sources[nextIndex]!);
    }, 1000);
    return () => clearInterval(interval);
  }, [sources, src]);
  return children(src);
}



================================================
FILE: apps/storybook/stories/checkbox.stories.module.css
================================================
.root {
  /* better default alignment */
  vertical-align: middle;
  /* ------ */
  border: 1px solid var(--gray-4);
  width: 30px;
  height: 30px;
  padding: 4px;

  &:focus {
    outline: none;
    border-color: var(--red-9);
    box-shadow: 0 0 0 1px var(--red-9);
  }

  &[data-disabled] {
    opacity: 0.3;
  }
}

.indicator {
  background-color: var(--red-9);
  display: block;
  width: 20px;
  height: 4px;
  &[data-state='checked'],
  &[data-state='unchecked'] {
    height: 20px;
  }
}

@keyframes fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes fadeOut {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}

.animatedIndicator {
  transition: height 300ms;
  &[data-state='checked'] {
    animation: fadeIn 1000ms ease-out;
  }
  &[data-state='unchecked'] {
    animation: fadeOut 1000ms ease-in;
  }
}

.rootAttr,
.indicatorAttr {
  background-color: var(--blue-a12);
  border: 2px solid var(--blue-9);
  padding: 10px;
  &[data-state='unchecked'] {
    border-color: var(--red-9);
  }
  &[data-state='checked'] {
    border-color: var(--green-9);
  }
  &[data-state='indeterminate'] {
    border-color: var(--purple-9);
  }
  &[data-disabled] {
    border-style: dashed;
  }
  &:disabled {
    opacity: 0.5;
  }
}

.label {
  /* ensures it can receive vertical margins */
  display: inline-block;
  /* better default alignment */
  vertical-align: middle;
  /* mimics default `label` tag (as we render a `span`) */
  cursor: default;
  display: inline-block;
}



================================================
FILE: apps/storybook/stories/checkbox.stories.tsx
================================================
/* eslint-disable react/jsx-pascal-case */
import * as React from 'react';
import { Checkbox, Label as LabelPrimitive } from 'radix-ui';
import styles from './checkbox.stories.module.css';

export default { title: 'Components/Checkbox' };

export const Styled = () => (
  <>
    <p>This checkbox is nested inside a label. The state is uncontrolled.</p>

    <h1>Custom label</h1>
    <Label>
      Label{' '}
      <Checkbox.unstable_Provider>
        <Checkbox.unstable_Trigger className={styles.root}>
          <Checkbox.Indicator className={styles.indicator} />
        </Checkbox.unstable_Trigger>
      </Checkbox.unstable_Provider>
    </Label>

    <br />
    <br />

    <h1>Native label</h1>
    <label>
      Label{' '}
      <Checkbox.unstable_Provider>
        <Checkbox.unstable_Trigger className={styles.root}>
          <Checkbox.Indicator className={styles.indicator} />
        </Checkbox.unstable_Trigger>
      </Checkbox.unstable_Provider>
    </label>

    <h1>Native label + native checkbox</h1>
    <label>
      Label <input type="checkbox" />
    </label>

    <h1>Custom label + htmlFor</h1>
    <Label htmlFor="one">Label</Label>
    <Checkbox.unstable_Provider>
      <Checkbox.unstable_Trigger className={styles.root} id="one">
        <Checkbox.Indicator className={styles.indicator} />
      </Checkbox.unstable_Trigger>
    </Checkbox.unstable_Provider>

    <br />
    <br />

    <h1>Native label + htmlFor</h1>
    <label htmlFor="two">Label</label>
    <Checkbox.unstable_Provider>
      <Checkbox.unstable_Trigger className={styles.root} id="two">
        <Checkbox.Indicator className={styles.indicator} />
      </Checkbox.unstable_Trigger>
    </Checkbox.unstable_Provider>

    <h1>Native label + native checkbox</h1>
    <label htmlFor="three">Label</label>
    <input type="checkbox" id="three" />
  </>
);

export const Controlled = () => {
  const [checked, setChecked] = React.useState<boolean | 'indeterminate'>(true);

  return (
    <>
      <p>This checkbox is placed adjacent to its label. The state is controlled.</p>
      <Label htmlFor="randBox">Label</Label>{' '}
      <Checkbox.unstable_Provider checked={checked} onCheckedChange={setChecked}>
        <Checkbox.unstable_Trigger className={styles.root} id="randBox">
          <Checkbox.Indicator className={styles.indicator} />
        </Checkbox.unstable_Trigger>
      </Checkbox.unstable_Provider>
    </>
  );
};

export const Indeterminate = () => {
  const [checked, setChecked] = React.useState<boolean | 'indeterminate'>('indeterminate');

  return (
    <>
      <p>
        <Checkbox.unstable_Provider checked={checked} onCheckedChange={setChecked}>
          <Checkbox.unstable_Trigger className={styles.root}>
            <Checkbox.Indicator className={styles.indicator} />
          </Checkbox.unstable_Trigger>
        </Checkbox.unstable_Provider>
      </p>

      <button
        type="button"
        onClick={() =>
          setChecked((prevIsChecked) =>
            prevIsChecked === 'indeterminate' ? false : 'indeterminate',
          )
        }
      >
        Toggle indeterminate
      </button>
    </>
  );
};

export const WithinForm = () => {
  const [data, setData] = React.useState({ optional: false, required: false, stopprop: false });
  const [checked, setChecked] = React.useState<boolean | 'indeterminate'>('indeterminate');

  return (
    <form
      onSubmit={(event) => event.preventDefault()}
      onChange={(event) => {
        const input = event.target as HTMLInputElement;
        setData((prevData) => ({ ...prevData, [input.name]: input.checked }));
      }}
    >
      <fieldset>
        <legend>optional checked: {String(data.optional)}</legend>
        <label>
          <Checkbox.Root
            className={styles.root}
            name="optional"
            checked={checked}
            onCheckedChange={setChecked}
          >
            <Checkbox.Indicator className={styles.indicator} />
          </Checkbox.Root>{' '}
          with label
        </label>
        <br />
        <br />

        <button
          type="button"
          onClick={() => {
            setChecked((v) => (v === 'indeterminate' ? false : 'indeterminate'));
          }}
        >
          Toggle indeterminate
        </button>
      </fieldset>

      <br />
      <br />

      <fieldset>
        <legend>required checked: {String(data.required)}</legend>
        <Checkbox.unstable_Provider name="required" required>
          <Checkbox.unstable_Trigger className={styles.root}>
            <Checkbox.Indicator className={styles.indicator} />
          </Checkbox.unstable_Trigger>
          <Checkbox.unstable_BubbleInput />
        </Checkbox.unstable_Provider>
      </fieldset>

      <br />
      <br />

      <fieldset>
        <legend>stop propagation checked: {String(data.stopprop)}</legend>
        <Checkbox.unstable_Provider name="stopprop">
          <Checkbox.unstable_Trigger
            className={styles.root}
            onClick={(event) => event.stopPropagation()}
          >
            <Checkbox.Indicator className={styles.indicator} />
          </Checkbox.unstable_Trigger>
          <Checkbox.unstable_BubbleInput />
        </Checkbox.unstable_Provider>
      </fieldset>

      <br />
      <br />

      <fieldset>
        <legend>no bubble input checked: {String(data.stopprop)}</legend>
        <Checkbox.unstable_Provider name="stopprop">
          <Checkbox.unstable_Trigger className={styles.root}>
            <Checkbox.Indicator className={styles.indicator} />
          </Checkbox.unstable_Trigger>
        </Checkbox.unstable_Provider>
      </fieldset>

      <br />
      <br />

      <button type="reset">Reset</button>
      <button>Submit</button>
    </form>
  );
};

export const LegacyStyled = () => (
  <>
    <p>This checkbox is nested inside a label. The state is uncontrolled.</p>

    <h1>Custom label</h1>
    <Label>
      Label{' '}
      <Checkbox.Root className={styles.root}>
        <Checkbox.Indicator className={styles.indicator} />
      </Checkbox.Root>
    </Label>

    <br />
    <br />

    <h1>Native label</h1>
    <label>
      Label{' '}
      <Checkbox.Root className={styles.root}>
        <Checkbox.Indicator className={styles.indicator} />
      </Checkbox.Root>
    </label>

    <h1>Native label + native checkbox</h1>
    <label>
      Label <input type="checkbox" />
    </label>

    <h1>Custom label + htmlFor</h1>
    <Label htmlFor="one">Label</Label>
    <Checkbox.Root className={styles.root} id="one">
      <Checkbox.Indicator className={styles.indicator} />
    </Checkbox.Root>

    <br />
    <br />

    <h1>Native label + htmlFor</h1>
    <label htmlFor="two">Label</label>
    <Checkbox.Root className={styles.root} id="two">
      <Checkbox.Indicator className={styles.indicator} />
    </Checkbox.Root>

    <h1>Native label + native checkbox</h1>
    <label htmlFor="three">Label</label>
    <input type="checkbox" id="three" />
  </>
);

export const LegacyControlled = () => {
  const [checked, setChecked] = React.useState<boolean | 'indeterminate'>(true);

  return (
    <>
      <p>This checkbox is placed adjacent to its label. The state is controlled.</p>
      <Label htmlFor="randBox">Label</Label>{' '}
      <Checkbox.Root
        className={styles.root}
        checked={checked}
        onCheckedChange={setChecked}
        id="randBox"
      >
        <Checkbox.Indicator className={styles.indicator} />
      </Checkbox.Root>
    </>
  );
};

export const LegacyIndeterminate = () => {
  const [checked, setChecked] = React.useState<boolean | 'indeterminate'>('indeterminate');

  return (
    <>
      <p>
        <Checkbox.Root className={styles.root} checked={checked} onCheckedChange={setChecked}>
          <Checkbox.Indicator className={styles.indicator} />
        </Checkbox.Root>
      </p>

      <button
        type="button"
        onClick={() =>
          setChecked((prevIsChecked) =>
            prevIsChecked === 'indeterminate' ? false : 'indeterminate',
          )
        }
      >
        Toggle indeterminate
      </button>
    </>
  );
};

export const LegacyWithinForm = () => {
  const [data, setData] = React.useState({ optional: false, required: false, stopprop: false });
  const [checked, setChecked] = React.useState<boolean | 'indeterminate'>('indeterminate');

  return (
    <form
      onSubmit={(event) => event.preventDefault()}
      onChange={(event) => {
        const input = event.target as HTMLInputElement;
        setData((prevData) => ({ ...prevData, [input.name]: input.checked }));
      }}
    >
      <fieldset>
        <legend>optional checked: {String(data.optional)}</legend>
        <label>
          <Checkbox.Root
            className={styles.root}
            name="optional"
            checked={checked}
            onCheckedChange={setChecked}
          >
            <Checkbox.Indicator className={styles.indicator} />
          </Checkbox.Root>{' '}
          with label
        </label>
        <br />
        <br />

        <button
          type="button"
          onClick={() => {
            setChecked((prevChecked) => {
              return prevChecked === 'indeterminate' ? false : 'indeterminate';
            });
          }}
        >
          Toggle indeterminate
        </button>
      </fieldset>

      <br />
      <br />

      <fieldset>
        <legend>required checked: {String(data.required)}</legend>
        <Checkbox.Root className={styles.root} name="required" required>
          <Checkbox.Indicator className={styles.indicator} />
        </Checkbox.Root>
      </fieldset>

      <br />
      <br />

      <fieldset>
        <legend>stop propagation checked: {String(data.stopprop)}</legend>
        <Checkbox.Root
          className={styles.root}
          name="stopprop"
          onClick={(event) => event.stopPropagation()}
        >
          <Checkbox.Indicator className={styles.indicator} />
        </Checkbox.Root>
      </fieldset>

      <br />
      <br />

      <button type="reset">Reset</button>
      <button>Submit</button>
    </form>
  );
};

export const LegacyAnimated = () => {
  const [checked, setChecked] = React.useState<boolean | 'indeterminate'>('indeterminate');

  return (
    <>
      <p>
        <Checkbox.Root className={styles.root} checked={checked} onCheckedChange={setChecked}>
          <Checkbox.Indicator className={[styles.indicator, styles.animatedIndicator].join(' ')} />
        </Checkbox.Root>
      </p>

      <button
        type="button"
        onClick={() =>
          setChecked((prevIsChecked) =>
            prevIsChecked === 'indeterminate' ? false : 'indeterminate',
          )
        }
      >
        Toggle indeterminate
      </button>
    </>
  );
};

export const LegacyChromatic = () => (
  <>
    <h1>Uncontrolled</h1>
    <h2>Unchecked</h2>
    <Checkbox.Root className={styles.root}>
      <Checkbox.Indicator className={styles.indicator} />
    </Checkbox.Root>

    <h2>Checked</h2>
    <Checkbox.Root className={styles.root} defaultChecked>
      <Checkbox.Indicator className={styles.indicator} />
    </Checkbox.Root>

    <h1>Controlled</h1>
    <h2>Unchecked</h2>
    <Checkbox.Root className={styles.root} checked={false}>
      <Checkbox.Indicator className={styles.indicator} />
    </Checkbox.Root>

    <h2>Checked</h2>
    <Checkbox.Root className={styles.root} checked>
      <Checkbox.Indicator className={styles.indicator} />
    </Checkbox.Root>

    <h1>Indeterminate</h1>
    <Checkbox.Root className={styles.root} checked="indeterminate">
      <Checkbox.Indicator className={styles.indicator} />
    </Checkbox.Root>

    <h1>Disabled</h1>
    <Checkbox.Root className={styles.root} defaultChecked disabled>
      <Checkbox.Indicator className={styles.indicator} />
    </Checkbox.Root>

    <h1>Force mounted indicator</h1>
    <Checkbox.Root className={styles.root}>
      <Checkbox.Indicator className={styles.indicator} forceMount style={{ height: 20 }} />
    </Checkbox.Root>

    <h1>State attributes</h1>
    <h2>Unchecked</h2>
    <Checkbox.Root className={styles.rootAttr}>
      <Checkbox.Indicator className={styles.indicatorAttr} />
    </Checkbox.Root>

    <h2>Checked</h2>
    <Checkbox.Root className={styles.rootAttr} defaultChecked>
      <Checkbox.Indicator className={styles.indicatorAttr} />
    </Checkbox.Root>

    <h2>Indeterminate</h2>
    <Checkbox.Root className={styles.rootAttr} checked="indeterminate">
      <Checkbox.Indicator className={styles.indicatorAttr} />
    </Checkbox.Root>

    <h2>Disabled</h2>
    <Checkbox.Root className={styles.rootAttr} defaultChecked disabled>
      <Checkbox.Indicator className={styles.indicatorAttr} />
    </Checkbox.Root>

    <h2>Force mounted indicator</h2>
    <Checkbox.Root className={styles.rootAttr}>
      <Checkbox.Indicator className={styles.indicatorAttr} forceMount style={{ height: 20 }} />
    </Checkbox.Root>
  </>
);
LegacyChromatic.parameters = { chromatic: { disable: false } };

const Label = (props: any) => <LabelPrimitive.Root {...props} className={styles.label} />;



================================================
FILE: apps/storybook/stories/collapsible.stories.module.css
================================================
.root {
  max-width: 20em;
  font-family: sans-serif;
}

.trigger {
  /* because it's a button, we want to stretch it */
  width: 100%;
  /* and remove center text alignment in favour of inheriting */
  text-align: inherit;
  /* ---- */
  appearance: none;
  border: none;
  padding: 10px;
  background-color: var(--color-black);
  color: white;
  font-family: inherit;
  font-size: 1.2em;
  --shadow-color: crimson;

  &:focus {
    outline: none;
    box-shadow: inset 0 -5px 0 0 var(--shadow-color);
    color: var(--color-red);
  }

  &[data-disabled] {
    color: var(--color-gray300);
  }

  &[data-state='open'] {
    background-color: var(--color-red);
    color: var(--color-white);

    &:focus {
      --shadow-color: #111;
      color: var(--color-black);
    }
  }
}

.content {
  padding: 10px;
  line-height: 1.5;
}

@keyframes collapsible-slideDown {
  from {
    height: 0;
  }
  to {
    height: var(--radix-collapsible-content-height);
  }
}

@keyframes collapsible-slideUp {
  from {
    height: var(--radix-collapsible-content-height);
  }
  to {
    height: 0;
  }
}

@keyframes collapsible-openRight {
  from {
    width: 0;
  }
  to {
    width: var(--radix-collapsible-content-width);
  }
}

@keyframes collapsible-closeRight {
  from {
    width: var(--radix-collapsible-content-width);
  }
  to {
    width: 0;
  }
}

.animatedContent {
  overflow: hidden;
  &[data-state='open'] {
    animation: collapsible-slideDown 300ms ease-out;
  }
  &[data-state='closed'] {
    animation: collapsible-slideUp 300ms ease-in;
  }
}

.animatedWidthContent {
  overflow: hidden;
  &[data-state='open'] {
    animation: collapsible-openRight 300ms ease-out;
  }
  &[data-state='closed'] {
    animation: collapsible-closeRight 300ms ease-in;
  }
}

.rootAttr,
.triggerAttr,
.contentAttr {
  /* ensure we can see the content (because it has `hidden` attribute) */
  display: block;
  background-color: rgb(0 0 255 / 0.3);
  border: 2px solid blue;
  padding: 10px;

  &[data-state='closed'] {
    border-color: red;
  }
  &[data-state='open'] {
    border-color: green;
  }
  &[data-disabled] {
    border-style: dashed;
  }
  &:disabled {
    opacity: 0.5;
  }
}



================================================
FILE: apps/storybook/stories/collapsible.stories.tsx
================================================
import * as React from 'react';
import { Collapsible } from 'radix-ui';
import styles from './collapsible.stories.module.css';

export default { title: 'Components/Collapsible' };

export const Styled = () => (
  <Collapsible.Root className={styles.root}>
    <Collapsible.Trigger className={styles.trigger}>Trigger</Collapsible.Trigger>
    <Collapsible.Content className={styles.content}>Content 1</Collapsible.Content>
  </Collapsible.Root>
);

export const Controlled = () => {
  const [open, setOpen] = React.useState(false);
  return (
    <Collapsible.Root open={open} onOpenChange={setOpen} className={styles.root}>
      <Collapsible.Trigger className={styles.trigger}>
        {open ? 'close' : 'open'}
      </Collapsible.Trigger>
      <Collapsible.Content className={styles.content} asChild>
        <article>Content 1</article>
      </Collapsible.Content>
    </Collapsible.Root>
  );
};

export const Animated = () => {
  return (
    <>
      <h1>Closed by default</h1>
      <Collapsible.Root className={styles.root}>
        <Collapsible.Trigger className={styles.trigger}>Trigger</Collapsible.Trigger>
        <Collapsible.Content className={styles.animatedContent}>
          <div style={{ padding: 10 }}>Content 1</div>
        </Collapsible.Content>
      </Collapsible.Root>

      <h1>Open by default</h1>
      <Collapsible.Root defaultOpen className={styles.root}>
        <Collapsible.Trigger className={styles.trigger}>Trigger</Collapsible.Trigger>
        <Collapsible.Content className={styles.animatedContent}>
          <div style={{ padding: 10 }}>Content 1</div>
        </Collapsible.Content>
      </Collapsible.Root>
    </>
  );
};

export const AnimatedHorizontal = () => {
  return (
    <Collapsible.Root className={styles.root}>
      <Collapsible.Trigger className={styles.trigger}>Trigger</Collapsible.Trigger>
      <Collapsible.Content className={styles.animatedWidthContent}>
        <div style={{ padding: 10 }}>Content</div>
      </Collapsible.Content>
    </Collapsible.Root>
  );
};

export const Chromatic = () => (
  <>
    <h1>Uncontrolled</h1>
    <h2>Closed</h2>
    <Collapsible.Root className={styles.root}>
      <Collapsible.Trigger className={styles.trigger}>Trigger</Collapsible.Trigger>
      <Collapsible.Content className={styles.content}>Content 1</Collapsible.Content>
    </Collapsible.Root>

    <h2>Open</h2>
    <Collapsible.Root className={styles.root} defaultOpen>
      <Collapsible.Trigger className={styles.trigger}>Trigger</Collapsible.Trigger>
      <Collapsible.Content className={styles.content}>Content 1</Collapsible.Content>
    </Collapsible.Root>

    <h1>Controlled</h1>
    <h2>Closed</h2>
    <Collapsible.Root className={styles.root} open={false}>
      <Collapsible.Trigger className={styles.trigger}>Trigger</Collapsible.Trigger>
      <Collapsible.Content className={styles.content}>Content 1</Collapsible.Content>
    </Collapsible.Root>

    <h2>Open</h2>
    <Collapsible.Root className={styles.root} open>
      <Collapsible.Trigger className={styles.trigger}>Trigger</Collapsible.Trigger>
      <Collapsible.Content className={styles.content}>Content 1</Collapsible.Content>
    </Collapsible.Root>

    <h1>Disabled</h1>
    <Collapsible.Root className={styles.root} disabled>
      <Collapsible.Trigger className={styles.trigger}>Trigger</Collapsible.Trigger>
      <Collapsible.Content className={styles.content}>Content 1</Collapsible.Content>
    </Collapsible.Root>

    <h1>State attributes</h1>
    <h2>Closed</h2>
    <Collapsible.Root className={styles.rootAttr}>
      <Collapsible.Trigger className={styles.triggerAttr}>Trigger</Collapsible.Trigger>
      <Collapsible.Content className={styles.contentAttr}>Content 1</Collapsible.Content>
    </Collapsible.Root>

    <h2>Open</h2>
    <Collapsible.Root className={styles.rootAttr} defaultOpen>
      <Collapsible.Trigger className={styles.triggerAttr}>Trigger</Collapsible.Trigger>
      <Collapsible.Content className={styles.contentAttr}>Content 1</Collapsible.Content>
    </Collapsible.Root>

    <h2>Disabled</h2>
    <Collapsible.Root className={styles.rootAttr} defaultOpen disabled>
      <Collapsible.Trigger className={styles.triggerAttr}>Trigger</Collapsible.Trigger>
      <Collapsible.Content className={styles.contentAttr}>Content 1</Collapsible.Content>
    </Collapsible.Root>
  </>
);
Chromatic.parameters = { chromatic: { disable: false } };



================================================
FILE: apps/storybook/stories/collection.stories.tsx
================================================
import * as React from 'react';
import { Collection as CollectionPrimitive } from 'radix-ui/internal';

const { createCollection } = CollectionPrimitive;

export default { title: 'Utilities/Collection' };

export const Basic = () => (
  <List>
    <Item>Red</Item>
    <Item disabled>Green</Item>
    <Item>Blue</Item>
    <LogItems />
  </List>
);

export const WithElementInBetween = () => (
  <List>
    <div style={{ fontVariant: 'small-caps' }}>Colors</div>
    <Item>Red</Item>
    <Item disabled>Green</Item>
    <Item>Blue</Item>
    <div style={{ fontVariant: 'small-caps' }}>Words</div>
    <Item>Hello</Item>
    <Item>World</Item>
    <LogItems />
  </List>
);

const Tomato = () => <Item style={{ color: 'tomato' }}>Tomato</Item>;

export const WithWrappedItem = () => (
  <List>
    <Item>Red</Item>
    <Item disabled>Green</Item>
    <Item>Blue</Item>
    <Tomato />
    <LogItems />
  </List>
);

export const WithFragment = () => {
  const countries = (
    <>
      <Item>France</Item>
      <Item disabled>UK</Item>
      <Item>Spain</Item>
    </>
  );
  return (
    <List>
      {countries}
      <LogItems />
    </List>
  );
};

export const DynamicInsertion = () => {
  const [hasTomato, setHasTomato] = React.useState(false);
  const [, forceUpdate] = React.useState<any>();
  return (
    <>
      <button onClick={() => setHasTomato(!hasTomato)}>
        {hasTomato ? 'Remove' : 'Add'} Tomato
      </button>
      <button onClick={() => forceUpdate({})} style={{ marginLeft: 10 }}>
        Force Update
      </button>

      <List>
        <MemoItems hasTomato={hasTomato} />
        <LogItems />
      </List>
    </>
  );
};

function WrappedItems({ hasTomato }: any) {
  return (
    <>
      <MemoItem>Red</MemoItem>
      {hasTomato ? <Tomato /> : null}
      <MemoItem disabled>Green</MemoItem>
      <MemoItem>Blue</MemoItem>
    </>
  );
}

export const WithChangingItem = () => {
  const [isDisabled, setIsDisabled] = React.useState(false);
  return (
    <>
      <button onClick={() => setIsDisabled(!isDisabled)}>
        {isDisabled ? 'Enable' : 'Disable'} Green
      </button>

      <List>
        <Item>Red</Item>
        <Item disabled={isDisabled}>Green</Item>
        <Item>Blue</Item>
        <LogItems />
      </List>
    </>
  );
};

export const Nested = () => (
  <List>
    <Item>1</Item>
    <Item>
      2
      <List>
        <Item>2.1</Item>
        <Item>2.2</Item>
        <Item>2.3</Item>
        <LogItems name="items inside 2" />
      </List>
    </Item>
    <Item>3</Item>
    <LogItems name="top-level items" />
  </List>
);

/* -------------------------------------------------------------------------------------------------
 * List implementation
 * -----------------------------------------------------------------------------------------------*/

type ItemData = { disabled: boolean };

const [Collection, useCollection] = createCollection<React.ComponentRef<typeof Item>, ItemData>(
  'List',
);

const List: React.FC<{ children: React.ReactNode }> = (props) => {
  return (
    <Collection.Provider scope={undefined}>
      <Collection.Slot scope={undefined}>
        <ul {...props} style={{ width: 200 }} />
      </Collection.Slot>
    </Collection.Provider>
  );
};

type ItemProps = React.ComponentPropsWithRef<'li'> & {
  children: React.ReactNode;
  disabled?: boolean;
};

function Item({ disabled = false, ...props }: ItemProps) {
  return (
    <Collection.ItemSlot scope={undefined} disabled={disabled}>
      <li {...props} style={{ ...props.style, opacity: disabled ? 0.3 : undefined }} />
    </Collection.ItemSlot>
  );
}

// Ensure that our implementation doesn't break if the item list/item is memoized
const MemoItem = React.memo(Item);
const MemoItems = React.memo(WrappedItems);

function LogItems({ name = 'items' }: { name?: string }) {
  const getItems = useCollection(undefined);
  React.useEffect(() => console.log(name, getItems()));
  return null;
}



================================================
FILE: apps/storybook/stories/context-menu.stories.module.css
================================================
.trigger {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 200px;
  height: 100px;
  border: 2px dashed var(--color-black);
  border-radius: 6px;
  background-color: rgba(0, 0, 0, 0.1);

  &:focus {
    outline: none;
    box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.5);
  }

  &[data-state='open'] {
    background-color: lightblue;
  }
}

.content {
  display: inline-block;
  box-sizing: border-box;
  min-width: 130px;
  background-color: var(--color-white);
  border: 1px solid var(--color-gray100);
  border-radius: 6px;
  padding: 5px;
  box-shadow: 0 5px 10px 0 rgba(0, 0, 0, 0.1);
  font-family: apple-system, BlinkMacSystemFont, helvetica, arial, sans-serif;
  font-size: 13px;
  &:focus-within {
    border-color: var(--color-black);
  }
}

.animatedContent {
  transform-origin: var(--radix-context-menu-content-transform-origin);
  &[data-state='open'] {
    animation: contextMenu-scaleIn 0.6s cubic-bezier(0.16, 1, 0.3, 1);
  }
}

.label,
.item,
.subTrigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  line-height: 1;
  cursor: default;
  user-select: none;
  white-space: nowrap;
  height: 25px;
  padding: 0 10px;
  color: var(--color-black);
  border-radius: 3px;
}

.label {
  color: var(--color-gray100);
}

.item,
.subTrigger {
  outline: none;

  &[data-highlighted] {
    background-color: var(--color-black);
    color: var(--color-white);
  }

  &[data-disabled] {
    color: var(--color-gray100);
  }
}

.subTrigger {
  &:not([data-highlighted])[data-state='open'] {
    background-color: var(--color-gray100);
    color: var(--color-black);
  }
}

.separator {
  height: 1;
  margin: 5px 10px;
  background-color: var(--color-gray100);
}

@keyframes contextMenu-scaleIn {
  0% {
    transform: scale(0) rotateZ(-10deg);
  }
  20% {
    transform: scale(1.1);
  }
  100% {
    transform: scale(1);
  }
}



================================================
FILE: apps/storybook/stories/context-menu.stories.tsx
================================================
import * as React from 'react';
import { ContextMenu } from 'radix-ui';
import { foodGroups } from '@repo/test-data/foods';
import styles from './context-menu.stories.module.css';

export default { title: 'Components/ContextMenu' };

export const Styled = () => (
  <div
    style={{
      display: 'flex',
      alignItems: 'center',
      justifyContent: 'center',
      width: '200vw',
      height: '200vh',
      gap: 20,
    }}
  >
    <ContextMenu.Root>
      <ContextMenu.Trigger className={styles.trigger}>Right click here</ContextMenu.Trigger>
      <ContextMenu.Portal>
        <ContextMenu.Content className={styles.content} alignOffset={-5}>
          <ContextMenu.Item className={styles.item} onSelect={() => console.log('undo')}>
            Undo
          </ContextMenu.Item>
          <ContextMenu.Item className={styles.item} onSelect={() => console.log('redo')}>
            Redo
          </ContextMenu.Item>
          <ContextMenu.Separator className={styles.separator} />
          <ContextMenu.Item className={styles.item} disabled onSelect={() => console.log('cut')}>
            Cut
          </ContextMenu.Item>
          <ContextMenu.Item className={styles.item} onSelect={() => console.log('copy')}>
            Copy
          </ContextMenu.Item>
          <ContextMenu.Item className={styles.item} onSelect={() => console.log('paste')}>
            Paste
          </ContextMenu.Item>
        </ContextMenu.Content>
      </ContextMenu.Portal>
    </ContextMenu.Root>
  </div>
);

export const Modality = () => (
  <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', height: '110vh' }}>
    <div style={{ display: 'grid', gap: 50 }}>
      <div style={{ display: 'inline-flex', alignItems: 'center', flexDirection: 'column' }}>
        <h1>Modal (default)</h1>
        <ContextMenu.Root>
          <ContextMenu.Trigger className={styles.trigger} />
          <ContextMenu.Portal>
            <ContextMenu.Content className={styles.content} alignOffset={-5}>
              <ContextMenu.Item className={styles.item} onSelect={() => console.log('undo')}>
                Undo
              </ContextMenu.Item>
              <ContextMenu.Item className={styles.item} onSelect={() => console.log('redo')}>
                Redo
              </ContextMenu.Item>
              <ContextMenu.Separator className={styles.separator} />
              <ContextMenu.Sub>
                <ContextMenu.SubTrigger className={styles.subTrigger}>
                  Submenu →
                </ContextMenu.SubTrigger>
                <ContextMenu.Portal>
                  <ContextMenu.SubContent
                    className={styles.content}
                    sideOffset={12}
                    alignOffset={-6}
                  >
                    <ContextMenu.Item className={styles.item} onSelect={() => console.log('one')}>
                      One
                    </ContextMenu.Item>
                    <ContextMenu.Item className={styles.item} onSelect={() => console.log('two')}>
                      Two
                    </ContextMenu.Item>
                    <ContextMenu.Separator className={styles.separator} />
                    <ContextMenu.Sub>
                      <ContextMenu.SubTrigger className={styles.subTrigger}>
                        Submenu →
                      </ContextMenu.SubTrigger>
                      <ContextMenu.Portal>
                        <ContextMenu.SubContent
                          className={styles.content}
                          sideOffset={12}
                          alignOffset={-6}
                        >
                          <ContextMenu.Item
                            className={styles.item}
                            onSelect={() => console.log('one')}
                          >
                            One
                          </ContextMenu.Item>
                          <ContextMenu.Item
                            className={styles.item}
                            onSelect={() => console.log('two')}
                          >
                            Two
                          </ContextMenu.Item>
                          <ContextMenu.Item
                            className={styles.item}
                            onSelect={() => console.log('three')}
                          >
                            Three
                          </ContextMenu.Item>
                          <ContextMenu.Arrow />
                        </ContextMenu.SubContent>
                      </ContextMenu.Portal>
                    </ContextMenu.Sub>
                    <ContextMenu.Separator className={styles.separator} />
                    <ContextMenu.Item className={styles.item} onSelect={() => console.log('three')}>
                      Three
                    </ContextMenu.Item>
                    <ContextMenu.Arrow />
                  </ContextMenu.SubContent>
                </ContextMenu.Portal>
              </ContextMenu.Sub>
              <ContextMenu.Separator className={styles.separator} />
              <ContextMenu.Item
                className={styles.item}
                disabled
                onSelect={() => console.log('cut')}
              >
                Cut
              </ContextMenu.Item>
              <ContextMenu.Item className={styles.item} onSelect={() => console.log('copy')}>
                Copy
              </ContextMenu.Item>
              <ContextMenu.Item className={styles.item} onSelect={() => console.log('paste')}>
                Paste
              </ContextMenu.Item>
            </ContextMenu.Content>
          </ContextMenu.Portal>
        </ContextMenu.Root>
        <textarea
          style={{ width: 500, height: 100, marginTop: 10 }}
          defaultValue="Lorem ipsum dolor sit amet consectetur adipisicing elit. Quaerat nobis at ipsa, nihil tempora debitis maxime dignissimos non amet."
        />
      </div>
      <div style={{ display: 'inline-flex', alignItems: 'center', flexDirection: 'column' }}>
        <h1>Non modal</h1>
        <ContextMenu.Root modal={false}>
          <ContextMenu.Trigger className={styles.trigger} />
          <ContextMenu.Portal>
            <ContextMenu.Content className={styles.content} alignOffset={-5}>
              <ContextMenu.Item className={styles.item} onSelect={() => console.log('undo')}>
                Undo
              </ContextMenu.Item>
              <ContextMenu.Item className={styles.item} onSelect={() => console.log('redo')}>
                Redo
              </ContextMenu.Item>
              <ContextMenu.Separator className={styles.separator} />
              <ContextMenu.Sub>
                <ContextMenu.SubTrigger className={styles.subTrigger}>
                  Submenu →
                </ContextMenu.SubTrigger>
                <ContextMenu.Portal>
                  <ContextMenu.SubContent
                    className={styles.content}
                    sideOffset={12}
                    alignOffset={-6}
                  >
                    <ContextMenu.Item className={styles.item} onSelect={() => console.log('one')}>
                      One
                    </ContextMenu.Item>
                    <ContextMenu.Item className={styles.item} onSelect={() => console.log('two')}>
                      Two
                    </ContextMenu.Item>
                    <ContextMenu.Separator className={styles.separator} />
                    <ContextMenu.Sub>
                      <ContextMenu.SubTrigger className={styles.subTrigger}>
                        Submenu →
                      </ContextMenu.SubTrigger>
                      <ContextMenu.Portal>
                        <ContextMenu.SubContent
                          className={styles.content}
                          sideOffset={12}
                          alignOffset={-6}
                        >
                          <ContextMenu.Item
                            className={styles.item}
                            onSelect={() => console.log('one')}
                          >
                            One
                          </ContextMenu.Item>
                          <ContextMenu.Item
                            className={styles.item}
                            onSelect={() => console.log('two')}
                          >
                            Two
                          </ContextMenu.Item>
                          <ContextMenu.Item
                            className={styles.item}
                            onSelect={() => console.log('three')}
                          >
                            Three
                          </ContextMenu.Item>
                          <ContextMenu.Arrow />
                        </ContextMenu.SubContent>
                      </ContextMenu.Portal>
                    </ContextMenu.Sub>
                    <ContextMenu.Separator className={styles.separator} />
                    <ContextMenu.Item className={styles.item} onSelect={() => console.log('three')}>
                      Three
                    </ContextMenu.Item>
                    <ContextMenu.Arrow />
                  </ContextMenu.SubContent>
                </ContextMenu.Portal>
              </ContextMenu.Sub>
              <ContextMenu.Separator className={styles.separator} />
              <ContextMenu.Item
                className={styles.item}
                disabled
                onSelect={() => console.log('cut')}
              >
                Cut
              </ContextMenu.Item>
              <ContextMenu.Item className={styles.item} onSelect={() => console.log('copy')}>
                Copy
              </ContextMenu.Item>
              <ContextMenu.Item className={styles.item} onSelect={() => console.log('paste')}>
                Paste
              </ContextMenu.Item>
            </ContextMenu.Content>
          </ContextMenu.Portal>
        </ContextMenu.Root>
        <textarea
          style={{ width: 500, height: 100, marginTop: 10 }}
          defaultValue="Lorem ipsum dolor sit amet consectetur adipisicing elit. Quaerat nobis at ipsa, nihil tempora debitis maxime dignissimos non amet."
        />
      </div>
    </div>
  </div>
);

export const Submenus = () => {
  const [rtl, setRtl] = React.useState(false);

  return (
    <div
      style={{
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        height: '100vh',
        gap: 20,
      }}
    >
      <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
        <label style={{ marginBottom: 10 }}>
          <input
            type="checkbox"
            checked={rtl}
            onChange={(event) => setRtl(event.currentTarget.checked)}
          />
          Right-to-left
        </label>
        <ContextMenu.Root dir={rtl ? 'rtl' : 'ltr'}>
          <ContextMenu.Trigger className={styles.trigger}>Right Click Here</ContextMenu.Trigger>
          <ContextMenu.Portal>
            <ContextMenu.Content className={styles.content}>
              <ContextMenu.Item className={styles.item} onSelect={() => console.log('new-tab')}>
                New Tab
              </ContextMenu.Item>
              <ContextMenu.Item className={styles.item} onSelect={() => console.log('new-window')}>
                New Window
              </ContextMenu.Item>
              <ContextMenu.Separator className={styles.separator} />
              <ContextMenu.Sub>
                <ContextMenu.SubTrigger className={styles.subTrigger}>
                  Bookmarks →
                </ContextMenu.SubTrigger>
                <ContextMenu.Portal>
                  <ContextMenu.SubContent
                    className={styles.content}
                    sideOffset={12}
                    alignOffset={-6}
                  >
                    <ContextMenu.Item className={styles.item} onSelect={() => console.log('index')}>
                      Inbox
                    </ContextMenu.Item>
                    <ContextMenu.Item
                      className={styles.item}
                      onSelect={() => console.log('calendar')}
                    >
                      Calendar
                    </ContextMenu.Item>
                    <ContextMenu.Separator className={styles.separator} />
                    <ContextMenu.Sub>
                      <ContextMenu.SubTrigger className={styles.subTrigger}>
                        WorkOS →
                      </ContextMenu.SubTrigger>
                      <ContextMenu.Portal>
                        <ContextMenu.SubContent
                          className={styles.content}
                          sideOffset={12}
                          alignOffset={-6}
                        >
                          <ContextMenu.Item
                            className={styles.item}
                            onSelect={() => console.log('stitches')}
                          >
                            Stitches
                          </ContextMenu.Item>
                          <ContextMenu.Item
                            className={styles.item}
                            onSelect={() => console.log('composer')}
                          >
                            Composer
                          </ContextMenu.Item>
                          <ContextMenu.Item
                            className={styles.item}
                            onSelect={() => console.log('radix')}
                          >
                            Radix
                          </ContextMenu.Item>
                          <ContextMenu.Arrow />
                        </ContextMenu.SubContent>
                      </ContextMenu.Portal>
                    </ContextMenu.Sub>
                    <ContextMenu.Separator className={styles.separator} />
                    <ContextMenu.Item
                      className={styles.item}
                      onSelect={() => console.log('notion')}
                    >
                      Notion
                    </ContextMenu.Item>
                    <ContextMenu.Arrow />
                  </ContextMenu.SubContent>
                </ContextMenu.Portal>
              </ContextMenu.Sub>
              <ContextMenu.Sub>
                <ContextMenu.SubTrigger className={styles.subTrigger} disabled>
                  History →
                </ContextMenu.SubTrigger>
                <ContextMenu.Portal>
                  <ContextMenu.SubContent
                    className={styles.content}
                    sideOffset={12}
                    alignOffset={-6}
                  >
                    <ContextMenu.Item
                      className={styles.item}
                      onSelect={() => console.log('github')}
                    >
                      Github
                    </ContextMenu.Item>
                    <ContextMenu.Item
                      className={styles.item}
                      onSelect={() => console.log('google')}
                    >
                      Google
                    </ContextMenu.Item>
                    <ContextMenu.Item
                      className={styles.item}
                      onSelect={() => console.log('stack-overflow')}
                    >
                      Stack Overflow
                    </ContextMenu.Item>
                    <ContextMenu.Arrow />
                  </ContextMenu.SubContent>
                </ContextMenu.Portal>
              </ContextMenu.Sub>
              <ContextMenu.Sub>
                <ContextMenu.SubTrigger className={styles.subTrigger}>
                  Tools →
                </ContextMenu.SubTrigger>
                <ContextMenu.Portal>
                  <ContextMenu.SubContent
                    className={styles.content}
                    sideOffset={12}
                    alignOffset={-6}
                  >
                    <ContextMenu.Item
                      className={styles.item}
                      onSelect={() => console.log('extensions')}
                    >
                      Extensions
                    </ContextMenu.Item>
                    <ContextMenu.Item
                      className={styles.item}
                      onSelect={() => console.log('task-manager')}
                    >
                      Task Manager
                    </ContextMenu.Item>
                    <ContextMenu.Item
                      className={styles.item}
                      onSelect={() => console.log('developer-tools')}
                    >
                      Developer Tools
                    </ContextMenu.Item>
                    <ContextMenu.Arrow />
                  </ContextMenu.SubContent>
                </ContextMenu.Portal>
              </ContextMenu.Sub>
              <ContextMenu.Separator className={styles.separator} />
              <ContextMenu.Item
                className={styles.item}
                disabled
                onSelect={() => console.log('print')}
              >
                Print…
              </ContextMenu.Item>
              <ContextMenu.Item className={styles.item} onSelect={() => console.log('cast')}>
                Cast…
              </ContextMenu.Item>
              <ContextMenu.Item className={styles.item} onSelect={() => console.log('find')}>
                Find…
              </ContextMenu.Item>
            </ContextMenu.Content>
          </ContextMenu.Portal>
        </ContextMenu.Root>
      </div>
    </div>
  );
};

export const WithLabels = () => (
  <div style={{ textAlign: 'center', padding: 50 }}>
    <ContextMenu.Root>
      <ContextMenu.Trigger className={styles.trigger}>Right click here</ContextMenu.Trigger>
      <ContextMenu.Portal>
        <ContextMenu.Content className={styles.content} alignOffset={-5}>
          {foodGroups.map((foodGroup, index) => (
            <ContextMenu.Group key={index}>
              {foodGroup.label && (
                <ContextMenu.Label className={styles.label} key={foodGroup.label}>
                  {foodGroup.label}
                </ContextMenu.Label>
              )}
              {foodGroup.foods.map((food) => (
                <ContextMenu.Item
                  key={food.value}
                  className={styles.item}
                  disabled={food.disabled}
                  onSelect={() => console.log(food.label)}
                >
                  {food.label}
                </ContextMenu.Item>
              ))}
              {index < foodGroups.length - 1 && (
                <ContextMenu.Separator className={styles.separator} />
              )}
            </ContextMenu.Group>
          ))}
        </ContextMenu.Content>
      </ContextMenu.Portal>
    </ContextMenu.Root>
  </div>
);

export const CheckboxItems = () => {
  const checkboxItems = ['Bold', 'Italic', 'Underline'];
  const [selection, setSelection] = React.useState<string[]>([]);

  return (
    <div style={{ textAlign: 'center', padding: 50 }}>
      <ContextMenu.Root>
        <ContextMenu.Trigger className={styles.trigger}>Right click here</ContextMenu.Trigger>
        <ContextMenu.Portal>
          <ContextMenu.Content className={styles.content} alignOffset={-5}>
            <ContextMenu.Item className={styles.item} onSelect={() => console.log('show')}>
              Show fonts
            </ContextMenu.Item>
            <ContextMenu.Item className={styles.item} onSelect={() => console.log('bigger')}>
              Bigger
            </ContextMenu.Item>
            <ContextMenu.Item className={styles.item} onSelect={() => console.log('smaller')}>
              Smaller
            </ContextMenu.Item>
            <ContextMenu.Separator className={styles.separator} />
            {checkboxItems.map((item) => (
              <ContextMenu.CheckboxItem
                key={item}
                className={styles.item}
                checked={selection.includes(item)}
                onCheckedChange={() =>
                  setSelection((current) =>
                    current.includes(item)
                      ? current.filter((el) => el !== item)
                      : current.concat(item),
                  )
                }
              >
                {item}
                <ContextMenu.ItemIndicator>
                  <TickIcon />
                </ContextMenu.ItemIndicator>
              </ContextMenu.CheckboxItem>
            ))}
            <ContextMenu.Separator />
            <ContextMenu.CheckboxItem className={styles.item} disabled>
              Strikethrough
              <ContextMenu.ItemIndicator>
                <TickIcon />
              </ContextMenu.ItemIndicator>
            </ContextMenu.CheckboxItem>
          </ContextMenu.Content>
        </ContextMenu.Portal>
      </ContextMenu.Root>
    </div>
  );
};

export const RadioItems = () => {
  const files = ['README.md', 'index.js', 'page.css'];
  const [file, setFile] = React.useState(files[1]);

  return (
    <div style={{ textAlign: 'center', padding: 50 }}>
      <ContextMenu.Root>
        <ContextMenu.Trigger className={styles.trigger}>Right click here</ContextMenu.Trigger>
        <ContextMenu.Portal>
          <ContextMenu.Content className={styles.content} alignOffset={-5}>
            <ContextMenu.Item className={styles.item} onSelect={() => console.log('minimize')}>
              Minimize window
            </ContextMenu.Item>
            <ContextMenu.Item className={styles.item} onSelect={() => console.log('zoom')}>
              Zoom
            </ContextMenu.Item>
            <ContextMenu.Item className={styles.item} onSelect={() => console.log('smaller')}>
              Smaller
            </ContextMenu.Item>
            <ContextMenu.Separator className={styles.separator} />
            <ContextMenu.RadioGroup value={file} onValueChange={setFile}>
              {files.map((file) => (
                <ContextMenu.RadioItem key={file} className={styles.item} value={file}>
                  {file}
                  <ContextMenu.ItemIndicator>
                    <TickIcon />
                  </ContextMenu.ItemIndicator>
                </ContextMenu.RadioItem>
              ))}
            </ContextMenu.RadioGroup>
          </ContextMenu.Content>
        </ContextMenu.Portal>
      </ContextMenu.Root>
      <p>Selected file: {file}</p>
    </div>
  );
};

export const PreventClosing = () => (
  <div style={{ textAlign: 'center', padding: 50 }}>
    <ContextMenu.Root>
      <ContextMenu.Trigger className={styles.trigger}>Right click here</ContextMenu.Trigger>
      <ContextMenu.Portal>
        <ContextMenu.Content className={styles.content} alignOffset={-5}>
          <ContextMenu.Item className={styles.item} onSelect={() => window.alert('action 1')}>
            I will close
          </ContextMenu.Item>
          <ContextMenu.Item
            className={styles.item}
            onSelect={(event) => {
              event.preventDefault();
              window.alert('action 1');
            }}
          >
            I won't close
          </ContextMenu.Item>
        </ContextMenu.Content>
      </ContextMenu.Portal>
    </ContextMenu.Root>
  </div>
);

export const Multiple = () => {
  const [customColors, setCustomColors] = React.useState<{ [index: number]: string }>({});
  const [fadedIndexes, setFadedIndexes] = React.useState<number[]>([]);
  return (
    <div
      style={{ display: 'flex', flexWrap: 'wrap', gap: 10 }}
      onContextMenu={(event) => event.preventDefault()}
    >
      {Array.from({ length: 100 }, (_, i) => {
        const customColor = customColors[i];
        return (
          <ContextMenu.Root key={i}>
            <ContextMenu.Portal>
              <ContextMenu.Content
                className={[styles.content, styles.animatedContent].join(' ')}
                alignOffset={-5}
              >
                <ContextMenu.Label className={styles.label}>Color</ContextMenu.Label>
                <ContextMenu.RadioGroup
                  value={customColor}
                  onValueChange={(color) =>
                    setCustomColors((colors) => ({ ...colors, [i]: color }))
                  }
                >
                  <ContextMenu.RadioItem className={styles.item} value="royalblue">
                    Blue
                    <ContextMenu.ItemIndicator>
                      <TickIcon />
                    </ContextMenu.ItemIndicator>
                  </ContextMenu.RadioItem>
                  <ContextMenu.RadioItem className={styles.item} value="tomato">
                    Red
                    <ContextMenu.ItemIndicator>
                      <TickIcon />
                    </ContextMenu.ItemIndicator>
                  </ContextMenu.RadioItem>
                </ContextMenu.RadioGroup>
                <ContextMenu.Separator className={styles.separator} />
                <ContextMenu.CheckboxItem
                  className={styles.item}
                  checked={fadedIndexes.includes(i)}
                  onCheckedChange={(faded) =>
                    setFadedIndexes((indexes) =>
                      faded ? [...indexes, i] : indexes.filter((index) => index !== i),
                    )
                  }
                >
                  Fade
                  <ContextMenu.ItemIndicator>
                    <TickIcon />
                  </ContextMenu.ItemIndicator>
                </ContextMenu.CheckboxItem>
              </ContextMenu.Content>
            </ContextMenu.Portal>
            <ContextMenu.Trigger>
              <div
                style={{
                  flexShrink: 0,
                  display: 'flex',
                  alignItems: 'center',
                  justifyContent: 'center',
                  width: 100,
                  height: 100,
                  backgroundColor: customColor ? customColor : '#eeeef0',
                  color: customColor ? 'white' : '#666670',
                  fontSize: 32,
                  borderRadius: 5,
                  cursor: 'default',
                  userSelect: 'none',
                  opacity: fadedIndexes.includes(i) ? 0.5 : 1,
                }}
              >
                {i + 1}
              </div>
            </ContextMenu.Trigger>
          </ContextMenu.Root>
        );
      })}
    </div>
  );
};

export const Nested = () => (
  <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
    <ContextMenu.Root>
      <ContextMenu.Trigger
        className={styles.trigger}
        style={{ padding: 100, backgroundColor: 'royalblue' }}
      >
        <ContextMenu.Root>
          <ContextMenu.Trigger className={styles.trigger} style={{ backgroundColor: 'tomato' }} />{' '}
          <ContextMenu.Portal>
            <ContextMenu.Content className={styles.content} alignOffset={-5}>
              <ContextMenu.Label className={styles.label}>Red box menu</ContextMenu.Label>
              <ContextMenu.Separator className={styles.separator} />
              <ContextMenu.Item className={styles.item} onSelect={() => console.log('red action1')}>
                Red action 1
              </ContextMenu.Item>
              <ContextMenu.Item className={styles.item} onSelect={() => console.log('red action2')}>
                Red action 2
              </ContextMenu.Item>
              <ContextMenu.Separator className={styles.separator} />
              <ContextMenu.Sub>
                <ContextMenu.SubTrigger className={styles.subTrigger}>
                  Submenu →
                </ContextMenu.SubTrigger>
                <ContextMenu.Portal>
                  <ContextMenu.SubContent
                    className={styles.content}
                    sideOffset={12}
                    alignOffset={-6}
                  >
                    <ContextMenu.Item
                      className={styles.item}
                      onSelect={() => console.log('red sub action 1')}
                    >
                      Red sub action 1
                    </ContextMenu.Item>
                    <ContextMenu.Item
                      className={styles.item}
                      onSelect={() => console.log('red sub action 2')}
                    >
                      Red sub action 2
                    </ContextMenu.Item>
                    <ContextMenu.Arrow />
                  </ContextMenu.SubContent>
                </ContextMenu.Portal>
              </ContextMenu.Sub>
            </ContextMenu.Content>
          </ContextMenu.Portal>
        </ContextMenu.Root>
      </ContextMenu.Trigger>
      <ContextMenu.Portal>
        <ContextMenu.Content className={styles.content} alignOffset={-5}>
          <ContextMenu.Label className={styles.label}>Blue box menu</ContextMenu.Label>
          <ContextMenu.Separator className={styles.separator} />
          <ContextMenu.Item className={styles.item} onSelect={() => console.log('blue action1')}>
            Blue action 1
          </ContextMenu.Item>
          <ContextMenu.Item className={styles.item} onSelect={() => console.log('blue action2')}>
            Blue action 2
          </ContextMenu.Item>
          <ContextMenu.Separator className={styles.separator} />
          <ContextMenu.Sub>
            <ContextMenu.SubTrigger className={styles.subTrigger}>Submenu →</ContextMenu.SubTrigger>
            <ContextMenu.Portal>
              <ContextMenu.SubContent className={styles.content} sideOffset={12} alignOffset={-6}>
                <ContextMenu.Item
                  className={styles.item}
                  onSelect={() => console.log('blue sub action 1')}
                >
                  Blue sub action 1
                </ContextMenu.Item>
                <ContextMenu.Item
                  className={styles.item}
                  onSelect={() => console.log('blue sub action 2')}
                >
                  Blue sub action 2
                </ContextMenu.Item>
                <ContextMenu.Arrow />
              </ContextMenu.SubContent>
            </ContextMenu.Portal>
          </ContextMenu.Sub>
        </ContextMenu.Content>
      </ContextMenu.Portal>
    </ContextMenu.Root>
  </div>
);

const TickIcon = () => (
  <svg
    xmlns="http://www.w3.org/2000/svg"
    viewBox="0 0 32 32"
    width="12"
    height="12"
    fill="none"
    stroke="currentcolor"
    strokeLinecap="round"
    strokeLinejoin="round"
    strokeWidth="3"
  >
    <path d="M2 20 L12 28 30 4" />
  </svg>
);



================================================
FILE: apps/storybook/stories/dialog.stories.module.css
================================================
.trigger {
}

.overlay {
  /* ensures overlay is positioned correctly */
  position: fixed;
  inset: 0;
  /* ------ */
  background-color: rgb(0 0 0 / 0.2);
}

.scrollableOverlay {
  overflow: auto;
  display: flex;
  align-items: flex-start;
  justify-content: center;
}

.contentDefault,
.contentSheet {
  /* ensures good default position for content */
  position: fixed;
  top: 0;
  left: 0;
  /* ------ */
  min-width: 300px;
  min-height: 150px;
  padding: 50px;
  border-radius: 10px;
  background-color: white;
  box-shadow: 0 2px 10px rgb(0 0 0 / 0.12);
}

.contentDefault {
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

.contentScrollable {
  overflow: auto;
  max-height: 300px;
}

.contentInScrollableOverlay {
  margin-top: 50px;
  margin-bottom: 50px;
}

.contentSheet {
  left: initial;
  right: 0;
  min-width: 300px;
  min-height: 100vh;
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}

.close {
}

@keyframes dialog-fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes dialog-fadeOut {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}

@keyframes dialog-scaleIn {
  from {
    transform: translate(-50%, -50%) scale(0.75);
  }
  to {
    transform: translate(-50%, -50%) scale(1);
  }
}

.animatedOverlay {
  &[data-state='open'] {
    animation: dialog-fadeIn 300ms ease-out;
  }
  &[data-state='closed'] {
    animation: dialog-fadeOut 300ms ease-in;
  }
}

.animatedContent {
  &[data-state='open'] {
    animation:
      dialog-fadeIn 150ms ease-out,
      dialog-scaleIn 200ms ease-out;
  }
  &[data-state='closed'] {
    animation: dialog-fadeOut 300ms ease-in;
  }
}

.duration50 {
  animation-duration: 50ms;
}

.chromaticContent {
  padding: 10px;
  min-width: auto;
  min-height: auto;
}

.triggerAttr,
.overlayAttr,
.contentAttr,
.closeAttr {
  background-color: rgb(0 0 255 / 0.3);
  border: 2px solid blue;
  padding: 10px;

  &[data-state='closed'] {
    border-color: red;
  }
  &[data-state='open'] {
    border-color: green;
  }
}



================================================
FILE: apps/storybook/stories/dialog.stories.tsx
================================================
import * as React from 'react';
import { Dialog } from 'radix-ui';
import styles from './dialog.stories.module.css';

export default { title: 'Components/Dialog' };

export const Styled = () => (
  <Dialog.Root>
    <Dialog.Trigger className={styles.trigger}>open</Dialog.Trigger>
    <Dialog.Portal>
      <Dialog.Overlay className={styles.overlay} />
      <Dialog.Content className={styles.contentDefault}>
        <Dialog.Title>Booking info</Dialog.Title>
        <Dialog.Description>Please enter the info for your booking below.</Dialog.Description>
        <Dialog.Close className={styles.close}>close</Dialog.Close>
      </Dialog.Content>
    </Dialog.Portal>
  </Dialog.Root>
);

export const NonModal = () => (
  <>
    <Dialog.Root modal={false}>
      <Dialog.Trigger className={styles.trigger}>open (non-modal)</Dialog.Trigger>
      <Dialog.Portal>
        <Dialog.Overlay className={styles.overlay} />
        <Dialog.Content
          className={[styles.contentDefault, styles.contentSheet].join(' ')}
          onInteractOutside={(event) => event.preventDefault()}
        >
          <Dialog.Title>Booking info</Dialog.Title>
          <Dialog.Description>Description</Dialog.Description>
          <Dialog.Close className={styles.close}>close</Dialog.Close>
        </Dialog.Content>
      </Dialog.Portal>
    </Dialog.Root>

    {Array.from({ length: 5 }, (_, i) => (
      <div key={i} style={{ marginTop: 20 }}>
        <textarea
          style={{ width: 800, height: 400 }}
          defaultValue="Lorem ipsum dolor sit amet consectetur adipisicing elit. Quaerat nobis at ipsa, nihil tempora debitis maxime dignissimos non amet, minima expedita alias et fugit voluptate laborum placeat odio dolore ab!"
        />
      </div>
    ))}
  </>
);

export const Controlled = () => {
  const [open, setOpen] = React.useState(false);
  return (
    <Dialog.Root open={open} onOpenChange={setOpen}>
      <Dialog.Trigger>{open ? 'close' : 'open'}</Dialog.Trigger>
      <Dialog.Portal>
        <Dialog.Overlay className={styles.overlay} />
        <Dialog.Content className={styles.contentDefault}>
          <Dialog.Title>Title</Dialog.Title>
          <Dialog.Description>Description</Dialog.Description>
          <Dialog.Close>close</Dialog.Close>
        </Dialog.Content>
      </Dialog.Portal>
    </Dialog.Root>
  );
};

export const FocusTrap = () => (
  <>
    <Dialog.Root>
      <Dialog.Trigger>open</Dialog.Trigger>
      <Dialog.Portal>
        <Dialog.Overlay className={styles.overlay} />
        <Dialog.Content className={styles.contentDefault}>
          <Dialog.Close>close</Dialog.Close>
          <Dialog.Title>Title</Dialog.Title>
          <Dialog.Description>Description</Dialog.Description>
          <div>
            <label htmlFor="firstName">First Name</label>
            <input type="text" id="firstName" placeholder="John" />

            <label htmlFor="lastName">Last Name</label>
            <input type="text" id="lastName" placeholder="Doe" />

            <button type="submit">Send</button>
          </div>
        </Dialog.Content>
      </Dialog.Portal>
    </Dialog.Root>

    <p>These elements can't be focused when the dialog is opened.</p>
    <button type="button">A button</button>
    <input type="text" placeholder="Another focusable element" />
  </>
);

export const CustomFocus = () => {
  const firstNameRef = React.useRef<HTMLInputElement>(null);
  const searchFieldRef = React.useRef<HTMLInputElement>(null);
  return (
    <>
      <Dialog.Root>
        <Dialog.Trigger>open</Dialog.Trigger>
        <Dialog.Portal>
          <Dialog.Overlay className={styles.overlay} />
          <Dialog.Content
            className={styles.contentDefault}
            onOpenAutoFocus={(event) => {
              event.preventDefault();
              firstNameRef.current?.focus();
            }}
            onCloseAutoFocus={(event) => {
              event.preventDefault();
              searchFieldRef.current?.focus();
            }}
          >
            <Dialog.Close>close</Dialog.Close>

            <div>
              <Dialog.Title>Title</Dialog.Title>
              <Dialog.Description>
                The first name input will receive the focus after opening the dialog.
              </Dialog.Description>
              <label htmlFor="firstName">First Name</label>
              <input type="text" id="firstName" placeholder="John" ref={firstNameRef} />

              <label htmlFor="lastName">Last Name</label>
              <input type="text" id="lastName" placeholder="Doe" />

              <button type="submit">Send</button>
            </div>
          </Dialog.Content>
        </Dialog.Portal>
      </Dialog.Root>

      <div>
        <p>The search input will receive the focus after closing the dialog.</p>
        <input type="text" placeholder="Search…" ref={searchFieldRef} />
      </div>
    </>
  );
};

export const NoEscapeDismiss = () => (
  <Dialog.Root>
    <Dialog.Trigger>open</Dialog.Trigger>
    <Dialog.Portal>
      <Dialog.Overlay className={styles.overlay} />
      <Dialog.Content
        className={styles.contentDefault}
        onEscapeKeyDown={(event) => event.preventDefault()}
      >
        <Dialog.Title>Title</Dialog.Title>
        <Dialog.Description>
          The first name input will receive the focus after opening the dialog.
        </Dialog.Description>
        <Dialog.Close>close</Dialog.Close>
      </Dialog.Content>
    </Dialog.Portal>
  </Dialog.Root>
);

export const NoPointerDownOutsideDismiss = () => (
  <Dialog.Root>
    <Dialog.Trigger>open</Dialog.Trigger>
    <Dialog.Portal>
      <Dialog.Overlay className={styles.overlay} />
      <Dialog.Content
        className={styles.contentDefault}
        onPointerDownOutside={(event) => event.preventDefault()}
      >
        <Dialog.Title>Title</Dialog.Title>
        <Dialog.Description>Description</Dialog.Description>
        <Dialog.Close>close</Dialog.Close>
      </Dialog.Content>
    </Dialog.Portal>
  </Dialog.Root>
);

export const WithPortalContainer = () => {
  const [portalContainer, setPortalContainer] = React.useState<HTMLDivElement | null>(null);
  return (
    <>
      <Dialog.Root>
        <Dialog.Trigger>open</Dialog.Trigger>
        <Dialog.Portal container={portalContainer}>
          <Dialog.Overlay className={styles.overlay} />
          <Dialog.Content className={styles.contentDefault}>
            <Dialog.Title>Title</Dialog.Title>
            <Dialog.Description>Description</Dialog.Description>
            <Dialog.Close>close</Dialog.Close>
          </Dialog.Content>
        </Dialog.Portal>
      </Dialog.Root>
      <div data-portal-container="" ref={setPortalContainer} />
    </>
  );
};

export const Animated = () => (
  <Dialog.Root>
    <Dialog.Trigger>open</Dialog.Trigger>
    <Dialog.Portal>
      <Dialog.Overlay className={[styles.overlay, styles.animatedOverlay].join(' ')} />
      <Dialog.Content className={[styles.contentDefault, styles.animatedContent].join(' ')}>
        <Dialog.Title>Title</Dialog.Title>
        <Dialog.Description>Description</Dialog.Description>
        <Dialog.Close>close</Dialog.Close>
      </Dialog.Content>
    </Dialog.Portal>
  </Dialog.Root>
);

export const ForcedMount = () => (
  <Dialog.Root>
    <Dialog.Trigger>open</Dialog.Trigger>
    <Dialog.Portal forceMount>
      <Dialog.Overlay className={styles.overlay} />
      <Dialog.Content className={styles.contentDefault}>
        <Dialog.Title>Title</Dialog.Title>
        <Dialog.Description>Description</Dialog.Description>
        <Dialog.Close>close</Dialog.Close>
      </Dialog.Content>
    </Dialog.Portal>
  </Dialog.Root>
);

export const InnerScrollable = () => (
  <Dialog.Root>
    <Dialog.Trigger className={styles.trigger}>open</Dialog.Trigger>
    <Dialog.Portal>
      <Dialog.Overlay className={styles.overlay} />
      <Dialog.Content className={[styles.contentDefault, styles.contentScrollable].join(' ')}>
        <Dialog.Title>Booking info</Dialog.Title>
        <Dialog.Description>Please enter the info for your booking below.</Dialog.Description>
        <div style={{ backgroundColor: '#eee', height: 500 }} />
        <Dialog.Close className={styles.close}>close</Dialog.Close>
      </Dialog.Content>
    </Dialog.Portal>
  </Dialog.Root>
);

export const OuterScrollable = () => (
  <Dialog.Root>
    <Dialog.Trigger className={styles.trigger}>open</Dialog.Trigger>
    <div style={{ backgroundColor: '#eee', width: 300, height: 1000 }} />
    <Dialog.Portal>
      <Dialog.Overlay className={[styles.overlay, styles.scrollableOverlay].join(' ')}>
        <Dialog.Content
          className={[styles.contentDefault, styles.contentInScrollableOverlay].join(' ')}
        >
          <Dialog.Title>Booking info</Dialog.Title>
          <Dialog.Description>Please enter the info for your booking below.</Dialog.Description>
          <div style={{ backgroundColor: '#eee', height: 500 }} />
          <Dialog.Close className={styles.close}>close</Dialog.Close>
        </Dialog.Content>
      </Dialog.Overlay>
    </Dialog.Portal>
  </Dialog.Root>
);

export const Chromatic = () => (
  <>
    <div
      style={{
        display: 'grid',
        gridTemplateColumns: 'repeat(4, 1fr)',
        height: '50vh',
      }}
    >
      <div>
        <h1>Uncontrolled</h1>
        <h2>Closed</h2>
        <Dialog.Root>
          <Dialog.Trigger className={styles.trigger}>open</Dialog.Trigger>
          <Dialog.Portal>
            <Dialog.Overlay className={styles.overlay} />
            <Dialog.Content className={[styles.contentDefault, styles.chromaticContent].join(' ')}>
              <Dialog.Title>Title</Dialog.Title>
              <Dialog.Description>Description</Dialog.Description>
              <Dialog.Close className={styles.close}>close</Dialog.Close>
            </Dialog.Content>
          </Dialog.Portal>
        </Dialog.Root>

        <h2>Open</h2>
        <Dialog.Root defaultOpen>
          <Dialog.Trigger className={styles.trigger}>open</Dialog.Trigger>
          <Dialog.Portal>
            <Dialog.Overlay
              className={styles.overlay}
              style={{ left: 0, bottom: '50%', width: '25%' }}
            />
            <Dialog.Content className={styles.chromaticContent} style={{ top: '25%', left: '12%' }}>
              <Dialog.Title>Title</Dialog.Title>
              <Dialog.Description>Description</Dialog.Description>
              <Dialog.Close className={styles.close}>close</Dialog.Close>
            </Dialog.Content>
          </Dialog.Portal>
        </Dialog.Root>
      </div>

      <div>
        <h1>Uncontrolled with reordered parts</h1>
        <h2>Closed</h2>
        <Dialog.Root>
          <Dialog.Portal>
            <Dialog.Overlay className={styles.overlay} />
            <Dialog.Content className={styles.chromaticContent}>
              <Dialog.Title>Title</Dialog.Title>
              <Dialog.Description>Description</Dialog.Description>
              <Dialog.Close className={styles.close}>close</Dialog.Close>
            </Dialog.Content>
          </Dialog.Portal>
          <Dialog.Trigger className={styles.trigger}>open</Dialog.Trigger>
        </Dialog.Root>

        <h2>Open</h2>
        <Dialog.Root defaultOpen>
          <Dialog.Portal>
            <Dialog.Overlay
              className={styles.overlay}
              style={{ left: '25%', bottom: '50%', width: '25%' }}
            />
            <Dialog.Content className={styles.chromaticContent} style={{ top: '25%', left: '37%' }}>
              <Dialog.Title>Title</Dialog.Title>
              <Dialog.Description>Description</Dialog.Description>
              <Dialog.Close className={styles.close}>close</Dialog.Close>
            </Dialog.Content>
          </Dialog.Portal>
          <Dialog.Trigger className={styles.trigger}>open</Dialog.Trigger>
        </Dialog.Root>
      </div>

      <div>
        <h1>Controlled</h1>
        <h2>Closed</h2>
        <Dialog.Root open={false}>
          <Dialog.Trigger className={styles.trigger}>open</Dialog.Trigger>
          <Dialog.Portal>
            <Dialog.Overlay className={styles.overlay} />
            <Dialog.Content className={styles.chromaticContent}>
              <Dialog.Title>Title</Dialog.Title>
              <Dialog.Description>Description</Dialog.Description>
              <Dialog.Close className={styles.close}>close</Dialog.Close>
            </Dialog.Content>
          </Dialog.Portal>
        </Dialog.Root>

        <h2>Open</h2>
        <Dialog.Root open>
          <Dialog.Trigger className={styles.trigger}>open</Dialog.Trigger>
          <Dialog.Portal>
            <Dialog.Overlay
              className={styles.overlay}
              style={{ left: '50%', bottom: '50%', width: '25%' }}
            />
            <Dialog.Content className={styles.chromaticContent} style={{ top: '25%', left: '62%' }}>
              <Dialog.Title>Title</Dialog.Title>
              <Dialog.Description>Description</Dialog.Description>
              <Dialog.Close className={styles.close}>close</Dialog.Close>
            </Dialog.Content>
          </Dialog.Portal>
        </Dialog.Root>
      </div>

      <div>
        <h1>Controlled with reordered parts</h1>
        <h2>Closed</h2>
        <Dialog.Root open={false}>
          <Dialog.Portal>
            <Dialog.Overlay className={styles.overlay} />
            <Dialog.Content className={styles.chromaticContent}>
              <Dialog.Title>Title</Dialog.Title>
              <Dialog.Description>Description</Dialog.Description>
              <Dialog.Close className={styles.close}>close</Dialog.Close>
            </Dialog.Content>
          </Dialog.Portal>
          <Dialog.Trigger className={styles.trigger}>open</Dialog.Trigger>
        </Dialog.Root>

        <h2>Open</h2>
        <Dialog.Root open>
          <Dialog.Portal>
            <Dialog.Overlay
              className={styles.overlay}
              style={{ left: '75%', bottom: '50%', width: '25%' }}
            />
            <Dialog.Content className={styles.chromaticContent} style={{ top: '25%', left: '88%' }}>
              <Dialog.Title>Title</Dialog.Title>
              <Dialog.Description>Description</Dialog.Description>
              <Dialog.Close className={styles.close}>close</Dialog.Close>
            </Dialog.Content>
          </Dialog.Portal>
          <Dialog.Trigger className={styles.trigger}>open</Dialog.Trigger>
        </Dialog.Root>
      </div>
    </div>

    <div
      style={{
        display: 'grid',
        gridTemplateColumns: 'repeat(2, 1fr)',
        height: '50vh',
      }}
    >
      <div>
        <h1>Forced mount</h1>
        <Dialog.Root>
          <Dialog.Trigger className={styles.trigger}>open</Dialog.Trigger>
          <Dialog.Portal forceMount>
            <Dialog.Overlay
              className={styles.overlay}
              style={{
                top: '50%',
                backgroundColor: 'rgba(0, 0, 0, 0.3)',
              }}
            />
            <Dialog.Content className={styles.chromaticContent} style={{ left: '25%', top: '75%' }}>
              <Dialog.Title>Title</Dialog.Title>
              <Dialog.Description>Description</Dialog.Description>
              <Dialog.Close className={styles.close}>close</Dialog.Close>
            </Dialog.Content>
          </Dialog.Portal>
        </Dialog.Root>
      </div>

      <div>
        <h1>State attributes</h1>
        <h2>Closed</h2>
        <Dialog.Root>
          <Dialog.Trigger className={styles.triggerAttr}>open</Dialog.Trigger>
          <Dialog.Portal>
            <Dialog.Overlay className={styles.overlayAttr} />
            <Dialog.Content className={[styles.chromaticContent, styles.contentAttr].join(' ')}>
              <Dialog.Title>Title</Dialog.Title>
              <Dialog.Description>Description</Dialog.Description>
              <Dialog.Close className={styles.closeAttr}>close</Dialog.Close>
            </Dialog.Content>
          </Dialog.Portal>
        </Dialog.Root>

        <h2>Open</h2>
        <Dialog.Root defaultOpen>
          <Dialog.Trigger className={styles.triggerAttr}>open</Dialog.Trigger>
          <Dialog.Portal>
            <Dialog.Overlay
              className={[styles.overlay, styles.overlayAttr].join(' ')}
              style={{ left: '50%', top: '50%' }}
            />
            <Dialog.Content
              className={[styles.chromaticContent, styles.contentAttr].join(' ')}
              style={{ left: '75%', top: '75%' }}
            >
              <Dialog.Title>Title</Dialog.Title>
              <Dialog.Description>Description</Dialog.Description>
              <Dialog.Close className={styles.closeAttr}>close</Dialog.Close>
            </Dialog.Content>
          </Dialog.Portal>
        </Dialog.Root>
      </div>
    </div>
  </>
);
Chromatic.parameters = { chromatic: { disable: false } };

export const Cypress = () => {
  const [modal, setModal] = React.useState(true);
  const [animated, setAnimated] = React.useState(false);
  const [count, setCount] = React.useState(0);
  const [hasDestroyButton, setHasDestroyButton] = React.useState(true);

  return (
    <>
      <Dialog.Root modal={modal}>
        <Dialog.Trigger className={styles.trigger}>open</Dialog.Trigger>
        <Dialog.Portal>
          <Dialog.Content
            className={[
              styles.contentDefault,
              animated && styles.animatedContent,
              animated && styles.duration50,
            ]
              .filter(Boolean)
              .join(' ')}
          >
            <Dialog.Title>title</Dialog.Title>
            <Dialog.Description>description</Dialog.Description>
            <Dialog.Close className={styles.close}>close</Dialog.Close>
            {hasDestroyButton && (
              <div>
                <button type="button" onClick={() => setHasDestroyButton(false)}>
                  destroy me
                </button>
              </div>
            )}
          </Dialog.Content>
        </Dialog.Portal>
      </Dialog.Root>

      <br />
      <br />

      <label>
        <input
          type="checkbox"
          checked={modal}
          onChange={(event) => setModal(Boolean(event.target.checked))}
        />{' '}
        modal
      </label>

      <br />

      <label>
        <input
          type="checkbox"
          checked={animated}
          onChange={(event) => setAnimated(Boolean(event.target.checked))}
        />{' '}
        animated
      </label>

      <br />

      <label>
        count up{' '}
        <button type="button" onClick={() => setCount((count) => count + 1)}>
          {count}
        </button>
      </label>

      <br />

      <label>
        name: <input type="text" placeholder="name" />
      </label>
    </>
  );
};



================================================
FILE: apps/storybook/stories/dismissable-layer.stories.tsx
================================================
import * as React from 'react';
import * as ReactDOM from 'react-dom/client';
import { Portal, Slot } from 'radix-ui';
import {
  DismissableLayer as DismissableLayerPrimitive,
  FocusGuards,
  FocusScope as FocusScopePrimitive,
  Popper,
} from 'radix-ui/internal';
import { RemoveScroll } from 'react-remove-scroll';

const DismissableLayer = DismissableLayerPrimitive.Root;
const FocusScope = FocusScopePrimitive.Root;

type DismissableLayerProps = React.ComponentProps<typeof DismissableLayer>;
type FocusScopeProps = React.ComponentProps<typeof FocusScope>;

export default { title: 'Utilities/DismissableLayer' };

const SYSTEM_FONT =
  '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"';

export const Basic = () => {
  const [open, setOpen] = React.useState(false);
  const openButtonRef = React.useRef(null);

  const [dismissOnEscape, setDismissOnEscape] = React.useState(false);
  const [dismissOnPointerDownOutside, setDismissOnPointerDownOutside] = React.useState(false);
  const [dismissOnFocusOutside, setDismissOnFocusOutside] = React.useState(false);
  const [disabledOutsidePointerEvents, setDisableOutsidePointerEvents] = React.useState(false);

  return (
    <div style={{ fontFamily: 'sans-serif', textAlign: 'center' }}>
      <h1>DismissableLayer</h1>

      <div style={{ display: 'inline-block', textAlign: 'left', marginBottom: 20 }}>
        <label style={{ display: 'block' }}>
          <input
            type="checkbox"
            checked={dismissOnEscape}
            onChange={(event) => setDismissOnEscape(event.target.checked)}
          />{' '}
          Dismiss on escape?
        </label>

        <label style={{ display: 'block' }}>
          <input
            type="checkbox"
            checked={dismissOnPointerDownOutside}
            onChange={(event) => setDismissOnPointerDownOutside(event.target.checked)}
          />{' '}
          Dismiss on pointer down outside?
        </label>

        <label style={{ display: 'block' }}>
          <input
            type="checkbox"
            checked={dismissOnFocusOutside}
            onChange={(event) => setDismissOnFocusOutside(event.target.checked)}
          />{' '}
          Dismiss on focus outside?
        </label>

        <hr />

        <label style={{ display: 'block' }}>
          <input
            type="checkbox"
            checked={disabledOutsidePointerEvents}
            onChange={(event) => setDisableOutsidePointerEvents(event.target.checked)}
          />{' '}
          Disable outside pointer events?
        </label>
      </div>

      <div style={{ marginBottom: 20 }}>
        <button ref={openButtonRef} type="button" onClick={() => setOpen((open) => !open)}>
          {open ? 'Close' : 'Open'} layer
        </button>
      </div>

      {open ? (
        <DismissableLayer
          onEscapeKeyDown={(event) => {
            if (dismissOnEscape === false) {
              event.preventDefault();
            }
          }}
          onPointerDownOutside={(event) => {
            if (dismissOnPointerDownOutside === false || event.target === openButtonRef.current) {
              event.preventDefault();
            }
          }}
          onFocusOutside={(event) => {
            if (dismissOnFocusOutside === false) {
              event.preventDefault();
            }
          }}
          disableOutsidePointerEvents={disabledOutsidePointerEvents}
          onDismiss={() => setOpen(false)}
          style={{
            display: 'inline-flex',
            justifyContent: 'center',
            alignItems: 'center',
            verticalAlign: 'middle',
            width: 400,
            height: 300,
            backgroundColor: 'black',
            borderRadius: 10,
            marginBottom: 20,
          }}
        >
          <input type="text" />
        </DismissableLayer>
      ) : null}

      <div style={{ marginBottom: 20 }}>
        <input type="text" defaultValue="hello" style={{ marginRight: 20 }} />
        <button type="button" onMouseDown={() => alert('hey!')}>
          hey!
        </button>
      </div>
    </div>
  );
};

export const Nested = () => {
  return (
    <div style={{ fontFamily: 'sans-serif', textAlign: 'center' }}>
      <h1>DismissableLayer (nested)</h1>
      <DismissableBox />
    </div>
  );
};

export const WithFocusScope = () => {
  const [open, setOpen] = React.useState(false);
  const openButtonRef = React.useRef(null);

  return (
    <div style={{ fontFamily: 'sans-serif', textAlign: 'center' }}>
      <h1>DismissableLayer + FocusScope</h1>
      <div style={{ marginBottom: 20 }}>
        <button ref={openButtonRef} type="button" onClick={() => setOpen((open) => !open)}>
          {open ? 'Close' : 'Open'} layer
        </button>
      </div>

      {open ? (
        <DismissableLayer
          asChild
          onPointerDownOutside={(event) => {
            if (event.target === openButtonRef.current) {
              event.preventDefault();
            }
          }}
          disableOutsidePointerEvents
          onDismiss={() => setOpen(false)}
        >
          <FocusScope
            trapped
            style={{
              display: 'inline-flex',
              justifyContent: 'center',
              alignItems: 'center',
              verticalAlign: 'middle',
              width: 400,
              height: 300,
              backgroundColor: 'black',
              borderRadius: 10,
              marginBottom: 20,
            }}
          >
            <input type="text" />
          </FocusScope>
        </DismissableLayer>
      ) : null}

      <div style={{ marginBottom: 20 }}>
        <input type="text" defaultValue="hello" style={{ marginRight: 20 }} />
        <button type="button" onMouseDown={() => alert('hey!')}>
          hey!
        </button>
      </div>
    </div>
  );
};

type DismissableBoxProps = Omit<DismissableLayerProps, 'children'>;

function DismissableBox(props: DismissableBoxProps) {
  const [open, setOpen] = React.useState(false);
  const openButtonRef = React.useRef(null);

  return (
    <DismissableLayer
      {...props}
      style={{
        display: 'inline-block',
        verticalAlign: 'middle',
        padding: 20,
        backgroundColor: 'rgba(0, 0, 0, 0.2)',
        borderRadius: 10,
        marginTop: 20,
        ...props.style,
      }}
    >
      <div>
        <button ref={openButtonRef} type="button" onClick={() => setOpen((open) => !open)}>
          {open ? 'Close' : 'Open'} new layer
        </button>
      </div>

      {open ? (
        <DismissableBox
          onPointerDownOutside={(event) => {
            if (event.target === openButtonRef.current) {
              event.preventDefault();
            }
          }}
          onFocusOutside={(event) => event.preventDefault()}
          onDismiss={() => setOpen(false)}
        />
      ) : null}
    </DismissableLayer>
  );
}

export const DialogExample = () => (
  <div style={{ height: '300vh', fontFamily: SYSTEM_FONT }}>
    <h1>Dialog (fully modal example)</h1>
    <ul style={{ listStyle: 'none', padding: 0, marginBottom: 30 }}>
      <li>✅ focus should move inside `Dialog` when mounted</li>
      <li>✅ focus should be trapped inside `Dialog`</li>
      <li>✅ scrolling outside `Dialog` should be disabled</li>
      <li>✅ should be able to dismiss `Dialog` on pressing escape</li>
      <li style={{ marginLeft: 30 }}>✅ focus should return to the open button</li>
      <li>
        ✅ interacting outside `Dialog` should be disabled (clicking the "alert me" button shouldn't
        do anything)
      </li>
      <li>➕</li>
      <li>✅ should be able to dismiss `Dialog` when interacting outside</li>
      <li style={{ marginLeft: 30 }}>✅ focus should return to the open button</li>
    </ul>

    <div style={{ display: 'flex', gap: 10 }}>
      <DummyDialog openLabel="Open Dialog" closeLabel="Close Dialog" />
      <input type="text" defaultValue="some input" />
      <button type="button" onClick={() => window.alert('clicked!')}>
        Alert me
      </button>
    </div>
  </div>
);

export const PopoverFullyModal = () => (
  <div style={{ height: '300vh', fontFamily: SYSTEM_FONT }}>
    <h1>Popover (fully modal example)</h1>
    <ul style={{ listStyle: 'none', padding: 0, marginBottom: 30 }}>
      <li>✅ focus should move inside `Popover` when mounted</li>
      <li>✅ focus should be trapped inside `Popover`</li>
      <li>✅ scrolling outside `Popover` should be disabled</li>
      <li>✅ should be able to dismiss `Popover` on pressing escape</li>
      <li style={{ marginLeft: 30 }}>✅ focus should return to the open button</li>
      <li>
        ✅ interacting outside `Popover` should be disabled (clicking the "alert me" button
        shouldn't do anything)
      </li>
      <li>➕</li>
      <li>✅ should be able to dismiss `Popover` when interacting outside</li>
      <li style={{ marginLeft: 30 }}>✅ focus should return to the open button</li>
    </ul>

    <div style={{ display: 'flex', gap: 10 }}>
      <DummyPopover
        openLabel="Open Popover"
        closeLabel="Close Popover"
        disableOutsidePointerEvents
        preventScroll
      />
      <input type="text" defaultValue="some input" />
      <button type="button" onClick={() => window.alert('clicked!')}>
        Alert me
      </button>
    </div>
  </div>
);

export const PopoverSemiModal = () => {
  const [color, setColor] = React.useState('royalblue');
  const changeColorButtonRef = React.useRef(null);
  return (
    <div style={{ height: '300vh', fontFamily: SYSTEM_FONT }}>
      <h1>Popover (semi-modal example)</h1>
      <ul style={{ listStyle: 'none', padding: 0, marginBottom: 30 }}>
        <li>✅ focus should move inside `Popover` when mounted</li>
        <li>✅ focus should be trapped inside `Popover`</li>
        <li>✅ scrolling outside `Popover` should be allowed</li>
        <li>✅ should be able to dismiss `Popover` on pressing escape</li>
        <li style={{ marginLeft: 30 }}>✅ focus should return to the open button</li>
        <li>
          ✅ interacting outside `Popover` should be allowed (clicking the "alert me" button should
          trigger)
        </li>
        <li>➕</li>
        <li>
          ✅ should be able to dismiss `Popover` when interacting outside{' '}
          <span style={{ fontWeight: 600 }}>unless specified (ie. change color button)</span>
        </li>
        <li style={{ marginLeft: 30 }}>
          ✅ focus should <span style={{ fontWeight: 600 }}>NOT</span> return to the open button
          when unmounted, natural focus should occur
        </li>
      </ul>

      <div style={{ display: 'flex', gap: 10 }}>
        <DummyPopover
          color={color}
          openLabel="Open Popover"
          closeLabel="Close Popover"
          onPointerDownOutside={(event) => {
            if (event.target === changeColorButtonRef.current) {
              event.preventDefault();
            }
          }}
        />
        <input type="text" defaultValue="some input" />
        <button type="button" onClick={() => window.alert('clicked!')}>
          Alert me
        </button>
        <button
          ref={changeColorButtonRef}
          type="button"
          onClick={() =>
            setColor((prevColor) => (prevColor === 'royalblue' ? 'tomato' : 'royalblue'))
          }
        >
          Change color
        </button>
      </div>
    </div>
  );
};

export const PopoverNonModal = () => (
  <div style={{ height: '300vh', fontFamily: SYSTEM_FONT }}>
    <h1>Popover (non modal example)</h1>
    <ul style={{ listStyle: 'none', padding: 0, marginBottom: 30 }}>
      <li>✅ focus should move inside `Popover` when mounted</li>
      <li>
        ✅ focus should <span style={{ fontWeight: 600 }}>NOT</span> be trapped inside `Popover`
      </li>
      <li>✅ scrolling outside `Popover` should be allowed</li>
      <li>✅ should be able to dismiss `Popover` on pressing escape</li>
      <li style={{ marginLeft: 30 }}>✅ focus should return to the open button</li>
      <li>
        ✅ interacting outside `Popover` should be allowed (clicking the "alert me" button should
        trigger)
      </li>
      <li>➕</li>
      <li>✅ should be able to dismiss `Popover` when clicking outside</li>
      <li style={{ marginLeft: 30 }}>
        ✅ focus should <span style={{ fontWeight: 600 }}>NOT</span> return to the open button when
        unmounted, natural focus should occur
      </li>
      <li>✅ should be able to dismiss `Popover` when focus leaves it</li>
      <li style={{ marginLeft: 30 }}>
        ❓ focus should move to next tabbable element after open button
        <div style={{ fontWeight: 600 }}>
          <span style={{ marginLeft: 20 }}>notes:</span>
          <ul>
            <li>
              I have left this one out for now as I am still unsure in which case it should do this
            </li>
            <li>
              for the moment, focus will be returned to the open button when `FocusScope` unmounts
            </li>
            <li>Need to do some more thinking, in the meantime, I think this behavior is ok</li>
          </ul>
        </div>
      </li>
    </ul>

    <div style={{ display: 'flex', gap: 10 }}>
      <DummyPopover openLabel="Open Popover" closeLabel="Close Popover" trapped={false} />
      <input type="text" defaultValue="some input" />
      <button type="button" onClick={() => window.alert('clicked!')}>
        Alert me
      </button>
    </div>
  </div>
);

export const PopoverInDialog = () => (
  <div style={{ height: '300vh', fontFamily: SYSTEM_FONT }}>
    <h1>Popover (semi-modal) in Dialog (fully modal)</h1>
    <ul style={{ listStyle: 'none', padding: 0, marginBottom: 30 }}>
      <li>
        ✅ dismissing `Popover` by pressing escape should{' '}
        <span style={{ fontWeight: 600 }}>NOT</span> dismiss `Dialog`
      </li>
      <li>✅ dismissing `Popover` by clicking outside should also dismiss `Dialog`</li>
    </ul>

    <div style={{ display: 'flex', gap: 10 }}>
      <DummyDialog openLabel="Open Dialog" closeLabel="Close Dialog">
        <DummyPopover openLabel="Open Popover" closeLabel="Close Popover" />
      </DummyDialog>
      <input type="text" defaultValue="some input" />
      <button type="button" onClick={() => window.alert('clicked!')}>
        Alert me
      </button>
    </div>
  </div>
);

export const PopoverNested = () => (
  <div style={{ height: '300vh', fontFamily: SYSTEM_FONT }}>
    <h1>Popover (nested example)</h1>
    <ul style={{ listStyle: 'none', padding: 0, marginBottom: 30 }}>
      <li>
        ✅ dismissing a `Popover` by pressing escape should only dismiss that given `Popover`, not
        its parents
      </li>
      <li>
        ✅ interacting outside the blue `Popover` should only dismiss itself and not its parents
      </li>
      <li>✅ interacting outside the red `Popover` should dismiss itself and the black one</li>
      <li>✅ unless the click wasn't outside the black one</li>
      <li>
        ✅ when the blue `Popover` is open, there should be{' '}
        <span style={{ fontWeight: 600 }}>NO</span> text cursor above the red or black inputs
      </li>
      <li>
        ✅ when the red `Popover` is open, there should be a text cursor above the black input but
        not the one on the page behind
      </li>
    </ul>

    <div style={{ display: 'flex', gap: 10 }}>
      <DummyPopover
        disableOutsidePointerEvents
        onInteractOutside={() => {
          console.log('interact outside black');
        }}
      >
        <DummyPopover
          color="tomato"
          openLabel="Open red"
          closeLabel="Close red"
          onInteractOutside={() => {
            console.log('interact outside red');
          }}
        >
          <DummyPopover
            color="royalblue"
            openLabel="Open blue"
            closeLabel="Close blue"
            disableOutsidePointerEvents
            onInteractOutside={() => {
              console.log('interact outside blue');
            }}
          ></DummyPopover>
        </DummyPopover>
      </DummyPopover>
      <input type="text" defaultValue="some input" />
      <button type="button" onClick={() => window.alert('clicked!')}>
        Alert me
      </button>
    </div>
  </div>
);

/* -------------------------------------------------------------------------------------------------
 * Dummy components
 * -----------------------------------------------------------------------------------------------*/

type DummyDialogProps = {
  children?: React.ReactNode;
  openLabel?: string;
  closeLabel?: string;
};

function DummyDialog({ children, openLabel = 'Open', closeLabel = 'Close' }: DummyDialogProps) {
  const [open, setOpen] = React.useState(false);
  return (
    <>
      <button type="button" onClick={() => setOpen((prevOpen) => !prevOpen)}>
        {openLabel}
      </button>
      {open ? (
        <FocusGuards.Root>
          <Portal.Root asChild>
            <div
              style={{
                position: 'fixed',
                top: 0,
                right: 0,
                bottom: 0,
                left: 0,
                pointerEvents: 'none',
                backgroundColor: 'black',
                opacity: 0.2,
              }}
            />
          </Portal.Root>
          <Portal.Root asChild>
            <RemoveScroll as={Slot.Root}>
              <DismissableLayer
                asChild
                disableOutsidePointerEvents
                onDismiss={() => setOpen(false)}
              >
                <FocusScope
                  trapped
                  style={{
                    boxSizing: 'border-box',
                    display: 'flex',
                    alignItems: 'start',
                    gap: 10,
                    position: 'fixed',
                    top: '50%',
                    left: '50%',
                    transform: 'translate(-50%, -50%)',
                    background: 'white',
                    minWidth: 300,
                    minHeight: 200,
                    padding: 40,
                    borderRadius: 10,
                    backgroundColor: 'white',
                    boxShadow: '0 2px 10px rgba(0, 0, 0, 0.12)',
                  }}
                >
                  {children}
                  <button type="button" onClick={() => setOpen(false)}>
                    {closeLabel}
                  </button>
                  <input type="text" defaultValue="hello world" />
                </FocusScope>
              </DismissableLayer>
            </RemoveScroll>
          </Portal.Root>
        </FocusGuards.Root>
      ) : null}
    </>
  );
}

type DummyPopoverOwnProps = {
  children?: React.ReactNode;
  openLabel?: string;
  closeLabel?: string;
  color?: string;
  preventScroll?: boolean;
};
type DummyPopoverProps = DummyPopoverOwnProps &
  Omit<FocusScopeProps, 'children'> &
  Omit<DismissableLayerProps, 'children'>;

function DummyPopover({
  children,
  openLabel = 'Open',
  closeLabel = 'Close',
  color = '#333',
  trapped = true,
  onEscapeKeyDown,
  onPointerDownOutside,
  onFocusOutside,
  onInteractOutside,
  disableOutsidePointerEvents = false,
  preventScroll = false,
}: DummyPopoverProps) {
  const [skipUnmountAutoFocus, setSkipUnmountAutoFocus] = React.useState(false);
  const [open, setOpen] = React.useState(false);
  const openButtonRef = React.useRef(null);
  const ScrollContainer = preventScroll ? RemoveScroll : React.Fragment;
  const scrollLockWrapperProps = preventScroll ? { as: Slot.Root } : undefined;

  return (
    <Popper.Root>
      <Popper.Anchor asChild>
        <button type="button" ref={openButtonRef} onClick={() => setOpen((prevOpen) => !prevOpen)}>
          {openLabel}
        </button>
      </Popper.Anchor>
      {open ? (
        <FocusGuards.Root>
          <ScrollContainer {...scrollLockWrapperProps}>
            <Portal.Root asChild>
              <DismissableLayer
                asChild
                disableOutsidePointerEvents={disableOutsidePointerEvents}
                onEscapeKeyDown={onEscapeKeyDown}
                onPointerDownOutside={(event) => {
                  setSkipUnmountAutoFocus(!disableOutsidePointerEvents);
                  if (event.target === openButtonRef.current) {
                    event.preventDefault();
                  } else {
                    onPointerDownOutside?.(event);
                  }
                }}
                onFocusOutside={onFocusOutside}
                onInteractOutside={onInteractOutside}
                onDismiss={() => setOpen(false)}
              >
                <FocusScope
                  asChild
                  trapped={trapped}
                  onUnmountAutoFocus={(event) => {
                    if (skipUnmountAutoFocus) {
                      event.preventDefault();
                    }
                    setSkipUnmountAutoFocus(false);
                  }}
                >
                  <Popper.Content
                    style={{
                      filter: 'drop-shadow(0 2px 10px rgba(0, 0, 0, 0.12))',
                      display: 'flex',
                      alignItems: 'flex-start',
                      gap: 10,
                      background: 'white',
                      minWidth: 200,
                      minHeight: 150,
                      padding: 20,
                      borderRadius: 4,
                      backgroundColor: color,
                    }}
                    side="bottom"
                    sideOffset={10}
                  >
                    {children}
                    <button type="button" onClick={() => setOpen(false)}>
                      {closeLabel}
                    </button>
                    <input type="text" defaultValue="hello world" />
                    <Popper.Arrow width={10} height={4} style={{ fill: color }} offset={20} />
                  </Popper.Content>
                </FocusScope>
              </DismissableLayer>
            </Portal.Root>
          </ScrollContainer>
        </FocusGuards.Root>
      ) : null}
    </Popper.Root>
  );
}

export const InPopupWindow = () => {
  const handlePopupClick = React.useCallback(() => {
    const popupWindow = window.open(undefined, undefined, 'width=300,height=300,top=100,left=100');
    if (!popupWindow) {
      console.error('Failed to open popup window, check your popup blocker settings');
      return;
    }

    const containerNode = popupWindow.document.createElement('div');
    popupWindow.document.body.append(containerNode);

    ReactDOM.createRoot(containerNode).render(<DismissableBox />);
  }, []);
  return (
    <div style={{ fontFamily: 'sans-serif', textAlign: 'center' }}>
      <button onClick={handlePopupClick}>Open Popup</button>
    </div>
  );
};



================================================
FILE: apps/storybook/stories/dropdown-menu.stories.module.css
================================================
.trigger {
  border: 1px solid $black;
  border-radius: 6px;
  background-color: transparent;
  padding: 5px 10px;
  font-family: apple-system, BlinkMacSystemFont, helvetica, arial, sans-serif;
  font-size: 13px;

  &:focus {
    outline: none;
    box-shadow: 0 0 0 2px rgb(0 0 0 / 0.5);
  }
}

.content {
  display: inline-block;
  box-sizing: border-box;
  min-width: 130px;
  background-color: var(--color-white);
  border: 1px solid var(--color-gray100);
  border-radius: 6px;
  padding: 5px;
  box-shadow: 0 5px 10px 0 rgba(0, 0, 0, 0.1);
  font-family: apple-system, BlinkMacSystemFont, helvetica, arial, sans-serif;
  font-size: 13px;
  &:focus-within {
    border-color: var(--color-black);
  }
}

.label,
.item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  line-height: 1;
  cursor: default;
  user-select: none;
  white-space: nowrap;
  height: 25px;
  padding: 0 10px;
  color: var(--color-black);
  border-radius: 3px;
}

.label {
  color: var(--color-gray100);
}

.item {
  outline: none;

  &[data-highlighted] {
    background-color: var(--color-black);
    color: var(--color-white);
  }

  &[data-disabled] {
    color: var(--color-gray100);
  }
}

.subTrigger {
  &:not([data-highlighted])[data-state='open'] {
    background-color: var(--color-gray100);
    color: var(--color-black);
  }
}

.separator {
  height: 1;
  margin: 5px 10px;
  background-color: var(--color-gray100);
}

@keyframes dropdownMenu-animateIn {
  from {
    transform: scale(0.95);
    opacity: 0;
  }
  to {
    transform: scale(1);
    opacity: 1;
  }
}

@keyframes dropdownMenu-animateOut {
  from {
    transform: scale(1);
    opacity: 1;
  }
  to {
    transform: scale(0.95);
    opacity: 0;
  }
}

.animatedContent {
  &[data-state='open'] {
    animation: dropdownMenu-animateIn 300ms ease;
  }
  &[data-state='closed'] {
    animation: dropdownMenu-animateOut 300ms ease;
  }
}

.animatedItemIndicator {
  &[data-state='checked'] {
    animation: dropdownMenu-animateIn 300ms ease;
  }
  &[data-state='unchecked'] {
    animation: dropdownMenu-animateOut 300ms ease;
  }
}

.grid {
  display: inline-grid;
  grid-template-columns: repeat(3, 50px);
  column-gap: 150px;
  row-gap: 100px;
  padding: 100px;
  border: 1px solid var(--color-black);
}

.dialog {
  position: fixed;
  background: white;
  border: 1px solid black;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  padding: 30px;
}

.chromaticTrigger {
  width: 30px;
  height: 30px;
  background-color: tomato;
  border: 1px solid rgba(0, 0, 0, 0.3);
}
.chromaticContent {
  display: grid;
  place-content: center;
  width: 60px;
  height: 60px;
  background-color: royalblue;
  color: var(--color-white);
  font-size: 10px;
  border: 1px solid rgb(0 0 0 / 0.3);
}

.chromaticArrow {
  fill: var(--color-black);
}

.triggerAttr,
.contentAttr,
.itemAttr,
.itemIndicatorAttr,
.checkboxItemAttr,
.radioGroupAttr,
.radioItemAttr,
.separatorAttr,
.arrowAttr {
  background-color: rgb(0 0 255 / 0.3);
  border: 2px solid blue;
  padding: 10px;

  & [data-disabled] {
    border-style: dashed;
  }

  &[data-state='closed'] {
    border-color: red;
  }
  &[data-state='open'] {
    border-color: green;
  }
}



================================================
FILE: apps/storybook/stories/focus-scope.stories.tsx
================================================
import React from 'react';
import { FocusScope } from 'radix-ui/internal';

export default { title: 'Utilities/FocusScope' };

export const Basic = () => {
  const [trapped, setTrapped] = React.useState(false);
  const [hasDestroyButton, setHasDestroyButton] = React.useState(true);

  return (
    <>
      <div>
        <button type="button" onClick={() => setTrapped(true)}>
          Trap
        </button>{' '}
        <input /> <input />
      </div>
      {trapped ? (
        <FocusScope.Root asChild loop={trapped} trapped={trapped}>
          <form
            style={{
              display: 'inline-flex',
              flexDirection: 'column',
              gap: 20,
              padding: 20,
              margin: 50,
              maxWidth: 500,
              border: '2px solid',
            }}
          >
            <input type="text" placeholder="First name" />
            <input type="text" placeholder="Last name" />
            <input type="number" placeholder="Age" />
            {hasDestroyButton && (
              <div>
                <button type="button" onClick={() => setHasDestroyButton(false)}>
                  Destroy me
                </button>
              </div>
            )}
            <button type="button" onClick={() => setTrapped(false)}>
              Close
            </button>
          </form>
        </FocusScope.Root>
      ) : null}
      <div>
        <input /> <input />
      </div>
    </>
  );
};

export const Multiple = () => {
  const [trapped1, setTrapped1] = React.useState(false);
  const [trapped2, setTrapped2] = React.useState(false);

  return (
    <div style={{ display: 'inline-flex', flexDirection: 'column', gap: 10 }}>
      <div>
        <button type="button" onClick={() => setTrapped1(true)}>
          Trap 1
        </button>
      </div>
      {trapped1 ? (
        <FocusScope.Root asChild loop={trapped1} trapped={trapped1}>
          <form
            style={{
              display: 'inline-flex',
              flexDirection: 'column',
              gap: 20,
              padding: 20,
              maxWidth: 500,
              border: '2px solid',
            }}
          >
            <h1>One</h1>
            <input type="text" placeholder="First name" />
            <input type="text" placeholder="Last name" />
            <input type="number" placeholder="Age" />
            <button type="button" onClick={() => setTrapped1(false)}>
              Close
            </button>
          </form>
        </FocusScope.Root>
      ) : null}

      <div>
        <button type="button" onClick={() => setTrapped2(true)}>
          Trap 2
        </button>
      </div>
      {trapped2 ? (
        <FocusScope.Root asChild loop={trapped2} trapped={trapped2}>
          <form
            style={{
              display: 'inline-flex',
              flexDirection: 'column',
              gap: 20,
              padding: 20,
              maxWidth: 500,
              border: '2px solid',
            }}
          >
            <h1>Two</h1>
            <input type="text" placeholder="First name" />
            <input type="text" placeholder="Last name" />
            <input type="number" placeholder="Age" />
            <button type="button" onClick={() => setTrapped2(false)}>
              Close
            </button>
          </form>
        </FocusScope.Root>
      ) : null}
      <div>
        <input />
      </div>
    </div>
  );
};

// true => default focus, false => no focus, ref => focus element
type FocusParam = boolean | React.RefObject<HTMLElement | null>;

export const WithOptions = () => {
  const [open, setOpen] = React.useState(false);
  const [isEmptyForm, setIsEmptyForm] = React.useState(false);

  const [trapFocus, setTrapFocus] = React.useState(false);
  const [focusOnMount, setFocusOnMount] = React.useState<FocusParam>(false);
  const [focusOnUnmount, setFocusOnUnmount] = React.useState<FocusParam>(false);

  const ageFieldRef = React.useRef<HTMLInputElement>(null);
  const nextButtonRef = React.useRef<HTMLButtonElement>(null);

  return (
    <div style={{ fontFamily: 'sans-serif', textAlign: 'center' }}>
      <h1>FocusScope</h1>

      <div style={{ display: 'inline-block', textAlign: 'left', marginBottom: 20 }}>
        <label style={{ display: 'block' }}>
          <input
            type="checkbox"
            checked={trapFocus}
            onChange={(event) => setTrapFocus(event.target.checked)}
          />{' '}
          Trap focus?
        </label>
        <label style={{ display: 'block' }}>
          <input
            type="checkbox"
            checked={focusOnMount !== false}
            onChange={(event) => {
              setFocusOnMount(event.target.checked);
              if (event.target.checked === false) {
                setIsEmptyForm(false);
              }
            }}
          />{' '}
          Focus on mount?
        </label>
        {focusOnMount !== false && !isEmptyForm && (
          <label style={{ display: 'block', marginLeft: 20 }}>
            <input
              type="checkbox"
              checked={focusOnMount !== true}
              onChange={(event) => setFocusOnMount(event.target.checked ? ageFieldRef : true)}
            />{' '}
            on "age" field?
          </label>
        )}
        {focusOnMount !== false && (
          <label style={{ display: 'block', marginLeft: 20 }}>
            <input
              type="checkbox"
              checked={isEmptyForm}
              onChange={(event) => {
                setIsEmptyForm(event.target.checked);
                setFocusOnMount(true);
              }}
            />{' '}
            empty form?
          </label>
        )}
        <label style={{ display: 'block' }}>
          <input
            type="checkbox"
            checked={focusOnUnmount !== false}
            onChange={(event) => setFocusOnUnmount(event.target.checked)}
          />{' '}
          Focus on unmount?
        </label>
        {focusOnUnmount !== false && (
          <label style={{ display: 'block', marginLeft: 20 }}>
            <input
              type="checkbox"
              checked={focusOnUnmount !== true}
              onChange={(event) => setFocusOnUnmount(event.target.checked ? nextButtonRef : true)}
            />{' '}
            on "next" button?
          </label>
        )}
      </div>

      <div style={{ marginBottom: 20 }}>
        <button type="button" onClick={() => setOpen((open) => !open)}>
          {open ? 'Close' : 'Open'} form in between buttons
        </button>
      </div>

      <button type="button" style={{ marginRight: 10 }}>
        previous
      </button>

      {open ? (
        <FocusScope.Root
          key="form"
          asChild
          loop={trapFocus}
          trapped={trapFocus}
          onMountAutoFocus={(event) => {
            if (focusOnMount !== true) {
              event.preventDefault();
              if (focusOnMount) focusOnMount.current?.focus();
            }
          }}
          onUnmountAutoFocus={(event) => {
            if (focusOnUnmount !== true) {
              event.preventDefault();
              if (focusOnUnmount) focusOnUnmount.current?.focus();
            }
          }}
        >
          <form
            style={{
              display: 'inline-flex',
              flexDirection: 'column',
              gap: 20,
              padding: 20,
              margin: 50,
              maxWidth: 500,
              border: '2px solid',
            }}
          >
            {!isEmptyForm && (
              <>
                <input type="text" placeholder="First name" />
                <input type="text" placeholder="Last name" />
                <input ref={ageFieldRef} type="number" placeholder="Age" />
                <button type="button" onClick={() => setOpen(false)}>
                  Close
                </button>
              </>
            )}
          </form>
        </FocusScope.Root>
      ) : null}

      <button ref={nextButtonRef} type="button" style={{ marginLeft: 10 }}>
        next
      </button>
    </div>
  );
};



================================================
FILE: apps/storybook/stories/form.stories.module.css
================================================
.form {
  & [data-invalid] {
    color: var(--red-9);
    outline-color: currentColor;
  }
  & [data-valid] {
    color: var(--green-9);
    outline-color: currentColor;
  }
}



================================================
FILE: apps/storybook/stories/form.stories.tsx
================================================
import * as React from 'react';
import { Form } from 'radix-ui';
import styles from './form.stories.module.css';

export default { title: 'Components/Form' };

export const Basic = () => {
  const [loading, setLoading] = React.useState(false);
  const [serverErrors, setServerErrors] = React.useState<{ email?: boolean; password?: boolean }>(
    {},
  );

  return (
    <>
      <Form.Root
        className={styles.form}
        onClearServerErrors={() => setServerErrors({})}
        onSubmit={async (event) => {
          const form = event.currentTarget;
          event.preventDefault();

          const formData = new FormData(form);

          setLoading(true);
          await wait(500);
          setLoading(false);

          const errors = new Set();
          if (!(formData.get('email') as string).includes('@gmail.com')) errors.add('email');
          if (!(formData.get('password') as string).includes('#')) errors.add('password');

          if (errors.size > 0) {
            setServerErrors(Object.fromEntries([...errors].map((name) => [name, true])));
            return;
          }

          window.alert(JSON.stringify(Object.fromEntries(formData), null, 2));
        }}
      >
        <Form.Field name="email" serverInvalid={serverErrors.email}>
          <Form.Label>Email</Form.Label>
          <Form.Control
            type="email"
            required
            onChange={() => setServerErrors((prev) => ({ ...prev, email: false }))}
          />
          <Form.Message match="valueMissing" />
          <Form.Message match="typeMismatch" forceMatch={serverErrors.email}>
            Email is invalid
          </Form.Message>
        </Form.Field>

        <Form.Field name="password" serverInvalid={serverErrors.password}>
          <Form.Label>Password</Form.Label>
          <Form.Control
            type="password"
            required
            onChange={() => setServerErrors((prev) => ({ ...prev, password: false }))}
          />
          <Form.Message match="valueMissing">Password is required</Form.Message>
          <Form.Message
            match={(value) => value.match(/.*[0-9]+.*/) === null}
            forceMatch={serverErrors.password}
          >
            Password is not complex enough
          </Form.Message>
          {serverErrors.password && <Form.Message>Woops</Form.Message>}
        </Form.Field>

        <Form.Submit disabled={loading}>Submit</Form.Submit>
        <button type="reset">Reset</button>
      </Form.Root>
    </>
  );
};

export const Cypress = () => {
  const [data, setData] = React.useState({});
  const [simulateServerErrors, setSimulateServerErrors] = React.useState(false);
  const [serverErrors, setServerErrors] = React.useState<{
    email?: boolean;
    pin?: boolean;
    global?: boolean;
  }>({});

  return (
    <>
      <Form.Root
        className={styles.form}
        onClearServerErrors={() => setServerErrors({})}
        onSubmit={async (event) => {
          event.preventDefault();

          setData({});

          const data = Object.fromEntries(new FormData(event.currentTarget));

          if (simulateServerErrors) {
            await wait(100);
            setServerErrors({ email: !data.email, pin: String(data.pin)[3] !== '9', global: true });
          }

          setData(data);
        }}
        onReset={() => setData({})}
      >
        <Form.Field name="name">
          <Form.Label>Name (required)</Form.Label>
          <Form.Control type="text" required />
          <Form.Message match="valueMissing" />
          <Form.Message match="valid">valid!</Form.Message>
        </Form.Field>

        <Form.Field name="age">
          <Form.Label>Age (0-99)</Form.Label>
          <Form.Control type="number" min="0" max="99" step="1" />
          <Form.Message match="rangeOverflow" />
          <Form.Message match="rangeUnderflow" />
          <Form.Message match="stepMismatch" />
        </Form.Field>

        <Form.Field name="email" serverInvalid={serverErrors.email}>
          <Form.Label>Email</Form.Label>
          <Form.Control type="email" />
          <Form.Message match="typeMismatch" />
          {serverErrors.email ? (
            <Form.Message>Email is actually required server side!</Form.Message>
          ) : null}
        </Form.Field>

        <Form.Field name="password">
          <Form.Label>Password</Form.Label>
          <Form.Control type="password" minLength={8} maxLength={16} />
          <Form.Message match="tooShort" />
          <Form.Message match="tooLong" />
        </Form.Field>

        <Form.Field name="pin" serverInvalid={serverErrors.pin}>
          <Form.Label>Pin (4 digits)</Form.Label>
          <Form.Control type="text" pattern="\d{4,4}" />
          <Form.Message match="patternMismatch" forceMatch={serverErrors.pin} />
        </Form.Field>

        <Form.Field name="secret">
          <Form.Label>Secret 1</Form.Label>
          <Form.Control type="text" />
          <Form.Message match={(value) => value !== 'shush'} />
        </Form.Field>

        <Form.Field name="asyncSecret">
          <Form.Label>Secret 2</Form.Label>
          <Form.Control type="text" />
          <Form.Message
            match={async (value) => {
              await wait(100);
              return value !== 'shush';
            }}
          />
        </Form.Field>

        <Form.Field name="country">
          <Form.Label htmlFor="my-country">Country</Form.Label>
          <Form.Control id="my-country" type="text" pattern="France|Spain" />
          <Form.Message match="patternMismatch">Country should be "France" or "Spain"</Form.Message>
        </Form.Field>

        <Form.Submit>submit</Form.Submit>
        <button type="reset">reset</button>
      </Form.Root>
      <pre>Data: {JSON.stringify(data, null, 2)}</pre>

      <label>
        <input
          type="checkbox"
          checked={simulateServerErrors}
          onChange={(event) => setSimulateServerErrors(event.target.checked)}
        />{' '}
        Simulate server errors?
      </label>
    </>
  );
};

async function wait(ms: number) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}



================================================
FILE: apps/storybook/stories/hover-card.stories.module.css
================================================
.content {
  transform-origin: var(--radix-hover-card-content-transform-origin);
  /* ----- */
  background-color: var(--color-gray300);
  padding: 20px;
  border-radius: 5px;
}

.arrow {
  fill: var(--color-gray300);
}

@keyframes hoverCard-fadeIn {
  from {
    transform: scale(0.9);
    opacity: 0;
  }
  to {
    transform: scale(1);
    opacity: 1;
  }
}

@keyframes hoverCard-fadeOut {
  from {
    transform: scale(1);
    opacity: 1;
  }
  to {
    transform: scale(0.9);
    opacity: 0;
  }
}

.animatedContent {
  &[data-state='open'] {
    animation: hoverCard-fadeIn 250ms ease;
  }
  &[data-state='closed'] {
    animation: hoverCard-fadeOut 250ms ease;
  }
}

.grid {
  display: inline-grid;
  grid-template-columns: repeat(3, 50px);
  column-gap: 150px;
  row-gap: 100px;
  padding: 100px;
  border: 1px solid black;
}

.contentAttr,
.arrowAttr,
.triggerAttr {
  background-color: rgb(0 0 255 / 0.3);
  border: 2px solid blue;
  padding: 10px;

  &[data-state='closed'] {
    border-color: red;
  }
  &[data-state='open'] {
    border-color: green;
  }
}

.chromaticArrow {
  fill: black;
}

.chromaticContent,
.contentAttr {
  display: grid;
  place-content: center;
  width: 60px;
  height: 60px;
  background-color: royalblue;
  color: white;
  font-size: 10px;
  border: 1px solid rgb(0 0 0 / 0.3);
}

.chromaticTrigger {
  width: 30px;
  height: 30px;
  background-color: tomato;
  border: 1px solid rgb(0 0 0 / 0.3);
}



================================================
FILE: apps/storybook/stories/hover-card.stories.tsx
================================================
import * as React from 'react';
import { Dialog, HoverCard } from 'radix-ui';
import { Popper } from 'radix-ui/internal';
import styles from './hover-card.stories.module.css';

const { SIDE_OPTIONS, ALIGN_OPTIONS } = Popper;

export default { title: 'Components/HoverCard' };

const contentClass = ({ animated }: { animated?: boolean }) =>
  [
    styles.content, ///
    animated && styles.animatedContent,
  ]
    .filter(Boolean)
    .join(' ');

export const Basic = () => {
  return (
    <div style={{ padding: 50, display: 'flex', justifyContent: 'center' }}>
      <HoverCard.Root>
        <HoverCard.Trigger href="/" className={styles.trigger}>
          trigger
        </HoverCard.Trigger>
        <HoverCard.Portal>
          <HoverCard.Content className={styles.content} sideOffset={5}>
            <HoverCard.Arrow className={styles.arrow} width={20} height={10} />
            <CardContentPlaceholder />
          </HoverCard.Content>
        </HoverCard.Portal>
      </HoverCard.Root>
    </div>
  );
};

export const ContainTextSelection = () => {
  return (
    <div
      style={{
        padding: 50,
        display: 'flex',
        justifyContent: 'center',
        flexDirection: 'column',
        alignItems: 'center',
      }}
    >
      <div style={{ display: 'flex', gap: 30 }}>
        <HoverCard.Root>
          <HoverCard.Trigger href="/" className={styles.trigger}>
            single
          </HoverCard.Trigger>
          <HoverCard.Portal>
            <HoverCard.Content className={contentClass({ animated: true })} sideOffset={5}>
              <HoverCard.Arrow className={styles.arrow} width={20} height={10} />
              <div style={{ maxWidth: 400 }}>
                Text selections will be contained within the content. While a selection is active
                the content will not dismiss unless the selection is cleared or an outside
                interaction is performed.
              </div>
            </HoverCard.Content>
          </HoverCard.Portal>
        </HoverCard.Root>

        <HoverCard.Root>
          <HoverCard.Trigger href="/" className={styles.trigger}>
            nested
          </HoverCard.Trigger>
          <HoverCard.Portal>
            <HoverCard.Content className={contentClass({ animated: true })} sideOffset={5}>
              <HoverCard.Arrow className={styles.arrow} width={20} height={10} />
              <div style={{ maxWidth: 400 }}>
                Text selections will be contained within the content. While a selection is active
                the content will not dismiss unless the selection is cleared or an outside
                interaction is performed.
              </div>

              <HoverCard.Root>
                <HoverCard.Trigger href="/" className={styles.trigger}>
                  nested trigger
                </HoverCard.Trigger>
                <HoverCard.Portal>
                  <HoverCard.Content
                    className={contentClass({ animated: true })}
                    sideOffset={5}
                    style={{ backgroundColor: 'crimson' }}
                  >
                    <HoverCard.Arrow
                      className={styles.arrow}
                      width={20}
                      height={10}
                      style={{ fill: 'crimson' }}
                    />
                    <div style={{ maxWidth: 400 }}>
                      Text selections will be contained within the content. While a selection is
                      active the content will not dismiss unless the selection is cleared or an
                      outside interaction is performed.
                    </div>

                    <HoverCard.Root>
                      <HoverCard.Trigger href="/" className={styles.trigger}>
                        nested trigger
                      </HoverCard.Trigger>
                      <HoverCard.Portal>
                        <HoverCard.Content
                          className={contentClass({ animated: true })}
                          sideOffset={5}
                          style={{ backgroundColor: 'green' }}
                        >
                          <HoverCard.Arrow
                            className={styles.arrow}
                            width={20}
                            height={10}
                            style={{ fill: 'green' }}
                          />
                          <div style={{ maxWidth: 400 }}>
                            Text selections will be contained within the content. While a selection
                            is active the content will not dismiss unless the selection is cleared
                            or an outside interaction is performed.
                          </div>
                        </HoverCard.Content>
                      </HoverCard.Portal>
                    </HoverCard.Root>
                  </HoverCard.Content>
                </HoverCard.Portal>
              </HoverCard.Root>
            </HoverCard.Content>
          </HoverCard.Portal>
        </HoverCard.Root>
      </div>
      <div style={{ maxWidth: 800 }}>
        <p>
          Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer feugiat mattis malesuada.
          Fusce elementum vulputate aliquet. Integer fringilla porta eros. Ut ultricies mattis nisi.
          Sed et tempor massa. Sed non arcu ut velit scelerisque bibendum tempor sed mi. In non
          consequat sapien. Donec sollicitudin eget tellus ut venenatis. Donec posuere sem ante, nec
          iaculis arcu varius sit amet. Praesent non tortor quam. Curabitur dapibus justo a commodo
          ornare.
        </p>
        <p>
          Suspendisse eleifend consequat iaculis. Nunc bibendum velit felis, nec vulputate purus
          egestas quis. Integer mauris dui, pulvinar non metus id, tristique dignissim elit. Vivamus
          massa tellus, porttitor id lorem non, molestie aliquam dolor. Pellentesque erat quam,
          pellentesque non metus id, tempus sagittis massa.
        </p>
        <p>
          Sed at elementum sem, non venenatis leo. Ut vulputate consectetur finibus. Sed nunc
          lectus, accumsan in nisl et, vehicula pretium nisi. Vivamus vestibulum ante quis urna
          consequat, ultrices condimentum sem commodo. Pellentesque eget orci laoreet, feugiat purus
          sed, maximus nisi. Suspendisse commodo venenatis facilisis.
        </p>
      </div>
    </div>
  );
};

export const AsyncUpdate = () => {
  const [open, setOpen] = React.useState(false);
  const [contentLoaded, setContentLoaded] = React.useState(false);
  const timerRef = React.useRef(0);

  const handleOpenChange = React.useCallback((open: boolean) => {
    clearTimeout(timerRef.current);

    if (open) {
      timerRef.current = window.setTimeout(() => {
        setContentLoaded(true);
      }, 500);
    } else {
      setContentLoaded(false);
    }

    setOpen(open);
  }, []);

  React.useEffect(() => {
    return () => {
      clearTimeout(timerRef.current);
    };
  }, []);

  return (
    <div style={{ padding: 50, display: 'flex', justifyContent: 'center' }}>
      <HoverCard.Root open={open} onOpenChange={handleOpenChange}>
        <HoverCard.Trigger href="/" className={styles.trigger}>
          trigger
        </HoverCard.Trigger>
        <HoverCard.Portal>
          <HoverCard.Content className={styles.content} sideOffset={5}>
            <HoverCard.Arrow className={styles.arrow} width={20} height={10} />
            {contentLoaded ? <CardContentPlaceholder /> : 'Loading...'}
          </HoverCard.Content>
        </HoverCard.Portal>
      </HoverCard.Root>
    </div>
  );
};

export const CustomDurations = () => (
  <div>
    <h1>Delay duration</h1>
    <h2>Default (700ms open, 300ms close)</h2>

    <HoverCard.Root>
      <HoverCard.Trigger href="/" className={styles.trigger}>
        trigger
      </HoverCard.Trigger>
      <HoverCard.Portal>
        <HoverCard.Content className={styles.content}>
          <CardContentPlaceholder />
        </HoverCard.Content>
      </HoverCard.Portal>
    </HoverCard.Root>

    <h2>Custom (instant, 0ms open, 0ms close)</h2>
    <HoverCard.Root openDelay={0} closeDelay={0}>
      <HoverCard.Trigger href="/" className={styles.trigger}>
        trigger
      </HoverCard.Trigger>
      <HoverCard.Portal>
        <HoverCard.Content className={styles.content}>
          <CardContentPlaceholder />
        </HoverCard.Content>
      </HoverCard.Portal>
    </HoverCard.Root>

    <h2>Custom (300ms open, 100ms close)</h2>

    <HoverCard.Root openDelay={300} closeDelay={100}>
      <HoverCard.Trigger href="/" className={styles.trigger}>
        trigger
      </HoverCard.Trigger>
      <HoverCard.Portal>
        <HoverCard.Content className={styles.content}>
          <CardContentPlaceholder />
        </HoverCard.Content>
      </HoverCard.Portal>
    </HoverCard.Root>
  </div>
);

export const Controlled = () => {
  const [open, setOpen] = React.useState(false);

  return (
    <div style={{ padding: 50, display: 'flex', justifyContent: 'center' }}>
      <HoverCard.Root open={open} onOpenChange={setOpen}>
        <HoverCard.Trigger href="/" className={styles.trigger}>
          trigger
        </HoverCard.Trigger>
        <HoverCard.Portal>
          <HoverCard.Content className={styles.content}>
            <HoverCard.Arrow className={styles.arrow} width={20} height={10} />
            <CardContentPlaceholder />
          </HoverCard.Content>
        </HoverCard.Portal>
      </HoverCard.Root>
    </div>
  );
};

export const Layerable = () => (
  <div style={{ padding: 50, display: 'flex', justifyContent: 'center' }}>
    <Dialog.Root>
      <Dialog.Trigger>Open</Dialog.Trigger>
      <Dialog.Content
        style={{
          position: 'fixed',
          top: '50%',
          left: '50%',
          transform: 'translate(-50%, -50%)',
          background: 'white',
          border: '1px solid',
          borderRadius: 4,
          padding: 20,
        }}
      >
        <Dialog.Title>Some dialog title</Dialog.Title>
        Some dialog content with a{' '}
        <HoverCard.Root>
          <HoverCard.Trigger href="/" className={styles.trigger}>
            trigger
          </HoverCard.Trigger>
          <HoverCard.Portal>
            <HoverCard.Content className={styles.content} sideOffset={5}>
              <HoverCard.Arrow className={styles.arrow} width={20} height={10} />
              <CardContentPlaceholder />
            </HoverCard.Content>
          </HoverCard.Portal>
        </HoverCard.Root>{' '}
        <Dialog.Close>Close</Dialog.Close>
      </Dialog.Content>
    </Dialog.Root>
  </div>
);

export const Animated = () => {
  return (
    <div style={{ padding: 50, display: 'flex', justifyContent: 'center' }}>
      <HoverCard.Root>
        <HoverCard.Trigger href="/" className={styles.trigger}>
          trigger
        </HoverCard.Trigger>
        <HoverCard.Portal>
          <HoverCard.Content className={contentClass({ animated: true })} sideOffset={10}>
            <HoverCard.Arrow className={styles.arrow} width={20} height={10} />
            <CardContentPlaceholder />
          </HoverCard.Content>
        </HoverCard.Portal>
      </HoverCard.Root>
    </div>
  );
};

export const ForcedMount = () => {
  return (
    <div style={{ padding: 50, display: 'flex', justifyContent: 'center' }}>
      <HoverCard.Root>
        <HoverCard.Trigger href="/" className={styles.trigger}>
          trigger
        </HoverCard.Trigger>
        <HoverCard.Portal forceMount>
          <HoverCard.Content className={styles.content} sideOffset={10}>
            <HoverCard.Arrow className={styles.arrow} width={20} height={10} />
            <CardContentPlaceholder />
          </HoverCard.Content>
        </HoverCard.Portal>
      </HoverCard.Root>
    </div>
  );
};

export const Nested = () => {
  return (
    <HoverCard.Root>
      <HoverCard.Trigger href="/" className={styles.trigger}>
        trigger level 1
      </HoverCard.Trigger>

      <HoverCard.Portal>
        <HoverCard.Content
          className={styles.content}
          sideOffset={5}
          style={{ backgroundColor: 'crimson' }}
        >
          <HoverCard.Root>
            <HoverCard.Trigger href="/" className={styles.trigger}>
              trigger level 2
            </HoverCard.Trigger>
            <HoverCard.Portal>
              <HoverCard.Content
                className={styles.content}
                side="top"
                align="center"
                sideOffset={5}
                style={{ backgroundColor: 'green' }}
              >
                <HoverCard.Arrow
                  className={styles.arrow}
                  width={20}
                  height={10}
                  offset={20}
                  style={{ fill: 'green' }}
                />
                <HoverCard.Root>
                  <HoverCard.Trigger href="/" className={styles.trigger}>
                    trigger level 3
                  </HoverCard.Trigger>
                  <HoverCard.Portal>
                    <HoverCard.Content
                      className={styles.content}
                      side="bottom"
                      align="start"
                      sideOffset={5}
                      style={{ backgroundColor: 'purple' }}
                    >
                      <HoverCard.Arrow
                        className={styles.arrow}
                        width={20}
                        height={10}
                        offset={20}
                        style={{ fill: 'purple' }}
                      />
                      level 3
                    </HoverCard.Content>
                  </HoverCard.Portal>
                </HoverCard.Root>
              </HoverCard.Content>
            </HoverCard.Portal>
          </HoverCard.Root>

          <HoverCard.Arrow
            className={styles.arrow}
            width={20}
            height={10}
            offset={20}
            style={{ fill: 'crimson' }}
          />
        </HoverCard.Content>
      </HoverCard.Portal>
    </HoverCard.Root>
  );
};

export const NonPortal = () => {
  return (
    <div>
      <button>button</button>
      <HoverCard.Root>
        <HoverCard.Trigger href="/" className={styles.trigger}>
          trigger
        </HoverCard.Trigger>
        <HoverCard.Content className={styles.content} sideOffset={5}>
          <HoverCard.Arrow className={styles.arrow} width={20} height={10} offset={10} />
          <a href="#link">Should not be able to focus me</a>
          <CardContentPlaceholder />
        </HoverCard.Content>
      </HoverCard.Root>
      <button>button</button>
    </div>
  );
};

export const WithSlottedTrigger = () => {
  return (
    <HoverCard.Root>
      <HoverCard.Trigger asChild>
        <button className={styles.trigger} onClick={() => console.log('StyledTrigger click')}>
          trigger
        </button>
      </HoverCard.Trigger>
      <HoverCard.Portal>
        <HoverCard.Content className={styles.content} sideOffset={5}>
          <HoverCard.Arrow className={styles.arrow} width={20} height={10} offset={10} />
          <CardContentPlaceholder />
        </HoverCard.Content>
      </HoverCard.Portal>
    </HoverCard.Root>
  );
};

export const WithSlottedContent = () => (
  <HoverCard.Root>
    <HoverCard.Trigger href="/" className={styles.trigger}>
      trigger
    </HoverCard.Trigger>
    <HoverCard.Portal>
      <HoverCard.Content asChild sideOffset={5}>
        <div className={styles.content}>
          <HoverCard.Arrow className={styles.arrow} width={20} height={10} offset={10} />
          <CardContentPlaceholder />
        </div>
      </HoverCard.Content>
    </HoverCard.Portal>
  </HoverCard.Root>
);

// change order slightly for more pleasing visual
const SIDES = [...SIDE_OPTIONS.filter((side) => side !== 'bottom'), 'bottom' as const];

export const Chromatic = () => (
  <div style={{ padding: 200, paddingBottom: 500 }}>
    <h1>Uncontrolled</h1>
    <h2>Closed</h2>
    <HoverCard.Root>
      <HoverCard.Trigger className={styles.trigger}>open</HoverCard.Trigger>
      <HoverCard.Portal>
        <HoverCard.Content className={styles.content} sideOffset={5}>
          <HoverCard.Arrow className={styles.arrow} width={20} height={10} />
          Some content
        </HoverCard.Content>
      </HoverCard.Portal>
    </HoverCard.Root>

    <h2>Open</h2>
    <HoverCard.Root defaultOpen>
      <HoverCard.Trigger className={styles.trigger}>open</HoverCard.Trigger>
      <HoverCard.Portal>
        <HoverCard.Content className={styles.content} sideOffset={5}>
          <HoverCard.Arrow className={styles.arrow} width={20} height={10} />
          Some content
        </HoverCard.Content>
      </HoverCard.Portal>
    </HoverCard.Root>

    <h2 style={{ marginTop: 60 }}>Open with reordered parts</h2>
    <HoverCard.Root defaultOpen>
      <HoverCard.Portal>
        <HoverCard.Content className={styles.content} sideOffset={5}>
          Some content
          <HoverCard.Arrow className={styles.arrow} offset={10} />
        </HoverCard.Content>
      </HoverCard.Portal>
      <HoverCard.Trigger className={styles.trigger}>open</HoverCard.Trigger>
    </HoverCard.Root>

    <h1 style={{ marginTop: 100 }}>Controlled</h1>
    <h2>Closed</h2>
    <HoverCard.Root open={false}>
      <HoverCard.Trigger className={styles.trigger}>open</HoverCard.Trigger>
      <HoverCard.Portal>
        <HoverCard.Content className={styles.content} sideOffset={5}>
          <HoverCard.Arrow className={styles.arrow} width={20} height={10} />
          Some content
        </HoverCard.Content>
      </HoverCard.Portal>
    </HoverCard.Root>

    <h2>Open</h2>
    <HoverCard.Root open>
      <HoverCard.Trigger className={styles.trigger}>open</HoverCard.Trigger>
      <HoverCard.Portal>
        <HoverCard.Content className={styles.content} sideOffset={5}>
          <HoverCard.Arrow className={styles.arrow} width={20} height={10} />
          Some content
        </HoverCard.Content>
      </HoverCard.Portal>
    </HoverCard.Root>

    <h2 style={{ marginTop: 60 }}>Open with reordered parts</h2>
    <HoverCard.Root open>
      <HoverCard.Portal>
        <HoverCard.Content className={styles.content} sideOffset={5}>
          Some content
          <HoverCard.Arrow className={styles.arrow} offset={10} />
        </HoverCard.Content>
      </HoverCard.Portal>
      <HoverCard.Trigger className={styles.trigger}>open</HoverCard.Trigger>
    </HoverCard.Root>

    <h1 style={{ marginTop: 100 }}>Force mounted content</h1>
    <HoverCard.Root>
      <HoverCard.Trigger className={styles.trigger}>open</HoverCard.Trigger>
      <HoverCard.Portal forceMount>
        <HoverCard.Content className={styles.content} sideOffset={5}>
          <HoverCard.Arrow className={styles.arrow} width={20} height={10} />
          Some content
        </HoverCard.Content>
      </HoverCard.Portal>
    </HoverCard.Root>

    <h1 style={{ marginTop: 100 }}>Positioning</h1>
    <h2>No collisions</h2>
    <h3>Side & Align</h3>
    <div className={styles.grid}>
      {SIDES.map((side) =>
        ALIGN_OPTIONS.map((align) => (
          <HoverCard.Root key={`${side}-${align}`} open>
            <HoverCard.Trigger className={styles.chromaticTrigger} />
            <HoverCard.Portal>
              <HoverCard.Content
                className={styles.chromaticContent}
                side={side}
                align={align}
                avoidCollisions={false}
              >
                <p style={{ textAlign: 'center' }}>
                  {side}
                  <br />
                  {align}
                </p>
                <HoverCard.Arrow className={styles.chromaticArrow} width={20} height={10} />
              </HoverCard.Content>
            </HoverCard.Portal>
          </HoverCard.Root>
        )),
      )}
    </div>

    <h3>Side offset</h3>
    <h4>Positive</h4>
    <div className={styles.grid}>
      {SIDES.map((side) =>
        ALIGN_OPTIONS.map((align) => (
          <HoverCard.Root key={`${side}-${align}`} open>
            <HoverCard.Trigger className={styles.chromaticTrigger} />
            <HoverCard.Portal>
              <HoverCard.Content
                className={styles.chromaticContent}
                side={side}
                sideOffset={5}
                align={align}
                avoidCollisions={false}
              >
                <p style={{ textAlign: 'center' }}>
                  {side}
                  <br />
                  {align}
                </p>
                <HoverCard.Arrow className={styles.chromaticArrow} width={20} height={10} />
              </HoverCard.Content>
            </HoverCard.Portal>
          </HoverCard.Root>
        )),
      )}
    </div>
    <h4>Negative</h4>
    <div className={styles.grid}>
      {SIDES.map((side) =>
        ALIGN_OPTIONS.map((align) => (
          <HoverCard.Root key={`${side}-${align}`} open>
            <HoverCard.Trigger className={styles.chromaticTrigger} />
            <HoverCard.Portal>
              <HoverCard.Content
                className={styles.chromaticContent}
                side={side}
                sideOffset={-10}
                align={align}
                avoidCollisions={false}
              >
                <p style={{ textAlign: 'center' }}>
                  {side}
                  <br />
                  {align}
                </p>
                <HoverCard.Arrow className={styles.chromaticArrow} width={20} height={10} />
              </HoverCard.Content>
            </HoverCard.Portal>
          </HoverCard.Root>
        )),
      )}
    </div>

    <h3>Align offset</h3>
    <h4>Positive</h4>
    <div className={styles.grid}>
      {SIDES.map((side) =>
        ALIGN_OPTIONS.map((align) => (
          <HoverCard.Root key={`${side}-${align}`} open>
            <HoverCard.Trigger className={styles.chromaticTrigger} />
            <HoverCard.Portal>
              <HoverCard.Content
                className={styles.chromaticContent}
                side={side}
                align={align}
                alignOffset={20}
                avoidCollisions={false}
              >
                <p style={{ textAlign: 'center' }}>
                  {side}
                  <br />
                  {align}
                </p>
                <HoverCard.Arrow className={styles.chromaticArrow} width={20} height={10} />
              </HoverCard.Content>
            </HoverCard.Portal>
          </HoverCard.Root>
        )),
      )}
    </div>
    <h4>Negative</h4>
    <div className={styles.grid}>
      {SIDES.map((side) =>
        ALIGN_OPTIONS.map((align) => (
          <HoverCard.Root key={`${side}-${align}`} open>
            <HoverCard.Trigger className={styles.chromaticTrigger} />
            <HoverCard.Portal>
              <HoverCard.Content
                className={styles.chromaticContent}
                side={side}
                align={align}
                alignOffset={-10}
                avoidCollisions={false}
              >
                <p style={{ textAlign: 'center' }}>
                  {side}
                  <br />
                  {align}
                </p>
                <HoverCard.Arrow className={styles.chromaticArrow} width={20} height={10} />
              </HoverCard.Content>
            </HoverCard.Portal>
          </HoverCard.Root>
        )),
      )}
    </div>

    <h2>Collisions</h2>
    <p>See instances on the periphery of the page.</p>
    {SIDES.map((side) =>
      ALIGN_OPTIONS.map((align) => (
        <HoverCard.Root key={`${side}-${align}`} open>
          <HoverCard.Trigger
            className={styles.chromaticTrigger}
            style={{
              position: 'absolute',
              [side]: 10,
              ...((side === 'right' || side === 'left') &&
                (align === 'start'
                  ? { bottom: 10 }
                  : align === 'center'
                    ? { top: 'calc(50% - 15px)' }
                    : { top: 10 })),
              ...((side === 'top' || side === 'bottom') &&
                (align === 'start'
                  ? { right: 10 }
                  : align === 'center'
                    ? { left: 'calc(50% - 15px)' }
                    : { left: 10 })),
            }}
          />
          <HoverCard.Portal>
            <HoverCard.Content className={styles.chromaticContent} side={side} align={align}>
              <p style={{ textAlign: 'center' }}>
                {side}
                <br />
                {align}
              </p>
              <HoverCard.Arrow className={styles.chromaticArrow} width={20} height={10} />
            </HoverCard.Content>
          </HoverCard.Portal>
        </HoverCard.Root>
      )),
    )}

    <h2>Relative parent (non-portalled)</h2>
    <div style={{ position: 'relative' }}>
      <HoverCard.Root open>
        <HoverCard.Trigger href="/" className={styles.trigger}>
          trigger
        </HoverCard.Trigger>
        <HoverCard.Content className={styles.content} sideOffset={5}>
          <HoverCard.Arrow className={styles.arrow} width={20} height={10} />
          Some content
        </HoverCard.Content>
      </HoverCard.Root>
    </div>

    <h1 style={{ marginTop: 100 }}>With slotted trigger</h1>
    <HoverCard.Root open>
      <HoverCard.Trigger asChild>
        <button className={styles.trigger}>open</button>
      </HoverCard.Trigger>
      <HoverCard.Portal>
        <HoverCard.Content className={styles.content} sideOffset={5}>
          <HoverCard.Arrow className={styles.arrow} width={20} height={10} offset={10} />
          Some content
        </HoverCard.Content>
      </HoverCard.Portal>
    </HoverCard.Root>

    <h1 style={{ marginTop: 100 }}>State attributes</h1>
    <h2>Closed</h2>
    <HoverCard.Root open={false}>
      <HoverCard.Trigger className={styles.triggerAttr}>open</HoverCard.Trigger>
      <HoverCard.Portal>
        <HoverCard.Content className={styles.contentAttr} sideOffset={5} avoidCollisions={false}>
          <HoverCard.Arrow className={styles.arrowAttr} width={20} height={10} />
          Some content
        </HoverCard.Content>
      </HoverCard.Portal>
    </HoverCard.Root>

    <h2>Open</h2>
    <HoverCard.Root open>
      <HoverCard.Trigger className={styles.triggerAttr}>open</HoverCard.Trigger>
      <HoverCard.Portal>
        <HoverCard.Content
          className={styles.contentAttr}
          side="right"
          sideOffset={5}
          avoidCollisions={false}
        >
          <HoverCard.Arrow className={styles.arrowAttr} width={20} height={10} />
          Some content
        </HoverCard.Content>
      </HoverCard.Portal>
    </HoverCard.Root>
  </div>
);
Chromatic.parameters = { chromatic: { disable: false } };

function CardContentPlaceholder() {
  return (
    <div style={{ maxWidth: 400, display: 'flex', alignItems: 'center' }}>
      <div style={{ width: 60, height: 60, backgroundColor: 'white', borderRadius: 100 }} />
      <div style={{ marginLeft: 14 }}>
        <div style={{ width: 200, backgroundColor: 'white', height: 14, borderRadius: 100 }} />
        <div
          style={{
            width: 150,
            backgroundColor: 'white',
            height: 14,
            borderRadius: 100,
            marginTop: 10,
          }}
        />
      </div>
    </div>
  );
}



================================================
FILE: apps/storybook/stories/label.stories.module.css
================================================
.root {
  /* ensures it can receive vertical margins */
  display: inline-block;
  /* better default alignment */
  vertical-align: middle;
  /* mimics default `label` tag (as we render a `span`) */
  cursor: default;
  display: inline-block;
  border: 1px solid var(--gray-5);
  padding: 10px;
}

.control {
  display: inline-flex;
  border: 1px solid var(--gray-5);
  padding: 10px;
  vertical-align: middle;
  margin: 0 10px;

  &:hover {
    background-color: var(--red-9);
  }
}



================================================
FILE: apps/storybook/stories/label.stories.tsx
================================================
import { Label as LabelPrimitive } from 'radix-ui';
import styles from './label.stories.module.css';

const Label = LabelPrimitive.Root;

export default { title: 'Components/Label' };

export const Styled = () => <Label className={styles.root}>Label</Label>;

export const WithControl = () => {
  return (
    <>
      <h1>Wrapping control</h1>
      <Label>
        <Control className={styles.control} /> Label
      </Label>

      <h1>Referencing control</h1>
      <Control id="control" className={styles.control} />
      <Label htmlFor="control">Label</Label>
    </>
  );
};

export const WithInputNumber = (_props: any) => {
  return (
    <Label>
      <span>Name:</span>
      <input type="number" />
    </Label>
  );
};

const Control = (props: any) => {
  return (
    <button className={styles.control} {...props} onClick={() => window.alert('clicked')}>
      Control
    </button>
  );
};



================================================
FILE: apps/storybook/stories/menu.stories.module.css
================================================
.content {
  display: inline-block;
  box-sizing: border-box;
  min-width: 130px;
  background-color: var(--color-white);
  border: 1px solid var(--color-gray100);
  border-radius: 6px;
  padding: 5px;
  box-shadow: 0 5px 10px 0 rgba(0, 0, 0, 0.1);
  font-family: apple-system, BlinkMacSystemFont, helvetica, arial, sans-serif;
  font-size: 13px;
  &:focus-within {
    border-color: var(--color-black);
  }
}

.label,
.item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  line-height: 1;
  cursor: default;
  user-select: none;
  white-space: nowrap;
  height: 25px;
  padding: 0 10px;
  color: var(--color-black);
  border-radius: 3px;
}

.label {
  color: var(--color-gray100);
}

.item {
  outline: none;

  &[data-highlighted] {
    background-color: var(--color-black);
    color: var(--color-white);
  }

  &[data-disabled] {
    color: var(--color-gray100);
  }
}

.subTrigger {
  &:not([data-highlighted])[data-state='open'] {
    background-color: var(--color-gray100);
    color: var(--color-black);
  }
}

.separator {
  height: 1;
  margin: 5px 10px;
  background-color: var(--color-gray100);
}

@keyframes menu-animateIn {
  from {
    transform: scale(0.95);
    opacity: 0;
  }
  to {
    transform: scale(1);
    opacity: 1;
  }
}

@keyframes menu-animateOut {
  from {
    transform: scale(1);
    opacity: 1;
  }
  to {
    transform: scale(0.95);
    opacity: 0;
  }
}

.animatedContent {
  &[data-state='open'] {
    animation: menu-animateIn 300ms ease;
  }
  &[data-state='closed'] {
    animation: menu-animateOut 300ms ease;
  }
}

.animatedItemIndicator {
  &[data-state='checked'] {
    animation: menu-animateIn 300ms ease;
  }
  &[data-state='unchecked'] {
    animation: menu-animateOut 300ms ease;
  }
}



================================================
FILE: apps/storybook/stories/menu.stories.tsx
================================================
import * as React from 'react';
import { Direction } from 'radix-ui';
import { Menu } from 'radix-ui/internal';
import { foodGroups } from '@repo/test-data/foods';
import styles from './menu.stories.module.css';

export default {
  title: 'Utilities/Menu',
  excludeStories: ['TickIcon', 'classes'],
};

export const Styled = () => (
  <MenuWithAnchor>
    <Menu.Item className={styles.item} onSelect={() => window.alert('undo')}>
      Undo
    </Menu.Item>
    <Menu.Item className={styles.item} onSelect={() => window.alert('redo')}>
      Redo
    </Menu.Item>
    <Menu.Separator className={styles.separator} />
    <Menu.Item className={styles.item} disabled onSelect={() => window.alert('cut')}>
      Cut
    </Menu.Item>
    <Menu.Item className={styles.item} onSelect={() => window.alert('copy')}>
      Copy
    </Menu.Item>
    <Menu.Item className={styles.item} onSelect={() => window.alert('paste')}>
      Paste
    </Menu.Item>
  </MenuWithAnchor>
);

export const Submenus = () => {
  const [open1, setOpen1] = React.useState(false);
  const [open2, setOpen2] = React.useState(false);
  const [open3, setOpen3] = React.useState(false);
  const [open4, setOpen4] = React.useState(false);
  const [rtl, setRtl] = React.useState(false);
  const [animated, setAnimated] = React.useState(false);

  React.useEffect(() => {
    if (rtl) {
      document.documentElement.setAttribute('dir', 'rtl');
      return () => document.documentElement.removeAttribute('dir');
    }
  }, [rtl]);

  return (
    <Direction.Provider dir={rtl ? 'rtl' : 'ltr'}>
      <div style={{ marginBottom: 8, display: 'grid', gridAutoFlow: 'row', gap: 4 }}>
        <label>
          <input
            type="checkbox"
            checked={rtl}
            onChange={(event) => setRtl(event.currentTarget.checked)}
          />
          Right-to-left
        </label>
        <label>
          <input
            type="checkbox"
            checked={animated}
            onChange={(event) => setAnimated(event.currentTarget.checked)}
          />
          Animated
        </label>
      </div>
      <MenuWithAnchor>
        <Menu.Item className={styles.item} onSelect={() => window.alert('undo')}>
          Undo
        </Menu.Item>
        <Submenu open={open1} onOpenChange={setOpen1} animated={animated}>
          <Menu.Item className={styles.item} disabled>
            Disabled
          </Menu.Item>
          <Menu.Item className={styles.item} onSelect={() => window.alert('one')}>
            One
          </Menu.Item>
          <Submenu open={open2} onOpenChange={setOpen2} animated={animated}>
            <Menu.Item className={styles.item} onSelect={() => window.alert('one')}>
              One
            </Menu.Item>
            <Menu.Item className={styles.item} onSelect={() => window.alert('two')}>
              Two
            </Menu.Item>
            <Menu.Item className={styles.item} onSelect={() => window.alert('three')}>
              Three
            </Menu.Item>
            <Menu.Item className={styles.item} onSelect={() => window.alert('four')}>
              Four
            </Menu.Item>
            <Menu.Item className={styles.item} onSelect={() => window.alert('five')}>
              Five
            </Menu.Item>
            <Menu.Item className={styles.item} onSelect={() => window.alert('six')}>
              Six
            </Menu.Item>
          </Submenu>
          <Submenu heading="Sub Menu" open={open3} onOpenChange={setOpen3} animated={animated}>
            <Menu.Item className={styles.item} onSelect={() => window.alert('one')}>
              One
            </Menu.Item>
            <Menu.Item className={styles.item} onSelect={() => window.alert('two')}>
              Two
            </Menu.Item>
            <Menu.Item className={styles.item} onSelect={() => window.alert('three')}>
              Three
            </Menu.Item>
          </Submenu>
          <Menu.Item className={styles.item} onSelect={() => window.alert('two')}>
            Two
          </Menu.Item>
          <Submenu open={open4} onOpenChange={setOpen4} animated={animated} disabled>
            <Menu.Item className={styles.item} onSelect={() => window.alert('one')}>
              One
            </Menu.Item>
            <Menu.Item className={styles.item} onSelect={() => window.alert('two')}>
              Two
            </Menu.Item>
            <Menu.Item className={styles.item} onSelect={() => window.alert('three')}>
              Three
            </Menu.Item>
          </Submenu>
          <Menu.Item className={styles.item} onSelect={() => window.alert('three')}>
            Three
          </Menu.Item>
        </Submenu>

        <Menu.Separator className={styles.separator} />
        <Menu.Item className={styles.item} disabled onSelect={() => window.alert('cut')}>
          Cut
        </Menu.Item>
        <Menu.Item className={styles.item} onSelect={() => window.alert('copy')}>
          Copy
        </Menu.Item>
        <Menu.Item className={styles.item} onSelect={() => window.alert('paste')}>
          Paste
        </Menu.Item>
      </MenuWithAnchor>
    </Direction.Provider>
  );
};

export const WithLabels = () => (
  <MenuWithAnchor>
    {foodGroups.map((foodGroup, index) => (
      <Menu.Group key={index}>
        {foodGroup.label && (
          <Menu.Label className={styles.label} key={foodGroup.label}>
            {foodGroup.label}
          </Menu.Label>
        )}
        {foodGroup.foods.map((food) => (
          <Menu.Item
            key={food.value}
            className={styles.item}
            disabled={food.disabled}
            onSelect={() => window.alert(food.label)}
          >
            {food.label}
          </Menu.Item>
        ))}
        {index < foodGroups.length - 1 && <Menu.Separator className={styles.separator} />}
      </Menu.Group>
    ))}
  </MenuWithAnchor>
);

const suits = [
  { emoji: '♥️', label: 'Hearts' },
  { emoji: '♠️', label: 'Spades' },
  { emoji: '♦️', label: 'Diamonds' },
  { emoji: '♣️', label: 'Clubs' },
];

export const Typeahead = () => (
  <>
    <h1>Testing ground for typeahead behaviour</h1>

    <div style={{ display: 'flex', alignItems: 'flex-start', gap: 100 }}>
      <div>
        <h2>Text labels</h2>
        <div style={{ marginBottom: 20 }}>
          <p>
            For comparison
            <br />
            try the closed select below
          </p>
          <select>
            {foodGroups.map((foodGroup, index) => (
              <React.Fragment key={index}>
                {foodGroup.foods.map((food) => (
                  <option key={food.value} value={food.value} disabled={food.disabled}>
                    {food.label}
                  </option>
                ))}
              </React.Fragment>
            ))}
          </select>
        </div>
        <WithLabels />
      </div>

      <div>
        <h2>Complex children</h2>
        <p>(relying on `.textContent` — default)</p>
        <MenuWithAnchor>
          {suits.map((suit) => (
            <Menu.Item key={suit.emoji} className={styles.item}>
              {suit.label}
              <span role="img" aria-label={suit.label}>
                {suit.emoji}
              </span>
            </Menu.Item>
          ))}
        </MenuWithAnchor>
      </div>

      <div>
        <h2>Complex children</h2>
        <p>(with explicit `textValue` prop)</p>
        <MenuWithAnchor>
          {suits.map((suit) => (
            <Menu.Item key={suit.emoji} className={styles.item} textValue={suit.label}>
              <span role="img" aria-label={suit.label}>
                {suit.emoji}
              </span>
              {suit.label}
            </Menu.Item>
          ))}
        </MenuWithAnchor>
      </div>
    </div>
  </>
);

export const CheckboxItems = () => {
  const options = ['Crows', 'Ravens', 'Magpies', 'Jackdaws'];

  const [selection, setSelection] = React.useState<string[]>([]);

  const handleSelectAll = () => {
    setSelection((currentSelection) => (currentSelection.length === options.length ? [] : options));
  };

  return (
    <MenuWithAnchor>
      <Menu.CheckboxItem
        className={styles.item}
        checked={
          selection.length === options.length ? true : selection.length ? 'indeterminate' : false
        }
        onCheckedChange={handleSelectAll}
      >
        Select all
        <Menu.ItemIndicator>
          {selection.length === options.length ? <TickIcon /> : '—'}
        </Menu.ItemIndicator>
      </Menu.CheckboxItem>
      <Menu.Separator className={styles.separator} />
      {options.map((option) => (
        <Menu.CheckboxItem
          key={option}
          className={styles.item}
          checked={selection.includes(option)}
          onCheckedChange={() =>
            setSelection((current) =>
              current.includes(option)
                ? current.filter((el) => el !== option)
                : current.concat(option),
            )
          }
        >
          {option}
          <Menu.ItemIndicator>
            <TickIcon />
          </Menu.ItemIndicator>
        </Menu.CheckboxItem>
      ))}
    </MenuWithAnchor>
  );
};

export const RadioItems = () => {
  const files = ['README.md', 'index.js', 'page.css'];
  const [file, setFile] = React.useState(files[1]);

  return (
    <MenuWithAnchor>
      <Menu.Item className={styles.item} onSelect={() => window.alert('minimize')}>
        Minimize window
      </Menu.Item>
      <Menu.Item className={styles.item} onSelect={() => window.alert('zoom')}>
        Zoom
      </Menu.Item>
      <Menu.Item className={styles.item} onSelect={() => window.alert('smaller')}>
        Smaller
      </Menu.Item>
      <Menu.Separator className={styles.separator} />
      <Menu.RadioGroup value={file} onValueChange={setFile}>
        {files.map((file) => (
          <Menu.RadioItem key={file} className={styles.item} value={file}>
            {file}
            <Menu.ItemIndicator>
              <TickIcon />
            </Menu.ItemIndicator>
          </Menu.RadioItem>
        ))}
      </Menu.RadioGroup>
    </MenuWithAnchor>
  );
};

export const Animated = () => {
  const files = ['README.md', 'index.js', 'page.css'];
  const [file, setFile] = React.useState(files[1]);
  const [open, setOpen] = React.useState(true);
  const checkboxItems = [
    { label: 'Bold', state: React.useState(false) },
    { label: 'Italic', state: React.useState(true) },
    { label: 'Underline', state: React.useState(false) },
    { label: 'Strikethrough', state: React.useState(false), disabled: true },
  ];

  return (
    <>
      <label>
        <input type="checkbox" checked={open} onChange={(event) => setOpen(event.target.checked)} />{' '}
        open
      </label>
      <br />
      <br />
      <MenuWithAnchor className={styles.animatedContent} open={open}>
        {checkboxItems.map(({ label, state: [checked, setChecked], disabled }) => (
          <Menu.CheckboxItem
            key={label}
            className={styles.item}
            checked={checked}
            onCheckedChange={setChecked}
            disabled={disabled}
          >
            {label}
            <Menu.ItemIndicator className={styles.animatedItemIndicator}>
              <TickIcon />
            </Menu.ItemIndicator>
          </Menu.CheckboxItem>
        ))}
        <Menu.RadioGroup value={file} onValueChange={setFile}>
          {files.map((file) => (
            <Menu.RadioItem key={file} className={styles.item} value={file}>
              {file}
              <Menu.ItemIndicator className={styles.animatedItemIndicator}>
                <TickIcon />
              </Menu.ItemIndicator>
            </Menu.RadioItem>
          ))}
        </Menu.RadioGroup>
      </MenuWithAnchor>
    </>
  );
};

type MenuProps = Omit<
  React.ComponentProps<typeof Menu.Root> & React.ComponentProps<typeof Menu.Content>,
  'trapFocus' | 'onCloseAutoFocus' | 'disableOutsidePointerEvents' | 'disableOutsideScroll'
>;

const MenuWithAnchor: React.FC<MenuProps> = (props) => {
  const { open = true, children, ...contentProps } = props;
  return (
    <Menu.Root open={open} onOpenChange={() => {}} modal={false}>
      {/* inline-block allows anchor to move when rtl changes on document */}
      <Menu.Anchor style={{ display: 'inline-block' }} />
      <Menu.Portal>
        <Menu.Content
          className={styles.content}
          onCloseAutoFocus={(event) => event.preventDefault()}
          align="start"
          {...contentProps}
        >
          {children}
        </Menu.Content>
      </Menu.Portal>
    </Menu.Root>
  );
};

const Submenu: React.FC<MenuProps & { animated: boolean; disabled?: boolean; heading?: string }> = (
  props,
) => {
  const {
    heading = 'Submenu',
    open = true,
    onOpenChange,
    children,
    animated,
    disabled,
    ...contentProps
  } = props;
  return (
    <Menu.Sub open={open} onOpenChange={onOpenChange}>
      <Menu.SubTrigger className={[styles.item, styles.subTrigger].join(' ')} disabled={disabled}>
        {heading} →
      </Menu.SubTrigger>
      <Menu.Portal>
        <Menu.SubContent
          className={[animated && styles.animatedContent, styles.content].filter(Boolean).join(' ')}
          {...contentProps}
        >
          {children}
        </Menu.SubContent>
      </Menu.Portal>
    </Menu.Sub>
  );
};

const TickIcon = () => (
  <svg
    xmlns="http://www.w3.org/2000/svg"
    viewBox="0 0 32 32"
    width="12"
    height="12"
    fill="none"
    stroke="currentcolor"
    strokeLinecap="round"
    strokeLinejoin="round"
    strokeWidth="3"
  >
    <path d="M2 20 L12 28 30 4" />
  </svg>
);



================================================
FILE: apps/storybook/stories/menubar.stories.module.css
================================================
.root {
  border: 1px solid var(--gray-4);
  border-radius: 6px;
  padding: 2px;
}

.trigger {
  padding: 6px 16px;
  border: 0;
  background-color: transparent;
  font-family: apple-system, BlinkMacSystemFont, helvetica, arial, sans-serif;
  font-size: 13px;
  border-radius: 4px;
  outline: none;
  &[data-highlighted] {
    background-color: var(--gray-4);
  }
  &[data-state='open'] {
    background-color: var(--gray-12);
    color: var(--gray-1);
  }
}

.content {
  display: inline-block;
  box-sizing: border-box;
  min-width: 130px;
  background-color: var(--color-white);
  border: 1px solid var(--color-gray100);
  border-radius: 6px;
  padding: 5px;
  box-shadow: 0 5px 10px 0 rgba(0, 0, 0, 0.1);
  font-family: apple-system, BlinkMacSystemFont, helvetica, arial, sans-serif;
  font-size: 13px;
  &:focus-within {
    border-color: var(--color-black);
  }
}

.label,
.item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  line-height: 1;
  cursor: default;
  user-select: none;
  white-space: nowrap;
  height: 25px;
  padding: 0 10px;
  color: var(--color-black);
  border-radius: 3px;
}

.label {
  color: var(--color-gray100);
}

.item {
  outline: none;

  &[data-highlighted] {
    background-color: var(--color-black);
    color: var(--color-white);
  }

  &[data-disabled] {
    color: var(--color-gray100);
  }
}

.subTrigger {
  &:not([data-highlighted])[data-state='open'] {
    background-color: var(--color-gray100);
    color: var(--color-black);
  }
}

.separator {
  height: 1;
  margin: 5px 10px;
  background-color: var(--color-gray100);
}

@keyframes menu-animateIn {
  from {
    transform: scale(0.95);
    opacity: 0;
  }
  to {
    transform: scale(1);
    opacity: 1;
  }
}

@keyframes menu-animateOut {
  from {
    transform: scale(1);
    opacity: 1;
  }
  to {
    transform: scale(0.95);
    opacity: 0;
  }
}

.animatedContent {
  &[data-state='open'] {
    animation: menu-animateIn 300ms ease;
  }
  &[data-state='closed'] {
    animation: menu-animateOut 300ms ease;
  }
}

.animatedItemIndicator {
  &[data-state='checked'] {
    animation: menu-animateIn 300ms ease;
  }
  &[data-state='unchecked'] {
    animation: menu-animateOut 300ms ease;
  }
}



================================================
FILE: apps/storybook/stories/menubar.stories.tsx
================================================
import * as React from 'react';
import { Menubar } from 'radix-ui';
import { foodGroups } from '@repo/test-data/foods';
import styles from './menubar.stories.module.css';

const subTriggerClass = [styles.item, styles.subTrigger].join(' ');

export default { title: 'Components/Menubar' };

export const Styled = () => {
  const [loop, setLoop] = React.useState(false);
  const [rtl, setRtl] = React.useState(false);
  const dir = rtl ? 'rtl' : 'ltr';
  const checkOptions = [
    'Always Show Bookmarks Bar',
    'Always Show Toolbar in Fullscreen',
    'Always Show Full URLs',
  ];
  const [checkedSelection, setCheckedSelection] = React.useState([checkOptions[1]!]);

  const radioOptions = ['Andy', 'Benoît', 'Colm', 'Jenna', 'Pedro'];
  const [radioSelection, setRadioSelection] = React.useState(radioOptions[1]);

  return (
    <div
      style={{
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        flexDirection: 'column',
        paddingTop: 50,
      }}
    >
      <div style={{ display: 'flex', gap: 25, marginBottom: 20 }}>
        <label>
          <input
            type="checkbox"
            checked={rtl}
            onChange={(event) => setRtl(event.currentTarget.checked)}
          />
          Right-to-left
        </label>

        <label>
          <input
            type="checkbox"
            checked={loop}
            onChange={(event) => setLoop(event.currentTarget.checked)}
          />
          Loop
        </label>
      </div>

      <div dir={dir}>
        <Menubar.Root className={styles.root} loop={loop} dir={dir}>
          <Menubar.Menu>
            <Menubar.Trigger className={styles.trigger}>File</Menubar.Trigger>
            <Menubar.Portal>
              <Menubar.Content className={styles.content} sideOffset={2}>
                <Menubar.Item className={styles.item}>New Tab</Menubar.Item>
                <Menubar.Item className={styles.item}>New Window</Menubar.Item>
                <Menubar.Item className={styles.item}>New Incognito Window</Menubar.Item>
                <Menubar.Separator className={styles.separator} />
                <Menubar.Sub>
                  <Menubar.SubTrigger className={subTriggerClass}>
                    Share <span>→</span>
                  </Menubar.SubTrigger>
                  <Menubar.Portal>
                    <Menubar.SubContent className={styles.content} alignOffset={-6}>
                      <Menubar.Item className={styles.item}>Email Link</Menubar.Item>
                      <Menubar.Item className={styles.item}>Messages</Menubar.Item>
                      <Menubar.Item className={styles.item}>Airdrop</Menubar.Item>
                    </Menubar.SubContent>
                  </Menubar.Portal>
                </Menubar.Sub>
                <Menubar.Separator className={styles.separator} />
                <Menubar.Item className={styles.item}>Print…</Menubar.Item>
              </Menubar.Content>
            </Menubar.Portal>
          </Menubar.Menu>

          <Menubar.Menu>
            <Menubar.Trigger className={styles.trigger}>Edit</Menubar.Trigger>
            <Menubar.Portal>
              <Menubar.Content className={styles.content} sideOffset={2}>
                <Menubar.Item className={styles.item}>Undo</Menubar.Item>
                <Menubar.Item className={styles.item}>Redo</Menubar.Item>
                <Menubar.Separator className={styles.separator} />
                <Menubar.Sub>
                  <Menubar.SubTrigger className={subTriggerClass}>
                    Find <span>→</span>
                  </Menubar.SubTrigger>

                  <Menubar.Portal>
                    <Menubar.SubContent className={styles.content} alignOffset={-6}>
                      <Menubar.Item className={styles.item}>Search the web…</Menubar.Item>
                      <Menubar.Separator className={styles.separator} />
                      <Menubar.Item className={styles.item}>Find…</Menubar.Item>
                      <Menubar.Item className={styles.item}>Find Next</Menubar.Item>
                      <Menubar.Item className={styles.item}>Find Previous</Menubar.Item>
                      <Menubar.Sub>
                        <Menubar.SubTrigger className={subTriggerClass}>
                          Advanced <span>→</span>
                        </Menubar.SubTrigger>

                        <Menubar.Portal>
                          <Menubar.SubContent className={styles.content} alignOffset={-6}>
                            <Menubar.Item className={styles.item}>Regex</Menubar.Item>
                            <Menubar.Item className={styles.item}>Replace</Menubar.Item>
                          </Menubar.SubContent>
                        </Menubar.Portal>
                      </Menubar.Sub>
                    </Menubar.SubContent>
                  </Menubar.Portal>
                </Menubar.Sub>
                <Menubar.Separator className={styles.separator} />
                <Menubar.Item className={styles.item}>Cut</Menubar.Item>
                <Menubar.Item className={styles.item}>Copy</Menubar.Item>
                <Menubar.Item className={styles.item}>Paste</Menubar.Item>
              </Menubar.Content>
            </Menubar.Portal>
          </Menubar.Menu>

          <Menubar.Menu>
            <Menubar.Trigger className={styles.trigger}>View</Menubar.Trigger>
            <Menubar.Portal>
              <Menubar.Content className={styles.content} sideOffset={2}>
                {checkOptions.map((option) => (
                  <Menubar.CheckboxItem
                    key={option}
                    className={styles.item}
                    checked={checkedSelection.includes(option)}
                    onCheckedChange={() =>
                      setCheckedSelection((current) =>
                        current.includes(option)
                          ? current.filter((el) => el !== option)
                          : current.concat(option),
                      )
                    }
                  >
                    {option}
                    <Menubar.ItemIndicator style={{ marginLeft: 10 }}>
                      <TickIcon />
                    </Menubar.ItemIndicator>
                  </Menubar.CheckboxItem>
                ))}
                <Menubar.Separator className={styles.separator} />
                <Menubar.Item className={styles.item}>Reload</Menubar.Item>
                <Menubar.Item className={styles.item}>Force Reload</Menubar.Item>
                <Menubar.Separator className={styles.separator} />
                <Menubar.Item className={styles.item}>Toggle Fullscreen</Menubar.Item>
                <Menubar.Separator className={styles.separator} />
                <Menubar.Item className={styles.item}>Hide Sidebar</Menubar.Item>
              </Menubar.Content>
            </Menubar.Portal>
          </Menubar.Menu>

          <Menubar.Menu>
            <Menubar.Trigger className={styles.trigger}>Profiles</Menubar.Trigger>
            <Menubar.Portal>
              <Menubar.Content className={styles.content} sideOffset={2}>
                <Menubar.RadioGroup value={radioSelection} onValueChange={setRadioSelection}>
                  {radioOptions.map((option) => (
                    <Menubar.RadioItem key={option} className={styles.item} value={option}>
                      {option}
                      <Menubar.ItemIndicator style={{ marginLeft: 10 }}>
                        <TickIcon />
                      </Menubar.ItemIndicator>
                    </Menubar.RadioItem>
                  ))}
                </Menubar.RadioGroup>
              </Menubar.Content>
            </Menubar.Portal>
          </Menubar.Menu>

          <Menubar.Menu>
            <Menubar.Trigger className={styles.trigger}>History</Menubar.Trigger>
            <Menubar.Portal>
              <Menubar.Content className={styles.content} sideOffset={2}>
                <Menubar.Label className={styles.label}>Work</Menubar.Label>
                <Menubar.Item className={styles.item}>Radix</Menubar.Item>
                <Menubar.Item className={styles.item}>Github</Menubar.Item>
                <Menubar.Item className={styles.item}>WorkOS</Menubar.Item>
                <Menubar.Label className={styles.label}>Community</Menubar.Label>
                <Menubar.Item className={styles.item}>Twitter</Menubar.Item>
                <Menubar.Item className={styles.item}>Discord</Menubar.Item>
                <Menubar.Item className={styles.item}>Slack</Menubar.Item>
              </Menubar.Content>
            </Menubar.Portal>
          </Menubar.Menu>
        </Menubar.Root>
      </div>
    </div>
  );
};

export const Cypress = () => {
  const [loop, setLoop] = React.useState(false);
  const [rtl, setRtl] = React.useState(false);
  const [portalled, setPortalled] = React.useState(false);

  const dir = rtl ? 'rtl' : 'ltr';
  const Portal = portalled ? Menubar.Portal : React.Fragment;

  return (
    <div
      style={{
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        flexDirection: 'column',
        paddingTop: 50,
      }}
    >
      <div style={{ display: 'flex', gap: 25, marginBottom: 20 }}>
        <label>
          <input
            type="checkbox"
            checked={rtl}
            onChange={(event) => setRtl(event.currentTarget.checked)}
          />
          Right-to-left
        </label>

        <label>
          <input
            type="checkbox"
            checked={loop}
            onChange={(event) => setLoop(event.currentTarget.checked)}
          />
          Loop
        </label>

        <label>
          <input
            type="checkbox"
            checked={portalled}
            onChange={(event) => setPortalled(event.currentTarget.checked)}
          />
          Portalled
        </label>
      </div>
      <div dir={dir}>
        <Menubar.Root className={styles.root} loop={loop} dir={dir}>
          <Menubar.Menu>
            <Menubar.Trigger className={styles.trigger}>File</Menubar.Trigger>
            <Portal>
              <Menubar.Content className={styles.content} sideOffset={2}>
                <Menubar.Item className={styles.item}>New Tab</Menubar.Item>
                <Menubar.Item className={styles.item}>New Window</Menubar.Item>
                <Menubar.Item className={styles.item}>New Incognito Window</Menubar.Item>
                <Menubar.Separator className={styles.separator} />
                <Menubar.Sub>
                  <Menubar.SubTrigger className={subTriggerClass}>
                    Share <span>→</span>
                  </Menubar.SubTrigger>
                  <Menubar.SubContent className={styles.content} alignOffset={-6}>
                    <Menubar.Item className={styles.item}>Email Link</Menubar.Item>
                    <Menubar.Item className={styles.item}>Messages</Menubar.Item>
                    <Menubar.Item className={styles.item}>Airdrop</Menubar.Item>
                  </Menubar.SubContent>
                </Menubar.Sub>
                <Menubar.Separator className={styles.separator} />
                <Menubar.Item className={styles.item}>Print…</Menubar.Item>
              </Menubar.Content>
            </Portal>
          </Menubar.Menu>

          <Menubar.Menu>
            <Menubar.Trigger className={styles.trigger}>Edit</Menubar.Trigger>
            <Portal>
              <Menubar.Content className={styles.content} sideOffset={2}>
                <Menubar.Item className={styles.item} disabled>
                  Undo
                </Menubar.Item>
                <Menubar.Item className={styles.item}>Redo</Menubar.Item>
                <Menubar.Separator className={styles.separator} />
                <Menubar.Sub>
                  <Menubar.SubTrigger className={subTriggerClass}>
                    Find <span>→</span>
                  </Menubar.SubTrigger>
                  <Portal>
                    <Menubar.SubContent className={styles.content} alignOffset={-6}>
                      <Menubar.Item className={styles.item}>Search the web…</Menubar.Item>
                      <Menubar.Separator className={styles.separator} />
                      <Menubar.Item className={styles.item}>Find…</Menubar.Item>
                      <Menubar.Item className={styles.item}>Find Next</Menubar.Item>
                      <Menubar.Item className={styles.item}>Find Previous</Menubar.Item>
                      <Menubar.Sub>
                        <Menubar.SubTrigger className={subTriggerClass}>
                          Advanced <span>→</span>
                        </Menubar.SubTrigger>

                        <Portal>
                          <Menubar.SubContent className={styles.content} alignOffset={-6}>
                            <Menubar.Item className={styles.item}>Regex</Menubar.Item>
                            <Menubar.Item className={styles.item}>Replace</Menubar.Item>
                          </Menubar.SubContent>
                        </Portal>
                      </Menubar.Sub>
                    </Menubar.SubContent>
                  </Portal>
                </Menubar.Sub>

                <Menubar.Sub>
                  <Menubar.SubTrigger className={subTriggerClass} disabled>
                    Speech <span>→</span>
                  </Menubar.SubTrigger>
                  <Portal>
                    <Menubar.SubContent className={styles.content} alignOffset={-6}>
                      <Menubar.Item className={styles.item}>Start Speaking</Menubar.Item>
                      <Menubar.Item className={styles.item}>Stop Speaking</Menubar.Item>
                    </Menubar.SubContent>
                  </Portal>
                </Menubar.Sub>

                <Menubar.Sub>
                  <Menubar.SubTrigger className={subTriggerClass}>
                    Substitutions <span>→</span>
                  </Menubar.SubTrigger>
                  <Portal>
                    <Menubar.SubContent className={styles.content} alignOffset={-6}>
                      <Menubar.Item className={styles.item}>Smart Quotes</Menubar.Item>
                      <Menubar.Item className={styles.item}>Smart Dashes</Menubar.Item>
                    </Menubar.SubContent>
                  </Portal>
                </Menubar.Sub>
                <Menubar.Separator className={styles.separator} />
                <Menubar.Item className={styles.item}>Cut</Menubar.Item>
                <Menubar.Item className={styles.item}>Copy</Menubar.Item>
                <Menubar.Item className={styles.item}>Paste</Menubar.Item>
              </Menubar.Content>
            </Portal>
          </Menubar.Menu>

          <Menubar.Menu>
            <Menubar.Trigger className={styles.trigger}>History</Menubar.Trigger>
            <Portal>
              <Menubar.Content className={styles.content} sideOffset={2}>
                <Menubar.Item className={styles.item}>Radix</Menubar.Item>
                <Menubar.Item className={styles.item}>Github</Menubar.Item>
                <Menubar.Item className={styles.item}>WorkOS</Menubar.Item>
              </Menubar.Content>
            </Portal>
          </Menubar.Menu>
        </Menubar.Root>
      </div>
    </div>
  );
};

export const Chromatic = () => {
  const checkboxItems = [
    { label: 'Bold', state: React.useState(false) },
    { label: 'Italic', state: React.useState(true) },
    { label: 'Underline', state: React.useState(false) },
    { label: 'Strikethrough', state: React.useState(false), disabled: true },
  ];
  const files = ['README.md', 'index.js', 'page.css'];
  const [file, setFile] = React.useState(files[1]);

  return (
    <div style={{ padding: 200, paddingTop: 50, paddingBottom: 800 }}>
      <h1>Uncontrolled</h1>
      <h2>Closed</h2>
      <Menubar.Root className={styles.root}>
        <Menubar.Menu>
          <Menubar.Trigger className={styles.trigger}>File</Menubar.Trigger>
          <Menubar.Portal>
            <Menubar.Content className={styles.content} avoidCollisions={false} sideOffset={2}>
              <Menubar.Item className={styles.item}>New Tab</Menubar.Item>
              <Menubar.Item className={styles.item}>New Window</Menubar.Item>
              <Menubar.Item className={styles.item}>New Incognito Window</Menubar.Item>
              <Menubar.Separator className={styles.separator} />

              <Menubar.Item className={styles.item}>Print…</Menubar.Item>
            </Menubar.Content>
          </Menubar.Portal>
        </Menubar.Menu>

        <Menubar.Menu>
          <Menubar.Trigger className={styles.trigger}>Edit</Menubar.Trigger>
          <Menubar.Portal>
            <Menubar.Content className={styles.content} avoidCollisions={false} sideOffset={2}>
              <Menubar.Item className={styles.item} disabled>
                Undo
              </Menubar.Item>
              <Menubar.Item className={styles.item}>Redo</Menubar.Item>
              <Menubar.Separator className={styles.separator} />
              <Menubar.Item className={styles.item}>Cut</Menubar.Item>
              <Menubar.Item className={styles.item}>Copy</Menubar.Item>
              <Menubar.Item className={styles.item}>Paste</Menubar.Item>
            </Menubar.Content>
          </Menubar.Portal>
        </Menubar.Menu>
      </Menubar.Root>

      <h2>Open</h2>
      <Menubar.Root defaultValue="file" className={styles.root}>
        <Menubar.Menu value="file">
          <Menubar.Trigger className={styles.trigger}>File</Menubar.Trigger>
          <Menubar.Portal>
            <Menubar.Content
              className={styles.content}
              onFocusOutside={(event) => event.preventDefault()}
              avoidCollisions={false}
              sideOffset={2}
            >
              <Menubar.Item className={styles.item}>New Tab</Menubar.Item>
              <Menubar.Item className={styles.item}>New Window</Menubar.Item>
              <Menubar.Item className={styles.item}>New Incognito Window</Menubar.Item>
              <Menubar.Separator className={styles.separator} />

              <Menubar.Item className={styles.item}>Print…</Menubar.Item>
            </Menubar.Content>
          </Menubar.Portal>
        </Menubar.Menu>

        <Menubar.Menu value="edit">
          <Menubar.Trigger className={styles.trigger}>Edit</Menubar.Trigger>
          <Menubar.Portal>
            <Menubar.Content className={styles.content} avoidCollisions={false} sideOffset={2}>
              <Menubar.Item className={styles.item} disabled>
                Undo
              </Menubar.Item>
              <Menubar.Item className={styles.item}>Redo</Menubar.Item>
              <Menubar.Separator className={styles.separator} />
              <Menubar.Item className={styles.item}>Cut</Menubar.Item>
              <Menubar.Item className={styles.item}>Copy</Menubar.Item>
              <Menubar.Item className={styles.item}>Paste</Menubar.Item>
            </Menubar.Content>
          </Menubar.Portal>
        </Menubar.Menu>
      </Menubar.Root>

      <h1 style={{ marginTop: 180 }}>Controlled</h1>
      <h2>Closed</h2>
      <Menubar.Root value="" className={styles.root}>
        <Menubar.Menu value="file">
          <Menubar.Trigger className={styles.trigger}>File</Menubar.Trigger>
          <Menubar.Portal>
            <Menubar.Content className={styles.content} avoidCollisions={false} sideOffset={2}>
              <Menubar.Item className={styles.item}>New Tab</Menubar.Item>
              <Menubar.Item className={styles.item}>New Window</Menubar.Item>
              <Menubar.Item className={styles.item}>New Incognito Window</Menubar.Item>
              <Menubar.Separator className={styles.separator} />

              <Menubar.Item className={styles.item}>Print…</Menubar.Item>
            </Menubar.Content>
          </Menubar.Portal>
        </Menubar.Menu>

        <Menubar.Menu value="edit">
          <Menubar.Trigger className={styles.trigger}>Edit</Menubar.Trigger>
          <Menubar.Portal>
            <Menubar.Content className={styles.content} avoidCollisions={false} sideOffset={2}>
              <Menubar.Item className={styles.item} disabled>
                Undo
              </Menubar.Item>
              <Menubar.Item className={styles.item}>Redo</Menubar.Item>
              <Menubar.Separator className={styles.separator} />
              <Menubar.Item className={styles.item}>Cut</Menubar.Item>
              <Menubar.Item className={styles.item}>Copy</Menubar.Item>
              <Menubar.Item className={styles.item}>Paste</Menubar.Item>
            </Menubar.Content>
          </Menubar.Portal>
        </Menubar.Menu>
      </Menubar.Root>

      <h2>Open</h2>
      <Menubar.Root value="file" className={styles.root}>
        <Menubar.Menu value="file">
          <Menubar.Trigger className={styles.trigger}>File</Menubar.Trigger>
          <Menubar.Portal>
            <Menubar.Content className={styles.content} avoidCollisions={false} sideOffset={2}>
              <Menubar.Item className={styles.item}>New Tab</Menubar.Item>
              <Menubar.Item className={styles.item}>New Window</Menubar.Item>
              <Menubar.Item className={styles.item}>New Incognito Window</Menubar.Item>
              <Menubar.Separator className={styles.separator} />

              <Menubar.Item className={styles.item}>Print…</Menubar.Item>
            </Menubar.Content>
          </Menubar.Portal>
        </Menubar.Menu>

        <Menubar.Menu value="edit">
          <Menubar.Trigger className={styles.trigger}>Edit</Menubar.Trigger>
          <Menubar.Portal>
            <Menubar.Content className={styles.content} avoidCollisions={false} sideOffset={2}>
              <Menubar.Item className={styles.item} disabled>
                Undo
              </Menubar.Item>
              <Menubar.Item className={styles.item}>Redo</Menubar.Item>
              <Menubar.Separator className={styles.separator} />
              <Menubar.Item className={styles.item}>Cut</Menubar.Item>
              <Menubar.Item className={styles.item}>Copy</Menubar.Item>
              <Menubar.Item className={styles.item}>Paste</Menubar.Item>
            </Menubar.Content>
          </Menubar.Portal>
        </Menubar.Menu>
      </Menubar.Root>

      <h1 style={{ marginTop: 200 }}>Submenus</h1>
      <Menubar.Root value="edit" className={styles.root}>
        <Menubar.Menu value="file">
          <Menubar.Trigger className={styles.trigger}>File</Menubar.Trigger>
          <Menubar.Portal>
            <Menubar.Content className={styles.content} avoidCollisions={false} sideOffset={2}>
              <Menubar.Item className={styles.item}>New Tab</Menubar.Item>
              <Menubar.Item className={styles.item}>New Window</Menubar.Item>
              <Menubar.Item className={styles.item}>New Incognito Window</Menubar.Item>
              <Menubar.Separator className={styles.separator} />

              <Menubar.Item className={styles.item}>Print…</Menubar.Item>
            </Menubar.Content>
          </Menubar.Portal>
        </Menubar.Menu>

        <Menubar.Menu value="edit">
          <Menubar.Trigger className={styles.trigger}>Edit</Menubar.Trigger>
          <Menubar.Portal>
            <Menubar.Content className={styles.content} avoidCollisions={false} sideOffset={2}>
              <Menubar.Item className={styles.item} disabled>
                Undo
              </Menubar.Item>
              <Menubar.Item className={styles.item}>Redo</Menubar.Item>
              <Menubar.Separator className={styles.separator} />
              <Menubar.Sub open>
                <Menubar.SubTrigger className={subTriggerClass}>
                  Find <span>→</span>
                </Menubar.SubTrigger>
                <Menubar.Portal>
                  <Menubar.SubContent
                    className={styles.content}
                    sideOffset={10}
                    alignOffset={-6}
                    avoidCollisions={false}
                  >
                    <Menubar.Item className={styles.item}>Search the web…</Menubar.Item>
                    <Menubar.Separator className={styles.separator} />
                    <Menubar.Item className={styles.item}>Find…</Menubar.Item>
                    <Menubar.Item className={styles.item}>Find Next</Menubar.Item>
                    <Menubar.Item className={styles.item}>Find Previous</Menubar.Item>
                    <Menubar.Sub open>
                      <Menubar.SubTrigger className={subTriggerClass}>
                        Advanced <span>→</span>
                      </Menubar.SubTrigger>

                      <Menubar.Portal>
                        <Menubar.SubContent
                          className={styles.content}
                          sideOffset={10}
                          alignOffset={-6}
                          avoidCollisions={false}
                        >
                          <Menubar.Item className={styles.item}>Regex</Menubar.Item>
                          <Menubar.Item className={styles.item}>Replace</Menubar.Item>
                          <Menubar.Arrow />
                        </Menubar.SubContent>
                      </Menubar.Portal>
                    </Menubar.Sub>
                    <Menubar.Arrow />
                  </Menubar.SubContent>
                </Menubar.Portal>
              </Menubar.Sub>

              <Menubar.Separator className={styles.separator} />
              <Menubar.Item className={styles.item}>Cut</Menubar.Item>
              <Menubar.Item className={styles.item}>Copy</Menubar.Item>
              <Menubar.Item className={styles.item}>Paste</Menubar.Item>
            </Menubar.Content>
          </Menubar.Portal>
        </Menubar.Menu>
      </Menubar.Root>

      <h2 style={{ marginTop: 250 }}>RTL</h2>
      <div dir="rtl">
        <Menubar.Root value="edit" className={styles.root} dir="rtl">
          <Menubar.Menu value="file">
            <Menubar.Trigger className={styles.trigger}>File</Menubar.Trigger>
            <Menubar.Portal>
              <Menubar.Content className={styles.content} avoidCollisions={false} sideOffset={2}>
                <Menubar.Item className={styles.item}>New Tab</Menubar.Item>
                <Menubar.Item className={styles.item}>New Window</Menubar.Item>
                <Menubar.Item className={styles.item}>New Incognito Window</Menubar.Item>
                <Menubar.Separator className={styles.separator} />

                <Menubar.Item className={styles.item}>Print…</Menubar.Item>
              </Menubar.Content>
            </Menubar.Portal>
          </Menubar.Menu>

          <Menubar.Menu value="edit">
            <Menubar.Trigger className={styles.trigger}>Edit</Menubar.Trigger>
            <Menubar.Portal>
              <Menubar.Content className={styles.content} avoidCollisions={false} sideOffset={2}>
                <Menubar.Item className={styles.item} disabled>
                  Undo
                </Menubar.Item>
                <Menubar.Item className={styles.item}>Redo</Menubar.Item>
                <Menubar.Separator className={styles.separator} />
                <Menubar.Sub open>
                  <Menubar.SubTrigger className={subTriggerClass}>
                    Find <span>→</span>
                  </Menubar.SubTrigger>
                  <Menubar.Portal>
                    <Menubar.SubContent
                      className={styles.content}
                      sideOffset={10}
                      alignOffset={-6}
                      avoidCollisions={false}
                    >
                      <Menubar.Item className={styles.item}>Search the web…</Menubar.Item>
                      <Menubar.Separator className={styles.separator} />
                      <Menubar.Item className={styles.item}>Find…</Menubar.Item>
                      <Menubar.Item className={styles.item}>Find Next</Menubar.Item>
                      <Menubar.Item className={styles.item}>Find Previous</Menubar.Item>
                      <Menubar.Sub open>
                        <Menubar.SubTrigger className={subTriggerClass}>
                          Advanced <span>→</span>
                        </Menubar.SubTrigger>

                        <Menubar.Portal>
                          <Menubar.SubContent
                            className={styles.content}
                            sideOffset={10}
                            alignOffset={-6}
                            avoidCollisions={false}
                          >
                            <Menubar.Item className={styles.item}>Regex</Menubar.Item>
                            <Menubar.Item className={styles.item}>Replace</Menubar.Item>
                            <Menubar.Arrow />
                          </Menubar.SubContent>
                        </Menubar.Portal>
                      </Menubar.Sub>
                      <Menubar.Arrow />
                    </Menubar.SubContent>
                  </Menubar.Portal>
                </Menubar.Sub>

                <Menubar.Separator className={styles.separator} />
                <Menubar.Item className={styles.item}>Cut</Menubar.Item>
                <Menubar.Item className={styles.item}>Copy</Menubar.Item>
                <Menubar.Item className={styles.item}>Paste</Menubar.Item>
              </Menubar.Content>
            </Menubar.Portal>
          </Menubar.Menu>
        </Menubar.Root>
      </div>

      <h2 style={{ marginTop: 250 }}>With labels</h2>
      <Menubar.Root value="food" className={styles.root}>
        <Menubar.Menu value="food">
          <Menubar.Trigger className={styles.trigger}>Food</Menubar.Trigger>
          <Menubar.Portal>
            <Menubar.Content className={styles.content} avoidCollisions={false} sideOffset={2}>
              {foodGroups.map((foodGroup, index) => (
                <Menubar.Group key={index}>
                  {foodGroup.label && (
                    <Menubar.Label className={styles.label} key={foodGroup.label}>
                      {foodGroup.label}
                    </Menubar.Label>
                  )}
                  {foodGroup.foods.map((food) => (
                    <Menubar.Item
                      key={food.value}
                      className={styles.item}
                      disabled={food.disabled}
                      onSelect={() => console.log(food.label)}
                    >
                      {food.label}
                    </Menubar.Item>
                  ))}
                  {index < foodGroups.length - 1 && (
                    <Menubar.Separator className={styles.separator} />
                  )}
                </Menubar.Group>
              ))}
            </Menubar.Content>
          </Menubar.Portal>
        </Menubar.Menu>

        <Menubar.Menu value="edit">
          <Menubar.Trigger className={styles.trigger}>Edit</Menubar.Trigger>
          <Menubar.Portal>
            <Menubar.Content className={styles.content} avoidCollisions={false} sideOffset={2}>
              <Menubar.Item className={styles.item} disabled>
                Undo
              </Menubar.Item>
              <Menubar.Item className={styles.item}>Redo</Menubar.Item>
              <Menubar.Separator className={styles.separator} />
              <Menubar.Item className={styles.item}>Cut</Menubar.Item>
              <Menubar.Item className={styles.item}>Copy</Menubar.Item>
              <Menubar.Item className={styles.item}>Paste</Menubar.Item>
            </Menubar.Content>
          </Menubar.Portal>
        </Menubar.Menu>
      </Menubar.Root>

      <h2 style={{ marginTop: 600 }}>With checkbox and radio items</h2>
      <Menubar.Root value="items" className={styles.root}>
        <Menubar.Menu value="items">
          <Menubar.Trigger className={styles.trigger}>Items</Menubar.Trigger>
          <Menubar.Portal>
            <Menubar.Content className={styles.content} avoidCollisions={false} sideOffset={2}>
              <Menubar.Item className={styles.item} onSelect={() => console.log('show')}>
                Show fonts
              </Menubar.Item>
              <Menubar.Item className={styles.item} onSelect={() => console.log('bigger')}>
                Bigger
              </Menubar.Item>
              <Menubar.Item className={styles.item} onSelect={() => console.log('smaller')}>
                Smaller
              </Menubar.Item>
              <Menubar.Separator className={styles.separator} />
              {checkboxItems.map(({ label, state: [checked, setChecked], disabled }) => (
                <Menubar.CheckboxItem
                  key={label}
                  className={styles.item}
                  checked={checked}
                  onCheckedChange={setChecked}
                  disabled={disabled}
                >
                  {label}
                  <Menubar.ItemIndicator>
                    <TickIcon />
                  </Menubar.ItemIndicator>
                </Menubar.CheckboxItem>
              ))}
              <Menubar.Separator className={styles.separator} />
              <Menubar.RadioGroup value={file} onValueChange={setFile}>
                {files.map((file) => (
                  <Menubar.RadioItem key={file} className={styles.item} value={file}>
                    {file}
                    <Menubar.ItemIndicator>
                      <TickIcon />
                    </Menubar.ItemIndicator>
                  </Menubar.RadioItem>
                ))}
              </Menubar.RadioGroup>
            </Menubar.Content>
          </Menubar.Portal>
        </Menubar.Menu>

        <Menubar.Menu value="edit">
          <Menubar.Trigger className={styles.trigger}>Edit</Menubar.Trigger>
          <Menubar.Portal>
            <Menubar.Content className={styles.content} avoidCollisions={false} sideOffset={2}>
              <Menubar.Item className={styles.item} disabled>
                Undo
              </Menubar.Item>
              <Menubar.Item className={styles.item}>Redo</Menubar.Item>
              <Menubar.Separator className={styles.separator} />
              <Menubar.Item className={styles.item}>Cut</Menubar.Item>
              <Menubar.Item className={styles.item}>Copy</Menubar.Item>
              <Menubar.Item className={styles.item}>Paste</Menubar.Item>
            </Menubar.Content>
          </Menubar.Portal>
        </Menubar.Menu>
      </Menubar.Root>
    </div>
  );
};
Chromatic.parameters = { chromatic: { disable: false } };

const TickIcon = () => (
  <svg
    xmlns="http://www.w3.org/2000/svg"
    viewBox="0 0 32 32"
    width="12"
    height="12"
    fill="none"
    stroke="currentcolor"
    strokeLinecap="round"
    strokeLinejoin="round"
    strokeWidth="3"
  >
    <path d="M2 20 L12 28 30 4" />
  </svg>
);



================================================
FILE: apps/storybook/stories/navigation-menu.stories.module.css
================================================
.list {
  display: flex;
  flex-direction: column;
  gap: 14px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.borderdList {
  background-color: #f3f4f5;
  border: 1px solid #d4d6d8;
  padding: 25px;
  border-radius: 8px;
}

/* -----------------------------------------------------------------------------------------------*/

@keyframes navigationMenu-fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes navigationMenu-fadeOut {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}

@keyframes navigationMenu-scaleIn {
  from {
    transform: scale(0.9);
    opacity: 0;
  }
  to {
    transform: scale(1);
    opacity: 1;
  }
}

@keyframes navigationMenu-scaleOut {
  from {
    transform: scale(1);
    opacity: 1;
  }
  to {
    transform: scale(0.95);
    opacity: 0;
  }
}

@keyframes navigationMenu-enterFromRight {
  from {
    transform: translate3d(200px, 0, 0);
    opacity: 0;
  }
  to {
    transform: translate3d(0, 0, 0);
    opacity: 1;
  }
}

@keyframes navigationMenu-enterFromLeft {
  from {
    transform: translate3d(-200px, 0, 0);
    opacity: 0;
  }
  to {
    transform: translate3d(0, 0, 0);
    opacity: 1;
  }
}

@keyframes navigationMenu-exitToRight {
  from {
    transform: translate3d(0, 0, 0);
    opacity: 1;
  }
  to {
    transform: translate3d(200px, 0, 0);
    opacity: 0;
  }
}

@keyframes navigationMenu-exitToLeft {
  from {
    transform: translate3d(0, 0, 0);
    opacity: 1;
  }
  to {
    transform: translate3d(-200px, 0, 0);
    opacity: 0;
  }
}

/* -----------------------------------------------------------------------------------------------*/

.mainList {
  all: unset;
  list-style: none;
  display: flex;

  &[data-orientation='vertical'] {
    flex-direction: column;
  }
}

.expandableItem {
  position: relative;
}

.trigger,
.link,
.submenusSubTrigger {
  padding: 10px 16px;
  font-weight: bold;
}

.trigger {
  display: flex;
  align-items: center;
  border: 0;
  background: transparent;
  font-size: inherit;
  gap: 4px;

  & > svg {
    transition: transform 200ms ease;
  }

  &[data-state='open'] > svg {
    transform: rotate(-180deg);
  }
}

.link {
  color: inherit;
  text-decoration: none;
  display: block;
}

/* -----------------------------------------------------------------------------------------------*/

.basicContent {
  position: absolute;
  top: 100%;
  width: max-content;
  left: 0;
  margin-top: 5px;
  gap: 20px;
  border-radius: 10px;
  background-color: white;
  padding: 20px;
  transform-origin: top left;
  box-shadow:
    0 10px 100px -20px rgba(50, 50, 93, 0.25),
    0 30px 60px -30px rgba(0, 0, 0, 0.3);
  z-index: 1;

  [dir='rtl'] & {
    left: unset;
    right: 0;
    transform-origin: top right;
  }

  &[data-state='open'] {
    animation: navigationMenu-scaleIn 250ms ease;
  }
  &[data-state='closed'] {
    animation: navigationMenu-scaleOut 250ms ease;
  }
}

/* -----------------------------------------------------------------------------------------------*/

.viewportIndicator {
  display: flex;
  justify-content: center;
  height: 10px;
  bottom: -30px;
  z-index: 1;
  transition:
    transform,
    width,
    250ms ease;
  overflow: hidden;

  &[data-state='visible'] {
    animation: navigationMenu-fadeIn 250ms ease;
  }
  &[data-state='hidden'] {
    animation: navigationMenu-fadeOut 250ms ease;
  }
}

.viewportInnerIndicator {
  position: relative;
  top: 4px;
  width: 20px;
  height: 20px;
  background-color: white;
  transform: rotate(45deg);
  border-radius: 3px;
}

.viewportViewport {
  position: relative;
  background-color: white;
  transition:
    width,
    height,
    300ms ease;
  width: var(--radix-navigation-menu-viewport-width);
  height: var(--radix-navigation-menu-viewport-height);
  transform-origin: top center;
  overflow: hidden;
  margin-top: 15px;
  border-radius: 8px;
  box-shadow:
    0 50px 100px -20px rgba(50, 50, 93, 0.25),
    0 30px 60px -30px rgba(0, 0, 0, 0.3);
  &[data-state='open'] {
    animation: navigationMenu-scaleIn 300ms ease;
  }
  &[data-state='closed'] {
    animation: navigationMenu-scaleOut 300ms ease;
  }
}

.viewportContent {
  position: absolute;
  top: 0;
  left: 0;
  display: grid;
  gap: 20px;
  padding: 40px;

  &[data-motion='from-start'] {
    animation: navigationMenu-enterFromLeft 250ms ease;
  }
  &[data-motion='from-end'] {
    animation: navigationMenu-enterFromRight 250ms ease;
  }
  &[data-motion='to-start'] {
    animation: navigationMenu-exitToLeft 250ms ease;
  }
  &[data-motion='to-end'] {
    animation: navigationMenu-exitToRight 250ms ease;
  }
}

/* -----------------------------------------------------------------------------------------------*/

.submenusRoot {
  display: grid;
  width: 100%;
  max-width: 800px;
  gap: 20px;

  &[data-orientation='vertical'] {
    grid-template-columns: 0.3fr 1fr;
  }

  &[data-orientation='horizontal'] {
    justify-items: center;
    margin-top: -10px;
  }
}

.submenusViewport {
  position: absolute;
  left: 0;
  top: 100%;
  border-top: 1px solid #dcdfe3;
  transform-origin: top center;
  width: 100vw;
  background-color: white;
  height: var(--radix-navigation-menu-viewport-height);
  transition: height 300ms ease;
  overflow: hidden;
  box-shadow:
    0 50px 100px -20px rgba(50, 50, 93, 0.1),
    0 30px 60px -30px rgba(0, 0, 0, 0.2);

  &[data-state='open'] {
    animation: navigationMenu-fadeIn 250ms ease;
  }
  &[data-state='closed'] {
    animation: navigationMenu-fadeOut 250ms ease;
  }
}

.submenusContent {
  display: flex;
  justify-content: center;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  padding-top: 35px;
  padding-bottom: 35px;
  &[data-motion='from-start'] {
    animation: navigationMenu-enterFromLeft 250ms ease;
  }
  &[data-motion='from-end'] {
    animation: navigationMenu-enterFromRight 250ms ease;
  }
  &[data-motion='to-start'] {
    animation: navigationMenu-exitToLeft 250ms ease;
  }
  &[data-motion='to-end'] {
    animation: navigationMenu-exitToRight 250ms ease;
  }
}

.submenusSubContent {
  display: grid;
  gap: 20px;
  width: 100%;
}

.submenusSubViewport {
  width: 100%;
}

.submenusSubTrigger {
  position: relative;
  display: flex;
  align-items: center;
  border: 0;
  background: transparent;
  font-size: inherit;
  width: 100%;
  border-radius: 4px;
  &[data-state='open'] {
    background-color: #f3f4f5;
  }
}

.submenusSubIndicator {
  background-color: black;
  border-radius: 4px;

  &[data-orientation='vertical'] {
    width: 3px;
    transition:
      transform,
      height,
      250ms ease;
    [dir='ltr'] & {
      right: 0;
    }
    [dir='rtl'] {
      left: 0;
    }
  }

  &[data-orientation='horizontal'] {
    height: 3px;
    bottom: 0;
    transition:
      transform,
      width,
      250ms ease;
  }
}



================================================
FILE: apps/storybook/stories/navigation-menu.stories.tsx
================================================
import * as React from 'react';
import { NavigationMenu, Direction } from 'radix-ui';
import styles from './navigation-menu.stories.module.css';

export default { title: 'Components/NavigationMenu' };

export const Basic = () => {
  return (
    <StoryFrame>
      <NavigationMenu.Root>
        <NavigationMenu.List className={styles.mainList}>
          <NavigationMenu.Item className={styles.expandableItem}>
            <TriggerWithIndicator>Products</TriggerWithIndicator>
            <NavigationMenu.Content className={styles.basicContent}>
              <LinkGroup
                bordered={false}
                items={[
                  'Fusce pellentesque',
                  'Aliquam porttitor',
                  'Pellentesque',
                  'Fusce pellentesque',
                  'Aliquam porttitor',
                  'Pellentesque',
                ]}
              />
            </NavigationMenu.Content>
          </NavigationMenu.Item>

          <NavigationMenu.Item className={styles.expandableItem}>
            <TriggerWithIndicator>Company</TriggerWithIndicator>
            <NavigationMenu.Content className={styles.basicContent}>
              <LinkGroup
                bordered={false}
                items={['Fusce pellentesque', 'Aliquam porttitor', 'Pellentesque']}
              />
            </NavigationMenu.Content>
          </NavigationMenu.Item>

          <NavigationMenu.Item className={styles.expandableItem}>
            <TriggerWithIndicator disabled>Developers</TriggerWithIndicator>
            <NavigationMenu.Content className={styles.basicContent}>
              <LinkGroup bordered={false} items={['Aliquam porttitor', 'Pellentesque']} />
            </NavigationMenu.Content>
          </NavigationMenu.Item>

          <NavigationMenu.Item>
            <NavigationMenu.Link href="#example" className={styles.link}>
              Link
            </NavigationMenu.Link>
          </NavigationMenu.Item>
        </NavigationMenu.List>
      </NavigationMenu.Root>
    </StoryFrame>
  );
};

export const CustomDurations = () => {
  return (
    <div
      style={{
        minHeight: '100vh',
        backgroundColor: '#e5e8eb',
        paddingBottom: 150,
        display: 'flex',
        flexDirection: 'column',
        alignItems: 'center',
      }}
    >
      <h1>Delay duration</h1>
      <h2>Default (200ms)</h2>
      <DurationNavigation />

      <h2>Custom (0ms = instant open)</h2>
      <DurationNavigation delayDuration={0} />

      <h2>Custom (700ms)</h2>
      <DurationNavigation delayDuration={700} />

      <h1 style={{ marginTop: 50 }}>Skip delay duration</h1>
      <h2>Default (300ms to move from one trigger to another)</h2>
      <DurationNavigation />

      <h2>Custom (0ms to move from one trigger to another = never skip)</h2>
      <DurationNavigation skipDelayDuration={0} />

      <h2>Custom (2000ms to move from one trigger to another)</h2>
      <DurationNavigation delayDuration={500} skipDelayDuration={2000} />
    </div>
  );
};

export const Viewport = () => {
  return (
    <StoryFrame>
      <NavigationMenu.Root>
        <NavigationMenu.List className={styles.mainList}>
          <NavigationMenu.Item>
            <TriggerWithIndicator>Products</TriggerWithIndicator>
            <NavigationMenu.Content
              className={styles.viewportContent}
              style={{
                gridTemplateColumns: '1fr 2fr',
                width: 600,
              }}
            >
              <LinkGroup
                items={[
                  'Fusce pellentesque',
                  'Aliquam porttitor',
                  'Pellentesque',
                  'Fusce pellentesque',
                  'Aliquam porttitor',
                  'Pellentesque',
                ]}
              />

              <LinkGroup items={['Fusce pellentesque', 'Aliquam porttitor', 'Pellentesque']} />
            </NavigationMenu.Content>
          </NavigationMenu.Item>

          <NavigationMenu.Item>
            <TriggerWithIndicator>Company</TriggerWithIndicator>
            <NavigationMenu.Content
              className={styles.viewportContent}
              style={{
                gridTemplateColumns: '1fr 1fr',
                width: 450,
              }}
            >
              <LinkGroup
                items={[
                  'Fusce pellentesque',
                  'Aliquam porttitor',
                  'Pellentesque',
                  'Aliquam porttitor',
                ]}
              />

              <LinkGroup items={['Fusce pellentesque', 'Aliquam porttitor', 'Pellentesque']} />
            </NavigationMenu.Content>
          </NavigationMenu.Item>

          <NavigationMenu.Item>
            <TriggerWithIndicator disabled>Developers</TriggerWithIndicator>
            <NavigationMenu.Content
              className={styles.viewportContent}
              style={{
                gridTemplateColumns: '1.6fr 1fr',
                width: 650,
              }}
            >
              <LinkGroup items={['Donec quis dui', 'Vestibulum']} />
              <LinkGroup items={['Fusce pellentesque', 'Aliquam porttitor']} />
            </NavigationMenu.Content>
          </NavigationMenu.Item>

          <NavigationMenu.Item>
            <NavigationMenu.Link href="#example" className={styles.link}>
              Link
            </NavigationMenu.Link>
          </NavigationMenu.Item>

          <NavigationMenu.Indicator className={styles.viewportIndicator}>
            <div className={styles.viewportInnerIndicator} />
          </NavigationMenu.Indicator>
        </NavigationMenu.List>

        <div
          style={{
            position: 'absolute',
            display: 'flex',
            justifyContent: 'center',
            width: '100%',
            top: '100%',
            left: 0,
          }}
        >
          <NavigationMenu.Viewport className={styles.viewportViewport} />
        </div>
      </NavigationMenu.Root>
    </StoryFrame>
  );
};

export const Submenus = () => {
  return (
    <StoryFrame>
      <NavigationMenu.Root>
        <NavigationMenu.List className={styles.mainList}>
          <NavigationMenu.Item>
            <TriggerWithIndicator>Products</TriggerWithIndicator>
            <NavigationMenu.Content className={styles.submenusContent}>
              <NavigationMenu.Sub className={styles.submenusRoot} defaultValue="extensibility">
                <NavigationMenu.List className={styles.mainList}>
                  <NavigationMenu.Item value="extensibility">
                    <NavigationMenu.Trigger className={styles.submenusSubTrigger}>
                      Extensibility
                    </NavigationMenu.Trigger>

                    <NavigationMenu.Content
                      className={styles.submenusSubContent}
                      style={{
                        gridTemplateColumns: '1.5fr 1fr 1fr',
                      }}
                    >
                      <LinkGroup items={['Donec quis dui', 'Vestibulum', 'Nunc dignissim']} />
                      <LinkGroup
                        items={['Fusce pellentesque', 'Aliquam porttitor', 'Pellentesque']}
                      />
                      <LinkGroup
                        items={['Fusce pellentesque', 'Aliquam porttitor', 'Pellentesque']}
                      />
                    </NavigationMenu.Content>
                  </NavigationMenu.Item>

                  <NavigationMenu.Item value="security">
                    <NavigationMenu.Trigger className={styles.submenusSubTrigger}>
                      Security
                    </NavigationMenu.Trigger>
                    <NavigationMenu.Content
                      className={styles.submenusSubContent}
                      style={{
                        gridTemplateColumns: '1fr 1fr 1fr',
                      }}
                    >
                      <LinkGroup
                        items={[
                          'Fusce pellentesque',
                          'Aliquam porttitor',
                          'Pellentesque',
                          'Vestibulum',
                        ]}
                      />
                      <LinkGroup
                        items={['Fusce pellentesque', 'Aliquam porttitor', 'Pellentesque']}
                      />
                      <LinkGroup items={['Fusce pellentesque', 'Aliquam porttitor']} />
                    </NavigationMenu.Content>
                  </NavigationMenu.Item>

                  <NavigationMenu.Item value="authentication">
                    <NavigationMenu.Trigger className={styles.submenusSubTrigger}>
                      Authentication
                    </NavigationMenu.Trigger>

                    <NavigationMenu.Content
                      className={styles.submenusSubContent}
                      style={{
                        gridTemplateColumns: '1.5fr 1fr 1fr',
                      }}
                    >
                      <LinkGroup items={['Donec quis dui', 'Vestibulum', 'Nunc dignissim']} />
                      <LinkGroup
                        items={['Fusce pellentesque', 'Aliquam porttitor', 'Pellentesque']}
                      />
                      <LinkGroup
                        items={['Fusce pellentesque', 'Aliquam porttitor', 'Pellentesque']}
                      />
                    </NavigationMenu.Content>
                  </NavigationMenu.Item>

                  <NavigationMenu.Indicator className={styles.submenusSubIndicator} />
                </NavigationMenu.List>

                <NavigationMenu.Viewport className={styles.submenusSubViewport} />
              </NavigationMenu.Sub>
            </NavigationMenu.Content>
          </NavigationMenu.Item>

          <NavigationMenu.Item>
            <TriggerWithIndicator>Company</TriggerWithIndicator>
            <NavigationMenu.Content className={styles.submenusContent}>
              <NavigationMenu.Sub
                className={styles.submenusRoot}
                orientation="vertical"
                defaultValue="customers"
              >
                <NavigationMenu.List className={styles.mainList}>
                  <NavigationMenu.Item value="customers">
                    <NavigationMenu.Trigger className={styles.submenusSubTrigger}>
                      Customers
                    </NavigationMenu.Trigger>

                    <NavigationMenu.Content
                      className={styles.submenusSubContent}
                      style={{
                        gridTemplateColumns: '1.5fr 1fr',
                      }}
                    >
                      <LinkGroup items={['Donec quis dui', 'Vestibulum', 'Nunc dignissim']} />
                      <LinkGroup
                        items={['Fusce pellentesque', 'Aliquam porttitor', 'Pellentesque']}
                      />
                    </NavigationMenu.Content>
                  </NavigationMenu.Item>

                  <NavigationMenu.Item value="partners">
                    <NavigationMenu.Trigger className={styles.submenusSubTrigger}>
                      Partners
                    </NavigationMenu.Trigger>
                    <NavigationMenu.Content
                      className={styles.submenusSubContent}
                      style={{
                        gridTemplateColumns: '1fr 1fr',
                      }}
                    >
                      <LinkGroup
                        items={[
                          'Fusce pellentesque',
                          'Aliquam porttitor',
                          'Pellentesque',
                          'Vestibulum',
                        ]}
                      />
                      <LinkGroup
                        items={['Fusce pellentesque', 'Aliquam porttitor', 'Pellentesque']}
                      />
                    </NavigationMenu.Content>
                  </NavigationMenu.Item>

                  <NavigationMenu.Item value="enterprise">
                    <NavigationMenu.Trigger className={styles.submenusSubTrigger}>
                      Enterprise
                    </NavigationMenu.Trigger>

                    <NavigationMenu.Content
                      className={styles.submenusSubContent}
                      style={{
                        gridTemplateColumns: '1.5fr 1fr',
                      }}
                    >
                      <LinkGroup items={['Donec quis dui', 'Vestibulum', 'Nunc dignissim']} />
                      <LinkGroup
                        items={['Fusce pellentesque', 'Aliquam porttitor', 'Pellentesque']}
                      />
                    </NavigationMenu.Content>
                  </NavigationMenu.Item>

                  <NavigationMenu.Indicator className={styles.submenusSubIndicator} />
                </NavigationMenu.List>

                <NavigationMenu.Viewport className={styles.submenusSubViewport} />
              </NavigationMenu.Sub>
            </NavigationMenu.Content>
          </NavigationMenu.Item>

          <NavigationMenu.Item>
            <TriggerWithIndicator disabled>Developers</TriggerWithIndicator>
            <NavigationMenu.Content
              className={styles.submenusSubContent}
              style={{ gridTemplateColumns: '1fr 1fr' }}
            >
              <LinkGroup items={['Donec quis dui', 'Vestibulum']} />
              <LinkGroup items={['Fusce pellentesque', 'Aliquam porttitor']} />
            </NavigationMenu.Content>
          </NavigationMenu.Item>

          <NavigationMenu.Item>
            <NavigationMenu.Link href="#example" className={styles.link}>
              Link
            </NavigationMenu.Link>
          </NavigationMenu.Item>
        </NavigationMenu.List>

        <NavigationMenu.Viewport className={styles.submenusViewport} />
      </NavigationMenu.Root>
    </StoryFrame>
  );
};

/* -----------------------------------------------------------------------------------------------*/

const StoryFrame: React.FC<{ children: React.ReactNode }> = ({ children }) => {
  const [rtl, setRtl] = React.useState(false);

  return (
    <div style={{ height: '100vh', backgroundColor: '#e5e8eb' }}>
      <div style={{ display: 'flex', justifyContent: 'center', paddingTop: 20, paddingBottom: 30 }}>
        <label>
          <input
            type="checkbox"
            checked={rtl}
            onChange={(event) => setRtl(event.currentTarget.checked)}
          />
          Right-to-left
        </label>
      </div>
      <Direction.Provider dir={rtl ? 'rtl' : 'ltr'}>
        <div dir={rtl ? 'rtl' : 'ltr'}>
          <div
            style={{
              position: 'relative',
              display: 'flex',
              boxSizing: 'border-box',
              alignItems: 'center',
              padding: '15px 20px',
              justifyContent: 'space-between',
              width: '100%',
              backgroundColor: 'white',
              boxShadow: '0 50px 100px -20px rgba(50,50,93,0.1),0 30px 60px -30px rgba(0,0,0,0.2)',
            }}
          >
            <button>Logo</button>
            {children}
            <button>Login</button>
          </div>
          <div style={{ maxWidth: 800, margin: 'auto', lineHeight: 1.5, paddingTop: 25 }}>
            <h2>Test page content</h2>
            <p>
              Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam purus odio, vestibulum
              in dictum et, <a href="#example">sagittis vel nibh</a>. Fusce placerat arcu lorem, a
              scelerisque odio fringilla sit amet. Suspendisse volutpat sed diam ut cursus. Nulla
              facilisi. Ut at volutpat nibh. Nullam justo mi, elementum vitae ex eu,{' '}
              <a href="#example">gravida dictum metus</a>. Morbi vulputate consectetur cursus. Fusce
              vitae nisi nunc. Suspendisse pellentesque aliquet tincidunt. Aenean molestie pulvinar
              ipsum.
            </p>

            <button>Button</button>
          </div>
        </div>
      </Direction.Provider>
    </div>
  );
};

const DurationNavigation = (props: React.ComponentProps<typeof NavigationMenu.Root>) => {
  return (
    <NavigationMenu.Root
      {...props}
      style={{ backgroundColor: 'white', borderRadius: 500, padding: '2px 12px', ...props.style }}
    >
      <NavigationMenu.List className={styles.mainList}>
        <NavigationMenu.Item className={styles.expandableItem}>
          <TriggerWithIndicator>Products</TriggerWithIndicator>
          <NavigationMenu.Content className={styles.basicContent}>
            <LinkGroup
              bordered={false}
              items={['Fusce pellentesque', 'Aliquam porttitor', 'Pellentesque']}
            />
          </NavigationMenu.Content>
        </NavigationMenu.Item>

        <NavigationMenu.Item className={styles.expandableItem}>
          <TriggerWithIndicator>Company</TriggerWithIndicator>
          <NavigationMenu.Content className={styles.basicContent}>
            <LinkGroup
              bordered={false}
              items={['Fusce pellentesque', 'Aliquam porttitor', 'Pellentesque']}
            />
          </NavigationMenu.Content>
        </NavigationMenu.Item>

        <NavigationMenu.Item className={styles.expandableItem}>
          <TriggerWithIndicator>Developers</TriggerWithIndicator>
          <NavigationMenu.Content className={styles.basicContent}>
            <LinkGroup
              bordered={false}
              items={['Fusce pellentesque', 'Aliquam porttitor', 'Pellentesque']}
            />
          </NavigationMenu.Content>
        </NavigationMenu.Item>

        <NavigationMenu.Item className={styles.expandableItem}>
          <TriggerWithIndicator>About</TriggerWithIndicator>
          <NavigationMenu.Content className={styles.basicContent}>
            <LinkGroup
              bordered={false}
              items={['Fusce pellentesque', 'Aliquam porttitor', 'Pellentesque']}
            />
          </NavigationMenu.Content>
        </NavigationMenu.Item>
      </NavigationMenu.List>
    </NavigationMenu.Root>
  );
};

const TriggerWithIndicator: React.FC<{ children?: React.ReactNode; disabled?: boolean }> = ({
  children,
  disabled,
}) => {
  return (
    <NavigationMenu.Trigger className={styles.trigger} disabled={disabled}>
      {children}
      <CaretDownIcon />
    </NavigationMenu.Trigger>
  );
};

const CaretDownIcon = () => (
  <svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
    <path
      d="M4.18179 6.18181C4.35753 6.00608 4.64245 6.00608 4.81819 6.18181L7.49999 8.86362L10.1818 6.18181C10.3575 6.00608 10.6424 6.00608 10.8182 6.18181C10.9939 6.35755 10.9939 6.64247 10.8182 6.81821L7.81819 9.81821C7.73379 9.9026 7.61934 9.95001 7.49999 9.95001C7.38064 9.95001 7.26618 9.9026 7.18179 9.81821L4.18179 6.81821C4.00605 6.64247 4.00605 6.35755 4.18179 6.18181Z"
      fill="currentColor"
      fillRule="evenodd"
      clipRule="evenodd"
    ></path>
  </svg>
);

const LinkGroup: React.FC<{ items: string[]; bordered?: boolean }> = ({
  items,
  bordered = true,
}) => {
  return (
    <ul className={[bordered && styles.borderdList, styles.list].filter(Boolean).join(' ')}>
      {items.map((item, i) => (
        <li key={i}>
          <NavigationMenu.Link
            href="#example"
            style={{
              display: 'flex',
              alignItems: 'center',
              color: 'black',
            }}
          >
            {item}
          </NavigationMenu.Link>
        </li>
      ))}
    </ul>
  );
};



================================================
FILE: apps/storybook/stories/one-time-password-field.stories.module.css
================================================
.viewport {
  display: flex;
  flex-direction: column;
  height: 100vh;
  width: 100vw;
  justify-content: center;
  align-items: center;
}

.form {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.field {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.selectField {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

.otpRoot {
  display: flex;
  gap: 0.5rem;
  align-items: center;
}

:where(.otpRoot) input:not([type='hidden']) {
  --border-color: #ddd;
  --focus-ring-color: dodgerblue;
  height: 3rem;
  width: 2rem;
  text-align: center;
  font-size: 1em;
  padding: 0;
  box-shadow: none;
  border: 2px solid var(--border-color);
  border-radius: 4px;
}

:where(.otpRoot[data-state='invalid']) input:not([type='hidden']) {
  --focus-ring-color: tomato;
  --border-color: crimson;
}

:where(.otpRoot[data-state='valid']) input:not([type='hidden']) {
  --focus-ring-color: limegreen;
  --border-color: green;
}

:where(.otpRoot[data-state='valid']) input:focus {
  outline: 2px solid var(--focus-ring-color);
  outline-offset: 0;
}

.errorMessage {
}

.separator {
  height: calc(100% - 8px);
  width: 1px;
  background-color: #ddd;
}

.output {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  align-items: center;
  justify-content: center;
  font-family: monospace;
  padding: 1rem;
  background-color: var(--gray-4);
  border: 1px solid var(--gray-6);
  border-radius: 4px;

  &:where([data-state='valid']) {
    background-color: var(--green-5);
    border-color: var(--green-6);
  }

  &:where([data-state='invalid']) {
    background-color: var(--red-5);
    border-color: var(--red-6);
  }
}



================================================
FILE: apps/storybook/stories/one-time-password-field.stories.tsx
================================================
import * as React from 'react';
import { unstable_OneTimePasswordField as OneTimePasswordField, Separator } from 'radix-ui';
import { Dialog as DialogPrimitive } from 'radix-ui';
import dialogStyles from './dialog.stories.module.css';
import type { Meta, StoryObj } from '@storybook/react-webpack5';
import { userEvent, within, expect } from 'storybook/test';
import styles from './one-time-password-field.stories.module.css';

export default {
  title: 'Components/OneTimePasswordField',
} satisfies Meta<typeof OneTimePasswordField.Root>;

type Story = StoryObj<typeof OneTimePasswordField.Root>;

type FormState = { type: 'idle' } | { type: 'valid' } | { type: 'invalid'; error: string };

const VALID_CODE = '123456';

const sharedStoryProps = {
  argTypes: {
    placeholder: {
      control: { type: 'text' },
    },
    validationType: {
      options: ['numeric', 'alphanumeric', 'alpha', 'none'],
      control: { type: 'select' },
    },
    autoFocus: {
      control: { type: 'boolean' },
    },
    autoSubmit: {
      control: { type: 'boolean' },
    },
  },
} satisfies Story;

export const Uncontrolled = {
  ...sharedStoryProps,
  render: (args) => <UncontrolledImpl {...args} />,
} satisfies Story;

function UncontrolledImpl(props: OneTimePasswordField.OneTimePasswordFieldProps) {
  const [showSuccessMessage, setShowSuccessMessage] = React.useState(false);
  const rootRef = React.useRef<HTMLDivElement | null>(null);
  const [formState, setFormState] = React.useState<FormState>({ type: 'idle' });

  return (
    <div className={styles.viewport}>
      <form
        className={styles.form}
        onSubmit={(event) => {
          const formData = new FormData(event.currentTarget);
          const code = formData.get('code') as string;
          event.preventDefault();
          if (code.length === VALID_CODE.length && code !== VALID_CODE) {
            setFormState({ type: 'invalid', error: 'Invalid code' });
          }
          //
          else if (code.length !== VALID_CODE.length) {
            setFormState({ type: 'invalid', error: 'Please fill in all fields' });
          }
          //
          else if (Math.random() > 0.675) {
            setFormState({ type: 'invalid', error: 'Server error' });
          }
          //
          else {
            setFormState({ type: 'valid' });
            setShowSuccessMessage(true);
          }
        }}
      >
        <div className={styles.field}>
          <OneTimePasswordField.Root
            data-state={formState.type}
            className={styles.otpRoot}
            ref={rootRef}
            {...props}
          >
            <OneTimePasswordField.Input />
            <Separator.Root orientation="vertical" className={styles.separator} />
            <OneTimePasswordField.Input />
            <Separator.Root orientation="vertical" className={styles.separator} />
            <OneTimePasswordField.Input />
            <Separator.Root orientation="vertical" className={styles.separator} />
            <OneTimePasswordField.Input />
            <Separator.Root orientation="vertical" className={styles.separator} />
            <OneTimePasswordField.Input />
            <Separator.Root orientation="vertical" className={styles.separator} />
            <OneTimePasswordField.Input />

            <OneTimePasswordField.HiddenInput name="code" />
          </OneTimePasswordField.Root>
          {formState.type === 'invalid' && <ErrorMessage>{formState.error}</ErrorMessage>}
        </div>
        <button type="reset">Reset form</button>
        <button>Submit</button>
      </form>
      <Dialog
        open={showSuccessMessage}
        onOpenChange={setShowSuccessMessage}
        title="Password match"
        content="Success!"
      />
    </div>
  );
}

export const Controlled = {
  ...sharedStoryProps,
  render: (args) => <ControlledImpl {...args} />,
} satisfies Story;

function ControlledImpl(props: OneTimePasswordField.OneTimePasswordFieldProps) {
  const [error, setError] = React.useState<string | null>(null);
  const [code, setCode] = React.useState('');
  const [showSuccessMessage, setShowSuccessMessage] = React.useState(false);
  const rootRef = React.useRef<HTMLDivElement | null>(null);
  const VALID_CODE = '123456';
  const isInvalid = code.length === VALID_CODE.length ? code !== VALID_CODE : false;
  const isValid = code.length === VALID_CODE.length ? code === VALID_CODE : false;
  return (
    <div className={styles.viewport}>
      <form
        className={styles.form}
        onSubmit={(event) => {
          event.preventDefault();
          if (isInvalid) {
            setError('Invalid code');
          }

          //
          else if (code.length !== VALID_CODE.length) {
            setError('Please fill in all fields');
          }

          //
          else if (Math.random() > 0.675) {
            setError('Server error');
          }

          //
          else {
            setShowSuccessMessage(true);
          }
        }}
      >
        <div className={styles.field}>
          <OneTimePasswordField.Root
            data-state={error || isInvalid ? 'invalid' : isValid ? 'valid' : undefined}
            className={styles.otpRoot}
            ref={rootRef}
            onValueChange={(value) => setCode(value)}
            value={code}
            {...props}
          >
            <OneTimePasswordField.Input />
            <Separator.Root orientation="vertical" className={styles.separator} />
            <OneTimePasswordField.Input />
            <Separator.Root orientation="vertical" className={styles.separator} />
            <OneTimePasswordField.Input />
            <Separator.Root orientation="vertical" className={styles.separator} />
            <OneTimePasswordField.Input />
            <Separator.Root orientation="vertical" className={styles.separator} />
            <OneTimePasswordField.Input />
            <Separator.Root orientation="vertical" className={styles.separator} />
            <OneTimePasswordField.Input />

            <OneTimePasswordField.HiddenInput name="code" />
          </OneTimePasswordField.Root>
          {error && <ErrorMessage>{error}</ErrorMessage>}
        </div>
        <button type="button" onClick={() => setCode('')}>
          Reset state
        </button>
        <button type="reset">Reset form</button>
        <button>Submit</button>
        <output
          data-state={error || isInvalid ? 'invalid' : isValid ? 'valid' : undefined}
          className={styles.output}
        >
          {code || 'code'}
        </output>
      </form>
      <Dialog
        open={showSuccessMessage}
        onOpenChange={setShowSuccessMessage}
        title="Password match"
        content="Success!"
      />
    </div>
  );
}

export const PastedAndDeletedControlled: Story = {
  render: (args) => <ControlledImpl {...args} />,
  name: 'Pasted and deleted (controlled test)',
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    const inputs = canvas.getAllByRole<HTMLInputElement>('textbox', {
      hidden: false,
    });

    const firstInput = inputs[0]!;
    expect(firstInput).toBeInTheDocument();
    await userEvent.click(firstInput);
    await userEvent.paste('123123');
    expect(getInputValues(inputs)).toBe('1,2,3,1,2,3');
    await userEvent.keyboard('{backspace}{backspace}{backspace}{backspace}{backspace}');
    expect(getInputValues(inputs)).toBe('1,,,,,');
    await userEvent.keyboard('{backspace}');
    expect(getInputValues(inputs)).toBe(',,,,,');
  },
};

export const PastedAndDeletedUncontrolled: Story = {
  render: (args) => <UncontrolledImpl {...args} />,
  name: 'Pasted and deleted (uncontrolled test)',
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    const inputs = canvas.getAllByRole<HTMLInputElement>('textbox', {
      hidden: false,
    });

    const firstInput = inputs[0]!;
    expect(firstInput).toBeInTheDocument();
    await userEvent.click(firstInput);
    await userEvent.paste('123123');
    expect(getInputValues(inputs)).toBe('1,2,3,1,2,3');
    await userEvent.keyboard('{backspace}{backspace}{backspace}{backspace}{backspace}');
    expect(getInputValues(inputs)).toBe('1,,,,,');
    await userEvent.keyboard('{backspace}');
    // With the current bug, the actual behavior is 1,2,3,1,2,3
    expect(getInputValues(inputs)).toBe(',,,,,');

    // if we keep deleting while the first input is focused, we eventually get ,2,3,1,2,3
  },
};

function ErrorMessage({ children }: { children: string }) {
  return <div className={styles.errorMessage}>{children}</div>;
}

function Dialog({
  trigger,
  title = 'Hello!',
  content,
  open,
  onOpenChange,
}: {
  title?: string;
  content: string;
  trigger?: React.ReactNode;
  open: boolean;
  onOpenChange: (open: boolean) => void;
}) {
  const lastFocusedRef = React.useRef<HTMLElement | null>(null);
  React.useLayoutEffect(() => {
    lastFocusedRef.current = document.activeElement as HTMLElement;
  }, []);
  return (
    <DialogPrimitive.Root open={open} onOpenChange={onOpenChange}>
      {trigger}
      <DialogPrimitive.Portal>
        <DialogPrimitive.Overlay className={dialogStyles.overlay} />
        <DialogPrimitive.Content className={dialogStyles.contentDefault}>
          <DialogPrimitive.Title>{title}</DialogPrimitive.Title>
          <DialogPrimitive.Description>{content}</DialogPrimitive.Description>
          <DialogPrimitive.Close className={dialogStyles.close}>close</DialogPrimitive.Close>
        </DialogPrimitive.Content>
      </DialogPrimitive.Portal>
    </DialogPrimitive.Root>
  );
}

function getInputValues(inputs: HTMLInputElement[]) {
  return inputs.map((input) => input.value).join(',');
}



================================================
FILE: apps/storybook/stories/password-toggle-field.stories.module.css
================================================
.viewport {
  --easing: cubic-bezier(0.165, 0.84, 0.44, 1);
  display: flex;
  flex-direction: column;
  height: 100vh;
  width: 100vw;
  justify-content: center;
  align-items: center;

  margin: 0;
  padding: 24px;
  font-family:
    system-ui,
    -apple-system,
    BlinkMacSystemFont,
    'Segoe UI',
    Roboto,
    Oxygen,
    Ubuntu,
    Cantarell,
    'Open Sans',
    'Helvetica Neue',
    sans-serif;
  font-size: 14px;
}

.field {
  --_field-height: 1.75rem;
  display: flex;
  width: 300px;
  max-width: 100%;
  border: 1px solid #ddd;
  height: var(--_field-height);
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
}

.field:has(.input:focus) {
  outline: 1px solid dodgerblue;
  border-color: dodgerblue;
}

.input {
  all: unset;
  flex: 1 1 auto;
  height: 100%;
  vertical-align: center;
  padding: 0 0.5rem;
}

.toggle {
  all: unset;
  height: var(--_field-height);
  aspect-ratio: 1;
  flex: 0 0 var(--_field-height);
  display: flex;
  align-items: center;
  justify-content: center;
}

.toggle:focus-visible {
  outline: 2px solid dodgerblue;
  outline-offset: -4px;
}



================================================
FILE: apps/storybook/stories/password-toggle-field.stories.tsx
================================================
import * as React from 'react';
import type { Meta, StoryObj } from '@storybook/react-webpack5';
import { useArgs } from 'storybook/preview-api';
import { unstable_PasswordToggleField as PasswordToggleField } from 'radix-ui';
import styles from './password-toggle-field.stories.module.css';

export default {
  title: 'Components/PasswordToggleField',
  component: PasswordToggleField.Root,
} satisfies Meta<typeof PasswordToggleField.Root>;

type Story = StoryObj<typeof PasswordToggleField.Root>;
type StoryArgs = Exclude<Story['args'], undefined>;

export const Uncontrolled = {
  argTypes: {
    children: { table: { disable: true } },
    defaultVisible: { table: { disable: true } },
    visible: { table: { disable: true } },
  },
  render: function Uncontrolled(args) {
    return (
      <div className={styles.viewport}>
        <PasswordToggleField.Root {...args}>
          <div className={styles.field}>
            <PasswordToggleField.Input className={styles.input} />
            <PasswordToggleField.Toggle className={styles.toggle}>
              <PasswordToggleField.Icon
                className={styles.toggleIcon}
                visible={<EyeOpenIcon />}
                hidden={<EyeClosedIcon />}
              />
            </PasswordToggleField.Toggle>
          </div>
        </PasswordToggleField.Root>
      </div>
    );
  },
} satisfies Story;

export const Controlled = {
  argTypes: {
    children: { table: { disable: true } },
    defaultVisible: { table: { disable: true } },
    visible: { control: { type: 'boolean' } },
  },
  args: {
    visible: false,
  },
  render: function Controlled(args) {
    const [{ visible }, updateArgs] = useArgs<StoryArgs>();
    return (
      <div className={styles.viewport}>
        <PasswordToggleField.Root
          {...args}
          visible={visible}
          onVisiblityChange={(visible) => updateArgs({ visible })}
        >
          <div className={styles.field}>
            <PasswordToggleField.Input className={styles.input} />
            <PasswordToggleField.Toggle className={styles.toggle}>
              <PasswordToggleField.Icon
                className={styles.toggleIcon}
                visible={<EyeOpenIcon />}
                hidden={<EyeClosedIcon />}
              />
            </PasswordToggleField.Toggle>
          </div>
        </PasswordToggleField.Root>
      </div>
    );
  },
} satisfies Story;

export const InsideForm = {
  argTypes: {
    children: { table: { disable: true } },
    defaultVisible: { table: { disable: true } },
    visible: { control: { type: 'boolean' } },
  },
  args: {
    visible: false,
  },
  render: function InsideForm(args) {
    const [{ visible }, updateArgs] = useArgs<StoryArgs>();
    const inputRef = React.useRef<HTMLInputElement>(null);
    return (
      <div className={styles.viewport}>
        <form
          onSubmit={(event) => {
            event.preventDefault();
            // should be reset on submit, so this should always be hidden
            window.alert(`Submitted! Field is ${visible ? 'visible' : 'hidden'}`);
            inputRef.current?.focus();
          }}
        >
          <PasswordToggleField.Root
            visible={visible}
            onVisiblityChange={(visible) => updateArgs({ visible })}
            {...args}
          >
            <div className={styles.field}>
              <PasswordToggleField.Input ref={inputRef} className={styles.input} />
              <PasswordToggleField.Toggle className={styles.toggle}>
                <PasswordToggleField.Icon
                  className={styles.toggleIcon}
                  visible={<EyeOpenIcon />}
                  hidden={<EyeClosedIcon />}
                />
              </PasswordToggleField.Toggle>
            </div>
          </PasswordToggleField.Root>
          <button>Submit</button>
        </form>
      </div>
    );
  },
} satisfies Story;

const EyeClosedIcon = () => (
  <svg
    width="15"
    height="15"
    viewBox="0 0 15 15"
    fill="currentColor"
    xmlns="http://www.w3.org/2000/svg"
  >
    <path
      d="M14.7649 6.07596C14.9991 6.22231 15.0703 6.53079 14.9239 6.76495C14.4849 7.46743 13.9632 8.10645 13.3702 8.66305L14.5712 9.86406C14.7664 10.0593 14.7664 10.3759 14.5712 10.5712C14.3759 10.7664 14.0593 10.7664 13.8641 10.5712L12.6011 9.30817C11.805 9.90283 10.9089 10.3621 9.93375 10.651L10.383 12.3277C10.4544 12.5944 10.2961 12.8685 10.0294 12.94C9.76267 13.0115 9.4885 12.8532 9.41704 12.5865L8.95917 10.8775C8.48743 10.958 8.00036 10.9999 7.50001 10.9999C6.99965 10.9999 6.51257 10.958 6.04082 10.8775L5.58299 12.5864C5.51153 12.8532 5.23737 13.0115 4.97064 12.94C4.7039 12.8686 4.5456 12.5944 4.61706 12.3277L5.06625 10.651C4.09111 10.3621 3.19503 9.90282 2.3989 9.30815L1.1359 10.5712C0.940638 10.7664 0.624058 10.7664 0.428798 10.5712C0.233537 10.3759 0.233537 10.0593 0.428798 9.86405L1.62982 8.66303C1.03682 8.10643 0.515113 7.46742 0.0760677 6.76495C-0.0702867 6.53079 0.000898544 6.22231 0.235065 6.07596C0.469231 5.9296 0.777703 6.00079 0.924058 6.23496C1.40354 7.00213 1.989 7.68057 2.66233 8.2427C2.67315 8.25096 2.6837 8.25972 2.69397 8.26898C4.00897 9.35527 5.65537 9.99991 7.50001 9.99991C10.3078 9.99991 12.6564 8.5063 14.076 6.23495C14.2223 6.00079 14.5308 5.9296 14.7649 6.07596Z"
      fillRule="evenodd"
      clipRule="evenodd"
    />
  </svg>
);

const EyeOpenIcon = () => (
  <svg
    width="15"
    height="15"
    viewBox="0 0 15 15"
    fill="currentColor"
    xmlns="http://www.w3.org/2000/svg"
  >
    <path
      d="M7.5 11C4.80285 11 2.52952 9.62184 1.09622 7.50001C2.52952 5.37816 4.80285 4 7.5 4C10.1971 4 12.4705 5.37816 13.9038 7.50001C12.4705 9.62183 10.1971 11 7.5 11ZM7.5 3C4.30786 3 1.65639 4.70638 0.0760002 7.23501C-0.0253338 7.39715 -0.0253334 7.60288 0.0760014 7.76501C1.65639 10.2936 4.30786 12 7.5 12C10.6921 12 13.3436 10.2936 14.924 7.76501C15.0253 7.60288 15.0253 7.39715 14.924 7.23501C13.3436 4.70638 10.6921 3 7.5 3ZM7.5 9.5C8.60457 9.5 9.5 8.60457 9.5 7.5C9.5 6.39543 8.60457 5.5 7.5 5.5C6.39543 5.5 5.5 6.39543 5.5 7.5C5.5 8.60457 6.39543 9.5 7.5 9.5Z"
      fillRule="evenodd"
      clipRule="evenodd"
    />
  </svg>
);



================================================
FILE: apps/storybook/stories/popover.stories.module.css
================================================
.trigger {
}

.content {
  transform-origin: var(--radix-popover-content-transform-origin);
  background-color: var(--color-gray300);
  padding: 20px;
  border-radius: 5px;
}

.close {
}

.arrow {
  fill: var(--color-gray300);
}

@keyframes popover-fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes popover-fadeOut {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}

.animatedContent {
  &[data-state='open'] {
    animation: popover-fadeIn 300ms ease-out;
  }
  &[data-state='closed'] {
    animation: popover-fadeOut 300ms ease-in;
  }
}

.grid {
  display: inline-grid;
  grid-template-columns: repeat(3, 50px);
  column-gap: 150px;
  row-gap: 100px;
  padding: 100px;
  border: 1px solid black;
}

.chromaticTrigger {
  box-sizing: border-box;
  width: 30px;
  height: 30px;
  background-color: tomato;
  border: 1px solid rgba(0, 0, 0, 0.3);
}

.contentAttr,
.chromaticContent {
  box-sizing: border-box;
  display: grid;
  place-content: center;
  width: 60px;
  height: 60px;
  background-color: royalblue;
  color: white;
  font-size: 10px;
  border: 1px solid rgba(0, 0, 0, 0.3);
}

.chromaticArrow {
  fill: black;
}

.triggerAttr,
.contentAttr,
.arrowAttr,
.closeAttr {
  background-color: rgba(0, 0, 255, 0.3);
  border: 2px solid blue;
  padding: 10px;
  &[data-state='closed'] {
    border-color: red;
  }
  &[data-state='open'] {
    border-color: green;
  }
}



================================================
FILE: apps/storybook/stories/popover.stories.tsx
================================================
import * as React from 'react';
import { Popover } from 'radix-ui';
import { Popper } from 'radix-ui/internal';
import styles from './popover.stories.module.css';

const { SIDE_OPTIONS, ALIGN_OPTIONS } = Popper;

export default { title: 'Components/Popover' };

export const Styled = () => {
  return (
    <div
      style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', height: '200vh' }}
    >
      <Popover.Root>
        <Popover.Trigger className={styles.trigger}>open</Popover.Trigger>
        <Popover.Portal>
          <Popover.Content className={styles.content} sideOffset={5}>
            <Popover.Close className={styles.close}>close</Popover.Close>
            <Popover.Arrow className={styles.arrow} width={20} height={10} />
          </Popover.Content>
        </Popover.Portal>
      </Popover.Root>
      <input />
    </div>
  );
};

// Original issue: https://github.com/radix-ui/primitives/issues/2128
export const Boundary = () => {
  const [boundary, setBoundary] = React.useState<HTMLDivElement | null>(null);

  return (
    <div
      style={{
        border: '3px dashed red',
        width: '200px',
        height: '200px',
      }}
      ref={setBoundary}
    >
      <Popover.Root>
        <Popover.Trigger asChild>
          <button>open</button>
        </Popover.Trigger>
        <Popover.Portal>
          <Popover.Content
            style={{
              boxSizing: 'border-box',
              borderRadius: '8px',
              padding: '8px',
              color: 'white',
              backgroundColor: 'black',
              width: 'var(--radix-popper-available-width)',
              height: 'var(--radix-popper-available-height)',
            }}
            sideOffset={5}
            collisionBoundary={boundary}
          >
            out of bound out of bound out of bound out of bound out of bound out of bound out of
            bound out of bound out of bound
          </Popover.Content>
        </Popover.Portal>
      </Popover.Root>
    </div>
  );
};

export const Modality = () => {
  return (
    <div
      style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', height: '110vh' }}
    >
      <div style={{ display: 'grid', gap: 50 }}>
        <div style={{ display: 'inline-flex', alignItems: 'center', flexDirection: 'column' }}>
          <h1>Non modal (default)</h1>
          <Popover.Root>
            <Popover.Trigger className={styles.trigger}>open</Popover.Trigger>
            <Popover.Portal>
              <Popover.Content className={styles.content} sideOffset={5}>
                <Popover.Close className={styles.close}>close</Popover.Close>
                <Popover.Arrow className={styles.arrow} width={20} height={10} offset={10} />
              </Popover.Content>
            </Popover.Portal>
          </Popover.Root>
          <textarea
            style={{ width: 500, height: 100, marginTop: 10 }}
            defaultValue="Lorem ipsum dolor sit amet consectetur adipisicing elit. Quaerat nobis at ipsa, nihil tempora debitis maxime dignissimos non amet."
          />
        </div>
        <div style={{ display: 'inline-flex', alignItems: 'center', flexDirection: 'column' }}>
          <h1>Modal</h1>
          <Popover.Root modal>
            <Popover.Trigger className={styles.trigger}>open</Popover.Trigger>
            <Popover.Portal>
              <Popover.Content className={styles.content} sideOffset={5}>
                <Popover.Close className={styles.close}>close</Popover.Close>
                <Popover.Arrow className={styles.arrow} width={20} height={10} offset={10} />
              </Popover.Content>
            </Popover.Portal>
          </Popover.Root>
          <textarea
            style={{ width: 500, height: 100, marginTop: 10 }}
            defaultValue="Lorem ipsum dolor sit amet consectetur adipisicing elit. Quaerat nobis at ipsa, nihil tempora debitis maxime dignissimos non amet."
          />
        </div>
      </div>
    </div>
  );
};

export const Controlled = () => {
  const [open, setOpen] = React.useState(false);
  return (
    <div
      style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', height: '50vh' }}
    >
      <Popover.Root open={open} onOpenChange={setOpen}>
        <Popover.Trigger className={styles.trigger}>{open ? 'close' : 'open'}</Popover.Trigger>
        <Popover.Portal>
          <Popover.Content className={styles.content}>
            <Popover.Close className={styles.close}>close</Popover.Close>
            <Popover.Arrow className={styles.arrow} width={20} height={10} />
          </Popover.Content>
        </Popover.Portal>
      </Popover.Root>
    </div>
  );
};

export const Animated = () => {
  return (
    <div
      style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', height: '200vh' }}
    >
      <Popover.Root>
        <Popover.Trigger className={styles.trigger}>open</Popover.Trigger>
        <Popover.Portal>
          <Popover.Content
            className={[styles.content, styles.animatedContent].join(' ')}
            sideOffset={10}
          >
            <Popover.Close className={styles.close}>close</Popover.Close>
            <Popover.Arrow className={styles.arrow} width={20} height={10} />
          </Popover.Content>
        </Popover.Portal>
      </Popover.Root>
    </div>
  );
};

export const ForcedMount = () => {
  return (
    <div
      style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', height: '200vh' }}
    >
      <Popover.Root>
        <Popover.Trigger className={styles.trigger}>open</Popover.Trigger>
        <Popover.Portal forceMount>
          <Popover.Content className={styles.content} sideOffset={10}>
            <Popover.Close className={styles.close}>close</Popover.Close>
            <Popover.Arrow className={styles.arrow} width={20} height={10} />
          </Popover.Content>
        </Popover.Portal>
      </Popover.Root>
    </div>
  );
};

export const Nested = () => {
  const buttonRef = React.useRef<HTMLButtonElement>(null);

  return (
    <div
      style={{
        height: '300vh',
        width: '300vw',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      <button
        type="button"
        style={{ position: 'fixed', top: 10, left: 10 }}
        onClick={() => buttonRef.current?.focus()}
      >
        Focus popover button
      </button>

      <Popover.Root>
        <Popover.Trigger className={styles.trigger} ref={buttonRef}>
          Open popover
        </Popover.Trigger>

        <Popover.Portal>
          <Popover.Content
            className={styles.content}
            sideOffset={5}
            style={{ backgroundColor: 'crimson' }}
          >
            <Popover.Root>
              <Popover.Trigger className={styles.trigger}>Open nested popover</Popover.Trigger>
              <Popover.Portal>
                <Popover.Content
                  className={styles.content}
                  side="top"
                  align="center"
                  sideOffset={5}
                  style={{ backgroundColor: 'green' }}
                >
                  <Popover.Close className={styles.close}>close</Popover.Close>
                  <Popover.Arrow
                    className={styles.arrow}
                    width={20}
                    height={10}
                    offset={20}
                    style={{ fill: 'green' }}
                  />
                </Popover.Content>
              </Popover.Portal>
            </Popover.Root>

            <Popover.Close className={styles.close} style={{ marginLeft: 10 }}>
              close
            </Popover.Close>
            <Popover.Arrow
              className={styles.arrow}
              width={20}
              height={10}
              offset={20}
              style={{ fill: 'crimson' }}
            />
          </Popover.Content>
        </Popover.Portal>
      </Popover.Root>
    </div>
  );
};

export const CustomAnchor = () => (
  <Popover.Root>
    <Popover.Anchor
      style={{
        display: 'flex',
        justifyContent: 'space-between',
        alignItems: 'center',
        width: 250,
        padding: 20,
        margin: 100,
        backgroundColor: '#eee',
      }}
    >
      Item <Popover.Trigger className={styles.trigger}>open</Popover.Trigger>
    </Popover.Anchor>
    <Popover.Portal>
      <Popover.Content
        className={styles.content}
        side="right"
        sideOffset={1}
        align="start"
        style={{ borderRadius: 0, width: 200, height: 100 }}
      >
        <Popover.Close>close</Popover.Close>
      </Popover.Content>
    </Popover.Portal>
  </Popover.Root>
);

export const WithSlottedTrigger = () => {
  return (
    <Popover.Root>
      <Popover.Trigger asChild>
        <button className={styles.trigger} onClick={() => console.log('StyledTrigger click')}>
          open
        </button>
      </Popover.Trigger>
      <Popover.Portal>
        <Popover.Content className={styles.content} sideOffset={5}>
          <Popover.Close className={styles.close}>close</Popover.Close>
          <Popover.Arrow className={styles.arrow} width={20} height={10} offset={10} />
        </Popover.Content>
      </Popover.Portal>
    </Popover.Root>
  );
};

// change order slightly for more pleasing visual
const SIDES = [...SIDE_OPTIONS.filter((side) => side !== 'bottom'), 'bottom' as const];

export const Chromatic = () => (
  <div style={{ padding: 200, paddingBottom: 500 }}>
    <h1>Uncontrolled</h1>
    <h2>Closed</h2>
    <Popover.Root>
      <Popover.Trigger className={styles.trigger}>open</Popover.Trigger>
      <Popover.Portal>
        <Popover.Content className={styles.content} sideOffset={5}>
          <Popover.Close className={styles.close}>close</Popover.Close>
          <Popover.Arrow className={styles.arrow} width={20} height={10} />
        </Popover.Content>
      </Popover.Portal>
    </Popover.Root>

    <h2>Open</h2>
    <Popover.Root defaultOpen>
      <Popover.Trigger className={styles.trigger}>open</Popover.Trigger>
      <Popover.Portal>
        <Popover.Content
          className={styles.content}
          sideOffset={5}
          onFocusOutside={(event) => event.preventDefault()}
        >
          <Popover.Close className={styles.close}>close</Popover.Close>
          <Popover.Arrow className={styles.arrow} width={20} height={10} />
        </Popover.Content>
      </Popover.Portal>
    </Popover.Root>

    <h2 style={{ marginTop: 100 }}>Open with reordered parts</h2>
    <Popover.Root defaultOpen>
      <Popover.Portal>
        <Popover.Content
          className={styles.content}
          sideOffset={5}
          onFocusOutside={(event) => event.preventDefault()}
        >
          <Popover.Close className={styles.close}>close</Popover.Close>
          <Popover.Arrow className={styles.arrow} width={20} height={10} />
        </Popover.Content>
      </Popover.Portal>
      <Popover.Trigger className={styles.trigger}>open</Popover.Trigger>
    </Popover.Root>

    <h1 style={{ marginTop: 100 }}>Controlled</h1>
    <h2>Closed</h2>
    <Popover.Root open={false}>
      <Popover.Trigger className={styles.trigger}>open</Popover.Trigger>
      <Popover.Portal>
        <Popover.Content className={styles.content} sideOffset={5}>
          <Popover.Close className={styles.close}>close</Popover.Close>
          <Popover.Arrow className={styles.arrow} width={20} height={10} />
        </Popover.Content>
      </Popover.Portal>
    </Popover.Root>

    <h2>Open</h2>
    <Popover.Root open>
      <Popover.Trigger className={styles.trigger}>open</Popover.Trigger>
      <Popover.Portal>
        <Popover.Content className={styles.content} sideOffset={5}>
          <Popover.Close className={styles.close}>close</Popover.Close>
          <Popover.Arrow className={styles.arrow} width={20} height={10} />
        </Popover.Content>
      </Popover.Portal>
    </Popover.Root>

    <h2 style={{ marginTop: 100 }}>Open with reordered parts</h2>
    <Popover.Root open>
      <Popover.Content className={styles.content} sideOffset={5}>
        <Popover.Close className={styles.close}>close</Popover.Close>
        <Popover.Arrow className={styles.arrow} width={20} height={10} />
      </Popover.Content>
      <Popover.Trigger className={styles.trigger}>open</Popover.Trigger>
    </Popover.Root>

    <h1 style={{ marginTop: 100 }}>Force mounted content</h1>
    <Popover.Root>
      <Popover.Trigger className={styles.trigger}>open</Popover.Trigger>
      <Popover.Portal forceMount>
        <Popover.Content className={styles.content} sideOffset={5}>
          <Popover.Close className={styles.close}>close</Popover.Close>
          <Popover.Arrow className={styles.arrow} width={20} height={10} />
        </Popover.Content>
      </Popover.Portal>
    </Popover.Root>

    <h1 style={{ marginTop: 100 }}>Anchor</h1>
    <h2>Controlled</h2>
    <Popover.Root open>
      <Popover.Anchor style={{ padding: 20, background: 'gainsboro' }}>
        <Popover.Trigger className={styles.trigger}>open</Popover.Trigger>
      </Popover.Anchor>
      <Popover.Portal>
        <Popover.Content className={styles.content}>
          <Popover.Close className={styles.close}>close</Popover.Close>
          <Popover.Arrow className={styles.arrow} width={20} height={10} />
        </Popover.Content>
      </Popover.Portal>
    </Popover.Root>

    <h2>Uncontrolled</h2>
    <Popover.Root defaultOpen>
      <Popover.Anchor style={{ padding: 20, background: 'gainsboro' }}>
        <Popover.Trigger className={styles.trigger}>open</Popover.Trigger>
      </Popover.Anchor>
      <Popover.Portal>
        <Popover.Content
          className={styles.content}
          onFocusOutside={(event) => event.preventDefault()}
        >
          <Popover.Close className={styles.close}>close</Popover.Close>
          <Popover.Arrow className={styles.arrow} width={20} height={10} />
        </Popover.Content>
      </Popover.Portal>
    </Popover.Root>

    <h1 style={{ marginTop: 100 }}>Positioning</h1>
    <h2>No collisions</h2>
    <h3>Side & Align</h3>
    <div className={styles.grid}>
      {SIDES.map((side) =>
        ALIGN_OPTIONS.map((align) => (
          <Popover.Root key={`${side}-${align}`} open>
            <Popover.Trigger className={styles.chromaticTrigger} />
            <Popover.Portal>
              <Popover.Content
                className={styles.chromaticContent}
                side={side}
                align={align}
                avoidCollisions={false}
              >
                <p style={{ textAlign: 'center' }}>
                  {side}
                  <br />
                  {align}
                </p>
                <Popover.Arrow className={styles.chromaticArrow} width={20} height={10} />
              </Popover.Content>
            </Popover.Portal>
          </Popover.Root>
        )),
      )}
    </div>

    <h3>Side offset</h3>
    <h4>Positive</h4>
    <div className={styles.grid}>
      {SIDES.map((side) =>
        ALIGN_OPTIONS.map((align) => (
          <Popover.Root key={`${side}-${align}`} open>
            <Popover.Trigger className={styles.chromaticTrigger} />
            <Popover.Portal>
              <Popover.Content
                className={styles.chromaticContent}
                side={side}
                sideOffset={5}
                align={align}
                avoidCollisions={false}
              >
                <p style={{ textAlign: 'center' }}>
                  {side}
                  <br />
                  {align}
                </p>
                <Popover.Arrow className={styles.chromaticArrow} width={20} height={10} />
              </Popover.Content>
            </Popover.Portal>
          </Popover.Root>
        )),
      )}
    </div>
    <h4>Negative</h4>
    <div className={styles.grid}>
      {SIDES.map((side) =>
        ALIGN_OPTIONS.map((align) => (
          <Popover.Root key={`${side}-${align}`} open>
            <Popover.Trigger className={styles.chromaticTrigger} />
            <Popover.Portal>
              <Popover.Content
                className={styles.chromaticContent}
                side={side}
                sideOffset={-10}
                align={align}
                avoidCollisions={false}
              >
                <p style={{ textAlign: 'center' }}>
                  {side}
                  <br />
                  {align}
                </p>
                <Popover.Arrow className={styles.chromaticArrow} width={20} height={10} />
              </Popover.Content>
            </Popover.Portal>
          </Popover.Root>
        )),
      )}
    </div>

    <h3>Align offset</h3>
    <h4>Positive</h4>
    <div className={styles.grid}>
      {SIDES.map((side) =>
        ALIGN_OPTIONS.map((align) => (
          <Popover.Root key={`${side}-${align}`} open>
            <Popover.Trigger className={styles.chromaticTrigger} />
            <Popover.Portal>
              <Popover.Content
                className={styles.chromaticContent}
                side={side}
                align={align}
                alignOffset={20}
                avoidCollisions={false}
              >
                <p style={{ textAlign: 'center' }}>
                  {side}
                  <br />
                  {align}
                </p>
                <Popover.Arrow className={styles.chromaticArrow} width={20} height={10} />
              </Popover.Content>
            </Popover.Portal>
          </Popover.Root>
        )),
      )}
    </div>
    <h4>Negative</h4>
    <div className={styles.grid}>
      {SIDES.map((side) =>
        ALIGN_OPTIONS.map((align) => (
          <Popover.Root key={`${side}-${align}`} open>
            <Popover.Trigger className={styles.chromaticTrigger} />
            <Popover.Portal>
              <Popover.Content
                className={styles.chromaticContent}
                side={side}
                align={align}
                alignOffset={-10}
                avoidCollisions={false}
              >
                <p style={{ textAlign: 'center' }}>
                  {side}
                  <br />
                  {align}
                </p>
                <Popover.Arrow className={styles.chromaticArrow} width={20} height={10} />
              </Popover.Content>
            </Popover.Portal>
          </Popover.Root>
        )),
      )}
    </div>

    <h2>Collisions</h2>
    <p>See instances on the periphery of the page.</p>
    {SIDES.map((side) =>
      ALIGN_OPTIONS.map((align) => (
        <Popover.Root key={`${side}-${align}`} open>
          <Popover.Trigger
            className={styles.chromaticTrigger}
            style={{
              position: 'absolute',
              [side]: 10,
              ...((side === 'right' || side === 'left') &&
                (align === 'start'
                  ? { bottom: 10 }
                  : align === 'center'
                    ? { top: 'calc(50% - 15px)' }
                    : { top: 10 })),
              ...((side === 'top' || side === 'bottom') &&
                (align === 'start'
                  ? { right: 10 }
                  : align === 'center'
                    ? { left: 'calc(50% - 15px)' }
                    : { left: 10 })),
            }}
          />
          <Popover.Portal>
            <Popover.Content className={styles.chromaticContent} side={side} align={align}>
              <p style={{ textAlign: 'center' }}>
                {side}
                <br />
                {align}
              </p>
              <Popover.Arrow className={styles.chromaticArrow} width={20} height={10} />
            </Popover.Content>
          </Popover.Portal>
        </Popover.Root>
      )),
    )}

    <h2>Relative parent (non-portalled)</h2>
    <div style={{ position: 'relative' }}>
      <Popover.Root open>
        <Popover.Trigger asChild>
          <button className={styles.trigger}>open</button>
        </Popover.Trigger>
        <Popover.Content className={styles.content} sideOffset={5}>
          <Popover.Close className={styles.close}>close</Popover.Close>
          <Popover.Arrow className={styles.arrow} width={20} height={10} offset={10} />
        </Popover.Content>
      </Popover.Root>
    </div>

    <h1 style={{ marginTop: 100 }}>With slotted trigger</h1>
    <Popover.Root open>
      <Popover.Trigger asChild>
        <button className={styles.trigger}>open</button>
      </Popover.Trigger>
      <Popover.Portal>
        <Popover.Content className={styles.content} sideOffset={5}>
          <Popover.Close className={styles.close}>close</Popover.Close>
          <Popover.Arrow className={styles.arrow} width={20} height={10} offset={10} />
        </Popover.Content>
      </Popover.Portal>
    </Popover.Root>

    <h1 style={{ marginTop: 100 }}>State attributes</h1>
    <h2>Closed</h2>
    <Popover.Root open={false}>
      <Popover.Trigger className={styles.triggerAttr}>open</Popover.Trigger>
      <Popover.Portal>
        <Popover.Content className={styles.contentAttr} sideOffset={5} avoidCollisions={false}>
          <Popover.Close className={styles.closeAttr}>close</Popover.Close>
          <Popover.Arrow className={styles.arrowAttr} width={20} height={10} />
        </Popover.Content>
      </Popover.Portal>
    </Popover.Root>

    <h2>Open</h2>
    <Popover.Root open>
      <Popover.Trigger className={styles.triggerAttr}>open</Popover.Trigger>
      <Popover.Portal>
        <Popover.Content
          className={styles.contentAttr}
          side="right"
          sideOffset={5}
          avoidCollisions={false}
        >
          <Popover.Close className={styles.closeAttr}>close</Popover.Close>
          <Popover.Arrow className={styles.arrowAttr} width={20} height={10} />
        </Popover.Content>
      </Popover.Portal>
    </Popover.Root>
  </div>
);
Chromatic.parameters = { chromatic: { disable: false } };



================================================
FILE: apps/storybook/stories/popper.stories.module.css
================================================
.content {
  transform-origin: var(--radix-popper-transform-origin);
  background-color: var(--color-gray100);
  padding: 10px;
  border-radius: 10px;
}

.contentSmall {
  width: 100px;
  height: 50px;
}

.contentLarge {
  width: 300px;
  height: 150px;
}

.anchor {
  background-color: hotpink;
}

.anchorSmall {
  width: 50px;
  height: 50px;
}

.anchorLarge {
  width: 100px;
  height: 100px;
}

.arrow {
  fill: var(--color-gray100);
}

@keyframes popper-rotateIn {
  0% {
    transform: scale(0) rotateZ(calc(var(--direction, 0) * 45deg));
  }
  100% {
    transform: scale(1);
  }
}

.animatedContent {
  &[data-side='top'] {
    --direction: 1;
  }
  &[data-side='bottom'] {
    --direction: -1;
  }
  animation: popper-rotateIn 0.6s cubic-bezier(0.16, 1, 0.3, 1);
}



================================================
FILE: apps/storybook/stories/popper.stories.tsx
================================================
import * as React from 'react';
import { Portal } from 'radix-ui';
import { Popper } from 'radix-ui/internal';
import styles from './popper.stories.module.css';

export default { title: 'Utilities/Popper' };

export const Styled = () => {
  const [open, setOpen] = React.useState(false);
  return (
    <Scrollable>
      <Popper.Root>
        <Popper.Anchor className={styles.anchor} onClick={() => setOpen(true)}>
          open
        </Popper.Anchor>

        {open && (
          <Popper.Content className={styles.content} sideOffset={5}>
            <button onClick={() => setOpen(false)}>close</button>
            <Popper.Arrow className={styles.arrow} width={20} height={10} />
          </Popper.Content>
        )}
      </Popper.Root>
    </Scrollable>
  );
};

export const WithCustomArrow = () => {
  const [open, setOpen] = React.useState(false);
  return (
    <Scrollable>
      <Popper.Root>
        <Popper.Anchor className={styles.anchor} onClick={() => setOpen(true)}>
          open
        </Popper.Anchor>

        {open && (
          <Popper.Content className={styles.content} side="right" sideOffset={5}>
            <button onClick={() => setOpen(false)}>close</button>
            <Popper.Arrow asChild offset={20}>
              <CustomArrow width={20} height={10} />
            </Popper.Arrow>
          </Popper.Content>
        )}
      </Popper.Root>
    </Scrollable>
  );
};

export const Animated = () => {
  const [open, setOpen] = React.useState(false);

  return (
    <Scrollable>
      <Popper.Root>
        <Popper.Anchor className={styles.anchor} onClick={() => setOpen(true)}>
          open
        </Popper.Anchor>

        {open && (
          <Portal.Root asChild>
            <Popper.Content
              className={[styles.content, styles.animatedContent].join(' ')}
              sideOffset={5}
            >
              <button onClick={() => setOpen(false)}>close</button>
              <Popper.Arrow className={styles.arrow} width={20} height={10} offset={25} />
            </Popper.Content>
          </Portal.Root>
        )}
      </Popper.Root>
    </Scrollable>
  );
};

export const WithPortal = () => {
  const [open, setOpen] = React.useState(false);
  return (
    <Scrollable>
      <Popper.Root>
        <Popper.Anchor className={styles.anchor} onClick={() => setOpen(true)}>
          open
        </Popper.Anchor>

        {open && (
          <Portal.Root asChild>
            <Popper.Content className={styles.content} sideOffset={5}>
              <button onClick={() => setOpen(false)}>close</button>
              <Popper.Arrow className={styles.arrow} width={20} height={10} />
            </Popper.Content>
          </Portal.Root>
        )}
      </Popper.Root>
    </Scrollable>
  );
};

export const WithUpdatePositionStrategyAlways = () => {
  const [open, setOpen] = React.useState(false);
  const [left, setLeft] = React.useState(0);
  React.useEffect(() => {
    const intervalId = setInterval(() => {
      setLeft((prev) => (prev + 50) % 300);
    }, 500);
    return () => clearInterval(intervalId);
  }, []);
  return (
    <Scrollable>
      <Popper.Root>
        <Popper.Anchor
          className={styles.anchor}
          onClick={() => setOpen(true)}
          style={{ marginLeft: left }}
        >
          open
        </Popper.Anchor>

        {open && (
          <Portal.Root asChild>
            <Popper.Content
              className={styles.content}
              sideOffset={5}
              updatePositionStrategy="always"
            >
              <button onClick={() => setOpen(false)}>close</button>
              <Popper.Arrow className={styles.arrow} width={20} height={10} />
            </Popper.Content>
          </Portal.Root>
        )}
      </Popper.Root>
    </Scrollable>
  );
};

export const Chromatic = () => {
  const [scrollContainer1, setScrollContainer1] = React.useState<HTMLDivElement | null>(null);
  const [scrollContainer2, setScrollContainer2] = React.useState<HTMLDivElement | null>(null);

  return (
    <div style={{ paddingBottom: 500 }}>
      <header
        style={{
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
          gap: 150,

          position: 'fixed',
          top: 0,
          left: 0,
          right: 0,

          backgroundColor: 'grey',
          border: '1px solid black',
        }}
      >
        <h1>In fixed header</h1>
        <Popper.Root>
          <Popper.Anchor className={anchorClass({ size: 'small' })}>1</Popper.Anchor>
          <Popper.Content className={contentClass({ size: 'small' })} sideOffset={5}>
            <Popper.Arrow className={styles.arrow} width={10} height={5} />1
          </Popper.Content>
        </Popper.Root>

        <Popper.Root>
          <Popper.Anchor className={anchorClass({ size: 'small' })}>2</Popper.Anchor>
          <Portal.Root asChild>
            <Popper.Content className={contentClass({ size: 'small' })} sideOffset={5}>
              <Popper.Arrow className={styles.arrow} width={10} height={5} />2 (portalled)
            </Popper.Content>
          </Portal.Root>
        </Popper.Root>
      </header>

      <div
        style={{
          marginTop: 100,
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
          gap: 150,
          border: '1px solid black',
        }}
      >
        <h1>In normal page flow</h1>
        <Popper.Root>
          <Popper.Anchor className={anchorClass({ size: 'small' })}>3</Popper.Anchor>
          <Popper.Content className={contentClass({ size: 'small' })} sideOffset={5}>
            <Popper.Arrow className={styles.arrow} width={10} height={5} />3
          </Popper.Content>
        </Popper.Root>

        <Popper.Root>
          <Popper.Anchor className={anchorClass({ size: 'small' })}>4</Popper.Anchor>
          <Portal.Root asChild>
            <Popper.Content className={contentClass({ size: 'small' })} sideOffset={5}>
              <Popper.Arrow className={styles.arrow} width={10} height={5} />4 (portalled)
            </Popper.Content>
          </Portal.Root>
        </Popper.Root>
      </div>

      <div
        style={{
          position: 'relative',
          marginTop: 50,
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
          gap: 150,
          border: '1px solid black',
        }}
      >
        <h1>In relative parent</h1>
        <Popper.Root>
          <Popper.Anchor className={anchorClass({ size: 'small' })}>5</Popper.Anchor>
          <Popper.Content className={contentClass({ size: 'small' })} sideOffset={5}>
            <Popper.Arrow className={styles.arrow} width={10} height={5} />5
          </Popper.Content>
        </Popper.Root>

        <Popper.Root>
          <Popper.Anchor className={anchorClass({ size: 'small' })}>6</Popper.Anchor>
          <Portal.Root asChild>
            <Popper.Content className={contentClass({ size: 'small' })} sideOffset={5}>
              <Popper.Arrow className={styles.arrow} width={10} height={5} />6 (portalled)
            </Popper.Content>
          </Portal.Root>
        </Popper.Root>
      </div>

      <div
        style={{
          marginTop: 50,
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
          gap: 150,
          border: '1px solid black',
          transform: 'translate3d(100px, 0, 0)',
        }}
      >
        <h1>In translated parent</h1>
        <Popper.Root>
          <Popper.Anchor className={anchorClass({ size: 'small' })}>7</Popper.Anchor>
          <Popper.Content className={contentClass({ size: 'small' })} sideOffset={5}>
            <Popper.Arrow className={styles.arrow} width={10} height={5} />7
          </Popper.Content>
        </Popper.Root>

        <Popper.Root>
          <Popper.Anchor className={anchorClass({ size: 'small' })}>8</Popper.Anchor>
          <Portal.Root asChild>
            <Popper.Content className={contentClass({ size: 'small' })} sideOffset={5}>
              <Popper.Arrow className={styles.arrow} width={10} height={5} />8 (portalled)
            </Popper.Content>
          </Portal.Root>
        </Popper.Root>
      </div>

      <div style={{ display: 'flex', gap: 100 }}>
        <div>
          <h1>In scrolling container</h1>
          <div
            ref={setScrollContainer1}
            style={{ width: 400, height: 600, overflow: 'auto', border: '1px solid black' }}
          >
            <div style={{ height: 2000 }}>
              {Array.from({ length: 10 }, (_, i) => (
                <div
                  key={i}
                  style={{
                    display: 'flex',
                    alignItems: 'center',
                    justifyContent: 'center',
                    gap: 150,
                    paddingBottom: 100,
                  }}
                >
                  <Popper.Root>
                    <Popper.Anchor className={anchorClass({ size: 'small' })}>
                      9.{i + 1}
                    </Popper.Anchor>
                    <Popper.Content
                      className={contentClass({ size: 'small' })}
                      sideOffset={5}
                      hideWhenDetached
                      collisionBoundary={scrollContainer1}
                    >
                      <Popper.Arrow className={styles.arrow} width={10} height={5} />
                      9.{i + 1}
                    </Popper.Content>
                  </Popper.Root>

                  <Popper.Root>
                    <Popper.Anchor className={anchorClass({ size: 'small' })}>
                      10.{i + 1}
                    </Popper.Anchor>
                    <Portal.Root asChild>
                      <Popper.Content
                        className={contentClass({ size: 'small' })}
                        sideOffset={5}
                        hideWhenDetached
                        collisionBoundary={scrollContainer1}
                      >
                        <Popper.Arrow className={styles.arrow} width={10} height={5} />
                        10.{i + 1} (portalled)
                      </Popper.Content>
                    </Portal.Root>
                  </Popper.Root>
                </div>
              ))}
            </div>
          </div>
        </div>

        <div>
          <h1>With position sticky</h1>
          <div
            ref={setScrollContainer2}
            style={{ width: 400, height: 600, overflow: 'auto', border: '1px solid black' }}
          >
            <div style={{ height: 2000 }}>
              {Array.from({ length: 10 }, (_, i) => (
                <div
                  key={i}
                  style={{
                    display: 'flex',
                    alignItems: 'center',
                    justifyContent: 'center',
                    gap: 150,
                    paddingBottom: 100,
                    position: 'sticky',
                    top: 0,
                  }}
                >
                  <Popper.Root>
                    <Popper.Anchor className={anchorClass({ size: 'small' })}>
                      9.{i + 1}
                    </Popper.Anchor>
                    <Popper.Content
                      className={contentClass({ size: 'small' })}
                      sideOffset={5}
                      hideWhenDetached
                      collisionBoundary={scrollContainer2}
                    >
                      <Popper.Arrow className={styles.arrow} width={10} height={5} />
                      9.{i + 1}
                    </Popper.Content>
                  </Popper.Root>

                  <Popper.Root>
                    <Popper.Anchor className={anchorClass({ size: 'small' })}>
                      10.{i + 1}
                    </Popper.Anchor>
                    <Portal.Root asChild>
                      <Popper.Content
                        className={contentClass({ size: 'small' })}
                        sideOffset={5}
                        hideWhenDetached
                        collisionBoundary={scrollContainer2}
                      >
                        <Popper.Arrow className={styles.arrow} width={10} height={5} />
                        10.{i + 1} (portalled)
                      </Popper.Content>
                    </Portal.Root>
                  </Popper.Root>
                </div>
              ))}
            </div>
          </div>
        </div>
      </div>
      <div
        style={{
          marginTop: 50,
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
          gap: 150,
          border: '1px solid black',
        }}
      >
        <h1>Logical "start" alignment (LTR)</h1>
        <Popper.Root>
          <Popper.Anchor className={anchorClass({ size: 'small' })}>11</Popper.Anchor>
          <Popper.Content align="start" className={contentClass({ size: 'small' })} sideOffset={5}>
            <Popper.Arrow className={styles.arrow} width={10} height={5} />
            11
          </Popper.Content>
        </Popper.Root>

        <Popper.Root>
          <Popper.Anchor className={anchorClass({ size: 'small' })}>12</Popper.Anchor>
          <Portal.Root asChild>
            <Popper.Content
              align="start"
              className={contentClass({ size: 'small' })}
              sideOffset={5}
            >
              <Popper.Arrow className={styles.arrow} width={10} height={5} />
              12 (portalled)
            </Popper.Content>
          </Portal.Root>
        </Popper.Root>
      </div>
      <div
        style={{
          marginTop: 50,
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
          gap: 150,
          border: '1px solid black',
        }}
      >
        <h1>Logical "start" alignment (RTL)</h1>
        <Popper.Root>
          <Popper.Anchor className={anchorClass({ size: 'small' })}>13</Popper.Anchor>
          <Popper.Content
            align="start"
            className={contentClass({ size: 'small' })}
            sideOffset={5}
            dir="rtl"
          >
            <Popper.Arrow className={styles.arrow} width={10} height={5} />
            13
          </Popper.Content>
        </Popper.Root>

        <Popper.Root>
          <Popper.Anchor className={anchorClass({ size: 'small' })}>14</Popper.Anchor>
          <Portal.Root asChild>
            <Popper.Content
              align="start"
              className={contentClass({ size: 'small' })}
              sideOffset={5}
              dir="rtl"
            >
              <Popper.Arrow className={styles.arrow} width={10} height={5} />
              14 (portalled)
            </Popper.Content>
          </Portal.Root>
        </Popper.Root>
      </div>
    </div>
  );
};
Chromatic.parameters = { chromatic: { disable: false } };

const Scrollable = (props: any) => (
  <div
    style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', height: '200vh' }}
    {...props}
  />
);

const CustomArrow = (props: any) => (
  <div
    {...props}
    style={{
      ...props.style,
      width: 20,
      height: 10,
      borderBottomLeftRadius: 10,
      borderBottomRightRadius: 10,
      backgroundColor: 'tomato',
    }}
  />
);

function anchorClass(props: { size: 'small' | 'large' }) {
  return [
    styles.anchor,
    props.size === 'small' && styles.anchorSmall,
    props.size === 'large' && styles.anchorLarge,
  ]
    .filter(Boolean)
    .join(' ');
}

function contentClass(props: { size: 'small' | 'large' }) {
  return [
    styles.content,
    props.size === 'small' && styles.contentSmall,
    props.size === 'large' && styles.contentLarge,
  ]
    .filter(Boolean)
    .join(' ');
}



================================================
FILE: apps/storybook/stories/portal.stories.tsx
================================================
import * as React from 'react';
import { Portal } from 'radix-ui';

export default { title: 'Utilities/Portal' };

export const Base = () => (
  <div
    style={{
      maxWidth: 300,
      maxHeight: 200,
      overflow: 'auto',
      border: '1px solid',
    }}
  >
    <h1>This content is rendered in the main DOM tree</h1>
    <p>
      Lorem ipsum dolor sit amet consectetur adipisicing elit. Quos porro, est ex quia itaque facere
      fugit necessitatibus aut enim. Nisi rerum quae, repellat in perspiciatis explicabo laboriosam
      necessitatibus eius pariatur.
    </p>

    <Portal.Root>
      <h1>This content is rendered in a portal (another DOM tree)</h1>
      <p>
        Because of the portal, it can appear in a different DOM tree from the main one (by default a
        new element inside the body), even though it is part of the same React tree.
      </p>
    </Portal.Root>
  </div>
);

export const CustomContainer = () => {
  const [portalContainer, setPortalContainer] = React.useState<HTMLDivElement | null>(null);

  return (
    <>
      <div style={{ maxWidth: 300, padding: 10, margin: 10, border: '1px solid' }}>
        <h1>Container A</h1>
        <Portal.Root asChild container={portalContainer}>
          <p>
            This content is rendered in a portal inside Container A but appears inside Container B
            because we have used Container B as a container element for the Portal.
          </p>
        </Portal.Root>
      </div>

      <div
        ref={setPortalContainer}
        style={{ maxWidth: 300, padding: 10, margin: 10, border: '1px solid' }}
      >
        <h1>Container B</h1>
      </div>
    </>
  );
};

export const Chromatic = () => {
  const [portalContainer, setPortalContainer] = React.useState<HTMLDivElement | null>(null);

  return (
    <div style={{ padding: 150 }}>
      <h1>Default (append to body)</h1>
      <div style={{ padding: 10, margin: 10, border: '1px solid blue' }}>
        <p>Container A</p>

        <Portal.Root asChild>
          <div
            style={{
              padding: 10,
              margin: 10,
              border: '1px solid blue',
              position: 'absolute',
              top: 0,
              left: 0,
              zIndex: 9999999,
            }}
          >
            <p>This content is rendered in a portal (another DOM tree)</p>
            <p>
              Because of the portal, it can appear in a different DOM tree from the main one (by
              default a new element inside the body), even though it is part of the same React tree.
            </p>
          </div>
        </Portal.Root>
      </div>

      <h1>Custom container</h1>
      <div style={{ padding: 10, margin: 10, border: '1px solid green' }}>
        <p>Container B</p>
        <Portal.Root asChild container={portalContainer}>
          <div style={{ padding: 10, margin: 10, border: '1px solid green' }}>
            <p>
              This content is rendered in a portal inside Container B but appears inside Container C
              because we have used Container C as a container element for the Portal.
            </p>
          </div>
        </Portal.Root>
      </div>

      <div ref={setPortalContainer} style={{ padding: 10, margin: 10, border: '1px solid' }}>
        <p>Container C</p>
      </div>

      <h1>zIndex and order</h1>
      <p>See squares in the top-left</p>
      <Portal.Root asChild>
        <div
          style={{
            width: 20,
            height: 20,
            backgroundColor: 'red',
            position: 'absolute',
            top: 0,
            left: 0,
            zIndex: 9999999,
          }}
        />
      </Portal.Root>
      <Portal.Root asChild>
        <div
          style={{
            width: 20,
            height: 20,
            backgroundColor: 'green',
            marginLeft: 10,
            marginTop: 10,
            position: 'absolute',
            top: 0,
            left: 0,
            zIndex: 9999999,
          }}
        />
      </Portal.Root>
      <Portal.Root asChild>
        <div
          style={{
            width: 20,
            height: 20,
            backgroundColor: 'blue',
            marginLeft: 20,
            marginTop: 20,
            position: 'absolute',
            top: 0,
            left: 0,
            zIndex: 9999999,
          }}
        />
      </Portal.Root>
    </div>
  );
};
Chromatic.parameters = { chromatic: { disable: false } };



================================================
FILE: apps/storybook/stories/presence.stories.module.css
================================================
@keyframes presence-fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes presence-fadeOut {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}

@keyframes presence-slideUp {
  from {
    transform: translateY(30px);
  }
  to {
    transform: translateY(0);
  }
}

@keyframes presence-slideDown {
  from {
    transform: translateY(0);
  }
  to {
    transform: translateY(30px);
  }
}

.mountAnimation {
  animation: presence-fadeIn 3s ease-out;
}

.unmountAnimation {
  &[data-state='closed'] {
    animation: presence-fadeOut 3s ease-in;
  }
}

.multipleMountAnimations {
  animation:
    presence-fadeIn 6s cubic-bezier(0.22, 1, 0.36, 1),
    presence-slideUp 6s cubic-bezier(0.22, 1, 0.36, 1);
}

.openAndCloseAnimation {
  &[data-state='open'] {
    animation: presence-fadeIn 3s ease-out;
  }
  &[data-state='closed'] {
    animation: presence-fadeOut 3s ease-in;
  }
}

.multipleOpenAndCloseAnimations {
  &[data-state='open'] {
    animation:
      presence-fadeIn 3s cubic-bezier(0.22, 1, 0.36, 1),
      presence-slideUp 1s cubic-bezier(0.22, 1, 0.36, 1);
  }
  &[data-state='closed'] {
    animation:
      presence-fadeOut 3s cubic-bezier(0.22, 1, 0.36, 1),
      presence-slideDown 1s cubic-bezier(0.22, 1, 0.36, 1);
  }
}



================================================
FILE: apps/storybook/stories/presence.stories.tsx
================================================
import * as React from 'react';
import { Presence } from 'radix-ui/internal';
import styles from './presence.stories.module.css';

export default { title: 'Utilities/Presence' };

export const Basic = () => {
  const [open, setOpen] = React.useState(true);

  return (
    <>
      <button onClick={() => setOpen((prevOpen) => !prevOpen)}>toggle</button>

      <Presence.Root present={open}>
        <div>Content</div>
      </Presence.Root>
    </>
  );
};

export const WithMountAnimation = () => <Animation className={styles.mountAnimation} />;
export const WithUnmountAnimation = () => <Animation className={styles.unmountAnimation} />;
export const WithMultipleMountAnimations = () => (
  <Animation className={styles.multipleMountAnimations} />
);
export const WithOpenAndCloseAnimation = () => (
  <Animation className={styles.openAndCloseAnimation} />
);
export const WithMultipleOpenAndCloseAnimations = () => (
  <Animation className={styles.multipleOpenAndCloseAnimations} />
);

export const WithDeferredMountAnimation = () => {
  const ref = React.useRef<HTMLDivElement>(null);
  const timerRef = React.useRef(0);
  const [open, setOpen] = React.useState(false);
  const [animate, setAnimate] = React.useState(false);

  React.useEffect(() => {
    if (open) {
      timerRef.current = window.setTimeout(() => setAnimate(true), 150);
    } else {
      setAnimate(false);
      window.clearTimeout(timerRef.current);
    }
  }, [open]);

  return (
    <>
      <p>
        Deferred animation should unmount correctly when toggled. Content will flash briefly while
        we wait for animation to be applied.
      </p>
      <Toggles nodeRef={ref} open={open} onOpenChange={setOpen} />
      <Presence.Root present={open}>
        <div className={animate ? styles.mountAnimation : undefined} ref={ref}>
          Content
        </div>
      </Presence.Root>
    </>
  );
};

function Animation(props: React.ComponentProps<'div'>) {
  const ref = React.useRef<HTMLDivElement>(null);
  const [open, setOpen] = React.useState(false);

  return (
    <>
      <Toggles nodeRef={ref} open={open} onOpenChange={setOpen} />
      <Presence.Root present={open}>
        <div {...props} data-state={open ? 'open' : 'closed'} ref={ref}>
          Content
        </div>
      </Presence.Root>
    </>
  );
}

function Toggles({ open, onOpenChange, nodeRef }: any) {
  function handleToggleVisibility() {
    const node = nodeRef.current;
    if (node) {
      if (node.style.display === 'none') {
        node.style.display = 'block';
      } else {
        node.style.display = 'none';
      }
    }
  }

  return (
    <form style={{ display: 'flex', marginBottom: 30 }}>
      <fieldset>
        <legend>Mount</legend>
        <button type="button" onClick={() => onOpenChange(!open)}>
          toggle
        </button>
      </fieldset>
      <fieldset>
        <legend>Visibility (triggers cancel event)</legend>
        <button type="button" onClick={handleToggleVisibility}>
          toggle
        </button>
      </fieldset>
    </form>
  );
}



================================================
FILE: apps/storybook/stories/progress.stories.module.css
================================================
.root {
  width: 400px;
  height: 20px;
  max-width: 100%;
  border: 5px solid var(--gray-12);
  background-color: var(--gray-3);
}

.indicator,
.chromaticIndicatorClass {
  width: 0;
  height: 100%;
  background-color: var(--red-9);
  transition: background 150ms ease-out;
  &[data-state='indeterminate'] {
    background-color: var(--gray-8);
  }
  &[data-state='complete'] {
    background-color: var(--green-9);
  }
  &::before {
    content: attr(data-value);
  }
  &::after {
    content: attr(data-max);
  }
}

.rootAttr,
.indicatorAttr {
  background-color: var(--blue-a12);
  border: 2px solid var(--blue-9);
  padding: 10px;

  &[data-state='loading'] {
    border-color: var(--red-9);
  }
  &[data-state='indeterminate'] {
    border-color: var(--purple-9);
  }
  &[data-state='complete'] {
    border-color: var(--green-9);
  }
}

.indicatorAttr {
  &::before {
    content: attr(data-value);
  }
  &::after {
    content: attr(data-max);
  }
}



================================================
FILE: apps/storybook/stories/progress.stories.tsx
================================================
import * as React from 'react';
import { Progress } from 'radix-ui';
import styles from './progress.stories.module.css';

export default {
  title: 'Components/Progress',
};

export const Styled = () => {
  const max = 150;
  const [value, percentage, setValue] = useProgressValueState(0, max);
  const toggleIndeterminate = useIndeterminateToggle(value, setValue);
  return (
    <div>
      <Progress.Root className={styles.root} value={value} max={max}>
        <Progress.Indicator
          className={styles.indicator}
          style={{ width: percentage != null ? `${percentage}%` : undefined }}
        />
      </Progress.Root>
      <hr />
      <button onClick={toggleIndeterminate}>Toggle Indeterminate</button>
      <ProgressRange value={value} setValue={setValue} max={max} />
    </div>
  );
};

export const Chromatic = () => (
  <>
    <h1>Loading (not started)</h1>
    <Progress.Root className={styles.root} value={0}>
      <Progress.Indicator className={styles.chromaticIndicator}>/</Progress.Indicator>
    </Progress.Root>

    <h1>Loading (started)</h1>
    <Progress.Root className={styles.root} value={30}>
      <Progress.Indicator className={styles.chromaticIndicator}>/</Progress.Indicator>
    </Progress.Root>

    <h1>Indeterminate</h1>
    <Progress.Root className={styles.root}>
      <Progress.Indicator className={styles.chromaticIndicator}>/</Progress.Indicator>
    </Progress.Root>

    <h1>Complete</h1>
    <Progress.Root className={styles.root} value={100}>
      <Progress.Indicator className={styles.chromaticIndicator}>/</Progress.Indicator>
    </Progress.Root>

    <h1>State attributes</h1>
    <h2>Loading (started)</h2>
    <Progress.Root className={styles.rootAttr} value={30}>
      <Progress.Indicator className={styles.indicatorAttr}>/</Progress.Indicator>
    </Progress.Root>

    <h2>Indeterminate</h2>
    <Progress.Root className={styles.rootAttr}>
      <Progress.Indicator className={styles.indicatorAttr}>/</Progress.Indicator>
    </Progress.Root>

    <h2>Complete</h2>
    <Progress.Root className={styles.rootAttr} value={100}>
      <Progress.Indicator className={styles.indicatorAttr}>/</Progress.Indicator>
    </Progress.Root>
  </>
);
Chromatic.parameters = { chromatic: { disable: false } };

function ProgressRange({ value, setValue, max = 100 }: any) {
  const previousValueRef = usePreviousValueRef(value);
  return (
    <input
      type="range"
      disabled={value == null}
      value={value == null ? previousValueRef.current : value}
      max={max}
      min={0}
      onChange={(e) => {
        const val = Number(e.target.value);
        if (!isNaN(val)) {
          setValue(val);
        }
      }}
    />
  );
}

type ProgressValue = number | null;
function useProgressValueState(initialState: ProgressValue | (() => ProgressValue), max = 100) {
  const [value, setValue] = React.useState<number | null>(initialState);
  const precentage = value != null ? Math.round((value / max) * 100) : null;
  return [value, precentage, setValue] as const;
}

function useIndeterminateToggle(
  value: ProgressValue,
  setValue: React.Dispatch<React.SetStateAction<ProgressValue>>,
) {
  const previousValueRef = usePreviousValueRef(value);
  const toggleIndeterminate = React.useCallback(
    function setIndeterminate() {
      setValue((val) => {
        if (val == null) {
          return previousValueRef.current;
        }
        return null;
      });
    },
    [previousValueRef, setValue],
  );
  return toggleIndeterminate;
}

function usePreviousValueRef(value: ProgressValue) {
  const previousValueRef = React.useRef<number>(value || 0);
  React.useEffect(() => {
    if (value != null) {
      previousValueRef.current = value;
    }
  });
  return previousValueRef;
}



================================================
FILE: apps/storybook/stories/radio-group.stories.module.css
================================================
.root {
}

.item {
  vertical-align: middle;
  width: 30px;
  height: 30px;
  display: inline-grid;
  padding: 0;
  place-items: center;
  border: 1px solid var(--color-gray300);
  border-radius: 9999px;

  &:focus {
    outline: none;
    border-color: var(--color-red);
    box-shadow: 0 0 0 1px var(--color-red);
  }

  ,
  &[data-disabled] {
    opacity: 0.5;
  }
}

.indicator {
  width: 18px;
  height: 18px;
  background-color: var(--color-red);
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: inherit;
}

.animatedIndicator {
  &[data-state='checked'] {
    animation: radioGroup-fadeIn 300ms ease-out;
  }
  &[data-state='unchecked'] {
    animation: radioGroup-fadeOut 300ms ease-in;
  }
}

.rootAttr,
.itemAttr,
.indicatorAttr {
  background-color: rgba(0, 0, 255, 0.3);
  border: 2px solid blue;
  padding: 10px;

  &[tabindex='0'] {
    box-shadow: inset 0 0 0 2px yellow;
  }
  &:disabled {
    opacity: 0.5;
  }
  &[data-disabled] {
    border-style: dashed;
  }
  &[data-state='unchecked'] {
    border-color: red;
  }
  &[data-state='checked'] {
    border-color: green;
  }
}

.label {
  /* ensures it can receive vertical margins */
  display: inline-block;
  /* better default alignment */
  vertical-align: middle;
  /* mimics default `label` tag (as we render a `span`) */
  cursor: default;
  display: inline-block;
}

@keyframes radioGroup-fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes radioGroup-fadeOut {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}



================================================
FILE: apps/storybook/stories/radio-group.stories.tsx
================================================
import * as React from 'react';
import { Direction, Label as LabelPrimitive, RadioGroup } from 'radix-ui';
import styles from './radio-group.stories.module.css';

export default { title: 'Components/RadioGroup' };

export const LegacyStyled = () => (
  <Label>
    Favourite pet
    <RadioGroup.Root className={styles.root} defaultValue="1">
      <Label>
        <RadioGroup.Item className={styles.item} value="1">
          <RadioGroup.Indicator className={styles.indicator} />
        </RadioGroup.Item>
        Cat
      </Label>{' '}
      <Label>
        <RadioGroup.Item className={styles.item} value="2">
          <RadioGroup.Indicator className={styles.indicator} />
        </RadioGroup.Item>
        Dog
      </Label>{' '}
      <Label>
        <RadioGroup.Item className={styles.item} value="3">
          <RadioGroup.Indicator className={styles.indicator} />
        </RadioGroup.Item>
        Rabbit
      </Label>
    </RadioGroup.Root>
  </Label>
);

export const LegacyControlled = () => {
  const [value, setValue] = React.useState('2');

  return (
    <RadioGroup.Root className={styles.root} value={value} onValueChange={setValue}>
      <RadioGroup.Item className={styles.item} value="1">
        <RadioGroup.Indicator className={styles.indicator} />
      </RadioGroup.Item>
      <RadioGroup.Item className={styles.item} value="2">
        <RadioGroup.Indicator className={styles.indicator} />
      </RadioGroup.Item>
      <RadioGroup.Item className={styles.item} value="3">
        <RadioGroup.Indicator className={styles.indicator} />
      </RadioGroup.Item>
    </RadioGroup.Root>
  );
};

export const LegacyUnset = () => (
  <Label>
    Favourite pet
    <RadioGroup.Root className={styles.root}>
      <Label>
        <RadioGroup.Item className={styles.item} value="1">
          <RadioGroup.Indicator className={styles.indicator} />
        </RadioGroup.Item>
        Cat
      </Label>{' '}
      <Label>
        <RadioGroup.Item className={styles.item} value="2" disabled>
          <RadioGroup.Indicator className={styles.indicator} />
        </RadioGroup.Item>
        Dog
      </Label>{' '}
      <Label>
        <RadioGroup.Item className={styles.item} value="3">
          <RadioGroup.Indicator className={styles.indicator} />
        </RadioGroup.Item>
        Rabbit
      </Label>
    </RadioGroup.Root>
  </Label>
);

export const LegacyWithinForm = () => {
  const [data, setData] = React.useState({ optional: '', required: '', stopprop: '' });

  return (
    <form
      onSubmit={(event) => event.preventDefault()}
      onChange={(event) => {
        const radio = event.target as HTMLInputElement;
        setData((prevData) => ({ ...prevData, [radio.name]: radio.value }));
      }}
    >
      <fieldset>
        <legend>optional value: {data.optional}</legend>
        <RadioGroup.Root className={styles.root} name="optional">
          <RadioGroup.Item className={styles.item} value="1">
            <RadioGroup.Indicator className={styles.indicator} />
          </RadioGroup.Item>
          <RadioGroup.Item className={styles.item} value="2">
            <RadioGroup.Indicator className={styles.indicator} />
          </RadioGroup.Item>
          <RadioGroup.Item className={styles.item} value="3">
            <RadioGroup.Indicator className={styles.indicator} />
          </RadioGroup.Item>
        </RadioGroup.Root>
      </fieldset>

      <br />
      <br />

      <fieldset>
        <legend>required value: {data.required}</legend>
        <RadioGroup.Root className={styles.root} name="required" required>
          <RadioGroup.Item className={styles.item} value="1">
            <RadioGroup.Indicator className={styles.indicator} />
          </RadioGroup.Item>
          <RadioGroup.Item className={styles.item} value="2">
            <RadioGroup.Indicator className={styles.indicator} />
          </RadioGroup.Item>
          <RadioGroup.Item className={styles.item} value="3">
            <RadioGroup.Indicator className={styles.indicator} />
          </RadioGroup.Item>
        </RadioGroup.Root>
      </fieldset>

      <br />
      <br />

      <fieldset>
        <legend>stop propagation value: {data.stopprop}</legend>
        <RadioGroup.Root className={styles.root} name="stopprop">
          <RadioGroup.Item
            className={styles.item}
            value="1"
            onClick={(event) => event.stopPropagation()}
          >
            <RadioGroup.Indicator className={styles.indicator} />
          </RadioGroup.Item>
          <RadioGroup.Item
            className={styles.item}
            value="2"
            onClick={(event) => event.stopPropagation()}
          >
            <RadioGroup.Indicator className={styles.indicator} />
          </RadioGroup.Item>
          <RadioGroup.Item
            className={styles.item}
            value="3"
            onClick={(event) => event.stopPropagation()}
          >
            <RadioGroup.Indicator className={styles.indicator} />
          </RadioGroup.Item>
        </RadioGroup.Root>
      </fieldset>

      <br />
      <br />

      <button>Submit</button>
    </form>
  );
};

export const LegacyAnimated = () => {
  const indicatorClass = [styles.indicator, styles.animatedIndicator].join(' ');
  return (
    <Label>
      Favourite pet
      <RadioGroup.Root className={styles.root} defaultValue="1">
        <Label>
          <RadioGroup.Item className={styles.item} value="1">
            <RadioGroup.Indicator className={indicatorClass} />
          </RadioGroup.Item>
          Cat
        </Label>{' '}
        <Label>
          <RadioGroup.Item className={styles.item} value="2">
            <RadioGroup.Indicator className={indicatorClass} />
          </RadioGroup.Item>
          Dog
        </Label>{' '}
        <Label>
          <RadioGroup.Item className={styles.item} value="3">
            <RadioGroup.Indicator className={indicatorClass} />
          </RadioGroup.Item>
          Rabbit
        </Label>
      </RadioGroup.Root>
    </Label>
  );
};

export const LegacyChromatic = () => {
  const manualFocusRef = React.useRef<React.ComponentRef<typeof RadioGroup.Item>>(null);

  React.useEffect(() => {
    manualFocusRef.current?.focus();
  }, []);

  return (
    <>
      <h1>Uncontrolled</h1>
      <h2>Unset</h2>
      <RadioGroup.Root className={styles.root}>
        <RadioGroup.Item className={styles.item} value="1">
          <RadioGroup.Indicator className={styles.indicator} />
        </RadioGroup.Item>
        <RadioGroup.Item className={styles.item} value="2">
          <RadioGroup.Indicator className={styles.indicator} />
        </RadioGroup.Item>
        <RadioGroup.Item className={styles.item} value="3">
          <RadioGroup.Indicator className={styles.indicator} />
        </RadioGroup.Item>
      </RadioGroup.Root>

      <h2>Set</h2>
      <RadioGroup.Root className={styles.root} defaultValue="3">
        <RadioGroup.Item className={styles.item} value="1">
          <RadioGroup.Indicator className={styles.indicator} />
        </RadioGroup.Item>
        <RadioGroup.Item className={styles.item} value="2">
          <RadioGroup.Indicator className={styles.indicator} />
        </RadioGroup.Item>
        <RadioGroup.Item className={styles.item} value="3">
          <RadioGroup.Indicator className={styles.indicator} />
        </RadioGroup.Item>
      </RadioGroup.Root>

      <h1>Controlled</h1>
      <h2>Unset</h2>
      <RadioGroup.Root className={styles.root} value={null}>
        <RadioGroup.Item className={styles.item} value="1">
          <RadioGroup.Indicator className={styles.indicator} />
        </RadioGroup.Item>
        <RadioGroup.Item className={styles.item} value="2">
          <RadioGroup.Indicator className={styles.indicator} />
        </RadioGroup.Item>
        <RadioGroup.Item className={styles.item} value="3">
          <RadioGroup.Indicator className={styles.indicator} />
        </RadioGroup.Item>
      </RadioGroup.Root>

      <h2>Set</h2>
      <RadioGroup.Root className={styles.root} value="3">
        <RadioGroup.Item className={styles.item} value="1">
          <RadioGroup.Indicator className={styles.indicator} />
        </RadioGroup.Item>
        <RadioGroup.Item className={styles.item} value="2">
          <RadioGroup.Indicator className={styles.indicator} />
        </RadioGroup.Item>
        <RadioGroup.Item className={styles.item} value="3">
          <RadioGroup.Indicator className={styles.indicator} />
        </RadioGroup.Item>
      </RadioGroup.Root>

      <h1>Disabled item</h1>
      <RadioGroup.Root className={styles.root}>
        <RadioGroup.Item className={styles.item} value="1">
          <RadioGroup.Indicator className={styles.indicator} />
        </RadioGroup.Item>
        <RadioGroup.Item className={styles.item} value="2" disabled>
          <RadioGroup.Indicator className={styles.indicator} />
        </RadioGroup.Item>
        <RadioGroup.Item className={styles.item} value="3">
          <RadioGroup.Indicator className={styles.indicator} />
        </RadioGroup.Item>
      </RadioGroup.Root>

      <h1>Disabled root</h1>
      <RadioGroup.Root className={styles.root} disabled>
        <RadioGroup.Item className={styles.item} value="1">
          <RadioGroup.Indicator className={styles.indicator} />
        </RadioGroup.Item>
        {/* Not possible to set `disabled` back to `false` since it's set on the root (this item
            should still be disabled). */}
        <RadioGroup.Item className={styles.item} value="2" disabled={false}>
          <RadioGroup.Indicator className={styles.indicator} />
        </RadioGroup.Item>
        <RadioGroup.Item className={styles.item} value="3">
          <RadioGroup.Indicator className={styles.indicator} />
        </RadioGroup.Item>
      </RadioGroup.Root>

      <h1>All items disabled</h1>
      <RadioGroup.Root className={styles.root}>
        <RadioGroup.Item className={styles.item} value="1" disabled>
          <RadioGroup.Indicator className={styles.indicator} />
        </RadioGroup.Item>
        <RadioGroup.Item className={styles.item} value="2" disabled>
          <RadioGroup.Indicator className={styles.indicator} />
        </RadioGroup.Item>
        <RadioGroup.Item className={styles.item} value="3" disabled>
          <RadioGroup.Indicator className={styles.indicator} />
        </RadioGroup.Item>
      </RadioGroup.Root>

      <h1>Manual focus into group</h1>
      <RadioGroup.Root className={styles.root}>
        <RadioGroup.Item className={styles.item} value="1" ref={manualFocusRef}>
          <RadioGroup.Indicator className={styles.indicator} />
        </RadioGroup.Item>
        <RadioGroup.Item className={styles.item} value="2">
          <RadioGroup.Indicator className={styles.indicator} />
        </RadioGroup.Item>
        <RadioGroup.Item className={styles.item} value="3">
          <RadioGroup.Indicator className={styles.indicator} />
        </RadioGroup.Item>
      </RadioGroup.Root>

      <h1>Force mounted indicator</h1>
      <RadioGroup.Root className={styles.root}>
        <RadioGroup.Item className={styles.item} value="1">
          <RadioGroup.Indicator className={styles.indicator} forceMount />
        </RadioGroup.Item>
        <RadioGroup.Item className={styles.item} value="2">
          <RadioGroup.Indicator className={styles.indicator} forceMount />
        </RadioGroup.Item>
        <RadioGroup.Item className={styles.item} value="3">
          <RadioGroup.Indicator className={styles.indicator} forceMount />
        </RadioGroup.Item>
      </RadioGroup.Root>

      <h1>Direction</h1>
      <h2>Prop</h2>
      <RadioGroup.Root className={styles.root} defaultValue="1" dir="rtl">
        <RadioGroup.Item className={styles.item} value="1">
          <RadioGroup.Indicator className={styles.indicator} />
        </RadioGroup.Item>
        <RadioGroup.Item className={styles.item} value="2">
          <RadioGroup.Indicator className={styles.indicator} />
        </RadioGroup.Item>
        <RadioGroup.Item className={styles.item} value="3">
          <RadioGroup.Indicator className={styles.indicator} />
        </RadioGroup.Item>
      </RadioGroup.Root>

      <h2>Inherited</h2>
      <Direction.Provider dir="rtl">
        <RadioGroup.Root className={styles.root} defaultValue="1">
          <RadioGroup.Item className={styles.item} value="1">
            <RadioGroup.Indicator className={styles.indicator} />
          </RadioGroup.Item>
          <RadioGroup.Item className={styles.item} value="2">
            <RadioGroup.Indicator className={styles.indicator} />
          </RadioGroup.Item>
          <RadioGroup.Item className={styles.item} value="3">
            <RadioGroup.Indicator className={styles.indicator} />
          </RadioGroup.Item>
        </RadioGroup.Root>
      </Direction.Provider>

      <h1>State attributes</h1>
      <h2>Default</h2>
      <RadioGroup.Root className={styles.rootAttr} defaultValue="3">
        <RadioGroup.Item className={styles.itemAttr} value="1">
          <RadioGroup.Indicator className={styles.indicatorAttr} />
        </RadioGroup.Item>
        <RadioGroup.Item className={styles.itemAttr} value="2">
          <RadioGroup.Indicator className={styles.indicatorAttr} />
        </RadioGroup.Item>
        <RadioGroup.Item className={styles.itemAttr} value="3">
          <RadioGroup.Indicator className={styles.indicatorAttr} />
        </RadioGroup.Item>
      </RadioGroup.Root>

      <h2>Disabled item</h2>
      <RadioGroup.Root className={styles.rootAttr} defaultValue="3">
        <RadioGroup.Item className={styles.itemAttr} value="1">
          <RadioGroup.Indicator className={styles.indicatorAttr} />
        </RadioGroup.Item>
        <RadioGroup.Item className={styles.itemAttr} value="2" disabled>
          <RadioGroup.Indicator className={styles.indicatorAttr} />
        </RadioGroup.Item>
        <RadioGroup.Item className={styles.itemAttr} value="3">
          <RadioGroup.Indicator className={styles.indicatorAttr} />
        </RadioGroup.Item>
      </RadioGroup.Root>

      <RadioGroup.Root className={styles.rootAttr} defaultValue="2">
        <RadioGroup.Item className={styles.itemAttr} value="1">
          <RadioGroup.Indicator className={styles.indicatorAttr} />
        </RadioGroup.Item>
        <RadioGroup.Item className={styles.itemAttr} value="2" disabled>
          <RadioGroup.Indicator className={styles.indicatorAttr} />
        </RadioGroup.Item>
        <RadioGroup.Item className={styles.itemAttr} value="3">
          <RadioGroup.Indicator className={styles.indicatorAttr} />
        </RadioGroup.Item>
      </RadioGroup.Root>

      <h2>Disabled root</h2>
      <RadioGroup.Root className={styles.rootAttr} defaultValue="3" disabled>
        <RadioGroup.Item className={styles.itemAttr} value="1">
          <RadioGroup.Indicator className={styles.indicatorAttr} />
        </RadioGroup.Item>
        <RadioGroup.Item className={styles.itemAttr} value="2">
          <RadioGroup.Indicator className={styles.indicatorAttr} />
        </RadioGroup.Item>
        <RadioGroup.Item className={styles.itemAttr} value="3">
          <RadioGroup.Indicator className={styles.indicatorAttr} />
        </RadioGroup.Item>
      </RadioGroup.Root>

      <h2>All items disabled</h2>
      <RadioGroup.Root className={styles.rootAttr} defaultValue="3">
        <RadioGroup.Item className={styles.itemAttr} value="1" disabled>
          <RadioGroup.Indicator className={styles.indicatorAttr} />
        </RadioGroup.Item>
        <RadioGroup.Item className={styles.itemAttr} value="2" disabled>
          <RadioGroup.Indicator className={styles.indicatorAttr} />
        </RadioGroup.Item>
        <RadioGroup.Item className={styles.itemAttr} value="3" disabled>
          <RadioGroup.Indicator className={styles.indicatorAttr} />
        </RadioGroup.Item>
      </RadioGroup.Root>
    </>
  );
};
LegacyChromatic.parameters = { chromatic: { disable: false } };

const Label = (props: any) => <LabelPrimitive.Root {...props} className={styles.label} />;



================================================
FILE: apps/storybook/stories/roving-focus-group.stories.tsx
================================================
import * as React from 'react';
import { composeEventHandlers, RovingFocus } from 'radix-ui/internal';

type RovingFocusGroupProps = React.ComponentProps<typeof RovingFocus.Root>;

export default { title: 'Utilities/RovingFocusGroup' };

export const Basic = () => {
  const [dir, setDir] = React.useState<RovingFocusGroupProps['dir']>('ltr');

  return (
    <div dir={dir}>
      <h1>
        Direction: {dir}{' '}
        <button type="button" onClick={() => setDir((prev) => (prev === 'ltr' ? 'rtl' : 'ltr'))}>
          Toggle to {dir === 'ltr' ? 'rtl' : 'ltr'}
        </button>
      </h1>

      <h2>no orientation (both) + no looping</h2>
      <ButtonGroup dir={dir} defaultValue="two">
        <Button value="one">One</Button>
        <Button value="two">Two</Button>
        <Button disabled value="three">
          Three
        </Button>
        <Button value="four">Four</Button>
      </ButtonGroup>

      <h2>no orientation (both) + looping</h2>
      <ButtonGroup dir={dir} loop>
        <Button value="hidden" style={{ display: 'none' }}>
          Hidden
        </Button>
        <Button value="one">One</Button>
        <Button value="two">Two</Button>
        <Button disabled value="three">
          Three
        </Button>
        <Button value="four">Four</Button>
      </ButtonGroup>

      <h2>horizontal orientation + no looping</h2>
      <ButtonGroup orientation="horizontal" dir={dir}>
        <Button value="one">One</Button>
        <Button value="two">Two</Button>
        <Button disabled value="three">
          Three
        </Button>
        <Button value="four">Four</Button>
      </ButtonGroup>

      <h2>horizontal orientation + looping</h2>
      <ButtonGroup orientation="horizontal" dir={dir} loop>
        <Button value="one">One</Button>
        <Button value="two">Two</Button>
        <Button disabled value="three">
          Three
        </Button>
        <Button value="four">Four</Button>
      </ButtonGroup>

      <h2>vertical orientation + no looping</h2>
      <ButtonGroup orientation="vertical" dir={dir}>
        <Button value="one">One</Button>
        <Button value="two">Two</Button>
        <Button disabled value="three">
          Three
        </Button>
        <Button value="four">Four</Button>
      </ButtonGroup>

      <h2>vertical orientation + looping</h2>
      <ButtonGroup orientation="vertical" dir={dir} loop>
        <Button value="one">One</Button>
        <Button value="two">Two</Button>
        <Button disabled value="three">
          Three
        </Button>
        <Button value="four">Four</Button>
      </ButtonGroup>
    </div>
  );
};

export const Nested = () => (
  <ButtonGroup orientation="vertical" loop>
    <Button value="1">1</Button>

    <div style={{ display: 'flex', flexDirection: 'column' }}>
      <Button value="2" style={{ marginBottom: 10 }}>
        2
      </Button>

      <ButtonGroup orientation="horizontal" loop>
        <Button value="2.1">2.1</Button>
        <Button value="2.2">2.2</Button>
        <Button disabled value="2.3">
          2.3
        </Button>
        <Button value="2.4">2.4</Button>
      </ButtonGroup>
    </div>

    <Button value="3" disabled>
      3
    </Button>
    <Button value="4">4</Button>
  </ButtonGroup>
);

export const EdgeCases = () => {
  const [extra, setExtra] = React.useState(false);
  const [disabled, setDisabled] = React.useState(false);
  const [hidden, setHidden] = React.useState(false);
  const [disabled3To5, setDisabled3To5] = React.useState(false);

  return (
    <>
      <button onClick={() => setExtra((x) => !x)}>Add/remove extra</button>
      <button onClick={() => setDisabled((x) => !x)}>Disable/Enable "One"</button>
      <button onClick={() => setHidden((x) => !x)}>Hide/show "One"</button>
      <button onClick={() => setDisabled3To5((x) => !x)}>Disable/Enable "Three" to "Five"</button>
      <hr />

      <ButtonGroup>
        {extra ? <Button value="extra">Extra</Button> : null}
        <Button value="one" disabled={disabled} style={{ display: hidden ? 'none' : undefined }}>
          One
        </Button>
        <Button value="two" disabled>
          Two
        </Button>
        <Button value="three" disabled={disabled3To5}>
          Three
        </Button>
        <Button value="four" disabled={disabled3To5} style={{ display: 'none' }}>
          Four
        </Button>
        <Button value="five" disabled={disabled3To5}>
          Five
        </Button>
      </ButtonGroup>

      <hr />
      <button type="button">Focusable outside of group</button>
    </>
  );
};

const ButtonGroupContext = React.createContext<{
  value?: string;
  setValue: React.Dispatch<React.SetStateAction<string | undefined>>;
}>({} as any);

type ButtonGroupProps = Omit<React.ComponentPropsWithRef<'div'>, 'defaultValue'> &
  RovingFocusGroupProps & { defaultValue?: string };

const ButtonGroup = ({ defaultValue, ...props }: ButtonGroupProps) => {
  const [value, setValue] = React.useState(defaultValue);
  return (
    <ButtonGroupContext.Provider value={{ value, setValue }}>
      <RovingFocus.Root
        {...props}
        style={{
          ...props.style,
          display: 'inline-flex',
          flexDirection: props.orientation === 'vertical' ? 'column' : 'row',
          gap: 10,
        }}
      />
    </ButtonGroupContext.Provider>
  );
};

type ButtonProps = Omit<React.ComponentPropsWithRef<'button'>, 'value'> & { value?: string };

const Button = (props: ButtonProps) => {
  const { value: contextValue, setValue } = React.useContext(ButtonGroupContext);
  const isSelected =
    contextValue !== undefined && props.value !== undefined && contextValue === props.value;

  return (
    <RovingFocus.Item asChild active={isSelected} focusable={!props.disabled}>
      <button
        {...props}
        style={{
          ...props.style,
          border: '1px solid',
          borderColor: '#ccc',
          padding: '5px 10px',
          borderRadius: 5,
          ...(isSelected
            ? {
                borderColor: 'black',
                backgroundColor: 'black',
                color: 'white',
              }
            : {}),
        }}
        onClick={props.disabled ? undefined : () => setValue(props.value)}
        onFocus={composeEventHandlers(props.onFocus, (event) => {
          if (contextValue !== undefined) {
            event.target.click();
          }
        })}
      />
    </RovingFocus.Item>
  );
};



================================================
FILE: apps/storybook/stories/scroll-area.stories.module.css
================================================
.root,
:global(:root) {
  --scroll-area-scrollbar-size: 8px;
}

.scrollArea {
  width: 100%;
  height: 100%;
  border: 1px solid black;
}

.scrollAreaViewport {
  width: 100%;
  height: 100%;
}

.scrollbar {
  display: flex;
  /* ensures no selection */
  user-select: none;
  /* disable browser handling of all panning and zooming gestures on touch devices */
  touch-action: none;
  transition: background 160ms ease-out;
  padding: 2px;
  background: rgba(0, 0, 0, 0.3);
  &:hover {
    background: rgba(0, 0, 0, 0.5);
  }
  &[data-orientation='vertical'] {
    width: var(--scroll-area-scrollbar-size);
  }
  &[data-orientation='horizontal'] {
    flex-direction: column;
    height: var(--scroll-area-scrollbar-size);
  }
}

.thumb {
  flex: 1;
  /* increase target size for touch devices https://www.w3.org/WAI/WCAG21/Understanding/target-size.html */
  position: relative;
  &::before {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 100%;
    height: 100%;
    min-width: 44px;
    min-height: 44px;
  }
  background: black;
  border-radius: var(--scroll-area-scrollbar-size);
}

.corner {
  background: rgba(0, 0, 0, 0.3);
  position: relative;
  &::after {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    background: black;
    width: var(--scroll-area-scrollbar-size);
    height: var(--scroll-area-scrollbar-size);
    border-radius: var(--scroll-area-scrollbar-size);
  }
}

.animatedThumb {
  &[data-state='visible'] {
    animation: scrollArea-fadeIn 300ms ease;
  }
  &[data-state='hidden'] {
    animation: scrollArea-fadeOut 300ms ease;
  }
}

@keyframes scrollArea-fadeIn {
  from {
    transform: scale(0.2);
    opacity: 0;
  }
  to {
    transform: scale(1);
    opacity: 1;
  }
}

@keyframes scrollArea-fadeOut {
  from {
    transform: scale(1);
    opacity: 1;
  }
  to {
    transform: scale(0.2);
    opacity: 0;
  }
}



================================================
FILE: apps/storybook/stories/scroll-area.stories.tsx
================================================
import * as React from 'react';
import { Direction, ScrollArea } from 'radix-ui';
import styles from './scroll-area.stories.module.css';

export default { title: 'Components/ScrollArea' };

export const Basic = () => {
  const [props, setProps] = React.useState({} as any);
  return (
    <div className={styles.root}>
      <div style={{ margin: '20px auto', width: 'max-content', textAlign: 'center' }}>
        <form
          onChange={(event) => {
            const formData = new FormData(event.currentTarget);
            const entries = (formData as any).entries();
            const cleanup = [...entries].map(([key, value]: any) => [key, value || undefined]);
            const props = Object.fromEntries(cleanup);
            setProps(props);
          }}
        >
          <label>
            type:{' '}
            <select name="type">
              <option></option>
              <option>always</option>
              <option>auto</option>
              <option>scroll</option>
              <option>hover</option>
            </select>
          </label>{' '}
          <label>
            dir:{' '}
            <select name="dir">
              <option></option>
              <option>ltr</option>
              <option>rtl</option>
            </select>
          </label>{' '}
          <label>
            scrollHideDelay: <input type="number" name="scrollHideDelay" />
          </label>
        </form>
      </div>

      <ScrollAreaStory
        {...props}
        key={props.type}
        style={{ width: 800, height: 800, margin: '30px auto' }}
      >
        {Array.from({ length: 30 }).map((_, index) => (
          <Copy key={index} />
        ))}
      </ScrollAreaStory>
    </div>
  );
};

export const Resizable = () => (
  <div
    className={styles.root}
    style={{
      width: 800,
      height: 800,
      padding: 20,
      resize: 'both',
      border: '1px solid gray',
      overflow: 'hidden',
    }}
  >
    <ScrollAreaStory style={{ width: '100%', height: '100%' }}>
      {Array.from({ length: 30 }).map((_, index) => (
        <Copy key={index} />
      ))}
    </ScrollAreaStory>
  </div>
);

export const ContentChange = () => {
  const [verticalCount, setVerticalCount] = React.useState(1);
  const [horizontalCount, setHorizontalCount] = React.useState(1);
  return (
    <div className={styles.root}>
      <button onClick={() => setVerticalCount((count) => count + 1)}>Add vertical content</button>
      <button onClick={() => setHorizontalCount((count) => count + 1)}>
        Increase horizontal size
      </button>
      <ScrollAreaStory type="always" style={{ width: 800, height: 800 }}>
        {Array.from({ length: verticalCount }).map((_, index) => (
          <Copy key={index} style={{ width: 300 * horizontalCount + 'px' }} />
        ))}
      </ScrollAreaStory>
    </div>
  );
};

export const Animated = () => {
  return (
    <div className={styles.root}>
      <ScrollAreaStory animated style={{ width: 800, height: 800 }}>
        {Array.from({ length: 30 }).map((_, index) => (
          <Copy key={index} />
        ))}
      </ScrollAreaStory>
    </div>
  );
};

export const Chromatic = () => (
  <div className={styles.root}>
    <h1>Vertical</h1>
    <h2>Auto with overflow</h2>
    <ScrollAreaStory type="auto" vertical horizontal={false}>
      {Array.from({ length: 10 }).map((_, index) => (
        <Copy key={index} />
      ))}
    </ScrollAreaStory>

    <h2>Auto without overflow</h2>
    <ScrollAreaStory type="auto" vertical horizontal={false}>
      <Copy style={{ height: 50, overflow: 'hidden' }} />
    </ScrollAreaStory>

    <h2>Always with overflow</h2>
    <ScrollAreaStory type="always" vertical horizontal={false}>
      {Array.from({ length: 10 }).map((_, index) => (
        <Copy key={index} />
      ))}
    </ScrollAreaStory>

    <h2>Always without overflow</h2>
    <ScrollAreaStory type="always" vertical horizontal={false}>
      <Copy style={{ height: 50, overflow: 'hidden' }} />
    </ScrollAreaStory>

    <h2>Scroll with overflow</h2>
    <ScrollAreaStory type="scroll" vertical horizontal={false}>
      {Array.from({ length: 10 }).map((_, index) => (
        <Copy key={index} />
      ))}
    </ScrollAreaStory>

    <h2>Scroll without overflow</h2>
    <ScrollAreaStory type="scroll" vertical horizontal={false}>
      <Copy style={{ height: 50, overflow: 'hidden' }} />
    </ScrollAreaStory>

    <h2>Hover with overflow</h2>
    <ScrollAreaStory type="hover" vertical horizontal={false}>
      {Array.from({ length: 10 }).map((_, index) => (
        <Copy key={index} />
      ))}
    </ScrollAreaStory>

    <h2>Hover without overflow</h2>
    <ScrollAreaStory type="hover" vertical horizontal={false}>
      <Copy style={{ height: 50, overflow: 'hidden' }} />
    </ScrollAreaStory>

    <h1>Horizontal</h1>
    <h2>Auto with overflow</h2>
    <ScrollAreaStory type="auto" vertical={false} horizontal>
      {Array.from({ length: 10 }).map((_, index) => (
        <Copy key={index} />
      ))}
    </ScrollAreaStory>

    <h2>Auto without overflow</h2>
    <ScrollAreaStory type="auto" vertical={false} horizontal>
      <Copy style={{ width: 50, overflow: 'hidden' }} />
    </ScrollAreaStory>

    <h2>Always with overflow</h2>
    <ScrollAreaStory type="always" vertical={false} horizontal>
      {Array.from({ length: 10 }).map((_, index) => (
        <Copy key={index} />
      ))}
    </ScrollAreaStory>

    <h2>Always without overflow</h2>
    <ScrollAreaStory type="always" vertical={false} horizontal>
      <Copy style={{ width: 50, overflow: 'hidden' }} />
    </ScrollAreaStory>

    <h2>Scroll with overflow</h2>
    <ScrollAreaStory type="scroll" vertical={false} horizontal>
      {Array.from({ length: 10 }).map((_, index) => (
        <Copy key={index} />
      ))}
    </ScrollAreaStory>

    <h2>Scroll without overflow</h2>
    <ScrollAreaStory type="scroll" vertical={false} horizontal>
      <Copy style={{ width: 50, overflow: 'hidden' }} />
    </ScrollAreaStory>

    <h2>Hover with overflow</h2>
    <ScrollAreaStory type="hover" vertical={false} horizontal>
      {Array.from({ length: 10 }).map((_, index) => (
        <Copy key={index} />
      ))}
    </ScrollAreaStory>

    <h2>Hover without overflow</h2>
    <ScrollAreaStory type="hover" vertical={false} horizontal>
      <Copy style={{ width: 50, overflow: 'hidden' }} />
    </ScrollAreaStory>

    <h1>Both</h1>
    <h2>Auto with overflow</h2>
    <ScrollAreaStory type="auto" vertical horizontal>
      {Array.from({ length: 10 }).map((_, index) => (
        <Copy key={index} />
      ))}
    </ScrollAreaStory>

    <h2>Auto with horizontal overflow</h2>
    <ScrollAreaStory type="auto" vertical horizontal>
      {Array.from({ length: 1 }).map((_, index) => (
        <Copy key={index} />
      ))}
    </ScrollAreaStory>

    <h2>Auto with vertical overflow</h2>
    <ScrollAreaStory type="auto" vertical horizontal>
      {Array.from({ length: 10 }).map((_, index) => (
        <Copy key={index} style={{ width: 50, overflow: 'hidden' }} />
      ))}
    </ScrollAreaStory>

    <h2>Auto without overflow</h2>
    <ScrollAreaStory type="auto" vertical horizontal>
      <Copy style={{ width: 50, height: 50, overflow: 'hidden' }} />
    </ScrollAreaStory>

    <h2>Always with overflow</h2>
    <ScrollAreaStory type="always" vertical horizontal>
      {Array.from({ length: 10 }).map((_, index) => (
        <Copy key={index} />
      ))}
    </ScrollAreaStory>

    <h2>Always without overflow</h2>
    <ScrollAreaStory type="always" vertical horizontal>
      <Copy style={{ width: 50, height: 50, overflow: 'hidden' }} />
    </ScrollAreaStory>

    <h2>Scroll with overflow</h2>
    <ScrollAreaStory type="scroll" vertical horizontal>
      {Array.from({ length: 10 }).map((_, index) => (
        <Copy key={index} />
      ))}
    </ScrollAreaStory>

    <h2>Scroll without overflow</h2>
    <ScrollAreaStory type="scroll" vertical horizontal>
      <Copy style={{ width: 50, height: 50, overflow: 'hidden' }} />
    </ScrollAreaStory>

    <h2>Hover with overflow</h2>
    <ScrollAreaStory type="hover" vertical horizontal>
      {Array.from({ length: 10 }).map((_, index) => (
        <Copy key={index} />
      ))}
    </ScrollAreaStory>

    <h2>Hover without overflow</h2>
    <ScrollAreaStory type="hover" vertical horizontal>
      <Copy style={{ width: 50, height: 50, overflow: 'hidden' }} />
    </ScrollAreaStory>

    <h2>Hover with horizontal overflow</h2>
    <ScrollAreaStory type="hover" vertical horizontal>
      {Array.from({ length: 1 }).map((_, index) => (
        <Copy key={index} />
      ))}
    </ScrollAreaStory>

    <h2>Hover with vertical overflow</h2>
    <ScrollAreaStory type="hover" vertical horizontal>
      {Array.from({ length: 10 }).map((_, index) => (
        <Copy key={index} style={{ width: 50, overflow: 'hidden' }} />
      ))}
    </ScrollAreaStory>

    <h1>Min thumb size</h1>
    <ScrollAreaStory type="always" vertical horizontal>
      {Array.from({ length: 100 }).map((_, index) => (
        <Copy key={index} style={{ width: 10000 }} />
      ))}
    </ScrollAreaStory>

    <h1>RTL</h1>
    <h2>Prop</h2>
    <ScrollAreaStory type="always" dir="rtl" vertical horizontal>
      {Array.from({ length: 10 }).map((_, index) => (
        <Copy key={index} />
      ))}
    </ScrollAreaStory>

    <h2>Inherited</h2>
    <Direction.Provider dir="rtl">
      <ScrollAreaStory type="always" vertical horizontal>
        {Array.from({ length: 10 }).map((_, index) => (
          <Copy key={index} />
        ))}
      </ScrollAreaStory>
    </Direction.Provider>
  </div>
);
Chromatic.parameters = { chromatic: { disable: false } };

const DYNAMIC_CONTENT_DELAY = 2000;

export const ChromaticDynamicContentBeforeLoaded = () => {
  const [showContent, setShowContent] = React.useState(false);

  React.useEffect(() => {
    setTimeout(() => {
      setShowContent(true);
    }, DYNAMIC_CONTENT_DELAY);
  }, []);

  return (
    <div className={styles.root}>
      <h1>Always</h1>
      <ScrollAreaStory type="always" style={{ width: 500, height: 250 }}>
        {showContent ? (
          Array.from({ length: 30 }).map((_, index) => <Copy key={index} />)
        ) : (
          <h1>Loading...</h1>
        )}
      </ScrollAreaStory>

      <h1>Hover</h1>
      <ScrollAreaStory type="hover" style={{ width: 500, height: 250 }}>
        {showContent ? (
          Array.from({ length: 30 }).map((_, index) => <Copy key={index} />)
        ) : (
          <h1>Loading...</h1>
        )}
      </ScrollAreaStory>

      <h1>Scroll</h1>
      <ScrollAreaStory type="scroll" style={{ width: 500, height: 250 }}>
        {showContent ? (
          Array.from({ length: 30 }).map((_, index) => <Copy key={index} />)
        ) : (
          <h1>Loading...</h1>
        )}
      </ScrollAreaStory>

      <h1>Auto</h1>
      <ScrollAreaStory type="auto" style={{ width: 500, height: 250 }}>
        {showContent ? (
          Array.from({ length: 30 }).map((_, index) => <Copy key={index} />)
        ) : (
          <h1>Loading...</h1>
        )}
      </ScrollAreaStory>
    </div>
  );
};
ChromaticDynamicContentBeforeLoaded.parameters = { chromatic: { disable: false } };

export const ChromaticDynamicContentAfterLoaded = () => <ChromaticDynamicContentBeforeLoaded />;
ChromaticDynamicContentAfterLoaded.parameters = {
  chromatic: { disable: false, delay: DYNAMIC_CONTENT_DELAY },
};

const ScrollAreaStory = ({
  children,
  animated = false,
  vertical = true,
  horizontal = true,
  ...props
}: any) => (
  <ScrollArea.Root
    {...props}
    className={styles.scrollArea}
    style={{ width: 200, height: 200, ...props.style }}
  >
    <ScrollArea.Viewport className={styles.scrollAreaViewport}>{children}</ScrollArea.Viewport>
    {vertical && (
      <ScrollArea.Scrollbar className={styles.scrollbar} orientation="vertical">
        <ScrollArea.Thumb
          className={[animated && styles.animatedThumb, styles.thumb].filter(Boolean).join(' ')}
        />
      </ScrollArea.Scrollbar>
    )}
    {horizontal && (
      <ScrollArea.Scrollbar className={styles.scrollbar} orientation="horizontal">
        <ScrollArea.Thumb
          className={[animated && styles.animatedThumb, styles.thumb].filter(Boolean).join(' ')}
        />
      </ScrollArea.Scrollbar>
    )}
    <ScrollArea.Corner className={styles.corner} />
  </ScrollArea.Root>
);

const Copy = (props: any) => (
  <p style={{ width: 4000, marginTop: 0, ...props.style }}>
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sit amet eros iaculis, bibendum
    tellus ac, lobortis odio. Aliquam bibendum elit est, in iaculis est commodo id. Donec pulvinar
    est libero. Proin consectetur pellentesque molestie. Fusce mi ante, ullamcorper eu ante finibus,
    finibus pellentesque turpis. Mauris convallis, leo in vulputate varius, sapien lectus suscipit
    eros, ac semper odio sapien sit amet magna. Sed mattis turpis et lacinia ultrices. Nulla a
    commodo mauris. Orci varius natoque penatibus et magnis dis parturient montes, nascetur
    ridiculus mus. Pellentesque id tempor metus. Pellentesque faucibus tortor non nisi maximus
    dignissim. Etiam leo nisi, molestie a porttitor at, euismod a libero. Nullam placerat tristique
    enim nec pulvinar. Sed eleifend dictum nulla a aliquam. Sed tempus ipsum eget urna posuere
    aliquam. Nulla maximus tortor dui, sed laoreet odio aliquet ac. Vestibulum dolor orci, lacinia
    finibus vehicula eget, posuere ac lectus. Quisque non felis at ipsum scelerisque condimentum. In
    pharetra semper arcu, ut hendrerit sem auctor vel. Aliquam non lacinia elit, a facilisis ante.
    Praesent eget eros augue. Praesent nunc orci, ullamcorper non pulvinar eu, elementum id nibh.
    Nam id lorem euismod, sodales augue quis, porttitor magna. Vivamus ut nisl velit. Nam ultrices
    maximus felis, quis ullamcorper quam luctus et.
  </p>
);



================================================
FILE: apps/storybook/stories/select.stories.module.css
================================================
.trigger {
  display: flex;
  align-items: center;
  gap: 5px;
  border: 1px solid var(--color-black);
  border-radius: 6px;
  background-color: transparent;
  height: 50px;
  padding: 5px 15px;
  font-family: -apple-system, BlinkMacSystemFont, helvetica, arial, sans-serif;
  font-size: 13px;
  line-height: 1;
  overflow: hidden;

  &:focus {
    outline: none;
    box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.5);
  }
}

.content {
  background-color: var(--color-white);
  border: 1px solid var(--color-gray100);
  border-radius: 6px;
  box-shadow: 0 5px 10px 0 rgba(0, 0, 0, 0.1);
  position: relative;
  &:focus-within {
    border-color: var(--color-black);
  }
  min-width: var(--radix-select-trigger-width);
  max-height: var(--radix-select-content-available-height);
}

.contentWithPadding {
  padding: 5px;
}

.viewport {
  padding: 5px;
}

.group {
}

.label,
.item {
  display: flex;
  align-items: center;
  line-height: 1;
  cursor: default;
  user-select: none;
  white-space: nowrap;
  height: 25px;
  padding: 0 25px;
  font-family: -apple-system, BlinkMacSystemFont, helvetica, arial, sans-serif;
  font-size: 13px;
  color: var(--color-black);
  border-radius: 3px;
}

.label {
  color: var(--color-gray300);
  font-weight: 500;
}

.item {
  position: relative;
  outline: none;
  &:active {
    background-color: var(--color-gray100);
  }

  &[data-highlighted] {
    background-color: var(--color-black);
    color: white;
  }

  &[data-disabled] {
    color: var(--color-gray100);
  }
  [dir='rtl'] & {
    font-size: 16px;
    font-weight: bold;
  }
}

.itemInGroup {
  padding-left: 35px;
}

.indicator {
  position: absolute;
  left: 6px;
  top: 6px;
  & :global(svg) {
    display: block;
  }
  [dir='rtl'] & {
    left: auto;
    right: 6px;
  }
}

.scrollButton {
  display: flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  height: 25px;
  background-color: var(--color-white);
  color: var(--color-black);
  cursor: default;
  user-select: none;
}

.scrollUpButton {
  border-bottom: 1px solid rgba(0, 0, 0, 0.2);
  border-top-left-radius: 6px;
  border-top-right-radius: 6px;
}

.scrollDownButton {
  border-top: 1px solid rgba(0, 0, 0, 0.2);
  border-bottom-left-radius: 6px;
  border-bottom-right-radius: 6px;
}

.separator {
  height: 1px;
  margin: 5px -5px;
  background-color: var(--color-gray100);
}



================================================
FILE: apps/storybook/stories/select.stories.tsx
================================================
import * as React from 'react';
import { Dialog, Select, Label as LabelPrimitive } from 'radix-ui';
import { foodGroups } from '@repo/test-data/foods';
import styles from './select.stories.module.css';

const Label = LabelPrimitive.Root;

export default { title: 'Components/Select' };

const scrollUpButtonClass = [styles.scrollUpButton, styles.scrollButton].join(' ');
const scrollDownButtonClass = [styles.scrollDownButton, styles.scrollButton].join(' ');

const POSITIONS = ['item-aligned', 'popper'] as const;

export const Styled = () => (
  <div style={{ display: 'flex', gap: 20, padding: 50 }}>
    {POSITIONS.map((position) => (
      <Label key={position}>
        Choose a number:
        <Select.Root defaultValue="two">
          <Select.Trigger className={styles.trigger}>
            <Select.Value />
            <Select.Icon />
          </Select.Trigger>
          <Select.Portal>
            <Select.Content className={styles.content} position={position} sideOffset={5}>
              <Select.Viewport className={styles.viewport}>
                <Select.Item className={styles.item} value="one">
                  <Select.ItemText>
                    One<span aria-hidden> 👍</span>
                  </Select.ItemText>
                  <Select.ItemIndicator className={styles.indicator}>
                    <TickIcon />
                  </Select.ItemIndicator>
                </Select.Item>
                <Select.Item className={styles.item} value="two">
                  <Select.ItemText>
                    Two<span aria-hidden> 👌</span>
                  </Select.ItemText>
                  <Select.ItemIndicator className={styles.indicator}>
                    <TickIcon />
                  </Select.ItemIndicator>
                </Select.Item>
                <Select.Item className={styles.item} value="three">
                  <Select.ItemText>
                    Three<span aria-hidden> 🤘</span>
                  </Select.ItemText>
                  <Select.ItemIndicator className={styles.indicator}>
                    <TickIcon />
                  </Select.ItemIndicator>
                </Select.Item>
              </Select.Viewport>
              <Select.Arrow />
            </Select.Content>
          </Select.Portal>
        </Select.Root>
      </Label>
    ))}
  </div>
);

export const Controlled = () => {
  const [value, setValue] = React.useState('uk');
  return (
    <div style={{ display: 'flex', gap: 20, padding: 50 }}>
      {POSITIONS.map((position) => (
        <Label key={position}>
          Choose a country:
          <Select.Root value={value} onValueChange={setValue}>
            <Select.Trigger className={styles.trigger}>
              <Select.Value
                aria-label={
                  value === 'fr'
                    ? 'France'
                    : value === 'uk'
                      ? 'United Kingdom'
                      : value === 'es'
                        ? 'Spain'
                        : undefined
                }
              >
                {value === 'fr' ? '🇫🇷' : value === 'uk' ? '🇬🇧' : value === 'es' ? '🇪🇸' : null}
              </Select.Value>
              <Select.Icon />
            </Select.Trigger>
            <Select.Portal>
              <Select.Content className={styles.content} position={position} sideOffset={5}>
                <Select.Viewport className={styles.viewport}>
                  <Select.Item className={styles.item} value="fr">
                    <Select.ItemText>
                      France<span aria-hidden> 🇫🇷</span>
                    </Select.ItemText>
                    <Select.ItemIndicator className={styles.indicator}>
                      <TickIcon />
                    </Select.ItemIndicator>
                  </Select.Item>
                  <Select.Item className={styles.item} value="uk">
                    <Select.ItemText>
                      United Kingdom<span aria-hidden> 🇬🇧</span>
                    </Select.ItemText>
                    <Select.ItemIndicator className={styles.indicator}>
                      <TickIcon />
                    </Select.ItemIndicator>
                  </Select.Item>
                  <Select.Item className={styles.item} value="es">
                    <Select.ItemText>
                      Spain<span aria-hidden> 🇪🇸</span>
                    </Select.ItemText>
                    <Select.ItemIndicator className={styles.indicator}>
                      <TickIcon />
                    </Select.ItemIndicator>
                  </Select.Item>
                </Select.Viewport>
                <Select.Arrow />
              </Select.Content>
            </Select.Portal>
          </Select.Root>
        </Label>
      ))}
    </div>
  );
};

export const Position = () => (
  <div
    style={{
      display: 'flex',
      gap: 20,
      alignItems: 'center',
      justifyContent: 'center',
      width: '300vw',
      height: '300vh',
    }}
  >
    {POSITIONS.map((position) => (
      <Label key={position}>
        Choose an item:
        <Select.Root defaultValue="item-25">
          <Select.Trigger className={styles.trigger}>
            <Select.Value />
            <Select.Icon />
          </Select.Trigger>
          <Select.Portal>
            <Select.Content className={styles.content} position={position} sideOffset={5}>
              <Select.ScrollUpButton className={scrollUpButtonClass}>▲</Select.ScrollUpButton>
              <Select.Viewport className={styles.viewport}>
                {Array.from({ length: 50 }, (_, i) => {
                  const value = `item-${i + 1}`;
                  return (
                    <Select.Item
                      key={value}
                      className={styles.item}
                      value={value}
                      disabled={i > 5 && i < 9}
                    >
                      <Select.ItemText>item {i + 1}</Select.ItemText>
                      <Select.ItemIndicator className={styles.indicator}>
                        <TickIcon />
                      </Select.ItemIndicator>
                    </Select.Item>
                  );
                })}
              </Select.Viewport>
              <Select.ScrollDownButton className={scrollDownButtonClass}>▼</Select.ScrollDownButton>
              <Select.Arrow />
            </Select.Content>
          </Select.Portal>
        </Select.Root>
      </Label>
    ))}
  </div>
);

export const NoDefaultValue = () => (
  <div
    style={{
      display: 'flex',
      gap: 20,
      alignItems: 'center',
      justifyContent: 'center',
      height: '100vh',
    }}
  >
    {POSITIONS.map((position) => (
      <Label key={position}>
        Choose a number:
        <Select.Root>
          <Select.Trigger className={styles.trigger}>
            <Select.Value placeholder="Pick an option" />
            <Select.Icon />
          </Select.Trigger>
          <Select.Portal>
            <Select.Content className={styles.content} position={position} sideOffset={5}>
              <Select.Viewport className={styles.viewport}>
                <Select.Item className={styles.item} value="one" disabled>
                  <Select.ItemText>One</Select.ItemText>
                  <Select.ItemIndicator className={styles.indicator}>
                    <TickIcon />
                  </Select.ItemIndicator>
                </Select.Item>
                <Select.Item className={styles.item} value="two">
                  <Select.ItemText>Two</Select.ItemText>
                  <Select.ItemIndicator className={styles.indicator}>
                    <TickIcon />
                  </Select.ItemIndicator>
                </Select.Item>
                <Select.Item className={styles.item} value="three">
                  <Select.ItemText>Three</Select.ItemText>
                  <Select.ItemIndicator className={styles.indicator}>
                    <TickIcon />
                  </Select.ItemIndicator>
                </Select.Item>
              </Select.Viewport>
              <Select.Arrow />
            </Select.Content>
          </Select.Portal>
        </Select.Root>
      </Label>
    ))}
  </div>
);

export const Typeahead = () => (
  <div
    style={{
      display: 'flex',
      gap: 20,
      alignItems: 'center',
      justifyContent: 'center',
      height: '300vh',
    }}
  >
    {POSITIONS.map((position) => (
      <Label key={position}>
        Favourite food:
        <Select.Root defaultValue="banana">
          <Select.Trigger className={styles.trigger}>
            <Select.Value />
            <Select.Icon />
          </Select.Trigger>
          <Select.Portal>
            <Select.Content className={styles.content} position={position} sideOffset={5}>
              <Select.ScrollUpButton className={scrollUpButtonClass}>▲</Select.ScrollUpButton>
              <Select.Viewport className={styles.viewport}>
                {foodGroups.map((foodGroup) =>
                  foodGroup.foods.map((food) => (
                    <Select.Item key={food.value} className={styles.item} value={food.value}>
                      <Select.ItemText>{food.label}</Select.ItemText>
                      <Select.ItemIndicator className={styles.indicator}>
                        <TickIcon />
                      </Select.ItemIndicator>
                    </Select.Item>
                  )),
                )}
              </Select.Viewport>
              <Select.ScrollDownButton className={scrollDownButtonClass}>▼</Select.ScrollDownButton>
              <Select.Arrow />
            </Select.Content>
          </Select.Portal>
        </Select.Root>
      </Label>
    ))}
  </div>
);

export const WithGroups = () => (
  <div
    style={{
      display: 'flex',
      gap: 20,
      alignItems: 'center',
      justifyContent: 'center',
      height: '300vh',
    }}
  >
    {POSITIONS.map((position) => (
      <Label key={position}>
        Favourite food:
        <Select.Root defaultValue="banana">
          <Select.Trigger className={styles.trigger}>
            <Select.Value />
            <Select.Icon />
          </Select.Trigger>
          <Select.Portal>
            <Select.Content className={styles.content} position={position} sideOffset={5}>
              <Select.ScrollUpButton className={scrollUpButtonClass}>▲</Select.ScrollUpButton>
              <Select.Viewport className={styles.viewport}>
                {foodGroups.map((foodGroup, index) => {
                  const hasLabel = foodGroup.label !== undefined;
                  return (
                    <React.Fragment key={index}>
                      <Select.Group className={styles.group}>
                        {hasLabel && (
                          <Select.Label className={styles.label} key={foodGroup.label}>
                            {foodGroup.label}
                          </Select.Label>
                        )}
                        {foodGroup.foods.map((food) => (
                          <Select.Item
                            key={food.value}
                            className={[hasLabel && styles.itemInGroup, styles.item]
                              .filter(Boolean)
                              .join(' ')}
                            value={food.value}
                          >
                            <Select.ItemText>{food.label}</Select.ItemText>
                            <Select.ItemIndicator className={styles.indicator}>
                              <TickIcon />
                            </Select.ItemIndicator>
                          </Select.Item>
                        ))}
                      </Select.Group>
                      {index < foodGroups.length - 1 && (
                        <Select.Separator className={styles.separator} />
                      )}
                    </React.Fragment>
                  );
                })}
              </Select.Viewport>
              <Select.ScrollDownButton className={scrollDownButtonClass}>▼</Select.ScrollDownButton>
              <Select.Arrow />
            </Select.Content>
          </Select.Portal>
        </Select.Root>
      </Label>
    ))}
  </div>
);

export const Labelling = () => {
  const content = (
    <Select.Portal>
      <Select.Content className={styles.content}>
        <Select.Viewport className={styles.viewport}>
          <Select.Item className={styles.item} value="0-18">
            <Select.ItemText>0 to 18</Select.ItemText>
            <Select.ItemIndicator className={styles.indicator}>
              <TickIcon />
            </Select.ItemIndicator>
          </Select.Item>
          <Select.Item className={styles.item} value="18-40">
            <Select.ItemText>18 to 40</Select.ItemText>
            <Select.ItemIndicator className={styles.indicator}>
              <TickIcon />
            </Select.ItemIndicator>
          </Select.Item>
          <Select.Item className={styles.item} value="40+">
            <Select.ItemText>Over 40</Select.ItemText>
            <Select.ItemIndicator className={styles.indicator}>
              <TickIcon />
            </Select.ItemIndicator>
          </Select.Item>
        </Select.Viewport>
      </Select.Content>
    </Select.Portal>
  );
  return (
    <div style={{ padding: 50 }}>
      <h1>`Label` wrapping</h1>
      <Label>
        What is your age?
        <Select.Root defaultValue="18-40">
          <Select.Trigger className={styles.trigger}>
            <Select.Value />
            <Select.Icon />
          </Select.Trigger>
          {content}
        </Select.Root>
      </Label>

      <h1>`Label` with `htmlFor`</h1>
      <Label htmlFor="age-Label">What is your age?</Label>
      <Select.Root defaultValue="18-40">
        <Select.Trigger className={styles.trigger} id="age-Label">
          <Select.Value />
          <Select.Icon />
        </Select.Trigger>
        {content}
      </Select.Root>

      <h1>`aria-labelledby`</h1>
      <div id="age-aria-labelledby">What is your age?</div>
      <Select.Root defaultValue="18-40">
        <Select.Trigger className={styles.trigger} aria-labelledby="age-aria-labelledby">
          <Select.Value />
          <Select.Icon />
        </Select.Trigger>
        {content}
      </Select.Root>

      <h1>`aria-label`</h1>
      <Select.Root defaultValue="18-40">
        <Select.Trigger className={styles.trigger} aria-label="What is your age?">
          <Select.Value />
          <Select.Icon />
        </Select.Trigger>
        {content}
      </Select.Root>
    </div>
  );
};

export const RightToLeft = () => (
  <div style={{ display: 'flex', gap: 20, padding: 50 }} dir="rtl">
    {POSITIONS.map((position) => (
      <Label key={position}>
        اختر فاكهة:
        <Select.Root defaultValue="two" dir="rtl">
          <Select.Trigger className={styles.trigger}>
            <Select.Value />
            <Select.Icon />
          </Select.Trigger>
          <Select.Portal>
            <Select.Content className={styles.content} position={position} sideOffset={5}>
              <Select.Viewport className={styles.viewport}>
                <Select.Item className={styles.item} value="one">
                  <Select.ItemText>
                    تفاح<span aria-hidden> 🍎</span>
                  </Select.ItemText>
                  <Select.ItemIndicator className={styles.indicator}>
                    <TickIcon />
                  </Select.ItemIndicator>
                </Select.Item>
                <Select.Item className={styles.item} value="two">
                  <Select.ItemText>
                    حفنة من الموز<span aria-hidden> 🍌</span>
                  </Select.ItemText>
                  <Select.ItemIndicator className={styles.indicator}>
                    <TickIcon />
                  </Select.ItemIndicator>
                </Select.Item>
                <Select.Item className={styles.item} value="three">
                  <Select.ItemText>
                    الفراولة<span aria-hidden> 🍓</span>
                  </Select.ItemText>
                  <Select.ItemIndicator className={styles.indicator}>
                    <TickIcon />
                  </Select.ItemIndicator>
                </Select.Item>
              </Select.Viewport>
              <Select.Arrow />
            </Select.Content>
          </Select.Portal>
        </Select.Root>
      </Label>
    ))}
  </div>
);

export const WithinForm = () => {
  const [data, setData] = React.useState({});

  function handleChange(event: React.FormEvent<HTMLFormElement>) {
    const formData = new FormData(event.currentTarget);
    setData(Object.fromEntries((formData as any).entries()));
  }

  return (
    <form
      style={{ padding: 50 }}
      onSubmit={(event) => {
        handleChange(event);
        event.preventDefault();
      }}
      onChange={handleChange}
    >
      <Label style={{ display: 'block' }}>
        Name
        <input name="name" autoComplete="name" style={{ display: 'block' }} />
      </Label>
      <br />
      <Label style={{ display: 'block' }}>
        Country
        <Select.Root name="country" autoComplete="country" defaultValue="fr">
          <Select.Trigger className={styles.trigger}>
            <Select.Value />
            <Select.Icon />
          </Select.Trigger>
          <Select.Portal>
            <Select.Content className={styles.content}>
              <Select.Viewport className={styles.viewport}>
                <Select.Item className={styles.item} value="fr">
                  <Select.ItemText>France</Select.ItemText>
                  <Select.ItemIndicator className={styles.indicator}>
                    <TickIcon />
                  </Select.ItemIndicator>
                </Select.Item>
                <Select.Item className={styles.item} value="uk">
                  <Select.ItemText>United Kingdom</Select.ItemText>
                  <Select.ItemIndicator className={styles.indicator}>
                    <TickIcon />
                  </Select.ItemIndicator>
                </Select.Item>
                <Select.Item className={styles.item} value="es">
                  <Select.ItemText>Spain</Select.ItemText>
                  <Select.ItemIndicator className={styles.indicator}>
                    <TickIcon />
                  </Select.ItemIndicator>
                </Select.Item>
              </Select.Viewport>
            </Select.Content>
          </Select.Portal>
        </Select.Root>
      </Label>
      <br />
      <button type="submit">Submit</button>
      <br />
      <pre>{JSON.stringify(data, null, 2)}</pre>
    </form>
  );
};

export const DisabledWithinForm = () => {
  const [data, setData] = React.useState({});

  function handleChange(event: React.FormEvent<HTMLFormElement>) {
    const formData = new FormData(event.currentTarget);
    setData(Object.fromEntries((formData as any).entries()));
  }

  return (
    <form
      style={{ padding: 50 }}
      onSubmit={(event) => {
        handleChange(event);
        event.preventDefault();
      }}
      onChange={handleChange}
    >
      <Label style={{ display: 'block' }}>
        Name
        <input name="name" autoComplete="name" style={{ display: 'block' }} />
      </Label>
      <br />
      <Label style={{ display: 'block' }}>
        Country
        <Select.Root name="country" autoComplete="country" defaultValue="fr" disabled>
          <Select.Trigger className={styles.trigger}>
            <Select.Value />
            <Select.Icon />
          </Select.Trigger>
          <Select.Portal>
            <Select.Content className={styles.content}>
              <Select.Viewport className={styles.viewport}>
                <Select.Item className={styles.item} value="fr">
                  <Select.ItemText>France</Select.ItemText>
                  <Select.ItemIndicator className={styles.indicator}>
                    <TickIcon />
                  </Select.ItemIndicator>
                </Select.Item>
                <Select.Item className={styles.item} value="uk">
                  <Select.ItemText>United Kingdom</Select.ItemText>
                  <Select.ItemIndicator className={styles.indicator}>
                    <TickIcon />
                  </Select.ItemIndicator>
                </Select.Item>
                <Select.Item className={styles.item} value="es">
                  <Select.ItemText>Spain</Select.ItemText>
                  <Select.ItemIndicator className={styles.indicator}>
                    <TickIcon />
                  </Select.ItemIndicator>
                </Select.Item>
              </Select.Viewport>
            </Select.Content>
          </Select.Portal>
        </Select.Root>
      </Label>
      <br />
      <button type="submit">Submit</button>
      <br />
      <pre>{JSON.stringify(data, null, 2)}</pre>
    </form>
  );
};

export const RequiredWithinForm = () => {
  const [data, setData] = React.useState({});

  function handleChange(event: React.FormEvent<HTMLFormElement>) {
    const formData = new FormData(event.currentTarget);
    setData(Object.fromEntries((formData as any).entries()));
  }

  return (
    <form
      style={{ padding: 50 }}
      onSubmit={(event) => {
        handleChange(event);
        event.preventDefault();
      }}
      onChange={handleChange}
    >
      <Label style={{ display: 'block' }}>
        Name
        <input name="name" autoComplete="name" style={{ display: 'block' }} />
      </Label>
      <br />
      <Label style={{ display: 'block' }}>
        Country
        <Select.Root required name="country" autoComplete="country">
          <Select.Trigger className={styles.trigger}>
            <Select.Value placeholder="Pick an option" />
            <Select.Icon />
          </Select.Trigger>
          <Select.Portal>
            <Select.Content className={styles.content}>
              <Select.Viewport className={styles.viewport}>
                <Select.Item className={styles.item} value="fr">
                  <Select.ItemText>France</Select.ItemText>
                  <Select.ItemIndicator className={styles.indicator}>
                    <TickIcon />
                  </Select.ItemIndicator>
                </Select.Item>
                <Select.Item className={styles.item} value="uk">
                  <Select.ItemText>United Kingdom</Select.ItemText>
                  <Select.ItemIndicator className={styles.indicator}>
                    <TickIcon />
                  </Select.ItemIndicator>
                </Select.Item>
                <Select.Item className={styles.item} value="es">
                  <Select.ItemText>Spain</Select.ItemText>
                  <Select.ItemIndicator className={styles.indicator}>
                    <TickIcon />
                  </Select.ItemIndicator>
                </Select.Item>
              </Select.Viewport>
            </Select.Content>
          </Select.Portal>
        </Select.Root>
      </Label>
      <br />
      <button type="submit">Submit</button>
      <br />
      <pre>{JSON.stringify(data, null, 2)}</pre>
    </form>
  );
};

export const WithinDialog = () => (
  <div style={{ height: '120vh' }}>
    <Dialog.Root>
      <Dialog.Trigger>Open Dialog</Dialog.Trigger>
      <Dialog.Portal>
        <Dialog.Overlay />
        <Dialog.Content aria-describedby={undefined} style={{ position: 'fixed', top: 100 }}>
          <Dialog.Title>A select in a dialog</Dialog.Title>
          <Label>
            Choose a number:
            <Select.Root defaultValue="2">
              <Select.Trigger className={styles.trigger}>
                <Select.Value />
                <Select.Icon />
              </Select.Trigger>
              <Select.Portal>
                <Select.Content className={styles.content}>
                  <Select.ScrollUpButton className={scrollUpButtonClass}>▲</Select.ScrollUpButton>
                  <Select.Viewport className={styles.viewport}>
                    {Array.from({ length: 30 }, (_, i) => (
                      <Select.Item key={i} className={styles.item} value={String(i)}>
                        <Select.ItemText>Item {i}</Select.ItemText>
                        <Select.ItemIndicator className={styles.indicator}>
                          <TickIcon />
                        </Select.ItemIndicator>
                      </Select.Item>
                    ))}
                  </Select.Viewport>
                  <Select.ScrollDownButton className={scrollDownButtonClass}>
                    ▼
                  </Select.ScrollDownButton>
                </Select.Content>
              </Select.Portal>
            </Select.Root>
          </Label>
          <Dialog.Close>Close Dialog</Dialog.Close>
        </Dialog.Content>
      </Dialog.Portal>
    </Dialog.Root>
  </div>
);

export const WithVeryLongSelectItems = () => (
  <div style={{ paddingLeft: 300 }}>
    <Label>
      What is the meaning of life?
      <Select.Root defaultValue="1">
        <Select.Trigger className={styles.trigger}>
          <Select.Value />
          <Select.Icon />
        </Select.Trigger>
        <Select.Portal>
          <Select.Content className={styles.content}>
            <Select.ScrollUpButton className={scrollUpButtonClass}>▲</Select.ScrollUpButton>
            <Select.Viewport className={styles.viewport}>
              {[
                'The meaning of life is a complex topic that has been the subject of much philosophical, scientific, and theological speculation, with no definitive answer. The meaning of life can be interpreted in many different ways, depending on individual beliefs, values, and experiences.',
                '42',
              ].map((opt, i) => (
                <Select.Item
                  key={opt}
                  className={styles.item}
                  value={String(i)}
                  // style={{ maxWidth: 500 }}
                >
                  <Select.ItemText>{opt}</Select.ItemText>
                  <Select.ItemIndicator className={styles.indicator}>
                    <TickIcon />
                  </Select.ItemIndicator>
                </Select.Item>
              ))}
            </Select.Viewport>
            <Select.ScrollDownButton className={scrollDownButtonClass}>▼</Select.ScrollDownButton>
          </Select.Content>
        </Select.Portal>
      </Select.Root>
    </Label>
  </div>
);

export const ChromaticShortOptionsPaddedContent = () => (
  <ChromaticStoryShortOptions paddedElement="content" />
);
ChromaticShortOptionsPaddedContent.parameters = { chromatic: { disable: false } };

export const ChromaticShortOptionsPaddedViewport = () => (
  <ChromaticStoryShortOptions paddedElement="viewport" />
);
ChromaticShortOptionsPaddedViewport.parameters = { chromatic: { disable: false } };

export const ChromaticLongOptionsPaddedContent = () => (
  <ChromaticStoryLongOptions paddedElement="content" />
);
ChromaticLongOptionsPaddedContent.parameters = { chromatic: { disable: false } };

export const ChromaticLongOptionsPaddedViewport = () => (
  <ChromaticStoryLongOptions paddedElement="viewport" />
);
ChromaticLongOptionsPaddedViewport.parameters = { chromatic: { disable: false } };

export const ChromaticTopFirstPaddedContent = () => (
  <ChromaticStoryTopFirst paddedElement="content" />
);
ChromaticTopFirstPaddedContent.parameters = { chromatic: { disable: false } };

export const ChromaticTopFirstPaddedViewport = () => (
  <ChromaticStoryTopFirst paddedElement="viewport" />
);
ChromaticTopFirstPaddedViewport.parameters = { chromatic: { disable: false } };

export const ChromaticBottomLastPaddedContent = () => (
  <ChromaticStoryBottomLast paddedElement="content" />
);
ChromaticBottomLastPaddedContent.parameters = { chromatic: { disable: false } };

export const ChromaticBottomLastPaddedViewport = () => (
  <ChromaticStoryBottomLast paddedElement="viewport" />
);
ChromaticBottomLastPaddedViewport.parameters = { chromatic: { disable: false } };

export const ChromaticNoDefaultValue = () => (
  <div
    style={{
      display: 'grid',
      height: '100vh',
      placeItems: 'center',
      gridTemplateColumns: 'repeat(2, 1fr)',
    }}
  >
    <Select.Root open>
      <Select.Trigger className={styles.trigger}>
        <Select.Value />
        <Select.Icon />
      </Select.Trigger>
      <Select.Portal>
        <Select.Content className={styles.content} style={{ opacity: 0.7 }}>
          <Select.ScrollUpButton className={scrollUpButtonClass}>▲</Select.ScrollUpButton>
          <Select.Viewport className={styles.viewport}>
            {Array.from({ length: 10 }, (_, i) => (
              <Select.Item key={i} className={styles.item} value={String(i)} disabled={i < 5}>
                <Select.ItemText>{String(i)}</Select.ItemText>
                <Select.ItemIndicator className={styles.indicator}>
                  <TickIcon />
                </Select.ItemIndicator>
              </Select.Item>
            ))}
          </Select.Viewport>
          <Select.ScrollDownButton className={scrollDownButtonClass}>▼</Select.ScrollDownButton>
        </Select.Content>
      </Select.Portal>
    </Select.Root>

    <Select.Root open>
      <Select.Trigger className={styles.trigger}>
        <Select.Value placeholder="Pick an option" />
        <Select.Icon />
      </Select.Trigger>
      <Select.Portal>
        <Select.Content className={styles.content} style={{ opacity: 0.7 }}>
          <Select.ScrollUpButton className={scrollUpButtonClass}>▲</Select.ScrollUpButton>
          <Select.Viewport className={styles.viewport}>
            {Array.from({ length: 10 }, (_, i) => (
              <Select.Item key={i} className={styles.item} value={String(i)} disabled={i < 5}>
                <Select.ItemText>{String(i)}</Select.ItemText>
                <Select.ItemIndicator className={styles.indicator}>
                  <TickIcon />
                </Select.ItemIndicator>
              </Select.Item>
            ))}
          </Select.Viewport>
          <Select.ScrollDownButton className={scrollDownButtonClass}>▼</Select.ScrollDownButton>
        </Select.Content>
      </Select.Portal>
    </Select.Root>
  </div>
);
ChromaticNoDefaultValue.parameters = { chromatic: { disable: false } };

export const Cypress = () => {
  const [data, setData] = React.useState<{ size?: 'S' | 'M' | 'L' }>({});
  const [model, setModel] = React.useState<string | undefined>('');

  function handleChange(event: React.FormEvent<HTMLFormElement>) {
    const formData = new FormData(event.currentTarget);
    setData(Object.fromEntries((formData as any).entries()));
  }

  return (
    <>
      <form
        style={{ padding: 50 }}
        onSubmit={(event) => {
          handleChange(event);
          event.preventDefault();
        }}
        onChange={handleChange}
      >
        <Label>
          choose a size:
          <Select.Root defaultValue="M" name="size">
            <Select.Trigger className={styles.trigger}>
              <Select.Value />
              <Select.Icon />
            </Select.Trigger>
            <Select.Portal>
              <Select.Content className={styles.content}>
                <Select.Viewport className={styles.viewport}>
                  <Select.Item className={styles.item} value="S">
                    <Select.ItemText>Small</Select.ItemText>
                    <Select.ItemIndicator className={styles.indicator}>
                      <TickIcon />
                    </Select.ItemIndicator>
                  </Select.Item>
                  <Select.Item className={styles.item} value="M">
                    <Select.ItemText>Medium</Select.ItemText>
                    <Select.ItemIndicator className={styles.indicator}>
                      <TickIcon />
                    </Select.ItemIndicator>
                  </Select.Item>
                  <Select.Item className={styles.item} value="L">
                    <Select.ItemText>Large</Select.ItemText>
                    <Select.ItemIndicator className={styles.indicator}>
                      <TickIcon />
                    </Select.ItemIndicator>
                  </Select.Item>
                </Select.Viewport>
              </Select.Content>
            </Select.Portal>
          </Select.Root>
        </Label>
        <button type="submit" style={{ width: 100, height: 50 }}>
          buy
        </button>
        {data.size ? <p>You picked t-shirt size {data.size}</p> : null}
      </form>

      <hr />

      <div style={{ padding: 50 }}>
        <Label>
          choose a model
          <Select.Root name="model" value={model} onValueChange={setModel}>
            <Select.Trigger className={styles.trigger}>
              <Select.Value placeholder="…" />
              <Select.Icon />
            </Select.Trigger>
            <Select.Portal>
              <Select.Content className={styles.content}>
                <Select.Viewport className={styles.viewport}>
                  <Select.Item className={styles.item} value="S">
                    <Select.ItemText>Model S</Select.ItemText>
                    <Select.ItemIndicator className={styles.indicator}>
                      <TickIcon />
                    </Select.ItemIndicator>
                  </Select.Item>
                  <Select.Item className={styles.item} value="3">
                    <Select.ItemText>Modal 3</Select.ItemText>
                    <Select.ItemIndicator className={styles.indicator}>
                      <TickIcon />
                    </Select.ItemIndicator>
                  </Select.Item>
                  <Select.Item className={styles.item} value="X">
                    <Select.ItemText>Model X</Select.ItemText>
                    <Select.ItemIndicator className={styles.indicator}>
                      <TickIcon />
                    </Select.ItemIndicator>
                  </Select.Item>
                  <Select.Item className={styles.item} value="Y">
                    <Select.ItemText>Model Y</Select.ItemText>
                    <Select.ItemIndicator className={styles.indicator}>
                      <TickIcon />
                    </Select.ItemIndicator>
                  </Select.Item>
                </Select.Viewport>
              </Select.Content>
            </Select.Portal>
          </Select.Root>
        </Label>

        <button type="button" style={{ width: 100, height: 50 }} onClick={() => setModel('')}>
          unset
        </button>
      </div>
    </>
  );
};

type PaddedElement = 'content' | 'viewport';

interface ChromaticSelectProps extends React.ComponentProps<typeof Select.Trigger> {
  count?: number;
  paddedElement?: PaddedElement;
  selected: number;
}

const ChromaticSelect = ({
  count = 5,
  paddedElement = 'content',
  selected,
  ...props
}: ChromaticSelectProps) => (
  <Select.Root defaultValue={String(selected)} open>
    <Select.Trigger className={styles.trigger} {...props}>
      <Select.Value />
      <Select.Icon />
    </Select.Trigger>
    <Select.Portal>
      <Select.Content
        className={[paddedElement === 'content' && styles.contentWithPadding, styles.contentClass]
          .filter(Boolean)
          .join(' ')}
        style={{ opacity: 0.7 }}
      >
        <Select.ScrollUpButton
          className={scrollUpButtonClass}
          style={paddedElement === 'content' ? { marginTop: -5 } : undefined}
        >
          ▲
        </Select.ScrollUpButton>
        <Select.Viewport className={paddedElement === 'viewport' ? styles.viewport : undefined}>
          {Array.from({ length: count }, (_, i) => (
            <Select.Item key={i} className={styles.item} value={String(i)}>
              <Select.ItemText>{String(i)}</Select.ItemText>
              <Select.ItemIndicator className={styles.indicator}>
                <TickIcon />
              </Select.ItemIndicator>
            </Select.Item>
          ))}
        </Select.Viewport>
        <Select.ScrollDownButton
          className={scrollDownButtonClass}
          style={paddedElement === 'content' ? { marginBottom: -5 } : undefined}
        >
          ▼
        </Select.ScrollDownButton>
      </Select.Content>
    </Select.Portal>
  </Select.Root>
);

const SelectShort = React.forwardRef<
  React.ComponentRef<typeof ChromaticSelect>,
  React.ComponentProps<typeof ChromaticSelect>
>(({ count = 9, ...props }, forwardedRef) => (
  <ChromaticSelect count={count} {...props} ref={forwardedRef} />
));

const SelectLong = React.forwardRef<
  React.ComponentRef<typeof ChromaticSelect>,
  React.ComponentProps<typeof ChromaticSelect>
>(({ count = 50, ...props }, forwardedRef) => (
  <ChromaticSelect count={count} {...props} ref={forwardedRef} />
));

const ChromaticStoryShortOptions = ({ paddedElement }: { paddedElement: PaddedElement }) => (
  <div
    style={{
      display: 'grid',
      gridTemplateColumns: 'repeat(5, 1fr)',
      gridTemplateRows: 'repeat(3, 1fr)',
      height: '100vh',
      placeItems: 'center',
    }}
  >
    <SelectShort paddedElement={paddedElement} selected={0} style={{ alignSelf: 'start' }} />
    <SelectShort paddedElement={paddedElement} selected={2} style={{ alignSelf: 'start' }} />
    <SelectShort paddedElement={paddedElement} selected={4} style={{ alignSelf: 'start' }} />
    <SelectShort paddedElement={paddedElement} selected={6} style={{ alignSelf: 'start' }} />
    <SelectShort paddedElement={paddedElement} selected={8} style={{ alignSelf: 'start' }} />

    <SelectShort paddedElement={paddedElement} selected={0} />
    <SelectShort paddedElement={paddedElement} selected={2} />
    <SelectShort paddedElement={paddedElement} selected={4} />
    <SelectShort paddedElement={paddedElement} selected={6} />
    <SelectShort paddedElement={paddedElement} selected={8} />

    <SelectShort paddedElement={paddedElement} selected={0} style={{ alignSelf: 'end' }} />
    <SelectShort paddedElement={paddedElement} selected={2} style={{ alignSelf: 'end' }} />
    <SelectShort paddedElement={paddedElement} selected={4} style={{ alignSelf: 'end' }} />
    <SelectShort paddedElement={paddedElement} selected={6} style={{ alignSelf: 'end' }} />
    <SelectShort paddedElement={paddedElement} selected={8} style={{ alignSelf: 'end' }} />
  </div>
);

const ChromaticStoryLongOptions = ({ paddedElement }: { paddedElement: PaddedElement }) => (
  <div
    style={{
      display: 'grid',
      gridTemplateColumns: 'repeat(15, 1fr)',
      gridTemplateRows: 'repeat(3, 1fr)',
      height: '100vh',
      placeItems: 'center',
    }}
  >
    <SelectLong paddedElement={paddedElement} selected={0} style={{ alignSelf: 'start' }} />
    <SelectLong paddedElement={paddedElement} selected={25} style={{ alignSelf: 'start' }} />
    <SelectLong paddedElement={paddedElement} selected={49} style={{ alignSelf: 'start' }} />

    <SelectLong paddedElement={paddedElement} selected={0} style={{ gridRow: 1, gridColumn: 4 }} />
    <SelectLong paddedElement={paddedElement} selected={25} style={{ gridRow: 1, gridColumn: 5 }} />
    <SelectLong paddedElement={paddedElement} selected={49} style={{ gridRow: 1, gridColumn: 6 }} />

    <SelectLong paddedElement={paddedElement} selected={0} style={{ gridRow: 2, gridColumn: 7 }} />
    <SelectLong paddedElement={paddedElement} selected={25} style={{ gridRow: 2, gridColumn: 8 }} />
    <SelectLong paddedElement={paddedElement} selected={49} style={{ gridRow: 2, gridColumn: 9 }} />

    <SelectLong paddedElement={paddedElement} selected={0} style={{ gridRow: 3, gridColumn: 10 }} />
    <SelectLong
      paddedElement={paddedElement}
      selected={25}
      style={{ gridRow: 3, gridColumn: 11 }}
    />
    <SelectLong
      paddedElement={paddedElement}
      selected={49}
      style={{ gridRow: 3, gridColumn: 12 }}
    />

    <SelectLong
      paddedElement={paddedElement}
      selected={0}
      style={{ gridRow: 3, gridColumn: 13, alignSelf: 'end' }}
    />
    <SelectLong
      paddedElement={paddedElement}
      selected={25}
      style={{ gridRow: 3, gridColumn: 14, alignSelf: 'end' }}
    />
    <SelectLong
      paddedElement={paddedElement}
      selected={49}
      style={{ gridRow: 3, gridColumn: 15, alignSelf: 'end' }}
    />
  </div>
);

const ChromaticStoryTopFirst = ({ paddedElement }: { paddedElement: PaddedElement }) => (
  <div style={{ display: 'flex', height: '100vh' }}>
    <SelectShort paddedElement={paddedElement} selected={0} />
  </div>
);

const ChromaticStoryBottomLast = ({ paddedElement }: { paddedElement: PaddedElement }) => (
  <div style={{ display: 'flex', height: '100vh', alignItems: 'flex-end' }}>
    <SelectShort paddedElement={paddedElement} selected={8} />
  </div>
);

const TickIcon = () => (
  <svg
    xmlns="http://www.w3.org/2000/svg"
    viewBox="0 0 32 32"
    width="12"
    height="12"
    fill="none"
    stroke="currentcolor"
    strokeLinecap="round"
    strokeLinejoin="round"
    strokeWidth="3"
  >
    <path d="M2 20 L12 28 30 4" />
  </svg>
);



================================================
FILE: apps/storybook/stories/separator.stories.module.css
================================================
.root {
  border: none;
  background-color: var(--color-red);

  &[data-orientation='horizontal'] {
    height: 1px;
    width: 100%;
    margin: 20px 0;
  }

  &[data-orientation='vertical'] {
    height: 100px;
    width: 1px;
    margin: 0 20px;
  }
}



================================================
FILE: apps/storybook/stories/separator.stories.tsx
================================================
import { Separator } from 'radix-ui';
import styles from './separator.stories.module.css';

export default { title: 'Components/Separator' };

export const Styled = () => (
  <>
    <h1>Horizontal</h1>
    <p>The following separator is horizontal and has semantic meaning.</p>
    <Separator.Root className={styles.root} orientation="horizontal" />
    <p>
      The following separator is horizontal and is purely decorative. Assistive technology will
      ignore this element.
    </p>
    <Separator.Root className={styles.root} orientation="horizontal" decorative />

    <h1>Vertical</h1>
    <div style={{ display: 'flex', alignItems: 'center' }}>
      <p>The following separator is vertical and has semantic meaning.</p>
      <Separator.Root className={styles.root} orientation="vertical" />
      <p>
        The following separator is vertical and is purely decorative. Assistive technology will
        ignore this element.
      </p>
      <Separator.Root className={styles.root} orientation="vertical" decorative />
    </div>
  </>
);



================================================
FILE: apps/storybook/stories/slider.stories.module.css
================================================
.root,
.rootAttr {
  position: relative;
  display: flex;
  align-items: center;
  flex-shrink: 0;
  /* ensures no selection */
  user-select: none;
  /* disable browser handling of all panning and zooming gestures on touch devices */
  touch-action: none;
}

.root {
  &[data-orientation='horizontal'] {
    height: 25px;
  }
  &[data-orientation='vertical'] {
    flex-direction: column;
    width: 25px;
  }
  &[data-disabled] {
    opacity: 0.5;
  }
}

.track,
.trackAttr {
  position: relative;
  /* ensures full width in horizontal orientation, ignored in vertical orientation */
  flex-grow: 1;
}

.track {
  background: gainsboro;
  border-radius: 4px;
  &[data-orientation='horizontal'] {
    height: 4px;
  }
  &[data-orientation='vertical'] {
    width: 4px;
    height: 300px;
  }
}

.range,
.rangeAttr {
  position: absolute;
  /* good default for both orientation (match track width/height respectively) */
  &[data-orientation='horizontal'] {
    height: 100%;
  }
  &[data-orientation='vertical'] {
    width: 100%;
  }
}

.range {
  background: var(--color-black);
  border-radius: inherit;
}

.thumb,
.thumbAttr {
  /* ensures the thumb is sizeable */
  display: block;

  /* Add recommended target size regardless of styled size */
  &::before {
    content: '';
    position: absolute;
    z-index: -1;
    width: 44px;
    height: 44px;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
  }
}

.thumb {
  border-radius: 25px;
  width: 25px;
  height: 25px;
  background-color: var(--color-black);
  &:focus {
    outline: none;
    box-shadow: 0 0 0 2px var(--color-red);
  }

  display: inline-grid;
  place-items: center;
  &:after {
    content: attr(aria-valuenow);
    position: relative;
    font-size: 10px;
    color: white;
  }
}

.rootAttr,
.trackAttr,
.rangeAttr,
.thumbAttr {
  background-color: rgba(0, 0, 255, 0.3);
  border: 2px solid blue;
  padding: 10px;

  &[data-disabled] {
    border-style: dashed;
  }
}



================================================
FILE: apps/storybook/stories/slider.stories.tsx
================================================
import * as React from 'react';
import { Direction, Slider } from 'radix-ui';
import serialize from 'form-serialize';
import styles from './slider.stories.module.css';

export default { title: 'Components/Slider' };

export const Styled = () => (
  <Slider.Root className={styles.root}>
    <Slider.Track className={styles.track}>
      <Slider.Range className={styles.range} />
    </Slider.Track>
    <Slider.Thumb className={styles.thumb} />
  </Slider.Root>
);

export const WithOnValueCommit = () => (
  <>
    <Slider.Root className={styles.root} defaultValue={[20]} onValueCommit={console.log}>
      <Slider.Track className={styles.track}>
        <Slider.Range className={styles.range} />
      </Slider.Track>
      <Slider.Thumb className={styles.thumb} />
    </Slider.Root>
    <p>Check the console for the `onValueCommit` log</p>
  </>
);

export const RightToLeft = () => (
  <Slider.Root className={styles.root} dir="rtl">
    <Slider.Track className={styles.track}>
      <Slider.Range className={styles.range} />
    </Slider.Track>
    <Slider.Thumb className={styles.thumb} />
  </Slider.Root>
);

export const Horizontal = () => (
  <div style={{ display: 'flex', flexDirection: 'column', gap: 50 }}>
    <Slider.Root
      className={styles.root}
      defaultValue={[10, 30]}
      minStepsBetweenThumbs={1}
      onValueChange={(value) => console.log(value)}
    >
      <Slider.Track className={styles.track}>
        <Slider.Range className={styles.range} />
      </Slider.Track>
      <Slider.Thumb className={styles.thumb} />
      <Slider.Thumb className={styles.thumb} />
    </Slider.Root>

    <Slider.Root className={styles.root} defaultValue={[10]}>
      <Slider.Track className={styles.track}>
        <Slider.Range className={styles.range} />
      </Slider.Track>
      <Slider.Thumb className={styles.thumb} />
    </Slider.Root>
  </div>
);

export const Vertical = () => (
  <div style={{ display: 'flex', gap: 50 }}>
    <Slider.Root className={styles.root} defaultValue={[10, 30]} orientation="vertical">
      <Slider.Track className={styles.track}>
        <Slider.Range className={styles.range} />
      </Slider.Track>
      <Slider.Thumb className={styles.thumb} />
      <Slider.Thumb className={styles.thumb} />
    </Slider.Root>

    <Slider.Root className={styles.root} defaultValue={[10]} orientation="vertical">
      <Slider.Track className={styles.track}>
        <Slider.Range className={styles.range} />
      </Slider.Track>
      <Slider.Thumb className={styles.thumb} />
    </Slider.Root>
  </div>
);

export const Inversions = () => (
  <>
    <h1>Inversions</h1>
    <h2>Horizontal</h2>
    <div style={{ display: 'flex', gap: 50 }}>
      <div style={{ flex: 1 }}>
        <h3>LTR</h3>
        <h4>default</h4>
        <Slider.Root className={styles.root} defaultValue={[20]}>
          <Slider.Track className={styles.track}>
            <Slider.Range className={styles.range} />
          </Slider.Track>
          <Slider.Thumb className={styles.thumb} />
        </Slider.Root>

        <h4>Inverted</h4>
        <Slider.Root className={styles.root} defaultValue={[20]} inverted>
          <Slider.Track className={styles.track}>
            <Slider.Range className={styles.range} />
          </Slider.Track>
          <Slider.Thumb className={styles.thumb} />
        </Slider.Root>
      </div>

      <div style={{ flex: 1 }}>
        <h3>RTL</h3>
        <h4>Default</h4>
        <Slider.Root className={styles.root} defaultValue={[20]} dir="rtl">
          <Slider.Track className={styles.track}>
            <Slider.Range className={styles.range} />
          </Slider.Track>
          <Slider.Thumb className={styles.thumb} />
        </Slider.Root>

        <h4>Inverted</h4>
        <Slider.Root className={styles.root} defaultValue={[20]} dir="rtl" inverted>
          <Slider.Track className={styles.track}>
            <Slider.Range className={styles.range} />
          </Slider.Track>
          <Slider.Thumb className={styles.thumb} />
        </Slider.Root>
      </div>
    </div>

    <h2>Vertical</h2>
    <div style={{ display: 'flex', gap: 50 }}>
      <div style={{ flex: 1 }}>
        <h3>LTR</h3>
        <div style={{ display: 'flex', gap: 50 }}>
          <div>
            <h4>Default</h4>
            <Slider.Root className={styles.root} defaultValue={[20]} orientation="vertical">
              <Slider.Track className={styles.track}>
                <Slider.Range className={styles.range} />
              </Slider.Track>
              <Slider.Thumb className={styles.thumb} />
            </Slider.Root>
          </div>

          <div>
            <h4>Inverted</h4>
            <Slider.Root
              className={styles.root}
              defaultValue={[20]}
              orientation="vertical"
              inverted
            >
              <Slider.Track className={styles.track}>
                <Slider.Range className={styles.range} />
              </Slider.Track>
              <Slider.Thumb className={styles.thumb} />
            </Slider.Root>
          </div>
        </div>
      </div>

      <div style={{ flex: 1 }}>
        <h3>RTL</h3>
        <div style={{ display: 'flex', gap: 50 }}>
          <div>
            <h4>Default</h4>
            <Slider.Root
              className={styles.root}
              defaultValue={[20]}
              dir="rtl"
              orientation="vertical"
            >
              <Slider.Track className={styles.track}>
                <Slider.Range className={styles.range} />
              </Slider.Track>
              <Slider.Thumb className={styles.thumb} />
            </Slider.Root>
          </div>

          <div>
            <h4>Inverted</h4>
            <Slider.Root
              className={styles.root}
              defaultValue={[20]}
              dir="rtl"
              orientation="vertical"
              inverted
            >
              <Slider.Track className={styles.track}>
                <Slider.Range className={styles.range} />
              </Slider.Track>
              <Slider.Thumb className={styles.thumb} />
            </Slider.Root>
          </div>
        </div>
      </div>
    </div>
  </>
);

export const WithMinimumStepsBetweenThumbs = () => (
  <Slider.Root className={styles.root} defaultValue={[10, 30]} minStepsBetweenThumbs={3}>
    <Slider.Track className={styles.track}>
      <Slider.Range className={styles.range} />
    </Slider.Track>
    <Slider.Thumb className={styles.thumb} />
    <Slider.Thumb className={styles.thumb} />
  </Slider.Root>
);

export const WithMultipleRanges = () => {
  const [minStepsBetweenThumbs, setMinStepsBetweenThumbs] = React.useState(0);

  return (
    <>
      <label>
        Minimum steps between thumbs:{' '}
        <input
          type="number"
          value={minStepsBetweenThumbs}
          onChange={(event) => setMinStepsBetweenThumbs(Number(event.target.value))}
          style={{ width: 30 }}
        />
      </label>

      <br />
      <br />

      <Slider.Root
        className={styles.root}
        defaultValue={[10, 15, 20, 80]}
        minStepsBetweenThumbs={minStepsBetweenThumbs}
      >
        <Slider.Track className={styles.track}>
          <Slider.Range className={styles.range} />
        </Slider.Track>
        <Slider.Thumb className={styles.thumb} />
        <Slider.Thumb className={styles.thumb} />
        <Slider.Thumb className={styles.thumb} />
        <Slider.Thumb className={styles.thumb} />
      </Slider.Root>
    </>
  );
};

export const SmallSteps = () => {
  const [value, setValue] = React.useState([0.1]);
  return (
    <>
      <Slider.Root
        className={styles.root}
        value={value}
        onValueChange={setValue}
        min={0.1}
        max={0.2}
        step={0.003}
      >
        <Slider.Track className={styles.track}>
          <Slider.Range className={styles.range} />
        </Slider.Track>
        <Slider.Thumb className={styles.thumb} />
      </Slider.Root>
      <div>{value}</div>
    </>
  );
};

export const WithinForm = () => {
  const [data, setData] = React.useState({
    single: [0],
    multiple: [10, 15, 20, 80],
    price: {
      min: 30,
      max: 70,
    },
  });
  return (
    <form
      onSubmit={(event) => {
        event.preventDefault();
        console.log(serialize(event.currentTarget, { hash: true }));
      }}
      onChange={(event) => {
        const formData = serialize(event.currentTarget, { hash: true });
        setData(formData as any);
      }}
    >
      <fieldset>
        <legend>Single value: {String(data.single)}</legend>
        <Slider.Root name="single" defaultValue={data.single} className={styles.root}>
          <Slider.Track className={styles.track}>
            <Slider.Range className={styles.range} />
          </Slider.Track>
          <Slider.Thumb className={styles.thumb} />
        </Slider.Root>
      </fieldset>

      <br />
      <br />

      <fieldset>
        <legend>Multiple value: {String(data.multiple)}</legend>
        <Slider.Root name="multiple" defaultValue={data.multiple} className={styles.root}>
          <Slider.Track className={styles.track}>
            <Slider.Range className={styles.range} />
          </Slider.Track>
          <Slider.Thumb className={styles.thumb} />
          <Slider.Thumb className={styles.thumb} />
          <Slider.Thumb className={styles.thumb} />
          <Slider.Thumb className={styles.thumb} />
        </Slider.Root>
      </fieldset>

      <br />
      <br />

      <fieldset>
        <legend>Multiple values (with named thumbs): {JSON.stringify(data.price)}</legend>
        <Slider.Root defaultValue={[data.price.min, data.price.max]} className={styles.root}>
          <Slider.Track className={styles.track}>
            <Slider.Range className={styles.range} />
          </Slider.Track>
          <Slider.Thumb className={styles.thumb} name="price[min]" />
          <Slider.Thumb className={styles.thumb} name="price[max]" />
        </Slider.Root>
      </fieldset>

      <button type="submit">Submit</button>
    </form>
  );
};

export const Strict = () => (
  <React.StrictMode>
    <Slider.Root className={styles.root}>
      <Slider.Track className={styles.track}>
        <Slider.Range className={styles.range} />
      </Slider.Track>
      <Slider.Thumb className={styles.thumb} />
    </Slider.Root>
    <Slider.Root className={styles.root} defaultValue={[10, 15, 20, 80]}>
      <Slider.Track className={styles.track}>
        <Slider.Range className={styles.range} />
      </Slider.Track>
      <Slider.Thumb className={styles.thumb} />
      <Slider.Thumb className={styles.thumb} />
      <Slider.Thumb className={styles.thumb} />
      <Slider.Thumb className={styles.thumb} />
    </Slider.Root>
  </React.StrictMode>
);

export const Chromatic = () => (
  <>
    <h1>Uncontrolled</h1>
    <h2>LTR</h2>
    <Slider.Root className={styles.root} defaultValue={[20]}>
      <Slider.Track className={styles.track}>
        <Slider.Range className={styles.range} />
      </Slider.Track>
      <Slider.Thumb className={styles.thumb} />
    </Slider.Root>
    <Slider.Root className={styles.root} defaultValue={[10, 30]}>
      <Slider.Track className={styles.track}>
        <Slider.Range className={styles.range} />
      </Slider.Track>
      <Slider.Thumb className={styles.thumb} />
      <Slider.Thumb className={styles.thumb} />
    </Slider.Root>

    <h2>RTL</h2>
    <Slider.Root className={styles.root} defaultValue={[20]} dir="rtl">
      <Slider.Track className={styles.track}>
        <Slider.Range className={styles.range} />
      </Slider.Track>
      <Slider.Thumb className={styles.thumb} />
    </Slider.Root>
    <Slider.Root className={styles.root} defaultValue={[10, 30]} dir="rtl">
      <Slider.Track className={styles.track}>
        <Slider.Range className={styles.range} />
      </Slider.Track>
      <Slider.Thumb className={styles.thumb} />
      <Slider.Thumb className={styles.thumb} />
    </Slider.Root>

    <h2>Multiple ranges</h2>
    <Slider.Root className={styles.root} defaultValue={[10, 15, 20, 80]}>
      <Slider.Track className={styles.track}>
        <Slider.Range className={styles.range} />
      </Slider.Track>
      <Slider.Thumb className={styles.thumb} />
      <Slider.Thumb className={styles.thumb} />
      <Slider.Thumb className={styles.thumb} />
      <Slider.Thumb className={styles.thumb} />
    </Slider.Root>

    <h1>Controlled</h1>
    <h2>LTR</h2>
    <Slider.Root className={styles.root} value={[20]}>
      <Slider.Track className={styles.track}>
        <Slider.Range className={styles.range} />
      </Slider.Track>
      <Slider.Thumb className={styles.thumb} />
    </Slider.Root>
    <Slider.Root className={styles.root} value={[10, 30]}>
      <Slider.Track className={styles.track}>
        <Slider.Range className={styles.range} />
      </Slider.Track>
      <Slider.Thumb className={styles.thumb} />
      <Slider.Thumb className={styles.thumb} />
    </Slider.Root>

    <h1>Direction</h1>
    <h2>Prop</h2>
    <Slider.Root className={styles.root} value={[20]} dir="rtl">
      <Slider.Track className={styles.track}>
        <Slider.Range className={styles.range} />
      </Slider.Track>
      <Slider.Thumb className={styles.thumb} />
    </Slider.Root>
    <Slider.Root className={styles.root} value={[10, 30]} dir="rtl">
      <Slider.Track className={styles.track}>
        <Slider.Range className={styles.range} />
      </Slider.Track>
      <Slider.Thumb className={styles.thumb} />
      <Slider.Thumb className={styles.thumb} />
    </Slider.Root>

    <h2>Inherited</h2>
    <Direction.Provider dir="rtl">
      <Slider.Root className={styles.root} value={[20]}>
        <Slider.Track className={styles.track}>
          <Slider.Range className={styles.range} />
        </Slider.Track>
        <Slider.Thumb className={styles.thumb} />
      </Slider.Root>
      <Slider.Root className={styles.root} value={[10, 30]}>
        <Slider.Track className={styles.track}>
          <Slider.Range className={styles.range} />
        </Slider.Track>
        <Slider.Thumb className={styles.thumb} />
        <Slider.Thumb className={styles.thumb} />
      </Slider.Root>
    </Direction.Provider>

    <h1>Scenarios</h1>
    <h2>Extremes</h2>
    <Slider.Root className={styles.root} defaultValue={[0, 100]}>
      <Slider.Track className={styles.track}>
        <Slider.Range className={styles.range} />
      </Slider.Track>
      <Slider.Thumb className={styles.thumb} />
      <Slider.Thumb className={styles.thumb} />
    </Slider.Root>

    <h2>0 case</h2>
    <Slider.Root className={styles.root} defaultValue={[0]} min={-100} max={100}>
      <Slider.Track className={styles.track}>
        <Slider.Range className={styles.range} />
      </Slider.Track>
      <Slider.Thumb className={styles.thumb} />
    </Slider.Root>

    <h2>Multiple ranges</h2>
    <Slider.Root className={styles.root} value={[10, 15, 20, 80]}>
      <Slider.Track className={styles.track}>
        <Slider.Range className={styles.range} />
      </Slider.Track>
      <Slider.Thumb className={styles.thumb} />
      <Slider.Thumb className={styles.thumb} />
      <Slider.Thumb className={styles.thumb} />
      <Slider.Thumb className={styles.thumb} />
    </Slider.Root>

    <h2>Vertical</h2>
    <div style={{ display: 'flex' }}>
      <Slider.Root className={styles.root} defaultValue={[10, 30]} orientation="vertical">
        <Slider.Track className={styles.track}>
          <Slider.Range className={styles.range} />
        </Slider.Track>
        <Slider.Thumb className={styles.thumb} />
        <Slider.Thumb className={styles.thumb} />
      </Slider.Root>
      <Slider.Root className={styles.root} defaultValue={[20]} orientation="vertical">
        <Slider.Track className={styles.track}>
          <Slider.Range className={styles.range} />
        </Slider.Track>
        <Slider.Thumb className={styles.thumb} />
      </Slider.Root>
    </div>

    <h2>Out of bound value (negative)</h2>
    <Slider.Root className={styles.root} defaultValue={[-9000]} min={0} max={100}>
      <Slider.Track className={styles.track}>
        <Slider.Range className={styles.range} />
      </Slider.Track>
      <Slider.Thumb className={styles.thumb} />
    </Slider.Root>

    <h2>Out of bound value (positive)</h2>
    <Slider.Root className={styles.root} defaultValue={[9000]} min={0} max={100}>
      <Slider.Track className={styles.track}>
        <Slider.Range className={styles.range} />
      </Slider.Track>
      <Slider.Thumb className={styles.thumb} />
    </Slider.Root>

    <h1>Disabled</h1>
    <Slider.Root className={styles.root} defaultValue={[20]} disabled>
      <Slider.Track className={styles.track}>
        <Slider.Range className={styles.range} />
      </Slider.Track>
      <Slider.Thumb className={styles.thumb} />
    </Slider.Root>

    <Inversions />

    <h1>State attributes</h1>
    <h2>Default</h2>
    <Slider.Root className={styles.rootAttr} defaultValue={[20]}>
      <Slider.Track className={styles.trackAttr}>
        <Slider.Range className={styles.rangeAttr} />
      </Slider.Track>
      <Slider.Thumb className={styles.thumbAttr} />
    </Slider.Root>

    <h2>Disabled</h2>
    <Slider.Root className={styles.rootAttr} defaultValue={[20]} disabled>
      <Slider.Track className={styles.trackAttr}>
        <Slider.Range className={styles.rangeAttr} />
      </Slider.Track>
      <Slider.Thumb className={styles.thumbAttr} />
    </Slider.Root>
  </>
);
Chromatic.parameters = { chromatic: { disable: false } };



================================================
FILE: apps/storybook/stories/slot.stories.tsx
================================================
import * as React from 'react';
import { Slot } from 'radix-ui';
import type { Meta, StoryObj } from '@storybook/react-webpack5';

export default { title: 'Utilities/Slot' } satisfies Meta<typeof Slot.Root>;

type Story = StoryObj<typeof Slot.Root>;

export const WithoutSlottable = {
  render: () => (
    <SlotWithoutSlottable>
      <b data-slot-element>hello</b>
    </SlotWithoutSlottable>
  ),
} satisfies Story;

export const WithSlottable = () => (
  <SlotWithSlottable>
    <b data-slot-element>hello</b>
  </SlotWithSlottable>
);

export const WithComposedEvents = () => (
  <>
    <h1>Should log both</h1>
    <SlotWithPreventableEvent>
      <button onClick={() => console.log('button click')}>Slot event not prevented</button>
    </SlotWithPreventableEvent>

    <h1>Should log "button click"</h1>
    <SlotWithPreventableEvent>
      <button
        onClick={(event) => {
          console.log('button click');
          event.preventDefault();
        }}
      >
        Slot event prevented
      </button>
    </SlotWithPreventableEvent>

    <h1>Should log both</h1>
    <SlotWithoutPreventableEvent>
      <button onClick={() => console.log('button click')}>Slot event not prevented</button>
    </SlotWithoutPreventableEvent>

    <h1>Should log both</h1>
    <SlotWithoutPreventableEvent>
      <button
        onClick={(event) => {
          console.log('button click');
          event.preventDefault();
        }}
      >
        Slot event prevented
      </button>
    </SlotWithoutPreventableEvent>
  </>
);

export const ButtonAsLink = () => (
  <>
    <h1>Button with left/right icons</h1>
    <Button
      iconLeft={<MockIcon color="tomato" />}
      iconRight={<MockIcon color="royalblue" />}
      ref={console.log}
    >
      Button <em>text</em>
    </Button>

    <h1>Button with left/right icons as link (asChild)</h1>
    <Button
      asChild
      iconLeft={<MockIcon color="tomato" />}
      iconRight={<MockIcon color="royalblue" />}
      ref={console.log}
    >
      <a href="https://radix-ui.com">
        Button <em>text</em>
      </a>
    </Button>
  </>
);

const LazyButton = React.lazy(async () => {
  await wait(1000);
  return {
    default: ({ children, ...props }: React.ComponentProps<'button'>) => (
      <button {...props}>{children}</button>
    ),
  };
});

export const WithLazyComponent = () => {
  return (
    <React.Suspense fallback={<div>Loading...</div>}>
      <Slot.Root data-slot-root onClick={() => console.log('click')}>
        <LazyButton data-slot-lazy>Click me</LazyButton>
      </Slot.Root>
    </React.Suspense>
  );
};

export const Chromatic = () => (
  <>
    <h1>Without Slottable</h1>

    <h2>
      One consumer child - <span aria-hidden>✅</span>
    </h2>
    <ErrorBoundary>
      <SlotWithoutSlottable>
        <b data-slot-element>hello</b>
      </SlotWithoutSlottable>
    </ErrorBoundary>

    <h2>
      Multiple consumer child - <span aria-hidden>🔴</span>
    </h2>
    <ErrorBoundary>
      <SlotWithoutSlottable>
        <b data-slot-element>hello</b>
        <b data-slot-element>hello</b>
      </SlotWithoutSlottable>
    </ErrorBoundary>

    <h2>
      Null consumer child - <span aria-hidden>✅</span>
    </h2>
    <ErrorBoundary>
      <SlotWithoutSlottable>{null}</SlotWithoutSlottable>
    </ErrorBoundary>

    <h2>
      Empty consumer child - <span aria-hidden>✅</span>
    </h2>
    <ErrorBoundary>
      <SlotWithoutSlottable></SlotWithoutSlottable>
    </ErrorBoundary>

    <h2>
      False consumer child - <span aria-hidden>✅</span>
    </h2>
    <ErrorBoundary>
      <SlotWithoutSlottable>{false}</SlotWithoutSlottable>
    </ErrorBoundary>

    <h2>
      False internal child - <span aria-hidden>✅</span>
    </h2>
    <ErrorBoundary>
      <SlotWithFalseInternalChild>
        <b data-slot-element>hello</b>
      </SlotWithFalseInternalChild>
    </ErrorBoundary>

    <h2>
      Null internal child - <span aria-hidden>✅</span>
    </h2>
    <ErrorBoundary>
      <SlotWithNullInternalChild>
        <b data-slot-element>hello</b>
      </SlotWithNullInternalChild>
    </ErrorBoundary>

    <h2>
      String consumer child - <span aria-hidden>✅</span>
    </h2>
    <ErrorBoundary>
      <SlotWithoutSlottable>test</SlotWithoutSlottable>
    </ErrorBoundary>

    <h2>
      Number consumer child - <span aria-hidden>✅</span>
    </h2>
    <ErrorBoundary>
      <SlotWithoutSlottable>{1}</SlotWithoutSlottable>
    </ErrorBoundary>

    <h1>With Slottable</h1>

    <h2>
      One consumer child - <span aria-hidden>✅</span>
    </h2>
    <ErrorBoundary>
      <SlotWithSlottable>
        <b data-slot-element>hello</b>
      </SlotWithSlottable>
    </ErrorBoundary>

    <h2>
      Multiple consumer child - <span aria-hidden>🔴</span>
    </h2>
    <ErrorBoundary>
      <SlotWithSlottable>
        <b data-slot-element>hello</b>
        <b data-slot-element>hello</b>
      </SlotWithSlottable>
    </ErrorBoundary>

    <h2>
      Null consumer child - <span aria-hidden>✅</span>
    </h2>
    <ErrorBoundary>
      <SlotWithSlottable>{null}</SlotWithSlottable>
    </ErrorBoundary>

    <h2>
      String consumer child - <span aria-hidden>✅</span>
    </h2>
    <ErrorBoundary>
      <SlotWithSlottable>test</SlotWithSlottable>
    </ErrorBoundary>

    <h2>
      Number consumer child - <span aria-hidden>✅</span>
    </h2>
    <ErrorBoundary>
      <SlotWithSlottable>{1}</SlotWithSlottable>
    </ErrorBoundary>

    <h2>
      Empty consumer child - <span aria-hidden>✅</span>
    </h2>
    <ErrorBoundary>
      <SlotWithSlottable></SlotWithSlottable>
    </ErrorBoundary>

    <h2>
      False consumer child - <span aria-hidden>✅</span>
    </h2>
    <ErrorBoundary>
      <SlotWithSlottable>{false}</SlotWithSlottable>
    </ErrorBoundary>

    <h2>Button with left/right icons</h2>
    <Button iconLeft={<MockIcon color="tomato" />} iconRight={<MockIcon color="royalblue" />}>
      Button <em>text</em>
    </Button>

    <h2>Button with left/right icons as link (asChild)</h2>
    <Button
      asChild
      iconLeft={<MockIcon color="tomato" />}
      iconRight={<MockIcon color="royalblue" />}
    >
      <a href="https://radix-ui.com">
        Button <em>text</em>
      </a>
    </Button>

    <h1>With callback-dependent rendering</h1>
    <h2>Component not passing callback</h2>
    <p>Should NOT have delete button next to component</p>
    <Slot.Root>
      <MockTag>Component</MockTag>
    </Slot.Root>
    <h2>Component passing `undefined` callback</h2>
    <p>Should NOT have delete button next to component</p>
    <Slot.Root>
      <MockTag onDelete={undefined}>Component</MockTag>
    </Slot.Root>
    <h2>Component passing callback</h2>
    <p>Should have delete button next to component</p>
    <Slot.Root>
      <MockTag onDelete={() => alert('Delete')}>Component</MockTag>
    </Slot.Root>
  </>
);
Chromatic.parameters = { chromatic: { disable: false } };

/* ---------------------------------------------------------------------------------------------- */

class ErrorBoundary extends React.Component<any, { hasError: boolean }> {
  constructor(props: any) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError() {
    return { hasError: true };
  }

  render() {
    if (this.state.hasError) {
      return <div style={{ background: 'red', color: 'white', padding: 10 }}>Error</div>;
    }
    return this.props.children;
  }
}

/* Also verifying that props and ref types don't error */
const SlotWithoutSlottable = (props: React.ComponentPropsWithRef<'div'>) => (
  <Slot.Root {...props} className="test" />
);

const SlotWithSlottable = ({ children, ...props }: any) => (
  <Slot.Root {...props}>
    <Slot.Slottable>{children}</Slot.Slottable>
    <span>world</span>
  </Slot.Root>
);

const SlotWithFalseInternalChild = ({ children, ...props }: any) => (
  <Slot.Root {...props}>{false && children}</Slot.Root>
);

const SlotWithNullInternalChild = ({ children, ...props }: any) => (
  <Slot.Root {...props}>{false ? children : null}</Slot.Root>
);

const SlotWithPreventableEvent = (props: any) => (
  <Slot.Root
    {...props}
    onClick={(event) => {
      props.onClick?.(event);
      if (!event.defaultPrevented) {
        console.log(event.target);
      }
    }}
  />
);

const SlotWithoutPreventableEvent = (props: any) => (
  <Slot.Root
    {...props}
    onClick={(event) => {
      props.onClick?.(event);
      console.log(event.target);
    }}
  />
);

const Button = ({
  children,
  asChild = false,
  iconLeft,
  iconRight,
  ...props
}: React.ComponentProps<'button'> & {
  asChild?: boolean;
  iconLeft?: React.ReactNode;
  iconRight?: React.ReactNode;
}) => {
  const Comp = asChild ? Slot.Root : 'button';
  return (
    <Comp
      {...props}
      style={{
        display: 'inline-flex',
        alignItems: 'center',
        gap: 5,
        border: '1px solid black',
        padding: 10,
        backgroundColor: 'white',
        fontFamily: 'apple-system, BlinkMacSystemFont, helvetica, arial, sans-serif',
        fontSize: 14,
        borderRadius: 3,
        ...props.style,
      }}
    >
      {iconLeft}
      <Slot.Slottable>{children}</Slot.Slottable>
      {iconRight}
    </Comp>
  );
};

const MockIcon = ({ color = 'tomato', ...props }: React.ComponentProps<'span'>) => (
  <span
    {...props}
    style={{
      display: 'inline-block',
      width: 10,
      height: 10,
      backgroundColor: color,
      ...props.style,
    }}
  />
);

const MockTag = ({
  onDelete,
  ...props
}: React.ComponentProps<'div'> & {
  onDelete?: () => void;
}) => {
  return (
    <div {...props}>
      {props.children} {onDelete ? <button onClick={onDelete}>delete</button> : null}
    </div>
  );
};

async function wait(ms: number) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}



================================================
FILE: apps/storybook/stories/switch.stories.module.css
================================================
.root,
:global(:root) {
  --_switch-width: 50px;
  --_switch-thumb-width: 20px;
  --_switch-gap: 4px;
}

.root {
  /* better default alignment */
  vertical-align: middle;
  /* ensures thumb is not horizontally centered (default in `button`) */
  text-align: left;
  /* ------ */
  outline: none;
  border: none;
  width: var(--_switch-width);
  padding: var(--_switch-gap);
  border-radius: 9999px;
  background-color: var(--color-gray300);
  transition: background-color 166ms ease-out;

  &:focus {
    outline: none;
    box-shadow: 0 0 0 2px var(--color-black);
  }

  &[data-state='checked'] {
    background-color: var(--color-red);
    border-color: var(--color-red);
  }

  &[data-disabled] {
    opacity: 0.5;
  }
}

.thumb {
  /* ensures thumb is sizeable/can receive vertical margins */
  display: inline-block;
  /* ensures thumb is vertically centered */
  vertical-align: middle;
  /* ------ */
  width: var(--_switch-thumb-width);
  height: var(--_switch-thumb-width);
  background-color: var(--color-white);
  border-radius: 9999px;
  transition: transform 166ms ease-out;
  &[data-state='checked'] {
    transform: translateX(
      calc(var(--_switch-width) - var(--_switch-gap) * 2 - var(--_switch-thumb-width))
    );
  }
}

.rootAttr,
.thumbAttr {
  background-color: rgba(0, 0, 255, 0.3);
  border: 2px solid blue;
  padding: 10px;
  &[data-state='unchecked'] {
    border-color: red;
  }
  &[data-state='checked'] {
    border-color: green;
  }
  &[data-state='indeterminate'] {
    border-color: purple;
  }
  &[data-disabled] {
    border-style: dashed;
  }
  &:disabled {
    opacity: 0.5;
  }
}

.label {
  /* ensures it can receive vertical margins */
  display: inline-block;
  /* better default alignment */
  vertical-align: middle;
  /* mimics default `label` tag (as we render a `span`) */
  cursor: default;
  display: inline-block;
}



================================================
FILE: apps/storybook/stories/switch.stories.tsx
================================================
import * as React from 'react';
import { Label as LabelPrimitive, Switch } from 'radix-ui';
import styles from './switch.stories.module.css';

export default { title: 'Components/Switch' };

export const Styled = () => (
  <>
    <p>This switch is nested inside a label. The state is uncontrolled.</p>
    <Label>
      This is the label{' '}
      <Switch.Root className={styles.root}>
        <Switch.Thumb className={styles.thumb} />
      </Switch.Root>
    </Label>
  </>
);

export const Controlled = () => {
  const [checked, setChecked] = React.useState(true);

  return (
    <>
      <p>This switch is placed adjacent to its label. The state is controlled.</p>
      <Label htmlFor="randBox">This is the label</Label>{' '}
      <Switch.Root
        className={styles.root}
        checked={checked}
        onCheckedChange={setChecked}
        id="randBox"
      >
        <Switch.Thumb className={styles.thumb} />
      </Switch.Root>
    </>
  );
};

export const WithinForm = () => {
  const [data, setData] = React.useState({ optional: false, required: false, stopprop: false });
  const [checked, setChecked] = React.useState(false);

  return (
    <form
      onSubmit={(event) => event.preventDefault()}
      onChange={(event) => {
        const input = event.target as HTMLInputElement;
        setData((prevData) => ({ ...prevData, [input.name]: input.checked }));
      }}
    >
      <fieldset>
        <legend>optional checked: {String(data.optional)}</legend>
        <label>
          <Switch.Root
            className={styles.root}
            name="optional"
            checked={checked}
            onCheckedChange={setChecked}
          >
            <Switch.Thumb className={styles.thumb} />
          </Switch.Root>{' '}
          with label
        </label>
      </fieldset>

      <br />
      <br />

      <fieldset>
        <legend>required checked: {String(data.required)}</legend>
        <Switch.Root className={styles.root} name="required" required>
          <Switch.Thumb className={styles.thumb} />
        </Switch.Root>
      </fieldset>

      <br />
      <br />

      <fieldset>
        <legend>stop propagation checked: {String(data.stopprop)}</legend>
        <Switch.Root
          className={styles.root}
          name="stopprop"
          onClick={(event) => event.stopPropagation()}
        >
          <Switch.Thumb className={styles.thumb} />
        </Switch.Root>
      </fieldset>

      <br />
      <br />

      <button>Submit</button>
    </form>
  );
};

export const Chromatic = () => (
  <>
    <h1>Uncontrolled</h1>
    <h2>Off</h2>
    <Switch.Root className={styles.root}>
      <Switch.Thumb className={styles.thumb} />
    </Switch.Root>

    <h2>On</h2>
    <Switch.Root className={styles.root} defaultChecked>
      <Switch.Thumb className={styles.thumb} />
    </Switch.Root>

    <h1>Controlled</h1>
    <h2>Off</h2>
    <Switch.Root className={styles.root} checked={false}>
      <Switch.Thumb className={styles.thumb} />
    </Switch.Root>

    <h2>On</h2>
    <Switch.Root className={styles.root} checked>
      <Switch.Thumb className={styles.thumb} />
    </Switch.Root>

    <h1>Disabled</h1>
    <Switch.Root className={styles.root} disabled>
      <Switch.Thumb className={styles.thumb} />
    </Switch.Root>

    <h1>State attributes</h1>
    <h2>Unchecked</h2>
    <Switch.Root className={styles.rootAttr}>
      <Switch.Thumb className={styles.thumbAttr} />
    </Switch.Root>

    <h2>Checked</h2>
    <Switch.Root className={styles.rootAttr} defaultChecked>
      <Switch.Thumb className={styles.thumbAttr} />
    </Switch.Root>

    <h2>Disabled</h2>
    <Switch.Root className={styles.rootAttr} defaultChecked disabled>
      <Switch.Thumb className={styles.thumbAttr} />
    </Switch.Root>
  </>
);
Chromatic.parameters = { chromatic: { disable: false } };

const Label = (props: any) => <LabelPrimitive.Root {...props} className={styles.label} />;



================================================
FILE: apps/storybook/stories/tabs.stories.module.css
================================================
.root {
  /* ensures things are layed out correctly by default */
  display: flex;
  &[data-orientation='horizontal'] {
    flexdirection: column;
  }
  /* ---------- */
  border: 1px solid #eee;
  font-family:
    -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif,
    'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
  max-width: 20rem;
}

.list {
  flex-shrink: 0;
  /* ensures things are layed out correctly by default */
  display: flex;
  &[data-orientation='vertical'] {
    flex-direction: column;
  }
  /* ---------- */
  background-color: #eee;
}

.trigger {
  all: unset;
  flex-shrink: 0;
  /* ---------- */
  padding: 0.4em 0.6em;
  font-weight: 500;
  line-height: 1;
  user-select: none;

  &[data-orientation='horizontal'] {
    border-top: 4px solid transparent;
    border-bottom: 4px solid var(--border-color, transparent);
  }

  &[data-orientation='vertical'] {
    padding: 0.6em;
    border-right: 4px solid var(--border-color, transparent);
  }

  &[data-disabled] {
    color: var(--color-gray300);
  }

  &[data-state='active'] {
    --border-color: crimson;
  }

  &:focus {
    --border-color: #111;
    outline: 1px solid var(--border-color);
    &[data-state='active'] {
      --border-color: crimson;
    }
  }
}

.content {
  flex-grow: 1;
  /* ---------- */
  padding: 1em;
  font-weight: 300;
  font-size: 0.85em;
  line-height: 1.65;
  &[data-orientation='horizontal'] {
    border-top: none;
  }
  &[data-orientation='vertical'] {
    border-left: none;
  }
}

@keyframes show {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: translateY(0px);
  }
}

.animatedContent {
  &[data-state='active'] {
    animation: tabs--show 400ms ease;
  }
}

.contentAttr {
  /* ensure we can see the content (because it has `hidden` attribute) */
  display: block;
}

.rootAttr,
.contentAttr,
.listAttr,
.triggerAttr {
  background-color: rgb(0 0 255 / 0.3);
  border: 2px solid blue;
  padding: 10px;
  &:disabled {
    opacity: 0.5;
  }
  &[data-disabled] {
    border-style: dashed;
  }

  &[data-state='inactive'] {
    border-color: red;
  }
  &[data-state='active'] {
    border-color: green;
  }
}



================================================
FILE: apps/storybook/stories/tabs.stories.tsx
================================================
import { Direction, Tabs } from 'radix-ui';
import styles from './tabs.stories.module.css';

export default { title: 'Components/Tabs' };

const animatedContentClass = [styles.content, styles.animatedContent].join(' ');

export const Styled = () => (
  <>
    <h1>Horizontal (automatic activation)</h1>
    <Tabs.Root defaultValue="tab1" className={styles.root}>
      <Tabs.List aria-label="tabs example" className={styles.list}>
        <Tabs.Trigger value="tab1" className={styles.trigger}>
          Tab 1
        </Tabs.Trigger>
        <Tabs.Trigger value="tab2" disabled className={styles.trigger}>
          Tab 2
        </Tabs.Trigger>
        <Tabs.Trigger value="tab3" className={styles.trigger}>
          Tab 3
        </Tabs.Trigger>
      </Tabs.List>
      <Tabs.Content value="tab1" className={styles.content}>
        Dis metus rhoncus sit convallis sollicitudin vel cum, hac purus tincidunt eros sem himenaeos
        integer, faucibus varius nullam nostra bibendum consectetur mollis, gravida elementum
        pellentesque volutpat dictum ipsum.
      </Tabs.Content>
      <Tabs.Content value="tab2" className={styles.content}>
        You'll never find me!
      </Tabs.Content>
      <Tabs.Content value="tab3" className={styles.content}>
        Ut nisi elementum metus semper mauris dui fames accumsan aenean, maecenas ac sociis dolor
        quam tempus pretium.
      </Tabs.Content>
    </Tabs.Root>

    <h1>Vertical (manual activation)</h1>
    <Tabs.Root
      defaultValue="tab1"
      className={styles.root}
      orientation="vertical"
      activationMode="manual"
    >
      <Tabs.List aria-label="tabs example" className={styles.list}>
        <Tabs.Trigger value="tab1" className={styles.trigger}>
          Tab 1
        </Tabs.Trigger>
        <Tabs.Trigger value="tab2" disabled className={styles.trigger}>
          Tab 2
        </Tabs.Trigger>
        <Tabs.Trigger value="tab3" className={styles.trigger}>
          Tab 3
        </Tabs.Trigger>
      </Tabs.List>
      <Tabs.Content value="tab1" className={styles.content}>
        Dis metus rhoncus sit convallis sollicitudin vel cum, hac purus tincidunt eros sem himenaeos
        integer, faucibus varius nullam nostra bibendum consectetur mollis, gravida elementum
        pellentesque volutpat dictum ipsum.
      </Tabs.Content>
      <Tabs.Content value="tab2" className={styles.content}>
        You'll never find me!
      </Tabs.Content>
      <Tabs.Content value="tab3" className={styles.content}>
        Ut nisi elementum metus semper mauris dui fames accumsan aenean, maecenas ac sociis dolor
        quam tempus pretium.
      </Tabs.Content>
    </Tabs.Root>
  </>
);

export const Animated = () => (
  <>
    <h1>Horizontal (automatic activation)</h1>
    <Tabs.Root defaultValue="tab1" className={styles.root}>
      <Tabs.List aria-label="tabs example" className={styles.list}>
        <Tabs.Trigger value="tab1" className={styles.trigger}>
          Tab 1
        </Tabs.Trigger>
        <Tabs.Trigger value="tab2" disabled className={styles.trigger}>
          Tab 2
        </Tabs.Trigger>
        <Tabs.Trigger value="tab3" className={styles.trigger}>
          Tab 3
        </Tabs.Trigger>
      </Tabs.List>

      <Tabs.Content value="tab1" className={animatedContentClass}>
        Dis metus rhoncus sit convallis sollicitudin vel cum, hac purus tincidunt eros sem himenaeos
        integer, faucibus varius nullam nostra bibendum consectetur mollis, gravida elementum
        pellentesque volutpat dictum ipsum.
      </Tabs.Content>
      <Tabs.Content value="tab2" className={animatedContentClass}>
        You'll never find me!
      </Tabs.Content>
      <Tabs.Content value="tab3" className={animatedContentClass}>
        Ut nisi elementum metus semper mauris dui fames accumsan aenean, maecenas ac sociis dolor
        quam tempus pretium.
      </Tabs.Content>
    </Tabs.Root>

    <h1>Vertical (manual activation)</h1>
    <Tabs.Root
      defaultValue="tab1"
      className={styles.root}
      orientation="vertical"
      activationMode="manual"
    >
      <Tabs.List aria-label="tabs example" className={styles.list}>
        <Tabs.Trigger value="tab1" className={styles.trigger}>
          Tab 1
        </Tabs.Trigger>
        <Tabs.Trigger value="tab2" disabled className={styles.trigger}>
          Tab 2
        </Tabs.Trigger>
        <Tabs.Trigger value="tab3" className={styles.trigger}>
          Tab 3
        </Tabs.Trigger>
      </Tabs.List>
      <Tabs.Content value="tab1" className={animatedContentClass}>
        Dis metus rhoncus sit convallis sollicitudin vel cum, hac purus tincidunt eros sem himenaeos
        integer, faucibus varius nullam nostra bibendum consectetur mollis, gravida elementum
        pellentesque volutpat dictum ipsum.
      </Tabs.Content>
      <Tabs.Content value="tab2" className={animatedContentClass}>
        You'll never find me!
      </Tabs.Content>
      <Tabs.Content value="tab3" className={animatedContentClass}>
        Ut nisi elementum metus semper mauris dui fames accumsan aenean, maecenas ac sociis dolor
        quam tempus pretium.
      </Tabs.Content>
    </Tabs.Root>
  </>
);

export const Chromatic = () => (
  <>
    <h1>Uncontrolled</h1>
    <Tabs.Root defaultValue="tab3" className={styles.root}>
      <Tabs.List aria-label="tabs example" className={styles.list}>
        <Tabs.Trigger value="tab1" className={styles.trigger}>
          Tab 1
        </Tabs.Trigger>
        <Tabs.Trigger value="tab2" disabled className={styles.trigger}>
          Tab 2
        </Tabs.Trigger>
        <Tabs.Trigger value="tab3" className={styles.trigger}>
          Tab 3
        </Tabs.Trigger>
      </Tabs.List>
      <Tabs.Content value="tab1" className={styles.content}>
        Dis metus rhoncus sit convallis sollicitudin vel cum, hac purus tincidunt eros sem himenaeos
        integer, faucibus varius nullam nostra bibendum consectetur mollis, gravida elementum
        pellentesque volutpat dictum ipsum.
      </Tabs.Content>
      <Tabs.Content value="tab2" className={styles.content}>
        You'll never find me!
      </Tabs.Content>
      <Tabs.Content value="tab3" className={styles.content}>
        Ut nisi elementum metus semper mauris dui fames accumsan aenean, maecenas ac sociis dolor
        quam tempus pretium.
      </Tabs.Content>
    </Tabs.Root>

    <h1>Controlled</h1>
    <Tabs.Root value="tab3" className={styles.root}>
      <Tabs.List aria-label="tabs example" className={styles.list}>
        <Tabs.Trigger value="tab1" className={styles.trigger}>
          Tab 1
        </Tabs.Trigger>
        <Tabs.Trigger value="tab2" disabled className={styles.trigger}>
          Tab 2
        </Tabs.Trigger>
        <Tabs.Trigger value="tab3" className={styles.trigger}>
          Tab 3
        </Tabs.Trigger>
      </Tabs.List>
      <Tabs.Content value="tab1" className={styles.content}>
        Dis metus rhoncus sit convallis sollicitudin vel cum, hac purus tincidunt eros sem himenaeos
        integer, faucibus varius nullam nostra bibendum consectetur mollis, gravida elementum
        pellentesque volutpat dictum ipsum.
      </Tabs.Content>
      <Tabs.Content value="tab2" className={styles.content}>
        You'll never find me!
      </Tabs.Content>
      <Tabs.Content value="tab3" className={styles.content}>
        Ut nisi elementum metus semper mauris dui fames accumsan aenean, maecenas ac sociis dolor
        quam tempus pretium.
      </Tabs.Content>
    </Tabs.Root>

    <h1>Vertical</h1>
    <Tabs.Root
      defaultValue="tab3"
      className={styles.root}
      orientation="vertical"
      activationMode="manual"
    >
      <Tabs.List aria-label="tabs example" className={styles.list}>
        <Tabs.Trigger value="tab1" className={styles.trigger}>
          Tab 1
        </Tabs.Trigger>
        <Tabs.Trigger value="tab2" disabled className={styles.trigger}>
          Tab 2
        </Tabs.Trigger>
        <Tabs.Trigger value="tab3" className={styles.trigger}>
          Tab 3
        </Tabs.Trigger>
      </Tabs.List>
      <Tabs.Content value="tab1" className={styles.content}>
        Dis metus rhoncus sit convallis sollicitudin vel cum, hac purus tincidunt eros sem himenaeos
        integer, faucibus varius nullam nostra bibendum consectetur mollis, gravida elementum
        pellentesque volutpat dictum ipsum.
      </Tabs.Content>
      <Tabs.Content value="tab2" className={styles.content}>
        You'll never find me!
      </Tabs.Content>
      <Tabs.Content value="tab3" className={styles.content}>
        Ut nisi elementum metus semper mauris dui fames accumsan aenean, maecenas ac sociis dolor
        quam tempus pretium.
      </Tabs.Content>
    </Tabs.Root>

    <h1>Direction</h1>
    <h2>Prop</h2>
    <Tabs.Root defaultValue="tab3" dir="rtl" className={styles.root}>
      <Tabs.List aria-label="tabs example" className={styles.list}>
        <Tabs.Trigger value="tab1" className={styles.trigger}>
          Tab 1
        </Tabs.Trigger>
        <Tabs.Trigger value="tab2" disabled className={styles.trigger}>
          Tab 2
        </Tabs.Trigger>
        <Tabs.Trigger value="tab3" className={styles.trigger}>
          Tab 3
        </Tabs.Trigger>
      </Tabs.List>
      <Tabs.Content value="tab1" className={styles.content}>
        Dis metus rhoncus sit convallis sollicitudin vel cum, hac purus tincidunt eros sem himenaeos
        integer, faucibus varius nullam nostra bibendum consectetur mollis, gravida elementum
        pellentesque volutpat dictum ipsum.
      </Tabs.Content>
      <Tabs.Content value="tab2" className={styles.content}>
        You'll never find me!
      </Tabs.Content>
      <Tabs.Content value="tab3" className={styles.content}>
        Ut nisi elementum metus semper mauris dui fames accumsan aenean, maecenas ac sociis dolor
        quam tempus pretium.
      </Tabs.Content>
    </Tabs.Root>

    <h2>Inherited</h2>
    <Direction.Provider dir="rtl">
      <Tabs.Root defaultValue="tab3" className={styles.root}>
        <Tabs.List aria-label="tabs example" className={styles.list}>
          <Tabs.Trigger value="tab1" className={styles.trigger}>
            Tab 1
          </Tabs.Trigger>
          <Tabs.Trigger value="tab2" disabled className={styles.trigger}>
            Tab 2
          </Tabs.Trigger>
          <Tabs.Trigger value="tab3" className={styles.trigger}>
            Tab 3
          </Tabs.Trigger>
        </Tabs.List>
        <Tabs.Content value="tab1" className={styles.content}>
          Dis metus rhoncus sit convallis sollicitudin vel cum, hac purus tincidunt eros sem
          himenaeos integer, faucibus varius nullam nostra bibendum consectetur mollis, gravida
          elementum pellentesque volutpat dictum ipsum.
        </Tabs.Content>
        <Tabs.Content value="tab2" className={styles.content}>
          You'll never find me!
        </Tabs.Content>
        <Tabs.Content value="tab3" className={styles.content}>
          Ut nisi elementum metus semper mauris dui fames accumsan aenean, maecenas ac sociis dolor
          quam tempus pretium.
        </Tabs.Content>
      </Tabs.Root>
    </Direction.Provider>

    <h1>Animated</h1>
    <p>Should not animate on initial mount</p>
    <Tabs.Root value="tab1" className={styles.root}>
      <Tabs.List aria-label="tabs example" className={styles.list}>
        <Tabs.Trigger value="tab1" className={styles.trigger}>
          Tab 1
        </Tabs.Trigger>
        <Tabs.Trigger value="tab2" disabled className={styles.trigger}>
          Tab 2
        </Tabs.Trigger>
        <Tabs.Trigger value="tab3" className={styles.trigger}>
          Tab 3
        </Tabs.Trigger>
      </Tabs.List>
      <Tabs.Content
        value="tab1"
        className={animatedContentClass}
        style={{ animationDuration: '3000ms' }}
      >
        Dis metus rhoncus sit convallis sollicitudin vel cum, hac purus tincidunt eros sem himenaeos
        integer, faucibus varius nullam nostra bibendum consectetur mollis, gravida elementum
        pellentesque volutpat dictum ipsum.
      </Tabs.Content>
      <Tabs.Content value="tab2" className={animatedContentClass}>
        You'll never find me!
      </Tabs.Content>
      <Tabs.Content value="tab3" className={animatedContentClass}>
        Ut nisi elementum metus semper mauris dui fames accumsan aenean, maecenas ac sociis dolor
        quam tempus pretium.
      </Tabs.Content>
    </Tabs.Root>

    <h1>Force mounted contents</h1>
    <Tabs.Root className={styles.root}>
      <Tabs.List aria-label="tabs example" className={styles.list}>
        <Tabs.Trigger value="tab1" className={styles.trigger}>
          Tab 1
        </Tabs.Trigger>
        <Tabs.Trigger value="tab2" className={styles.trigger}>
          Tab 2
        </Tabs.Trigger>
        <Tabs.Trigger value="tab3" className={styles.trigger}>
          Tab 3
        </Tabs.Trigger>
      </Tabs.List>
      <Tabs.Content value="tab1" className={styles.content} forceMount>
        Tab 1 content
      </Tabs.Content>
      <Tabs.Content value="tab2" className={styles.content} forceMount>
        Tab 2 content
      </Tabs.Content>
      <Tabs.Content value="tab3" className={styles.content} forceMount>
        Tab 3 content
      </Tabs.Content>
    </Tabs.Root>

    <h1>State attributes</h1>
    <Tabs.Root defaultValue="tab3" className={styles.rootAttr}>
      <Tabs.List aria-label="tabs example" className={styles.listAttr}>
        <Tabs.Trigger value="tab1" className={styles.triggerAttr}>
          Tab 1
        </Tabs.Trigger>
        <Tabs.Trigger value="tab2" disabled className={styles.triggerAttr}>
          Tab 2
        </Tabs.Trigger>
        <Tabs.Trigger value="tab3" className={styles.triggerAttr}>
          Tab 3
        </Tabs.Trigger>
      </Tabs.List>
      <Tabs.Content value="tab1" className={styles.contentAttr}>
        Dis metus rhoncus sit convallis sollicitudin vel cum, hac purus tincidunt eros sem himenaeos
        integer, faucibus varius nullam nostra bibendum consectetur mollis, gravida elementum
        pellentesque volutpat dictum ipsum.
      </Tabs.Content>
      <Tabs.Content value="tab2" className={styles.contentAttr}>
        You'll never find me!
      </Tabs.Content>
      <Tabs.Content value="tab3" className={styles.contentAttr}>
        Ut nisi elementum metus semper mauris dui fames accumsan aenean, maecenas ac sociis dolor
        quam tempus pretium.
      </Tabs.Content>
    </Tabs.Root>
  </>
);
Chromatic.parameters = { chromatic: { disable: false } };



================================================
FILE: apps/storybook/stories/toast.stories.module.css
================================================
.viewport,
:global(:root) {
  --_viewport-padding: 10px;
}

.viewport {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  border: 1px solid;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  padding: var(--_viewport-padding);
  gap: var(--_viewport-padding);
  list-style: none;
}

.root {
  position: relative;
  overflow: hidden;
  list-style: none;
  width: 230px;
  border-radius: 4px;
  border: 1px solid black;
  box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
  padding: 10px;
  font-size: 12px;
}

.errorRoot {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.animatedRoot {
  &[data-state='open'] {
    animation: toast-fadeIn 200ms ease-out;
  }
  &[data-state='closed'] {
    animation: toast-fadeOut 200ms ease-out;
  }
  &[data-swipe='move'] {
    transform: translate(var(--radix-toast-swipe-move-x), var(--radix-toast-swipe-move-y));
  }
  &[data-swipe='cancel'] {
    transform: translate(0, 0);
    transition: transform 200ms ease-out;
  }
  &[data-swipe='end'] {
    animation-duration: 300ms;
    animation-timing-function: ease-out;
    &[data-swipe-direction='right'] {
      animation-name: toast-slideRight;
    }
    &[data-swipe-direction='left'] {
      animation-name: toast-slideLeft;
    }
    &[data-swipe-direction='up'] {
      animation-name: toast-slideUp;
    }
    &[data-swipe-direction='down'] {
      animation-name: toast-slideDown;
    }
  }
}

.header {
  padding: 5px 10px;
  margin: -10px -10px 10px;
  background: black;
  color: white;
  position: relative;
  height: 22px;
  display: flex;
  align-items: center;
}

.successHeader {
  background: green;
}

.title {
  font-size: inherit;
  font-weight: normal;
}

.description {
  margin: 0;
}

.button,
.close {
  border: 1px solid black;
  border-radius: 4px;
  background: gainsboro;
  font-family: inherit;
  padding: 2px 5px;
  &:hover,
  &:focus {
    background: royalblue;
    border-color: darkblue;
    color: white;
  }
}

.close {
  position: absolute;
  top: 50%;
  right: 5px;
  transform: translateY(-50%);
  width: 18px;
  height: 18px;
  padding: 0;
}

@keyframes toast-fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes toast-fadeOut {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}

@keyframes toast-slideRight {
  from {
    transform: translateX(var(--radix-toast-swipe-end-x));
  }
  to {
    transform: translateX(calc(100% + var(--_viewport-padding)));
  }
}

@keyframes toast-slideLeft {
  from {
    transform: translateX(var(--radix-toast-swipe-end-x));
  }
  to {
    transform: translateX(calc(-100% - var(--_viewport-padding)));
  }
}

@keyframes toast-slideUp {
  from {
    transform: translateY(var(--radix-toast-swipe-end-y));
  }
  to {
    transform: translateY(calc(-100% - var(--_viewport-padding)));
  }
}

@keyframes toast-slideDown {
  from {
    transform: translateY(var(--radix-toast-swipe-end-y));
  }
  to {
    transform: translateY(calc(100% + var(--_viewport-padding)));
  }
}

@keyframes toast-loading {
  from {
    transform: translateX(-100%);
  }
  to {
    transform: translateX(0%);
  }
}

.progressBar {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  height: 2px;
  overflow: hidden;
  background-color: var(--color-gray100);
}

.progressBarInner {
  height: 100%;
  background-color: var(--color-green);
  animation-name: toast-loading;
  animation-timing-function: linear;
}

.chromaticViewport {
  display: inline-flex;
  border: 5px solid royalblue;
  flex-direction: column;
  padding: var(--_viewport-padding);
  gap: var(--_viewport-padding);
}



================================================
FILE: apps/storybook/stories/toast.stories.tsx
================================================
import * as React from 'react';
import { Dialog, Toast } from 'radix-ui';
import styles from './toast.stories.module.css';

export default { title: 'Components/Toast' };

export const Styled = () => (
  <Toast.Provider>
    <ToastUpgradeAvailable />
    <Toast.Viewport className={styles.viewport} />
  </Toast.Provider>
);

export const Controlled = () => {
  const [hasUpgrade, setHasUpgrade] = React.useState(false);
  const [isSubscribed, setIsSubscribed] = React.useState(false);
  const [savedCount, setSavedCount] = React.useState(0);
  const [errorCount, setErrorCount] = React.useState(0);

  React.useEffect(() => {
    if (!hasUpgrade) {
      const timer = window.setTimeout(() => setHasUpgrade(true), 10000);
      return () => window.clearTimeout(timer);
    }
  }, [hasUpgrade]);

  return (
    <Toast.Provider>
      <button onClick={() => setIsSubscribed(true)}>subscribe</button>
      <button onClick={() => setErrorCount((count) => count + 1)}>error</button>
      <button onClick={() => setSavedCount((count) => count + 1)}>save</button>
      <ToastUpgradeAvailable open={hasUpgrade} onOpenChange={setHasUpgrade} />
      <ToastSubscribeSuccess open={isSubscribed} onOpenChange={setIsSubscribed} />

      {[...Array(errorCount)].map((_, index) => (
        <Toast.Root key={index} className={[styles.root, styles.errorRoot].join(' ')}>
          <Toast.Description>There was an error</Toast.Description>
          <Toast.Action
            className={styles.button}
            altText="Resubmit the form to try again."
            onClick={() => console.log('try again')}
          >
            Try again
          </Toast.Action>
        </Toast.Root>
      ))}

      {[...Array(savedCount)].map((_, index) => (
        <Toast.Root key={index} className={styles.root}>
          <Toast.Description>Successfully saved</Toast.Description>
        </Toast.Root>
      ))}

      <Toast.Viewport className={styles.viewport} />
    </Toast.Provider>
  );
};

export const FromDialog = () => {
  const [open, setOpen] = React.useState(false);
  return (
    <Toast.Provider>
      <Dialog.Root>
        <Dialog.Trigger>Open</Dialog.Trigger>
        <Dialog.Overlay />
        <Dialog.Content style={{ border: '1px solid', width: 300, padding: 30 }}>
          <Dialog.Title style={{ margin: 0 }}>Title</Dialog.Title>
          <Dialog.Description>Description</Dialog.Description>
          <button onClick={() => setOpen(true)}>Open toast</button>
          <Dialog.Close>Close</Dialog.Close>
        </Dialog.Content>
      </Dialog.Root>

      <Toast.Root
        open={open}
        onOpenChange={setOpen}
        className={[styles.root, styles.errorRoot].join(' ')}
      >
        <Toast.Description>There was an error</Toast.Description>
        <Toast.Action
          className={styles.button}
          altText="Resubmit the form to try again."
          onClick={() => console.log('try again')}
        >
          Try again
        </Toast.Action>
      </Toast.Root>

      <Toast.Viewport className={styles.viewport} />
    </Toast.Provider>
  );
};

export const Promise = () => {
  const [saving, setSaving] = React.useState(false);
  const [open, setOpen] = React.useState(false);

  React.useEffect(() => {
    if (saving) {
      const timer = window.setTimeout(() => setSaving(false), 2000);
      return () => window.clearTimeout(timer);
    }
  }, [saving]);

  return (
    <Toast.Provider>
      <form
        onSubmit={(event) => {
          setSaving(true);
          setOpen(true);
          event.preventDefault();
        }}
      >
        <button>Save</button>
        <Toast.Root
          className={styles.root}
          duration={saving ? Infinity : 2000}
          open={open}
          onOpenChange={setOpen}
        >
          {saving ? (
            <Toast.Description>Saving&hellip;</Toast.Description>
          ) : (
            <Toast.Description>Saved!</Toast.Description>
          )}
        </Toast.Root>
      </form>

      <Toast.Viewport className={styles.viewport} />
    </Toast.Provider>
  );
};

export const KeyChange = () => {
  const [toastOneCount, setToastOneCount] = React.useState(0);
  const [toastTwoCount, setToastTwoCount] = React.useState(0);

  return (
    <Toast.Provider>
      <button onClick={() => setToastOneCount((count) => count + 1)}>Open toast one</button>
      <button onClick={() => setToastTwoCount((count) => count + 1)}>Open toast two</button>

      {toastOneCount > 0 && (
        <Toast.Root key={'one-' + String(toastOneCount)} className={styles.root}>
          <Toast.Description>Toast one</Toast.Description>
        </Toast.Root>
      )}

      {toastTwoCount > 0 && (
        <Toast.Root key={'two-' + String(toastTwoCount)} className={styles.root}>
          <Toast.Description>Toast two</Toast.Description>
        </Toast.Root>
      )}

      <Toast.Viewport className={styles.viewport} />
    </Toast.Provider>
  );
};

export const PauseResumeProps = () => {
  const [toastCount, setToastCount] = React.useState(0);

  return (
    <Toast.Provider>
      <button onClick={() => setToastCount((count) => count + 1)}>Add toast</button>

      {[...Array(toastCount)].map((_, index) => (
        <ToastWithProgress key={index} />
      ))}

      <Toast.Viewport className={styles.viewport} />
    </Toast.Provider>
  );
};

type Direction = React.ComponentProps<typeof Toast.Provider>['swipeDirection'];

export const Animated = () => {
  const [open, setOpen] = React.useState(false);
  const [swipeDirection, setSwipeDirection] = React.useState<Direction>('right');
  const timerRef = React.useRef(0);
  return (
    <Toast.Provider
      swipeDirection={swipeDirection}
      swipeThreshold={(['up', 'down'] as Direction[]).includes(swipeDirection) ? 25 : undefined}
    >
      <button
        onClick={() => {
          setOpen(false);
          window.clearTimeout(timerRef.current);
          timerRef.current = window.setTimeout(() => setOpen(true), 150);
        }}
      >
        Open
      </button>
      <select
        value={swipeDirection}
        onChange={(event) => {
          setSwipeDirection(event.currentTarget.value as Direction);
        }}
      >
        <option value="right">Slide right</option>
        <option value="left">Slide left</option>
        <option value="up">Slide up</option>
        <option value="down">Slide down</option>
      </select>
      <Toast.Root
        className={[styles.root, styles.animatedRoot].join(' ')}
        open={open}
        onOpenChange={setOpen}
      >
        <Toast.Description>Swipe me {swipeDirection}</Toast.Description>
        <Toast.Close className={styles.button}>Dismiss</Toast.Close>
      </Toast.Root>
      <Toast.Viewport className={styles.viewport} />
    </Toast.Provider>
  );
};

export const Cypress = () => {
  const [count, setCount] = React.useState(0);

  return (
    <Toast.Provider>
      <button onClick={() => setCount((count) => count + 1)}>Add toast</button>
      <div
        style={{ display: 'flex', justifyContent: 'space-between', maxWidth: 700, margin: 'auto' }}
      >
        <button>Focusable before viewport</button>

        {[...Array(count)].map((_, index) => {
          const identifier = index + 1;
          return (
            <Toast.Root
              key={index}
              open
              className={styles.root}
              data-testid={`toast-${identifier}`}
            >
              <Toast.Title className={styles.title}>Toast {identifier} title</Toast.Title>
              <Toast.Description className={styles.description}>
                Toast {identifier} description
              </Toast.Description>

              <Toast.Close className={styles.button} aria-label="Close">
                Toast button {identifier}.1
              </Toast.Close>
              <Toast.Action
                altText="Go and perform an action"
                className={styles.button}
                style={{ marginTop: 10 }}
              >
                Toast button {identifier}.2
              </Toast.Action>
            </Toast.Root>
          );
        })}
        <Toast.Viewport className={styles.viewport} />

        <button>Focusable after viewport</button>
      </div>
    </Toast.Provider>
  );
};

const SNAPSHOT_DELAY = 300;

export const Chromatic = () => {
  const [open, setOpen] = React.useState(true);
  return (
    <>
      <h1>Order</h1>
      <Toast.Provider duration={Infinity}>
        <Toast.Root className={styles.root}>
          <div className={styles.header}>
            <Toast.Title className={styles.title}>Toast 1</Toast.Title>
            <Toast.Close className={styles.close}>×</Toast.Close>
          </div>
          <Toast.Description className={styles.description}>Description</Toast.Description>
          <Toast.Action altText="alternative" className={styles.button} style={{ marginTop: 10 }}>
            Action
          </Toast.Action>
        </Toast.Root>
        <Toast.Root className={styles.root}>
          <div className={styles.header}>
            <Toast.Title className={styles.title}>Toast 2</Toast.Title>
            <Toast.Close className={styles.close}>×</Toast.Close>
          </div>
          <Toast.Description className={styles.description}>Description</Toast.Description>
          <Toast.Action altText="alternative" className={styles.button} style={{ marginTop: 10 }}>
            Action
          </Toast.Action>
        </Toast.Root>
        <Toast.Viewport className={styles.chromaticViewport}></Toast.Viewport>
      </Toast.Provider>

      <h1>Uncontrolled</h1>

      <h2>Open</h2>
      <Toast.Provider>
        <Toast.Root duration={Infinity} className={styles.root}>
          <div className={styles.header}>
            <Toast.Title className={styles.title}>Toast</Toast.Title>
            <Toast.Close className={styles.close}>×</Toast.Close>
          </div>
          <Toast.Description className={styles.description}>Description</Toast.Description>
          <Toast.Action altText="alternative" className={styles.button} style={{ marginTop: 10 }}>
            Action
          </Toast.Action>
        </Toast.Root>
        <Toast.Viewport className={styles.chromaticViewport}></Toast.Viewport>
      </Toast.Provider>

      <h2>Closed</h2>
      <Toast.Provider>
        <Toast.Root defaultOpen={false} duration={Infinity} className={styles.root}>
          <div className={styles.header}>
            <Toast.Title className={styles.title}>Title</Toast.Title>
            <Toast.Close className={styles.close}>×</Toast.Close>
          </div>
          <Toast.Description className={styles.description}>
            Uncontrolled foreground closed
          </Toast.Description>
          <Toast.Action altText="alternative" className={styles.button} style={{ marginTop: 10 }}>
            Action
          </Toast.Action>
        </Toast.Root>
        <Toast.Viewport className={styles.chromaticViewport}></Toast.Viewport>
      </Toast.Provider>

      <h1>Controlled</h1>

      <h2>Open</h2>
      <Toast.Provider>
        <Toast.Root open duration={Infinity} className={styles.root}>
          <div className={styles.header}>
            <Toast.Title className={styles.title}>Toast</Toast.Title>
            <Toast.Close className={styles.close}>×</Toast.Close>
          </div>
          <Toast.Description className={styles.description}>Description</Toast.Description>
          <Toast.Action altText="alternative" className={styles.button} style={{ marginTop: 10 }}>
            Action
          </Toast.Action>
        </Toast.Root>
        <Toast.Viewport className={styles.chromaticViewport}></Toast.Viewport>
      </Toast.Provider>

      <h2>Closed</h2>
      <Toast.Provider>
        <Toast.Root open={false} duration={Infinity} className={styles.root}>
          <div className={styles.header}>
            <Toast.Title className={styles.title}>Toast</Toast.Title>
            <Toast.Close className={styles.close}>×</Toast.Close>
          </div>
          <Toast.Description className={styles.description}>Description</Toast.Description>
          <Toast.Action altText="alternative" className={styles.button} style={{ marginTop: 10 }}>
            Action
          </Toast.Action>
        </Toast.Root>
        <Toast.Viewport className={styles.chromaticViewport}></Toast.Viewport>
      </Toast.Provider>

      <h1>Dismissed</h1>
      <h2>Uncontrolled</h2>
      <Toast.Provider>
        <Toast.Root duration={SNAPSHOT_DELAY - 100} className={styles.root}>
          <div className={styles.header}>
            <Toast.Title className={styles.title}>Toast</Toast.Title>
            <Toast.Close className={styles.close}>×</Toast.Close>
          </div>
          <Toast.Description className={styles.description}>Description</Toast.Description>
          <Toast.Action altText="alternative" className={styles.button} style={{ marginTop: 10 }}>
            Action
          </Toast.Action>
        </Toast.Root>
        <Toast.Viewport className={styles.chromaticViewport}></Toast.Viewport>
      </Toast.Provider>

      <h2>Controlled</h2>
      <Toast.Provider>
        <Toast.Root
          duration={SNAPSHOT_DELAY - 100}
          open={open}
          onOpenChange={setOpen}
          className={styles.root}
        >
          <div className={styles.header}>
            <Toast.Title className={styles.title}>Toast</Toast.Title>
            <Toast.Close className={styles.close}>×</Toast.Close>
          </div>
          <Toast.Description className={styles.description}>Description</Toast.Description>
          <Toast.Action altText="alternative" className={styles.button} style={{ marginTop: 10 }}>
            Action
          </Toast.Action>
        </Toast.Root>
        <Toast.Viewport className={styles.chromaticViewport}></Toast.Viewport>
      </Toast.Provider>

      <h1>Provider</h1>
      <h2>Duration</h2>
      <Toast.Provider duration={SNAPSHOT_DELAY - 100}>
        <Toast.Root className={styles.root}>
          <div className={styles.header}>
            <Toast.Title className={styles.title}>Toast</Toast.Title>
            <Toast.Close className={styles.close}>×</Toast.Close>
          </div>
          <Toast.Description className={styles.description}>Description</Toast.Description>
          <Toast.Action altText="alternative" className={styles.button} style={{ marginTop: 10 }}>
            Action
          </Toast.Action>
        </Toast.Root>
        <Toast.Viewport className={styles.chromaticViewport}></Toast.Viewport>
      </Toast.Provider>

      <h2>Duration overridden</h2>
      <Toast.Provider duration={Infinity}>
        <Toast.Root duration={SNAPSHOT_DELAY - 100} className={styles.root}>
          <div className={styles.header}>
            <Toast.Title className={styles.title}>Toast</Toast.Title>
            <Toast.Close className={styles.close}>×</Toast.Close>
          </div>
          <Toast.Description className={styles.description}>Description</Toast.Description>
          <Toast.Action altText="alternative" className={styles.button} style={{ marginTop: 10 }}>
            Action
          </Toast.Action>
        </Toast.Root>
        <Toast.Viewport className={styles.chromaticViewport}></Toast.Viewport>
      </Toast.Provider>
    </>
  );
};
Chromatic.parameters = { chromatic: { disable: false, delay: SNAPSHOT_DELAY } };

/* -----------------------------------------------------------------------------------------------*/

const ToastUpgradeAvailable = (props: React.ComponentProps<typeof Toast.Root>) => (
  <Toast.Root className={styles.root} {...props}>
    <div className={styles.header}>
      <Toast.Title className={styles.title}>Upgrade available</Toast.Title>
      <Toast.Close className={styles.close} aria-label="Close">
        <span aria-hidden>×</span>
      </Toast.Close>
    </div>
    <Toast.Description className={styles.description}>
      We've just released Radix version 3.0
    </Toast.Description>
    <Toast.Action
      altText="Goto account settings to upgrade"
      className={styles.button}
      style={{ marginTop: 10 }}
    >
      Upgrade
    </Toast.Action>
  </Toast.Root>
);

const ToastSubscribeSuccess = (props: React.ComponentProps<typeof Toast.Root>) => (
  <Toast.Root className={styles.root} {...props}>
    <div className={[styles.header, styles.successHeader].join(' ')}>
      <Toast.Title className={styles.title}>Success!</Toast.Title>
      <Toast.Close className={styles.close} aria-label="Close">
        <span aria-hidden>×</span>
      </Toast.Close>
    </div>
    <Toast.Description className={styles.description}>
      You have subscribed. We'll be in touch.
    </Toast.Description>
  </Toast.Root>
);

const ToastWithProgress = (props: React.ComponentProps<typeof Toast.Root>) => {
  const [paused, setPaused] = React.useState(false);
  const duration = 3000;

  return (
    <Toast.Root
      className={styles.root}
      duration={duration}
      onPause={() => setPaused(true)}
      onResume={() => setPaused(false)}
      {...props}
    >
      <Toast.Description>Successfully saved</Toast.Description>
      <div className={styles.progressBar}>
        <div
          className={styles.progressBarInner}
          style={{
            animationDuration: duration - 100 + 'ms',
            animationPlayState: paused ? 'paused' : 'running',
          }}
        />
      </div>
    </Toast.Root>
  );
};



================================================
FILE: apps/storybook/stories/toggle-group.stories.module.css
================================================
.root {
  display: inline-flex;
  gap: 5px;
  padding: 5px;
  &[data-orientation='vertical'] {
    flex-direction: 'column';
  }
}

.item {
  border: 1px solid var(--color-black);
  border-radius: 6px;
  padding: 5px 10px;
  font-size: 13px;
  background-color: var(--color-white);
  color: var(--color-black);

  &:focus {
    outline: none;
    box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.5);
  }

  &:disabled {
    opacity: 0.5;
  }

  &[data-state='on'] {
    background-color: var(--color-black);
    color: var(--color-white);
  }
}

.itemAttr {
  background-color: rgba(0, 0, 255, 0.3);
  border: 2px solid blue;
  padding: 10px;

  &[data-state='off'] {
    border-color: red;
  }
  &[data-state='on'] {
    border-color: green;
  }
  &[data-disabled] {
    border-style: dashed;
  }
  &:disabled {
    opacity: 0.5;
  }
}



================================================
FILE: apps/storybook/stories/toggle-group.stories.tsx
================================================
import * as React from 'react';
import { Direction, ToggleGroup } from 'radix-ui';
import styles from './toggle-group.stories.module.css';

export default {
  title: 'Components/ToggleGroup',
};

export const Single = () => {
  const [value, setValue] = React.useState<string>();
  return (
    <>
      <h1>Uncontrolled</h1>
      <ToggleGroup.Root type="single" className={styles.root} aria-label="Options" defaultValue="1">
        <ToggleGroup.Item value="1" className={styles.item}>
          Option 1
        </ToggleGroup.Item>
        <ToggleGroup.Item value="2" className={styles.item}>
          Option 2
        </ToggleGroup.Item>
        <ToggleGroup.Item value="3" className={styles.item}>
          Option 3
        </ToggleGroup.Item>
      </ToggleGroup.Root>

      <h1>Controlled</h1>
      <ToggleGroup.Root
        type="single"
        className={styles.root}
        aria-label="Options"
        value={value}
        onValueChange={setValue}
      >
        <ToggleGroup.Item value="1" className={styles.item}>
          Option 1
        </ToggleGroup.Item>
        <ToggleGroup.Item value="2" className={styles.item}>
          Option 2
        </ToggleGroup.Item>
        <ToggleGroup.Item value="3" className={styles.item}>
          Option 3
        </ToggleGroup.Item>
      </ToggleGroup.Root>
    </>
  );
};

export const Vertical = () => {
  return (
    <ToggleGroup.Root
      type="single"
      orientation="vertical"
      className={styles.root}
      aria-label="Options"
      defaultValue="1"
    >
      <ToggleGroup.Item value="1" className={styles.item}>
        Option 1
      </ToggleGroup.Item>
      <ToggleGroup.Item value="2" className={styles.item}>
        Option 2
      </ToggleGroup.Item>
      <ToggleGroup.Item value="3" className={styles.item}>
        Option 3
      </ToggleGroup.Item>
    </ToggleGroup.Root>
  );
};

export const Multiple = () => {
  const [value, setValue] = React.useState<string[]>([]);
  return (
    <>
      <h1>Uncontrolled</h1>
      <ToggleGroup.Root
        type="multiple"
        className={styles.root}
        aria-label="Options"
        defaultValue={['1']}
      >
        <ToggleGroup.Item value="1" className={styles.item}>
          Option 1
        </ToggleGroup.Item>
        <ToggleGroup.Item value="2" className={styles.item}>
          Option 2
        </ToggleGroup.Item>
        <ToggleGroup.Item value="3" className={styles.item}>
          Option 3
        </ToggleGroup.Item>
      </ToggleGroup.Root>

      <h1>Controlled</h1>
      <ToggleGroup.Root
        type="multiple"
        className={styles.root}
        aria-label="Options"
        value={value}
        onValueChange={setValue}
      >
        <ToggleGroup.Item value="1" className={styles.item}>
          Option 1
        </ToggleGroup.Item>
        <ToggleGroup.Item value="2" className={styles.item}>
          Option 2
        </ToggleGroup.Item>
        <ToggleGroup.Item value="3" className={styles.item}>
          Option 3
        </ToggleGroup.Item>
      </ToggleGroup.Root>
    </>
  );
};

export const Chromatic = () => (
  <>
    <h1>Single</h1>
    <h2>Off</h2>
    <ToggleGroup.Root type="single" className={styles.root}>
      <ToggleGroup.Item value="1" className={styles.item}>
        Option 1
      </ToggleGroup.Item>
      <ToggleGroup.Item value="2" className={styles.item}>
        Option 2
      </ToggleGroup.Item>
      <ToggleGroup.Item value="3" className={styles.item} disabled>
        Option 3
      </ToggleGroup.Item>
    </ToggleGroup.Root>

    <h2>On</h2>
    <ToggleGroup.Root type="single" className={styles.root} defaultValue="1">
      <ToggleGroup.Item value="1" className={styles.item}>
        Option 1
      </ToggleGroup.Item>
      <ToggleGroup.Item value="2" className={styles.item}>
        Option 2
      </ToggleGroup.Item>
      <ToggleGroup.Item value="3" className={styles.item} disabled>
        Option 3
      </ToggleGroup.Item>
    </ToggleGroup.Root>

    <h2>Disabled</h2>
    <ToggleGroup.Root type="single" className={styles.root} disabled>
      <ToggleGroup.Item value="1" className={styles.item}>
        Option 1
      </ToggleGroup.Item>
      <ToggleGroup.Item value="2" className={styles.item}>
        Option 2
      </ToggleGroup.Item>
      <ToggleGroup.Item value="3" className={styles.item}>
        Option 3
      </ToggleGroup.Item>
    </ToggleGroup.Root>

    <h1>Multiple</h1>
    <h2>Off</h2>
    <ToggleGroup.Root type="multiple" className={styles.root}>
      <ToggleGroup.Item value="1" className={styles.item}>
        Option 1
      </ToggleGroup.Item>
      <ToggleGroup.Item value="2" className={styles.item}>
        Option 2
      </ToggleGroup.Item>
      <ToggleGroup.Item value="3" className={styles.item} disabled>
        Option 3
      </ToggleGroup.Item>
    </ToggleGroup.Root>

    <h2>One on</h2>
    <ToggleGroup.Root type="multiple" className={styles.root} defaultValue={['1']}>
      <ToggleGroup.Item value="1" className={styles.item}>
        Option 1
      </ToggleGroup.Item>
      <ToggleGroup.Item value="2" className={styles.item}>
        Option 2
      </ToggleGroup.Item>
      <ToggleGroup.Item value="3" className={styles.item} disabled>
        Option 3
      </ToggleGroup.Item>
    </ToggleGroup.Root>

    <h2>One and two on</h2>
    <ToggleGroup.Root type="multiple" className={styles.root} defaultValue={['1', '2']}>
      <ToggleGroup.Item value="1" className={styles.item}>
        Option 1
      </ToggleGroup.Item>
      <ToggleGroup.Item value="2" className={styles.item}>
        Option 2
      </ToggleGroup.Item>
      <ToggleGroup.Item value="3" className={styles.item}>
        Option 3
      </ToggleGroup.Item>
    </ToggleGroup.Root>

    <h2>Disabled</h2>
    <ToggleGroup.Root type="multiple" className={styles.root} disabled>
      <ToggleGroup.Item value="1" className={styles.item}>
        Option 1
      </ToggleGroup.Item>
      <ToggleGroup.Item value="2" className={styles.item}>
        Option 2
      </ToggleGroup.Item>
      <ToggleGroup.Item value="3" className={styles.item}>
        Option 3
      </ToggleGroup.Item>
    </ToggleGroup.Root>

    <h1>Direction</h1>
    <h2>Prop</h2>
    <ToggleGroup.Root type="single" className={styles.root} defaultValue="1" dir="rtl">
      <ToggleGroup.Item value="1" className={styles.item}>
        Option 1
      </ToggleGroup.Item>
      <ToggleGroup.Item value="2" className={styles.item}>
        Option 2
      </ToggleGroup.Item>
      <ToggleGroup.Item value="3" className={styles.item} disabled>
        Option 3
      </ToggleGroup.Item>
    </ToggleGroup.Root>

    <h2>Inherited</h2>
    <Direction.Provider dir="rtl">
      <ToggleGroup.Root type="single" className={styles.root} defaultValue="1">
        <ToggleGroup.Item value="1" className={styles.item}>
          Option 1
        </ToggleGroup.Item>
        <ToggleGroup.Item value="2" className={styles.item}>
          Option 2
        </ToggleGroup.Item>
        <ToggleGroup.Item value="3" className={styles.item} disabled>
          Option 3
        </ToggleGroup.Item>
      </ToggleGroup.Root>
    </Direction.Provider>

    <h1>State attributes</h1>
    <h2>Group disabled</h2>
    <ToggleGroup.Root type="multiple" className={styles.root} defaultValue={['1', '2']} disabled>
      <ToggleGroup.Item value="1" className={styles.itemAttr}>
        Option 1
      </ToggleGroup.Item>
      <ToggleGroup.Item value="2" className={styles.itemAttr}>
        Option 2
      </ToggleGroup.Item>
      <ToggleGroup.Item value="3" className={styles.itemAttr}>
        Option 3
      </ToggleGroup.Item>
      <ToggleGroup.Item value="4" className={styles.itemAttr}>
        Option 4
      </ToggleGroup.Item>
    </ToggleGroup.Root>

    <h2>Group enabled with button override</h2>
    <ToggleGroup.Root
      type="multiple"
      className={styles.root}
      defaultValue={['1', '2']}
      disabled={false}
    >
      <ToggleGroup.Item value="1" className={styles.itemAttr}>
        Option 1
      </ToggleGroup.Item>
      <ToggleGroup.Item value="2" className={styles.itemAttr} disabled>
        Option 2
      </ToggleGroup.Item>
      <ToggleGroup.Item value="3" className={styles.itemAttr}>
        Option 3
      </ToggleGroup.Item>
      <ToggleGroup.Item value="4" className={styles.itemAttr} disabled>
        Option 4
      </ToggleGroup.Item>
    </ToggleGroup.Root>

    <h2>Group disabled with button override</h2>
    <ToggleGroup.Root
      type="multiple"
      className={styles.root}
      defaultValue={['1', '2']}
      disabled={true}
    >
      <ToggleGroup.Item value="1" className={styles.itemAttr}>
        Option 1
      </ToggleGroup.Item>
      <ToggleGroup.Item value="2" className={styles.itemAttr} disabled={false}>
        Option 2
      </ToggleGroup.Item>
      <ToggleGroup.Item value="3" className={styles.itemAttr}>
        Option 3
      </ToggleGroup.Item>
      <ToggleGroup.Item value="4" className={styles.itemAttr} disabled={false}>
        Option 4
      </ToggleGroup.Item>
    </ToggleGroup.Root>
  </>
);
Chromatic.parameters = { chromatic: { disable: false } };



================================================
FILE: apps/storybook/stories/toggle.stories.module.css
================================================
.root {
  padding: 6px;
  line-height: 1;
  border: none;
  font-family: sans-serif;
  font-weight: bold;

  &:focus {
    outline: none;
    box-shadow: 0 0 0 2px var(--color-black);
  }

  &[data-disabled] {
    opacity: 0.5;
  }

  &[data-state='off'] {
    background-color: var(--color-red);
    color: var(--color-white);
  }

  &[data-state='on'] {
    background-color: var(--color-green);
    color: var(--color-white);
  }
}

.rootAttr {
  background-color: rgba(0, 0, 255, 0.3);
  border: 2px solid blue;
  padding: 10px;

  &:disabled {
    opacity: 0.5;
  }
  &[data-disabled] {
    border-style: dashed;
  }
}



================================================
FILE: apps/storybook/stories/toggle.stories.tsx
================================================
import * as React from 'react';
import { Toggle } from 'radix-ui';
import styles from './toggle.stories.module.css';

export default { title: 'Components/Toggle' };

export const Styled = () => <Toggle.Root className={styles.root}>Toggle</Toggle.Root>;

export const Controlled = () => {
  const [pressed, setPressed] = React.useState(true);

  return (
    <Toggle.Root className={styles.root} pressed={pressed} onPressedChange={setPressed}>
      {pressed ? 'On' : 'Off'}
    </Toggle.Root>
  );
};

export const Chromatic = () => (
  <>
    <h1>Uncontrolled</h1>
    <h2>Off</h2>
    <Toggle.Root className={styles.root}>Toggle</Toggle.Root>

    <h2>On</h2>
    <Toggle.Root className={styles.root} defaultPressed>
      Toggle
    </Toggle.Root>

    <h1>Controlled</h1>
    <h2>Off</h2>
    <Toggle.Root className={styles.root} pressed={false}>
      Toggle
    </Toggle.Root>

    <h2>On</h2>
    <Toggle.Root className={styles.root} pressed>
      Toggle
    </Toggle.Root>

    <h1>Disabled</h1>
    <Toggle.Root className={styles.root} disabled>
      Toggle
    </Toggle.Root>

    <h1>State attributes</h1>
    <Toggle.Root className={styles.rootAttr}>Toggle</Toggle.Root>
    <Toggle.Root className={styles.rootAttr} disabled>
      Toggle
    </Toggle.Root>
  </>
);
Chromatic.parameters = { chromatic: { disable: false } };



================================================
FILE: apps/storybook/stories/toolbar.stories.module.css
================================================
.toolbar {
  /* ensures things are layed out correctly by default */
  display: flex;
  &[data-orientation='vertical'] {
    flex-direction: column;
  }
  /* --------- */
  display: inline-flex;
  gap: 5px;
  box-sizing: border-box;
  min-width: 130px;
  background-color: var(--color-white);
  border: 1px solid var(--color-gray100);
  border-radius: 6px;
  padding: 5px;
  box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.1);
  font-family: apple-system, BlinkMacSystemFont, helvetica, arial, sans-serif;
  font-size: 13px;

  &:focus-within {
    bordercolor: var(--color-black);
  }
}

.toolbarSeparator {
  height: 1px;
  margin: 5px;
  background-color: var(--color-gray100);

  &[data-orientation='vertical'] {
    width: 1px;
    height: auto;
  }
}

.toolbarItem {
  border: 1px solid var(--color-black);
  border-radius: 6px;
  background-color: transparent;
  padding: 5px 10px;
  font-family: apple-system, BlinkMacSystemFont, helvetica, arial, sans-serif;
  font-size: 13px;
  display: flex;
  align-items: center;

  &:focus,
  &:focus-within {
    outline: none;
    box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.5);
  }

  &[data-disabled] {
    opacity: 0.5;
    user-select: none;
  }
}

.toolbarLink {
  display: inline-flex;
  justify-content: center;
  align-items: center;
  color: black;
}

.toolbarToggleButton {
  &[data-state='on'] {
    background: black;
    color: white;
  }
}

.toolbarToggleGroup {
  display: flex;
  gap: 5;
  &[data-orientation='vertical'] {
    flex-direction: column;
  }
}

.toolbarToggleItem {
  &[data-state='on'] {
    background: black;
    color: white;
  }
}

/* ----------- */

.dropdownMenuContent {
  display: inline-block;
  box-sizing: border-box;
  min-width: 130px;
  background-color: var(--color-white);
  border: 1px solid var(--color-gray100);
  border-radius: 6px;
  padding: 5px;
  box-shadow: 0 5px 10px 0 rgba(0, 0, 0, 0.1);
  font-family: apple-system, BlinkMacSystemFont, helvetica, arial, sans-serif;
  font-size: 13px;
  &:focus-within {
    border-color: var(--color-black);
  }
}

.label,
.dropdownMenuItem {
  display: flex;
  align-items: center;
  justify-content: space-between;
  line-height: 1;
  cursor: default;
  user-select: none;
  white-space: nowrap;
  height: 25px;
  padding: 0 10px;
  color: var(--color-black);
  border-radius: 3px;
}

.label {
  color: var(--color-gray100);
}

.dropdownMenuItem {
  outline: none;

  &[data-highlighted] {
    background-color: var(--color-black);
    color: var(--color-white);
  }

  &[data-disabled] {
    color: var(--color-gray100);
  }
}

@keyframes menu-animateIn {
  from {
    transform: scale(0.95);
    opacity: 0;
  }
  to {
    transform: scale(1);
    opacity: 1;
  }
}

@keyframes menu-animateOut {
  from {
    transform: scale(1);
    opacity: 1;
  }
  to {
    transform: scale(0.95);
    opacity: 0;
  }
}

.animatedContent {
  &[data-state='open'] {
    animation: menu-animateIn 300ms ease;
  }
  &[data-state='closed'] {
    animation: menu-animateOut 300ms ease;
  }
}

.animatedItemIndicator {
  &[data-state='checked'] {
    animation: menu-animateIn 300ms ease;
  }
  &[data-state='unchecked'] {
    animation: menu-animateOut 300ms ease;
  }
}



================================================
FILE: apps/storybook/stories/toolbar.stories.tsx
================================================
import { Direction, DropdownMenu, Toggle, Toolbar } from 'radix-ui';
import styles from './toolbar.stories.module.css';

export default { title: 'Components/Toolbar' };

export const Styled = () => (
  <>
    <ToolbarExample title="Horizontal"></ToolbarExample>
    <ToolbarExample title="Vertical" orientation="vertical"></ToolbarExample>
  </>
);

export const Chromatic = () => (
  <div style={{ padding: 50 }}>
    <h1>Example</h1>
    <ToolbarExample />
    <ToolbarExample orientation="vertical" />

    <h1>Direction</h1>
    <h2>Prop</h2>
    <ToolbarExample dir="rtl" />

    <h2>Inherited</h2>
    <Direction.Provider dir="rtl">
      <ToolbarExample />
    </Direction.Provider>
  </div>
);
Chromatic.parameters = { chromatic: { disable: false } };

const ToolbarExample = ({ title, dir, orientation }: any) => {
  const toggleItemClass = [styles.toolbarItem, styles.toolbarToggleItem].join(' ');
  return (
    <div style={{ padding: 1, margin: -1 }}>
      <h1>{title}</h1>
      <Toolbar.Root
        className={styles.toolbar}
        orientation={orientation}
        loop={true}
        aria-label={`${title} toolbar`}
        dir={dir}
      >
        <Toolbar.Button className={styles.toolbarItem}>Button</Toolbar.Button>
        <Toolbar.Button className={styles.toolbarItem} disabled>
          Button (disabled)
        </Toolbar.Button>
        <Toolbar.Separator className={styles.toolbarSeparator}></Toolbar.Separator>
        <Toolbar.Link
          className={[styles.toolbarItem, styles.toolbarLink].join(' ')}
          href="https://www.w3.org/TR/2019/WD-wai-aria-practices-1.2-20191218/examples/toolbar/toolbar.html"
          target="_blank"
        >
          Link
        </Toolbar.Link>
        <Toolbar.Separator className={styles.toolbarSeparator}></Toolbar.Separator>
        <Toolbar.Button
          className={[styles.toolbarItem, styles.toolbarToggleButton].join(' ')}
          asChild
        >
          <Toggle.Root>Toggle</Toggle.Root>
        </Toolbar.Button>
        <Toolbar.Separator className={styles.toolbarSeparator}></Toolbar.Separator>
        <Toolbar.ToggleGroup type="single" className={styles.toolbarToggleGroup}>
          <Toolbar.ToggleItem value="left" className={toggleItemClass}>
            Left
          </Toolbar.ToggleItem>
          <Toolbar.ToggleItem value="center" className={toggleItemClass}>
            Center
          </Toolbar.ToggleItem>
          <Toolbar.ToggleItem value="right" className={toggleItemClass}>
            Right
          </Toolbar.ToggleItem>
        </Toolbar.ToggleGroup>
        <Toolbar.Separator className={styles.toolbarSeparator}></Toolbar.Separator>
        <DropdownMenu.Root>
          <Toolbar.Button className={styles.toolbarItem} asChild>
            <DropdownMenu.Trigger>Menu</DropdownMenu.Trigger>
          </Toolbar.Button>
          <DropdownMenu.Content className={styles.dropdownMenuContent} sideOffset={5}>
            <DropdownMenu.Item className={styles.dropdownMenuItem}>Undo</DropdownMenu.Item>
            <DropdownMenu.Item className={styles.dropdownMenuItem}>Redo</DropdownMenu.Item>
            <DropdownMenu.Arrow />
          </DropdownMenu.Content>
        </DropdownMenu.Root>
      </Toolbar.Root>
    </div>
  );
};



================================================
FILE: apps/storybook/stories/tooltip.stories.module.css
================================================
.positionButton {
  margin: 5px;
  border: 1px solid black;
  background: transparent;
}

.trigger {
}

.content {
  transform-origin: var(--radix-tooltip-content-transform-origin);
  /* ensures content isn't selectable */
  /* this is a detterent to people putting interactive content inside a `Tooltip.Root` */
  user-select: none;
  /* ---- */
  background-color: var(--color-black);
  color: var(--color-white);
  font-size: 12px;
  border-radius: 5px;
  padding: 10px;
  max-width: 300px;
}

.arrow {
  fill: black;
}

.animatedContent {
  &[data-state='delayed-open'] {
    animation: tooltip-scaleIn 0.6s cubic-bezier(0.16, 1, 0.3, 1);
  }
  &[data-state='instant-open'] {
    animation: tooltip-fadeIn 0.2s ease-out;
  }
  &[data-state='closed'] {
    animation: tooltip-fadeOut 0.2s ease-out;
  }
}

.grid {
  display: inline-grid;
  grid-template-columns: repeat(3, 50px);
  column-gap: 150px;
  row-gap: 100px;
  padding: 100px;
  border: 1px solid black;
}

.chromaticTrigger {
  width: 30px;
  height: 30px;
  background-color: tomato;
  border: 1px solid rgb(0 0 0 / 0.3);
}

.chromaticContent {
  display: grid;
  place-content: center;
  width: 60px;
  height: 60px;
  background-color: royalblue;
  color: white;
  font-size: 10px;
  border: 1px solid rgb(0 0 0 / 0.3);
}

.chromaticArrow {
  fill: black;
}

@keyframes tooltip-scaleIn {
  0% {
    opacity: 0;
    transform: scale(0);
  }
  100% {
    opacity: 1;
    transform: scale(1);
  }
}

@keyframes tooltip-fadeIn {
  0% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}

@keyframes tooltip-fadeOut {
  0% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}



================================================
FILE: apps/storybook/stories/tooltip.stories.tsx
================================================
import * as React from 'react';
import { Popper } from 'radix-ui/internal';
import { Dialog, Tooltip } from 'radix-ui';
import styles from './tooltip.stories.module.css';

const { SIDE_OPTIONS, ALIGN_OPTIONS } = Popper;

export default { title: 'Components/Tooltip' };

export const Styled = () => (
  <Tooltip.Provider>
    <Tooltip.Root>
      <Tooltip.Trigger className={styles.trigger}>Hover or Focus me</Tooltip.Trigger>
      <Tooltip.Portal>
        <Tooltip.Content className={styles.content} sideOffset={5}>
          Nicely done!
          <Tooltip.Arrow className={styles.arrow} offset={10} />
        </Tooltip.Content>
      </Tooltip.Portal>
    </Tooltip.Root>
  </Tooltip.Provider>
);

export const Controlled = () => {
  const [open, setOpen] = React.useState(true);
  return (
    <Tooltip.Provider>
      <Tooltip.Root open={open} onOpenChange={setOpen}>
        <Tooltip.Trigger style={{ margin: 100 }}>
          I'm controlled, look I'm {open ? 'open' : 'closed'}
        </Tooltip.Trigger>
        <Tooltip.Portal>
          <Tooltip.Content className={styles.content} sideOffset={5}>
            Nicely done!
            <Tooltip.Arrow className={styles.arrow} offset={10} />
          </Tooltip.Content>
        </Tooltip.Portal>
      </Tooltip.Root>
    </Tooltip.Provider>
  );
};

export const CustomDurations = () => (
  <Tooltip.Provider>
    <h1>Delay duration</h1>
    <h2>Default (700ms)</h2>

    <div style={{ display: 'flex', gap: 50 }}>
      <Tooltip.Root>
        <Tooltip.Trigger className={styles.trigger}>Hover me</Tooltip.Trigger>
        <Tooltip.Portal>
          <Tooltip.Content className={styles.content} sideOffset={5}>
            Nicely done!
            <Tooltip.Arrow className={styles.arrow} offset={10} />
          </Tooltip.Content>
        </Tooltip.Portal>
      </Tooltip.Root>
      <Tooltip.Root>
        <Tooltip.Trigger className={styles.trigger}>Hover me</Tooltip.Trigger>
        <Tooltip.Portal>
          <Tooltip.Content className={styles.content} sideOffset={5}>
            Nicely done!
            <Tooltip.Arrow className={styles.arrow} offset={10} />
          </Tooltip.Content>
        </Tooltip.Portal>
      </Tooltip.Root>
      <Tooltip.Root>
        <Tooltip.Trigger className={styles.trigger}>Hover me</Tooltip.Trigger>
        <Tooltip.Portal>
          <Tooltip.Content className={styles.content} sideOffset={5}>
            Nicely done!
            <Tooltip.Arrow className={styles.arrow} offset={10} />
          </Tooltip.Content>
        </Tooltip.Portal>
      </Tooltip.Root>
    </div>

    <h2>Custom (0ms = instant open)</h2>
    <div style={{ display: 'flex', gap: 50 }}>
      <Tooltip.Provider delayDuration={0}>
        <Tooltip.Root>
          <Tooltip.Trigger className={styles.trigger}>Hover me</Tooltip.Trigger>
          <Tooltip.Portal>
            <Tooltip.Content className={styles.content} sideOffset={5}>
              Nicely done!
              <Tooltip.Arrow className={styles.arrow} offset={10} />
            </Tooltip.Content>
          </Tooltip.Portal>
        </Tooltip.Root>
        <Tooltip.Root>
          <Tooltip.Trigger className={styles.trigger}>Hover me</Tooltip.Trigger>
          <Tooltip.Portal>
            <Tooltip.Content className={styles.content} sideOffset={5}>
              Nicely done!
              <Tooltip.Arrow className={styles.arrow} offset={10} />
            </Tooltip.Content>
          </Tooltip.Portal>
        </Tooltip.Root>
        <Tooltip.Root>
          <Tooltip.Trigger className={styles.trigger}>Hover me</Tooltip.Trigger>
          <Tooltip.Portal>
            <Tooltip.Content className={styles.content} sideOffset={5}>
              Nicely done!
              <Tooltip.Arrow className={styles.arrow} offset={10} />
            </Tooltip.Content>
          </Tooltip.Portal>
        </Tooltip.Root>
      </Tooltip.Provider>
    </div>

    <h2>Custom (2s)</h2>
    <div style={{ display: 'flex', gap: 50 }}>
      <Tooltip.Provider delayDuration={2000}>
        <Tooltip.Root>
          <Tooltip.Trigger className={styles.trigger}>Hover me</Tooltip.Trigger>
          <Tooltip.Portal>
            <Tooltip.Content className={styles.content} sideOffset={5}>
              Nicely done!
              <Tooltip.Arrow className={styles.arrow} offset={10} />
            </Tooltip.Content>
          </Tooltip.Portal>
        </Tooltip.Root>
        <Tooltip.Root>
          <Tooltip.Trigger className={styles.trigger}>Hover me</Tooltip.Trigger>
          <Tooltip.Portal>
            <Tooltip.Content className={styles.content} sideOffset={5}>
              Nicely done!
              <Tooltip.Arrow className={styles.arrow} offset={10} />
            </Tooltip.Content>
          </Tooltip.Portal>
        </Tooltip.Root>
        <Tooltip.Root>
          <Tooltip.Trigger className={styles.trigger}>Hover me</Tooltip.Trigger>
          <Tooltip.Portal>
            <Tooltip.Content className={styles.content} sideOffset={5}>
              Nicely done!
              <Tooltip.Arrow className={styles.arrow} offset={10} />
            </Tooltip.Content>
          </Tooltip.Portal>
        </Tooltip.Root>
      </Tooltip.Provider>
    </div>

    <h1>Skip delay duration</h1>
    <h2>Default (300ms to move from one to another tooltip)</h2>
    <div style={{ display: 'flex', gap: 50 }}>
      <Tooltip.Root>
        <Tooltip.Trigger className={styles.trigger}>Hover me</Tooltip.Trigger>
        <Tooltip.Portal>
          <Tooltip.Content className={styles.content} sideOffset={5}>
            Nicely done!
            <Tooltip.Arrow className={styles.arrow} offset={10} />
          </Tooltip.Content>
        </Tooltip.Portal>
      </Tooltip.Root>
      <Tooltip.Root>
        <Tooltip.Trigger className={styles.trigger}>Hover me</Tooltip.Trigger>
        <Tooltip.Portal>
          <Tooltip.Content className={styles.content} sideOffset={5}>
            Nicely done!
            <Tooltip.Arrow className={styles.arrow} offset={10} />
          </Tooltip.Content>
        </Tooltip.Portal>
      </Tooltip.Root>
      <Tooltip.Root>
        <Tooltip.Trigger className={styles.trigger}>Hover me</Tooltip.Trigger>
        <Tooltip.Portal>
          <Tooltip.Content className={styles.content} sideOffset={5}>
            Nicely done!
            <Tooltip.Arrow className={styles.arrow} offset={10} />
          </Tooltip.Content>
        </Tooltip.Portal>
      </Tooltip.Root>
    </div>

    <h2>Custom (0ms to move from one to another tooltip = never skip)</h2>
    <div style={{ display: 'flex', gap: 50 }}>
      <Tooltip.Provider skipDelayDuration={0}>
        <Tooltip.Root>
          <Tooltip.Trigger className={styles.trigger}>Hover me</Tooltip.Trigger>
          <Tooltip.Portal>
            <Tooltip.Content className={styles.content} sideOffset={5}>
              Nicely done!
              <Tooltip.Arrow className={styles.arrow} offset={10} />
            </Tooltip.Content>
          </Tooltip.Portal>
        </Tooltip.Root>
        <Tooltip.Root>
          <Tooltip.Trigger className={styles.trigger}>Hover me</Tooltip.Trigger>
          <Tooltip.Portal>
            <Tooltip.Content className={styles.content} sideOffset={5}>
              Nicely done!
              <Tooltip.Arrow className={styles.arrow} offset={10} />
            </Tooltip.Content>
          </Tooltip.Portal>
        </Tooltip.Root>
        <Tooltip.Root>
          <Tooltip.Trigger className={styles.trigger}>Hover me</Tooltip.Trigger>
          <Tooltip.Portal>
            <Tooltip.Content className={styles.content} sideOffset={5}>
              Nicely done!
              <Tooltip.Arrow className={styles.arrow} offset={10} />
            </Tooltip.Content>
          </Tooltip.Portal>
        </Tooltip.Root>
      </Tooltip.Provider>
    </div>

    <h2>Custom (5s to move from one to another tooltip)</h2>
    <div style={{ display: 'flex', gap: 50 }}>
      <Tooltip.Provider skipDelayDuration={5000}>
        <Tooltip.Root>
          <Tooltip.Trigger className={styles.trigger}>Hover me</Tooltip.Trigger>
          <Tooltip.Portal>
            <Tooltip.Content className={styles.content} sideOffset={5}>
              Nicely done!
              <Tooltip.Arrow className={styles.arrow} offset={10} />
            </Tooltip.Content>
          </Tooltip.Portal>
        </Tooltip.Root>
        <Tooltip.Root>
          <Tooltip.Trigger className={styles.trigger}>Hover me</Tooltip.Trigger>
          <Tooltip.Portal>
            <Tooltip.Content className={styles.content} sideOffset={5}>
              Nicely done!
              <Tooltip.Arrow className={styles.arrow} offset={10} />
            </Tooltip.Content>
          </Tooltip.Portal>
        </Tooltip.Root>
        <Tooltip.Root>
          <Tooltip.Trigger className={styles.trigger}>Hover me</Tooltip.Trigger>
          <Tooltip.Portal>
            <Tooltip.Content className={styles.content} sideOffset={5}>
              Nicely done!
              <Tooltip.Arrow className={styles.arrow} offset={10} />
            </Tooltip.Content>
          </Tooltip.Portal>
        </Tooltip.Root>
      </Tooltip.Provider>
    </div>
  </Tooltip.Provider>
);

export const CustomContent = () => (
  <Tooltip.Provider>
    <div style={{ display: 'flex', gap: 20, padding: 100 }}>
      <Tooltip.Root>
        <Tooltip.Trigger>Heading</Tooltip.Trigger>
        <Tooltip.Portal>
          <Tooltip.Content className={styles.content} sideOffset={5}>
            <h1>Some heading</h1>
            <Tooltip.Arrow className={styles.arrow} offset={10} />
          </Tooltip.Content>
        </Tooltip.Portal>
      </Tooltip.Root>

      <Tooltip.Root>
        <Tooltip.Trigger>Paragraph</Tooltip.Trigger>
        <Tooltip.Portal>
          <Tooltip.Content className={styles.content} sideOffset={5}>
            <p>Some paragraph</p>
            <Tooltip.Arrow className={styles.arrow} offset={10} />
          </Tooltip.Content>
        </Tooltip.Portal>
      </Tooltip.Root>

      <Tooltip.Root>
        <Tooltip.Trigger>List</Tooltip.Trigger>
        <Tooltip.Portal>
          <Tooltip.Content className={styles.content} sideOffset={5}>
            <ul>
              <li>One</li>
              <li>Two</li>
              <li>Three</li>
            </ul>
            <Tooltip.Arrow className={styles.arrow} offset={10} />
          </Tooltip.Content>
        </Tooltip.Portal>
      </Tooltip.Root>

      <Tooltip.Root>
        <Tooltip.Trigger>Article</Tooltip.Trigger>
        <Tooltip.Portal>
          <Tooltip.Content className={styles.content} sideOffset={5}>
            <article>
              Lorem ipsum dolor sit amet consectetur, adipisicing elit. Harum, quae qui. Magnam
              delectus ex totam repellat amet distinctio unde, porro architecto voluptatibus nemo et
              nisi, voluptatem eligendi earum autem fugit.
            </article>
            <Tooltip.Arrow className={styles.arrow} offset={10} />
          </Tooltip.Content>
        </Tooltip.Portal>
      </Tooltip.Root>

      <Tooltip.Root>
        <Tooltip.Trigger>Figure</Tooltip.Trigger>
        <Tooltip.Portal>
          <Tooltip.Content className={styles.content} sideOffset={5}>
            <figure style={{ margin: 0 }}>
              <img
                src="https://pbs.twimg.com/profile_images/864164353771229187/Catw6Nmh_400x400.jpg"
                alt=""
                width={100}
              />
              <figcaption>Colm Tuite</figcaption>
            </figure>
            <Tooltip.Arrow className={styles.arrow} offset={10} />
          </Tooltip.Content>
        </Tooltip.Portal>
      </Tooltip.Root>

      <Tooltip.Root>
        <Tooltip.Trigger>Time</Tooltip.Trigger>
        <Tooltip.Portal>
          <Tooltip.Content className={styles.content} sideOffset={5}>
            {/* @ts-ignore */}
            <time datetime="2017-10-31T11:21:00+02:00">Tuesday, 31 October 2017</time>
            <Tooltip.Arrow className={styles.arrow} offset={10} />
          </Tooltip.Content>
        </Tooltip.Portal>
      </Tooltip.Root>

      <Tooltip.Root>
        <Tooltip.Trigger>Link</Tooltip.Trigger>
        <Tooltip.Portal>
          <Tooltip.Content className={styles.content} sideOffset={5}>
            View in <a href="https://workos.com">WorkOS</a>
            <Tooltip.Arrow className={styles.arrow} offset={10} />
          </Tooltip.Content>
        </Tooltip.Portal>
      </Tooltip.Root>

      <Tooltip.Root>
        <Tooltip.Trigger>Form</Tooltip.Trigger>
        <Tooltip.Portal>
          <Tooltip.Content className={styles.content} sideOffset={5}>
            <form>
              <label htmlFor="fname">First name:</label>
              <br />
              <input type="text" id="fname" name="fname" />
              <br />
              <label htmlFor="lname">Last name:</label>
              <br />
              <input type="text" id="lname" name="lname" />
            </form>
            <Tooltip.Arrow className={styles.arrow} offset={10} />
          </Tooltip.Content>
        </Tooltip.Portal>
      </Tooltip.Root>

      <Tooltip.Root>
        <Tooltip.Trigger>Mini layout</Tooltip.Trigger>
        <Tooltip.Portal>
          <Tooltip.Content className={styles.content} sideOffset={5}>
            <p
              style={{
                margin: 0,
                textAlign: 'center',
                fontFamily: 'apple-system, BlinkMacSystemFont, helvetica, arial, sans-serif',
                fontSize: 14,
              }}
            >
              Start video call
              <span style={{ display: 'block', color: '#999' }}>
                press{' '}
                <kbd
                  style={{
                    fontFamily: 'apple-system, BlinkMacSystemFont, helvetica, arial, sans-serif',
                    fontWeight: 'bold',
                    color: 'white',
                  }}
                  aria-label="c key"
                >
                  c
                </kbd>
              </span>
            </p>
            <Tooltip.Arrow className={styles.arrow} offset={10} />
          </Tooltip.Content>
        </Tooltip.Portal>
      </Tooltip.Root>
    </div>
  </Tooltip.Provider>
);

export const Positions = () => (
  <Tooltip.Provider>
    <div
      style={{
        display: 'flex',
        width: '100vw',
        height: '100vh',
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      <div
        style={{
          display: 'grid',
          gridTemplateColumns: 'repeat(5, 1fr)',
          gridTemplateRows: 'repeat(5, 50px)',
        }}
      >
        <SimpleTooltip label="Top start" side="top" align="start">
          <Tooltip.Trigger
            className={styles.positionButton}
            style={{ gridColumn: '2', gridRow: '1' }}
          >
            Top start
          </Tooltip.Trigger>
        </SimpleTooltip>
        <SimpleTooltip label="Top center" side="top" align="center">
          <Tooltip.Trigger
            className={styles.positionButton}
            style={{ gridColumn: '3', gridRow: '1' }}
          >
            Top center
          </Tooltip.Trigger>
        </SimpleTooltip>
        <SimpleTooltip label="Top end" side="top" align="end">
          <Tooltip.Trigger
            className={styles.positionButton}
            style={{ gridColumn: '4', gridRow: '1' }}
          >
            Top end
          </Tooltip.Trigger>
        </SimpleTooltip>

        <SimpleTooltip label="Right start" side="right" align="start">
          <Tooltip.Trigger
            className={styles.positionButton}
            style={{ gridColumn: '5', gridRow: '2' }}
            tabIndex={0}
          >
            Right start
          </Tooltip.Trigger>
        </SimpleTooltip>
        <SimpleTooltip label="Right center" side="right" align="center">
          <Tooltip.Trigger
            className={styles.positionButton}
            style={{ gridColumn: '5', gridRow: '3' }}
            tabIndex={0}
          >
            Right center
          </Tooltip.Trigger>
        </SimpleTooltip>
        <SimpleTooltip label="Right end" side="right" align="end">
          <Tooltip.Trigger
            className={styles.positionButton}
            style={{ gridColumn: '5', gridRow: '4' }}
            tabIndex={0}
          >
            Right end
          </Tooltip.Trigger>
        </SimpleTooltip>

        <SimpleTooltip label="Bottom end" side="bottom" align="end">
          <Tooltip.Trigger
            className={styles.positionButton}
            style={{ gridColumn: '4', gridRow: '5' }}
          >
            Bottom end
          </Tooltip.Trigger>
        </SimpleTooltip>
        <SimpleTooltip label="Bottom center" side="bottom" align="center">
          <Tooltip.Trigger
            className={styles.positionButton}
            style={{ gridColumn: '3', gridRow: '5' }}
          >
            Bottom center
          </Tooltip.Trigger>
        </SimpleTooltip>
        <SimpleTooltip label="Bottom start" side="bottom" align="start">
          <Tooltip.Trigger
            className={styles.positionButton}
            style={{ gridColumn: '2', gridRow: '5' }}
          >
            Bottom start
          </Tooltip.Trigger>
        </SimpleTooltip>

        <SimpleTooltip label="Left end" side="left" align="end">
          <Tooltip.Trigger
            className={styles.positionButton}
            style={{ gridColumn: '1', gridRow: '4' }}
          >
            Left end
          </Tooltip.Trigger>
        </SimpleTooltip>
        <SimpleTooltip label="Left center" side="left" align="center">
          <Tooltip.Trigger
            className={styles.positionButton}
            style={{ gridColumn: '1', gridRow: '3' }}
          >
            Left center
          </Tooltip.Trigger>
        </SimpleTooltip>
        <SimpleTooltip label="Left start" side="left" align="start">
          <Tooltip.Trigger
            className={styles.positionButton}
            style={{ gridColumn: '1', gridRow: '2' }}
          >
            Left start
          </Tooltip.Trigger>
        </SimpleTooltip>
      </div>
    </div>
  </Tooltip.Provider>
);

export const AriaLabel = () => (
  <Tooltip.Provider>
    <p>The first button will display AND enunciate the label.</p>
    <p>The second button will display the label, but enunciate the aria label.</p>
    <div style={{ display: 'flex' }}>
      <SimpleTooltip label="Notifications">
        <Tooltip.Trigger style={{ margin: 5 }}>
          <span aria-hidden>🔔(3)</span>
        </Tooltip.Trigger>
      </SimpleTooltip>

      <SimpleTooltip label="Notifications" aria-label="3 notifications">
        <Tooltip.Trigger style={{ margin: 5 }}>
          <span aria-hidden>🔔(3)</span>
        </Tooltip.Trigger>
      </SimpleTooltip>
    </div>
  </Tooltip.Provider>
);

export const WithText = () => (
  <Tooltip.Provider>
    <p>
      Hello this is a test with{' '}
      <SimpleTooltip label="This is a tooltip">
        <Tooltip.Trigger asChild>
          <a href="https://workos.com">Tooltip.Root</a>
        </Tooltip.Trigger>
      </SimpleTooltip>{' '}
      inside a Text Component{' '}
      <SimpleTooltip label="This is a tooltip" side="top">
        <Tooltip.Trigger asChild>
          <a href="https://workos.com">Tooltip.Root</a>
        </Tooltip.Trigger>
      </SimpleTooltip>{' '}
      some more text{' '}
      <SimpleTooltip label="This is a tooltip" side="right" align="center">
        <Tooltip.Trigger asChild>
          <a href="https://workos.com">Tooltip.Root</a>
        </Tooltip.Trigger>
      </SimpleTooltip>{' '}
    </p>
  </Tooltip.Provider>
);

export const WithExternalRef = () => {
  const buttonRef = React.useRef<HTMLButtonElement>(null);

  React.useEffect(() => {
    if (buttonRef.current) {
      buttonRef.current.style.boxShadow = '0 0 0 2px red';
    }
  });

  return (
    <Tooltip.Provider>
      <SimpleTooltip label="Save document" side="bottom" align="end">
        <Tooltip.Trigger ref={buttonRef} type="button" style={{ margin: 100 }}>
          Save
        </Tooltip.Trigger>
      </SimpleTooltip>
    </Tooltip.Provider>
  );
};

export const Unmount = () => {
  const [isMounted, setIsMounted] = React.useState(true);
  return (
    <Tooltip.Provider>
      <ul>
        <li>Focus the first button (tooltip 1 shows)</li>
        <li>Focus the second button (tooltip 2 shows)</li>
        <li>Press escape (second button unmounts)</li>
        <li>Focus the first button (tooltip 1 should still show)</li>
      </ul>
      <SimpleTooltip label="tooltip 1">
        <Tooltip.Trigger style={{ alignSelf: 'flex-start', margin: '0vmin' }}>
          Tool 1
        </Tooltip.Trigger>
      </SimpleTooltip>

      {isMounted && (
        <SimpleTooltip label="tooltip 2">
          <Tooltip.Trigger
            style={{ alignSelf: 'flex-start', margin: '0vmin' }}
            onKeyDown={(event) => event.key === 'Escape' && setIsMounted(false)}
          >
            Tool 2
          </Tooltip.Trigger>
        </SimpleTooltip>
      )}
    </Tooltip.Provider>
  );
};

export const Animated = () => {
  const contentClass = [styles.content, styles.animatedContent].join(' ');
  return (
    <Tooltip.Provider>
      <div style={{ padding: 100 }}>
        <SimpleTooltip className={contentClass} label="Hello world 1">
          <Tooltip.Trigger style={{ marginRight: 10 }}>Hello 1</Tooltip.Trigger>
        </SimpleTooltip>

        <SimpleTooltip className={contentClass} label="Hello world 2" side="top">
          <Tooltip.Trigger>Hello 2</Tooltip.Trigger>
        </SimpleTooltip>
      </div>
    </Tooltip.Provider>
  );
};

export const SlottableContent = () => (
  <Tooltip.Provider>
    <Tooltip.Root>
      <Tooltip.Trigger className={styles.trigger}>Hover or Focus me</Tooltip.Trigger>
      <Tooltip.Portal>
        <Tooltip.Content asChild sideOffset={5}>
          <div className={styles.content}>
            Nicely done!
            <Tooltip.Arrow className={styles.arrow} offset={10} />
          </div>
        </Tooltip.Content>
      </Tooltip.Portal>
    </Tooltip.Root>
  </Tooltip.Provider>
);

export const WithinDialog = () => (
  <Tooltip.Provider>
    <Dialog.Root>
      <Dialog.Trigger>Open dialog</Dialog.Trigger>
      <Dialog.Content>
        <Dialog.Title>Dialog title</Dialog.Title>
        <Dialog.Description>Dialog description</Dialog.Description>
        <Dialog.Close>Close dialog</Dialog.Close>
        <Tooltip.Root>
          <Tooltip.Trigger className={styles.trigger}>Hover or Focus me</Tooltip.Trigger>
          <Tooltip.Portal>
            <Tooltip.Content className={styles.content} sideOffset={5}>
              Nicely done!
              <Tooltip.Arrow className={styles.arrow} offset={10} />
            </Tooltip.Content>
          </Tooltip.Portal>
        </Tooltip.Root>
      </Dialog.Content>
    </Dialog.Root>
  </Tooltip.Provider>
);

export const KeepOpenOnActivation = () => {
  const triggerRef = React.useRef(null);

  return (
    <Tooltip.Provider>
      <Tooltip.Root>
        <Tooltip.Trigger
          ref={triggerRef}
          className={styles.trigger}
          onClick={(event) => event.preventDefault()}
        >
          Hover or Focus me
        </Tooltip.Trigger>
        <Tooltip.Portal>
          <Tooltip.Content
            className={styles.content}
            sideOffset={5}
            onPointerDownOutside={(event) => {
              if (event.target === triggerRef.current) event.preventDefault();
            }}
          >
            Nicely done!
            <Tooltip.Arrow className={styles.arrow} offset={10} />
          </Tooltip.Content>
        </Tooltip.Portal>
      </Tooltip.Root>
    </Tooltip.Provider>
  );
};

export const WithinScrollable = () => (
  <Tooltip.Provider>
    <div
      style={{
        position: 'absolute',
        top: 0,
        left: 0,
        height: 500,
        width: 300,
        border: '1px solid black',
        overflow: 'auto',
      }}
    >
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', height: 600 }}>
        <Tooltip.Root>
          <Tooltip.Trigger className={styles.trigger}>Hover or Focus me</Tooltip.Trigger>
          <Tooltip.Portal>
            <Tooltip.Content className={styles.content} sideOffset={5}>
              Nicely done!
              <Tooltip.Arrow className={styles.arrow} offset={10} />
            </Tooltip.Content>
          </Tooltip.Portal>
        </Tooltip.Root>
      </div>
    </div>
    <div
      style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', height: '150vh' }}
    >
      <Tooltip.Root>
        <Tooltip.Trigger className={styles.trigger}>Hover or Focus me</Tooltip.Trigger>
        <Tooltip.Portal>
          <Tooltip.Content className={styles.content} sideOffset={5}>
            Nicely done!
            <Tooltip.Arrow className={styles.arrow} offset={10} />
          </Tooltip.Content>
        </Tooltip.Portal>
      </Tooltip.Root>
    </div>
  </Tooltip.Provider>
);

export const DisableHoverableContent = () => (
  <>
    <h1>Hoverable content (Default)</h1>
    <p>Content remains open while moving pointer to it</p>
    <div style={{ display: 'flex', gap: 50 }}>
      <Tooltip.Provider skipDelayDuration={1000}>
        <Tooltip.Root>
          <Tooltip.Trigger className={styles.trigger}>Hover me</Tooltip.Trigger>
          <Tooltip.Portal>
            <Tooltip.Content className={styles.content} sideOffset={5}>
              Nicely done!
              <Tooltip.Arrow className={styles.arrow} offset={10} />
            </Tooltip.Content>
          </Tooltip.Portal>
        </Tooltip.Root>
      </Tooltip.Provider>
    </div>

    <h1>Disable hoverable content</h1>
    <p>Tooltip closes when pointer leaves the trigger</p>
    <h2>Inherited from provider</h2>
    <div style={{ display: 'flex', gap: 50 }}>
      <Tooltip.Provider delayDuration={0} disableHoverableContent>
        <Tooltip.Root>
          <Tooltip.Trigger className={styles.trigger}>Hover me</Tooltip.Trigger>
          <Tooltip.Portal>
            <Tooltip.Content className={styles.content} sideOffset={5}>
              Nicely done!
              <Tooltip.Arrow className={styles.arrow} offset={10} />
            </Tooltip.Content>
          </Tooltip.Portal>
        </Tooltip.Root>
      </Tooltip.Provider>
    </div>
    <h2>Inherited value overridden by prop on tooltip</h2>
    <div style={{ display: 'flex', gap: 50 }}>
      <Tooltip.Provider delayDuration={0} disableHoverableContent>
        <Tooltip.Root>
          <Tooltip.Trigger className={styles.trigger}>Disabled hoverable content</Tooltip.Trigger>
          <Tooltip.Portal>
            <Tooltip.Content className={styles.content} sideOffset={5}>
              Nicely done!
              <Tooltip.Arrow className={styles.arrow} offset={10} />
            </Tooltip.Content>
          </Tooltip.Portal>
        </Tooltip.Root>
        <Tooltip.Root disableHoverableContent={false}>
          <Tooltip.Trigger className={styles.trigger}>Hoverable content</Tooltip.Trigger>
          <Tooltip.Portal>
            <Tooltip.Content className={styles.content} sideOffset={5}>
              Nicely done!
              <Tooltip.Arrow className={styles.arrow} offset={10} />
            </Tooltip.Content>
          </Tooltip.Portal>
        </Tooltip.Root>
      </Tooltip.Provider>
    </div>
  </>
);

// change order slightly for more pleasing visual
const SIDES = [...SIDE_OPTIONS.filter((side) => side !== 'bottom'), 'bottom' as const];

export const Chromatic = () => (
  <Tooltip.Provider>
    <div style={{ padding: 200 }}>
      <h1>Uncontrolled</h1>
      <h2>Closed</h2>
      <Tooltip.Root>
        <Tooltip.Trigger className={styles.trigger}>open</Tooltip.Trigger>
        <Tooltip.Portal>
          <Tooltip.Content className={styles.content} sideOffset={5}>
            Some content
            <Tooltip.Arrow className={styles.arrow} offset={10} />
          </Tooltip.Content>
        </Tooltip.Portal>
      </Tooltip.Root>

      <h2 style={{ marginBottom: 60 }}>Open</h2>
      <Tooltip.Root defaultOpen>
        <Tooltip.Trigger className={styles.trigger}>open</Tooltip.Trigger>
        <Tooltip.Portal>
          <Tooltip.Content className={styles.content} sideOffset={5}>
            Some content
            <Tooltip.Arrow className={styles.arrow} offset={10} />
          </Tooltip.Content>
        </Tooltip.Portal>
      </Tooltip.Root>

      <h2 style={{ marginTop: 60, marginBottom: 60 }}>Open with reordered parts</h2>
      <Tooltip.Root defaultOpen>
        <Tooltip.Portal>
          <Tooltip.Content className={styles.content} sideOffset={5}>
            Some content
            <Tooltip.Arrow className={styles.arrow} offset={10} />
          </Tooltip.Content>
        </Tooltip.Portal>
        <Tooltip.Trigger className={styles.trigger}>open</Tooltip.Trigger>
      </Tooltip.Root>

      <h1 style={{ marginTop: 100 }}>Controlled</h1>
      <h2>Closed</h2>
      <Tooltip.Root open={false}>
        <Tooltip.Trigger className={styles.trigger}>open</Tooltip.Trigger>
        <Tooltip.Portal>
          <Tooltip.Content className={styles.content} sideOffset={5}>
            Some content
            <Tooltip.Arrow className={styles.arrow} offset={10} />
          </Tooltip.Content>
        </Tooltip.Portal>
      </Tooltip.Root>

      <h2 style={{ marginBottom: 60 }}>Open</h2>
      <Tooltip.Root open>
        <Tooltip.Trigger className={styles.trigger}>open</Tooltip.Trigger>
        <Tooltip.Portal>
          <Tooltip.Content className={styles.content} sideOffset={5}>
            Some content
            <Tooltip.Arrow className={styles.arrow} offset={10} />
          </Tooltip.Content>
        </Tooltip.Portal>
      </Tooltip.Root>

      <h2 style={{ marginTop: 60, marginBottom: 60 }}>Open with reordered parts</h2>
      <Tooltip.Root open>
        <Tooltip.Portal>
          <Tooltip.Content className={styles.content} sideOffset={5}>
            Some content
            <Tooltip.Arrow className={styles.arrow} offset={10} />
          </Tooltip.Content>
        </Tooltip.Portal>
        <Tooltip.Trigger className={styles.trigger}>open</Tooltip.Trigger>
      </Tooltip.Root>

      <h1 style={{ marginTop: 100 }}>Positioning</h1>
      <h2>No collisions</h2>
      <h3>Side & Align</h3>
      <div className={styles.grid}>
        {SIDES.map((side) =>
          ALIGN_OPTIONS.map((align) => (
            <Tooltip.Root key={`${side}-${align}`} open>
              <Tooltip.Trigger className={styles.chromaticTrigger} />
              <Tooltip.Portal>
                <Tooltip.Content
                  className={styles.chromaticContent}
                  side={side}
                  align={align}
                  avoidCollisions={false}
                >
                  <p style={{ textAlign: 'center' }}>
                    {side}
                    <br />
                    {align}
                  </p>
                  <Tooltip.Arrow className={styles.chromaticArrow} width={20} height={10} />
                </Tooltip.Content>
              </Tooltip.Portal>
            </Tooltip.Root>
          )),
        )}
      </div>

      <h3>Side offset</h3>
      <h4>Positive</h4>
      <div className={styles.grid}>
        {SIDES.map((side) =>
          ALIGN_OPTIONS.map((align) => (
            <Tooltip.Root key={`${side}-${align}`} open>
              <Tooltip.Trigger className={styles.chromaticTrigger} />
              <Tooltip.Portal>
                <Tooltip.Content
                  className={styles.chromaticContent}
                  side={side}
                  sideOffset={5}
                  align={align}
                  avoidCollisions={false}
                >
                  <p style={{ textAlign: 'center' }}>
                    {side}
                    <br />
                    {align}
                  </p>
                  <Tooltip.Arrow className={styles.chromaticArrow} width={20} height={10} />
                </Tooltip.Content>
              </Tooltip.Portal>
            </Tooltip.Root>
          )),
        )}
      </div>
      <h4>Negative</h4>
      <div className={styles.grid}>
        {SIDES.map((side) =>
          ALIGN_OPTIONS.map((align) => (
            <Tooltip.Root key={`${side}-${align}`} open>
              <Tooltip.Trigger className={styles.chromaticTrigger} />
              <Tooltip.Portal>
                <Tooltip.Content
                  className={styles.chromaticContent}
                  side={side}
                  sideOffset={-10}
                  align={align}
                  avoidCollisions={false}
                >
                  <p style={{ textAlign: 'center' }}>
                    {side}
                    <br />
                    {align}
                  </p>
                  <Tooltip.Arrow className={styles.chromaticArrow} width={20} height={10} />
                </Tooltip.Content>
              </Tooltip.Portal>
            </Tooltip.Root>
          )),
        )}
      </div>

      <h3>Align offset</h3>
      <h4>Positive</h4>
      <div className={styles.grid}>
        {SIDES.map((side) =>
          ALIGN_OPTIONS.map((align) => (
            <Tooltip.Root key={`${side}-${align}`} open>
              <Tooltip.Trigger className={styles.chromaticTrigger} />
              <Tooltip.Portal>
                <Tooltip.Content
                  className={styles.chromaticContent}
                  side={side}
                  align={align}
                  alignOffset={20}
                  avoidCollisions={false}
                >
                  <p style={{ textAlign: 'center' }}>
                    {side}
                    <br />
                    {align}
                  </p>
                  <Tooltip.Arrow className={styles.chromaticArrow} width={20} height={10} />
                </Tooltip.Content>
              </Tooltip.Portal>
            </Tooltip.Root>
          )),
        )}
      </div>
      <h4>Negative</h4>
      <div className={styles.grid}>
        {SIDES.map((side) =>
          ALIGN_OPTIONS.map((align) => (
            <Tooltip.Root key={`${side}-${align}`} open>
              <Tooltip.Trigger className={styles.chromaticTrigger} />
              <Tooltip.Portal>
                <Tooltip.Content
                  className={styles.chromaticContent}
                  side={side}
                  align={align}
                  alignOffset={-10}
                  avoidCollisions={false}
                >
                  <p style={{ textAlign: 'center' }}>
                    {side}
                    <br />
                    {align}
                  </p>
                  <Tooltip.Arrow className={styles.chromaticArrow} width={20} height={10} />
                </Tooltip.Content>
              </Tooltip.Portal>
            </Tooltip.Root>
          )),
        )}
      </div>

      <h2>Collisions</h2>
      <p>See instances on the periphery of the page.</p>
      {SIDES.map((side) =>
        ALIGN_OPTIONS.map((align) => (
          <Tooltip.Root key={`${side}-${align}`} open>
            <Tooltip.Trigger
              className={styles.chromaticTrigger}
              style={{
                position: 'absolute',
                [side]: 10,
                ...((side === 'right' || side === 'left') &&
                  (align === 'start'
                    ? { bottom: 10 }
                    : align === 'center'
                      ? { top: 'calc(50% - 15px)' }
                      : { top: 10 })),
                ...((side === 'top' || side === 'bottom') &&
                  (align === 'start'
                    ? { right: 10 }
                    : align === 'center'
                      ? { left: 'calc(50% - 15px)' }
                      : { left: 10 })),
              }}
            />
            <Tooltip.Portal>
              <Tooltip.Content className={styles.chromaticContent} side={side} align={align}>
                <p style={{ textAlign: 'center' }}>
                  {side}
                  <br />
                  {align}
                </p>
                <Tooltip.Arrow className={styles.chromaticArrow} width={20} height={10} />
              </Tooltip.Content>
            </Tooltip.Portal>
          </Tooltip.Root>
        )),
      )}

      <h2 style={{ marginTop: 50, marginBottom: 60 }}>Relative parent (non-portalled)</h2>
      <div style={{ position: 'relative' }}>
        <Tooltip.Provider>
          <Tooltip.Root open>
            <Tooltip.Trigger className={styles.trigger}>Hover or Focus me</Tooltip.Trigger>
            <Tooltip.Content className={styles.content} sideOffset={5}>
              Nicely done!
              <Tooltip.Arrow className={styles.arrow} offset={10} />
            </Tooltip.Content>
          </Tooltip.Root>
        </Tooltip.Provider>
      </div>

      <h1 style={{ marginTop: 100, marginBottom: 60 }}>With slotted trigger</h1>
      <Tooltip.Root open>
        <Tooltip.Trigger asChild>
          <button className={styles.trigger}>open</button>
        </Tooltip.Trigger>
        <Tooltip.Portal>
          <Tooltip.Content className={styles.content} sideOffset={5}>
            Some content
            <Tooltip.Arrow className={styles.arrow} width={20} height={10} offset={10} />
          </Tooltip.Content>
        </Tooltip.Portal>
      </Tooltip.Root>

      <h1 style={{ marginTop: 100, marginBottom: 60 }}>With slotted content</h1>
      <Tooltip.Root open>
        <Tooltip.Trigger className={styles.trigger}>Hover or Focus me</Tooltip.Trigger>
        <Tooltip.Portal>
          <Tooltip.Content asChild sideOffset={5}>
            <div className={styles.content}>
              Some content
              <Tooltip.Arrow className={styles.arrow} offset={10} />
            </div>
          </Tooltip.Content>
        </Tooltip.Portal>
      </Tooltip.Root>
    </div>
  </Tooltip.Provider>
);
Chromatic.parameters = { chromatic: { disable: false } };

function SimpleTooltip({
  children,
  label,
  'aria-label': ariaLabel,
  open,
  onOpenChange,
  ...props
}: any) {
  return (
    <Tooltip.Root open={open} onOpenChange={onOpenChange}>
      {children}
      <Tooltip.Portal>
        <Tooltip.Content
          className={styles.content}
          sideOffset={5}
          aria-label={ariaLabel}
          {...props}
        >
          {label}
          <Tooltip.Arrow className={styles.arrow} offset={10} />
        </Tooltip.Content>
      </Tooltip.Portal>
    </Tooltip.Root>
  );
}



================================================
FILE: apps/storybook/stories/visually-hidden.stories.tsx
================================================
import { VisuallyHidden } from 'radix-ui';

export default { title: 'Utilities/VisuallyHidden' };

export const Basic = () => (
  <button>
    <VisuallyHidden.Root>Save the file</VisuallyHidden.Root>
    <span aria-hidden>💾</span>
  </button>
);



================================================
FILE: apps/storybook/.storybook/main.ts
================================================
import type { StorybookConfig } from '@storybook/react-webpack5';

const config: StorybookConfig = {
  stories: [
    //
    '../stories/**/*.mdx',
    '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)',
  ],
  features: {
    experimentalRSC: true,
  },
  addons: ['@storybook/addon-webpack5-compiler-swc', '@storybook/addon-docs'],
  framework: {
    name: '@storybook/react-webpack5',
    options: {
      builder: {},
      // enable React strict mode
      strictMode: true,
    },
  },

  swc: (config: any) => ({
    ...config,
    jsc: {
      ...config?.jsc,
      transform: {
        ...config?.jsc?.transform,
        react: {
          // Do not require importing React into scope to use JSX
          runtime: 'automatic',
        },
      },
    },
  }),
};
export default config;



================================================
FILE: apps/storybook/.storybook/manager-head.html
================================================
<link rel="icon" type="image/png" href="/favicon.png" />
<link rel="icon" type="image/png" href="/favicon-white.svg" type="image/svg+xml" />



================================================
FILE: apps/storybook/.storybook/manager.ts
================================================
import { addons } from 'storybook/manager-api';
import { themes } from 'storybook/theming';

addons.setConfig({
  enableShortcuts: false,
  theme: themes.light,
});



================================================
FILE: apps/storybook/.storybook/preview.css
================================================
@import '@radix-ui/colors/gray.css';
@import '@radix-ui/colors/blue.css';
@import '@radix-ui/colors/green.css';
@import '@radix-ui/colors/red.css';
@import '@radix-ui/colors/purple.css';
@import '@radix-ui/colors/gray-dark.css';
@import '@radix-ui/colors/blue-dark.css';
@import '@radix-ui/colors/green-dark.css';
@import '@radix-ui/colors/red-dark.css';
@import '@radix-ui/colors/purple-dark.css';

* {
  box-sizing: border-box;
}

*::before,
*::after {
  box-sizing: inherit;
}

[hidden] {
  display: none;
}

:root {
  --color-white: #fff;
  --color-gray100: #ccc;
  --color-gray300: #aaa;
  --color-black: #111;
  --color-red: crimson;
  --color-green: green;
}

body {
  font-family:
    -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif,
    'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
}



================================================
FILE: apps/storybook/.storybook/preview.ts
================================================
import type { Preview } from '@storybook/react-webpack5';
import './preview.css';

const preview: Preview = {
  parameters: {
    layout: 'fullscreen',
    options: {
      storySort: {
        order: ['Components', 'Utilities'],
      },
    },
    // disables Chromatic on a global level
    chromatic: { disable: true },
    docs: {
      codePanel: true,
    },
  },
};

export default preview;



================================================
FILE: cypress/tsconfig.json
================================================
{
  "compilerOptions": {
    "target": "es5",
    "lib": ["es5", "dom"],
    "types": ["cypress", "@testing-library/cypress", "cypress-real-events", "cypress-axe"]
  },
  "include": ["**/*.ts"]
}



================================================
FILE: cypress/e2e/ContextMenu.cy.ts
================================================
describe('ContextMenu', () => {
  describe('given submenu user', () => {
    beforeEach(() => {
      cy.visitStory('contextmenu--submenus');
      cy.findByText('Right Click Here').rightclick();
    });

    describe('when using pointer', () => {
      it('should close open submenus and reopen the root menu when right clicking trigger', () => {
        pointerOver('Bookmarks →');
        cy.findByText('Inbox').should('be.visible');
        cy.findByText('Right Click Here').rightclick({ force: true });
        cy.findByText('New Tab').should('be.visible');
        cy.findByText('Inbox').should('not.exist');
      });

      it('should open submenu and not focus first item when moving pointer over trigger', () => {
        pointerOver('Bookmarks →');
        cy.findByText('Inbox').should('not.be.focused');
      });

      it('should not close when moving pointer to submenu and back to parent trigger', () => {
        pointerOver('Bookmarks →');
        pointerOver('Inbox');
        pointerOver('Bookmarks →');
        cy.findByText('Inbox').should('be.visible');
      });

      it(
        'should close submenu when moving pointer away but remain open when moving towards',
        {
          viewportWidth: 550,
        },
        () => {
          // Moving away
          pointerOver('Bookmarks →');
          cy.findByText('Inbox').should('be.visible');
          pointerExitRightToLeft('Bookmarks →');
          cy.findByText('Inbox').should('not.exist');

          // Moving towards
          pointerOver('Bookmarks →');
          cy.findByText('Inbox').should('be.visible');
          pointerExitLeftToRight('Bookmarks →');
          cy.findByText('Inbox').should('be.visible');

          // Test at collision edge
          // Moving away
          pointerOver('WorkOS →');
          cy.findByText('Radix').should('be.visible');
          pointerExitLeftToRight('WorkOS →');
          cy.findByText('Radix').should('not.exist');

          // Moving towards
          pointerOver('WorkOS →');
          cy.findByText('Radix').should('be.visible');
          pointerExitRightToLeft('WorkOS →');
          cy.findByText('Radix').should('be.visible');
        },
      );

      it('should close open submenu when moving pointer to any item in parent menu', () => {
        // Item
        pointerOver('Bookmarks →');
        pointerOver('Inbox');
        pointerOver('New Tab');
        cy.findByText('Inbox').should('not.exist');

        // Disabled item
        pointerOver('Bookmarks →');
        pointerOver('Inbox');
        pointerOver('Print…');
        cy.findByText('Inbox').should('not.exist');

        // Trigger item
        pointerOver('Bookmarks →');
        pointerOver('Inbox');
        pointerOver('Tools →');
        cy.findByText('Inbox').should('not.exist');

        // Disabled trigger item
        pointerOver('Bookmarks →');
        pointerOver('Inbox');
        pointerOver('History →');
        cy.findByText('Inbox').should('not.exist');
      });

      it('should close unassociated submenus when moving pointer back to the root trigger', () => {
        // Open multiple nested submenus and back to trigger in root menu
        pointerOver('Bookmarks →');
        pointerOver('WorkOS →');
        pointerOver('Radix');
        pointerOver('Bookmarks →');

        cy.findByText('Inbox').should('be.visible');
        cy.findByText('Radix').should('not.exist');
      });

      it('should close all menus when clicking item in any menu, or clicking outside', () => {
        // Root menu
        cy.findByText('New Tab').click();
        cy.findByText('New Tab').should('not.exist');

        // Submenu
        cy.findByText('Right Click Here').rightclick();
        pointerOver('Bookmarks →');
        cy.findByText('Inbox').click();
        cy.findByText('New Tab').should('not.exist');
        cy.findByText('Inbox').should('not.exist');

        // Click outside
        cy.findByText('Right Click Here').rightclick();
        cy.get('body').click({ force: true });
        cy.findByText('New Tab').should('not.exist');
      });
    });

    describe('When using keyboard', () => {
      it('should not open submenu when moving focus to trigger', () => {
        cy.findByText('Bookmarks →').focus();
        cy.findByText('Inbox').should('not.exist');
      });

      it('should open submenu and focus first item when pressing right arrow, enter or space key', () => {
        function shouldOpenOnKeydown(key: string) {
          cy.findByText('Bookmarks →').trigger('keydown', { key });
          cy.findByText('Inbox').should('be.focused').trigger('keydown', { key: 'ArrowLeft' });
        }

        shouldOpenOnKeydown(' ');
        shouldOpenOnKeydown('Enter');
        shouldOpenOnKeydown('ArrowRight');
      });

      it('should close only the focused submenu when pressing left arrow key', () => {
        cy.findByText('Bookmarks →').type('{enter}');
        cy.findByText('WorkOS →').type('{enter}');
        cy.findByText('Stitches').type('{leftarrow}');
        cy.findByText('Stitches').should('not.exist');
        cy.findByText('WorkOS →').should('be.visible');
        cy.findByText('New Window').should('be.visible');
      });

      it('should focus first item when pressing right arrow key after opening submenu with mouse', () => {
        pointerOver('Bookmarks →');
        cy.findByText('Inbox').should('be.visible');
        cy.findByText('Bookmarks →').type('{rightarrow}');
        cy.findByText('Inbox').should('be.focused');
      });

      it('should close all menus when pressing escape, enter or space key on any item', () => {
        // Test close on root menu
        cy.findByText('Bookmarks →').type('{esc}');
        cy.findByText('Bookmarks →').should('not.exist');

        // Reopen menu and test keys from within the submenu
        cy.findByText('Right Click Here').rightclick();
        cy.findByText('Bookmarks →').type('{enter}');
        cy.findByText('Inbox').type('{esc}');
        cy.findByText('Inbox').should('not.exist');
        cy.findByText('New Window').should('not.exist');
      });

      it('should scope typeahead behaviour to the active menu', () => {
        // Matching items outside of the active menu should not become focused
        pointerOver('Bookmarks →');
        pointerOver('WorkOS →');
        cy.findByText('Stitches').focus();
        cy.findByText('Stitches').type('Inbox');
        cy.findByText('Inbox').should('not.have.focus');

        // Matching items inside of active menu should become focused
        pointerOver('Notion').focus();
        pointerOver('Notion').type('Inbox');
        cy.findByText('Inbox').should('have.focus');
      });
    });

    describe('When using pointer in RTL', () => {
      beforeEach(() => {
        cy.findByText('Right-to-left').click({ force: true });
        cy.findByText('Right Click Here').rightclick();
      });

      it(
        'should close submenu when pointer moves away but remain open when moving towards',
        {
          viewportWidth: 550,
        },
        () => {
          // Moving away
          pointerOver('Bookmarks →');
          cy.findByText('Inbox').should('be.visible');
          pointerExitLeftToRight('Bookmarks →');
          cy.findByText('Inbox').should('not.exist');

          // Moving towards
          pointerOver('Bookmarks →');
          cy.findByText('Inbox').should('be.visible');
          pointerExitRightToLeft('Bookmarks →');
          cy.findByText('Inbox').should('be.visible');

          // Test at collision edge
          // Moving away
          pointerOver('WorkOS →');
          cy.findByText('Radix').should('be.visible');
          pointerExitRightToLeft('WorkOS →');
          cy.findByText('Radix').should('not.exist');

          // Moving towards
          pointerOver('WorkOS →');
          cy.findByText('Radix').should('be.visible');
          pointerExitLeftToRight('WorkOS →');
          cy.findByText('Radix').should('be.visible');
        },
      );
    });

    describe('When using keyboard in RTL', () => {
      beforeEach(() => {
        cy.findByText('Right-to-left').click({ force: true });
        cy.findByText('Right Click Here').rightclick();
      });

      it('should open submenu and focus first item when pressing left arrow key but close when pressing right arrow key', () => {
        cy.findByText('Bookmarks →').trigger('keydown', { key: 'ArrowLeft' });
        cy.findByText('Inbox').should('be.focused');
        cy.findByText('Inbox').should('be.focused');
        cy.findByText('Inbox').trigger('keydown', { key: 'ArrowRight' });
        cy.findByText('Inbox').should('not.exist');

        // Root level menu should remain open
        cy.findByText('New Tab').should('be.visible');
      });
    });
  });

  /* ---------------------------------------------------------------------------------------------- */

  function pointerExitRightToLeft(elementText: string) {
    return cy
      .findByText(elementText)
      .should('be.visible')
      .realHover({ position: 'right' })
      .realHover({ position: 'bottomLeft' })
      .trigger('pointerout', 'bottomLeft', { pointerType: 'mouse' });
  }

  function pointerExitLeftToRight(elementText: string) {
    return cy
      .findByText(elementText)
      .should('be.visible')
      .realHover({ position: 'left' })
      .realHover({ position: 'bottomRight' })
      .trigger('pointerout', 'bottomRight', { pointerType: 'mouse' });
  }

  function pointerOver(elementText: string) {
    return cy.findByText(elementText).should('be.visible').realHover();
  }
});



================================================
FILE: cypress/e2e/Dialog.cy.ts
================================================
describe('Dialog', () => {
  beforeEach(() => {
    cy.visitStory('dialog--cypress');
  });

  function shouldBeOpen() {
    cy.findByText('title').should('exist');
  }
  function shouldBeClosed() {
    cy.findByText('title').should('not.exist');
  }
  function shouldNotAllowOutsideInteraction(action: 'realClick' | 'realTouch') {
    cy.findByLabelText('count up')
      .invoke('text')
      .then((count) => {
        if (action === 'realTouch') {
          cy.findByLabelText('count up').realClick();
        } else {
          cy.findByLabelText('count up').realTouch();
        }
        cy.findByLabelText('count up').should('have.text', count);
      });
  }
  function shouldAllowOutsideInteraction(action: 'realClick' | 'realTouch') {
    cy.findByLabelText('count up')
      .invoke('text')
      .then((count) => {
        if (action === 'realTouch') {
          cy.findByLabelText('count up').realClick();
        } else {
          cy.findByLabelText('count up').realTouch();
        }
        cy.findByLabelText('count up').should('not.have.text', count);
      });
  }

  describe('given a modal dialog', () => {
    it('can be open/closed with a keyboard', () => {
      // using keyboard on open/close buttons
      cy.findByText('open').focus();
      cy.realPress('Space');
      shouldBeOpen();
      cy.findByText('close').should('be.focused');
      cy.realPress('Space');
      shouldBeClosed();
      cy.findByText('open').should('be.focused');

      // using keyboard on open button and close with escape
      cy.realPress('Space');
      shouldBeOpen();
      cy.realPress('Escape');
      shouldBeClosed();
    });

    it('can be open/closed with a pointer', () => {
      // using pointer on open/close buttons
      cy.findByText('open').click();
      shouldBeOpen();
      cy.findByText('close').should('be.focused').click();
      shouldBeClosed();
      cy.findByText('open').should('be.focused');

      // using mouse inside dialog, then on a button outside
      cy.findByText('open').click();
      shouldBeOpen();
      cy.findByText('title').click();
      shouldBeOpen();
      shouldNotAllowOutsideInteraction('realClick');
      shouldBeClosed();

      // using touch on a button outside
      cy.findByText('open').click();
      shouldBeOpen();
      shouldNotAllowOutsideInteraction('realTouch');
      shouldBeClosed();

      // using mouse on an input outside
      cy.findByText('open').click();
      shouldBeOpen();
      cy.findByPlaceholderText('name').realClick();
      cy.findByPlaceholderText('name').should('not.be.focused');
      shouldBeClosed();

      // using touch on an input outside
      cy.findByText('open').click();
      shouldBeOpen();
      cy.findByPlaceholderText('name').realTouch();
      cy.findByPlaceholderText('name').should('not.be.focused');
      shouldBeClosed();

      // turn on animation
      cy.findByLabelText('animated').click();

      // using mouse on an input outside an animated dialog
      cy.findByText('open').click();
      shouldBeOpen();
      cy.findByPlaceholderText('name').realClick();
      cy.findByPlaceholderText('name').should('not.be.focused');
      shouldBeClosed();

      // finally, ensure that pointer-events have been reset and interactions restored
      shouldAllowOutsideInteraction('realClick');

      // using touch on an input outside an animated dialog
      cy.findByText('open').click();
      shouldBeOpen();
      cy.findByPlaceholderText('name').realTouch();
      cy.findByPlaceholderText('name').should('not.be.focused');
      shouldBeClosed();

      // finally, ensure that pointer-events have been reset and interactions restored
      shouldAllowOutsideInteraction('realTouch');
    });

    it('keeps focus trapped even if focused element is removed', () => {
      cy.findByText('open').click();
      cy.findByText('close').should('be.focused');
      cy.realPress('Tab');
      cy.findByText('destroy me').should('be.focused');
      cy.realPress('Space');
      cy.realPress('Tab');
      cy.findByText('close').should('be.focused');
    });
  });

  describe('given a non-modal dialog', () => {
    beforeEach(() => {
      cy.findByLabelText('modal').click();
    });

    it('can be open/closed with a keyboard', () => {
      // using keyboard on open/close buttons
      cy.findByText('open').focus();
      cy.realPress('Space');
      shouldBeOpen();
      cy.findByText('close').should('be.focused');
      cy.realPress('Space');
      shouldBeClosed();
      cy.findByText('open').should('be.focused');

      // using keyboard on open button and close with escape
      cy.realPress('Space');
      shouldBeOpen();
      cy.realPress('Escape');
      shouldBeClosed();
    });

    it('can be open/closed with a pointer', () => {
      // using pointer on open/close buttons
      cy.findByText('open').click();
      shouldBeOpen();
      cy.findByText('close').should('be.focused').click();
      shouldBeClosed();
      cy.findByText('open').should('be.focused');

      // using mouse inside dialog, then on a button outside
      cy.findByText('open').click();
      shouldBeOpen();
      cy.findByText('title').click();
      shouldBeOpen();
      shouldAllowOutsideInteraction('realClick');
      shouldBeClosed();

      // using touch on a button outside
      cy.findByText('open').click();
      shouldBeOpen();
      shouldAllowOutsideInteraction('realTouch');
      shouldBeClosed();

      // using mouse on an input outside
      cy.findByText('open').click();
      shouldBeOpen();
      cy.findByPlaceholderText('name').realClick();
      cy.findByPlaceholderText('name').should('be.focused');
      shouldBeClosed();

      // using touch on an input outside
      cy.findByText('open').click();
      shouldBeOpen();
      cy.findByPlaceholderText('name').realTouch();
      cy.findByPlaceholderText('name').should('be.focused');
      shouldBeClosed();

      // turn on animation
      cy.findByLabelText('animated').click();

      // using mouse on an input outside an animated dialog
      cy.findByText('open').click();
      shouldBeOpen();
      cy.findByPlaceholderText('name').realClick();
      cy.findByPlaceholderText('name').should('be.focused');
      shouldBeClosed();

      // finally, ensure that pointer-events have been reset and interactions restored
      shouldAllowOutsideInteraction('realClick');

      // using touch on an input outside an animated dialog
      cy.findByText('open').click();
      shouldBeOpen();
      cy.findByPlaceholderText('name').realTouch();
      cy.findByPlaceholderText('name').should('be.focused');
      shouldBeClosed();

      // finally, ensure that pointer-events have been reset and interactions restored
      shouldAllowOutsideInteraction('realTouch');
    });
  });
});



================================================
FILE: cypress/e2e/DropdownMenu.cy.ts
================================================
describe('DropdownMenu', () => {
  describe('given submenu user', () => {
    beforeEach(() => {
      cy.visitStory('dropdownmenu--submenus');
      cy.findByText('Open').click();
    });

    describe('when using pointer', () => {
      it('should open submenu and not focus first item when moving pointer over trigger', () => {
        pointerOver('Bookmarks →');
        cy.findByText('Inbox').should('not.be.focused');
      });

      it('should not close when moving pointer to submenu and back to parent trigger', () => {
        pointerOver('Bookmarks →');
        pointerOver('Inbox');
        pointerOver('Bookmarks →');
        cy.findByText('Inbox').should('be.visible');
      });

      it(
        'should close submenu when moving pointer away but remain open when moving towards',
        {
          viewportWidth: 550,
        },
        () => {
          // Moving away
          pointerOver('Bookmarks →');
          cy.findByText('Inbox').should('be.visible');
          pointerExitRightToLeft('Bookmarks →');
          cy.findByText('Inbox').should('not.exist');

          // Moving towards
          pointerOver('Bookmarks →');
          cy.findByText('Inbox').should('be.visible');
          pointerExitLeftToRight('Bookmarks →');
          cy.findByText('Inbox').should('be.visible');

          // Test at collision edge
          // Moving away
          pointerOver('WorkOS →');
          cy.findByText('Radix').should('be.visible');
          pointerExitLeftToRight('WorkOS →');
          cy.findByText('Radix').should('not.exist');

          // Moving towards
          pointerOver('WorkOS →');
          cy.findByText('Radix').should('be.visible');
          pointerExitRightToLeft('WorkOS →');
          cy.findByText('Radix').should('be.visible');
        },
      );

      it('should close open submenu when moving pointer to any item in parent menu', () => {
        // Item
        pointerOver('Bookmarks →');
        pointerOver('Inbox');
        pointerOver('New Tab');
        cy.findByText('Inbox').should('not.exist');

        // Disabled item
        pointerOver('Bookmarks →');
        pointerOver('Inbox');
        pointerOver('Print…');
        cy.findByText('Inbox').should('not.exist');

        // Trigger item
        pointerOver('Bookmarks →');
        pointerOver('Inbox');
        pointerOver('Tools →');
        cy.findByText('Inbox').should('not.exist');

        // Disabled trigger item
        pointerOver('Bookmarks →');
        pointerOver('Inbox');
        pointerOver('History →');
        cy.findByText('Inbox').should('not.exist');
      });

      it('should close unassociated submenus when moving pointer back to the root trigger', () => {
        // Open multiple nested submenus and back to trigger in root menu
        pointerOver('Bookmarks →');
        pointerOver('WorkOS →');
        pointerOver('Radix');
        pointerOver('Bookmarks →');

        cy.findByText('Inbox').should('be.visible');
        cy.findByText('Radix').should('not.exist');
      });

      it('should close all menus when clicking item in any menu, or clicking outside', () => {
        // Root menu
        cy.findByText('New Tab').click();
        cy.findByText('New Tab').should('not.exist');

        // Submenu
        cy.findByText('Open').click();
        pointerOver('Bookmarks →');
        cy.findByText('Inbox').click();
        cy.findByText('New Tab').should('not.exist');
        cy.findByText('Inbox').should('not.exist');

        // Click outside
        cy.findByText('Open').click();
        cy.get('body').click({ force: true });
        cy.findByText('New Tab').should('not.exist');
      });
    });

    describe('When using keyboard', () => {
      it('should not open submenu when moving focus to trigger', () => {
        cy.findByText('Bookmarks →').focus();
        cy.findByText('Inbox').should('not.exist');
      });

      it('should open submenu and focus first item when pressing right arrow, enter or space key', () => {
        function shouldOpenOnKeydown(key: string) {
          cy.findByText('Bookmarks →').trigger('keydown', { key });
          cy.findByText('Inbox').should('be.focused').trigger('keydown', { key: 'ArrowLeft' });
        }

        shouldOpenOnKeydown(' ');
        shouldOpenOnKeydown('Enter');
        shouldOpenOnKeydown('ArrowRight');
      });

      it('should close only the focused submenu when pressing left arrow key', () => {
        cy.findByText('Bookmarks →').type('{enter}');
        cy.findByText('WorkOS →').type('{enter}');
        cy.findByText('Stitches').type('{leftarrow}');
        cy.findByText('Stitches').should('not.exist');
        cy.findByText('WorkOS →').should('be.visible');
        cy.findByText('New Window').should('be.visible');
      });

      it('should focus first item when pressing right arrow key after opening submenu with mouse', () => {
        pointerOver('Bookmarks →');
        cy.findByText('Inbox').should('be.visible');
        cy.findByText('Bookmarks →').type('{rightarrow}');
        cy.findByText('Inbox').should('be.focused');
      });

      it('should close all menus when pressing escape, enter or space key on any item', () => {
        // Test close on root menu
        cy.findByText('New Window').type('{esc}');
        cy.findByText('New Window').should('not.exist');

        // Reopen menu and test keys from within the submenu
        cy.findByText('Open').click();
        cy.findByText('Bookmarks →').type('{enter}');
        cy.findByText('Inbox').type('{esc}');
        cy.findByText('Inbox').should('not.exist');
        cy.findByText('New Window').should('not.exist');
      });

      it('should scope typeahead behaviour to the active menu', () => {
        // Matching items outside of the active menu should not become focused
        pointerOver('Bookmarks →');
        pointerOver('WorkOS →');
        cy.findByText('Stitches').focus();
        cy.findByText('Stitches').type('Inbox');
        cy.findByText('Inbox').should('not.have.focus');

        // Matching items inside of active menu should become focused
        pointerOver('Notion').focus().type('Inbox');
        cy.findByText('Inbox').should('have.focus');
      });
    });

    describe('When using pointer in RTL', () => {
      beforeEach(() => {
        cy.findByText('Right-to-left').click({ force: true });
        cy.findByText('Open').click();
      });

      it(
        'should close submenu when pointer moves away but remain open when moving towards',
        {
          viewportWidth: 550,
        },
        () => {
          // Moving away
          pointerOver('Bookmarks →');
          cy.findByText('Inbox').should('be.visible');
          pointerExitLeftToRight('Bookmarks →');
          cy.findByText('Inbox').should('not.exist');

          // Moving towards
          pointerOver('Bookmarks →');
          cy.findByText('Inbox').should('be.visible');
          pointerExitRightToLeft('Bookmarks →');
          cy.findByText('Inbox').should('be.visible');

          // Test at collision edge
          // Moving away
          pointerOver('WorkOS →');
          cy.findByText('Radix').should('be.visible');
          pointerExitRightToLeft('WorkOS →');
          cy.findByText('Radix').should('not.exist');

          // Moving towards
          pointerOver('WorkOS →');
          cy.findByText('Radix').should('be.visible');
          pointerExitLeftToRight('WorkOS →');
          cy.findByText('Radix').should('be.visible');
        },
      );
    });

    describe('When using keyboard in RTL', () => {
      beforeEach(() => {
        cy.findByText('Right-to-left').click({ force: true });
        cy.findByText('Open').click();
      });

      it('should open submenu and focus first item when pressing left arrow key but close when pressing right arrow key', () => {
        cy.findByText('Bookmarks →').trigger('keydown', { key: 'ArrowLeft' });
        cy.findByText('Inbox').should('be.focused');
        cy.findByText('Inbox').trigger('keydown', { key: 'ArrowRight' });
        cy.findByText('Inbox').should('not.exist');

        // Root level menu should remain open
        cy.findByText('New Tab').should('be.visible');
      });
    });
  });

  /* ---------------------------------------------------------------------------------------------- */

  function pointerExitRightToLeft(elementText: string) {
    return cy
      .findByText(elementText)
      .should('be.visible')
      .realHover({ position: 'right' })
      .realHover({ position: 'bottomLeft' })
      .trigger('pointerout', 'bottomLeft', { pointerType: 'mouse' });
  }

  function pointerExitLeftToRight(elementText: string) {
    return cy
      .findByText(elementText)
      .should('be.visible')
      .realHover({ position: 'left' })
      .realHover({ position: 'bottomRight' })
      .trigger('pointerout', 'bottomRight', { pointerType: 'mouse' });
  }

  function pointerOver(elementText: string) {
    return cy.findByText(elementText).should('be.visible').realHover();
  }
});



================================================
FILE: cypress/e2e/Form.cy.ts
================================================
describe('Form', () => {
  before(() => {
    cy.visitStory('form--cypress');
  });

  beforeEach(() => {
    cy.findByText('reset').click();
  });

  function checkControlMessageAssociation() {
    cy.get('@control').should('have.attr', 'aria-describedby');
    cy.get('@control')
      .invoke('attr', 'aria-describedby')
      .then((ariaDescribedby) =>
        cy.get('@message').invoke('attr', 'id').should('equal', ariaDescribedby),
      );
  }

  describe('given a form', () => {
    it('should associate label and control', () => {
      cy.findByText(/email/i).click();
      cy.findByLabelText(/email/i).should('be.focused');
    });

    it('allows custom label and control association', () => {
      cy.findByText(/country/i).click();
      cy.findByLabelText(/country/i).should('be.focused');
    });
  });

  describe('given a form with client-side validation', () => {
    it('should prevent submitting when there are errors', () => {
      cy.findByText('submit').click();
      cy.findByText(/data/i).should('include.text', '{}');
    });

    it('should focus the first control with an error', () => {
      cy.findByText('submit').click();
      cy.findByLabelText(/name/i).should('be.focused');
    });

    it('should handle `valueMissing` validity', () => {
      cy.findByLabelText(/name/i).as('control');
      cy.findByText('submit').click();
      cy.findByText(/missing/).as('message');
      checkControlMessageAssociation();

      cy.get('@control').focus();
      cy.get('@control').realType('John');
      cy.realPress('Tab');
      cy.findByText(/missing/).should('not.exist');
    });

    it('should handle `valid` validity', () => {
      cy.findByLabelText(/name/i).as('control').focus();
      cy.get('@control').realType('John');
      cy.realPress('Tab');
      cy.findByText('valid!').as('message');
      checkControlMessageAssociation();

      cy.findByText('submit').click();
      cy.findByText(/data/i).should('include.text', '"name": "John"');
    });

    it('should handle `rangeOverflow` validity', () => {
      cy.findByLabelText(/age/i).as('control').focus();
      cy.get('@control').realType('200');
      cy.realPress('Tab');
      cy.findByText(/too large/).as('message');
      checkControlMessageAssociation();

      cy.get('@control').focus();
      cy.get('@control').clear();
      cy.get('@control').realType('50');
      cy.realPress('Tab');
      cy.findByText(/does not match the required step/).should('not.exist');
    });

    it('should handle `rangeUnderflow` validity', () => {
      cy.findByLabelText(/age/i).as('control').focus();
      cy.get('@control').realType('-50');
      cy.realPress('Tab');
      cy.findByText(/too small/).as('message');
      checkControlMessageAssociation();

      cy.get('@control').focus();
      cy.get('@control').clear();
      cy.get('@control').realType('50');
      cy.realPress('Tab');
      cy.findByText(/does not match the required step/).should('not.exist');
    });

    it('should handle `stepMismatch` validity', () => {
      cy.findByLabelText(/age/i).as('control').focus();
      cy.get('@control').realType('10.5');
      cy.realPress('Tab');
      cy.findByText(/does not match the required step/).as('message');
      checkControlMessageAssociation();

      cy.get('@control').focus();
      cy.get('@control').clear();
      cy.get('@control').realType('50');
      cy.realPress('Tab');
      cy.findByText(/does not match the required step/).should('not.exist');
    });

    it('should handle `typeMismatch` validity', () => {
      cy.findByLabelText(/email/i).as('control').focus();
      cy.get('@control').realType('john.doe');
      cy.realPress('Tab');
      cy.findByText(/does not match the required type/).as('message');
      checkControlMessageAssociation();

      cy.get('@control').focus();
      cy.get('@control').realType('@gmail.com');
      cy.realPress('Tab');
      cy.findByText(/does not match the required type/).should('not.exist');
    });

    it('should handle `tooShort` validity', () => {
      cy.findByLabelText(/password/i)
        .as('control')
        .focus();
      cy.get('@control').realType('pass');
      cy.realPress('Tab');
      cy.findByText(/too short/).as('message');
      checkControlMessageAssociation();

      cy.get('@control').focus();
      cy.get('@control').clear();
      cy.get('@control').realType('password');
      cy.realPress('Tab');
      cy.findByText(/too short/).should('not.exist');
    });

    // the browser makes it impossible to type too long
    it.skip('should handle `tooLong` validity', () => {
      cy.findByLabelText(/password/i)
        .as('control')
        .focus();
      cy.get('@control').realType('password is way too long');
      cy.realPress('Tab');
      cy.findByText(/too long/).as('message');
      checkControlMessageAssociation();
    });

    it('should handle `patternMismatch` validity', () => {
      cy.findByLabelText(/pin/i).as('control').focus();
      cy.get('@control').realType('pin');
      cy.realPress('Tab');
      cy.findByText(/does not match the required pattern/).as('message');
      checkControlMessageAssociation();

      cy.get('@control').focus();
      cy.get('@control').clear();
      cy.get('@control').realType('1234');
      cy.realPress('Tab');
      cy.findByText(/does not match the required pattern/).should('not.exist');
    });

    it('should handle custom validity (sync custom validator)', () => {
      cy.findByLabelText(/secret 1/i)
        .as('control')
        .focus();
      cy.get('@control').realType('secret');
      cy.realPress('Tab');
      cy.findByText(/not valid/).as('message');
      checkControlMessageAssociation();

      cy.get('@control').focus();
      cy.get('@control').clear();
      cy.get('@control').realType('shush');
      cy.realPress('Tab');
      cy.findByText(/not valid/).should('not.exist');
    });

    it('should handle custom validity (async custom validator)', () => {
      cy.findByLabelText(/secret 2/i)
        .as('control')
        .focus();
      cy.get('@control').realType('secret');
      cy.realPress('Tab');
      cy.findByText(/not valid/).as('message');
      checkControlMessageAssociation();

      cy.get('@control').focus();
      cy.get('@control').clear();
      cy.get('@control').realType('shush');
      cy.realPress('Tab');
      cy.findByText(/not valid/).should('not.exist');
    });

    it('should allow custom error messages', () => {
      cy.findByLabelText(/country/i)
        .as('control')
        .focus();
      cy.get('@control').realType('Portugal');
      cy.realPress('Tab');
      cy.findByText(/country should be "france" or "spain"/i).as('message');
      checkControlMessageAssociation();
    });
  });

  describe('given a form with server-side validation', () => {
    before(() => {
      cy.findByLabelText(/simulate server errors/i).click();
    });

    beforeEach(() => {
      cy.findByLabelText(/name/i).focus();
      cy.findByLabelText(/name/i).realType('John');
      cy.findByText(/submit/i).click();
    });

    it('should focus the first control with a server error', () => {
      cy.findByLabelText(/email/i).should('be.focused');
    });

    it('allows showing custom server error messages per-field', () => {
      cy.findByLabelText(/email/i).as('control');
      cy.findByText(/email is actually required server side/i).as('message');
      checkControlMessageAssociation();
    });

    it('allows re-using client-side matchers for server errors', () => {
      cy.findByLabelText(/pin/i).as('control');
      cy.findByText(/does not match the required pattern/).as('message');
      checkControlMessageAssociation();
    });

    it('allows re-submitting the form with server errors', () => {
      cy.findByLabelText(/email/i).focus();
      cy.findByLabelText(/email/i).realType('john.doe@gmail.com').realPress('Enter');
      cy.findByLabelText(/email/i).should('be.focused');
    });
  });
});



================================================
FILE: cypress/e2e/Menubar.cy.ts
================================================
describe('Menubar', () => {
  beforeEach(() => {
    cy.visitStory('menubar--cypress');
  });

  describe('given a pointer user', () => {
    it('should open menu when pointer moves between triggers and not focus first item', () => {
      pointerOver('File');
      cy.findByText('New Tab').should('not.exist');

      cy.findByText('File').click();
      cy.findByText('New Tab').should('not.have.focus');

      pointerOver('Edit');
      cy.findByText('New Tab').should('not.exist');
      cy.findByText('Redo').should('not.have.focus');

      pointerOver('History');
      cy.findByText('Redo').should('not.exist');
      cy.findByText('Radix').should('not.have.focus');
    });

    it('should maintain the open state when pointer moves away from a trigger', () => {
      cy.findByText('File').click();
      pointerOver('File').trigger('pointerout', 'bottomRight', {
        pointerType: 'mouse',
        force: true,
      });
      cy.findByText('New Tab').should('be.visible');
    });

    it('should not close open submenu when moving pointer to submenu and back to parent trigger', () => {
      cy.findByText('Edit').click();
      pointerOver('Find');
      pointerOver('Find Next');
      pointerOver('Find');
      cy.findByText('Find Next').should('be.visible');
    });

    it('should close open submenu when moving pointer to any item in parent menu', () => {
      cy.findByText('Edit').click();
      // Item
      pointerOver('Find');
      pointerOver('Find Next');
      pointerOver('Redo');
      cy.findByText('Find Next').should('not.exist');

      // Disabled item
      pointerOver('Find');
      pointerOver('Find Next');
      pointerOver('Redo');
      cy.findByText('Find Next').should('not.exist');

      // Trigger item
      pointerOver('Find');
      pointerOver('Find Next');
      pointerOver('Substitutions');
      cy.findByText('Find Next').should('not.exist');

      // Disabled trigger item
      pointerOver('Find');
      pointerOver('Find Next');
      pointerOver('Speech');
      cy.findByText('Find Next').should('not.exist');
    });

    it('should close unassociated submenus when moving pointer back to the root trigger', () => {
      cy.findByText('Edit').click();
      // Open multiple nested submenus and back to trigger in root menu
      pointerOver('Find');
      pointerOver('Advanced');
      pointerOver('Regex');
      pointerOver('Find');

      cy.findByText('Find Next').should('be.visible');
      cy.findByText('Regex').should('not.exist');
    });

    it('should close all menus when clicking item in any menu, or clicking outside', () => {
      cy.findByText('Edit').click();

      // Root menu
      cy.findByText('Redo').click();
      cy.findByText('Redo').should('not.exist');

      // Submenu
      cy.findByText('Edit').click();
      pointerOver('Find');
      cy.findByText('Find Next').click();
      cy.findByText('Redo').should('not.exist');
      cy.findByText('Find Next').should('not.exist');

      // Click outside
      cy.findByText('Edit').click();
      cy.get('body').click();
      cy.findByText('Redo').should('not.exist');
    });
  });

  describe('given a keyboard user', () => {
    function shouldSupportArrowKeyNavigation(dir: 'ltr' | 'rtl') {
      const nextKey = dir === 'ltr' ? 'ArrowRight' : 'ArrowLeft';
      const prevKey = dir === 'ltr' ? 'ArrowLeft' : 'ArrowRight';

      // Moving forwards with menu closed
      cy.findByText('File').trigger('keydown', { key: nextKey });
      cy.findByText('Edit').should('be.focused').trigger('keydown', { key: nextKey });

      // Moving backwards with menu closed
      cy.findByText('History').should('be.focused').trigger('keydown', { key: prevKey });
      cy.findByText('Edit').should('be.focused').trigger('keydown', { key: prevKey });
      cy.findByText('File').should('be.focused');

      // End of list (should not loop)
      cy.findByText('File').trigger('keydown', { key: nextKey });
      cy.findByText('File').should('be.focused');

      // Open menu
      cy.findByText('File').click();

      // Moving forwards with menu open
      cy.findByText('New Tab').trigger('keydown', { key: nextKey });
      cy.findByText('New Tab').should('not.exist');

      // Moving backwards with menu open
      cy.findByText('Redo').trigger('keydown', { key: prevKey });
      cy.findByText('Redo').should('not.exist');

      // End of list (should not loop)
      cy.findByText('New Tab').trigger('keydown', { key: prevKey });
      cy.findByText('New Tab').should('be.visible');

      // Moving forwards at submenu edge
      cy.findByText('Share').trigger('keydown', { key: nextKey });
      cy.findByText('Email Link').trigger('keydown', { key: nextKey });
      cy.findByText('Redo').should('be.visible');

      // Moving backwards at submenu edge
      cy.findByText('Find').trigger('keydown', { key: nextKey });
      cy.findByText('Advanced').trigger('keydown', { key: nextKey });
      cy.findByText('Regex').trigger('keydown', { key: prevKey });
      cy.findByText('Advanced').trigger('keydown', { key: prevKey });
      cy.findByText('Find').trigger('keydown', { key: prevKey });
      cy.findByText('New Tab').should('be.visible');

      // Looping
      cy.findByText('Loop').click();
      cy.findByText('File').trigger('keydown', { key: prevKey });
      cy.findByText('History').should('be.focused').trigger('keydown', { key: nextKey });
      cy.findByText('File').should('be.focused');

      // Looping menu open
      cy.findByText('File').click();
      cy.findByText('New Tab').trigger('keydown', { key: prevKey });
      cy.findByText('Radix').trigger('keydown', { key: nextKey });
      cy.findByText('New Tab').should('be.visible');
    }

    it('should move to next menu using right arrow and previous menu with left arrow', () => {
      shouldSupportArrowKeyNavigation('ltr');
    });

    it('should not open submenu when moving focus to sub trigger', () => {
      cy.findByText('Edit').click();
      cy.findByText('Find').focus();
      cy.findByText('Find Next').should('not.exist');
    });

    it('should not open submenu when moving focus to sub trigger', () => {
      cy.findByText('Edit').click();
      cy.findByText('Find').focus();
      cy.findByText('Find Next').should('not.exist');
    });

    it('should open submenu and focus first item when pressing right arrow, enter or space key', () => {
      cy.findByText('Edit').click();

      function shouldOpenOnKeydown(key: string) {
        cy.findByText('Find').trigger('keydown', { key });
        cy.findByText('Search the web…')
          .should('be.focused')
          .trigger('keydown', { key: 'ArrowLeft' });
      }

      shouldOpenOnKeydown(' ');
      shouldOpenOnKeydown('Enter');
      shouldOpenOnKeydown('ArrowRight');
    });

    it('should close only the focused submenu when pressing left arrow key', () => {
      cy.findByText('Edit').click();

      cy.findByText('Find').type('{enter}');
      cy.findByText('Advanced').type('{enter}');
      cy.findByText('Regex').type('{leftarrow}');
      cy.findByText('Regex').should('not.exist');
      cy.findByText('Advanced').should('be.visible');
      cy.findByText('Redo').should('be.visible');
    });

    it('should focus first item when pressing right arrow key after opening submenu with pointer', () => {
      cy.findByText('Edit').click();

      pointerOver('Find');
      cy.findByText('Find Next').should('be.visible');
      cy.findByText('Find').type('{rightarrow}');
      cy.findByText('Search the web…').should('be.focused');
    });

    it('should close all menus when pressing escape, enter or space key on any item', () => {
      cy.findByText('Edit').click();

      // Test close on root menu
      cy.findByText('Redo').type('{esc}');
      cy.findByText('Redo').should('not.exist');

      // Reopen menu and test keys from within the submenu
      cy.findByText('Edit').click();
      cy.findByText('Find').type('{enter}');
      cy.findByText('Search the web…').type('{esc}');
      cy.findByText('Search the web…').should('not.exist');
      cy.findByText('Redo').should('not.exist');
    });

    it('should scope typeahead behaviour to the active menu', () => {
      cy.findByText('Edit').click();

      // Matching items outside of the active menu should not become focused
      pointerOver('Find');
      pointerOver('Advanced');
      cy.findByText('Regex').focus();
      cy.findByText('Regex').type('Find');
      cy.findByText('Find').should('not.have.focus');

      // Matching items inside of active menu should become focused
      pointerOver('Advanced').focus().type('Find Next');
      cy.findByText('Find Next').should('have.focus');
    });

    describe('with portals enabled', () => {
      it('should move to next menu using right arrow and previous menu with left arrow', () => {
        shouldSupportArrowKeyNavigation('ltr');
      });
    });

    describe('with RTL enabled', () => {
      beforeEach(() => {
        cy.findByText('Right-to-left').click();
      });

      it('should move to next menu using right arrow and previous menu with left arrow', () => {
        shouldSupportArrowKeyNavigation('rtl');
      });

      it('should open submenu and focus first item when pressing left arrow key but close when pressing right arrow key', () => {
        cy.findByText('Edit').click();
        cy.findByText('Find').trigger('keydown', { key: 'ArrowLeft' });
        cy.findByText('Search the web…').should('be.focused');
        cy.findByText('Search the web…').trigger('keydown', { key: 'ArrowRight' });
        cy.findByText('Search the web…').should('not.exist');

        // Root level menu should remain open
        cy.findByText('Redo').should('be.visible');
      });
    });
  });

  /* ---------------------------------------------------------------------------------------------- */

  function pointerOver(elementText: string) {
    return cy.findByText(elementText).should('be.visible').realHover();
  }
});



================================================
FILE: cypress/e2e/Select.cy.ts
================================================
describe('Select', () => {
  beforeEach(() => {
    cy.visitStory('select--cypress');
  });

  describe('given a select inside a form', () => {
    it('should submit and react to changes', () => {
      // submit without change
      cy.findByText('buy').click();
      cy.findByText(/t-shirt size/).should('include.text', 'size M');

      // react to changes
      cy.findByLabelText(/choose a size/).click();
      cy.findByRole('option', { name: /small/i }).click();
      cy.findByText(/t-shirt size/).should('include.text', 'size S');
    });
  });

  describe('given a select with no value', () => {
    it('should display the placeholder', () => {
      cy.findByText('…').should('exist');
    });

    it('can be reset to the placeholder', () => {
      cy.findByLabelText(/choose a model/).click();
      cy.findByRole('option', { name: /model x/i }).click();
      cy.findByText(/model y/i).should('not.exist');
      cy.findByText(/model x/i).should('exist');
      cy.findByText('unset').click();
      cy.findByText('…').should('exist');
    });
  });
});



================================================
FILE: cypress/e2e/Toast.cy.ts
================================================
describe('Toast', () => {
  beforeEach(() => {
    cy.visitStory('toast--cypress');
  });

  function buttonIsFocused(identifier: number) {
    cy.findByText(`Toast button ${identifier}`).should('be.focused');
  }

  function toastIsFocused(identifier: number) {
    cy.findByTestId(`toast-${identifier}`).should('be.focused');
  }

  describe('given zero toasts', () => {
    it('should not interrupt natural tab order in the document', () => {
      cy.findByText('Focusable before viewport').focus();

      cy.realPress('Tab');
      cy.findByText('Focusable after viewport').should('be.focused');

      cy.realPress(['Shift', 'Tab']);
      cy.findByText('Focusable before viewport').should('be.focused');
    });
  });

  describe('given multiple toasts', () => {
    beforeEach(() => {
      cy.findByText('Add toast').click();
      cy.findByText('Add toast').click();
    });

    it('should have no acessibility issues', () => {
      cy.injectAxe();
      cy.checkA11y('[aria-label="Notifications (F8)"]');
    });

    it('should reverse tab order from most recent to least', () => {
      cy.findByText('Focusable before viewport').focus();

      cy.realPress('Tab');
      toastIsFocused(2);

      // Forward tab
      cy.realPress('Tab');
      buttonIsFocused(2.1);

      cy.realPress('Tab');
      buttonIsFocused(2.2);

      cy.realPress('Tab');
      toastIsFocused(1);

      cy.realPress('Tab');
      buttonIsFocused(1.1);

      cy.realPress('Tab');
      buttonIsFocused(1.2);

      // End of viewport
      cy.realPress('Tab');
      cy.findByText('Focusable after viewport').should('be.focused');

      // Backwards tab
      cy.realPress(['Shift', 'Tab']);
      buttonIsFocused(1.2);

      cy.realPress(['Shift', 'Tab']);
      buttonIsFocused(1.1);

      cy.realPress(['Shift', 'Tab']);
      toastIsFocused(1);

      cy.realPress(['Shift', 'Tab']);
      buttonIsFocused(2.2);

      cy.realPress(['Shift', 'Tab']);
      buttonIsFocused(2.1);

      cy.realPress(['Shift', 'Tab']);
      toastIsFocused(2);

      // Start of viewport
      cy.realPress(['Shift', 'Tab']);
      cy.findByText('Focusable before viewport').should('be.focused');
    });

    it('should tab forwards from viewport to latest toast or backwards into the document', () => {
      // Tab forward from viewport
      cy.realPress('F8');
      cy.realPress('Tab');
      toastIsFocused(2);

      // Tab backward from viewport
      cy.realPress('F8');
      cy.realPress(['Shift', 'Tab']);
      cy.findByText('Focusable before viewport').should('be.focused');
    });
  });
});



================================================
FILE: cypress/support/commands.js
================================================
// @ts-check
/// <reference types="cypress" />
/// <reference types="./index.d.ts" />

// ***********************************************
// This example commands.js shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add("login", (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })

Cypress.Commands.add('visitStorybook', (options) => {
  return cy.visit('iframe.html', options);
});

Cypress.Commands.add('visitStory', (storyName, options) => {
  return cy.visit(`iframe.html?id=components-${storyName}`, options);
});



================================================
FILE: cypress/support/e2e.js
================================================
// ***********************************************************
// This file is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************

// Import commands.js using ES2015 syntax:
import '@testing-library/cypress/add-commands';
import 'cypress-real-events/support';
import 'cypress-axe';
import './commands';

// Alternatively you can use CommonJS syntax:
// require('./commands')



================================================
FILE: cypress/support/index.d.ts
================================================
declare namespace Cypress {
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  interface Chainable<Subject> {
    visitStorybook(options?: Partial<Cypress.VisitOptions>): Cypress.Chainable<Cypress.AUTWindow>;
    visitStory(
      storyName: string,
      options?: Partial<Cypress.VisitOptions>,
    ): Cypress.Chainable<Cypress.AUTWindow>;
  }
}



================================================
FILE: internal/builder/builder.js
================================================
// @ts-check
import path from 'node:path';
import fs from 'node:fs';
import * as esbuild from 'esbuild';
import * as tsup from 'tsup';

/**
 * @param {string} relativePath
 */
export async function build(relativePath) {
  const packageJsonPath = path.resolve(relativePath, 'package.json');
  if (!fs.existsSync(packageJsonPath)) {
    return;
  }

  const packageJsonContents = await fs.promises.readFile(packageJsonPath, 'utf-8').catch(() => {
    console.error(`Failed to read package.json file at ${packageJsonPath}`);
    process.exit(1);
  });

  /** @type {PackageJson} */
  let packageJson;
  try {
    packageJson = JSON.parse(packageJsonContents);
  } catch {
    console.error(`Failed to parse package.json file at ${packageJsonPath}`);
    process.exit(1);
  }

  const tasks = [];
  const pkg = packageJson.name;
  const files = ['index.ts'];
  if (pkg === 'radix-ui') {
    files.push('internal.ts');
  }

  const entryPoints = files.map((file) => `${relativePath || '.'}/src/${file}`);
  const dist = `${relativePath || '.'}/dist`;

  /** @type {esbuild.BuildOptions} */
  const esbuildConfig = {
    entryPoints: entryPoints,
    external: ['@radix-ui/*'],
    packages: 'external',
    bundle: true,
    sourcemap: true,
    format: 'cjs',
    target: 'es2022',
    outdir: dist,
  };

  tasks.push(esbuild.build(esbuildConfig).then(() => console.log(`CJS: Built ${relativePath}`)));
  tasks.push(
    esbuild
      .build({
        ...esbuildConfig,
        format: 'esm',
        outExtension: { '.js': '.mjs' },
      })
      .then(() => console.log(`ESM: Built ${relativePath}`)),
  );

  // tsup is used to emit d.ts files only (esbuild can't do that).
  //
  // Notes:
  // 1. Emitting d.ts files is super slow for whatever reason.
  // 2. It could have fully replaced esbuild (as it uses that internally),
  //    but at the moment its esbuild version is somewhat outdated.
  //    It’s also harder to configure and esbuild docs are more thorough.
  tasks.push(
    tsup
      .build({
        entry: entryPoints,
        format: ['cjs', 'esm'],
        dts: { only: true },
        outDir: dist,
        silent: true,
        external: [/@radix-ui\/.+/],
      })
      .then(() => console.log(`TSC: Built ${relativePath}`)),
  );

  await Promise.all(tasks);
}

/**
 * @typedef {{ name: string }} PackageJson
 */



================================================
FILE: internal/builder/eslint.config.js
================================================
// @ts-check
import { configs } from '@repo/eslint-config';

export default configs;



================================================
FILE: internal/builder/package.json
================================================
{
  "name": "@repo/builder",
  "version": "0.0.0",
  "private": true,
  "license": "MIT",
  "type": "module",
  "main": "./builder.js",
  "exports": {
    ".": "./builder.js"
  },
  "bin": {
    "radix-build": "./radix-build.js"
  },
  "dependencies": {
    "esbuild": "^0.25.11",
    "tsup": "^8.5.0"
  },
  "devDependencies": {
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "eslint": "^9.38.0"
  }
}



================================================
FILE: internal/builder/radix-build.js
================================================
#!/usr/bin/env node
// @ts-check
import path from 'node:path';
import { build } from './builder.js';

process.on('unhandledRejection', (err) => {
  throw err;
});
process.on('SIGINT', () => process.exit(0));
process.on('SIGTERM', () => process.exit(0));

const args = process.argv.slice(2);
const relativePath = path.relative(process.cwd(), args[0] || '.');

await build(relativePath);



================================================
FILE: internal/builder/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/base.json",
  "compilerOptions": {
    "rootDir": ".",
    "allowJs": true,
    "noEmit": true
  },
  "include": ["**/*"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: internal/eslint-config/eslint.config.js
================================================
// @ts-check
import { configs } from './index.js';
export default configs;



================================================
FILE: internal/eslint-config/index.js
================================================
// @ts-check
import * as eslintJs from '@chance/eslint';
import * as typescript from '@chance/eslint/typescript';
import { globals } from '@chance/eslint/globals';

export const js = eslintJs.getConfig({ ...globals.node, ...globals.browser });
export const ts = typescript.config;

/** @type {import("eslint").Linter.Config} */
export const overrides = {
  ignores: ['dist/**', '.next/**'],
  rules: {
    'prefer-const': ['warn', { destructuring: 'all' }],
  },
};

/** @type {import("eslint").Linter.Config[]} */
export const configs = [js, ts, overrides];



================================================
FILE: internal/eslint-config/package.json
================================================
{
  "name": "@repo/eslint-config",
  "version": "0.0.0",
  "private": true,
  "license": "MIT",
  "type": "module",
  "main": "./index.js",
  "exports": {
    ".": "./index.js",
    "./react-package": "./react-package.js",
    "./vite": "./vite.js"
  },
  "scripts": {
    "lint": "eslint --max-warnings 0 ."
  },
  "dependencies": {
    "@chance/eslint": "^1.1.0",
    "eslint-plugin-react-refresh": "^0.4.24"
  },
  "devDependencies": {
    "@repo/typescript-config": "workspace:*",
    "eslint": "^9.38.0"
  },
  "peerDependencies": {
    "eslint": ">=9.18"
  }
}



================================================
FILE: internal/eslint-config/react-package.js
================================================
// @ts-check
import * as react from '@chance/eslint/react';
import * as base from './index.js';

/** @type {import("eslint").Linter.Config[]} */
export const configs = [
  base.js,
  base.ts,
  react.config,
  base.overrides,
  {
    rules: {
      'react/jsx-pascal-case': ['warn', { allowNamespace: true }],
      // TODO: enable this and fix all the errors
      'react/display-name': 'off',
      'jsx-a11y/label-has-associated-control': [
        'warn',
        {
          controlComponents: ['Checkbox'],
          depth: 3,
        },
      ],
    },
  },
  { ignores: ['**/dist/**'] },
];



================================================
FILE: internal/eslint-config/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/base.json",
  "compilerOptions": {
    "rootDir": ".",
    "outDir": "dist",
    "allowJs": true
  },
  "include": ["**/*"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: internal/eslint-config/vite.js
================================================
// @ts-check
import * as react from '@chance/eslint/react';
import reactRefresh from 'eslint-plugin-react-refresh';
import * as base from './index.js';

/** @type {import("eslint").Linter.Config[]} */
export const configs = [
  base.js,
  base.ts,
  react.config,
  base.overrides,
  {
    plugins: {
      'react-refresh': reactRefresh,
    },
    rules: {
      'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
    },
  },
  { ignores: ['**/dist/**'] },
];



================================================
FILE: internal/test-data/eslint.config.js
================================================
// @ts-check
import { configs } from '@repo/eslint-config';

export default configs;



================================================
FILE: internal/test-data/foods.ts
================================================
export const foodGroups: Array<{
  label?: string;
  foods: Array<{ value: string; label: string; disabled?: boolean }>;
}> = [
  {
    label: 'Fruits',
    foods: [
      { value: 'apple', label: 'Apple' },
      { value: 'banana', label: 'Banana' },
      { value: 'blueberry', label: 'Blueberry' },
      { value: 'grapes', label: 'Grapes' },
      { value: 'pineapple', label: 'Pineapple' },
    ],
  },
  {
    label: 'Vegetables',
    foods: [
      { value: 'aubergine', label: 'Aubergine' },
      { value: 'broccoli', label: 'Broccoli' },
      { value: 'carrot', label: 'Carrot', disabled: true },
      { value: 'courgette', label: 'Courgette' },
      { value: 'leek', label: 'Leek' },
    ],
  },
  {
    label: 'Meat',
    foods: [
      { value: 'beef', label: 'Beef' },
      { value: 'beef-with-sauce', label: 'Beef with sauce' },
      { value: 'chicken', label: 'Chicken' },
      { value: 'lamb', label: 'Lamb' },
      { value: 'pork', label: 'Pork' },
    ],
  },
  {
    foods: [
      { value: 'candies', label: 'Candies' },
      { value: 'chocolates', label: 'Chocolates' },
    ],
  },
];



================================================
FILE: internal/test-data/package.json
================================================
{
  "name": "@repo/test-data",
  "version": "0.0.0",
  "private": true,
  "license": "MIT",
  "type": "module",
  "devDependencies": {
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "eslint": "^9.38.0",
    "typescript": "^5.9.3"
  },
  "exports": {
    "./*": "./*.ts"
  },
  "scripts": {
    "lint": "eslint --max-warnings 0 .",
    "check-types": "tsc --noEmit"
  }
}



================================================
FILE: internal/test-data/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/base.json",
  "compilerOptions": {
    "rootDir": ".",
    "outDir": "dist"
  },
  "include": ["**/*"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: internal/typescript-config/base.json
================================================
{
  "$schema": "https://json.schemastore.org/tsconfig",
  "compilerOptions": {
    "declaration": true,
    "declarationMap": true,
    "esModuleInterop": true,
    "incremental": false,
    "isolatedModules": true,
    "lib": ["ES2023", "DOM", "DOM.Iterable"],
    "module": "NodeNext",
    "moduleDetection": "force",
    "moduleResolution": "NodeNext",
    "noUncheckedIndexedAccess": true,
    "resolveJsonModule": true,
    "skipLibCheck": true,
    "strict": true,
    "target": "ES2022"
  }
}



================================================
FILE: internal/typescript-config/nextjs.json
================================================
{
  "$schema": "https://json.schemastore.org/tsconfig",
  "extends": "./base.json",
  "compilerOptions": {
    "plugins": [{ "name": "next" }],
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "allowJs": true,
    "jsx": "preserve",
    "noEmit": true
  }
}



================================================
FILE: internal/typescript-config/package.json
================================================
{
  "name": "@repo/typescript-config",
  "version": "0.0.0",
  "private": true,
  "license": "MIT"
}



================================================
FILE: internal/typescript-config/react-library.json
================================================
{
  "$schema": "https://json.schemastore.org/tsconfig",
  "extends": "./base.json",
  "compilerOptions": {
    "jsx": "react-jsx",
    "module": "ESNext",
    "moduleResolution": "Bundler"
  }
}



================================================
FILE: internal/typescript-config/vite-app.json
================================================
{
  "$schema": "https://json.schemastore.org/tsconfig",
  "extends": "./base.json",
  "compilerOptions": {
    "allowImportingTsExtensions": true,
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "noEmit": true,
    "jsx": "react-jsx",
    "useDefineForClassFields": true
  }
}



================================================
FILE: internal/typescript-config/vite-node.json
================================================
{
  "$schema": "https://json.schemastore.org/tsconfig",
  "extends": "./base.json",
  "compilerOptions": {
    "allowImportingTsExtensions": true,
    "lib": ["ES2023"],
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "noEmit": true
  }
}



================================================
FILE: internal/typescript-config/react-library/index.d.ts
================================================
/// <reference types="node" />
/// <reference types="@testing-library/react" />
/// <reference types="vitest-axe/extend-expect" />
/// <reference path="../../../scripts/setup-tests.ts" />

declare module '*.module.css' {
  const classes: { [key: string]: string };
  export default classes;
}



================================================
FILE: packages/core/number/README.md
================================================
# `number`

This is an internal utility, not intended for public usage.



================================================
FILE: packages/core/number/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/core/number/package.json
================================================
{
  "name": "@radix-ui/number",
  "version": "1.1.1",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "eslint": "^9.38.0",
    "typescript": "^5.9.3"
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/core/number/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/core/number/src/index.ts
================================================
export { clamp } from './number';



================================================
FILE: packages/core/number/src/number.ts
================================================
function clamp(value: number, [min, max]: [number, number]): number {
  return Math.min(max, Math.max(min, value));
}

export { clamp };



================================================
FILE: packages/core/primitive/README.md
================================================
# `primitive`

This is an internal utility, not intended for public usage.



================================================
FILE: packages/core/primitive/CHANGELOG.md
================================================
# @radix-ui/primitive

## 1.1.3

- Added internal DOM utilities



================================================
FILE: packages/core/primitive/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

/** @type {import("eslint").Linter.Config[]} */
export default [
  ...configs,
  {
    linterOptions: { reportUnusedDisableDirectives: false },
  },
];



================================================
FILE: packages/core/primitive/package.json
================================================
{
  "name": "@radix-ui/primitive",
  "version": "1.1.3",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "eslint": "^9.38.0",
    "typescript": "^5.9.3"
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/core/primitive/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/core/primitive/src/index.ts
================================================
export * from './primitive';
export type * from './types';



================================================
FILE: packages/core/primitive/src/primitive.tsx
================================================
/* eslint-disable no-restricted-properties */

/* eslint-disable no-restricted-globals */
export const canUseDOM = !!(
  typeof window !== 'undefined' &&
  window.document &&
  window.document.createElement
);
/* eslint-enable no-restricted-globals */

export function composeEventHandlers<E extends { defaultPrevented: boolean }>(
  originalEventHandler?: (event: E) => void,
  ourEventHandler?: (event: E) => void,
  { checkForDefaultPrevented = true } = {},
) {
  return function handleEvent(event: E) {
    originalEventHandler?.(event);

    if (checkForDefaultPrevented === false || !event.defaultPrevented) {
      return ourEventHandler?.(event);
    }
  };
}

export function getOwnerWindow(element: Node | null | undefined) {
  if (!canUseDOM) {
    throw new Error('Cannot access window outside of the DOM');
  }
  // eslint-disable-next-line no-restricted-globals
  return element?.ownerDocument?.defaultView ?? window;
}

export function getOwnerDocument(element: Node | null | undefined) {
  if (!canUseDOM) {
    throw new Error('Cannot access document outside of the DOM');
  }
  // eslint-disable-next-line no-restricted-globals
  return element?.ownerDocument ?? document;
}

/**
 * Lifted from https://github.com/ariakit/ariakit/blob/main/packages/ariakit-core/src/utils/dom.ts#L37
 * MIT License, Copyright (c) AriaKit.
 */
export function getActiveElement(
  node: Node | null | undefined,
  activeDescendant = false,
): HTMLElement | null {
  const { activeElement } = getOwnerDocument(node);
  if (!activeElement?.nodeName) {
    // `activeElement` might be an empty object if we're interacting with elements
    // inside of an iframe.
    return null;
  }

  if (isFrame(activeElement) && activeElement.contentDocument) {
    return getActiveElement(activeElement.contentDocument.body, activeDescendant);
  }

  if (activeDescendant) {
    const id = activeElement.getAttribute('aria-activedescendant');
    if (id) {
      const element = getOwnerDocument(activeElement).getElementById(id);
      if (element) {
        return element;
      }
    }
  }

  return activeElement as HTMLElement | null;
}

export function isFrame(element: Element): element is HTMLIFrameElement {
  return element.tagName === 'IFRAME';
}



================================================
FILE: packages/core/primitive/src/types.ts
================================================
export type Timeout = ReturnType<typeof setTimeout>;
export type Interval = ReturnType<typeof setInterval>;
export type Immediate = ReturnType<typeof setImmediate>;



================================================
FILE: packages/core/rect/README.md
================================================
# `rect`

This is an internal utility, not intended for public usage.



================================================
FILE: packages/core/rect/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/core/rect/package.json
================================================
{
  "name": "@radix-ui/rect",
  "version": "1.1.1",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "eslint": "^9.38.0",
    "typescript": "^5.9.3"
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/core/rect/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/core/rect/src/index.ts
================================================
export { observeElementRect } from './observe-element-rect';
export type { Measurable } from './observe-element-rect';



================================================
FILE: packages/core/rect/src/observe-element-rect.ts
================================================
// Adapted from https://github.com/reach/observe-rect/tree
// MIT license, React Training

type Measurable = { getBoundingClientRect(): DOMRect };

/**
 * Observes an element's rectangle on screen (getBoundingClientRect)
 * This is useful to track elements on the screen and attach other elements
 * that might be in different layers, etc.
 */
function observeElementRect(
  /** The element whose rect to observe */
  elementToObserve: Measurable,
  /** The callback which will be called when the rect changes */
  callback: CallbackFn,
) {
  const observedData = observedElements.get(elementToObserve);

  if (observedData === undefined) {
    // add the element to the map of observed elements with its first callback
    // because this is the first time this element is observed
    observedElements.set(elementToObserve, { rect: {} as DOMRect, callbacks: [callback] });

    if (observedElements.size === 1) {
      // start the internal loop once at least 1 element is observed
      rafId = requestAnimationFrame(runLoop);
    }
  } else {
    // only add a callback for this element as it's already observed
    observedData.callbacks.push(callback);
    callback(elementToObserve.getBoundingClientRect());
  }

  return () => {
    const observedData = observedElements.get(elementToObserve);
    if (observedData === undefined) return;

    // start by removing the callback
    const index = observedData.callbacks.indexOf(callback);
    if (index > -1) {
      observedData.callbacks.splice(index, 1);
    }

    if (observedData.callbacks.length === 0) {
      // stop observing this element because there are no
      // callbacks registered for it anymore
      observedElements.delete(elementToObserve);

      if (observedElements.size === 0) {
        // stop the internal loop once no elements are observed anymore
        cancelAnimationFrame(rafId);
      }
    }
  };
}

// ========================================================================
// module internals

type CallbackFn = (rect: DOMRect) => void;

type ObservedData = {
  rect: DOMRect;
  callbacks: Array<CallbackFn>;
};

let rafId: number;
const observedElements: Map<Measurable, ObservedData> = new Map();

function runLoop() {
  const changedRectsData: Array<ObservedData> = [];

  // process all DOM reads first (getBoundingClientRect)
  observedElements.forEach((data, element) => {
    const newRect = element.getBoundingClientRect();

    // gather all the data for elements whose rects have changed
    if (!rectEquals(data.rect, newRect)) {
      data.rect = newRect;
      changedRectsData.push(data);
    }
  });

  // group DOM writes here after the DOM reads (getBoundingClientRect)
  // as DOM writes will most likely happen with the callbacks
  changedRectsData.forEach((data) => {
    data.callbacks.forEach((callback) => callback(data.rect));
  });

  rafId = requestAnimationFrame(runLoop);
}
// ========================================================================

/**
 * Returns whether 2 rects are equal in values
 */
function rectEquals(rect1: DOMRect, rect2: DOMRect) {
  return (
    rect1.width === rect2.width &&
    rect1.height === rect2.height &&
    rect1.top === rect2.top &&
    rect1.right === rect2.right &&
    rect1.bottom === rect2.bottom &&
    rect1.left === rect2.left
  );
}

export { observeElementRect };
export type { Measurable };



================================================
FILE: packages/react/accessible-icon/README.md
================================================
# `react-accessible-icon`

View docs [here](https://radix-ui.com/primitives/docs/utilities/accessible-icon).



================================================
FILE: packages/react/accessible-icon/CHANGELOG.md
================================================
# @radix-ui/react-accessible-icon

## 1.1.8

- Updated dependencies: `@radix-ui/react-visually-hidden@1.2.4`

## 1.1.7

- Updated dependencies: `@radix-ui/react-visually-hidden@1.2.3`

## 1.1.6

- Updated dependencies: `@radix-ui/react-visually-hidden@1.2.2`

## 1.1.5

- Updated dependencies: `@radix-ui/react-visually-hidden@1.2.1`

## 1.1.4

- Updated dependencies: `@radix-ui/react-visually-hidden@1.2.0`



================================================
FILE: packages/react/accessible-icon/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/accessible-icon/package.json
================================================
{
  "name": "@radix-ui/react-accessible-icon",
  "version": "1.1.8",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/react-visually-hidden": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/accessible-icon/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/accessible-icon/src/accesible-icon.test.tsx
================================================
import React from 'react';
import { axe } from 'vitest-axe';
import type { RenderResult } from '@testing-library/react';
import { cleanup, render } from '@testing-library/react';
import { AccessibleIcon } from './accessible-icon';
import { afterEach, describe, it, beforeEach, vi, expect } from 'vitest';

const LABEL_TEXT = 'Close';

const AccessibleIconTest = (props: Omit<React.ComponentProps<typeof AccessibleIcon>, 'label'>) => (
  <AccessibleIcon {...props} label={LABEL_TEXT} />
);

describe('given a default AccessibleIcon', () => {
  let rendered: RenderResult;
  let label: HTMLElement;

  afterEach(cleanup);

  beforeEach(() => {
    rendered = render(
      <AccessibleIconTest>
        <svg
          viewBox="0 0 32 32"
          width={24}
          height={24}
          fill="none"
          stroke="currentColor"
          data-testid="icon"
        >
          <path d="M2 30 L30 2 M30 30 L2 2" />
        </svg>
      </AccessibleIconTest>,
    );

    label = rendered.getByText(LABEL_TEXT);
  });

  it('should have no accessibility violations', async () => {
    expect(await axe(rendered.container)).toHaveNoViolations();
  });

  it('should have a label', () => {
    expect(label).toBeInTheDocument();
  });

  it('should add an aria-hidden attribute to the child', () => {
    const svg = rendered.getByTestId('icon');
    expect(svg.getAttribute('aria-hidden')).toBe('true');
  });

  it('should set focusable attribute on the child to false', () => {
    const svg = rendered.getByTestId('icon');
    expect(svg.getAttribute('focusable')).toBe('false');
  });
});

describe('given an AccessibleIcon without children', () => {
  it('should error', () => {
    // Even though the error is caught, it still gets printed to the console
    // so we mock that out to avoid the wall of red text.
    const spy = vi.spyOn(console, 'error');
    spy.mockImplementation(() => {});

    expect(() => render(<AccessibleIconTest />)).toThrowError();

    spy.mockRestore();
  });
});



================================================
FILE: packages/react/accessible-icon/src/accessible-icon.tsx
================================================
import * as React from 'react';
import * as VisuallyHiddenPrimitive from '@radix-ui/react-visually-hidden';

const NAME = 'AccessibleIcon';

interface AccessibleIconProps {
  children?: React.ReactNode;
  /**
   * The accessible label for the icon. This label will be visually hidden but announced to screen
   * reader users, similar to `alt` text for `img` tags.
   */
  label: string;
}

const AccessibleIcon: React.FC<AccessibleIconProps> = ({ children, label }) => {
  const child = React.Children.only(children);
  return (
    <>
      {React.cloneElement(child as React.ReactElement<React.SVGAttributes<SVGElement>>, {
        // accessibility
        'aria-hidden': 'true',
        focusable: 'false', // See: https://allyjs.io/tutorials/focusing-in-svg.html#making-svg-elements-focusable
      })}
      <VisuallyHiddenPrimitive.Root>{label}</VisuallyHiddenPrimitive.Root>
    </>
  );
};

AccessibleIcon.displayName = NAME;

const Root = AccessibleIcon;

export {
  AccessibleIcon,
  //
  Root,
};
export type { AccessibleIconProps };



================================================
FILE: packages/react/accessible-icon/src/index.ts
================================================
export {
  AccessibleIcon,
  //
  Root,
} from './accessible-icon';
export type { AccessibleIconProps } from './accessible-icon';



================================================
FILE: packages/react/accordion/README.md
================================================
# `react-accordion`

View docs [here](https://radix-ui.com/primitives/docs/components/accordion).



================================================
FILE: packages/react/accordion/CHANGELOG.md
================================================
# @radix-ui/react-accordion

## 1.2.12

- Updated dependencies: `@radix-ui/primitive@1.1.3`, `@radix-ui/react-context@1.1.3`, `@radix-ui/react-collapsible@1.1.12`, `@radix-ui/react-collection@1.1.8`, `@radix-ui/react-primitive@2.1.4`

## 1.2.11

- Replace deprecated 'ElementRef' with 'ComponentRef' (#3426)
- Updated dependencies: `@radix-ui/react-collapsible@1.1.11`, `@radix-ui/react-collection@1.1.7`, `@radix-ui/react-primitive@2.1.3`

## 1.2.10

- Updated dependencies: `@radix-ui/react-collection@1.1.6`, `@radix-ui/react-primitive@2.1.2`, `@radix-ui/react-collapsible@1.1.10`

## 1.2.9

- Updated dependencies: `@radix-ui/react-collection@1.1.5`, `@radix-ui/react-primitive@2.1.1`, `@radix-ui/react-collapsible@1.1.9`

## 1.2.8

- Updated dependencies: `@radix-ui/react-collapsible@1.1.8`

## 1.2.7

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.2`, `@radix-ui/react-collapsible@1.1.7`

## 1.2.6

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.1`, `@radix-ui/react-collapsible@1.1.6`

## 1.2.5

- Minor improvements to `useControllableState` to enhance performance, reduce surface area for bugs, and log warnings when misused (#3455)
- Updated dependencies: `@radix-ui/react-collection@1.1.4`, `@radix-ui/react-use-controllable-state@1.2.0`, `@radix-ui/react-collapsible@1.1.5`, `@radix-ui/react-primitive@2.1.0`



================================================
FILE: packages/react/accordion/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/accordion/package.json
================================================
{
  "name": "@radix-ui/react-accordion",
  "version": "1.2.12",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/primitive": "workspace:*",
    "@radix-ui/react-collapsible": "workspace:*",
    "@radix-ui/react-collection": "workspace:*",
    "@radix-ui/react-compose-refs": "workspace:*",
    "@radix-ui/react-context": "workspace:*",
    "@radix-ui/react-direction": "workspace:*",
    "@radix-ui/react-id": "workspace:*",
    "@radix-ui/react-primitive": "workspace:*",
    "@radix-ui/react-use-controllable-state": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/accordion/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/accordion/src/accordion.test.tsx
================================================
import * as React from 'react';
import { axe } from 'vitest-axe';
import type { RenderResult } from '@testing-library/react';
import { cleanup, render, fireEvent } from '@testing-library/react';
import * as Accordion from './accordion';
import type { Mock } from 'vitest';
import { afterEach, describe, it, beforeEach, vi, expect } from 'vitest';

const ITEMS = ['One', 'Two', 'Three'];

describe('given a single Accordion', () => {
  let handleValueChange: Mock;
  let rendered: RenderResult;

  afterEach(cleanup);

  describe('with default orientation=vertical', () => {
    beforeEach(() => {
      handleValueChange = vi.fn();
      rendered = render(<AccordionTest type="single" onValueChange={handleValueChange} />);
    });

    it('should have no accessibility violations in default state', async () => {
      expect(await axe(rendered.container)).toHaveNoViolations();
    });

    describe('when navigating by keyboard', () => {
      beforeEach(() => {
        const trigger = rendered.getByText('Trigger One');
        trigger.focus();
      });

      describe('on `ArrowDown`', () => {
        it('should move focus to the next trigger', () => {
          fireEvent.keyDown(document.activeElement!, { key: 'ArrowDown' });
          expect(rendered.getByText('Trigger Two')).toHaveFocus();
        });

        it('should move focus to the first item if at the end', () => {
          const trigger = rendered.getByText('Trigger Three');
          trigger.focus();
          fireEvent.keyDown(document.activeElement!, { key: 'ArrowDown' });
          expect(rendered.getByText('Trigger One')).toHaveFocus();
        });
      });

      describe('on `ArrowUp`', () => {
        it('should move focus to the previous trigger', () => {
          const trigger = rendered.getByText('Trigger Three');
          trigger.focus();
          fireEvent.keyDown(document.activeElement!, { key: 'ArrowUp' });
          expect(rendered.getByText('Trigger Two')).toHaveFocus();
        });

        it('should move focus to the last item if at the beginning', () => {
          const trigger = rendered.getByText('Trigger One');
          trigger.focus();
          fireEvent.keyDown(document.activeElement!, { key: 'ArrowUp' });
          expect(rendered.getByText('Trigger Three')).toHaveFocus();
        });
      });

      describe('on `Home`', () => {
        it('should move focus to the first trigger', () => {
          fireEvent.keyDown(document.activeElement!, { key: 'Home' });
          expect(rendered.getByText('Trigger One')).toHaveFocus();
        });
      });

      describe('on `End`', () => {
        it('should move focus to the last trigger', () => {
          fireEvent.keyDown(document.activeElement!, { key: 'End' });
          expect(rendered.getByText('Trigger Three')).toHaveFocus();
        });
      });
    });

    describe('when clicking a trigger', () => {
      let trigger: HTMLElement;
      let contentOne: HTMLElement | null;

      beforeEach(() => {
        trigger = rendered.getByText('Trigger One');
        fireEvent.click(trigger);
        contentOne = rendered.getByText('Content One');
      });

      it('should show the content', () => {
        expect(contentOne).toBeVisible();
      });

      it('should have no accessibility violations', async () => {
        expect(await axe(rendered.container)).toHaveNoViolations();
      });

      it('should call onValueChange', () => {
        expect(handleValueChange).toHaveBeenCalledWith('One');
      });

      describe('then clicking the trigger again', () => {
        beforeEach(() => {
          fireEvent.click(trigger);
        });

        it('should not close the content', () => {
          expect(contentOne).toBeVisible();
        });

        it('should not call onValueChange', () => {
          expect(handleValueChange).toHaveBeenCalledTimes(1);
        });
      });

      describe('then clicking another trigger', () => {
        beforeEach(() => {
          const trigger = rendered.getByText('Trigger Two');
          fireEvent.click(trigger);
        });

        it('should show the new content', () => {
          const contentTwo = rendered.getByText('Content Two');
          expect(contentTwo).toBeVisible();
        });

        it('should call onValueChange', () => {
          expect(handleValueChange).toHaveBeenCalledWith('Two');
        });

        it('should hide the previous content', () => {
          expect(contentOne).not.toBeVisible();
        });
      });
    });
  });

  describe('with orientation=horizontal', () => {
    describe('and default dir="ltr"', () => {
      beforeEach(() => {
        handleValueChange = vi.fn();
        rendered = render(
          <AccordionTest
            type="single"
            orientation="horizontal"
            onValueChange={handleValueChange}
          />,
        );
      });

      describe('when navigating by keyboard', () => {
        beforeEach(() => {
          const trigger = rendered.getByText('Trigger One');
          trigger.focus();
        });

        describe('on `ArrowUp`', () => {
          it('should do nothing', () => {
            fireEvent.keyDown(document.activeElement!, { key: 'ArrowUp' });
            expect(rendered.getByText('Trigger One')).toHaveFocus();
          });
        });

        describe('on `ArrowDown`', () => {
          it('should do nothing', () => {
            fireEvent.keyDown(document.activeElement!, { key: 'ArrowDown' });
            expect(rendered.getByText('Trigger One')).toHaveFocus();
          });
        });

        describe('on `ArrowRight`', () => {
          it('should move focus to the next trigger', () => {
            fireEvent.keyDown(document.activeElement!, { key: 'ArrowRight' });
            expect(rendered.getByText('Trigger Two')).toHaveFocus();
          });

          it('should move focus to the first item if at the end', () => {
            const trigger = rendered.getByText('Trigger Three');
            trigger.focus();
            fireEvent.keyDown(document.activeElement!, { key: 'ArrowRight' });
            expect(rendered.getByText('Trigger One')).toHaveFocus();
          });
        });

        describe('on `ArrowLeft`', () => {
          it('should move focus to the previous trigger', () => {
            const trigger = rendered.getByText('Trigger Three');
            trigger.focus();
            fireEvent.keyDown(document.activeElement!, { key: 'ArrowLeft' });
            expect(rendered.getByText('Trigger Two')).toHaveFocus();
          });

          it('should move focus to the last item if at the beginning', () => {
            const trigger = rendered.getByText('Trigger One');
            trigger.focus();
            fireEvent.keyDown(document.activeElement!, { key: 'ArrowLeft' });
            expect(rendered.getByText('Trigger Three')).toHaveFocus();
          });
        });

        describe('on `Home`', () => {
          it('should move focus to the first trigger', () => {
            fireEvent.keyDown(document.activeElement!, { key: 'Home' });
            expect(rendered.getByText('Trigger One')).toHaveFocus();
          });
        });

        describe('on `End`', () => {
          it('should move focus to the last trigger', () => {
            fireEvent.keyDown(document.activeElement!, { key: 'End' });
            expect(rendered.getByText('Trigger Three')).toHaveFocus();
          });
        });
      });
    });

    describe('and dir="rtl"', () => {
      beforeEach(() => {
        handleValueChange = vi.fn();
        rendered = render(
          <AccordionTest
            type="single"
            dir="rtl"
            orientation="horizontal"
            onValueChange={handleValueChange}
          />,
        );
      });

      describe('when navigating by keyboard', () => {
        beforeEach(() => {
          const trigger = rendered.getByText('Trigger One');
          trigger.focus();
        });

        describe('on `ArrowUp`', () => {
          it('should do nothing', () => {
            fireEvent.keyDown(document.activeElement!, { key: 'ArrowUp' });
            expect(rendered.getByText('Trigger One')).toHaveFocus();
          });
        });

        describe('on `ArrowDown`', () => {
          it('should do nothing', () => {
            fireEvent.keyDown(document.activeElement!, { key: 'ArrowDown' });
            expect(rendered.getByText('Trigger One')).toHaveFocus();
          });
        });

        describe('on `ArrowRight`', () => {
          it('should move focus to the previous trigger', () => {
            const trigger = rendered.getByText('Trigger Two');
            trigger.focus();
            fireEvent.keyDown(document.activeElement!, { key: 'ArrowRight' });
            expect(rendered.getByText('Trigger One')).toHaveFocus();
          });

          it('should move focus to the last item if at the beginning', () => {
            fireEvent.keyDown(document.activeElement!, { key: 'ArrowRight' });
            expect(rendered.getByText('Trigger Three')).toHaveFocus();
          });
        });

        describe('on `ArrowLeft`', () => {
          it('should move focus to the next trigger', () => {
            fireEvent.keyDown(document.activeElement!, { key: 'ArrowLeft' });
            expect(rendered.getByText('Trigger Two')).toHaveFocus();
          });

          it('should move focus to the first item if at the end', () => {
            const trigger = rendered.getByText('Trigger Three');
            trigger.focus();
            fireEvent.keyDown(document.activeElement!, { key: 'ArrowLeft' });
            expect(rendered.getByText('Trigger One')).toHaveFocus();
          });
        });

        describe('on `Home`', () => {
          it('should move focus to the first trigger', () => {
            fireEvent.keyDown(document.activeElement!, { key: 'Home' });
            expect(rendered.getByText('Trigger One')).toHaveFocus();
          });
        });

        describe('on `End`', () => {
          it('should move focus to the last trigger', () => {
            fireEvent.keyDown(document.activeElement!, { key: 'End' });
            expect(rendered.getByText('Trigger Three')).toHaveFocus();
          });
        });
      });
    });
  });
});

describe('given a multiple Accordion', () => {
  let handleValueChange: Mock;
  let rendered: RenderResult;

  afterEach(cleanup);

  beforeEach(() => {
    handleValueChange = vi.fn();
    rendered = render(<AccordionTest type="multiple" onValueChange={handleValueChange} />);
  });

  it('should have no accessibility violations in default state', async () => {
    expect(await axe(rendered.container)).toHaveNoViolations();
  });

  describe('when navigating by keyboard', () => {
    beforeEach(() => {
      rendered.getByText('Trigger One').focus();
    });

    describe('on `ArrowDown`', () => {
      it('should move focus to the next trigger', () => {
        fireEvent.keyDown(document.activeElement!, { key: 'ArrowDown' });
        expect(rendered.getByText('Trigger Two')).toHaveFocus();
      });
    });

    describe('on `ArrowUp`', () => {
      it('should move focus to the previous trigger', () => {
        fireEvent.keyDown(document.activeElement!, { key: 'ArrowUp' });
        expect(rendered.getByText('Trigger Three')).toHaveFocus();
      });
    });

    describe('on `Home`', () => {
      it('should move focus to the first trigger', () => {
        fireEvent.keyDown(document.activeElement!, { key: 'Home' });
        expect(rendered.getByText('Trigger One')).toHaveFocus();
      });
    });

    describe('on `End`', () => {
      it('should move focus to the last trigger', () => {
        fireEvent.keyDown(document.activeElement!, { key: 'End' });
        expect(rendered.getByText('Trigger Three')).toHaveFocus();
      });
    });
  });

  describe('when clicking a trigger', () => {
    let trigger: HTMLElement;
    let contentOne: HTMLElement | null;

    beforeEach(() => {
      trigger = rendered.getByText('Trigger One');
      fireEvent.click(trigger);
      contentOne = rendered.getByText('Content One');
    });

    it('should show the content', () => {
      expect(contentOne).toBeVisible();
    });

    it('should have no accessibility violations', async () => {
      expect(await axe(rendered.container)).toHaveNoViolations();
    });

    it('should call onValueChange', () => {
      expect(handleValueChange).toHaveBeenCalledWith(['One']);
    });

    describe('then clicking the trigger again', () => {
      beforeEach(() => {
        fireEvent.click(trigger);
      });

      it('should hide the content', () => {
        expect(contentOne).not.toBeVisible();
      });

      it('should call onValueChange', () => {
        expect(handleValueChange).toHaveBeenCalledWith([]);
      });
    });

    describe('then clicking another trigger', () => {
      beforeEach(() => {
        const trigger = rendered.getByText('Trigger Two');
        fireEvent.click(trigger);
      });

      it('should show the new content', () => {
        const contentTwo = rendered.getByText('Content Two');
        expect(contentTwo).toBeVisible();
      });

      it('should call onValueChange', () => {
        expect(handleValueChange).toHaveBeenCalledWith(['One', 'Two']);
      });

      it('should not hide the previous content', () => {
        expect(contentOne).toBeVisible();
      });
    });
  });
});

function AccordionTest(props: React.ComponentProps<typeof Accordion.Root>) {
  return (
    <Accordion.Root data-testid="container" {...props}>
      {ITEMS.map((val) => (
        <Accordion.Item value={val} key={val} data-testid={`item-${val.toLowerCase()}`}>
          <Accordion.Header data-testid={`header-${val.toLowerCase()}`}>
            <Accordion.Trigger>Trigger {val}</Accordion.Trigger>
          </Accordion.Header>
          <Accordion.Content>Content {val}</Accordion.Content>
        </Accordion.Item>
      ))}
    </Accordion.Root>
  );
}



================================================
FILE: packages/react/accordion/src/accordion.tsx
================================================
import React from 'react';
import { createContextScope } from '@radix-ui/react-context';
import { createCollection } from '@radix-ui/react-collection';
import { useComposedRefs } from '@radix-ui/react-compose-refs';
import { composeEventHandlers } from '@radix-ui/primitive';
import { useControllableState } from '@radix-ui/react-use-controllable-state';
import { Primitive } from '@radix-ui/react-primitive';
import * as CollapsiblePrimitive from '@radix-ui/react-collapsible';
import { createCollapsibleScope } from '@radix-ui/react-collapsible';
import { useId } from '@radix-ui/react-id';

import type { Scope } from '@radix-ui/react-context';
import { useDirection } from '@radix-ui/react-direction';

type Direction = 'ltr' | 'rtl';

/* -------------------------------------------------------------------------------------------------
 * Accordion
 * -----------------------------------------------------------------------------------------------*/

const ACCORDION_NAME = 'Accordion';
const ACCORDION_KEYS = ['Home', 'End', 'ArrowDown', 'ArrowUp', 'ArrowLeft', 'ArrowRight'];

const [Collection, useCollection, createCollectionScope] =
  createCollection<AccordionTriggerElement>(ACCORDION_NAME);

type ScopedProps<P> = P & { __scopeAccordion?: Scope };
const [createAccordionContext, createAccordionScope] = createContextScope(ACCORDION_NAME, [
  createCollectionScope,
  createCollapsibleScope,
]);
const useCollapsibleScope = createCollapsibleScope();

type AccordionElement = AccordionImplMultipleElement | AccordionImplSingleElement;
interface AccordionSingleProps extends AccordionImplSingleProps {
  type: 'single';
}
interface AccordionMultipleProps extends AccordionImplMultipleProps {
  type: 'multiple';
}

const Accordion = React.forwardRef<AccordionElement, AccordionSingleProps | AccordionMultipleProps>(
  (props: ScopedProps<AccordionSingleProps | AccordionMultipleProps>, forwardedRef) => {
    const { type, ...accordionProps } = props;
    const singleProps = accordionProps as AccordionImplSingleProps;
    const multipleProps = accordionProps as AccordionImplMultipleProps;
    return (
      <Collection.Provider scope={props.__scopeAccordion}>
        {type === 'multiple' ? (
          <AccordionImplMultiple {...multipleProps} ref={forwardedRef} />
        ) : (
          <AccordionImplSingle {...singleProps} ref={forwardedRef} />
        )}
      </Collection.Provider>
    );
  },
);

Accordion.displayName = ACCORDION_NAME;

/* -----------------------------------------------------------------------------------------------*/

type AccordionValueContextValue = {
  value: string[];
  onItemOpen(value: string): void;
  onItemClose(value: string): void;
};

const [AccordionValueProvider, useAccordionValueContext] =
  createAccordionContext<AccordionValueContextValue>(ACCORDION_NAME);

const [AccordionCollapsibleProvider, useAccordionCollapsibleContext] = createAccordionContext(
  ACCORDION_NAME,
  { collapsible: false },
);

type AccordionImplSingleElement = AccordionImplElement;
interface AccordionImplSingleProps extends AccordionImplProps {
  /**
   * The controlled stateful value of the accordion item whose content is expanded.
   */
  value?: string;
  /**
   * The value of the item whose content is expanded when the accordion is initially rendered. Use
   * `defaultValue` if you do not need to control the state of an accordion.
   */
  defaultValue?: string;
  /**
   * The callback that fires when the state of the accordion changes.
   */
  onValueChange?(value: string): void;
  /**
   * Whether an accordion item can be collapsed after it has been opened.
   * @default false
   */
  collapsible?: boolean;
}

const AccordionImplSingle = React.forwardRef<AccordionImplSingleElement, AccordionImplSingleProps>(
  (props: ScopedProps<AccordionImplSingleProps>, forwardedRef) => {
    const {
      value: valueProp,
      defaultValue,
      onValueChange = () => {},
      collapsible = false,
      ...accordionSingleProps
    } = props;

    const [value, setValue] = useControllableState({
      prop: valueProp,
      defaultProp: defaultValue ?? '',
      onChange: onValueChange,
      caller: ACCORDION_NAME,
    });

    return (
      <AccordionValueProvider
        scope={props.__scopeAccordion}
        value={React.useMemo(() => (value ? [value] : []), [value])}
        onItemOpen={setValue}
        onItemClose={React.useCallback(() => collapsible && setValue(''), [collapsible, setValue])}
      >
        <AccordionCollapsibleProvider scope={props.__scopeAccordion} collapsible={collapsible}>
          <AccordionImpl {...accordionSingleProps} ref={forwardedRef} />
        </AccordionCollapsibleProvider>
      </AccordionValueProvider>
    );
  },
);

/* -----------------------------------------------------------------------------------------------*/

type AccordionImplMultipleElement = AccordionImplElement;
interface AccordionImplMultipleProps extends AccordionImplProps {
  /**
   * The controlled stateful value of the accordion items whose contents are expanded.
   */
  value?: string[];
  /**
   * The value of the items whose contents are expanded when the accordion is initially rendered. Use
   * `defaultValue` if you do not need to control the state of an accordion.
   */
  defaultValue?: string[];
  /**
   * The callback that fires when the state of the accordion changes.
   */
  onValueChange?(value: string[]): void;
}

const AccordionImplMultiple = React.forwardRef<
  AccordionImplMultipleElement,
  AccordionImplMultipleProps
>((props: ScopedProps<AccordionImplMultipleProps>, forwardedRef) => {
  const {
    value: valueProp,
    defaultValue,
    onValueChange = () => {},
    ...accordionMultipleProps
  } = props;

  const [value, setValue] = useControllableState({
    prop: valueProp,
    defaultProp: defaultValue ?? [],
    onChange: onValueChange,
    caller: ACCORDION_NAME,
  });

  const handleItemOpen = React.useCallback(
    (itemValue: string) => setValue((prevValue = []) => [...prevValue, itemValue]),
    [setValue],
  );

  const handleItemClose = React.useCallback(
    (itemValue: string) =>
      setValue((prevValue = []) => prevValue.filter((value) => value !== itemValue)),
    [setValue],
  );

  return (
    <AccordionValueProvider
      scope={props.__scopeAccordion}
      value={value}
      onItemOpen={handleItemOpen}
      onItemClose={handleItemClose}
    >
      <AccordionCollapsibleProvider scope={props.__scopeAccordion} collapsible={true}>
        <AccordionImpl {...accordionMultipleProps} ref={forwardedRef} />
      </AccordionCollapsibleProvider>
    </AccordionValueProvider>
  );
});

/* -----------------------------------------------------------------------------------------------*/

type AccordionImplContextValue = {
  disabled?: boolean;
  direction: AccordionImplProps['dir'];
  orientation: AccordionImplProps['orientation'];
};

const [AccordionImplProvider, useAccordionContext] =
  createAccordionContext<AccordionImplContextValue>(ACCORDION_NAME);

type AccordionImplElement = React.ComponentRef<typeof Primitive.div>;
type PrimitiveDivProps = React.ComponentPropsWithoutRef<typeof Primitive.div>;
interface AccordionImplProps extends PrimitiveDivProps {
  /**
   * Whether or not an accordion is disabled from user interaction.
   *
   * @defaultValue false
   */
  disabled?: boolean;
  /**
   * The layout in which the Accordion operates.
   * @default vertical
   */
  orientation?: React.AriaAttributes['aria-orientation'];
  /**
   * The language read direction.
   */
  dir?: Direction;
}

const AccordionImpl = React.forwardRef<AccordionImplElement, AccordionImplProps>(
  (props: ScopedProps<AccordionImplProps>, forwardedRef) => {
    const { __scopeAccordion, disabled, dir, orientation = 'vertical', ...accordionProps } = props;
    const accordionRef = React.useRef<AccordionImplElement>(null);
    const composedRefs = useComposedRefs(accordionRef, forwardedRef);
    const getItems = useCollection(__scopeAccordion);
    const direction = useDirection(dir);
    const isDirectionLTR = direction === 'ltr';

    const handleKeyDown = composeEventHandlers(props.onKeyDown, (event) => {
      if (!ACCORDION_KEYS.includes(event.key)) return;
      const target = event.target as HTMLElement;
      const triggerCollection = getItems().filter((item) => !item.ref.current?.disabled);
      const triggerIndex = triggerCollection.findIndex((item) => item.ref.current === target);
      const triggerCount = triggerCollection.length;

      if (triggerIndex === -1) return;

      // Prevents page scroll while user is navigating
      event.preventDefault();

      let nextIndex = triggerIndex;
      const homeIndex = 0;
      const endIndex = triggerCount - 1;

      const moveNext = () => {
        nextIndex = triggerIndex + 1;
        if (nextIndex > endIndex) {
          nextIndex = homeIndex;
        }
      };

      const movePrev = () => {
        nextIndex = triggerIndex - 1;
        if (nextIndex < homeIndex) {
          nextIndex = endIndex;
        }
      };

      switch (event.key) {
        case 'Home':
          nextIndex = homeIndex;
          break;
        case 'End':
          nextIndex = endIndex;
          break;
        case 'ArrowRight':
          if (orientation === 'horizontal') {
            if (isDirectionLTR) {
              moveNext();
            } else {
              movePrev();
            }
          }
          break;
        case 'ArrowDown':
          if (orientation === 'vertical') {
            moveNext();
          }
          break;
        case 'ArrowLeft':
          if (orientation === 'horizontal') {
            if (isDirectionLTR) {
              movePrev();
            } else {
              moveNext();
            }
          }
          break;
        case 'ArrowUp':
          if (orientation === 'vertical') {
            movePrev();
          }
          break;
      }

      const clampedIndex = nextIndex % triggerCount;
      triggerCollection[clampedIndex]!.ref.current?.focus();
    });

    return (
      <AccordionImplProvider
        scope={__scopeAccordion}
        disabled={disabled}
        direction={dir}
        orientation={orientation}
      >
        <Collection.Slot scope={__scopeAccordion}>
          <Primitive.div
            {...accordionProps}
            data-orientation={orientation}
            ref={composedRefs}
            onKeyDown={disabled ? undefined : handleKeyDown}
          />
        </Collection.Slot>
      </AccordionImplProvider>
    );
  },
);

/* -------------------------------------------------------------------------------------------------
 * AccordionItem
 * -----------------------------------------------------------------------------------------------*/

const ITEM_NAME = 'AccordionItem';

type AccordionItemContextValue = { open?: boolean; disabled?: boolean; triggerId: string };
const [AccordionItemProvider, useAccordionItemContext] =
  createAccordionContext<AccordionItemContextValue>(ITEM_NAME);

type AccordionItemElement = React.ComponentRef<typeof CollapsiblePrimitive.Root>;
type CollapsibleProps = React.ComponentPropsWithoutRef<typeof CollapsiblePrimitive.Root>;
interface AccordionItemProps
  extends Omit<CollapsibleProps, 'open' | 'defaultOpen' | 'onOpenChange'> {
  /**
   * Whether or not an accordion item is disabled from user interaction.
   *
   * @defaultValue false
   */
  disabled?: boolean;
  /**
   * A string value for the accordion item. All items within an accordion should use a unique value.
   */
  value: string;
}

/**
 * `AccordionItem` contains all of the parts of a collapsible section inside of an `Accordion`.
 */
const AccordionItem = React.forwardRef<AccordionItemElement, AccordionItemProps>(
  (props: ScopedProps<AccordionItemProps>, forwardedRef) => {
    const { __scopeAccordion, value, ...accordionItemProps } = props;
    const accordionContext = useAccordionContext(ITEM_NAME, __scopeAccordion);
    const valueContext = useAccordionValueContext(ITEM_NAME, __scopeAccordion);
    const collapsibleScope = useCollapsibleScope(__scopeAccordion);
    const triggerId = useId();
    const open = (value && valueContext.value.includes(value)) || false;
    const disabled = accordionContext.disabled || props.disabled;

    return (
      <AccordionItemProvider
        scope={__scopeAccordion}
        open={open}
        disabled={disabled}
        triggerId={triggerId}
      >
        <CollapsiblePrimitive.Root
          data-orientation={accordionContext.orientation}
          data-state={getState(open)}
          {...collapsibleScope}
          {...accordionItemProps}
          ref={forwardedRef}
          disabled={disabled}
          open={open}
          onOpenChange={(open) => {
            if (open) {
              valueContext.onItemOpen(value);
            } else {
              valueContext.onItemClose(value);
            }
          }}
        />
      </AccordionItemProvider>
    );
  },
);

AccordionItem.displayName = ITEM_NAME;

/* -------------------------------------------------------------------------------------------------
 * AccordionHeader
 * -----------------------------------------------------------------------------------------------*/

const HEADER_NAME = 'AccordionHeader';

type AccordionHeaderElement = React.ComponentRef<typeof Primitive.h3>;
type PrimitiveHeading3Props = React.ComponentPropsWithoutRef<typeof Primitive.h3>;
interface AccordionHeaderProps extends PrimitiveHeading3Props {}

/**
 * `AccordionHeader` contains the content for the parts of an `AccordionItem` that will be visible
 * whether or not its content is collapsed.
 */
const AccordionHeader = React.forwardRef<AccordionHeaderElement, AccordionHeaderProps>(
  (props: ScopedProps<AccordionHeaderProps>, forwardedRef) => {
    const { __scopeAccordion, ...headerProps } = props;
    const accordionContext = useAccordionContext(ACCORDION_NAME, __scopeAccordion);
    const itemContext = useAccordionItemContext(HEADER_NAME, __scopeAccordion);
    return (
      <Primitive.h3
        data-orientation={accordionContext.orientation}
        data-state={getState(itemContext.open)}
        data-disabled={itemContext.disabled ? '' : undefined}
        {...headerProps}
        ref={forwardedRef}
      />
    );
  },
);

AccordionHeader.displayName = HEADER_NAME;

/* -------------------------------------------------------------------------------------------------
 * AccordionTrigger
 * -----------------------------------------------------------------------------------------------*/

const TRIGGER_NAME = 'AccordionTrigger';

type AccordionTriggerElement = React.ComponentRef<typeof CollapsiblePrimitive.Trigger>;
type CollapsibleTriggerProps = React.ComponentPropsWithoutRef<typeof CollapsiblePrimitive.Trigger>;
interface AccordionTriggerProps extends CollapsibleTriggerProps {}

/**
 * `AccordionTrigger` is the trigger that toggles the collapsed state of an `AccordionItem`. It
 * should always be nested inside of an `AccordionHeader`.
 */
const AccordionTrigger = React.forwardRef<AccordionTriggerElement, AccordionTriggerProps>(
  (props: ScopedProps<AccordionTriggerProps>, forwardedRef) => {
    const { __scopeAccordion, ...triggerProps } = props;
    const accordionContext = useAccordionContext(ACCORDION_NAME, __scopeAccordion);
    const itemContext = useAccordionItemContext(TRIGGER_NAME, __scopeAccordion);
    const collapsibleContext = useAccordionCollapsibleContext(TRIGGER_NAME, __scopeAccordion);
    const collapsibleScope = useCollapsibleScope(__scopeAccordion);
    return (
      <Collection.ItemSlot scope={__scopeAccordion}>
        <CollapsiblePrimitive.Trigger
          aria-disabled={(itemContext.open && !collapsibleContext.collapsible) || undefined}
          data-orientation={accordionContext.orientation}
          id={itemContext.triggerId}
          {...collapsibleScope}
          {...triggerProps}
          ref={forwardedRef}
        />
      </Collection.ItemSlot>
    );
  },
);

AccordionTrigger.displayName = TRIGGER_NAME;

/* -------------------------------------------------------------------------------------------------
 * AccordionContent
 * -----------------------------------------------------------------------------------------------*/

const CONTENT_NAME = 'AccordionContent';

type AccordionContentElement = React.ComponentRef<typeof CollapsiblePrimitive.Content>;
type CollapsibleContentProps = React.ComponentPropsWithoutRef<typeof CollapsiblePrimitive.Content>;
interface AccordionContentProps extends CollapsibleContentProps {}

/**
 * `AccordionContent` contains the collapsible content for an `AccordionItem`.
 */
const AccordionContent = React.forwardRef<AccordionContentElement, AccordionContentProps>(
  (props: ScopedProps<AccordionContentProps>, forwardedRef) => {
    const { __scopeAccordion, ...contentProps } = props;
    const accordionContext = useAccordionContext(ACCORDION_NAME, __scopeAccordion);
    const itemContext = useAccordionItemContext(CONTENT_NAME, __scopeAccordion);
    const collapsibleScope = useCollapsibleScope(__scopeAccordion);
    return (
      <CollapsiblePrimitive.Content
        role="region"
        aria-labelledby={itemContext.triggerId}
        data-orientation={accordionContext.orientation}
        {...collapsibleScope}
        {...contentProps}
        ref={forwardedRef}
        style={{
          ['--radix-accordion-content-height' as any]: 'var(--radix-collapsible-content-height)',
          ['--radix-accordion-content-width' as any]: 'var(--radix-collapsible-content-width)',
          ...props.style,
        }}
      />
    );
  },
);

AccordionContent.displayName = CONTENT_NAME;

/* -----------------------------------------------------------------------------------------------*/

function getState(open?: boolean) {
  return open ? 'open' : 'closed';
}

const Root = Accordion;
const Item = AccordionItem;
const Header = AccordionHeader;
const Trigger = AccordionTrigger;
const Content = AccordionContent;

export {
  createAccordionScope,
  //
  Accordion,
  AccordionItem,
  AccordionHeader,
  AccordionTrigger,
  AccordionContent,
  //
  Root,
  Item,
  Header,
  Trigger,
  Content,
};
export type {
  AccordionSingleProps,
  AccordionMultipleProps,
  AccordionItemProps,
  AccordionHeaderProps,
  AccordionTriggerProps,
  AccordionContentProps,
};



================================================
FILE: packages/react/accordion/src/index.ts
================================================
'use client';
export {
  createAccordionScope,
  //
  Accordion,
  AccordionItem,
  AccordionHeader,
  AccordionTrigger,
  AccordionContent,
  //
  Root,
  Item,
  Header,
  Trigger,
  Content,
} from './accordion';
export type {
  AccordionSingleProps,
  AccordionMultipleProps,
  AccordionItemProps,
  AccordionHeaderProps,
  AccordionTriggerProps,
  AccordionContentProps,
} from './accordion';



================================================
FILE: packages/react/alert-dialog/README.md
================================================
# `react-alert-dialog`

View docs [here](https://radix-ui.com/primitives/docs/components/alert-dialog).



================================================
FILE: packages/react/alert-dialog/CHANGELOG.md
================================================
# @radix-ui/react-alert-dialog

## 1.1.15

- Updated dependencies: `@radix-ui/react-slot@1.2.4`, `@radix-ui/primitive@1.1.3`, `@radix-ui/react-context@1.1.3`, `@radix-ui/react-dialog@1.1.15`, `@radix-ui/react-primitive@2.1.4`

## 1.1.14

- Replace deprecated 'ElementRef' with 'ComponentRef' (#3426)
- Updated dependencies: `@radix-ui/react-dialog@1.1.14`, `@radix-ui/react-slot@1.2.3`, `@radix-ui/react-primitive@2.1.3`

## 1.1.13

- Updated dependencies: `@radix-ui/react-slot@1.2.2`, `@radix-ui/react-dialog@1.1.13`, `@radix-ui/react-primitive@2.1.2`

## 1.1.12

- Updated dependencies: `@radix-ui/react-slot@1.2.1`, `@radix-ui/react-dialog@1.1.12`, `@radix-ui/react-primitive@2.1.1`

## 1.1.11

- Updated dependencies: `@radix-ui/react-dialog@1.1.11`

## 1.1.10

- Updated dependencies: `@radix-ui/react-dialog@1.1.10`

## 1.1.9

- Updated dependencies: `@radix-ui/react-dialog@1.1.9`

## 1.1.8

- Updated dependencies: `@radix-ui/react-dialog@1.1.8`, `@radix-ui/react-primitive@2.1.0`



================================================
FILE: packages/react/alert-dialog/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/alert-dialog/package.json
================================================
{
  "name": "@radix-ui/react-alert-dialog",
  "version": "1.1.15",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "src",
    "dist"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/primitive": "workspace:*",
    "@radix-ui/react-compose-refs": "workspace:*",
    "@radix-ui/react-context": "workspace:*",
    "@radix-ui/react-dialog": "workspace:*",
    "@radix-ui/react-primitive": "workspace:*",
    "@radix-ui/react-slot": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/alert-dialog/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/alert-dialog/src/alert-dialog.test.tsx
================================================
import React from 'react';
import { axe } from 'vitest-axe';
import type { RenderResult } from '@testing-library/react';
import { cleanup, render, fireEvent } from '@testing-library/react';
import * as AlertDialog from './alert-dialog';
import { afterEach, describe, it, beforeEach, expect } from 'vitest';

const OPEN_TEXT = 'Open';
const CANCEL_TEXT = 'Cancel';
const ACTION_TEXT = 'Do it';
const TITLE_TEXT = 'Warning';
const DESC_TEXT = 'This is a warning';
const OVERLAY_TEST_ID = 'test-overlay';

const DialogTest = (props: React.ComponentProps<typeof AlertDialog.Root>) => (
  <AlertDialog.Root {...props}>
    <AlertDialog.Trigger>{OPEN_TEXT}</AlertDialog.Trigger>
    <AlertDialog.Overlay data-testid={OVERLAY_TEST_ID} />
    <AlertDialog.Content>
      <AlertDialog.Title>{TITLE_TEXT}</AlertDialog.Title>
      <AlertDialog.Description>{DESC_TEXT}</AlertDialog.Description>
      <AlertDialog.Cancel>{CANCEL_TEXT}</AlertDialog.Cancel>
      <AlertDialog.Action>{ACTION_TEXT}</AlertDialog.Action>
    </AlertDialog.Content>
  </AlertDialog.Root>
);

describe('given a default Dialog', () => {
  let rendered: RenderResult;
  let title: HTMLElement;
  let trigger: HTMLElement;
  let cancelButton: HTMLElement;

  afterEach(cleanup);

  beforeEach(() => {
    rendered = render(<DialogTest />);
    trigger = rendered.getByText(OPEN_TEXT);
  });

  it('should have no accessibility violations in default state', async () => {
    expect(await axe(rendered.container)).toHaveNoViolations();
  });

  describe('after clicking the trigger', () => {
    beforeEach(() => {
      fireEvent.click(trigger);
      title = rendered.getByText(TITLE_TEXT);
      cancelButton = rendered.getByText(CANCEL_TEXT);
    });

    it('should open the content', () => {
      expect(title).toBeVisible();
    });

    it('should have no accessibility violations when open', async () => {
      expect(await axe(rendered.container)).toHaveNoViolations();
    });

    it('should focus the cancel button', () => {
      expect(cancelButton).toHaveFocus();
    });
  });
});



================================================
FILE: packages/react/alert-dialog/src/alert-dialog.tsx
================================================
import * as React from 'react';
import { createContextScope } from '@radix-ui/react-context';
import { useComposedRefs } from '@radix-ui/react-compose-refs';
import * as DialogPrimitive from '@radix-ui/react-dialog';
import { createDialogScope } from '@radix-ui/react-dialog';
import { composeEventHandlers } from '@radix-ui/primitive';
import { createSlottable } from '@radix-ui/react-slot';

import type { Scope } from '@radix-ui/react-context';

/* -------------------------------------------------------------------------------------------------
 * AlertDialog
 * -----------------------------------------------------------------------------------------------*/

const ROOT_NAME = 'AlertDialog';

type ScopedProps<P> = P & { __scopeAlertDialog?: Scope };
const [createAlertDialogContext, createAlertDialogScope] = createContextScope(ROOT_NAME, [
  createDialogScope,
]);
const useDialogScope = createDialogScope();

type DialogProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Root>;
interface AlertDialogProps extends Omit<DialogProps, 'modal'> {}

const AlertDialog: React.FC<AlertDialogProps> = (props: ScopedProps<AlertDialogProps>) => {
  const { __scopeAlertDialog, ...alertDialogProps } = props;
  const dialogScope = useDialogScope(__scopeAlertDialog);
  return <DialogPrimitive.Root {...dialogScope} {...alertDialogProps} modal={true} />;
};

AlertDialog.displayName = ROOT_NAME;

/* -------------------------------------------------------------------------------------------------
 * AlertDialogTrigger
 * -----------------------------------------------------------------------------------------------*/
const TRIGGER_NAME = 'AlertDialogTrigger';

type AlertDialogTriggerElement = React.ComponentRef<typeof DialogPrimitive.Trigger>;
type DialogTriggerProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Trigger>;
interface AlertDialogTriggerProps extends DialogTriggerProps {}

const AlertDialogTrigger = React.forwardRef<AlertDialogTriggerElement, AlertDialogTriggerProps>(
  (props: ScopedProps<AlertDialogTriggerProps>, forwardedRef) => {
    const { __scopeAlertDialog, ...triggerProps } = props;
    const dialogScope = useDialogScope(__scopeAlertDialog);
    return <DialogPrimitive.Trigger {...dialogScope} {...triggerProps} ref={forwardedRef} />;
  },
);

AlertDialogTrigger.displayName = TRIGGER_NAME;

/* -------------------------------------------------------------------------------------------------
 * AlertDialogPortal
 * -----------------------------------------------------------------------------------------------*/

const PORTAL_NAME = 'AlertDialogPortal';

type DialogPortalProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Portal>;
interface AlertDialogPortalProps extends DialogPortalProps {}

const AlertDialogPortal: React.FC<AlertDialogPortalProps> = (
  props: ScopedProps<AlertDialogPortalProps>,
) => {
  const { __scopeAlertDialog, ...portalProps } = props;
  const dialogScope = useDialogScope(__scopeAlertDialog);
  return <DialogPrimitive.Portal {...dialogScope} {...portalProps} />;
};

AlertDialogPortal.displayName = PORTAL_NAME;

/* -------------------------------------------------------------------------------------------------
 * AlertDialogOverlay
 * -----------------------------------------------------------------------------------------------*/

const OVERLAY_NAME = 'AlertDialogOverlay';

type AlertDialogOverlayElement = React.ComponentRef<typeof DialogPrimitive.Overlay>;
type DialogOverlayProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>;
interface AlertDialogOverlayProps extends DialogOverlayProps {}

const AlertDialogOverlay = React.forwardRef<AlertDialogOverlayElement, AlertDialogOverlayProps>(
  (props: ScopedProps<AlertDialogOverlayProps>, forwardedRef) => {
    const { __scopeAlertDialog, ...overlayProps } = props;
    const dialogScope = useDialogScope(__scopeAlertDialog);
    return <DialogPrimitive.Overlay {...dialogScope} {...overlayProps} ref={forwardedRef} />;
  },
);

AlertDialogOverlay.displayName = OVERLAY_NAME;

/* -------------------------------------------------------------------------------------------------
 * AlertDialogContent
 * -----------------------------------------------------------------------------------------------*/

const CONTENT_NAME = 'AlertDialogContent';

type AlertDialogContentContextValue = {
  cancelRef: React.MutableRefObject<AlertDialogCancelElement | null>;
};

const [AlertDialogContentProvider, useAlertDialogContentContext] =
  createAlertDialogContext<AlertDialogContentContextValue>(CONTENT_NAME);

type AlertDialogContentElement = React.ComponentRef<typeof DialogPrimitive.Content>;
type DialogContentProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>;
interface AlertDialogContentProps
  extends Omit<DialogContentProps, 'onPointerDownOutside' | 'onInteractOutside'> {}

const Slottable = createSlottable('AlertDialogContent');

const AlertDialogContent = React.forwardRef<AlertDialogContentElement, AlertDialogContentProps>(
  (props: ScopedProps<AlertDialogContentProps>, forwardedRef) => {
    const { __scopeAlertDialog, children, ...contentProps } = props;
    const dialogScope = useDialogScope(__scopeAlertDialog);
    const contentRef = React.useRef<AlertDialogContentElement>(null);
    const composedRefs = useComposedRefs(forwardedRef, contentRef);
    const cancelRef = React.useRef<AlertDialogCancelElement | null>(null);

    return (
      <DialogPrimitive.WarningProvider
        contentName={CONTENT_NAME}
        titleName={TITLE_NAME}
        docsSlug="alert-dialog"
      >
        <AlertDialogContentProvider scope={__scopeAlertDialog} cancelRef={cancelRef}>
          <DialogPrimitive.Content
            role="alertdialog"
            {...dialogScope}
            {...contentProps}
            ref={composedRefs}
            onOpenAutoFocus={composeEventHandlers(contentProps.onOpenAutoFocus, (event) => {
              event.preventDefault();
              cancelRef.current?.focus({ preventScroll: true });
            })}
            onPointerDownOutside={(event) => event.preventDefault()}
            onInteractOutside={(event) => event.preventDefault()}
          >
            {/**
             * We have to use `Slottable` here as we cannot wrap the `AlertDialogContentProvider`
             * around everything, otherwise the `DescriptionWarning` would be rendered straight away.
             * This is because we want the accessibility checks to run only once the content is actually
             * open and that behaviour is already encapsulated in `DialogContent`.
             */}
            <Slottable>{children}</Slottable>
            {process.env.NODE_ENV === 'development' && (
              <DescriptionWarning contentRef={contentRef} />
            )}
          </DialogPrimitive.Content>
        </AlertDialogContentProvider>
      </DialogPrimitive.WarningProvider>
    );
  },
);

AlertDialogContent.displayName = CONTENT_NAME;

/* -------------------------------------------------------------------------------------------------
 * AlertDialogTitle
 * -----------------------------------------------------------------------------------------------*/

const TITLE_NAME = 'AlertDialogTitle';

type AlertDialogTitleElement = React.ComponentRef<typeof DialogPrimitive.Title>;
type DialogTitleProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>;
interface AlertDialogTitleProps extends DialogTitleProps {}

const AlertDialogTitle = React.forwardRef<AlertDialogTitleElement, AlertDialogTitleProps>(
  (props: ScopedProps<AlertDialogTitleProps>, forwardedRef) => {
    const { __scopeAlertDialog, ...titleProps } = props;
    const dialogScope = useDialogScope(__scopeAlertDialog);
    return <DialogPrimitive.Title {...dialogScope} {...titleProps} ref={forwardedRef} />;
  },
);

AlertDialogTitle.displayName = TITLE_NAME;

/* -------------------------------------------------------------------------------------------------
 * AlertDialogDescription
 * -----------------------------------------------------------------------------------------------*/

const DESCRIPTION_NAME = 'AlertDialogDescription';

type AlertDialogDescriptionElement = React.ComponentRef<typeof DialogPrimitive.Description>;
type DialogDescriptionProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>;
interface AlertDialogDescriptionProps extends DialogDescriptionProps {}

const AlertDialogDescription = React.forwardRef<
  AlertDialogDescriptionElement,
  AlertDialogDescriptionProps
>((props: ScopedProps<AlertDialogDescriptionProps>, forwardedRef) => {
  const { __scopeAlertDialog, ...descriptionProps } = props;
  const dialogScope = useDialogScope(__scopeAlertDialog);
  return <DialogPrimitive.Description {...dialogScope} {...descriptionProps} ref={forwardedRef} />;
});

AlertDialogDescription.displayName = DESCRIPTION_NAME;

/* -------------------------------------------------------------------------------------------------
 * AlertDialogAction
 * -----------------------------------------------------------------------------------------------*/

const ACTION_NAME = 'AlertDialogAction';

type AlertDialogActionElement = React.ComponentRef<typeof DialogPrimitive.Close>;
type DialogCloseProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Close>;
interface AlertDialogActionProps extends DialogCloseProps {}

const AlertDialogAction = React.forwardRef<AlertDialogActionElement, AlertDialogActionProps>(
  (props: ScopedProps<AlertDialogActionProps>, forwardedRef) => {
    const { __scopeAlertDialog, ...actionProps } = props;
    const dialogScope = useDialogScope(__scopeAlertDialog);
    return <DialogPrimitive.Close {...dialogScope} {...actionProps} ref={forwardedRef} />;
  },
);

AlertDialogAction.displayName = ACTION_NAME;

/* -------------------------------------------------------------------------------------------------
 * AlertDialogCancel
 * -----------------------------------------------------------------------------------------------*/

const CANCEL_NAME = 'AlertDialogCancel';

type AlertDialogCancelElement = React.ComponentRef<typeof DialogPrimitive.Close>;
interface AlertDialogCancelProps extends DialogCloseProps {}

const AlertDialogCancel = React.forwardRef<AlertDialogCancelElement, AlertDialogCancelProps>(
  (props: ScopedProps<AlertDialogCancelProps>, forwardedRef) => {
    const { __scopeAlertDialog, ...cancelProps } = props;
    const { cancelRef } = useAlertDialogContentContext(CANCEL_NAME, __scopeAlertDialog);
    const dialogScope = useDialogScope(__scopeAlertDialog);
    const ref = useComposedRefs(forwardedRef, cancelRef);
    return <DialogPrimitive.Close {...dialogScope} {...cancelProps} ref={ref} />;
  },
);

AlertDialogCancel.displayName = CANCEL_NAME;

/* ---------------------------------------------------------------------------------------------- */

type DescriptionWarningProps = {
  contentRef: React.RefObject<AlertDialogContentElement | null>;
};

const DescriptionWarning: React.FC<DescriptionWarningProps> = ({ contentRef }) => {
  const MESSAGE = `\`${CONTENT_NAME}\` requires a description for the component to be accessible for screen reader users.

You can add a description to the \`${CONTENT_NAME}\` by passing a \`${DESCRIPTION_NAME}\` component as a child, which also benefits sighted users by adding visible context to the dialog.

Alternatively, you can use your own component as a description by assigning it an \`id\` and passing the same value to the \`aria-describedby\` prop in \`${CONTENT_NAME}\`. If the description is confusing or duplicative for sighted users, you can use the \`@radix-ui/react-visually-hidden\` primitive as a wrapper around your description component.

For more information, see https://radix-ui.com/primitives/docs/components/alert-dialog`;

  React.useEffect(() => {
    const hasDescription = document.getElementById(
      contentRef.current?.getAttribute('aria-describedby')!,
    );
    if (!hasDescription) console.warn(MESSAGE);
  }, [MESSAGE, contentRef]);

  return null;
};

const Root = AlertDialog;
const Trigger = AlertDialogTrigger;
const Portal = AlertDialogPortal;
const Overlay = AlertDialogOverlay;
const Content = AlertDialogContent;
const Action = AlertDialogAction;
const Cancel = AlertDialogCancel;
const Title = AlertDialogTitle;
const Description = AlertDialogDescription;

export {
  createAlertDialogScope,
  //
  AlertDialog,
  AlertDialogTrigger,
  AlertDialogPortal,
  AlertDialogOverlay,
  AlertDialogContent,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogTitle,
  AlertDialogDescription,
  //
  Root,
  Trigger,
  Portal,
  Overlay,
  Content,
  Action,
  Cancel,
  Title,
  Description,
};
export type {
  AlertDialogProps,
  AlertDialogTriggerProps,
  AlertDialogPortalProps,
  AlertDialogOverlayProps,
  AlertDialogContentProps,
  AlertDialogActionProps,
  AlertDialogCancelProps,
  AlertDialogTitleProps,
  AlertDialogDescriptionProps,
};



================================================
FILE: packages/react/alert-dialog/src/index.ts
================================================
'use client';
export {
  createAlertDialogScope,
  //
  AlertDialog,
  AlertDialogTrigger,
  AlertDialogPortal,
  AlertDialogOverlay,
  AlertDialogContent,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogTitle,
  AlertDialogDescription,
  //
  Root,
  Trigger,
  Portal,
  Overlay,
  Content,
  Action,
  Cancel,
  Title,
  Description,
} from './alert-dialog';
export type {
  AlertDialogProps,
  AlertDialogTriggerProps,
  AlertDialogPortalProps,
  AlertDialogOverlayProps,
  AlertDialogContentProps,
  AlertDialogActionProps,
  AlertDialogCancelProps,
  AlertDialogTitleProps,
  AlertDialogDescriptionProps,
} from './alert-dialog';



================================================
FILE: packages/react/announce/README.md
================================================
# `react-announce`

View docs [here](https://radix-ui.com/primitives/docs/utilities/announce).



================================================
FILE: packages/react/announce/CHANGELOG.md
================================================
# @radix-ui/react-announce

## 0.2.8

- Updated dependencies: `@radix-ui/react-primitive@2.1.4`

## 0.2.7

- Replace deprecated 'ElementRef' with 'ComponentRef' (#3426)
- Updated dependencies: `@radix-ui/react-primitive@2.1.3`

## 0.2.6

- Updated dependencies: `@radix-ui/react-primitive@2.1.2`

## 0.2.5

- Updated dependencies: `@radix-ui/react-primitive@2.1.1`

## 0.2.4

- Updated dependencies: `@radix-ui/react-primitive@2.1.0`



================================================
FILE: packages/react/announce/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/announce/package.json
================================================
{
  "name": "@radix-ui/react-announce",
  "version": "0.2.8",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/react-compose-refs": "workspace:*",
    "@radix-ui/react-primitive": "workspace:*",
    "@radix-ui/react-use-layout-effect": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/announce/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/announce/src/announce.tsx
================================================
import * as React from 'react';
import ReactDOM from 'react-dom';
import { useComposedRefs } from '@radix-ui/react-compose-refs';
import { Primitive } from '@radix-ui/react-primitive';
import { useLayoutEffect } from '@radix-ui/react-use-layout-effect';

type RegionType = 'polite' | 'assertive' | 'off';
type RegionRole = 'status' | 'alert' | 'log' | 'none';

const ROLES: { [key in RegionType]: RegionRole } = {
  polite: 'status',
  assertive: 'alert',
  off: 'none',
};

const listenerMap = new Map<Element, number>();

/* -------------------------------------------------------------------------------------------------
 * Announce
 * -----------------------------------------------------------------------------------------------*/

const NAME = 'Announce';

type AnnounceElement = React.ComponentRef<typeof Primitive.div>;
type PrimitiveDivProps = React.ComponentPropsWithoutRef<typeof Primitive.div>;
interface AnnounceProps extends PrimitiveDivProps {
  /**
   * Mirrors the `aria-atomic` DOM attribute for live regions. It is an optional attribute that
   * indicates whether assistive technologies will present all, or only parts of, the changed region
   * based on the change notifications defined by the `aria-relevant` attribute.
   *
   * @see WAI-ARIA https://www.w3.org/TR/wai-aria-1.2/#aria-atomic
   * @see Demo     http://pauljadam.com/demos/aria-atomic-relevant.html
   */
  'aria-atomic'?: boolean;
  /**
   * Mirrors the `aria-relevant` DOM attribute for live regions. It is an optional attribute used to
   * describe what types of changes have occurred to the region, and which changes are relevant and
   * should be announced. Any change that is not relevant acts in the same manner it would if the
   * `aria-live` attribute were set to off.
   *
   * Unfortunately, `aria-relevant` doesn't behave as expected across all device/screen reader
   * combinations. It's important to test its implementation before relying on it to work for your
   * users. The attribute is omitted by default.
   *
   * @see WAI-ARIA https://www.w3.org/TR/wai-aria-1.2/#aria-relevant
   * @see MDN      https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-relevant_attribute
   * @see Opinion  https://medium.com/dev-channel/why-authors-should-avoid-aria-relevant-5d3164fab1e3
   * @see Demo     http://pauljadam.com/demos/aria-atomic-relevant.html
   */
  'aria-relevant'?: PrimitiveDivProps['aria-relevant'];
  /**
   * React children of your component. Children can be mirrored directly or modified to optimize for
   * screen reader user experience.
   */
  children: React.ReactNode;
  /**
   * An optional unique identifier for the live region.
   *
   * By default, `Announce` components create, at most, two unique `aria-live` regions in the
   * document (one for all `polite` notifications, one for all `assertive` notifications). In some
   * cases you may wish to append additional `aria-live` regions for distinct purposes (for example,
   * simple status updates may need to be separated from a stack of toast-style notifications). By
   * passing an id, you indicate that any content rendered by components with the same identifier
   * should be mirrored in a separate `aria-live` region.
   */
  regionIdentifier?: string;
  /**
   * Mirrors the `role` DOM attribute. This is optional and may be useful as an override in some
   * cases. By default, the role is determined by the `type` prop.
   *
   * @see MDN https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Live_Regions#Preferring_specialized_live_region_roles
   */
  role?: RegionRole;
  /**
   * Mirrors the `aria-live` DOM attribute. The `aria-live=POLITENESS_SETTING` is used to set the
   * priority with which screen reader should treat updates to live regions. Its possible settings
   * are: off, polite or assertive. Defaults to `polite`.
   *
   * @see MDN https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Live_Regions
   */
  type?: RegionType;
}

const Announce = React.forwardRef<AnnounceElement, AnnounceProps>((props, forwardedRef) => {
  const {
    'aria-relevant': ariaRelevant,
    children,
    type = 'polite',
    role = ROLES[type],
    regionIdentifier,
    ...regionProps
  } = props;

  const ariaAtomic = ['true', true].includes(regionProps['aria-atomic'] as any);

  // The region is appended to the root document node, which is usually the global `document` but in
  // some contexts may be another node. After the Announce element ref is attached, we set the
  // ownerDocumentRef to make sure we have the right root node. We should only need to do this once.
  const ownerDocumentRef = React.useRef(document);
  const setOwnerDocumentFromRef = React.useCallback((node: HTMLDivElement) => {
    if (node) {
      ownerDocumentRef.current = node.ownerDocument;
    }
  }, []);
  const ownRef = React.useRef<HTMLDivElement | null>(null);
  const ref = useComposedRefs(forwardedRef, ownRef, setOwnerDocumentFromRef);

  const [region, setRegion] = React.useState<HTMLElement>();
  const relevant = ariaRelevant
    ? Array.isArray(ariaRelevant)
      ? ariaRelevant.join(' ')
      : ariaRelevant
    : undefined;

  const getLiveRegionElement = React.useCallback(() => {
    const ownerDocument = ownerDocumentRef.current;
    const regionConfig = { type, role, relevant, id: regionIdentifier, atomic: ariaAtomic };
    const regionSelector = buildSelector(regionConfig);
    const element = ownerDocument.querySelector(regionSelector);

    return element || buildLiveRegionElement(ownerDocument, regionConfig);
  }, [ariaAtomic, relevant, role, type, regionIdentifier]);

  useLayoutEffect(() => {
    setRegion(getLiveRegionElement() as HTMLElement);
  }, [getLiveRegionElement]);

  // In some screen reader/browser combinations, alerts coming from an inactive browser tab may be
  // announced, which is a confusing experience for a user interacting with a completely different
  // page. When the page visibility changes we'll update the `role` and `aria-live` attributes of
  // our region element to prevent that.
  // https://inclusive-components.design/notifications/#restrictingmessagestocontexts
  React.useEffect(() => {
    const ownerDocument = ownerDocumentRef.current;
    function updateAttributesOnVisibilityChange() {
      regionElement.setAttribute('role', ownerDocument.hidden ? 'none' : role);
      regionElement.setAttribute('aria-live', ownerDocument.hidden ? 'off' : type);
    }

    // Ok, so this might look a little weird and confusing, but here's what's going on:
    //   - We need to hide `aria-live` regions via a global event listener, as noted in the comment
    //     above.
    //   - We only need one listener per region. Keep in mind that each `Announce` does not
    //     necessarily generate a unique live region element.
    //   - We track whether or not a listener has already been attached for a given region in a map
    //     so we can skip these effects after `Announce` is used again with a shared live region.
    const regionElement = getLiveRegionElement();

    if (!listenerMap.get(regionElement)) {
      ownerDocument.addEventListener('visibilitychange', updateAttributesOnVisibilityChange);
      listenerMap.set(regionElement, 1);
    } else {
      const announceCount = listenerMap.get(regionElement)!;
      listenerMap.set(regionElement, announceCount + 1);
    }

    return function () {
      const announceCount = listenerMap.get(regionElement)!;
      listenerMap.set(regionElement, announceCount - 1);
      if (announceCount === 1) {
        ownerDocument.removeEventListener('visibilitychange', updateAttributesOnVisibilityChange);
      }
    };
  }, [getLiveRegionElement, role, type]);

  return (
    <React.Fragment>
      <Primitive.div {...regionProps} ref={ref}>
        {children}
      </Primitive.div>

      {/* portal into live region for screen reader announcements */}
      {region && ReactDOM.createPortal(<div>{children}</div>, region)}
    </React.Fragment>
  );
});

Announce.displayName = NAME;

/* ---------------------------------------------------------------------------------------------- */

type LiveRegionOptions = {
  type: string;
  relevant?: string;
  role: string;
  atomic?: boolean;
  id?: string;
};

function buildLiveRegionElement(
  ownerDocument: Document,
  { type, relevant, role, atomic, id }: LiveRegionOptions,
) {
  const element = ownerDocument.createElement('div');
  element.setAttribute(getLiveRegionPartDataAttr(id), '');
  element.setAttribute(
    'style',
    'position: absolute; top: -1px; width: 1px; height: 1px; overflow: hidden;',
  );
  ownerDocument.body.appendChild(element);

  element.setAttribute('aria-live', type);
  element.setAttribute('aria-atomic', String(atomic || false));
  element.setAttribute('role', role);
  if (relevant) {
    element.setAttribute('aria-relevant', relevant);
  }

  return element;
}

function buildSelector({ type, relevant, role, atomic, id }: LiveRegionOptions) {
  return `[${getLiveRegionPartDataAttr(id)}]${[
    ['aria-live', type],
    ['aria-atomic', atomic],
    ['aria-relevant', relevant],
    ['role', role],
  ]
    .filter(([, val]) => !!val)
    .map(([attr, val]) => `[${attr}=${val}]`)
    .join('')}`;
}

function getLiveRegionPartDataAttr(id?: string) {
  return 'data-radix-announce-region' + (id ? `-${id}` : '');
}

const Root = Announce;

export {
  Announce,
  //
  Root,
};
export type { AnnounceProps };



================================================
FILE: packages/react/announce/src/index.ts
================================================
'use client';
export {
  Announce,
  //
  Root,
} from './announce';
export type { AnnounceProps } from './announce';



================================================
FILE: packages/react/arrow/README.md
================================================
# `react-arrow`

This is an internal utility, not intended for public usage.



================================================
FILE: packages/react/arrow/CHANGELOG.md
================================================
# @radix-ui/react-arrow

## 1.1.8

- Updated dependencies: `@radix-ui/react-primitive@2.1.4`

## 1.1.7

- Replace deprecated 'ElementRef' with 'ComponentRef' (#3426)
- Updated dependencies: `@radix-ui/react-primitive@2.1.3`

## 1.1.6

- Updated dependencies: `@radix-ui/react-primitive@2.1.2`

## 1.1.5

- Updated dependencies: `@radix-ui/react-primitive@2.1.1`

## 1.1.4

- Updated dependencies: `@radix-ui/react-primitive@2.1.0`



================================================
FILE: packages/react/arrow/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/arrow/package.json
================================================
{
  "name": "@radix-ui/react-arrow",
  "version": "1.1.8",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/react-primitive": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/arrow/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/arrow/src/arrow.test.tsx
================================================
import { axe } from 'vitest-axe';
import type { RenderResult } from '@testing-library/react';
import { cleanup, render } from '@testing-library/react';
import { Arrow } from './arrow';
import { afterEach, describe, it, beforeEach, expect } from 'vitest';

const WIDTH = 40;
const HEIGHT = 30;

describe('given a default Arrow', () => {
  let rendered: RenderResult;
  let svg: HTMLElement;

  afterEach(cleanup);

  beforeEach(() => {
    rendered = render(<Arrow width={WIDTH} height={HEIGHT} data-testid="test-arrow" />);
    svg = rendered.getByTestId('test-arrow');
  });

  it('should have no accessibility violations', async () => {
    expect(await axe(rendered.container)).toHaveNoViolations();
  });

  it('should have width attribute', () => {
    expect(svg).toHaveAttribute('width', String(WIDTH));
  });

  it('should have height attribute', () => {
    expect(svg).toHaveAttribute('height', String(HEIGHT));
  });
});



================================================
FILE: packages/react/arrow/src/arrow.tsx
================================================
import * as React from 'react';
import { Primitive } from '@radix-ui/react-primitive';

/* -------------------------------------------------------------------------------------------------
 * Arrow
 * -----------------------------------------------------------------------------------------------*/

const NAME = 'Arrow';

type ArrowElement = React.ComponentRef<typeof Primitive.svg>;
type PrimitiveSvgProps = React.ComponentPropsWithoutRef<typeof Primitive.svg>;
interface ArrowProps extends PrimitiveSvgProps {}

const Arrow = React.forwardRef<ArrowElement, ArrowProps>((props, forwardedRef) => {
  const { children, width = 10, height = 5, ...arrowProps } = props;
  return (
    <Primitive.svg
      {...arrowProps}
      ref={forwardedRef}
      width={width}
      height={height}
      viewBox="0 0 30 10"
      preserveAspectRatio="none"
    >
      {/* We use their children if they're slotting to replace the whole svg */}
      {props.asChild ? children : <polygon points="0,0 30,0 15,10" />}
    </Primitive.svg>
  );
});

Arrow.displayName = NAME;

/* -----------------------------------------------------------------------------------------------*/

const Root = Arrow;

export {
  Arrow,
  //
  Root,
};
export type { ArrowProps };



================================================
FILE: packages/react/arrow/src/index.ts
================================================
export {
  Arrow,
  //
  Root,
} from './arrow';
export type { ArrowProps } from './arrow';



================================================
FILE: packages/react/aspect-ratio/README.md
================================================
# `react-aspect-ratio`

View docs [here](https://radix-ui.com/primitives/docs/utilities/aspect-ratio).



================================================
FILE: packages/react/aspect-ratio/CHANGELOG.md
================================================
# @radix-ui/react-aspect-ratio

## 1.1.8

- Updated dependencies: `@radix-ui/react-primitive@2.1.4`

## 1.1.7

- Replace deprecated 'ElementRef' with 'ComponentRef' (#3426)
- Updated dependencies: `@radix-ui/react-primitive@2.1.3`

## 1.1.6

- Updated dependencies: `@radix-ui/react-primitive@2.1.2`

## 1.1.5

- Updated dependencies: `@radix-ui/react-primitive@2.1.1`

## 1.1.4

- Updated dependencies: `@radix-ui/react-primitive@2.1.0`



================================================
FILE: packages/react/aspect-ratio/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/aspect-ratio/package.json
================================================
{
  "name": "@radix-ui/react-aspect-ratio",
  "version": "1.1.8",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/react-primitive": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/aspect-ratio/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/aspect-ratio/src/aspect-ratio.test.tsx
================================================
import { axe } from 'vitest-axe';
import type { RenderResult } from '@testing-library/react';
import { cleanup, render } from '@testing-library/react';
import { AspectRatio } from './aspect-ratio';
import { afterEach, describe, it, beforeEach, expect } from 'vitest';

const RATIO = 1 / 2;

describe('given a default Arrow', () => {
  let rendered: RenderResult;

  afterEach(cleanup);

  beforeEach(() => {
    rendered = render(
      <div style={{ width: 500 }}>
        <AspectRatio ratio={RATIO}>
          <span>Hello</span>
        </AspectRatio>
      </div>,
    );
  });

  it('should have no accessibility violations', async () => {
    expect(await axe(rendered.container)).toHaveNoViolations();
  });
});



================================================
FILE: packages/react/aspect-ratio/src/aspect-ratio.tsx
================================================
import * as React from 'react';
import { Primitive } from '@radix-ui/react-primitive';

/* -------------------------------------------------------------------------------------------------
 * AspectRatio
 * -----------------------------------------------------------------------------------------------*/

const NAME = 'AspectRatio';

type AspectRatioElement = React.ComponentRef<typeof Primitive.div>;
type PrimitiveDivProps = React.ComponentPropsWithoutRef<typeof Primitive.div>;
interface AspectRatioProps extends PrimitiveDivProps {
  ratio?: number;
}

const AspectRatio = React.forwardRef<AspectRatioElement, AspectRatioProps>(
  (props, forwardedRef) => {
    const { ratio = 1 / 1, style, ...aspectRatioProps } = props;
    return (
      <div
        style={{
          // ensures inner element is contained
          position: 'relative',
          // ensures padding bottom trick maths works
          width: '100%',
          paddingBottom: `${100 / ratio}%`,
        }}
        data-radix-aspect-ratio-wrapper=""
      >
        <Primitive.div
          {...aspectRatioProps}
          ref={forwardedRef}
          style={{
            ...style,
            // ensures children expand in ratio
            position: 'absolute',
            top: 0,
            right: 0,
            bottom: 0,
            left: 0,
          }}
        />
      </div>
    );
  },
);

AspectRatio.displayName = NAME;

/* -----------------------------------------------------------------------------------------------*/

const Root = AspectRatio;

export {
  AspectRatio,
  //
  Root,
};
export type { AspectRatioProps };



================================================
FILE: packages/react/aspect-ratio/src/index.ts
================================================
export {
  AspectRatio,
  //
  Root,
} from './aspect-ratio';
export type { AspectRatioProps } from './aspect-ratio';



================================================
FILE: packages/react/avatar/README.md
================================================
# `react-avatar`

View docs [here](https://radix-ui.com/primitives/docs/components/avatar).



================================================
FILE: packages/react/avatar/CHANGELOG.md
================================================
# @radix-ui/react-avatar

## 1.1.11

- Updated dependencies: `@radix-ui/react-context@1.1.3`, `@radix-ui/react-primitive@2.1.4`

## 1.1.10

- Replace deprecated 'ElementRef' with 'ComponentRef' (#3426)
- Updated dependencies: `@radix-ui/react-primitive@2.1.3`

## 1.1.9

- Updated dependencies: `@radix-ui/react-primitive@2.1.2`

## 1.1.8

- Updated dependencies: `@radix-ui/react-primitive@2.1.1`

## 1.1.7

- Updated dependencies: `@radix-ui/react-use-is-hydrated@0.1.0`

## 1.1.6

- Fix breaking `useSyncExternalStore` import in Avatar

## 1.1.5

- Updated dependencies: `@radix-ui/react-primitive@2.1.0`



================================================
FILE: packages/react/avatar/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/avatar/package.json
================================================
{
  "name": "@radix-ui/react-avatar",
  "version": "1.1.11",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/react-context": "workspace:*",
    "@radix-ui/react-primitive": "workspace:*",
    "@radix-ui/react-use-callback-ref": "workspace:*",
    "@radix-ui/react-use-is-hydrated": "workspace:*",
    "@radix-ui/react-use-layout-effect": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/avatar/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/avatar/src/avatar.test.tsx
================================================
import { axe } from 'vitest-axe';
import type { RenderResult } from '@testing-library/react';
import { cleanup, render, waitFor } from '@testing-library/react';
import * as Avatar from './avatar';
import * as React from 'react';
import { renderToString } from 'react-dom/server';
import { afterEach, describe, it, beforeAll, afterAll, beforeEach, vi, expect } from 'vitest';

const ROOT_TEST_ID = 'avatar-root';
const FALLBACK_TEXT = 'AB';
const IMAGE_ALT_TEXT = 'Fake Avatar';
const DELAY = 300;
const cache = new Set<string>();

describe('given an Avatar with fallback and no image', () => {
  afterEach(cleanup);

  const ui = (
    <Avatar.Root data-testid={ROOT_TEST_ID}>
      <Avatar.Fallback>{FALLBACK_TEXT}</Avatar.Fallback>
    </Avatar.Root>
  );

  it('should have no accessibility violations', async () => {
    const rendered = render(ui);
    expect(await axe(rendered.container)).toHaveNoViolations();
  });

  it('should work with SSR', () => {
    const container = document.createElement('div');
    document.body.appendChild(container);
    container.innerHTML = renderToString(ui);
    const rendered = render(ui, { hydrate: true, container });
    const fallback = rendered.queryByText(FALLBACK_TEXT);
    expect(fallback).toBeInTheDocument();
  });
});

describe('given an Avatar with fallback and an image', () => {
  let rendered: RenderResult;
  let image: HTMLElement | null = null;
  const originalGlobalImage = window.Image;
  const ui = (src?: string) => (
    <Avatar.Root data-testid={ROOT_TEST_ID}>
      <Avatar.Fallback>{FALLBACK_TEXT}</Avatar.Fallback>
      <Avatar.Image src={src} alt={IMAGE_ALT_TEXT} />
    </Avatar.Root>
  );

  beforeAll(() => {
    (window.Image as any) = MockImage;
  });

  afterAll(() => {
    window.Image = originalGlobalImage;
    vi.restoreAllMocks();
  });

  afterEach(cleanup);

  beforeEach(() => {
    cache.clear();
    rendered = render(ui('/test.png'));
  });

  it('should render the fallback initially', () => {
    const fallback = rendered.queryByText(FALLBACK_TEXT);
    expect(fallback).toBeInTheDocument();
  });

  it('should not render the image initially', () => {
    image = rendered.queryByRole('img');
    expect(image).not.toBeInTheDocument();
  });

  it('should render the image after it has loaded', async () => {
    image = await rendered.findByRole('img');
    expect(image).toBeInTheDocument();
  });

  it('should have alt text on the image', async () => {
    image = await rendered.findByAltText(IMAGE_ALT_TEXT);
    expect(image).toBeInTheDocument();
  });

  it('does not leak event listeners', async () => {
    rendered.unmount();
    const addEventListenerSpy = vi.spyOn(window.Image.prototype, 'addEventListener');
    const removeEventListenerSpy = vi.spyOn(window.Image.prototype, 'removeEventListener');
    rendered = render(ui('/test.png'));
    rendered.unmount();
    expect(addEventListenerSpy.mock.calls.length).toEqual(removeEventListenerSpy.mock.calls.length);
  });

  it('can handle changing src', async () => {
    image = await rendered.findByRole('img');
    expect(image).toBeInTheDocument();
    rendered.rerender(ui('/test2.png'));
    image = rendered.queryByRole('img');
    expect(image).not.toBeInTheDocument();
    image = await rendered.findByRole('img');
    expect(image).toBeInTheDocument();
  });

  it('should render the image immediately after it is cached', async () => {
    image = await rendered.findByRole('img');
    expect(image).toBeInTheDocument();

    rendered.unmount();
    rendered = render(ui('/test.png'));
    image = rendered.queryByRole('img');
    expect(image).toBeInTheDocument();
  });

  it('should not render image with no src', async () => {
    rendered.rerender(ui());
    image = rendered.queryByRole('img');
    expect(image).not.toBeInTheDocument();
    rendered.unmount();
    rendered = render(ui());
    image = rendered.queryByRole('img');
    expect(image).not.toBeInTheDocument();
  });

  it('should not render image with empty string as src', async () => {
    rendered.rerender(ui(''));
    image = rendered.queryByRole('img');
    expect(image).not.toBeInTheDocument();
    rendered.unmount();
    rendered = render(ui(''));
    image = rendered.queryByRole('img');
    expect(image).not.toBeInTheDocument();
  });

  it('should show fallback if image has no data', async () => {
    rendered.unmount();
    const spy = vi.spyOn(window.Image.prototype, 'naturalWidth', 'get');
    spy.mockReturnValue(0);
    rendered = render(ui('/test.png'));
    const fallback = rendered.queryByText(FALLBACK_TEXT);
    expect(fallback).toBeInTheDocument();
    spy.mockRestore();
  });

  describe('SSR', () => {
    afterEach(cleanup);

    function renderAndHydrate(ui: React.ReactElement) {
      const container = document.createElement('div');
      document.body.appendChild(container);
      container.innerHTML = renderToString(ui);
      return render(ui, { hydrate: true, container });
    }

    it('can render with working image', async () => {
      const rendered = renderAndHydrate(ui('/test.png'));
      let image = rendered.queryByRole('img');
      expect(image).not.toBeInTheDocument();

      image = await rendered.findByRole('img');
      expect(image).toBeInTheDocument();
    });

    it('can render with no src', () => {
      const rendered = renderAndHydrate(ui());
      const image = rendered.queryByRole('img');
      expect(image).not.toBeInTheDocument();
      const fallback = rendered.queryByText(FALLBACK_TEXT);
      expect(fallback).toBeInTheDocument();
    });
  });
});

describe('given an Avatar with fallback and delayed render', () => {
  let rendered: RenderResult;
  let fallback: HTMLElement | null;

  beforeEach(() => {
    rendered = render(
      <Avatar.Root data-testid={ROOT_TEST_ID}>
        <Avatar.Fallback delayMs={DELAY}>{FALLBACK_TEXT}</Avatar.Fallback>
      </Avatar.Root>,
    );
  });

  afterEach(cleanup);

  it('should not render a fallback immediately', () => {
    fallback = rendered.queryByText(FALLBACK_TEXT);
    expect(fallback).not.toBeInTheDocument();
  });

  it('should render a fallback after the delay', async () => {
    fallback = rendered.queryByText(FALLBACK_TEXT);
    expect(fallback).not.toBeInTheDocument();
    fallback = await rendered.findByText(FALLBACK_TEXT);
    expect(fallback).toBeInTheDocument();
  });
});

describe('given an Avatar with an image that only works when referrerPolicy=no-referrer', () => {
  let rendered: RenderResult;
  const originalGlobalImage = window.Image;
  const ui = (src?: string, referrerPolicy?: React.HTMLAttributeReferrerPolicy) => (
    <Avatar.Root data-testid={ROOT_TEST_ID}>
      <Avatar.Fallback>{FALLBACK_TEXT}</Avatar.Fallback>
      <Avatar.Image src={src} alt={IMAGE_ALT_TEXT} referrerPolicy={referrerPolicy} />
    </Avatar.Root>
  );

  beforeAll(() => {
    (window.Image as any) = class MockNoReferrerImage extends MockImage {
      referrerPolicy: string | undefined;

      onSrcChange() {
        setTimeout(() => {
          if (this.referrerPolicy === 'no-referrer') {
            this.dispatchEvent(new Event('load'));
          } else {
            this.dispatchEvent(new Event('error'));
          }
        }, DELAY);
      }
    };
  });

  afterAll(() => {
    window.Image = originalGlobalImage;
    vi.restoreAllMocks();
  });

  afterEach(cleanup);

  describe('referrerPolicy=no-referrer', () => {
    beforeEach(() => {
      cache.clear();
      rendered = render(ui('/test.png', 'no-referrer'));
    });

    it('should render the fallback initially', () => {
      const fallback = rendered.queryByText(FALLBACK_TEXT);
      expect(fallback).toBeInTheDocument();
    });

    it('should not render the image initially', () => {
      const image = rendered.queryByRole('img');
      expect(image).not.toBeInTheDocument();
    });

    it('should render the image after it has loaded', async () => {
      const image = await rendered.findByRole('img');
      expect(image).toBeInTheDocument();
    });

    it('should have alt text on the image', async () => {
      const image = await rendered.findByAltText(IMAGE_ALT_TEXT);
      expect(image).toBeInTheDocument();
    });
  });

  describe('referrerPolicy=origin', () => {
    beforeEach(() => {
      cache.clear();
      rendered = render(ui('/test.png', 'origin'));
    });

    it('should render the fallback initially', () => {
      const fallback = rendered.queryByText(FALLBACK_TEXT);
      expect(fallback).toBeInTheDocument();
    });

    it('should never render the image', async () => {
      try {
        await waitFor(() => rendered.getByRole('img'), {
          timeout: DELAY + 100,
        });
      } catch (error) {
        expect(error).toBeInstanceOf(Error);
        expect((error as Error).name).toBe('TestingLibraryElementError');
        expect((error as Error).message).toContain('Unable to find role="img"');
      }
    });
  });
});

class MockImage extends EventTarget {
  _src: string = '';

  constructor() {
    super();
    return this;
  }

  get src() {
    return this._src;
  }

  set src(src: string) {
    if (!src) {
      return;
    }
    this._src = src;
    this.onSrcChange();
  }

  get complete() {
    return !this.src || cache.has(this.src);
  }

  get naturalWidth() {
    return this.complete ? 300 : 0;
  }

  onSrcChange() {
    setTimeout(() => {
      this.dispatchEvent(new Event('load'));
      cache.add(this.src);
    }, DELAY);
  }
}



================================================
FILE: packages/react/avatar/src/avatar.tsx
================================================
import * as React from 'react';
import { createContextScope } from '@radix-ui/react-context';
import { useCallbackRef } from '@radix-ui/react-use-callback-ref';
import { useLayoutEffect } from '@radix-ui/react-use-layout-effect';
import { Primitive } from '@radix-ui/react-primitive';
import { useIsHydrated } from '@radix-ui/react-use-is-hydrated';

import type { Scope } from '@radix-ui/react-context';

/* -------------------------------------------------------------------------------------------------
 * Avatar
 * -----------------------------------------------------------------------------------------------*/

const AVATAR_NAME = 'Avatar';

type ScopedProps<P> = P & { __scopeAvatar?: Scope };
const [createAvatarContext, createAvatarScope] = createContextScope(AVATAR_NAME);

type ImageLoadingStatus = 'idle' | 'loading' | 'loaded' | 'error';

type AvatarContextValue = {
  imageLoadingStatus: ImageLoadingStatus;
  onImageLoadingStatusChange(status: ImageLoadingStatus): void;
};

const [AvatarProvider, useAvatarContext] = createAvatarContext<AvatarContextValue>(AVATAR_NAME);

type AvatarElement = React.ComponentRef<typeof Primitive.span>;
type PrimitiveSpanProps = React.ComponentPropsWithoutRef<typeof Primitive.span>;
interface AvatarProps extends PrimitiveSpanProps {}

const Avatar = React.forwardRef<AvatarElement, AvatarProps>(
  (props: ScopedProps<AvatarProps>, forwardedRef) => {
    const { __scopeAvatar, ...avatarProps } = props;
    const [imageLoadingStatus, setImageLoadingStatus] = React.useState<ImageLoadingStatus>('idle');
    return (
      <AvatarProvider
        scope={__scopeAvatar}
        imageLoadingStatus={imageLoadingStatus}
        onImageLoadingStatusChange={setImageLoadingStatus}
      >
        <Primitive.span {...avatarProps} ref={forwardedRef} />
      </AvatarProvider>
    );
  },
);

Avatar.displayName = AVATAR_NAME;

/* -------------------------------------------------------------------------------------------------
 * AvatarImage
 * -----------------------------------------------------------------------------------------------*/

const IMAGE_NAME = 'AvatarImage';

type AvatarImageElement = React.ComponentRef<typeof Primitive.img>;
type PrimitiveImageProps = React.ComponentPropsWithoutRef<typeof Primitive.img>;
interface AvatarImageProps extends PrimitiveImageProps {
  onLoadingStatusChange?: (status: ImageLoadingStatus) => void;
}

const AvatarImage = React.forwardRef<AvatarImageElement, AvatarImageProps>(
  (props: ScopedProps<AvatarImageProps>, forwardedRef) => {
    const { __scopeAvatar, src, onLoadingStatusChange = () => {}, ...imageProps } = props;
    const context = useAvatarContext(IMAGE_NAME, __scopeAvatar);
    const imageLoadingStatus = useImageLoadingStatus(src, imageProps);
    const handleLoadingStatusChange = useCallbackRef((status: ImageLoadingStatus) => {
      onLoadingStatusChange(status);
      context.onImageLoadingStatusChange(status);
    });

    useLayoutEffect(() => {
      if (imageLoadingStatus !== 'idle') {
        handleLoadingStatusChange(imageLoadingStatus);
      }
    }, [imageLoadingStatus, handleLoadingStatusChange]);

    return imageLoadingStatus === 'loaded' ? (
      <Primitive.img {...imageProps} ref={forwardedRef} src={src} />
    ) : null;
  },
);

AvatarImage.displayName = IMAGE_NAME;

/* -------------------------------------------------------------------------------------------------
 * AvatarFallback
 * -----------------------------------------------------------------------------------------------*/

const FALLBACK_NAME = 'AvatarFallback';

type AvatarFallbackElement = React.ComponentRef<typeof Primitive.span>;
interface AvatarFallbackProps extends PrimitiveSpanProps {
  delayMs?: number;
}

const AvatarFallback = React.forwardRef<AvatarFallbackElement, AvatarFallbackProps>(
  (props: ScopedProps<AvatarFallbackProps>, forwardedRef) => {
    const { __scopeAvatar, delayMs, ...fallbackProps } = props;
    const context = useAvatarContext(FALLBACK_NAME, __scopeAvatar);
    const [canRender, setCanRender] = React.useState(delayMs === undefined);

    React.useEffect(() => {
      if (delayMs !== undefined) {
        const timerId = window.setTimeout(() => setCanRender(true), delayMs);
        return () => window.clearTimeout(timerId);
      }
    }, [delayMs]);

    return canRender && context.imageLoadingStatus !== 'loaded' ? (
      <Primitive.span {...fallbackProps} ref={forwardedRef} />
    ) : null;
  },
);

AvatarFallback.displayName = FALLBACK_NAME;

/* -----------------------------------------------------------------------------------------------*/

function resolveLoadingStatus(image: HTMLImageElement | null, src?: string): ImageLoadingStatus {
  if (!image) {
    return 'idle';
  }
  if (!src) {
    return 'error';
  }
  if (image.src !== src) {
    image.src = src;
  }
  return image.complete && image.naturalWidth > 0 ? 'loaded' : 'loading';
}

function useImageLoadingStatus(
  src: string | undefined,
  { referrerPolicy, crossOrigin }: AvatarImageProps,
) {
  const isHydrated = useIsHydrated();
  const imageRef = React.useRef<HTMLImageElement | null>(null);
  const image = (() => {
    if (!isHydrated) return null;
    if (!imageRef.current) {
      imageRef.current = new window.Image();
    }
    return imageRef.current;
  })();

  const [loadingStatus, setLoadingStatus] = React.useState<ImageLoadingStatus>(() =>
    resolveLoadingStatus(image, src),
  );

  useLayoutEffect(() => {
    setLoadingStatus(resolveLoadingStatus(image, src));
  }, [image, src]);

  useLayoutEffect(() => {
    const updateStatus = (status: ImageLoadingStatus) => () => {
      setLoadingStatus(status);
    };

    if (!image) return;

    const handleLoad = updateStatus('loaded');
    const handleError = updateStatus('error');
    image.addEventListener('load', handleLoad);
    image.addEventListener('error', handleError);
    if (referrerPolicy) {
      image.referrerPolicy = referrerPolicy;
    }
    if (typeof crossOrigin === 'string') {
      image.crossOrigin = crossOrigin;
    }

    return () => {
      image.removeEventListener('load', handleLoad);
      image.removeEventListener('error', handleError);
    };
  }, [image, crossOrigin, referrerPolicy]);

  return loadingStatus;
}

const Root = Avatar;
const Image = AvatarImage;
const Fallback = AvatarFallback;

export {
  createAvatarScope,
  //
  Avatar,
  AvatarImage,
  AvatarFallback,
  //
  Root,
  Image,
  Fallback,
};
export type { AvatarProps, AvatarImageProps, AvatarFallbackProps };



================================================
FILE: packages/react/avatar/src/index.ts
================================================
'use client';
export {
  createAvatarScope,
  //
  Avatar,
  AvatarImage,
  AvatarFallback,
  //
  Root,
  Image,
  Fallback,
} from './avatar';
export type { AvatarProps, AvatarImageProps, AvatarFallbackProps } from './avatar';



================================================
FILE: packages/react/checkbox/README.md
================================================
# `react-checkbox`

View docs [here](https://radix-ui.com/primitives/docs/components/checkbox).



================================================
FILE: packages/react/checkbox/CHANGELOG.md
================================================
# @radix-ui/react-checkbox

## 1.3.3

- Updated dependencies: `@radix-ui/react-presence@1.1.5`, `@radix-ui/primitive@1.1.3`, `@radix-ui/react-context@1.1.3`, `@radix-ui/react-primitive@2.1.4`

## 1.3.2

- Replace deprecated 'ElementRef' with 'ComponentRef' (#3426)
- Updated dependencies: `@radix-ui/react-primitive@2.1.3`

## 1.3.1

- Fix type error emitted in build artifacts
- Updated dependencies: `@radix-ui/react-primitive@2.1.2`

## 1.3.0

- Add unstable `Provider`, `Trigger` and `BubbleInput` parts to Checkbox ([#3459](https://github.com/radix-ui/primitives/pull/3459))
- Updated dependencies: `@radix-ui/react-primitive@2.1.1`

## 1.2.3

- Updated dependencies: `@radix-ui/react-presence@1.1.4`

## 1.2.2

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.2`

## 1.2.1

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.1`

## 1.2.0

- All form controls with internal bubble inputs now use the Radix `Primitive` component by default. This will allow us to expose these components directly so users can better control this behavior in the future.
- Minor improvements to `useControllableState` to enhance performance, reduce surface area for bugs, and log warnings when misused (#3455)
- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.0`, `@radix-ui/react-primitive@2.1.0`



================================================
FILE: packages/react/checkbox/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/checkbox/package.json
================================================
{
  "name": "@radix-ui/react-checkbox",
  "version": "1.3.3",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/primitive": "workspace:*",
    "@radix-ui/react-compose-refs": "workspace:*",
    "@radix-ui/react-context": "workspace:*",
    "@radix-ui/react-presence": "workspace:*",
    "@radix-ui/react-primitive": "workspace:*",
    "@radix-ui/react-use-controllable-state": "workspace:*",
    "@radix-ui/react-use-previous": "workspace:*",
    "@radix-ui/react-use-size": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/checkbox/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/checkbox/src/checkbox.test.tsx
================================================
import * as React from 'react';
import { axe } from 'vitest-axe';
import type { RenderResult } from '@testing-library/react';
import { cleanup, render, fireEvent, screen, waitFor, act } from '@testing-library/react';
import * as Checkbox from '.';
import { afterEach, describe, it, beforeEach, vi, expect } from 'vitest';

const CHECKBOX_ROLE = 'checkbox';
const INDICATOR_TEST_ID = 'checkbox-indicator';

global.ResizeObserver = class ResizeObserver {
  cb: any;
  constructor(cb: any) {
    this.cb = cb;
  }
  observe() {
    this.cb([{ borderBoxSize: { inlineSize: 0, blockSize: 0 } }]);
  }
  unobserve() {}
  disconnect() {}
};

describe('Checkbox', () => {
  afterEach(cleanup);

  describe('given a default Checkbox', () => {
    let rendered: RenderResult;
    beforeEach(() => {
      rendered = render(
        <Checkbox.unstable_Provider>
          <Checkbox.unstable_Trigger aria-label="basic checkbox">
            <Checkbox.Indicator data-testid={INDICATOR_TEST_ID} />
          </Checkbox.unstable_Trigger>
        </Checkbox.unstable_Provider>,
      );
    });

    it('should have no accessibility violations', async () => {
      expect(await axe(rendered.container)).toHaveNoViolations();
    });

    it('should toggle the indicator when clicked', async () => {
      const checkbox = screen.getByRole(CHECKBOX_ROLE);
      await act(async () => fireEvent.click(checkbox));

      let indicator = screen.queryByTestId(INDICATOR_TEST_ID);
      expect(indicator).toBeVisible();

      await act(async () => fireEvent.click(checkbox));
      indicator = screen.queryByTestId(INDICATOR_TEST_ID);
      expect(indicator).not.toBeInTheDocument();
    });
  });

  describe('given a disabled Checkbox', () => {
    let rendered: RenderResult;
    beforeEach(() => {
      rendered = render(
        <Checkbox.unstable_Provider disabled>
          <Checkbox.unstable_Trigger aria-label="basic checkbox">
            <Checkbox.Indicator data-testid={INDICATOR_TEST_ID} />
          </Checkbox.unstable_Trigger>
        </Checkbox.unstable_Provider>,
      );
    });

    it('should have no accessibility violations', async () => {
      expect(await axe(rendered.container)).toHaveNoViolations();
    });

    it('should not toggle the indicator when clicked', async () => {
      const checkbox = screen.getByRole(CHECKBOX_ROLE);

      await act(async () => fireEvent.click(checkbox));
      const indicator = screen.queryByTestId(INDICATOR_TEST_ID);
      expect(indicator).not.toBeInTheDocument();

      await act(async () => fireEvent.click(checkbox));
      expect(indicator).not.toBeInTheDocument();
    });
  });

  describe('given an uncontrolled `checked` Checkbox', () => {
    const onCheckedChange = vi.fn();
    let rendered: RenderResult;

    beforeEach(() => {
      rendered = render(
        <Checkbox.unstable_Provider defaultChecked onCheckedChange={onCheckedChange}>
          <Checkbox.unstable_Trigger aria-label="basic checkbox">
            <Checkbox.Indicator data-testid={INDICATOR_TEST_ID} />
          </Checkbox.unstable_Trigger>
        </Checkbox.unstable_Provider>,
      );
    });

    afterEach(cleanup);

    it('should have no accessibility violations', async () => {
      expect(await axe(rendered.container)).toHaveNoViolations();
    });

    it('should render a visible indicator', () => {
      const indicator = screen.queryByTestId(INDICATOR_TEST_ID);
      expect(indicator).toBeVisible();
    });

    it('should toggle the indicator when clicked', async () => {
      const checkbox = screen.getByRole(CHECKBOX_ROLE);
      await act(async () => fireEvent.click(checkbox));
      let indicator = screen.queryByTestId(INDICATOR_TEST_ID);
      expect(indicator).not.toBeInTheDocument();

      await act(async () => fireEvent.click(checkbox));
      indicator = screen.queryByTestId(INDICATOR_TEST_ID);
      expect(indicator).toBeVisible();
    });

    it('should call `onCheckedChange` prop', () => {
      const checkbox = screen.getByRole(CHECKBOX_ROLE);
      fireEvent.click(checkbox);
      waitFor(() => {
        expect(onCheckedChange).toHaveBeenCalledWith(false);
      });
    });
  });

  describe('given a controlled Checkbox', () => {
    const onCheckedChange = vi.fn();
    let rendered: RenderResult;

    function ControlledCheckbox() {
      const [checked, setChecked] = React.useState(false);
      const [blockToggle, setBlockToggle] = React.useState(false);
      return (
        <div>
          <Checkbox.unstable_Provider
            checked={checked}
            onCheckedChange={(checked) => {
              onCheckedChange(checked);
              if (!blockToggle) {
                setChecked(checked);
              }
            }}
          >
            <Checkbox.unstable_Trigger aria-label="basic checkbox">
              <Checkbox.Indicator data-testid={INDICATOR_TEST_ID} />
            </Checkbox.unstable_Trigger>
          </Checkbox.unstable_Provider>
          <button type="button" onClick={() => setChecked((prev) => !prev)}>
            Toggle checkbox
          </button>
          <button type="button" onClick={() => setBlockToggle((prev) => !prev)}>
            {blockToggle ? 'Unblock' : 'Block'} checkbox
          </button>
        </div>
      );
    }

    beforeEach(() => {
      rendered = render(<ControlledCheckbox />);
    });

    it('should have no accessibility violations', async () => {
      expect(await axe(rendered.container)).toHaveNoViolations();
    });

    it('should toggle the indicator', async () => {
      const checkbox = screen.getByRole(CHECKBOX_ROLE);
      await act(async () => fireEvent.click(checkbox));
      const indicator = screen.queryByTestId(INDICATOR_TEST_ID);
      expect(indicator).toBeVisible();
    });

    it('should call `onCheckedChange` prop', async () => {
      const checkbox = screen.getByRole(CHECKBOX_ROLE);
      await act(async () => fireEvent.click(checkbox));
      expect(onCheckedChange).toHaveBeenCalledWith(true);
    });

    it('should not toggle unless state is updated', async () => {
      const checkbox = screen.getByRole(CHECKBOX_ROLE);
      const blocker = screen.getByText('Block checkbox');
      await act(async () => fireEvent.click(blocker));
      await act(async () => fireEvent.click(checkbox));
      const indicator = screen.queryByTestId(INDICATOR_TEST_ID);
      expect(indicator).not.toBeInTheDocument();
    });
  });

  describe('given an uncontrolled Checkbox in form with bubble input', () => {
    const onChange = vi.fn();

    it('should receive change event with next state', async () => {
      render(
        <form
          onChange={(event) => {
            const target = event.target as HTMLInputElement;
            onChange(target.checked);
          }}
        >
          <Checkbox.unstable_Provider>
            <Checkbox.unstable_Trigger aria-label="basic checkbox">
              <Checkbox.Indicator data-testid={INDICATOR_TEST_ID} />
            </Checkbox.unstable_Trigger>
            <Checkbox.unstable_BubbleInput />
          </Checkbox.unstable_Provider>
        </form>,
      );

      const checkbox = screen.getByRole(CHECKBOX_ROLE);
      act(() => fireEvent.click(checkbox));
      expect(onChange).toHaveBeenCalledWith(true);
    });

    describe('when `defaultChecked` is true', () => {
      it('should receive change event with next state', async () => {
        console.log(parseInt(React.version));
        render(
          <form
            onChange={(event) => {
              const target = event.target as HTMLInputElement;
              onChange(target.checked);
            }}
          >
            <Checkbox.unstable_Provider defaultChecked>
              <Checkbox.unstable_Trigger aria-label="basic checkbox">
                <Checkbox.Indicator data-testid={INDICATOR_TEST_ID} />
              </Checkbox.unstable_Trigger>
              <Checkbox.unstable_BubbleInput />
            </Checkbox.unstable_Provider>
          </form>,
        );

        const checkbox = screen.getByRole(CHECKBOX_ROLE);
        act(() => fireEvent.click(checkbox));
        expect(onChange).toHaveBeenCalledWith(false);
      });
    });
  });

  describe('given a controlled Checkbox in form with bubble input', () => {
    const onChange = vi.fn();

    function ControlledCheckbox() {
      const [checked, setChecked] = React.useState(false);
      return (
        <>
          <Checkbox.unstable_Provider checked={checked} onCheckedChange={setChecked as any}>
            <Checkbox.unstable_Trigger aria-label="basic checkbox">
              <Checkbox.Indicator data-testid={INDICATOR_TEST_ID} />
            </Checkbox.unstable_Trigger>
            <Checkbox.unstable_BubbleInput />
          </Checkbox.unstable_Provider>
          <button type="button" onClick={() => setChecked((prev) => !prev)}>
            Toggle checkbox
          </button>
        </>
      );
    }

    it('should receive change event with controlled state when clicked', async () => {
      render(
        <form
          onChange={(event) => {
            const target = event.target as HTMLInputElement;
            onChange(target.checked);
          }}
        >
          <ControlledCheckbox />
        </form>,
      );

      const checkbox = screen.getByRole(CHECKBOX_ROLE);
      act(() => fireEvent.click(checkbox));
      expect(onChange).toHaveBeenCalledWith(true);

      act(() => fireEvent.click(checkbox));
      expect(onChange).toHaveBeenCalledWith(false);
    });

    it('should receive change event with controlled state when set externally', async () => {
      render(
        <form
          onChange={(event) => {
            const target = event.target as HTMLInputElement;
            onChange(target.checked);
          }}
        >
          <ControlledCheckbox />
        </form>,
      );

      const toggleButton = screen.getByText('Toggle checkbox');
      act(() => fireEvent.click(toggleButton));
      expect(onChange).toHaveBeenCalledWith(false);
    });
  });
});

describe('Legacy Checkbox', () => {
  describe('given a default Checkbox', () => {
    let rendered: RenderResult;
    let checkbox: HTMLElement;
    let indicator: HTMLElement | null;

    beforeEach(() => {
      rendered = render(<LegacyCheckbox />);
      checkbox = rendered.getByRole(CHECKBOX_ROLE);
      indicator = rendered.queryByTestId(INDICATOR_TEST_ID);
    });

    afterEach(cleanup);

    it('should have no accessibility violations', async () => {
      expect(await axe(rendered.container)).toHaveNoViolations();
    });

    describe('when clicking the checkbox', () => {
      beforeEach(async () => {
        fireEvent.click(checkbox);
        indicator = rendered.queryByTestId(INDICATOR_TEST_ID);
      });

      it('should render a visible indicator', () => {
        expect(indicator).toBeVisible();
      });

      describe('and clicking the checkbox again', () => {
        beforeEach(async () => {
          fireEvent.click(checkbox);
        });

        it('should remove the indicator', () => {
          expect(indicator).not.toBeInTheDocument();
        });
      });
    });
  });

  describe('given a disabled Checkbox', () => {
    let rendered: RenderResult;

    beforeEach(() => {
      rendered = render(<LegacyCheckbox disabled />);
    });

    afterEach(cleanup);

    it('should have no accessibility violations', async () => {
      expect(await axe(rendered.container)).toHaveNoViolations();
    });
  });

  describe('given an uncontrolled `checked` Checkbox', () => {
    let rendered: RenderResult;
    let checkbox: HTMLElement;
    let indicator: HTMLElement | null;
    const onCheckedChange = vi.fn();

    beforeEach(() => {
      rendered = render(<LegacyCheckbox defaultChecked onCheckedChange={onCheckedChange} />);
      checkbox = rendered.getByRole(CHECKBOX_ROLE);
      indicator = rendered.queryByTestId(INDICATOR_TEST_ID);
    });

    afterEach(cleanup);

    it('should have no accessibility violations', async () => {
      expect(await axe(rendered.container)).toHaveNoViolations();
    });

    describe('when clicking the checkbox', () => {
      beforeEach(async () => {
        fireEvent.click(checkbox);
      });

      it('should remove the indicator', () => {
        expect(indicator).not.toBeInTheDocument();
      });

      it('should call `onCheckedChange` prop', () => {
        expect(onCheckedChange).toHaveBeenCalled();
      });
    });
  });

  describe('given a controlled `checked` Checkbox', () => {
    let rendered: RenderResult;
    let checkbox: HTMLElement;
    const onCheckedChange = vi.fn();

    beforeEach(() => {
      rendered = render(<LegacyCheckbox checked onCheckedChange={onCheckedChange} />);
      checkbox = rendered.getByRole(CHECKBOX_ROLE);
    });

    afterEach(cleanup);

    describe('when clicking the checkbox', () => {
      beforeEach(() => {
        fireEvent.click(checkbox);
      });

      it('should call `onCheckedChange` prop', () => {
        expect(onCheckedChange).toHaveBeenCalled();
      });
    });
  });

  describe('given an uncontrolled Checkbox in form', () => {
    afterEach(cleanup);

    describe('when clicking the checkbox', () => {
      it('should receive change event with target `defaultChecked` same as the `defaultChecked` prop of Checkbox', () =>
        new Promise((done) => {
          const rendered = render(
            <form
              onChange={(event) => {
                const target = event.target as HTMLInputElement;
                expect(target.defaultChecked).toBe(true);
              }}
            >
              <LegacyCheckbox defaultChecked />
            </form>,
          );
          const checkbox = rendered.getByRole(CHECKBOX_ROLE);
          fireEvent.click(checkbox);
          rendered.rerender(
            <form
              onChange={(event) => {
                const target = event.target as HTMLInputElement;
                expect(target.defaultChecked).toBe(false);
                done(null);
              }}
            >
              <LegacyCheckbox defaultChecked={false} />
            </form>,
          );
          fireEvent.click(checkbox);
        }));
    });
  });

  describe('given a controlled Checkbox in a form', () => {
    afterEach(cleanup);

    describe('when clicking the checkbox', () => {
      it('should receive change event with target `defaultChecked` same as initial value of `checked` of Checkbox', () =>
        new Promise((done) => {
          const rendered = render(
            <form
              onChange={(event) => {
                const target = event.target as HTMLInputElement;
                expect(target.defaultChecked).toBe(true);
              }}
            >
              <LegacyCheckbox checked />
            </form>,
          );
          const checkbox = rendered.getByRole(CHECKBOX_ROLE);
          fireEvent.click(checkbox);
          rendered.rerender(
            <form
              onChange={(event) => {
                const target = event.target as HTMLInputElement;
                expect(target.defaultChecked).toBe(true);
                done(null);
              }}
            >
              <LegacyCheckbox checked={false} />
            </form>,
          );
          fireEvent.click(checkbox);
        }));
    });
  });
});

function LegacyCheckbox(props: React.ComponentProps<typeof Checkbox.Root>) {
  const containerRef = React.useRef<HTMLDivElement>(null);
  React.useEffect(() => {
    // We use the `hidden` attribute to hide the nested input from both sighted users and the
    // accessibility tree. This is perfectly valid so long as users don't override the display of
    // `hidden` in CSS. Unfortunately axe doesn't recognize this, so we get a violation because the
    // input doesn't have a label. This adds an additional `aria-hidden` attribute to the input to
    // get around that.
    // https://developer.paciellogroup.com/blog/2012/05/html5-accessibility-chops-hidden-and-aria-hidden/
    containerRef.current?.querySelector('input')?.setAttribute('aria-hidden', 'true');
  }, []);
  return (
    <div ref={containerRef}>
      <Checkbox.Root aria-label="basic checkbox" {...props}>
        <Checkbox.Indicator data-testid={INDICATOR_TEST_ID} />
      </Checkbox.Root>
    </div>
  );
}



================================================
FILE: packages/react/checkbox/src/checkbox.tsx
================================================
import * as React from 'react';
import { useComposedRefs } from '@radix-ui/react-compose-refs';
import { createContextScope } from '@radix-ui/react-context';
import { composeEventHandlers } from '@radix-ui/primitive';
import { useControllableState } from '@radix-ui/react-use-controllable-state';
import { usePrevious } from '@radix-ui/react-use-previous';
import { useSize } from '@radix-ui/react-use-size';
import { Presence } from '@radix-ui/react-presence';
import { Primitive } from '@radix-ui/react-primitive';

import type { Scope } from '@radix-ui/react-context';

const CHECKBOX_NAME = 'Checkbox';

type ScopedProps<P> = P & { __scopeCheckbox?: Scope };
const [createCheckboxContext, createCheckboxScope] = createContextScope(CHECKBOX_NAME);

type CheckedState = boolean | 'indeterminate';

type CheckboxContextValue<State extends CheckedState | boolean = CheckedState> = {
  checked: State | boolean;
  setChecked: React.Dispatch<React.SetStateAction<State | boolean>>;
  disabled: boolean | undefined;
  control: HTMLButtonElement | null;
  setControl: React.Dispatch<React.SetStateAction<HTMLButtonElement | null>>;
  name: string | undefined;
  form: string | undefined;
  value: string | number | readonly string[];
  hasConsumerStoppedPropagationRef: React.RefObject<boolean>;
  required: boolean | undefined;
  defaultChecked: boolean | undefined;
  isFormControl: boolean;
  bubbleInput: HTMLInputElement | null;
  setBubbleInput: React.Dispatch<React.SetStateAction<HTMLInputElement | null>>;
};

const [CheckboxProviderImpl, useCheckboxContext] =
  createCheckboxContext<CheckboxContextValue>(CHECKBOX_NAME);

/* -------------------------------------------------------------------------------------------------
 * CheckboxProvider
 * -----------------------------------------------------------------------------------------------*/

interface CheckboxProviderProps<State extends CheckedState = CheckedState> {
  checked?: State | boolean;
  defaultChecked?: State | boolean;
  required?: boolean;
  onCheckedChange?(checked: State | boolean): void;
  name?: string;
  form?: string;
  disabled?: boolean;
  value?: string | number | readonly string[];
  children?: React.ReactNode;
}

function CheckboxProvider<State extends CheckedState = CheckedState>(
  props: ScopedProps<CheckboxProviderProps<State>>,
) {
  const {
    __scopeCheckbox,
    checked: checkedProp,
    children,
    defaultChecked,
    disabled,
    form,
    name,
    onCheckedChange,
    required,
    value = 'on',
    // @ts-expect-error
    internal_do_not_use_render,
  } = props;

  const [checked, setChecked] = useControllableState({
    prop: checkedProp,
    defaultProp: defaultChecked ?? false,
    onChange: onCheckedChange,
    caller: CHECKBOX_NAME,
  });
  const [control, setControl] = React.useState<HTMLButtonElement | null>(null);
  const [bubbleInput, setBubbleInput] = React.useState<HTMLInputElement | null>(null);
  const hasConsumerStoppedPropagationRef = React.useRef(false);
  const isFormControl = control
    ? !!form || !!control.closest('form')
    : // We set this to true by default so that events bubble to forms without JS (SSR)
      true;

  const context: CheckboxContextValue<State> = {
    checked: checked,
    disabled: disabled,
    setChecked: setChecked,
    control: control,
    setControl: setControl,
    name: name,
    form: form,
    value: value,
    hasConsumerStoppedPropagationRef: hasConsumerStoppedPropagationRef,
    required: required,
    defaultChecked: isIndeterminate(defaultChecked) ? false : defaultChecked,
    isFormControl: isFormControl,
    bubbleInput,
    setBubbleInput,
  };

  return (
    <CheckboxProviderImpl
      scope={__scopeCheckbox}
      {...(context as unknown as CheckboxContextValue<CheckedState>)}
    >
      {isFunction(internal_do_not_use_render) ? internal_do_not_use_render(context) : children}
    </CheckboxProviderImpl>
  );
}

/* -------------------------------------------------------------------------------------------------
 * CheckboxTrigger
 * -----------------------------------------------------------------------------------------------*/

const TRIGGER_NAME = 'CheckboxTrigger';

interface CheckboxTriggerProps
  extends Omit<
    React.ComponentPropsWithoutRef<typeof Primitive.button>,
    keyof CheckboxProviderProps
  > {
  children?: React.ReactNode;
}

const CheckboxTrigger = React.forwardRef<HTMLButtonElement, CheckboxTriggerProps>(
  (
    { __scopeCheckbox, onKeyDown, onClick, ...checkboxProps }: ScopedProps<CheckboxTriggerProps>,
    forwardedRef,
  ) => {
    const {
      control,
      value,
      disabled,
      checked,
      required,
      setControl,
      setChecked,
      hasConsumerStoppedPropagationRef,
      isFormControl,
      bubbleInput,
    } = useCheckboxContext(TRIGGER_NAME, __scopeCheckbox);
    const composedRefs = useComposedRefs(forwardedRef, setControl);

    const initialCheckedStateRef = React.useRef(checked);
    React.useEffect(() => {
      const form = control?.form;
      if (form) {
        const reset = () => setChecked(initialCheckedStateRef.current);
        form.addEventListener('reset', reset);
        return () => form.removeEventListener('reset', reset);
      }
    }, [control, setChecked]);

    return (
      <Primitive.button
        type="button"
        role="checkbox"
        aria-checked={isIndeterminate(checked) ? 'mixed' : checked}
        aria-required={required}
        data-state={getState(checked)}
        data-disabled={disabled ? '' : undefined}
        disabled={disabled}
        value={value}
        {...checkboxProps}
        ref={composedRefs}
        onKeyDown={composeEventHandlers(onKeyDown, (event) => {
          // According to WAI ARIA, Checkboxes don't activate on enter keypress
          if (event.key === 'Enter') event.preventDefault();
        })}
        onClick={composeEventHandlers(onClick, (event) => {
          setChecked((prevChecked) => (isIndeterminate(prevChecked) ? true : !prevChecked));
          if (bubbleInput && isFormControl) {
            hasConsumerStoppedPropagationRef.current = event.isPropagationStopped();
            // if checkbox has a bubble input and is a form control, stop
            // propagation from the button so that we only propagate one click
            // event (from the input). We propagate changes from an input so
            // that native form validation works and form events reflect
            // checkbox updates.
            if (!hasConsumerStoppedPropagationRef.current) event.stopPropagation();
          }
        })}
      />
    );
  },
);

CheckboxTrigger.displayName = TRIGGER_NAME;

/* -------------------------------------------------------------------------------------------------
 * Checkbox
 * -----------------------------------------------------------------------------------------------*/

type CheckboxElement = React.ComponentRef<typeof Primitive.button>;
type PrimitiveButtonProps = React.ComponentPropsWithoutRef<typeof Primitive.button>;
interface CheckboxProps extends Omit<PrimitiveButtonProps, 'checked' | 'defaultChecked'> {
  checked?: CheckedState;
  defaultChecked?: CheckedState;
  required?: boolean;
  onCheckedChange?(checked: CheckedState): void;
}

const Checkbox = React.forwardRef<CheckboxElement, CheckboxProps>(
  (props: ScopedProps<CheckboxProps>, forwardedRef) => {
    const {
      __scopeCheckbox,
      name,
      checked,
      defaultChecked,
      required,
      disabled,
      value,
      onCheckedChange,
      form,
      ...checkboxProps
    } = props;

    return (
      <CheckboxProvider
        __scopeCheckbox={__scopeCheckbox}
        checked={checked}
        defaultChecked={defaultChecked}
        disabled={disabled}
        required={required}
        onCheckedChange={onCheckedChange}
        name={name}
        form={form}
        value={value}
        // @ts-expect-error
        internal_do_not_use_render={({ isFormControl }: CheckboxContextValue) => (
          <>
            <CheckboxTrigger
              {...checkboxProps}
              ref={forwardedRef}
              // @ts-expect-error
              __scopeCheckbox={__scopeCheckbox}
            />
            {isFormControl && (
              <CheckboxBubbleInput
                // @ts-expect-error
                __scopeCheckbox={__scopeCheckbox}
              />
            )}
          </>
        )}
      />
    );
  },
);

Checkbox.displayName = CHECKBOX_NAME;

/* -------------------------------------------------------------------------------------------------
 * CheckboxIndicator
 * -----------------------------------------------------------------------------------------------*/

const INDICATOR_NAME = 'CheckboxIndicator';

type CheckboxIndicatorElement = React.ComponentRef<typeof Primitive.span>;
type PrimitiveSpanProps = React.ComponentPropsWithoutRef<typeof Primitive.span>;
interface CheckboxIndicatorProps extends PrimitiveSpanProps {
  /**
   * Used to force mounting when more control is needed. Useful when
   * controlling animation with React animation libraries.
   */
  forceMount?: true;
}

const CheckboxIndicator = React.forwardRef<CheckboxIndicatorElement, CheckboxIndicatorProps>(
  (props: ScopedProps<CheckboxIndicatorProps>, forwardedRef) => {
    const { __scopeCheckbox, forceMount, ...indicatorProps } = props;
    const context = useCheckboxContext(INDICATOR_NAME, __scopeCheckbox);
    return (
      <Presence
        present={forceMount || isIndeterminate(context.checked) || context.checked === true}
      >
        <Primitive.span
          data-state={getState(context.checked)}
          data-disabled={context.disabled ? '' : undefined}
          {...indicatorProps}
          ref={forwardedRef}
          style={{ pointerEvents: 'none', ...props.style }}
        />
      </Presence>
    );
  },
);

CheckboxIndicator.displayName = INDICATOR_NAME;

/* -------------------------------------------------------------------------------------------------
 * CheckboxBubbleInput
 * -----------------------------------------------------------------------------------------------*/

const BUBBLE_INPUT_NAME = 'CheckboxBubbleInput';

type InputProps = React.ComponentPropsWithoutRef<typeof Primitive.input>;
interface CheckboxBubbleInputProps extends Omit<InputProps, 'checked'> {}

const CheckboxBubbleInput = React.forwardRef<HTMLInputElement, CheckboxBubbleInputProps>(
  ({ __scopeCheckbox, ...props }: ScopedProps<CheckboxBubbleInputProps>, forwardedRef) => {
    const {
      control,
      hasConsumerStoppedPropagationRef,
      checked,
      defaultChecked,
      required,
      disabled,
      name,
      value,
      form,
      bubbleInput,
      setBubbleInput,
    } = useCheckboxContext(BUBBLE_INPUT_NAME, __scopeCheckbox);

    const composedRefs = useComposedRefs(forwardedRef, setBubbleInput);
    const prevChecked = usePrevious(checked);
    const controlSize = useSize(control);

    // Bubble checked change to parents (e.g form change event)
    React.useEffect(() => {
      const input = bubbleInput;
      if (!input) return;

      const inputProto = window.HTMLInputElement.prototype;
      const descriptor = Object.getOwnPropertyDescriptor(
        inputProto,
        'checked',
      ) as PropertyDescriptor;
      const setChecked = descriptor.set;

      const bubbles = !hasConsumerStoppedPropagationRef.current;
      if (prevChecked !== checked && setChecked) {
        const event = new Event('click', { bubbles });
        input.indeterminate = isIndeterminate(checked);
        setChecked.call(input, isIndeterminate(checked) ? false : checked);
        input.dispatchEvent(event);
      }
    }, [bubbleInput, prevChecked, checked, hasConsumerStoppedPropagationRef]);

    const defaultCheckedRef = React.useRef(isIndeterminate(checked) ? false : checked);
    return (
      <Primitive.input
        type="checkbox"
        aria-hidden
        defaultChecked={defaultChecked ?? defaultCheckedRef.current}
        required={required}
        disabled={disabled}
        name={name}
        value={value}
        form={form}
        {...props}
        tabIndex={-1}
        ref={composedRefs}
        style={{
          ...props.style,
          ...controlSize,
          position: 'absolute',
          pointerEvents: 'none',
          opacity: 0,
          margin: 0,
          // We transform because the input is absolutely positioned but we have
          // rendered it **after** the button. This pulls it back to sit on top
          // of the button.
          transform: 'translateX(-100%)',
        }}
      />
    );
  },
);

CheckboxBubbleInput.displayName = BUBBLE_INPUT_NAME;

/* ---------------------------------------------------------------------------------------------- */

function isFunction(value: unknown): value is (...args: any[]) => any {
  return typeof value === 'function';
}

function isIndeterminate(checked?: CheckedState): checked is 'indeterminate' {
  return checked === 'indeterminate';
}

function getState(checked: CheckedState) {
  return isIndeterminate(checked) ? 'indeterminate' : checked ? 'checked' : 'unchecked';
}

export {
  createCheckboxScope,
  //
  Checkbox,
  CheckboxProvider,
  CheckboxTrigger,
  CheckboxIndicator,
  CheckboxBubbleInput,
  //
  Checkbox as Root,
  CheckboxProvider as Provider,
  CheckboxTrigger as Trigger,
  CheckboxIndicator as Indicator,
  CheckboxBubbleInput as BubbleInput,
};
export type {
  CheckboxProps,
  CheckboxProviderProps,
  CheckboxTriggerProps,
  CheckboxIndicatorProps,
  CheckboxBubbleInputProps,
  CheckedState,
};



================================================
FILE: packages/react/checkbox/src/index.ts
================================================
'use client';
export {
  createCheckboxScope,
  //
  Checkbox,
  CheckboxProvider as unstable_CheckboxProvider,
  CheckboxTrigger as unstable_CheckboxTrigger,
  CheckboxIndicator,
  CheckboxBubbleInput as unstable_CheckboxBubbleInput,
  //
  Root,
  Provider as unstable_Provider,
  Trigger as unstable_Trigger,
  Indicator,
  BubbleInput as unstable_BubbleInput,
} from './checkbox';
export type {
  CheckboxProps,
  CheckboxProviderProps as unstable_CheckboxProviderProps,
  CheckboxTriggerProps as unstable_CheckboxTriggerProps,
  CheckboxIndicatorProps,
  CheckboxBubbleInputProps as unstable_CheckboxBubbleInputProps,
  CheckedState,
} from './checkbox';



================================================
FILE: packages/react/collapsible/README.md
================================================
# `react-collapsible`

View docs [here](https://radix-ui.com/primitives/docs/components/collapsible).



================================================
FILE: packages/react/collapsible/CHANGELOG.md
================================================
# @radix-ui/react-collapsible

## 1.1.12

- Updated dependencies: `@radix-ui/react-presence@1.1.5`, `@radix-ui/primitive@1.1.3`, `@radix-ui/react-context@1.1.3`, `@radix-ui/react-primitive@2.1.4`

## 1.1.11

- Replace deprecated 'ElementRef' with 'ComponentRef' (#3426)
- Updated dependencies: `@radix-ui/react-primitive@2.1.3`

## 1.1.10

- Updated dependencies: `@radix-ui/react-primitive@2.1.2`

## 1.1.9

- Updated dependencies: `@radix-ui/react-primitive@2.1.1`

## 1.1.8

- Updated dependencies: `@radix-ui/react-presence@1.1.4`

## 1.1.7

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.2`

## 1.1.6

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.1`

## 1.1.5

- Minor improvements to `useControllableState` to enhance performance, reduce surface area for bugs, and log warnings when misused (#3455)
- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.0`, `@radix-ui/react-primitive@2.1.0`



================================================
FILE: packages/react/collapsible/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/collapsible/package.json
================================================
{
  "name": "@radix-ui/react-collapsible",
  "version": "1.1.12",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/primitive": "workspace:*",
    "@radix-ui/react-compose-refs": "workspace:*",
    "@radix-ui/react-context": "workspace:*",
    "@radix-ui/react-id": "workspace:*",
    "@radix-ui/react-presence": "workspace:*",
    "@radix-ui/react-primitive": "workspace:*",
    "@radix-ui/react-use-controllable-state": "workspace:*",
    "@radix-ui/react-use-layout-effect": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/collapsible/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/collapsible/src/collapsible.test.tsx
================================================
import React from 'react';
import { axe } from 'vitest-axe';
import type { RenderResult } from '@testing-library/react';
import { cleanup, render, fireEvent } from '@testing-library/react';
import { Collapsible, CollapsibleTrigger, CollapsibleContent } from './collapsible';
import { afterEach, describe, it, beforeEach, vi, expect } from 'vitest';

const TRIGGER_TEXT = 'Trigger';
const CONTENT_TEXT = 'Content';

const CollapsibleTest = (props: React.ComponentProps<typeof Collapsible>) => (
  <Collapsible {...props}>
    <CollapsibleTrigger>{TRIGGER_TEXT}</CollapsibleTrigger>
    <CollapsibleContent>{CONTENT_TEXT}</CollapsibleContent>
  </Collapsible>
);

describe('given a default Collapsible', () => {
  let rendered: RenderResult;
  let trigger: HTMLElement;
  let content: HTMLElement | null;

  afterEach(cleanup);

  beforeEach(() => {
    rendered = render(<CollapsibleTest />);
    trigger = rendered.getByText(TRIGGER_TEXT);
  });

  it('should have no accessibility violations', async () => {
    expect(await axe(rendered.container)).toHaveNoViolations();
  });

  describe('when clicking the trigger', () => {
    beforeEach(async () => {
      fireEvent.click(trigger);
      content = rendered.queryByText(CONTENT_TEXT);
    });

    it('should open the content', () => {
      expect(content).toBeVisible();
    });

    describe('and clicking the trigger again', () => {
      beforeEach(() => {
        fireEvent.click(trigger);
      });

      it('should close the content', () => {
        expect(content).not.toBeVisible();
      });
    });
  });
});

describe('given an open uncontrolled Collapsible', () => {
  let rendered: RenderResult;
  let content: HTMLElement | null;
  const onOpenChange = vi.fn();

  afterEach(cleanup);

  beforeEach(() => {
    rendered = render(<CollapsibleTest defaultOpen onOpenChange={onOpenChange} />);
  });

  describe('when clicking the trigger', () => {
    beforeEach(async () => {
      const trigger = rendered.getByText(TRIGGER_TEXT);
      content = rendered.getByText(CONTENT_TEXT);
      fireEvent.click(trigger);
    });

    it('should close the content', () => {
      expect(content).not.toBeVisible();
    });

    it('should call `onOpenChange` prop with `false` value', () => {
      expect(onOpenChange).toHaveBeenCalledWith(false);
    });
  });
});

describe('given an open controlled Collapsible', () => {
  let rendered: RenderResult;
  let content: HTMLElement;
  const onOpenChange = vi.fn();

  afterEach(cleanup);

  beforeEach(() => {
    rendered = render(<CollapsibleTest open onOpenChange={onOpenChange} />);
    content = rendered.getByText(CONTENT_TEXT);
  });

  describe('when clicking the trigger', () => {
    beforeEach(() => {
      const trigger = rendered.getByText(TRIGGER_TEXT);
      fireEvent.click(trigger);
    });

    it('should call `onOpenChange` prop with `false` value', () => {
      expect(onOpenChange).toHaveBeenCalledWith(false);
    });

    it('should not close the content', () => {
      expect(content).toBeVisible();
    });
  });
});



================================================
FILE: packages/react/collapsible/src/collapsible.tsx
================================================
import * as React from 'react';
import { composeEventHandlers } from '@radix-ui/primitive';
import { createContextScope } from '@radix-ui/react-context';
import { useControllableState } from '@radix-ui/react-use-controllable-state';
import { useLayoutEffect } from '@radix-ui/react-use-layout-effect';
import { useComposedRefs } from '@radix-ui/react-compose-refs';
import { Primitive } from '@radix-ui/react-primitive';
import { Presence } from '@radix-ui/react-presence';
import { useId } from '@radix-ui/react-id';

import type { Scope } from '@radix-ui/react-context';

/* -------------------------------------------------------------------------------------------------
 * Collapsible
 * -----------------------------------------------------------------------------------------------*/

const COLLAPSIBLE_NAME = 'Collapsible';

type ScopedProps<P> = P & { __scopeCollapsible?: Scope };
const [createCollapsibleContext, createCollapsibleScope] = createContextScope(COLLAPSIBLE_NAME);

type CollapsibleContextValue = {
  contentId: string;
  disabled?: boolean;
  open: boolean;
  onOpenToggle(): void;
};

const [CollapsibleProvider, useCollapsibleContext] =
  createCollapsibleContext<CollapsibleContextValue>(COLLAPSIBLE_NAME);

type CollapsibleElement = React.ComponentRef<typeof Primitive.div>;
type PrimitiveDivProps = React.ComponentPropsWithoutRef<typeof Primitive.div>;
interface CollapsibleProps extends PrimitiveDivProps {
  defaultOpen?: boolean;
  open?: boolean;
  disabled?: boolean;
  onOpenChange?(open: boolean): void;
}

const Collapsible = React.forwardRef<CollapsibleElement, CollapsibleProps>(
  (props: ScopedProps<CollapsibleProps>, forwardedRef) => {
    const {
      __scopeCollapsible,
      open: openProp,
      defaultOpen,
      disabled,
      onOpenChange,
      ...collapsibleProps
    } = props;

    const [open, setOpen] = useControllableState({
      prop: openProp,
      defaultProp: defaultOpen ?? false,
      onChange: onOpenChange,
      caller: COLLAPSIBLE_NAME,
    });

    return (
      <CollapsibleProvider
        scope={__scopeCollapsible}
        disabled={disabled}
        contentId={useId()}
        open={open}
        onOpenToggle={React.useCallback(() => setOpen((prevOpen) => !prevOpen), [setOpen])}
      >
        <Primitive.div
          data-state={getState(open)}
          data-disabled={disabled ? '' : undefined}
          {...collapsibleProps}
          ref={forwardedRef}
        />
      </CollapsibleProvider>
    );
  },
);

Collapsible.displayName = COLLAPSIBLE_NAME;

/* -------------------------------------------------------------------------------------------------
 * CollapsibleTrigger
 * -----------------------------------------------------------------------------------------------*/

const TRIGGER_NAME = 'CollapsibleTrigger';

type CollapsibleTriggerElement = React.ComponentRef<typeof Primitive.button>;
type PrimitiveButtonProps = React.ComponentPropsWithoutRef<typeof Primitive.button>;
interface CollapsibleTriggerProps extends PrimitiveButtonProps {}

const CollapsibleTrigger = React.forwardRef<CollapsibleTriggerElement, CollapsibleTriggerProps>(
  (props: ScopedProps<CollapsibleTriggerProps>, forwardedRef) => {
    const { __scopeCollapsible, ...triggerProps } = props;
    const context = useCollapsibleContext(TRIGGER_NAME, __scopeCollapsible);
    return (
      <Primitive.button
        type="button"
        aria-controls={context.contentId}
        aria-expanded={context.open || false}
        data-state={getState(context.open)}
        data-disabled={context.disabled ? '' : undefined}
        disabled={context.disabled}
        {...triggerProps}
        ref={forwardedRef}
        onClick={composeEventHandlers(props.onClick, context.onOpenToggle)}
      />
    );
  },
);

CollapsibleTrigger.displayName = TRIGGER_NAME;

/* -------------------------------------------------------------------------------------------------
 * CollapsibleContent
 * -----------------------------------------------------------------------------------------------*/

const CONTENT_NAME = 'CollapsibleContent';

type CollapsibleContentElement = CollapsibleContentImplElement;
interface CollapsibleContentProps extends Omit<CollapsibleContentImplProps, 'present'> {
  /**
   * Used to force mounting when more control is needed. Useful when
   * controlling animation with React animation libraries.
   */
  forceMount?: true;
}

const CollapsibleContent = React.forwardRef<CollapsibleContentElement, CollapsibleContentProps>(
  (props: ScopedProps<CollapsibleContentProps>, forwardedRef) => {
    const { forceMount, ...contentProps } = props;
    const context = useCollapsibleContext(CONTENT_NAME, props.__scopeCollapsible);
    return (
      <Presence present={forceMount || context.open}>
        {({ present }) => (
          <CollapsibleContentImpl {...contentProps} ref={forwardedRef} present={present} />
        )}
      </Presence>
    );
  },
);

CollapsibleContent.displayName = CONTENT_NAME;

/* -----------------------------------------------------------------------------------------------*/

type CollapsibleContentImplElement = React.ComponentRef<typeof Primitive.div>;
interface CollapsibleContentImplProps extends PrimitiveDivProps {
  present: boolean;
}

const CollapsibleContentImpl = React.forwardRef<
  CollapsibleContentImplElement,
  CollapsibleContentImplProps
>((props: ScopedProps<CollapsibleContentImplProps>, forwardedRef) => {
  const { __scopeCollapsible, present, children, ...contentProps } = props;
  const context = useCollapsibleContext(CONTENT_NAME, __scopeCollapsible);
  const [isPresent, setIsPresent] = React.useState(present);
  const ref = React.useRef<CollapsibleContentImplElement>(null);
  const composedRefs = useComposedRefs(forwardedRef, ref);
  const heightRef = React.useRef<number | undefined>(0);
  const height = heightRef.current;
  const widthRef = React.useRef<number | undefined>(0);
  const width = widthRef.current;
  // when opening we want it to immediately open to retrieve dimensions
  // when closing we delay `present` to retrieve dimensions before closing
  const isOpen = context.open || isPresent;
  const isMountAnimationPreventedRef = React.useRef(isOpen);
  const originalStylesRef = React.useRef<Record<string, string>>(undefined);

  React.useEffect(() => {
    const rAF = requestAnimationFrame(() => (isMountAnimationPreventedRef.current = false));
    return () => cancelAnimationFrame(rAF);
  }, []);

  useLayoutEffect(() => {
    const node = ref.current;
    if (node) {
      originalStylesRef.current = originalStylesRef.current || {
        transitionDuration: node.style.transitionDuration,
        animationName: node.style.animationName,
      };
      // block any animations/transitions so the element renders at its full dimensions
      node.style.transitionDuration = '0s';
      node.style.animationName = 'none';

      // get width and height from full dimensions
      const rect = node.getBoundingClientRect();
      heightRef.current = rect.height;
      widthRef.current = rect.width;

      // kick off any animations/transitions that were originally set up if it isn't the initial mount
      if (!isMountAnimationPreventedRef.current) {
        node.style.transitionDuration = originalStylesRef.current.transitionDuration!;
        node.style.animationName = originalStylesRef.current.animationName!;
      }

      setIsPresent(present);
    }
    /**
     * depends on `context.open` because it will change to `false`
     * when a close is triggered but `present` will be `false` on
     * animation end (so when close finishes). This allows us to
     * retrieve the dimensions *before* closing.
     */
  }, [context.open, present]);

  return (
    <Primitive.div
      data-state={getState(context.open)}
      data-disabled={context.disabled ? '' : undefined}
      id={context.contentId}
      hidden={!isOpen}
      {...contentProps}
      ref={composedRefs}
      style={{
        [`--radix-collapsible-content-height` as any]: height ? `${height}px` : undefined,
        [`--radix-collapsible-content-width` as any]: width ? `${width}px` : undefined,
        ...props.style,
      }}
    >
      {isOpen && children}
    </Primitive.div>
  );
});

/* -----------------------------------------------------------------------------------------------*/

function getState(open?: boolean) {
  return open ? 'open' : 'closed';
}

const Root = Collapsible;
const Trigger = CollapsibleTrigger;
const Content = CollapsibleContent;

export {
  createCollapsibleScope,
  //
  Collapsible,
  CollapsibleTrigger,
  CollapsibleContent,
  //
  Root,
  Trigger,
  Content,
};
export type { CollapsibleProps, CollapsibleTriggerProps, CollapsibleContentProps };



================================================
FILE: packages/react/collapsible/src/index.ts
================================================
'use client';
export {
  createCollapsibleScope,
  //
  Collapsible,
  CollapsibleTrigger,
  CollapsibleContent,
  //
  Root,
  Trigger,
  Content,
} from './collapsible';
export type {
  CollapsibleProps,
  CollapsibleTriggerProps,
  CollapsibleContentProps,
} from './collapsible';



================================================
FILE: packages/react/collection/README.md
================================================
# `react-collection`

This is an internal utility, not intended for public usage.



================================================
FILE: packages/react/collection/CHANGELOG.md
================================================
# @radix-ui/react-collection

## 1.1.8

- Updated dependencies: `@radix-ui/react-slot@1.2.4`, `@radix-ui/react-context@1.1.3`, `@radix-ui/react-primitive@2.1.4`

## 1.1.7

- Updated dependencies: `@radix-ui/react-slot@1.2.3`, `@radix-ui/react-primitive@2.1.3`

## 1.1.6

- Updated dependencies: `@radix-ui/react-slot@1.2.2`, `@radix-ui/react-primitive@2.1.2`

## 1.1.5

- Updated dependencies: `@radix-ui/react-slot@1.2.1`, `@radix-ui/react-primitive@2.1.1`

## 1.1.4

- Add unstable collection utilities
- Minor changes to unreleased unstable APIs
- Updated dependencies: `@radix-ui/react-primitive@2.1.0`



================================================
FILE: packages/react/collection/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/collection/package.json
================================================
{
  "name": "@radix-ui/react-collection",
  "version": "1.1.8",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/react-compose-refs": "workspace:*",
    "@radix-ui/react-context": "workspace:*",
    "@radix-ui/react-primitive": "workspace:*",
    "@radix-ui/react-slot": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/collection/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/collection/src/collection-legacy.tsx
================================================
import React from 'react';
import { createContextScope } from '@radix-ui/react-context';
import { useComposedRefs } from '@radix-ui/react-compose-refs';
import { createSlot, type Slot } from '@radix-ui/react-slot';

type SlotProps = React.ComponentPropsWithoutRef<typeof Slot>;
type CollectionElement = HTMLElement;
interface CollectionProps extends SlotProps {
  scope: any;
}

// We have resorted to returning slots directly rather than exposing primitives that can then
// be slotted like `<CollectionItem as={Slot}>…</CollectionItem>`.
// This is because we encountered issues with generic types that cannot be statically analysed
// due to creating them dynamically via createCollection.

function createCollection<ItemElement extends HTMLElement, ItemData = {}>(name: string) {
  /* -----------------------------------------------------------------------------------------------
   * CollectionProvider
   * ---------------------------------------------------------------------------------------------*/

  const PROVIDER_NAME = name + 'CollectionProvider';
  const [createCollectionContext, createCollectionScope] = createContextScope(PROVIDER_NAME);

  type ContextValue = {
    collectionRef: React.RefObject<CollectionElement | null>;
    itemMap: Map<
      React.RefObject<ItemElement | null>,
      { ref: React.RefObject<ItemElement | null> } & ItemData
    >;
  };

  const [CollectionProviderImpl, useCollectionContext] = createCollectionContext<ContextValue>(
    PROVIDER_NAME,
    { collectionRef: { current: null }, itemMap: new Map() },
  );

  const CollectionProvider: React.FC<{ children?: React.ReactNode; scope: any }> = (props) => {
    const { scope, children } = props;
    const ref = React.useRef<CollectionElement>(null);
    const itemMap = React.useRef<ContextValue['itemMap']>(new Map()).current;
    return (
      <CollectionProviderImpl scope={scope} itemMap={itemMap} collectionRef={ref}>
        {children}
      </CollectionProviderImpl>
    );
  };

  CollectionProvider.displayName = PROVIDER_NAME;

  /* -----------------------------------------------------------------------------------------------
   * CollectionSlot
   * ---------------------------------------------------------------------------------------------*/

  const COLLECTION_SLOT_NAME = name + 'CollectionSlot';

  const CollectionSlotImpl = createSlot(COLLECTION_SLOT_NAME);
  const CollectionSlot = React.forwardRef<CollectionElement, CollectionProps>(
    (props, forwardedRef) => {
      const { scope, children } = props;
      const context = useCollectionContext(COLLECTION_SLOT_NAME, scope);
      const composedRefs = useComposedRefs(forwardedRef, context.collectionRef);
      return <CollectionSlotImpl ref={composedRefs}>{children}</CollectionSlotImpl>;
    },
  );

  CollectionSlot.displayName = COLLECTION_SLOT_NAME;

  /* -----------------------------------------------------------------------------------------------
   * CollectionItem
   * ---------------------------------------------------------------------------------------------*/

  const ITEM_SLOT_NAME = name + 'CollectionItemSlot';
  const ITEM_DATA_ATTR = 'data-radix-collection-item';

  type CollectionItemSlotProps = ItemData & {
    children: React.ReactNode;
    scope: any;
  };

  const CollectionItemSlotImpl = createSlot(ITEM_SLOT_NAME);
  const CollectionItemSlot = React.forwardRef<ItemElement, CollectionItemSlotProps>(
    (props, forwardedRef) => {
      const { scope, children, ...itemData } = props;
      const ref = React.useRef<ItemElement>(null);
      const composedRefs = useComposedRefs(forwardedRef, ref);
      const context = useCollectionContext(ITEM_SLOT_NAME, scope);

      React.useEffect(() => {
        context.itemMap.set(ref, { ref, ...(itemData as unknown as ItemData) });
        return () => void context.itemMap.delete(ref);
      });

      return (
        <CollectionItemSlotImpl {...{ [ITEM_DATA_ATTR]: '' }} ref={composedRefs}>
          {children}
        </CollectionItemSlotImpl>
      );
    },
  );

  CollectionItemSlot.displayName = ITEM_SLOT_NAME;

  /* -----------------------------------------------------------------------------------------------
   * useCollection
   * ---------------------------------------------------------------------------------------------*/

  function useCollection(scope: any) {
    const context = useCollectionContext(name + 'CollectionConsumer', scope);

    const getItems = React.useCallback(() => {
      const collectionNode = context.collectionRef.current;
      if (!collectionNode) return [];
      const orderedNodes = Array.from(collectionNode.querySelectorAll(`[${ITEM_DATA_ATTR}]`));
      const items = Array.from(context.itemMap.values());
      const orderedItems = items.sort(
        (a, b) => orderedNodes.indexOf(a.ref.current!) - orderedNodes.indexOf(b.ref.current!),
      );
      return orderedItems;
    }, [context.collectionRef, context.itemMap]);

    return getItems;
  }

  return [
    { Provider: CollectionProvider, Slot: CollectionSlot, ItemSlot: CollectionItemSlot },
    useCollection,
    createCollectionScope,
  ] as const;
}

export { createCollection };
export type { CollectionProps };



================================================
FILE: packages/react/collection/src/collection.tsx
================================================
import React from 'react';
import { createContextScope } from '@radix-ui/react-context';
import { useComposedRefs } from '@radix-ui/react-compose-refs';
import { createSlot, type Slot } from '@radix-ui/react-slot';
import type { EntryOf } from './ordered-dictionary';
import { OrderedDict } from './ordered-dictionary';

type SlotProps = React.ComponentPropsWithoutRef<typeof Slot>;
type CollectionElement = HTMLElement;
interface CollectionProps extends SlotProps {
  scope: any;
}

interface BaseItemData {
  id?: string;
}

type ItemDataWithElement<
  ItemData extends BaseItemData,
  ItemElement extends HTMLElement,
> = ItemData & {
  element: ItemElement;
};

type ItemMap<ItemElement extends HTMLElement, ItemData extends BaseItemData> = OrderedDict<
  ItemElement,
  ItemDataWithElement<ItemData, ItemElement>
>;

function createCollection<ItemElement extends HTMLElement, ItemData extends {} = {}>(name: string) {
  type AllItemData = ItemData & BaseItemData;
  /* -----------------------------------------------------------------------------------------------
   * CollectionProvider
   * ---------------------------------------------------------------------------------------------*/

  const PROVIDER_NAME = name + 'CollectionProvider';
  const [createCollectionContext, createCollectionScope] = createContextScope(PROVIDER_NAME);

  interface ContextValue {
    collectionElement: CollectionElement | null;
    collectionRef: React.Ref<CollectionElement | null>;
    collectionRefObject: React.RefObject<CollectionElement | null>;
    itemMap: ItemMap<ItemElement, AllItemData>;
    setItemMap: React.Dispatch<React.SetStateAction<ItemMap<ItemElement, AllItemData>>>;
  }

  const [CollectionContextProvider, useCollectionContext] = createCollectionContext<ContextValue>(
    PROVIDER_NAME,
    {
      collectionElement: null,
      collectionRef: { current: null },
      collectionRefObject: { current: null },
      itemMap: new OrderedDict(),
      setItemMap: () => void 0,
    },
  );

  type CollectionState = [
    ItemMap: ItemMap<ItemElement, AllItemData>,
    SetItemMap: React.Dispatch<React.SetStateAction<ItemMap<ItemElement, AllItemData>>>,
  ];

  const CollectionProvider: React.FC<{
    children?: React.ReactNode;
    scope: any;
    state?: CollectionState;
  }> = ({ state, ...props }) => {
    return state ? (
      <CollectionProviderImpl {...props} state={state} />
    ) : (
      <CollectionInit {...props} />
    );
  };
  CollectionProvider.displayName = PROVIDER_NAME;

  const CollectionInit: React.FC<{
    children?: React.ReactNode;
    scope: any;
  }> = (props) => {
    const state = useInitCollection();
    return <CollectionProviderImpl {...props} state={state} />;
  };
  CollectionInit.displayName = PROVIDER_NAME + 'Init';

  const CollectionProviderImpl: React.FC<{
    children?: React.ReactNode;
    scope: any;
    state: CollectionState;
  }> = (props) => {
    const { scope, children, state } = props;
    const ref = React.useRef<CollectionElement>(null);
    const [collectionElement, setCollectionElement] = React.useState<CollectionElement | null>(
      null,
    );
    const composeRefs = useComposedRefs(ref, setCollectionElement);
    const [itemMap, setItemMap] = state;

    React.useEffect(() => {
      if (!collectionElement) return;

      const observer = getChildListObserver(() => {
        // setItemMap((map) => {
        //   const copy = new OrderedDict(map).toSorted(([, a], [, b]) =>
        //     !a.element || !b.element ? 0 : isElementPreceding(a.element, b.element) ? -1 : 1
        //   );
        //   // check if the order has changed
        //   let index = -1;
        //   for (const entry of copy) {
        //     index++;
        //     const key = map.keyAt(index)!;
        //     const [copyKey] = entry;
        //     if (key !== copyKey) {
        //       // order has changed!
        //       return copy;
        //     }
        //   }
        //   return map;
        // });
      });
      observer.observe(collectionElement, {
        childList: true,
        subtree: true,
      });
      return () => {
        observer.disconnect();
      };
    }, [collectionElement]);

    return (
      <CollectionContextProvider
        scope={scope}
        itemMap={itemMap}
        setItemMap={setItemMap}
        collectionRef={composeRefs}
        collectionRefObject={ref}
        collectionElement={collectionElement}
      >
        {children}
      </CollectionContextProvider>
    );
  };

  CollectionProviderImpl.displayName = PROVIDER_NAME + 'Impl';

  /* -----------------------------------------------------------------------------------------------
   * CollectionSlot
   * ---------------------------------------------------------------------------------------------*/

  const COLLECTION_SLOT_NAME = name + 'CollectionSlot';

  const CollectionSlotImpl = createSlot(COLLECTION_SLOT_NAME);
  const CollectionSlot = React.forwardRef<CollectionElement, CollectionProps>(
    (props, forwardedRef) => {
      const { scope, children } = props;
      const context = useCollectionContext(COLLECTION_SLOT_NAME, scope);
      const composedRefs = useComposedRefs(forwardedRef, context.collectionRef);
      return <CollectionSlotImpl ref={composedRefs}>{children}</CollectionSlotImpl>;
    },
  );

  CollectionSlot.displayName = COLLECTION_SLOT_NAME;

  /* -----------------------------------------------------------------------------------------------
   * CollectionItem
   * ---------------------------------------------------------------------------------------------*/

  const ITEM_SLOT_NAME = name + 'CollectionItemSlot';
  const ITEM_DATA_ATTR = 'data-radix-collection-item';

  type CollectionItemSlotProps = AllItemData & {
    children: React.ReactNode;
    scope: any;
  };

  const CollectionItemSlotImpl = createSlot(ITEM_SLOT_NAME);
  const CollectionItemSlot = React.forwardRef<ItemElement, CollectionItemSlotProps>(
    (props, forwardedRef) => {
      const { scope, children, ...itemData } = props;
      const ref = React.useRef<ItemElement>(null);
      const [element, setElement] = React.useState<ItemElement | null>(null);
      const composedRefs = useComposedRefs(forwardedRef, ref, setElement);
      const context = useCollectionContext(ITEM_SLOT_NAME, scope);

      const { setItemMap } = context;

      const itemDataRef = React.useRef(itemData);
      if (!shallowEqual(itemDataRef.current, itemData)) {
        itemDataRef.current = itemData;
      }
      const memoizedItemData = itemDataRef.current;

      React.useEffect(() => {
        const itemData = memoizedItemData;
        setItemMap((map) => {
          if (!element) {
            return map;
          }

          if (!map.has(element)) {
            map.set(element, { ...(itemData as unknown as AllItemData), element });
            return map.toSorted(sortByDocumentPosition);
          }

          return map
            .set(element, { ...(itemData as unknown as AllItemData), element })
            .toSorted(sortByDocumentPosition);
        });

        return () => {
          setItemMap((map) => {
            if (!element || !map.has(element)) {
              return map;
            }
            map.delete(element);
            return new OrderedDict(map);
          });
        };
      }, [element, memoizedItemData, setItemMap]);

      return (
        <CollectionItemSlotImpl {...{ [ITEM_DATA_ATTR]: '' }} ref={composedRefs as any}>
          {children}
        </CollectionItemSlotImpl>
      );
    },
  );

  CollectionItemSlot.displayName = ITEM_SLOT_NAME;

  /* -----------------------------------------------------------------------------------------------
   * useInitCollection
   * ---------------------------------------------------------------------------------------------*/

  function useInitCollection() {
    return React.useState<ItemMap<ItemElement, AllItemData>>(new OrderedDict());
  }

  /* -----------------------------------------------------------------------------------------------
   * useCollection
   * ---------------------------------------------------------------------------------------------*/

  function useCollection(scope: any) {
    const { itemMap } = useCollectionContext(name + 'CollectionConsumer', scope);

    return itemMap;
  }

  const functions = {
    createCollectionScope,
    useCollection,
    useInitCollection,
  };

  return [
    { Provider: CollectionProvider, Slot: CollectionSlot, ItemSlot: CollectionItemSlot },
    functions,
  ] as const;
}

export { createCollection };
export type { CollectionProps };

function shallowEqual(a: any, b: any) {
  if (a === b) return true;
  if (typeof a !== 'object' || typeof b !== 'object') return false;
  if (a == null || b == null) return false;
  const keysA = Object.keys(a);
  const keysB = Object.keys(b);
  if (keysA.length !== keysB.length) return false;
  for (const key of keysA) {
    if (!Object.prototype.hasOwnProperty.call(b, key)) return false;
    if (a[key] !== b[key]) return false;
  }
  return true;
}

function isElementPreceding(a: Element, b: Element) {
  return !!(b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_PRECEDING);
}

function sortByDocumentPosition<E extends HTMLElement, T extends BaseItemData>(
  a: EntryOf<ItemMap<E, T>>,
  b: EntryOf<ItemMap<E, T>>,
) {
  return !a[1].element || !b[1].element
    ? 0
    : isElementPreceding(a[1].element, b[1].element)
      ? -1
      : 1;
}

function getChildListObserver(callback: () => void) {
  const observer = new MutationObserver((mutationsList) => {
    for (const mutation of mutationsList) {
      if (mutation.type === 'childList') {
        callback();
        return;
      }
    }
  });

  return observer;
}



================================================
FILE: packages/react/collection/src/index.ts
================================================
'use client';
export { createCollection } from './collection-legacy';
export type { CollectionProps } from './collection-legacy';

export { createCollection as unstable_createCollection } from './collection';
export type { CollectionProps as unstable_CollectionProps } from './collection';



================================================
FILE: packages/react/collection/src/ordered-dictionary.test.ts
================================================
import { describe, expect, test } from 'vitest';
import { OrderedDict } from './ordered-dictionary';

describe('OrderedDict', () => {
  test('size', () => {
    const dict = new OrderedDict([
      ['a', 1],
      ['b', 2],
      ['c', 3],
    ]);
    expect(dict.size).toBe(3);
    dict.delete('b');
    expect(dict.size).toBe(2);
    dict.set('d', 4);
    expect(dict.size).toBe(3);
    dict.clear();
    expect(dict.size).toBe(0);
  });

  test('get()', () => {
    const dict = new OrderedDict([
      ['a', 1],
      ['b', 2],
      ['c', 3],
    ]);
    expect(dict.get('a')).toBe(1);
    expect(dict.get('b')).toBe(2);
    expect(dict.get('d')).toBeUndefined();
  });

  test('set()', () => {
    const dict = new OrderedDict([
      ['a', 1],
      ['b', 2],
      ['c', 3],
    ]);
    dict.set('b', 4);
    expect(dict.get('b')).toBe(4);
    dict.set('d', 5);
    expect(dict.get('d')).toBe(5);
  });

  test('insert(): existing key at its current index', () => {
    const dict = new OrderedDict([
      ['a', 1],
      ['b', 2],
      ['c', 3],
    ]);
    dict.insert(1, 'b', 4);
    expect(dict.get('b')).toBe(4);
  });

  test('insert(): existing key at a new index', () => {
    const dict = new OrderedDict([
      ['a', 1],
      ['b', 2],
      ['c', 3],
    ]);
    dict.insert(0, 'b', 1);
    // sets the correct value
    expect(dict.get('b')).toBe(1);

    // moves to the inserted index
    expect(dict.at(0)).toBe(1);
    expect(dict.keyAt(0)).toBe('b');

    // previous item at the inserted index is moved up by one
    expect(dict.keyAt(1)).toBe('a');
    expect(dict.get('a')).toBe(1);
  });

  test('insert(): existing key at out-of-range index', () => {
    const dict = new OrderedDict([
      ['a', 1],
      ['b', 2],
      ['c', 3],
    ]);
    dict.insert(20, 'd', 4);
    expect(dict.keyAt(3)).toBe('d');
    expect(dict.at(3)).toBe(4);
  });

  test('insert(): existing key at 0 index', () => {
    const dict = new OrderedDict([
      ['a', 0],
      ['b', 2],
      ['c', 3],
      ['e', 5],
    ]);
    dict.insert(0, 'a', 1);
    expect(dict.keyAt(0)).toBe('a');
    expect(dict.at(0)).toBe(1);
    expect(dict.keyAt(1)).toBe('b');
    expect(dict.at(1)).toBe(2);
    expect(dict.size).toBe(4);
  });

  test('insert(): new key at 0 index', () => {
    const dict = new OrderedDict([
      ['b', 2],
      ['c', 3],
      ['e', 5],
    ]);
    dict.insert(0, 'a', 1);
    expect(dict.keyAt(0)).toBe('a');
    expect(dict.at(0)).toBe(1);
    expect(dict.keyAt(1)).toBe('b');
    expect(dict.at(1)).toBe(2);
    expect(dict.size).toBe(4);
  });

  test('insert(): existing key at relative negative index', () => {
    const dict = new OrderedDict([
      ['a', 1],
      ['b', 2],
      ['c', 3],
      ['e', 5],
      ['f', 4],
    ]);
    dict.insert(-1, 'f', 6);
    expect(dict.keyAt(-1)).toBe('f');
    expect(dict.at(-1)).toBe(6);
    expect(dict.size).toBe(5);
  });

  test('insert(): new key at relative negative index', () => {
    const dict = new OrderedDict([
      ['a', 1],
      ['b', 2],
      ['c', 3],
      ['e', 5],
    ]);
    dict.insert(-1, 'f', 6);
    expect(dict.keyAt(-1)).toBe('f');
    expect(dict.at(0)).toBe(1);
    expect(dict.at(-1)).toBe(6);

    dict.insert(-3, 'd', 4);
    expect(dict.keyAt(3)).toBe('d');
    expect(dict.at(3)).toBe(4);
  });

  test('insert(): existing key at a new index', () => {
    const dict = new OrderedDict([
      ['a', 1],
      ['b', 2],
      ['c', 3],
    ]);
    dict.insert(0, 'b', 1);
    expect(dict.get('b')).toBe(1);
    expect(dict.at(0)).toBe(1);
    expect(dict.keyAt(0)).toBe('b');
  });

  test('insert(): adds item to existing object', () => {
    const dict = new OrderedDict([
      ['a', 1],
      ['b', 2],
      ['c', 3],
    ]);
    const next = dict.insert(0, 'b', 1);
    expect(next).toBe(dict);
  });

  test('with(): returns a new reference', () => {
    const dict = new OrderedDict([
      ['a', 1],
      ['b', 2],
      ['c', 3],
    ]);
    const next = dict.with(0, 'b', 1);
    expect(next).not.toBe(dict);
  });

  test('with(): does not update copied object', () => {
    const dict = new OrderedDict([
      ['a', 1],
      ['b', 2],
      ['c', 3],
    ]);
    dict.with(0, 'b', 1);
    expect(dict.get('b')).toBe(2);
    expect(dict.keyAt(1)).toBe('b');
  });

  test('first()', () => {
    expect(
      new OrderedDict([
        ['a', 1],
        ['b', 2],
        ['c', 3],
        ['d', 4],
      ]).first(),
    ).toEqual(['a', 1]);
    expect(new OrderedDict().first()).toBeUndefined();
  });

  test('last()', () => {
    expect(
      new OrderedDict([
        ['a', 1],
        ['b', 2],
        ['c', 3],
        ['d', 4],
      ]).last(),
    ).toEqual(['d', 4]);
    expect(new OrderedDict().last()).toBeUndefined();
  });

  test('before()', () => {
    const dict = new OrderedDict([
      ['a', 1],
      ['b', 2],
      ['c', 3],
      ['d', 4],
    ]);
    expect(dict.before('b')).toEqual(['a', 1]);
    expect(dict.before('a')).toBeUndefined();
  });

  test('after()', () => {
    const dict = new OrderedDict([
      ['a', 1],
      ['b', 2],
      ['c', 3],
      ['d', 4],
    ]);
    expect(dict.after('b')).toEqual(['c', 3]);
    expect(dict.after('d')).toBeUndefined();
  });

  test('clear()', () => {
    const dict = new OrderedDict([
      ['a', 1],
      ['b', 2],
    ]);
    dict.clear();
    expect(dict.size).toBe(0);
    expect(dict.get('a')).toBeUndefined();
    expect(dict.get('b')).toBeUndefined();
    expect(dict.at(0)).toBeUndefined();
  });

  test('delete(): existing key', () => {
    const dict = new OrderedDict([
      ['a', 1],
      ['b', 2],
    ]);
    const status = dict.delete('a');
    expect(status).toBe(true);
    expect(dict.size).toBe(1);
    expect(dict.get('a')).toBeUndefined();
    expect(dict.at(0)).toBe(2);
  });

  test('delete(): non-existing key', () => {
    const dict = new OrderedDict([
      ['a', 1],
      ['b', 2],
    ]);
    const status = dict.delete('c');
    expect(status).toBe(false);
    expect(dict.size).toBe(2);
    expect(dict.at(0)).toBe(1);
  });

  test('deleteAt(): standard indices', () => {
    const dict = new OrderedDict([
      ['a', 1],
      ['b', 2],
      ['c', 3],
      ['d', 4],
    ]);
    const status = dict.deleteAt(0);
    expect(status).toBe(true);
    expect(dict.size).toBe(3);
    expect(dict.get('a')).toBeUndefined();

    dict.deleteAt(1);
    expect(dict.size).toBe(2);
    expect(dict.get('c')).toBeUndefined();
  });

  test('deleteAt(): negative indices', () => {
    const dict = new OrderedDict([
      ['a', 1],
      ['b', 2],
      ['c', 3],
      ['d', 4],
    ]);
    const status = dict.deleteAt(-1);
    expect(status).toBe(true);
    expect(dict.size).toBe(3);
    expect(dict.get('d')).toBeUndefined();

    dict.deleteAt(-2);
    expect(dict.size).toBe(2);
    expect(dict.get('b')).toBeUndefined();
  });

  test('deleteAt(): out-of-range indices', () => {
    const dict = new OrderedDict([
      ['a', 1],
      ['b', 2],
      ['c', 3],
      ['d', 4],
    ]);
    let status = dict.deleteAt(20);
    expect(status).toBe(false);
    expect(dict.size).toBe(4);
    status = dict.deleteAt(-20);
    expect(status).toBe(false);
    expect(dict.size).toBe(4);
  });

  describe('find', () => {
    const dict = new OrderedDict([
      ['a', 1],
      ['b', 2],
      ['c', 3],
    ]);
    test('key: found', () => {
      const result = dict.find(([key]) => key === 'b');
      expect(result).toEqual(['b', 2]);
    });

    test('key: not found', () => {
      const result = dict.find(([key]) => key === 'd');
      expect(result).toBeUndefined();
    });

    test('value: found', () => {
      const result = dict.find(([, value]) => value === 3);
      expect(result).toEqual(['c', 3]);
    });

    test('value: not found', () => {
      const result = dict.find(([, value]) => value === 4);
      expect(result).toBeUndefined();
    });

    test('thisArg', () => {
      const result = dict.find(function (this: number, [, value]) {
        return value === this;
      }, 1);
      expect(result).toEqual(['a', 1]);
    });

    test('no thisArg', () => {
      const result = dict.find(function (this: unknown, _, dictionary) {
        return dictionary === this;
      });
      expect(result).toBeUndefined();
    });
  });

  describe('findIndex', () => {
    const dict = new OrderedDict([
      ['a', 1],
      ['b', 2],
      ['c', 3],
    ]);
    test('key: found', () => {
      const result = dict.findIndex(([key]) => key === 'b');
      expect(result).toBe(1);
    });

    test('key: not found', () => {
      const result = dict.findIndex(([key]) => key === 'd');
      expect(result).toBe(-1);
    });

    test('value: found', () => {
      const result = dict.findIndex(([, value]) => value === 3);
      expect(result).toBe(2);
    });

    test('value: not found', () => {
      const result = dict.findIndex(([, value]) => value === 4);
      expect(result).toBe(-1);
    });

    test('with thisArg', () => {
      const thisArg = { key: 'b' };
      const result = dict.findIndex(function (this: typeof thisArg, [key]) {
        return key === this.key;
      }, thisArg);
      expect(result).toBe(1);
    });

    test('no thisArg', () => {
      expect(() => {
        dict.findIndex(function (this: unknown, [, value]) {
          return value === (this as any).get('b');
        });
      }).toThrow();
    });
  });

  describe('filter', () => {
    test('makes a copy of the dictionary', () => {
      const dict = new OrderedDict([
        ['a', 1],
        ['b', 2],
        ['c', 3],
      ]);
      const result = dict.filter(() => true);
      expect(result).not.toBe(dict);
    });

    test('misc', () => {
      const dict = new OrderedDict([
        ['a', 1],
        ['b', 2],
        ['c', 3],
      ]);
      const result = dict.filter(([key, value]) => key === 'b' || value === 3);
      expect(result).toEqual(
        new OrderedDict([
          ['b', 2],
          ['c', 3],
        ]),
      );

      const result2 = dict.filter(([key]) => key === 'd');
      expect(result2).toEqual(new OrderedDict());

      const result3 = dict.filter(([, value]) => value === 3);
      expect(result3).toEqual(new OrderedDict([['c', 3]]));

      const result4 = dict.filter(([, value]) => value === 4);
      expect(result4).toEqual(new OrderedDict());
    });
  });

  describe('some', () => {
    const dict = new OrderedDict([
      ['a', 1],
      ['b', 2],
      ['c', 3],
    ]);

    test('key: truthy', () => {
      const result = dict.some(([key]) => key === 'b');
      expect(result).toBe(true);
    });

    test('key: falsey', () => {
      const result = dict.some(([key]) => key === 'd');
      expect(result).toBe(false);
    });

    test('value: truthy', () => {
      const result = dict.some(([, value]) => value === 2);
      expect(result).toBe(true);
    });

    test('value: truthy', () => {
      const result = dict.some(([, value]) => value === 4);
      expect(result).toBe(false);
    });

    test('thisArg', () => {
      const result = dict.some(function (this: string, [key]) {
        return key === this;
      }, 'b');
      expect(result).toBe(true);
    });

    test('no thisArg', () => {
      expect(() =>
        dict.some(function (this: unknown, [, value]) {
          return (this as any).get('b') === value;
        }),
      ).toThrow();
    });
  });

  describe('every', () => {
    const dict = new OrderedDict([
      ['a', 1],
      ['b', 2],
      ['c', 3],
    ]);

    test('key: truthy', () => {
      const result = dict.every(([key]) => key.length === 1);
      expect(result).toBe(true);
    });

    test('key: falsey', () => {
      const result = dict.every(([key]) => key === 'a');
      expect(result).toBe(false);
    });

    test('value: truthy', () => {
      const result = dict.every(([, value]) => value > 0);
      expect(result).toBe(true);
    });

    test('value: falsey', () => {
      const result = dict.every(([, value]) => value > 1);
      expect(result).toBe(false);
    });

    test('thisArg', () => {
      const result = dict.every(function (this: string, [key]) {
        return typeof key === typeof this;
      }, 'b');
      expect(result).toBe(true);
    });

    test('no thisArg', () => {
      expect(() =>
        dict.every(function (this: unknown, [, value]) {
          return typeof (this as any).get('b') === typeof value;
        }),
      ).toThrow();
    });
  });
});



================================================
FILE: packages/react/collection/src/ordered-dictionary.ts
================================================
// Not a real member because it shouldn't be accessible, but the super class
// calls `set` which needs to read the instanciation state, so it can't be a
// private member.
const __instanciated = new WeakMap<OrderedDict<any, any>, boolean>();
export class OrderedDict<K, V> extends Map<K, V> {
  #keys: K[];

  constructor(iterable?: Iterable<readonly [K, V]> | null | undefined);
  constructor(entries?: readonly (readonly [K, V])[] | null) {
    super(entries);
    this.#keys = [...super.keys()];
    __instanciated.set(this, true);
  }

  set(key: K, value: V) {
    if (__instanciated.get(this)) {
      if (this.has(key)) {
        this.#keys[this.#keys.indexOf(key)] = key;
      } else {
        this.#keys.push(key);
      }
    }
    super.set(key, value);
    return this;
  }

  insert(index: number, key: K, value: V) {
    const has = this.has(key);
    const length = this.#keys.length;
    const relativeIndex = toSafeInteger(index);
    let actualIndex = relativeIndex >= 0 ? relativeIndex : length + relativeIndex;
    const safeIndex = actualIndex < 0 || actualIndex >= length ? -1 : actualIndex;

    if (safeIndex === this.size || (has && safeIndex === this.size - 1) || safeIndex === -1) {
      this.set(key, value);
      return this;
    }

    const size = this.size + (has ? 0 : 1);

    // If you insert at, say, -2, without this bit you'd replace the
    // second-to-last item and push the rest up one, which means the new item is
    // 3rd to last. This isn't very intuitive; inserting at -2 is more like
    // saying "make this item the second to last".
    if (relativeIndex < 0) {
      actualIndex++;
    }

    const keys = [...this.#keys];
    let nextValue: V | undefined;
    let shouldSkip = false;
    for (let i = actualIndex; i < size; i++) {
      if (actualIndex === i) {
        let nextKey = keys[i]!;
        if (keys[i] === key) {
          nextKey = keys[i + 1]!;
        }
        if (has) {
          // delete first to ensure that the item is moved to the end
          this.delete(key);
        }
        nextValue = this.get(nextKey);
        this.set(key, value);
      } else {
        if (!shouldSkip && keys[i - 1] === key) {
          shouldSkip = true;
        }
        const currentKey = keys[shouldSkip ? i : i - 1]!;
        const currentValue = nextValue!;
        nextValue = this.get(currentKey);
        this.delete(currentKey);
        this.set(currentKey, currentValue);
      }
    }
    return this;
  }

  with(index: number, key: K, value: V) {
    const copy = new OrderedDict(this);
    copy.insert(index, key, value);
    return copy;
  }

  before(key: K) {
    const index = this.#keys.indexOf(key) - 1;
    if (index < 0) {
      return undefined;
    }
    return this.entryAt(index);
  }

  /**
   * Sets a new key-value pair at the position before the given key.
   */
  setBefore(key: K, newKey: K, value: V) {
    const index = this.#keys.indexOf(key);
    if (index === -1) {
      return this;
    }
    return this.insert(index, newKey, value);
  }

  after(key: K) {
    let index = this.#keys.indexOf(key);
    index = index === -1 || index === this.size - 1 ? -1 : index + 1;
    if (index === -1) {
      return undefined;
    }
    return this.entryAt(index);
  }

  /**
   * Sets a new key-value pair at the position after the given key.
   */
  setAfter(key: K, newKey: K, value: V) {
    const index = this.#keys.indexOf(key);
    if (index === -1) {
      return this;
    }
    return this.insert(index + 1, newKey, value);
  }

  first() {
    return this.entryAt(0);
  }

  last() {
    return this.entryAt(-1);
  }

  clear() {
    this.#keys = [];
    return super.clear();
  }

  delete(key: K) {
    const deleted = super.delete(key);
    if (deleted) {
      this.#keys.splice(this.#keys.indexOf(key), 1);
    }
    return deleted;
  }

  deleteAt(index: number) {
    const key = this.keyAt(index);
    if (key !== undefined) {
      return this.delete(key);
    }
    return false;
  }

  at(index: number) {
    const key = at(this.#keys, index);
    if (key !== undefined) {
      return this.get(key);
    }
  }

  entryAt(index: number): [K, V] | undefined {
    const key = at(this.#keys, index);
    if (key !== undefined) {
      return [key, this.get(key)!];
    }
  }

  indexOf(key: K) {
    return this.#keys.indexOf(key);
  }

  keyAt(index: number) {
    return at(this.#keys, index);
  }

  from(key: K, offset: number) {
    const index = this.indexOf(key);
    if (index === -1) {
      return undefined;
    }
    let dest = index + offset;
    if (dest < 0) dest = 0;
    if (dest >= this.size) dest = this.size - 1;
    return this.at(dest);
  }

  keyFrom(key: K, offset: number) {
    const index = this.indexOf(key);
    if (index === -1) {
      return undefined;
    }
    let dest = index + offset;
    if (dest < 0) dest = 0;
    if (dest >= this.size) dest = this.size - 1;
    return this.keyAt(dest);
  }

  find(
    predicate: (entry: [K, V], index: number, dictionary: OrderedDict<K, V>) => boolean,
    thisArg?: any,
  ) {
    let index = 0;
    for (const entry of this) {
      if (Reflect.apply(predicate, thisArg, [entry, index, this])) {
        return entry;
      }
      index++;
    }
    return undefined;
  }

  findIndex(
    predicate: (entry: [K, V], index: number, dictionary: OrderedDict<K, V>) => boolean,
    thisArg?: any,
  ) {
    let index = 0;
    for (const entry of this) {
      if (Reflect.apply(predicate, thisArg, [entry, index, this])) {
        return index;
      }
      index++;
    }
    return -1;
  }

  filter<KK extends K, VV extends V>(
    predicate: (entry: [K, V], index: number, dict: OrderedDict<K, V>) => entry is [KK, VV],
    thisArg?: any,
  ): OrderedDict<KK, VV>;

  filter(
    predicate: (entry: [K, V], index: number, dictionary: OrderedDict<K, V>) => unknown,
    thisArg?: any,
  ): OrderedDict<K, V>;

  filter(
    predicate: (entry: [K, V], index: number, dictionary: OrderedDict<K, V>) => unknown,
    thisArg?: any,
  ) {
    const entries: Array<[K, V]> = [];
    let index = 0;
    for (const entry of this) {
      if (Reflect.apply(predicate, thisArg, [entry, index, this])) {
        entries.push(entry);
      }
      index++;
    }
    return new OrderedDict(entries);
  }

  map<U>(
    callbackfn: (entry: [K, V], index: number, dictionary: OrderedDict<K, V>) => U,
    thisArg?: any,
  ): OrderedDict<K, U> {
    const entries: [K, U][] = [];
    let index = 0;
    for (const entry of this) {
      entries.push([entry[0], Reflect.apply(callbackfn, thisArg, [entry, index, this])]);
      index++;
    }
    return new OrderedDict(entries);
  }

  reduce(
    callbackfn: (
      previousValue: [K, V],
      currentEntry: [K, V],
      currentIndex: number,
      dictionary: OrderedDict<K, V>,
    ) => [K, V],
  ): [K, V];
  reduce(
    callbackfn: (
      previousValue: [K, V],
      currentEntry: [K, V],
      currentIndex: number,
      dictionary: OrderedDict<K, V>,
    ) => [K, V],
    initialValue: [K, V],
  ): [K, V];
  reduce<U>(
    callbackfn: (
      previousValue: U,
      currentEntry: [K, V],
      currentIndex: number,
      dictionary: OrderedDict<K, V>,
    ) => U,
    initialValue: U,
  ): U;

  reduce<U>(
    ...args: [
      (
        previousValue: U,
        currentEntry: [K, V],
        currentIndex: number,
        dictionary: OrderedDict<K, V>,
      ) => U,
      U?,
    ]
  ) {
    const [callbackfn, initialValue] = args;
    let index = 0;
    let accumulator = initialValue ?? this.at(0)!;
    for (const entry of this) {
      if (index === 0 && args.length === 1) {
        accumulator = entry as any;
      } else {
        accumulator = Reflect.apply(callbackfn, this, [accumulator, entry, index, this]);
      }
      index++;
    }
    return accumulator;
  }

  reduceRight(
    callbackfn: (
      previousValue: [K, V],
      currentEntry: [K, V],
      currentIndex: number,
      dictionary: OrderedDict<K, V>,
    ) => [K, V],
  ): [K, V];
  reduceRight(
    callbackfn: (
      previousValue: [K, V],
      currentEntry: [K, V],
      currentIndex: number,
      dictionary: OrderedDict<K, V>,
    ) => [K, V],
    initialValue: [K, V],
  ): [K, V];
  reduceRight<U>(
    callbackfn: (
      previousValue: [K, V],
      currentValue: U,
      currentIndex: number,
      dictionary: OrderedDict<K, V>,
    ) => U,
    initialValue: U,
  ): U;

  reduceRight<U>(
    ...args: [
      (
        previousValue: U,
        currentEntry: [K, V],
        currentIndex: number,
        dictionary: OrderedDict<K, V>,
      ) => U,
      U?,
    ]
  ) {
    const [callbackfn, initialValue] = args;
    let accumulator = initialValue ?? this.at(-1)!;
    for (let index = this.size - 1; index >= 0; index--) {
      const entry = this.at(index)!;
      if (index === this.size - 1 && args.length === 1) {
        accumulator = entry as any;
      } else {
        accumulator = Reflect.apply(callbackfn, this, [accumulator, entry, index, this]);
      }
    }
    return accumulator;
  }

  toSorted(compareFn?: (a: [K, V], b: [K, V]) => number): OrderedDict<K, V> {
    const entries = [...this.entries()].sort(compareFn);
    return new OrderedDict(entries);
  }

  toReversed(): OrderedDict<K, V> {
    const reversed = new OrderedDict<K, V>();
    for (let index = this.size - 1; index >= 0; index--) {
      const key = this.keyAt(index)!;
      const element = this.get(key)!;
      reversed.set(key, element);
    }
    return reversed;
  }

  toSpliced(start: number, deleteCount?: number): OrderedDict<K, V>;
  toSpliced(start: number, deleteCount: number, ...items: [K, V][]): OrderedDict<K, V>;

  toSpliced(...args: [start: number, deleteCount: number, ...items: [K, V][]]) {
    const entries = [...this.entries()];
    entries.splice(...args);
    return new OrderedDict(entries);
  }

  slice(start?: number, end?: number) {
    const result = new OrderedDict<K, V>();
    let stop = this.size - 1;

    if (start === undefined) {
      return result;
    }

    if (start < 0) {
      start = start + this.size;
    }

    if (end !== undefined && end > 0) {
      stop = end - 1;
    }

    for (let index = start; index <= stop; index++) {
      const key = this.keyAt(index)!;
      const element = this.get(key)!;
      result.set(key, element);
    }
    return result;
  }

  every(
    predicate: (entry: [K, V], index: number, dictionary: OrderedDict<K, V>) => unknown,
    thisArg?: any,
  ) {
    let index = 0;
    for (const entry of this) {
      if (!Reflect.apply(predicate, thisArg, [entry, index, this])) {
        return false;
      }
      index++;
    }
    return true;
  }

  some(
    predicate: (entry: [K, V], index: number, dictionary: OrderedDict<K, V>) => unknown,
    thisArg?: any,
  ) {
    let index = 0;
    for (const entry of this) {
      if (Reflect.apply(predicate, thisArg, [entry, index, this])) {
        return true;
      }
      index++;
    }
    return false;
  }
}

export type KeyOf<D extends OrderedDict<any, any>> =
  D extends OrderedDict<infer K, any> ? K : never;
export type ValueOf<D extends OrderedDict<any, any>> =
  D extends OrderedDict<any, infer V> ? V : never;
export type EntryOf<D extends OrderedDict<any, any>> = [KeyOf<D>, ValueOf<D>];
export type KeyFrom<E extends EntryOf<any>> = E[0];
export type ValueFrom<E extends EntryOf<any>> = E[1];

function at<T>(array: ArrayLike<T>, index: number): T | undefined {
  if ('at' in Array.prototype) {
    return Array.prototype.at.call(array, index);
  }
  const actualIndex = toSafeIndex(array, index);
  return actualIndex === -1 ? undefined : array[actualIndex];
}

function toSafeIndex(array: ArrayLike<any>, index: number) {
  const length = array.length;
  const relativeIndex = toSafeInteger(index);
  const actualIndex = relativeIndex >= 0 ? relativeIndex : length + relativeIndex;
  return actualIndex < 0 || actualIndex >= length ? -1 : actualIndex;
}

function toSafeInteger(number: number) {
  // eslint-disable-next-line no-self-compare
  return number !== number || number === 0 ? 0 : Math.trunc(number);
}



================================================
FILE: packages/react/compose-refs/README.md
================================================
# `react-compose-refs`

This is an internal utility, not intended for public usage.



================================================
FILE: packages/react/compose-refs/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/compose-refs/package.json
================================================
{
  "name": "@radix-ui/react-compose-refs",
  "version": "1.1.2",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/compose-refs/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/compose-refs/src/compose-refs.tsx
================================================
import * as React from 'react';

type PossibleRef<T> = React.Ref<T> | undefined;

/**
 * Set a given ref to a given value
 * This utility takes care of different types of refs: callback refs and RefObject(s)
 */
function setRef<T>(ref: PossibleRef<T>, value: T) {
  if (typeof ref === 'function') {
    return ref(value);
  } else if (ref !== null && ref !== undefined) {
    ref.current = value;
  }
}

/**
 * A utility to compose multiple refs together
 * Accepts callback refs and RefObject(s)
 */
function composeRefs<T>(...refs: PossibleRef<T>[]): React.RefCallback<T> {
  return (node) => {
    let hasCleanup = false;
    const cleanups = refs.map((ref) => {
      const cleanup = setRef(ref, node);
      if (!hasCleanup && typeof cleanup == 'function') {
        hasCleanup = true;
      }
      return cleanup;
    });

    // React <19 will log an error to the console if a callback ref returns a
    // value. We don't use ref cleanups internally so this will only happen if a
    // user's ref callback returns a value, which we only expect if they are
    // using the cleanup functionality added in React 19.
    if (hasCleanup) {
      return () => {
        for (let i = 0; i < cleanups.length; i++) {
          const cleanup = cleanups[i];
          if (typeof cleanup == 'function') {
            cleanup();
          } else {
            setRef(refs[i], null);
          }
        }
      };
    }
  };
}

/**
 * A custom hook that composes multiple refs
 * Accepts callback refs and RefObject(s)
 */
function useComposedRefs<T>(...refs: PossibleRef<T>[]): React.RefCallback<T> {
  // eslint-disable-next-line react-hooks/exhaustive-deps
  return React.useCallback(composeRefs(...refs), refs);
}

export { composeRefs, useComposedRefs };



================================================
FILE: packages/react/compose-refs/src/index.ts
================================================
export { composeRefs, useComposedRefs } from './compose-refs';



================================================
FILE: packages/react/context/README.md
================================================
# `react-context`

This is an internal utility, not intended for public usage.



================================================
FILE: packages/react/context/CHANGELOG.md
================================================
# @radix-ui/react-context

## 1.1.3

- Added `displayName` to context objects



================================================
FILE: packages/react/context/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/context/package.json
================================================
{
  "name": "@radix-ui/react-context",
  "version": "1.1.3",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/context/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/context/src/create-context.tsx
================================================
import * as React from 'react';

function createContext<ContextValueType extends object | null>(
  rootComponentName: string,
  defaultContext?: ContextValueType,
) {
  const Context = React.createContext<ContextValueType | undefined>(defaultContext);
  Context.displayName = rootComponentName + 'Context';

  const Provider: React.FC<ContextValueType & { children: React.ReactNode }> = (props) => {
    const { children, ...context } = props;
    // Only re-memoize when prop values change
    // eslint-disable-next-line react-hooks/exhaustive-deps
    const value = React.useMemo(() => context, Object.values(context)) as ContextValueType;
    return <Context.Provider value={value}>{children}</Context.Provider>;
  };

  Provider.displayName = rootComponentName + 'Provider';

  function useContext(consumerName: string) {
    const context = React.useContext(Context);
    if (context) return context;
    if (defaultContext !== undefined) return defaultContext;
    // if a defaultContext wasn't specified, it's a required context.
    throw new Error(`\`${consumerName}\` must be used within \`${rootComponentName}\``);
  }

  return [Provider, useContext] as const;
}

/* -------------------------------------------------------------------------------------------------
 * createContextScope
 * -----------------------------------------------------------------------------------------------*/

type Scope<C = any> = { [scopeName: string]: React.Context<C>[] } | undefined;
type ScopeHook = (scope: Scope) => { [__scopeProp: string]: Scope };
interface CreateScope {
  scopeName: string;
  (): ScopeHook;
}

function createContextScope(scopeName: string, createContextScopeDeps: CreateScope[] = []) {
  let defaultContexts: any[] = [];

  /* -----------------------------------------------------------------------------------------------
   * createContext
   * ---------------------------------------------------------------------------------------------*/

  function createContext<ContextValueType extends object | null>(
    rootComponentName: string,
    defaultContext?: ContextValueType,
  ) {
    const BaseContext = React.createContext<ContextValueType | undefined>(defaultContext);
    BaseContext.displayName = rootComponentName + 'Context';
    const index = defaultContexts.length;
    defaultContexts = [...defaultContexts, defaultContext];

    const Provider: React.FC<
      ContextValueType & { scope: Scope<ContextValueType>; children: React.ReactNode }
    > = (props) => {
      const { scope, children, ...context } = props;
      const Context = scope?.[scopeName]?.[index] || BaseContext;
      // Only re-memoize when prop values change
      // eslint-disable-next-line react-hooks/exhaustive-deps
      const value = React.useMemo(() => context, Object.values(context)) as ContextValueType;
      return <Context.Provider value={value}>{children}</Context.Provider>;
    };

    Provider.displayName = rootComponentName + 'Provider';

    function useContext(consumerName: string, scope: Scope<ContextValueType | undefined>) {
      const Context = scope?.[scopeName]?.[index] || BaseContext;
      const context = React.useContext(Context);
      if (context) return context;
      if (defaultContext !== undefined) return defaultContext;
      // if a defaultContext wasn't specified, it's a required context.
      throw new Error(`\`${consumerName}\` must be used within \`${rootComponentName}\``);
    }

    return [Provider, useContext] as const;
  }

  /* -----------------------------------------------------------------------------------------------
   * createScope
   * ---------------------------------------------------------------------------------------------*/

  const createScope: CreateScope = () => {
    const scopeContexts = defaultContexts.map((defaultContext) => {
      return React.createContext(defaultContext);
    });
    return function useScope(scope: Scope) {
      const contexts = scope?.[scopeName] || scopeContexts;
      return React.useMemo(
        () => ({ [`__scope${scopeName}`]: { ...scope, [scopeName]: contexts } }),
        [scope, contexts],
      );
    };
  };

  createScope.scopeName = scopeName;
  return [createContext, composeContextScopes(createScope, ...createContextScopeDeps)] as const;
}

/* -------------------------------------------------------------------------------------------------
 * composeContextScopes
 * -----------------------------------------------------------------------------------------------*/

function composeContextScopes(...scopes: [CreateScope, ...CreateScope[]]): CreateScope {
  const baseScope = scopes[0];
  if (scopes.length === 1) return baseScope;

  const createScope: CreateScope = () => {
    const scopeHooks = scopes.map((createScope) => ({
      useScope: createScope(),
      scopeName: createScope.scopeName,
    }));

    return function useComposedScopes(overrideScopes) {
      const nextScopes = scopeHooks.reduce((nextScopes, { useScope, scopeName }) => {
        // We are calling a hook inside a callback which React warns against to avoid inconsistent
        // renders, however, scoping doesn't have render side effects so we ignore the rule.
        // eslint-disable-next-line react-hooks/rules-of-hooks
        const scopeProps = useScope(overrideScopes);
        const currentScope = scopeProps[`__scope${scopeName}`];
        return { ...nextScopes, ...currentScope };
      }, {});

      return React.useMemo(() => ({ [`__scope${baseScope.scopeName}`]: nextScopes }), [nextScopes]);
    };
  };

  createScope.scopeName = baseScope.scopeName;
  return createScope;
}

/* -----------------------------------------------------------------------------------------------*/

export { createContext, createContextScope };
export type { CreateScope, Scope };



================================================
FILE: packages/react/context/src/index.ts
================================================
export { createContext, createContextScope } from './create-context';
export type { CreateScope, Scope } from './create-context';



================================================
FILE: packages/react/context-menu/README.md
================================================
# `react-context-menu`

View docs [here](https://radix-ui.com/primitives/docs/components/context-menu).



================================================
FILE: packages/react/context-menu/CHANGELOG.md
================================================
# @radix-ui/react-context-menu

## 2.2.16

- Updated dependencies: `@radix-ui/primitive@1.1.3`, `@radix-ui/react-context@1.1.3`, `@radix-ui/react-menu@2.1.16`, `@radix-ui/react-primitive@2.1.4`

## 2.2.15

- Replace deprecated 'ElementRef' with 'ComponentRef' (#3426)
- Updated dependencies: `@radix-ui/react-menu@2.1.15`, `@radix-ui/react-primitive@2.1.3`

## 2.2.14

- Updated dependencies: `@radix-ui/react-menu@2.1.14`, `@radix-ui/react-primitive@2.1.2`

## 2.2.13

- Updated dependencies: `@radix-ui/react-menu@2.1.13`, `@radix-ui/react-primitive@2.1.1`

## 2.2.12

- Updated dependencies: `@radix-ui/react-menu@2.1.12`

## 2.2.11

- Updated dependencies: `@radix-ui/react-menu@2.1.11`

## 2.2.10

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.2`, `@radix-ui/react-menu@2.1.10`

## 2.2.9

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.1`, `@radix-ui/react-menu@2.1.9`

## 2.2.8

- Minor improvements to `useControllableState` to enhance performance, reduce surface area for bugs, and log warnings when misused (#3455)
- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.0`, `@radix-ui/react-primitive@2.1.0`, `@radix-ui/react-menu@2.1.8`



================================================
FILE: packages/react/context-menu/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/context-menu/package.json
================================================
{
  "name": "@radix-ui/react-context-menu",
  "version": "2.2.16",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/primitive": "workspace:*",
    "@radix-ui/react-context": "workspace:*",
    "@radix-ui/react-menu": "workspace:*",
    "@radix-ui/react-primitive": "workspace:*",
    "@radix-ui/react-use-callback-ref": "workspace:*",
    "@radix-ui/react-use-controllable-state": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/test-data": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/context-menu/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/context-menu/src/context-menu.tsx
================================================
import * as React from 'react';
import { composeEventHandlers } from '@radix-ui/primitive';
import { createContextScope } from '@radix-ui/react-context';
import { Primitive } from '@radix-ui/react-primitive';
import * as MenuPrimitive from '@radix-ui/react-menu';
import { createMenuScope } from '@radix-ui/react-menu';
import { useCallbackRef } from '@radix-ui/react-use-callback-ref';
import { useControllableState } from '@radix-ui/react-use-controllable-state';

import type { Scope } from '@radix-ui/react-context';

type Direction = 'ltr' | 'rtl';
type Point = { x: number; y: number };

/* -------------------------------------------------------------------------------------------------
 * ContextMenu
 * -----------------------------------------------------------------------------------------------*/

const CONTEXT_MENU_NAME = 'ContextMenu';

type ScopedProps<P> = P & { __scopeContextMenu?: Scope };
const [createContextMenuContext, createContextMenuScope] = createContextScope(CONTEXT_MENU_NAME, [
  createMenuScope,
]);
const useMenuScope = createMenuScope();

type ContextMenuContextValue = {
  open: boolean;
  onOpenChange(open: boolean): void;
  modal: boolean;
};

const [ContextMenuProvider, useContextMenuContext] =
  createContextMenuContext<ContextMenuContextValue>(CONTEXT_MENU_NAME);

interface ContextMenuProps {
  children?: React.ReactNode;
  onOpenChange?(open: boolean): void;
  dir?: Direction;
  modal?: boolean;
}

const ContextMenu: React.FC<ContextMenuProps> = (props: ScopedProps<ContextMenuProps>) => {
  const { __scopeContextMenu, children, onOpenChange, dir, modal = true } = props;
  const [open, setOpen] = React.useState(false);
  const menuScope = useMenuScope(__scopeContextMenu);
  const handleOpenChangeProp = useCallbackRef(onOpenChange);

  const handleOpenChange = React.useCallback(
    (open: boolean) => {
      setOpen(open);
      handleOpenChangeProp(open);
    },
    [handleOpenChangeProp],
  );

  return (
    <ContextMenuProvider
      scope={__scopeContextMenu}
      open={open}
      onOpenChange={handleOpenChange}
      modal={modal}
    >
      <MenuPrimitive.Root
        {...menuScope}
        dir={dir}
        open={open}
        onOpenChange={handleOpenChange}
        modal={modal}
      >
        {children}
      </MenuPrimitive.Root>
    </ContextMenuProvider>
  );
};

ContextMenu.displayName = CONTEXT_MENU_NAME;

/* -------------------------------------------------------------------------------------------------
 * ContextMenuTrigger
 * -----------------------------------------------------------------------------------------------*/

const TRIGGER_NAME = 'ContextMenuTrigger';

type ContextMenuTriggerElement = React.ComponentRef<typeof Primitive.span>;
type PrimitiveSpanProps = React.ComponentPropsWithoutRef<typeof Primitive.span>;
interface ContextMenuTriggerProps extends PrimitiveSpanProps {
  disabled?: boolean;
}

const ContextMenuTrigger = React.forwardRef<ContextMenuTriggerElement, ContextMenuTriggerProps>(
  (props: ScopedProps<ContextMenuTriggerProps>, forwardedRef) => {
    const { __scopeContextMenu, disabled = false, ...triggerProps } = props;
    const context = useContextMenuContext(TRIGGER_NAME, __scopeContextMenu);
    const menuScope = useMenuScope(__scopeContextMenu);
    const pointRef = React.useRef<Point>({ x: 0, y: 0 });
    const virtualRef = React.useRef({
      getBoundingClientRect: () => DOMRect.fromRect({ width: 0, height: 0, ...pointRef.current }),
    });
    const longPressTimerRef = React.useRef(0);
    const clearLongPress = React.useCallback(
      () => window.clearTimeout(longPressTimerRef.current),
      [],
    );
    const handleOpen = (event: React.MouseEvent | React.PointerEvent) => {
      pointRef.current = { x: event.clientX, y: event.clientY };
      context.onOpenChange(true);
    };

    React.useEffect(() => clearLongPress, [clearLongPress]);
    React.useEffect(() => void (disabled && clearLongPress()), [disabled, clearLongPress]);

    return (
      <>
        <MenuPrimitive.Anchor {...menuScope} virtualRef={virtualRef} />
        <Primitive.span
          data-state={context.open ? 'open' : 'closed'}
          data-disabled={disabled ? '' : undefined}
          {...triggerProps}
          ref={forwardedRef}
          // prevent iOS context menu from appearing
          style={{ WebkitTouchCallout: 'none', ...props.style }}
          // if trigger is disabled, enable the native Context Menu
          onContextMenu={
            disabled
              ? props.onContextMenu
              : composeEventHandlers(props.onContextMenu, (event) => {
                  // clearing the long press here because some platforms already support
                  // long press to trigger a `contextmenu` event
                  clearLongPress();
                  handleOpen(event);
                  event.preventDefault();
                })
          }
          onPointerDown={
            disabled
              ? props.onPointerDown
              : composeEventHandlers(
                  props.onPointerDown,
                  whenTouchOrPen((event) => {
                    // clear the long press here in case there's multiple touch points
                    clearLongPress();
                    longPressTimerRef.current = window.setTimeout(() => handleOpen(event), 700);
                  }),
                )
          }
          onPointerMove={
            disabled
              ? props.onPointerMove
              : composeEventHandlers(props.onPointerMove, whenTouchOrPen(clearLongPress))
          }
          onPointerCancel={
            disabled
              ? props.onPointerCancel
              : composeEventHandlers(props.onPointerCancel, whenTouchOrPen(clearLongPress))
          }
          onPointerUp={
            disabled
              ? props.onPointerUp
              : composeEventHandlers(props.onPointerUp, whenTouchOrPen(clearLongPress))
          }
        />
      </>
    );
  },
);

ContextMenuTrigger.displayName = TRIGGER_NAME;

/* -------------------------------------------------------------------------------------------------
 * ContextMenuPortal
 * -----------------------------------------------------------------------------------------------*/

const PORTAL_NAME = 'ContextMenuPortal';

type MenuPortalProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.Portal>;
interface ContextMenuPortalProps extends MenuPortalProps {}

const ContextMenuPortal: React.FC<ContextMenuPortalProps> = (
  props: ScopedProps<ContextMenuPortalProps>,
) => {
  const { __scopeContextMenu, ...portalProps } = props;
  const menuScope = useMenuScope(__scopeContextMenu);
  return <MenuPrimitive.Portal {...menuScope} {...portalProps} />;
};

ContextMenuPortal.displayName = PORTAL_NAME;

/* -------------------------------------------------------------------------------------------------
 * ContextMenuContent
 * -----------------------------------------------------------------------------------------------*/

const CONTENT_NAME = 'ContextMenuContent';

type ContextMenuContentElement = React.ComponentRef<typeof MenuPrimitive.Content>;
type MenuContentProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.Content>;
interface ContextMenuContentProps
  extends Omit<MenuContentProps, 'onEntryFocus' | 'side' | 'sideOffset' | 'align'> {}

const ContextMenuContent = React.forwardRef<ContextMenuContentElement, ContextMenuContentProps>(
  (props: ScopedProps<ContextMenuContentProps>, forwardedRef) => {
    const { __scopeContextMenu, ...contentProps } = props;
    const context = useContextMenuContext(CONTENT_NAME, __scopeContextMenu);
    const menuScope = useMenuScope(__scopeContextMenu);
    const hasInteractedOutsideRef = React.useRef(false);

    return (
      <MenuPrimitive.Content
        {...menuScope}
        {...contentProps}
        ref={forwardedRef}
        side="right"
        sideOffset={2}
        align="start"
        onCloseAutoFocus={(event) => {
          props.onCloseAutoFocus?.(event);

          if (!event.defaultPrevented && hasInteractedOutsideRef.current) {
            event.preventDefault();
          }

          hasInteractedOutsideRef.current = false;
        }}
        onInteractOutside={(event) => {
          props.onInteractOutside?.(event);

          if (!event.defaultPrevented && !context.modal) hasInteractedOutsideRef.current = true;
        }}
        style={{
          ...props.style,
          // re-namespace exposed content custom properties
          ...{
            '--radix-context-menu-content-transform-origin': 'var(--radix-popper-transform-origin)',
            '--radix-context-menu-content-available-width': 'var(--radix-popper-available-width)',
            '--radix-context-menu-content-available-height': 'var(--radix-popper-available-height)',
            '--radix-context-menu-trigger-width': 'var(--radix-popper-anchor-width)',
            '--radix-context-menu-trigger-height': 'var(--radix-popper-anchor-height)',
          },
        }}
      />
    );
  },
);

ContextMenuContent.displayName = CONTENT_NAME;

/* -------------------------------------------------------------------------------------------------
 * ContextMenuGroup
 * -----------------------------------------------------------------------------------------------*/

const GROUP_NAME = 'ContextMenuGroup';

type ContextMenuGroupElement = React.ComponentRef<typeof MenuPrimitive.Group>;
type MenuGroupProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.Group>;
interface ContextMenuGroupProps extends MenuGroupProps {}

const ContextMenuGroup = React.forwardRef<ContextMenuGroupElement, ContextMenuGroupProps>(
  (props: ScopedProps<ContextMenuGroupProps>, forwardedRef) => {
    const { __scopeContextMenu, ...groupProps } = props;
    const menuScope = useMenuScope(__scopeContextMenu);
    return <MenuPrimitive.Group {...menuScope} {...groupProps} ref={forwardedRef} />;
  },
);

ContextMenuGroup.displayName = GROUP_NAME;

/* -------------------------------------------------------------------------------------------------
 * ContextMenuLabel
 * -----------------------------------------------------------------------------------------------*/

const LABEL_NAME = 'ContextMenuLabel';

type ContextMenuLabelElement = React.ComponentRef<typeof MenuPrimitive.Label>;
type MenuLabelProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.Label>;
interface ContextMenuLabelProps extends MenuLabelProps {}

const ContextMenuLabel = React.forwardRef<ContextMenuLabelElement, ContextMenuLabelProps>(
  (props: ScopedProps<ContextMenuLabelProps>, forwardedRef) => {
    const { __scopeContextMenu, ...labelProps } = props;
    const menuScope = useMenuScope(__scopeContextMenu);
    return <MenuPrimitive.Label {...menuScope} {...labelProps} ref={forwardedRef} />;
  },
);

ContextMenuLabel.displayName = LABEL_NAME;

/* -------------------------------------------------------------------------------------------------
 * ContextMenuItem
 * -----------------------------------------------------------------------------------------------*/

const ITEM_NAME = 'ContextMenuItem';

type ContextMenuItemElement = React.ComponentRef<typeof MenuPrimitive.Item>;
type MenuItemProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.Item>;
interface ContextMenuItemProps extends MenuItemProps {}

const ContextMenuItem = React.forwardRef<ContextMenuItemElement, ContextMenuItemProps>(
  (props: ScopedProps<ContextMenuItemProps>, forwardedRef) => {
    const { __scopeContextMenu, ...itemProps } = props;
    const menuScope = useMenuScope(__scopeContextMenu);
    return <MenuPrimitive.Item {...menuScope} {...itemProps} ref={forwardedRef} />;
  },
);

ContextMenuItem.displayName = ITEM_NAME;

/* -------------------------------------------------------------------------------------------------
 * ContextMenuCheckboxItem
 * -----------------------------------------------------------------------------------------------*/

const CHECKBOX_ITEM_NAME = 'ContextMenuCheckboxItem';

type ContextMenuCheckboxItemElement = React.ComponentRef<typeof MenuPrimitive.CheckboxItem>;
type MenuCheckboxItemProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.CheckboxItem>;
interface ContextMenuCheckboxItemProps extends MenuCheckboxItemProps {}

const ContextMenuCheckboxItem = React.forwardRef<
  ContextMenuCheckboxItemElement,
  ContextMenuCheckboxItemProps
>((props: ScopedProps<ContextMenuCheckboxItemProps>, forwardedRef) => {
  const { __scopeContextMenu, ...checkboxItemProps } = props;
  const menuScope = useMenuScope(__scopeContextMenu);
  return <MenuPrimitive.CheckboxItem {...menuScope} {...checkboxItemProps} ref={forwardedRef} />;
});

ContextMenuCheckboxItem.displayName = CHECKBOX_ITEM_NAME;

/* -------------------------------------------------------------------------------------------------
 * ContextMenuRadioGroup
 * -----------------------------------------------------------------------------------------------*/

const RADIO_GROUP_NAME = 'ContextMenuRadioGroup';

type ContextMenuRadioGroupElement = React.ComponentRef<typeof MenuPrimitive.RadioGroup>;
type MenuRadioGroupProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.RadioGroup>;
interface ContextMenuRadioGroupProps extends MenuRadioGroupProps {}

const ContextMenuRadioGroup = React.forwardRef<
  ContextMenuRadioGroupElement,
  ContextMenuRadioGroupProps
>((props: ScopedProps<ContextMenuRadioGroupProps>, forwardedRef) => {
  const { __scopeContextMenu, ...radioGroupProps } = props;
  const menuScope = useMenuScope(__scopeContextMenu);
  return <MenuPrimitive.RadioGroup {...menuScope} {...radioGroupProps} ref={forwardedRef} />;
});

ContextMenuRadioGroup.displayName = RADIO_GROUP_NAME;

/* -------------------------------------------------------------------------------------------------
 * ContextMenuRadioItem
 * -----------------------------------------------------------------------------------------------*/

const RADIO_ITEM_NAME = 'ContextMenuRadioItem';

type ContextMenuRadioItemElement = React.ComponentRef<typeof MenuPrimitive.RadioItem>;
type MenuRadioItemProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.RadioItem>;
interface ContextMenuRadioItemProps extends MenuRadioItemProps {}

const ContextMenuRadioItem = React.forwardRef<
  ContextMenuRadioItemElement,
  ContextMenuRadioItemProps
>((props: ScopedProps<ContextMenuRadioItemProps>, forwardedRef) => {
  const { __scopeContextMenu, ...radioItemProps } = props;
  const menuScope = useMenuScope(__scopeContextMenu);
  return <MenuPrimitive.RadioItem {...menuScope} {...radioItemProps} ref={forwardedRef} />;
});

ContextMenuRadioItem.displayName = RADIO_ITEM_NAME;

/* -------------------------------------------------------------------------------------------------
 * ContextMenuItemIndicator
 * -----------------------------------------------------------------------------------------------*/

const INDICATOR_NAME = 'ContextMenuItemIndicator';

type ContextMenuItemIndicatorElement = React.ComponentRef<typeof MenuPrimitive.ItemIndicator>;
type MenuItemIndicatorProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.ItemIndicator>;
interface ContextMenuItemIndicatorProps extends MenuItemIndicatorProps {}

const ContextMenuItemIndicator = React.forwardRef<
  ContextMenuItemIndicatorElement,
  ContextMenuItemIndicatorProps
>((props: ScopedProps<ContextMenuItemIndicatorProps>, forwardedRef) => {
  const { __scopeContextMenu, ...itemIndicatorProps } = props;
  const menuScope = useMenuScope(__scopeContextMenu);
  return <MenuPrimitive.ItemIndicator {...menuScope} {...itemIndicatorProps} ref={forwardedRef} />;
});

ContextMenuItemIndicator.displayName = INDICATOR_NAME;

/* -------------------------------------------------------------------------------------------------
 * ContextMenuSeparator
 * -----------------------------------------------------------------------------------------------*/

const SEPARATOR_NAME = 'ContextMenuSeparator';

type ContextMenuSeparatorElement = React.ComponentRef<typeof MenuPrimitive.Separator>;
type MenuSeparatorProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.Separator>;
interface ContextMenuSeparatorProps extends MenuSeparatorProps {}

const ContextMenuSeparator = React.forwardRef<
  ContextMenuSeparatorElement,
  ContextMenuSeparatorProps
>((props: ScopedProps<ContextMenuSeparatorProps>, forwardedRef) => {
  const { __scopeContextMenu, ...separatorProps } = props;
  const menuScope = useMenuScope(__scopeContextMenu);
  return <MenuPrimitive.Separator {...menuScope} {...separatorProps} ref={forwardedRef} />;
});

ContextMenuSeparator.displayName = SEPARATOR_NAME;

/* -------------------------------------------------------------------------------------------------
 * ContextMenuArrow
 * -----------------------------------------------------------------------------------------------*/

const ARROW_NAME = 'ContextMenuArrow';

type ContextMenuArrowElement = React.ComponentRef<typeof MenuPrimitive.Arrow>;
type MenuArrowProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.Arrow>;
interface ContextMenuArrowProps extends MenuArrowProps {}

const ContextMenuArrow = React.forwardRef<ContextMenuArrowElement, ContextMenuArrowProps>(
  (props: ScopedProps<ContextMenuArrowProps>, forwardedRef) => {
    const { __scopeContextMenu, ...arrowProps } = props;
    const menuScope = useMenuScope(__scopeContextMenu);
    return <MenuPrimitive.Arrow {...menuScope} {...arrowProps} ref={forwardedRef} />;
  },
);

ContextMenuArrow.displayName = ARROW_NAME;

/* -------------------------------------------------------------------------------------------------
 * ContextMenuSub
 * -----------------------------------------------------------------------------------------------*/

const SUB_NAME = 'ContextMenuSub';

interface ContextMenuSubProps {
  children?: React.ReactNode;
  open?: boolean;
  defaultOpen?: boolean;
  onOpenChange?(open: boolean): void;
}

const ContextMenuSub: React.FC<ContextMenuSubProps> = (props: ScopedProps<ContextMenuSubProps>) => {
  const { __scopeContextMenu, children, onOpenChange, open: openProp, defaultOpen } = props;
  const menuScope = useMenuScope(__scopeContextMenu);
  const [open, setOpen] = useControllableState({
    prop: openProp,
    defaultProp: defaultOpen ?? false,
    onChange: onOpenChange,
    caller: SUB_NAME,
  });

  return (
    <MenuPrimitive.Sub {...menuScope} open={open} onOpenChange={setOpen}>
      {children}
    </MenuPrimitive.Sub>
  );
};

ContextMenuSub.displayName = SUB_NAME;

/* -------------------------------------------------------------------------------------------------
 * ContextMenuSubTrigger
 * -----------------------------------------------------------------------------------------------*/

const SUB_TRIGGER_NAME = 'ContextMenuSubTrigger';

type ContextMenuSubTriggerElement = React.ComponentRef<typeof MenuPrimitive.SubTrigger>;
type MenuSubTriggerProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.SubTrigger>;
interface ContextMenuSubTriggerProps extends MenuSubTriggerProps {}

const ContextMenuSubTrigger = React.forwardRef<
  ContextMenuSubTriggerElement,
  ContextMenuSubTriggerProps
>((props: ScopedProps<ContextMenuSubTriggerProps>, forwardedRef) => {
  const { __scopeContextMenu, ...triggerItemProps } = props;
  const menuScope = useMenuScope(__scopeContextMenu);
  return <MenuPrimitive.SubTrigger {...menuScope} {...triggerItemProps} ref={forwardedRef} />;
});

ContextMenuSubTrigger.displayName = SUB_TRIGGER_NAME;

/* -------------------------------------------------------------------------------------------------
 * ContextMenuSubContent
 * -----------------------------------------------------------------------------------------------*/

const SUB_CONTENT_NAME = 'ContextMenuSubContent';

type ContextMenuSubContentElement = React.ComponentRef<typeof MenuPrimitive.Content>;
type MenuSubContentProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.SubContent>;
interface ContextMenuSubContentProps extends MenuSubContentProps {}

const ContextMenuSubContent = React.forwardRef<
  ContextMenuSubContentElement,
  ContextMenuSubContentProps
>((props: ScopedProps<ContextMenuSubContentProps>, forwardedRef) => {
  const { __scopeContextMenu, ...subContentProps } = props;
  const menuScope = useMenuScope(__scopeContextMenu);

  return (
    <MenuPrimitive.SubContent
      {...menuScope}
      {...subContentProps}
      ref={forwardedRef}
      style={{
        ...props.style,
        // re-namespace exposed content custom properties
        ...{
          '--radix-context-menu-content-transform-origin': 'var(--radix-popper-transform-origin)',
          '--radix-context-menu-content-available-width': 'var(--radix-popper-available-width)',
          '--radix-context-menu-content-available-height': 'var(--radix-popper-available-height)',
          '--radix-context-menu-trigger-width': 'var(--radix-popper-anchor-width)',
          '--radix-context-menu-trigger-height': 'var(--radix-popper-anchor-height)',
        },
      }}
    />
  );
});

ContextMenuSubContent.displayName = SUB_CONTENT_NAME;

/* -----------------------------------------------------------------------------------------------*/

function whenTouchOrPen<E>(handler: React.PointerEventHandler<E>): React.PointerEventHandler<E> {
  return (event) => (event.pointerType !== 'mouse' ? handler(event) : undefined);
}

const Root = ContextMenu;
const Trigger = ContextMenuTrigger;
const Portal = ContextMenuPortal;
const Content = ContextMenuContent;
const Group = ContextMenuGroup;
const Label = ContextMenuLabel;
const Item = ContextMenuItem;
const CheckboxItem = ContextMenuCheckboxItem;
const RadioGroup = ContextMenuRadioGroup;
const RadioItem = ContextMenuRadioItem;
const ItemIndicator = ContextMenuItemIndicator;
const Separator = ContextMenuSeparator;
const Arrow = ContextMenuArrow;
const Sub = ContextMenuSub;
const SubTrigger = ContextMenuSubTrigger;
const SubContent = ContextMenuSubContent;

export {
  createContextMenuScope,
  //
  ContextMenu,
  ContextMenuTrigger,
  ContextMenuPortal,
  ContextMenuContent,
  ContextMenuGroup,
  ContextMenuLabel,
  ContextMenuItem,
  ContextMenuCheckboxItem,
  ContextMenuRadioGroup,
  ContextMenuRadioItem,
  ContextMenuItemIndicator,
  ContextMenuSeparator,
  ContextMenuArrow,
  ContextMenuSub,
  ContextMenuSubTrigger,
  ContextMenuSubContent,
  //
  Root,
  Trigger,
  Portal,
  Content,
  Group,
  Label,
  Item,
  CheckboxItem,
  RadioGroup,
  RadioItem,
  ItemIndicator,
  Separator,
  Arrow,
  Sub,
  SubTrigger,
  SubContent,
};
export type {
  ContextMenuProps,
  ContextMenuTriggerProps,
  ContextMenuPortalProps,
  ContextMenuContentProps,
  ContextMenuGroupProps,
  ContextMenuLabelProps,
  ContextMenuItemProps,
  ContextMenuCheckboxItemProps,
  ContextMenuRadioGroupProps,
  ContextMenuRadioItemProps,
  ContextMenuItemIndicatorProps,
  ContextMenuSeparatorProps,
  ContextMenuArrowProps,
  ContextMenuSubProps,
  ContextMenuSubTriggerProps,
  ContextMenuSubContentProps,
};



================================================
FILE: packages/react/context-menu/src/index.ts
================================================
'use client';
export {
  createContextMenuScope,
  //
  ContextMenu,
  ContextMenuTrigger,
  ContextMenuPortal,
  ContextMenuContent,
  ContextMenuGroup,
  ContextMenuLabel,
  ContextMenuItem,
  ContextMenuCheckboxItem,
  ContextMenuRadioGroup,
  ContextMenuRadioItem,
  ContextMenuItemIndicator,
  ContextMenuSeparator,
  ContextMenuArrow,
  ContextMenuSub,
  ContextMenuSubTrigger,
  ContextMenuSubContent,
  //
  Root,
  Trigger,
  Portal,
  Content,
  Group,
  Label,
  Item,
  CheckboxItem,
  RadioGroup,
  RadioItem,
  ItemIndicator,
  Separator,
  Arrow,
  Sub,
  SubTrigger,
  SubContent,
} from './context-menu';
export type {
  ContextMenuProps,
  ContextMenuTriggerProps,
  ContextMenuPortalProps,
  ContextMenuContentProps,
  ContextMenuGroupProps,
  ContextMenuLabelProps,
  ContextMenuItemProps,
  ContextMenuCheckboxItemProps,
  ContextMenuRadioGroupProps,
  ContextMenuRadioItemProps,
  ContextMenuItemIndicatorProps,
  ContextMenuSeparatorProps,
  ContextMenuArrowProps,
  ContextMenuSubProps,
  ContextMenuSubTriggerProps,
  ContextMenuSubContentProps,
} from './context-menu';



================================================
FILE: packages/react/dialog/README.md
================================================
# `react-dialog`

View docs [here](https://radix-ui.com/primitives/docs/components/dialog).



================================================
FILE: packages/react/dialog/CHANGELOG.md
================================================
# @radix-ui/react-dialog

## 1.1.15

- Updated dependencies: `@radix-ui/react-presence@1.1.5`, `@radix-ui/react-slot@1.2.4`, `@radix-ui/react-focus-guards@1.1.3`, `@radix-ui/primitive@1.1.3`, `@radix-ui/react-context@1.1.3`, `@radix-ui/react-primitive@2.1.4`, `@radix-ui/react-dismissable-layer@1.1.11`, `@radix-ui/react-focus-scope@1.1.8`, `@radix-ui/react-portal@1.1.10`

## 1.1.14

- Replace deprecated 'ElementRef' with 'ComponentRef' (#3426)
- Updated dependencies: `@radix-ui/react-dismissable-layer@1.1.10`, `@radix-ui/react-focus-scope@1.1.7`, `@radix-ui/react-portal@1.1.9`, `@radix-ui/react-slot@1.2.3`, `@radix-ui/react-primitive@2.1.3`

## 1.1.13

- Updated dependencies: `@radix-ui/react-slot@1.2.2`, `@radix-ui/react-primitive@2.1.2`, `@radix-ui/react-dismissable-layer@1.1.9`, `@radix-ui/react-focus-scope@1.1.6`, `@radix-ui/react-portal@1.1.8`

## 1.1.12

- Updated dependencies: `@radix-ui/react-slot@1.2.1`, `@radix-ui/react-primitive@2.1.1`, `@radix-ui/react-dismissable-layer@1.1.8`, `@radix-ui/react-focus-scope@1.1.5`, `@radix-ui/react-portal@1.1.7`

## 1.1.11

- Updated dependencies: `@radix-ui/react-presence@1.1.4`

## 1.1.10

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.2`

## 1.1.9

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.1`

## 1.1.8

- Minor improvements to `useControllableState` to enhance performance, reduce surface area for bugs, and log warnings when misused (#3455)
- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.0`, `@radix-ui/react-primitive@2.1.0`, `@radix-ui/react-dismissable-layer@1.1.7`, `@radix-ui/react-focus-scope@1.1.4`, `@radix-ui/react-portal@1.1.6`



================================================
FILE: packages/react/dialog/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/dialog/package.json
================================================
{
  "name": "@radix-ui/react-dialog",
  "version": "1.1.15",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/primitive": "workspace:*",
    "@radix-ui/react-compose-refs": "workspace:*",
    "@radix-ui/react-context": "workspace:*",
    "@radix-ui/react-dismissable-layer": "workspace:*",
    "@radix-ui/react-focus-guards": "workspace:*",
    "@radix-ui/react-focus-scope": "workspace:*",
    "@radix-ui/react-id": "workspace:*",
    "@radix-ui/react-portal": "workspace:*",
    "@radix-ui/react-presence": "workspace:*",
    "@radix-ui/react-primitive": "workspace:*",
    "@radix-ui/react-slot": "workspace:*",
    "@radix-ui/react-use-controllable-state": "workspace:*",
    "aria-hidden": "^1.2.4",
    "react-remove-scroll": "^2.6.3"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/dialog/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/dialog/src/dialog.test.tsx
================================================
import React from 'react';
import { axe } from 'vitest-axe';
import type { RenderResult } from '@testing-library/react';
import { render, fireEvent, cleanup } from '@testing-library/react';
import * as Dialog from './dialog';
import type { Mock, MockInstance } from 'vitest';
import { describe, it, afterEach, beforeEach, vi, expect } from 'vitest';

const OPEN_TEXT = 'Open';
const CLOSE_TEXT = 'Close';
const TITLE_TEXT = 'Title';

const NoLabelDialogTest = (props: React.ComponentProps<typeof Dialog.Root>) => (
  <Dialog.Root {...props}>
    <Dialog.Trigger>{OPEN_TEXT}</Dialog.Trigger>
    <Dialog.Overlay />
    <Dialog.Content>
      <Dialog.Close>{CLOSE_TEXT}</Dialog.Close>
    </Dialog.Content>
  </Dialog.Root>
);

const UndefinedDescribedByDialog = (props: React.ComponentProps<typeof Dialog.Root>) => (
  <Dialog.Root {...props}>
    <Dialog.Trigger>{OPEN_TEXT}</Dialog.Trigger>
    <Dialog.Overlay />
    <Dialog.Content aria-describedby={undefined}>
      <Dialog.Title>{TITLE_TEXT}</Dialog.Title>
      <Dialog.Close>{CLOSE_TEXT}</Dialog.Close>
    </Dialog.Content>
  </Dialog.Root>
);

const DialogTest = (props: React.ComponentProps<typeof Dialog.Root>) => (
  <Dialog.Root {...props}>
    <Dialog.Trigger>{OPEN_TEXT}</Dialog.Trigger>
    <Dialog.Overlay />
    <Dialog.Content>
      <Dialog.Title>{TITLE_TEXT}</Dialog.Title>
      <Dialog.Close>{CLOSE_TEXT}</Dialog.Close>
    </Dialog.Content>
  </Dialog.Root>
);

function renderAndClickDialogTrigger(Dialog: any) {
  fireEvent.click(render(Dialog).getByText(OPEN_TEXT));
}

describe('given a default Dialog', () => {
  let rendered: RenderResult;
  let trigger: HTMLElement;
  let closeButton: HTMLElement;
  let consoleWarnMock: MockInstance;
  let consoleWarnMockFunction: Mock;
  let consoleErrorMock: MockInstance;
  let consoleErrorMockFunction: Mock;

  beforeEach(() => {
    // This surpresses React error boundary logs for testing intentionally
    // thrown errors, like in some test cases in this suite. See discussion of
    // this here: https://github.com/facebook/react/issues/11098
    consoleWarnMockFunction = vi.fn();
    consoleWarnMock = vi.spyOn(console, 'warn').mockImplementation(consoleWarnMockFunction);
    consoleErrorMockFunction = vi.fn();
    consoleErrorMock = vi.spyOn(console, 'error').mockImplementation(consoleErrorMockFunction);

    rendered = render(<DialogTest />);
    trigger = rendered.getByText(OPEN_TEXT);
  });

  afterEach(() => {
    cleanup();
    consoleWarnMock.mockRestore();
    consoleWarnMockFunction.mockClear();
    consoleErrorMock.mockRestore();
    consoleErrorMockFunction.mockClear();
  });

  it('should have no accessibility violations in default state', async () => {
    expect(await axe(rendered.container)).toHaveNoViolations();
  });

  describe('after clicking the trigger', () => {
    beforeEach(() => {
      fireEvent.click(trigger);
      closeButton = rendered.getByText(CLOSE_TEXT);
    });

    describe('when no description has been provided', () => {
      it('should warn to the console', () => {
        expect(consoleWarnMockFunction).toHaveBeenCalledTimes(1);
      });
    });

    describe('when no title has been provided', () => {
      beforeEach(() => {
        cleanup();
      });
      it('should display an error in the console', () => {
        consoleErrorMockFunction.mockClear();

        renderAndClickDialogTrigger(<NoLabelDialogTest />);
        expect(consoleErrorMockFunction).toHaveBeenCalled();
      });
    });

    describe('when aria-describedby is set to undefined', () => {
      beforeEach(() => {
        cleanup();
      });
      it('should not warn to the console', () => {
        consoleWarnMockFunction.mockClear();

        renderAndClickDialogTrigger(<UndefinedDescribedByDialog />);
        expect(consoleWarnMockFunction).not.toHaveBeenCalled();
      });
    });

    it('should open the content', () => {
      expect(closeButton).toBeVisible();
    });

    it('should have no accessibility violations', async () => {
      expect(await axe(rendered.container)).toHaveNoViolations();
    });

    it('should focus the close button', () => {
      expect(closeButton).toHaveFocus();
    });

    describe('when pressing escape', () => {
      beforeEach(() => {
        fireEvent.keyDown(document.activeElement!, { key: 'Escape' });
      });

      it('should close the content', () => {
        expect(closeButton).not.toBeInTheDocument();
      });
    });
  });
});



================================================
FILE: packages/react/dialog/src/dialog.tsx
================================================
import * as React from 'react';
import { composeEventHandlers } from '@radix-ui/primitive';
import { useComposedRefs } from '@radix-ui/react-compose-refs';
import { createContext, createContextScope } from '@radix-ui/react-context';
import { useId } from '@radix-ui/react-id';
import { useControllableState } from '@radix-ui/react-use-controllable-state';
import { DismissableLayer } from '@radix-ui/react-dismissable-layer';
import { FocusScope } from '@radix-ui/react-focus-scope';
import { Portal as PortalPrimitive } from '@radix-ui/react-portal';
import { Presence } from '@radix-ui/react-presence';
import { Primitive } from '@radix-ui/react-primitive';
import { useFocusGuards } from '@radix-ui/react-focus-guards';
import { RemoveScroll } from 'react-remove-scroll';
import { hideOthers } from 'aria-hidden';
import { createSlot } from '@radix-ui/react-slot';

import type { Scope } from '@radix-ui/react-context';

/* -------------------------------------------------------------------------------------------------
 * Dialog
 * -----------------------------------------------------------------------------------------------*/

const DIALOG_NAME = 'Dialog';

type ScopedProps<P> = P & { __scopeDialog?: Scope };
const [createDialogContext, createDialogScope] = createContextScope(DIALOG_NAME);

type DialogContextValue = {
  triggerRef: React.RefObject<HTMLButtonElement | null>;
  contentRef: React.RefObject<DialogContentElement | null>;
  contentId: string;
  titleId: string;
  descriptionId: string;
  open: boolean;
  onOpenChange(open: boolean): void;
  onOpenToggle(): void;
  modal: boolean;
};

const [DialogProvider, useDialogContext] = createDialogContext<DialogContextValue>(DIALOG_NAME);

interface DialogProps {
  children?: React.ReactNode;
  open?: boolean;
  defaultOpen?: boolean;
  onOpenChange?(open: boolean): void;
  modal?: boolean;
}

const Dialog: React.FC<DialogProps> = (props: ScopedProps<DialogProps>) => {
  const {
    __scopeDialog,
    children,
    open: openProp,
    defaultOpen,
    onOpenChange,
    modal = true,
  } = props;
  const triggerRef = React.useRef<HTMLButtonElement>(null);
  const contentRef = React.useRef<DialogContentElement>(null);
  const [open, setOpen] = useControllableState({
    prop: openProp,
    defaultProp: defaultOpen ?? false,
    onChange: onOpenChange,
    caller: DIALOG_NAME,
  });

  return (
    <DialogProvider
      scope={__scopeDialog}
      triggerRef={triggerRef}
      contentRef={contentRef}
      contentId={useId()}
      titleId={useId()}
      descriptionId={useId()}
      open={open}
      onOpenChange={setOpen}
      onOpenToggle={React.useCallback(() => setOpen((prevOpen) => !prevOpen), [setOpen])}
      modal={modal}
    >
      {children}
    </DialogProvider>
  );
};

Dialog.displayName = DIALOG_NAME;

/* -------------------------------------------------------------------------------------------------
 * DialogTrigger
 * -----------------------------------------------------------------------------------------------*/

const TRIGGER_NAME = 'DialogTrigger';

type DialogTriggerElement = React.ComponentRef<typeof Primitive.button>;
type PrimitiveButtonProps = React.ComponentPropsWithoutRef<typeof Primitive.button>;
interface DialogTriggerProps extends PrimitiveButtonProps {}

const DialogTrigger = React.forwardRef<DialogTriggerElement, DialogTriggerProps>(
  (props: ScopedProps<DialogTriggerProps>, forwardedRef) => {
    const { __scopeDialog, ...triggerProps } = props;
    const context = useDialogContext(TRIGGER_NAME, __scopeDialog);
    const composedTriggerRef = useComposedRefs(forwardedRef, context.triggerRef);
    return (
      <Primitive.button
        type="button"
        aria-haspopup="dialog"
        aria-expanded={context.open}
        aria-controls={context.contentId}
        data-state={getState(context.open)}
        {...triggerProps}
        ref={composedTriggerRef}
        onClick={composeEventHandlers(props.onClick, context.onOpenToggle)}
      />
    );
  },
);

DialogTrigger.displayName = TRIGGER_NAME;

/* -------------------------------------------------------------------------------------------------
 * DialogPortal
 * -----------------------------------------------------------------------------------------------*/

const PORTAL_NAME = 'DialogPortal';

type PortalContextValue = { forceMount?: true };
const [PortalProvider, usePortalContext] = createDialogContext<PortalContextValue>(PORTAL_NAME, {
  forceMount: undefined,
});

type PortalProps = React.ComponentPropsWithoutRef<typeof PortalPrimitive>;
interface DialogPortalProps {
  children?: React.ReactNode;
  /**
   * Specify a container element to portal the content into.
   */
  container?: PortalProps['container'];
  /**
   * Used to force mounting when more control is needed. Useful when
   * controlling animation with React animation libraries.
   */
  forceMount?: true;
}

const DialogPortal: React.FC<DialogPortalProps> = (props: ScopedProps<DialogPortalProps>) => {
  const { __scopeDialog, forceMount, children, container } = props;
  const context = useDialogContext(PORTAL_NAME, __scopeDialog);
  return (
    <PortalProvider scope={__scopeDialog} forceMount={forceMount}>
      {React.Children.map(children, (child) => (
        <Presence present={forceMount || context.open}>
          <PortalPrimitive asChild container={container}>
            {child}
          </PortalPrimitive>
        </Presence>
      ))}
    </PortalProvider>
  );
};

DialogPortal.displayName = PORTAL_NAME;

/* -------------------------------------------------------------------------------------------------
 * DialogOverlay
 * -----------------------------------------------------------------------------------------------*/

const OVERLAY_NAME = 'DialogOverlay';

type DialogOverlayElement = DialogOverlayImplElement;
interface DialogOverlayProps extends DialogOverlayImplProps {
  /**
   * Used to force mounting when more control is needed. Useful when
   * controlling animation with React animation libraries.
   */
  forceMount?: true;
}

const DialogOverlay = React.forwardRef<DialogOverlayElement, DialogOverlayProps>(
  (props: ScopedProps<DialogOverlayProps>, forwardedRef) => {
    const portalContext = usePortalContext(OVERLAY_NAME, props.__scopeDialog);
    const { forceMount = portalContext.forceMount, ...overlayProps } = props;
    const context = useDialogContext(OVERLAY_NAME, props.__scopeDialog);
    return context.modal ? (
      <Presence present={forceMount || context.open}>
        <DialogOverlayImpl {...overlayProps} ref={forwardedRef} />
      </Presence>
    ) : null;
  },
);

DialogOverlay.displayName = OVERLAY_NAME;

type DialogOverlayImplElement = React.ComponentRef<typeof Primitive.div>;
type PrimitiveDivProps = React.ComponentPropsWithoutRef<typeof Primitive.div>;
interface DialogOverlayImplProps extends PrimitiveDivProps {}

const Slot = createSlot('DialogOverlay.RemoveScroll');

const DialogOverlayImpl = React.forwardRef<DialogOverlayImplElement, DialogOverlayImplProps>(
  (props: ScopedProps<DialogOverlayImplProps>, forwardedRef) => {
    const { __scopeDialog, ...overlayProps } = props;
    const context = useDialogContext(OVERLAY_NAME, __scopeDialog);
    return (
      // Make sure `Content` is scrollable even when it doesn't live inside `RemoveScroll`
      // ie. when `Overlay` and `Content` are siblings
      <RemoveScroll as={Slot} allowPinchZoom shards={[context.contentRef]}>
        <Primitive.div
          data-state={getState(context.open)}
          {...overlayProps}
          ref={forwardedRef}
          // We re-enable pointer-events prevented by `Dialog.Content` to allow scrolling the overlay.
          style={{ pointerEvents: 'auto', ...overlayProps.style }}
        />
      </RemoveScroll>
    );
  },
);

/* -------------------------------------------------------------------------------------------------
 * DialogContent
 * -----------------------------------------------------------------------------------------------*/

const CONTENT_NAME = 'DialogContent';

type DialogContentElement = DialogContentTypeElement;
interface DialogContentProps extends DialogContentTypeProps {
  /**
   * Used to force mounting when more control is needed. Useful when
   * controlling animation with React animation libraries.
   */
  forceMount?: true;
}

const DialogContent = React.forwardRef<DialogContentElement, DialogContentProps>(
  (props: ScopedProps<DialogContentProps>, forwardedRef) => {
    const portalContext = usePortalContext(CONTENT_NAME, props.__scopeDialog);
    const { forceMount = portalContext.forceMount, ...contentProps } = props;
    const context = useDialogContext(CONTENT_NAME, props.__scopeDialog);
    return (
      <Presence present={forceMount || context.open}>
        {context.modal ? (
          <DialogContentModal {...contentProps} ref={forwardedRef} />
        ) : (
          <DialogContentNonModal {...contentProps} ref={forwardedRef} />
        )}
      </Presence>
    );
  },
);

DialogContent.displayName = CONTENT_NAME;

/* -----------------------------------------------------------------------------------------------*/

type DialogContentTypeElement = DialogContentImplElement;
interface DialogContentTypeProps
  extends Omit<DialogContentImplProps, 'trapFocus' | 'disableOutsidePointerEvents'> {}

const DialogContentModal = React.forwardRef<DialogContentTypeElement, DialogContentTypeProps>(
  (props: ScopedProps<DialogContentTypeProps>, forwardedRef) => {
    const context = useDialogContext(CONTENT_NAME, props.__scopeDialog);
    const contentRef = React.useRef<HTMLDivElement>(null);
    const composedRefs = useComposedRefs(forwardedRef, context.contentRef, contentRef);

    // aria-hide everything except the content (better supported equivalent to setting aria-modal)
    React.useEffect(() => {
      const content = contentRef.current;
      if (content) return hideOthers(content);
    }, []);

    return (
      <DialogContentImpl
        {...props}
        ref={composedRefs}
        // we make sure focus isn't trapped once `DialogContent` has been closed
        // (closed !== unmounted when animating out)
        trapFocus={context.open}
        disableOutsidePointerEvents
        onCloseAutoFocus={composeEventHandlers(props.onCloseAutoFocus, (event) => {
          event.preventDefault();
          context.triggerRef.current?.focus();
        })}
        onPointerDownOutside={composeEventHandlers(props.onPointerDownOutside, (event) => {
          const originalEvent = event.detail.originalEvent;
          const ctrlLeftClick = originalEvent.button === 0 && originalEvent.ctrlKey === true;
          const isRightClick = originalEvent.button === 2 || ctrlLeftClick;

          // If the event is a right-click, we shouldn't close because
          // it is effectively as if we right-clicked the `Overlay`.
          if (isRightClick) event.preventDefault();
        })}
        // When focus is trapped, a `focusout` event may still happen.
        // We make sure we don't trigger our `onDismiss` in such case.
        onFocusOutside={composeEventHandlers(props.onFocusOutside, (event) =>
          event.preventDefault(),
        )}
      />
    );
  },
);

/* -----------------------------------------------------------------------------------------------*/

const DialogContentNonModal = React.forwardRef<DialogContentTypeElement, DialogContentTypeProps>(
  (props: ScopedProps<DialogContentTypeProps>, forwardedRef) => {
    const context = useDialogContext(CONTENT_NAME, props.__scopeDialog);
    const hasInteractedOutsideRef = React.useRef(false);
    const hasPointerDownOutsideRef = React.useRef(false);

    return (
      <DialogContentImpl
        {...props}
        ref={forwardedRef}
        trapFocus={false}
        disableOutsidePointerEvents={false}
        onCloseAutoFocus={(event) => {
          props.onCloseAutoFocus?.(event);

          if (!event.defaultPrevented) {
            if (!hasInteractedOutsideRef.current) context.triggerRef.current?.focus();
            // Always prevent auto focus because we either focus manually or want user agent focus
            event.preventDefault();
          }

          hasInteractedOutsideRef.current = false;
          hasPointerDownOutsideRef.current = false;
        }}
        onInteractOutside={(event) => {
          props.onInteractOutside?.(event);

          if (!event.defaultPrevented) {
            hasInteractedOutsideRef.current = true;
            if (event.detail.originalEvent.type === 'pointerdown') {
              hasPointerDownOutsideRef.current = true;
            }
          }

          // Prevent dismissing when clicking the trigger.
          // As the trigger is already setup to close, without doing so would
          // cause it to close and immediately open.
          const target = event.target as HTMLElement;
          const targetIsTrigger = context.triggerRef.current?.contains(target);
          if (targetIsTrigger) event.preventDefault();

          // On Safari if the trigger is inside a container with tabIndex={0}, when clicked
          // we will get the pointer down outside event on the trigger, but then a subsequent
          // focus outside event on the container, we ignore any focus outside event when we've
          // already had a pointer down outside event.
          if (event.detail.originalEvent.type === 'focusin' && hasPointerDownOutsideRef.current) {
            event.preventDefault();
          }
        }}
      />
    );
  },
);

/* -----------------------------------------------------------------------------------------------*/

type DialogContentImplElement = React.ComponentRef<typeof DismissableLayer>;
type DismissableLayerProps = React.ComponentPropsWithoutRef<typeof DismissableLayer>;
type FocusScopeProps = React.ComponentPropsWithoutRef<typeof FocusScope>;
interface DialogContentImplProps extends Omit<DismissableLayerProps, 'onDismiss'> {
  /**
   * When `true`, focus cannot escape the `Content` via keyboard,
   * pointer, or a programmatic focus.
   * @defaultValue false
   */
  trapFocus?: FocusScopeProps['trapped'];

  /**
   * Event handler called when auto-focusing on open.
   * Can be prevented.
   */
  onOpenAutoFocus?: FocusScopeProps['onMountAutoFocus'];

  /**
   * Event handler called when auto-focusing on close.
   * Can be prevented.
   */
  onCloseAutoFocus?: FocusScopeProps['onUnmountAutoFocus'];
}

const DialogContentImpl = React.forwardRef<DialogContentImplElement, DialogContentImplProps>(
  (props: ScopedProps<DialogContentImplProps>, forwardedRef) => {
    const { __scopeDialog, trapFocus, onOpenAutoFocus, onCloseAutoFocus, ...contentProps } = props;
    const context = useDialogContext(CONTENT_NAME, __scopeDialog);
    const contentRef = React.useRef<HTMLDivElement>(null);
    const composedRefs = useComposedRefs(forwardedRef, contentRef);

    // Make sure the whole tree has focus guards as our `Dialog` will be
    // the last element in the DOM (because of the `Portal`)
    useFocusGuards();

    return (
      <>
        <FocusScope
          asChild
          loop
          trapped={trapFocus}
          onMountAutoFocus={onOpenAutoFocus}
          onUnmountAutoFocus={onCloseAutoFocus}
        >
          <DismissableLayer
            role="dialog"
            id={context.contentId}
            aria-describedby={context.descriptionId}
            aria-labelledby={context.titleId}
            data-state={getState(context.open)}
            {...contentProps}
            ref={composedRefs}
            onDismiss={() => context.onOpenChange(false)}
          />
        </FocusScope>
        {process.env.NODE_ENV !== 'production' && (
          <>
            <TitleWarning titleId={context.titleId} />
            <DescriptionWarning contentRef={contentRef} descriptionId={context.descriptionId} />
          </>
        )}
      </>
    );
  },
);

/* -------------------------------------------------------------------------------------------------
 * DialogTitle
 * -----------------------------------------------------------------------------------------------*/

const TITLE_NAME = 'DialogTitle';

type DialogTitleElement = React.ComponentRef<typeof Primitive.h2>;
type PrimitiveHeading2Props = React.ComponentPropsWithoutRef<typeof Primitive.h2>;
interface DialogTitleProps extends PrimitiveHeading2Props {}

const DialogTitle = React.forwardRef<DialogTitleElement, DialogTitleProps>(
  (props: ScopedProps<DialogTitleProps>, forwardedRef) => {
    const { __scopeDialog, ...titleProps } = props;
    const context = useDialogContext(TITLE_NAME, __scopeDialog);
    return <Primitive.h2 id={context.titleId} {...titleProps} ref={forwardedRef} />;
  },
);

DialogTitle.displayName = TITLE_NAME;

/* -------------------------------------------------------------------------------------------------
 * DialogDescription
 * -----------------------------------------------------------------------------------------------*/

const DESCRIPTION_NAME = 'DialogDescription';

type DialogDescriptionElement = React.ComponentRef<typeof Primitive.p>;
type PrimitiveParagraphProps = React.ComponentPropsWithoutRef<typeof Primitive.p>;
interface DialogDescriptionProps extends PrimitiveParagraphProps {}

const DialogDescription = React.forwardRef<DialogDescriptionElement, DialogDescriptionProps>(
  (props: ScopedProps<DialogDescriptionProps>, forwardedRef) => {
    const { __scopeDialog, ...descriptionProps } = props;
    const context = useDialogContext(DESCRIPTION_NAME, __scopeDialog);
    return <Primitive.p id={context.descriptionId} {...descriptionProps} ref={forwardedRef} />;
  },
);

DialogDescription.displayName = DESCRIPTION_NAME;

/* -------------------------------------------------------------------------------------------------
 * DialogClose
 * -----------------------------------------------------------------------------------------------*/

const CLOSE_NAME = 'DialogClose';

type DialogCloseElement = React.ComponentRef<typeof Primitive.button>;
interface DialogCloseProps extends PrimitiveButtonProps {}

const DialogClose = React.forwardRef<DialogCloseElement, DialogCloseProps>(
  (props: ScopedProps<DialogCloseProps>, forwardedRef) => {
    const { __scopeDialog, ...closeProps } = props;
    const context = useDialogContext(CLOSE_NAME, __scopeDialog);
    return (
      <Primitive.button
        type="button"
        {...closeProps}
        ref={forwardedRef}
        onClick={composeEventHandlers(props.onClick, () => context.onOpenChange(false))}
      />
    );
  },
);

DialogClose.displayName = CLOSE_NAME;

/* -----------------------------------------------------------------------------------------------*/

function getState(open: boolean) {
  return open ? 'open' : 'closed';
}

const TITLE_WARNING_NAME = 'DialogTitleWarning';

const [WarningProvider, useWarningContext] = createContext(TITLE_WARNING_NAME, {
  contentName: CONTENT_NAME,
  titleName: TITLE_NAME,
  docsSlug: 'dialog',
});

type TitleWarningProps = { titleId?: string };

const TitleWarning: React.FC<TitleWarningProps> = ({ titleId }) => {
  const titleWarningContext = useWarningContext(TITLE_WARNING_NAME);

  const MESSAGE = `\`${titleWarningContext.contentName}\` requires a \`${titleWarningContext.titleName}\` for the component to be accessible for screen reader users.

If you want to hide the \`${titleWarningContext.titleName}\`, you can wrap it with our VisuallyHidden component.

For more information, see https://radix-ui.com/primitives/docs/components/${titleWarningContext.docsSlug}`;

  React.useEffect(() => {
    if (titleId) {
      const hasTitle = document.getElementById(titleId);
      if (!hasTitle) console.error(MESSAGE);
    }
  }, [MESSAGE, titleId]);

  return null;
};

const DESCRIPTION_WARNING_NAME = 'DialogDescriptionWarning';

type DescriptionWarningProps = {
  contentRef: React.RefObject<DialogContentElement | null>;
  descriptionId?: string;
};

const DescriptionWarning: React.FC<DescriptionWarningProps> = ({ contentRef, descriptionId }) => {
  const descriptionWarningContext = useWarningContext(DESCRIPTION_WARNING_NAME);
  const MESSAGE = `Warning: Missing \`Description\` or \`aria-describedby={undefined}\` for {${descriptionWarningContext.contentName}}.`;

  React.useEffect(() => {
    const describedById = contentRef.current?.getAttribute('aria-describedby');
    // if we have an id and the user hasn't set aria-describedby={undefined}
    if (descriptionId && describedById) {
      const hasDescription = document.getElementById(descriptionId);
      if (!hasDescription) console.warn(MESSAGE);
    }
  }, [MESSAGE, contentRef, descriptionId]);

  return null;
};

const Root = Dialog;
const Trigger = DialogTrigger;
const Portal = DialogPortal;
const Overlay = DialogOverlay;
const Content = DialogContent;
const Title = DialogTitle;
const Description = DialogDescription;
const Close = DialogClose;

export {
  createDialogScope,
  //
  Dialog,
  DialogTrigger,
  DialogPortal,
  DialogOverlay,
  DialogContent,
  DialogTitle,
  DialogDescription,
  DialogClose,
  //
  Root,
  Trigger,
  Portal,
  Overlay,
  Content,
  Title,
  Description,
  Close,
  //
  WarningProvider,
};
export type {
  DialogProps,
  DialogTriggerProps,
  DialogPortalProps,
  DialogOverlayProps,
  DialogContentProps,
  DialogTitleProps,
  DialogDescriptionProps,
  DialogCloseProps,
};



================================================
FILE: packages/react/dialog/src/index.ts
================================================
'use client';
export {
  createDialogScope,
  //
  Dialog,
  DialogTrigger,
  DialogPortal,
  DialogOverlay,
  DialogContent,
  DialogTitle,
  DialogDescription,
  DialogClose,
  //
  Root,
  Trigger,
  Portal,
  Overlay,
  Content,
  Title,
  Description,
  Close,
  //
  WarningProvider,
} from './dialog';
export type {
  DialogProps,
  DialogTriggerProps,
  DialogPortalProps,
  DialogOverlayProps,
  DialogContentProps,
  DialogTitleProps,
  DialogDescriptionProps,
  DialogCloseProps,
} from './dialog';



================================================
FILE: packages/react/direction/README.md
================================================
# `react-direction`

View docs [here](https://radix-ui.com/primitives/docs/utilities/direction).



================================================
FILE: packages/react/direction/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/direction/package.json
================================================
{
  "name": "@radix-ui/react-direction",
  "version": "1.1.1",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/direction/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/direction/src/direction.tsx
================================================
import * as React from 'react';

type Direction = 'ltr' | 'rtl';
const DirectionContext = React.createContext<Direction | undefined>(undefined);

/* -------------------------------------------------------------------------------------------------
 * Direction
 * -----------------------------------------------------------------------------------------------*/

interface DirectionProviderProps {
  children?: React.ReactNode;
  dir: Direction;
}
const DirectionProvider: React.FC<DirectionProviderProps> = (props) => {
  const { dir, children } = props;
  return <DirectionContext.Provider value={dir}>{children}</DirectionContext.Provider>;
};

/* -----------------------------------------------------------------------------------------------*/

function useDirection(localDir?: Direction) {
  const globalDir = React.useContext(DirectionContext);
  return localDir || globalDir || 'ltr';
}

const Provider = DirectionProvider;

export {
  useDirection,
  //
  Provider,
  //
  DirectionProvider,
};



================================================
FILE: packages/react/direction/src/index.ts
================================================
'use client';
export {
  useDirection,
  //
  Provider,
  //
  DirectionProvider,
} from './direction';



================================================
FILE: packages/react/dismissable-layer/README.md
================================================
# `react-dismissable-layer`

This is an internal utility, not intended for public usage.



================================================
FILE: packages/react/dismissable-layer/CHANGELOG.md
================================================
# @radix-ui/react-dismissable-layer

## 1.1.11

- Updated dependencies: `@radix-ui/primitive@1.1.3`, `@radix-ui/react-primitive@2.1.4`

## 1.1.10

- Replace deprecated 'ElementRef' with 'ComponentRef' (#3426)
- Updated dependencies: `@radix-ui/react-primitive@2.1.3`

## 1.1.9

- Updated dependencies: `@radix-ui/react-primitive@2.1.2`

## 1.1.8

- Updated dependencies: `@radix-ui/react-primitive@2.1.1`

## 1.1.7

- Updated dependencies: `@radix-ui/react-primitive@2.1.0`



================================================
FILE: packages/react/dismissable-layer/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/dismissable-layer/package.json
================================================
{
  "name": "@radix-ui/react-dismissable-layer",
  "version": "1.1.11",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/primitive": "workspace:*",
    "@radix-ui/react-compose-refs": "workspace:*",
    "@radix-ui/react-primitive": "workspace:*",
    "@radix-ui/react-use-callback-ref": "workspace:*",
    "@radix-ui/react-use-escape-keydown": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "react-remove-scroll": "^2.6.3",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/dismissable-layer/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/dismissable-layer/src/dismissable-layer.tsx
================================================
import * as React from 'react';
import { composeEventHandlers } from '@radix-ui/primitive';
import { Primitive, dispatchDiscreteCustomEvent } from '@radix-ui/react-primitive';
import { useComposedRefs } from '@radix-ui/react-compose-refs';
import { useCallbackRef } from '@radix-ui/react-use-callback-ref';
import { useEscapeKeydown } from '@radix-ui/react-use-escape-keydown';

/* -------------------------------------------------------------------------------------------------
 * DismissableLayer
 * -----------------------------------------------------------------------------------------------*/

const DISMISSABLE_LAYER_NAME = 'DismissableLayer';
const CONTEXT_UPDATE = 'dismissableLayer.update';
const POINTER_DOWN_OUTSIDE = 'dismissableLayer.pointerDownOutside';
const FOCUS_OUTSIDE = 'dismissableLayer.focusOutside';

let originalBodyPointerEvents: string;

const DismissableLayerContext = React.createContext({
  layers: new Set<DismissableLayerElement>(),
  layersWithOutsidePointerEventsDisabled: new Set<DismissableLayerElement>(),
  branches: new Set<DismissableLayerBranchElement>(),
});

type DismissableLayerElement = React.ComponentRef<typeof Primitive.div>;
type PrimitiveDivProps = React.ComponentPropsWithoutRef<typeof Primitive.div>;
interface DismissableLayerProps extends PrimitiveDivProps {
  /**
   * When `true`, hover/focus/click interactions will be disabled on elements outside
   * the `DismissableLayer`. Users will need to click twice on outside elements to
   * interact with them: once to close the `DismissableLayer`, and again to trigger the element.
   */
  disableOutsidePointerEvents?: boolean;
  /**
   * Event handler called when the escape key is down.
   * Can be prevented.
   */
  onEscapeKeyDown?: (event: KeyboardEvent) => void;
  /**
   * Event handler called when the a `pointerdown` event happens outside of the `DismissableLayer`.
   * Can be prevented.
   */
  onPointerDownOutside?: (event: PointerDownOutsideEvent) => void;
  /**
   * Event handler called when the focus moves outside of the `DismissableLayer`.
   * Can be prevented.
   */
  onFocusOutside?: (event: FocusOutsideEvent) => void;
  /**
   * Event handler called when an interaction happens outside the `DismissableLayer`.
   * Specifically, when a `pointerdown` event happens outside or focus moves outside of it.
   * Can be prevented.
   */
  onInteractOutside?: (event: PointerDownOutsideEvent | FocusOutsideEvent) => void;
  /**
   * Handler called when the `DismissableLayer` should be dismissed
   */
  onDismiss?: () => void;
}

const DismissableLayer = React.forwardRef<DismissableLayerElement, DismissableLayerProps>(
  (props, forwardedRef) => {
    const {
      disableOutsidePointerEvents = false,
      onEscapeKeyDown,
      onPointerDownOutside,
      onFocusOutside,
      onInteractOutside,
      onDismiss,
      ...layerProps
    } = props;
    const context = React.useContext(DismissableLayerContext);
    const [node, setNode] = React.useState<DismissableLayerElement | null>(null);
    const ownerDocument = node?.ownerDocument ?? globalThis?.document;
    const [, force] = React.useState({});
    const composedRefs = useComposedRefs(forwardedRef, (node) => setNode(node));
    const layers = Array.from(context.layers);
    const [highestLayerWithOutsidePointerEventsDisabled] = [...context.layersWithOutsidePointerEventsDisabled].slice(-1); // prettier-ignore
    const highestLayerWithOutsidePointerEventsDisabledIndex = layers.indexOf(highestLayerWithOutsidePointerEventsDisabled!); // prettier-ignore
    const index = node ? layers.indexOf(node) : -1;
    const isBodyPointerEventsDisabled = context.layersWithOutsidePointerEventsDisabled.size > 0;
    const isPointerEventsEnabled = index >= highestLayerWithOutsidePointerEventsDisabledIndex;

    const pointerDownOutside = usePointerDownOutside((event) => {
      const target = event.target as HTMLElement;
      const isPointerDownOnBranch = [...context.branches].some((branch) => branch.contains(target));
      if (!isPointerEventsEnabled || isPointerDownOnBranch) return;
      onPointerDownOutside?.(event);
      onInteractOutside?.(event);
      if (!event.defaultPrevented) onDismiss?.();
    }, ownerDocument);

    const focusOutside = useFocusOutside((event) => {
      const target = event.target as HTMLElement;
      const isFocusInBranch = [...context.branches].some((branch) => branch.contains(target));
      if (isFocusInBranch) return;
      onFocusOutside?.(event);
      onInteractOutside?.(event);
      if (!event.defaultPrevented) onDismiss?.();
    }, ownerDocument);

    useEscapeKeydown((event) => {
      const isHighestLayer = index === context.layers.size - 1;
      if (!isHighestLayer) return;
      onEscapeKeyDown?.(event);
      if (!event.defaultPrevented && onDismiss) {
        event.preventDefault();
        onDismiss();
      }
    }, ownerDocument);

    React.useEffect(() => {
      if (!node) return;
      if (disableOutsidePointerEvents) {
        if (context.layersWithOutsidePointerEventsDisabled.size === 0) {
          originalBodyPointerEvents = ownerDocument.body.style.pointerEvents;
          ownerDocument.body.style.pointerEvents = 'none';
        }
        context.layersWithOutsidePointerEventsDisabled.add(node);
      }
      context.layers.add(node);
      dispatchUpdate();
      return () => {
        if (
          disableOutsidePointerEvents &&
          context.layersWithOutsidePointerEventsDisabled.size === 1
        ) {
          ownerDocument.body.style.pointerEvents = originalBodyPointerEvents;
        }
      };
    }, [node, ownerDocument, disableOutsidePointerEvents, context]);

    /**
     * We purposefully prevent combining this effect with the `disableOutsidePointerEvents` effect
     * because a change to `disableOutsidePointerEvents` would remove this layer from the stack
     * and add it to the end again so the layering order wouldn't be _creation order_.
     * We only want them to be removed from context stacks when unmounted.
     */
    React.useEffect(() => {
      return () => {
        if (!node) return;
        context.layers.delete(node);
        context.layersWithOutsidePointerEventsDisabled.delete(node);
        dispatchUpdate();
      };
    }, [node, context]);

    React.useEffect(() => {
      const handleUpdate = () => force({});
      document.addEventListener(CONTEXT_UPDATE, handleUpdate);
      return () => document.removeEventListener(CONTEXT_UPDATE, handleUpdate);
    }, []);

    return (
      <Primitive.div
        {...layerProps}
        ref={composedRefs}
        style={{
          pointerEvents: isBodyPointerEventsDisabled
            ? isPointerEventsEnabled
              ? 'auto'
              : 'none'
            : undefined,
          ...props.style,
        }}
        onFocusCapture={composeEventHandlers(props.onFocusCapture, focusOutside.onFocusCapture)}
        onBlurCapture={composeEventHandlers(props.onBlurCapture, focusOutside.onBlurCapture)}
        onPointerDownCapture={composeEventHandlers(
          props.onPointerDownCapture,
          pointerDownOutside.onPointerDownCapture,
        )}
      />
    );
  },
);

DismissableLayer.displayName = DISMISSABLE_LAYER_NAME;

/* -------------------------------------------------------------------------------------------------
 * DismissableLayerBranch
 * -----------------------------------------------------------------------------------------------*/

const BRANCH_NAME = 'DismissableLayerBranch';

type DismissableLayerBranchElement = React.ComponentRef<typeof Primitive.div>;
interface DismissableLayerBranchProps extends PrimitiveDivProps {}

const DismissableLayerBranch = React.forwardRef<
  DismissableLayerBranchElement,
  DismissableLayerBranchProps
>((props, forwardedRef) => {
  const context = React.useContext(DismissableLayerContext);
  const ref = React.useRef<DismissableLayerBranchElement>(null);
  const composedRefs = useComposedRefs(forwardedRef, ref);

  React.useEffect(() => {
    const node = ref.current;
    if (node) {
      context.branches.add(node);
      return () => {
        context.branches.delete(node);
      };
    }
  }, [context.branches]);

  return <Primitive.div {...props} ref={composedRefs} />;
});

DismissableLayerBranch.displayName = BRANCH_NAME;

/* -----------------------------------------------------------------------------------------------*/

type PointerDownOutsideEvent = CustomEvent<{ originalEvent: PointerEvent }>;
type FocusOutsideEvent = CustomEvent<{ originalEvent: FocusEvent }>;

/**
 * Listens for `pointerdown` outside a react subtree. We use `pointerdown` rather than `pointerup`
 * to mimic layer dismissing behaviour present in OS.
 * Returns props to pass to the node we want to check for outside events.
 */
function usePointerDownOutside(
  onPointerDownOutside?: (event: PointerDownOutsideEvent) => void,
  ownerDocument: Document = globalThis?.document,
) {
  const handlePointerDownOutside = useCallbackRef(onPointerDownOutside) as EventListener;
  const isPointerInsideReactTreeRef = React.useRef(false);
  const handleClickRef = React.useRef(() => {});

  React.useEffect(() => {
    const handlePointerDown = (event: PointerEvent) => {
      if (event.target && !isPointerInsideReactTreeRef.current) {
        const eventDetail = { originalEvent: event };

        function handleAndDispatchPointerDownOutsideEvent() {
          handleAndDispatchCustomEvent(
            POINTER_DOWN_OUTSIDE,
            handlePointerDownOutside,
            eventDetail,
            { discrete: true },
          );
        }

        /**
         * On touch devices, we need to wait for a click event because browsers implement
         * a ~350ms delay between the time the user stops touching the display and when the
         * browser executres events. We need to ensure we don't reactivate pointer-events within
         * this timeframe otherwise the browser may execute events that should have been prevented.
         *
         * Additionally, this also lets us deal automatically with cancellations when a click event
         * isn't raised because the page was considered scrolled/drag-scrolled, long-pressed, etc.
         *
         * This is why we also continuously remove the previous listener, because we cannot be
         * certain that it was raised, and therefore cleaned-up.
         */
        if (event.pointerType === 'touch') {
          ownerDocument.removeEventListener('click', handleClickRef.current);
          handleClickRef.current = handleAndDispatchPointerDownOutsideEvent;
          ownerDocument.addEventListener('click', handleClickRef.current, { once: true });
        } else {
          handleAndDispatchPointerDownOutsideEvent();
        }
      } else {
        // We need to remove the event listener in case the outside click has been canceled.
        // See: https://github.com/radix-ui/primitives/issues/2171
        ownerDocument.removeEventListener('click', handleClickRef.current);
      }
      isPointerInsideReactTreeRef.current = false;
    };
    /**
     * if this hook executes in a component that mounts via a `pointerdown` event, the event
     * would bubble up to the document and trigger a `pointerDownOutside` event. We avoid
     * this by delaying the event listener registration on the document.
     * This is not React specific, but rather how the DOM works, ie:
     * ```
     * button.addEventListener('pointerdown', () => {
     *   console.log('I will log');
     *   document.addEventListener('pointerdown', () => {
     *     console.log('I will also log');
     *   })
     * });
     */
    const timerId = window.setTimeout(() => {
      ownerDocument.addEventListener('pointerdown', handlePointerDown);
    }, 0);
    return () => {
      window.clearTimeout(timerId);
      ownerDocument.removeEventListener('pointerdown', handlePointerDown);
      ownerDocument.removeEventListener('click', handleClickRef.current);
    };
  }, [ownerDocument, handlePointerDownOutside]);

  return {
    // ensures we check React component tree (not just DOM tree)
    onPointerDownCapture: () => (isPointerInsideReactTreeRef.current = true),
  };
}

/**
 * Listens for when focus happens outside a react subtree.
 * Returns props to pass to the root (node) of the subtree we want to check.
 */
function useFocusOutside(
  onFocusOutside?: (event: FocusOutsideEvent) => void,
  ownerDocument: Document = globalThis?.document,
) {
  const handleFocusOutside = useCallbackRef(onFocusOutside) as EventListener;
  const isFocusInsideReactTreeRef = React.useRef(false);

  React.useEffect(() => {
    const handleFocus = (event: FocusEvent) => {
      if (event.target && !isFocusInsideReactTreeRef.current) {
        const eventDetail = { originalEvent: event };
        handleAndDispatchCustomEvent(FOCUS_OUTSIDE, handleFocusOutside, eventDetail, {
          discrete: false,
        });
      }
    };
    ownerDocument.addEventListener('focusin', handleFocus);
    return () => ownerDocument.removeEventListener('focusin', handleFocus);
  }, [ownerDocument, handleFocusOutside]);

  return {
    onFocusCapture: () => (isFocusInsideReactTreeRef.current = true),
    onBlurCapture: () => (isFocusInsideReactTreeRef.current = false),
  };
}

function dispatchUpdate() {
  const event = new CustomEvent(CONTEXT_UPDATE);
  document.dispatchEvent(event);
}

function handleAndDispatchCustomEvent<E extends CustomEvent, OriginalEvent extends Event>(
  name: string,
  handler: ((event: E) => void) | undefined,
  detail: { originalEvent: OriginalEvent } & (E extends CustomEvent<infer D> ? D : never),
  { discrete }: { discrete: boolean },
) {
  const target = detail.originalEvent.target;
  const event = new CustomEvent(name, { bubbles: false, cancelable: true, detail });
  if (handler) target.addEventListener(name, handler as EventListener, { once: true });

  if (discrete) {
    dispatchDiscreteCustomEvent(target, event);
  } else {
    target.dispatchEvent(event);
  }
}

const Root = DismissableLayer;
const Branch = DismissableLayerBranch;

export {
  DismissableLayer,
  DismissableLayerBranch,
  //
  Root,
  Branch,
};
export type { DismissableLayerProps };



================================================
FILE: packages/react/dismissable-layer/src/index.ts
================================================
'use client';
export {
  DismissableLayer,
  DismissableLayerBranch,
  //
  Root,
  Branch,
} from './dismissable-layer';
export type { DismissableLayerProps } from './dismissable-layer';



================================================
FILE: packages/react/dropdown-menu/README.md
================================================
# `react-dropdown-menu`

View docs [here](https://radix-ui.com/primitives/docs/components/dropdown-menu).



================================================
FILE: packages/react/dropdown-menu/CHANGELOG.md
================================================
# @radix-ui/react-dropdown-menu

## 2.1.16

- Updated dependencies: `@radix-ui/primitive@1.1.3`, `@radix-ui/react-context@1.1.3`, `@radix-ui/react-menu@2.1.16`, `@radix-ui/react-primitive@2.1.4`

## 2.1.15

- Replace deprecated 'ElementRef' with 'ComponentRef' (#3426)
- Updated dependencies: `@radix-ui/react-menu@2.1.15`, `@radix-ui/react-primitive@2.1.3`

## 2.1.14

- Updated dependencies: `@radix-ui/react-menu@2.1.14`, `@radix-ui/react-primitive@2.1.2`

## 2.1.13

- Updated dependencies: `@radix-ui/react-menu@2.1.13`, `@radix-ui/react-primitive@2.1.1`

## 2.1.12

- Updated dependencies: `@radix-ui/react-menu@2.1.12`

## 2.1.11

- Updated dependencies: `@radix-ui/react-menu@2.1.11`

## 2.1.10

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.2`, `@radix-ui/react-menu@2.1.10`

## 2.1.9

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.1`, `@radix-ui/react-menu@2.1.9`

## 2.1.8

- Minor improvements to `useControllableState` to enhance performance, reduce surface area for bugs, and log warnings when misused (#3455)
- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.0`, `@radix-ui/react-primitive@2.1.0`, `@radix-ui/react-menu@2.1.8`



================================================
FILE: packages/react/dropdown-menu/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/dropdown-menu/package.json
================================================
{
  "name": "@radix-ui/react-dropdown-menu",
  "version": "2.1.16",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/primitive": "workspace:*",
    "@radix-ui/react-compose-refs": "workspace:*",
    "@radix-ui/react-context": "workspace:*",
    "@radix-ui/react-id": "workspace:*",
    "@radix-ui/react-menu": "workspace:*",
    "@radix-ui/react-primitive": "workspace:*",
    "@radix-ui/react-use-controllable-state": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/test-data": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/dropdown-menu/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/dropdown-menu/src/dropdown-menu.tsx
================================================
import * as React from 'react';
import { composeEventHandlers } from '@radix-ui/primitive';
import { composeRefs } from '@radix-ui/react-compose-refs';
import { createContextScope } from '@radix-ui/react-context';
import { useControllableState } from '@radix-ui/react-use-controllable-state';
import { Primitive } from '@radix-ui/react-primitive';
import * as MenuPrimitive from '@radix-ui/react-menu';
import { createMenuScope } from '@radix-ui/react-menu';
import { useId } from '@radix-ui/react-id';

import type { Scope } from '@radix-ui/react-context';

type Direction = 'ltr' | 'rtl';

/* -------------------------------------------------------------------------------------------------
 * DropdownMenu
 * -----------------------------------------------------------------------------------------------*/

const DROPDOWN_MENU_NAME = 'DropdownMenu';

type ScopedProps<P> = P & { __scopeDropdownMenu?: Scope };
const [createDropdownMenuContext, createDropdownMenuScope] = createContextScope(
  DROPDOWN_MENU_NAME,
  [createMenuScope],
);
const useMenuScope = createMenuScope();

type DropdownMenuContextValue = {
  triggerId: string;
  triggerRef: React.RefObject<HTMLButtonElement | null>;
  contentId: string;
  open: boolean;
  onOpenChange(open: boolean): void;
  onOpenToggle(): void;
  modal: boolean;
};

const [DropdownMenuProvider, useDropdownMenuContext] =
  createDropdownMenuContext<DropdownMenuContextValue>(DROPDOWN_MENU_NAME);

interface DropdownMenuProps {
  children?: React.ReactNode;
  dir?: Direction;
  open?: boolean;
  defaultOpen?: boolean;
  onOpenChange?(open: boolean): void;
  modal?: boolean;
}

const DropdownMenu: React.FC<DropdownMenuProps> = (props: ScopedProps<DropdownMenuProps>) => {
  const {
    __scopeDropdownMenu,
    children,
    dir,
    open: openProp,
    defaultOpen,
    onOpenChange,
    modal = true,
  } = props;
  const menuScope = useMenuScope(__scopeDropdownMenu);
  const triggerRef = React.useRef<HTMLButtonElement>(null);
  const [open, setOpen] = useControllableState({
    prop: openProp,
    defaultProp: defaultOpen ?? false,
    onChange: onOpenChange,
    caller: DROPDOWN_MENU_NAME,
  });

  return (
    <DropdownMenuProvider
      scope={__scopeDropdownMenu}
      triggerId={useId()}
      triggerRef={triggerRef}
      contentId={useId()}
      open={open}
      onOpenChange={setOpen}
      onOpenToggle={React.useCallback(() => setOpen((prevOpen) => !prevOpen), [setOpen])}
      modal={modal}
    >
      <MenuPrimitive.Root {...menuScope} open={open} onOpenChange={setOpen} dir={dir} modal={modal}>
        {children}
      </MenuPrimitive.Root>
    </DropdownMenuProvider>
  );
};

DropdownMenu.displayName = DROPDOWN_MENU_NAME;

/* -------------------------------------------------------------------------------------------------
 * DropdownMenuTrigger
 * -----------------------------------------------------------------------------------------------*/

const TRIGGER_NAME = 'DropdownMenuTrigger';

type DropdownMenuTriggerElement = React.ComponentRef<typeof Primitive.button>;
type PrimitiveButtonProps = React.ComponentPropsWithoutRef<typeof Primitive.button>;
interface DropdownMenuTriggerProps extends PrimitiveButtonProps {}

const DropdownMenuTrigger = React.forwardRef<DropdownMenuTriggerElement, DropdownMenuTriggerProps>(
  (props: ScopedProps<DropdownMenuTriggerProps>, forwardedRef) => {
    const { __scopeDropdownMenu, disabled = false, ...triggerProps } = props;
    const context = useDropdownMenuContext(TRIGGER_NAME, __scopeDropdownMenu);
    const menuScope = useMenuScope(__scopeDropdownMenu);
    return (
      <MenuPrimitive.Anchor asChild {...menuScope}>
        <Primitive.button
          type="button"
          id={context.triggerId}
          aria-haspopup="menu"
          aria-expanded={context.open}
          aria-controls={context.open ? context.contentId : undefined}
          data-state={context.open ? 'open' : 'closed'}
          data-disabled={disabled ? '' : undefined}
          disabled={disabled}
          {...triggerProps}
          ref={composeRefs(forwardedRef, context.triggerRef)}
          onPointerDown={composeEventHandlers(props.onPointerDown, (event) => {
            // only call handler if it's the left button (mousedown gets triggered by all mouse buttons)
            // but not when the control key is pressed (avoiding MacOS right click)
            if (!disabled && event.button === 0 && event.ctrlKey === false) {
              context.onOpenToggle();
              // prevent trigger focusing when opening
              // this allows the content to be given focus without competition
              if (!context.open) event.preventDefault();
            }
          })}
          onKeyDown={composeEventHandlers(props.onKeyDown, (event) => {
            if (disabled) return;
            if (['Enter', ' '].includes(event.key)) context.onOpenToggle();
            if (event.key === 'ArrowDown') context.onOpenChange(true);
            // prevent keydown from scrolling window / first focused item to execute
            // that keydown (inadvertently closing the menu)
            if (['Enter', ' ', 'ArrowDown'].includes(event.key)) event.preventDefault();
          })}
        />
      </MenuPrimitive.Anchor>
    );
  },
);

DropdownMenuTrigger.displayName = TRIGGER_NAME;

/* -------------------------------------------------------------------------------------------------
 * DropdownMenuPortal
 * -----------------------------------------------------------------------------------------------*/

const PORTAL_NAME = 'DropdownMenuPortal';

type MenuPortalProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.Portal>;
interface DropdownMenuPortalProps extends MenuPortalProps {}

const DropdownMenuPortal: React.FC<DropdownMenuPortalProps> = (
  props: ScopedProps<DropdownMenuPortalProps>,
) => {
  const { __scopeDropdownMenu, ...portalProps } = props;
  const menuScope = useMenuScope(__scopeDropdownMenu);
  return <MenuPrimitive.Portal {...menuScope} {...portalProps} />;
};

DropdownMenuPortal.displayName = PORTAL_NAME;

/* -------------------------------------------------------------------------------------------------
 * DropdownMenuContent
 * -----------------------------------------------------------------------------------------------*/

const CONTENT_NAME = 'DropdownMenuContent';

type DropdownMenuContentElement = React.ComponentRef<typeof MenuPrimitive.Content>;
type MenuContentProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.Content>;
interface DropdownMenuContentProps extends Omit<MenuContentProps, 'onEntryFocus'> {}

const DropdownMenuContent = React.forwardRef<DropdownMenuContentElement, DropdownMenuContentProps>(
  (props: ScopedProps<DropdownMenuContentProps>, forwardedRef) => {
    const { __scopeDropdownMenu, ...contentProps } = props;
    const context = useDropdownMenuContext(CONTENT_NAME, __scopeDropdownMenu);
    const menuScope = useMenuScope(__scopeDropdownMenu);
    const hasInteractedOutsideRef = React.useRef(false);

    return (
      <MenuPrimitive.Content
        id={context.contentId}
        aria-labelledby={context.triggerId}
        {...menuScope}
        {...contentProps}
        ref={forwardedRef}
        onCloseAutoFocus={composeEventHandlers(props.onCloseAutoFocus, (event) => {
          if (!hasInteractedOutsideRef.current) context.triggerRef.current?.focus();
          hasInteractedOutsideRef.current = false;
          // Always prevent auto focus because we either focus manually or want user agent focus
          event.preventDefault();
        })}
        onInteractOutside={composeEventHandlers(props.onInteractOutside, (event) => {
          const originalEvent = event.detail.originalEvent as PointerEvent;
          const ctrlLeftClick = originalEvent.button === 0 && originalEvent.ctrlKey === true;
          const isRightClick = originalEvent.button === 2 || ctrlLeftClick;
          if (!context.modal || isRightClick) hasInteractedOutsideRef.current = true;
        })}
        style={{
          ...props.style,
          // re-namespace exposed content custom properties
          ...{
            '--radix-dropdown-menu-content-transform-origin':
              'var(--radix-popper-transform-origin)',
            '--radix-dropdown-menu-content-available-width': 'var(--radix-popper-available-width)',
            '--radix-dropdown-menu-content-available-height':
              'var(--radix-popper-available-height)',
            '--radix-dropdown-menu-trigger-width': 'var(--radix-popper-anchor-width)',
            '--radix-dropdown-menu-trigger-height': 'var(--radix-popper-anchor-height)',
          },
        }}
      />
    );
  },
);

DropdownMenuContent.displayName = CONTENT_NAME;

/* -------------------------------------------------------------------------------------------------
 * DropdownMenuGroup
 * -----------------------------------------------------------------------------------------------*/

const GROUP_NAME = 'DropdownMenuGroup';

type DropdownMenuGroupElement = React.ComponentRef<typeof MenuPrimitive.Group>;
type MenuGroupProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.Group>;
interface DropdownMenuGroupProps extends MenuGroupProps {}

const DropdownMenuGroup = React.forwardRef<DropdownMenuGroupElement, DropdownMenuGroupProps>(
  (props: ScopedProps<DropdownMenuGroupProps>, forwardedRef) => {
    const { __scopeDropdownMenu, ...groupProps } = props;
    const menuScope = useMenuScope(__scopeDropdownMenu);
    return <MenuPrimitive.Group {...menuScope} {...groupProps} ref={forwardedRef} />;
  },
);

DropdownMenuGroup.displayName = GROUP_NAME;

/* -------------------------------------------------------------------------------------------------
 * DropdownMenuLabel
 * -----------------------------------------------------------------------------------------------*/

const LABEL_NAME = 'DropdownMenuLabel';

type DropdownMenuLabelElement = React.ComponentRef<typeof MenuPrimitive.Label>;
type MenuLabelProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.Label>;
interface DropdownMenuLabelProps extends MenuLabelProps {}

const DropdownMenuLabel = React.forwardRef<DropdownMenuLabelElement, DropdownMenuLabelProps>(
  (props: ScopedProps<DropdownMenuLabelProps>, forwardedRef) => {
    const { __scopeDropdownMenu, ...labelProps } = props;
    const menuScope = useMenuScope(__scopeDropdownMenu);
    return <MenuPrimitive.Label {...menuScope} {...labelProps} ref={forwardedRef} />;
  },
);

DropdownMenuLabel.displayName = LABEL_NAME;

/* -------------------------------------------------------------------------------------------------
 * DropdownMenuItem
 * -----------------------------------------------------------------------------------------------*/

const ITEM_NAME = 'DropdownMenuItem';

type DropdownMenuItemElement = React.ComponentRef<typeof MenuPrimitive.Item>;
type MenuItemProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.Item>;
interface DropdownMenuItemProps extends MenuItemProps {}

const DropdownMenuItem = React.forwardRef<DropdownMenuItemElement, DropdownMenuItemProps>(
  (props: ScopedProps<DropdownMenuItemProps>, forwardedRef) => {
    const { __scopeDropdownMenu, ...itemProps } = props;
    const menuScope = useMenuScope(__scopeDropdownMenu);
    return <MenuPrimitive.Item {...menuScope} {...itemProps} ref={forwardedRef} />;
  },
);

DropdownMenuItem.displayName = ITEM_NAME;

/* -------------------------------------------------------------------------------------------------
 * DropdownMenuCheckboxItem
 * -----------------------------------------------------------------------------------------------*/

const CHECKBOX_ITEM_NAME = 'DropdownMenuCheckboxItem';

type DropdownMenuCheckboxItemElement = React.ComponentRef<typeof MenuPrimitive.CheckboxItem>;
type MenuCheckboxItemProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.CheckboxItem>;
interface DropdownMenuCheckboxItemProps extends MenuCheckboxItemProps {}

const DropdownMenuCheckboxItem = React.forwardRef<
  DropdownMenuCheckboxItemElement,
  DropdownMenuCheckboxItemProps
>((props: ScopedProps<DropdownMenuCheckboxItemProps>, forwardedRef) => {
  const { __scopeDropdownMenu, ...checkboxItemProps } = props;
  const menuScope = useMenuScope(__scopeDropdownMenu);
  return <MenuPrimitive.CheckboxItem {...menuScope} {...checkboxItemProps} ref={forwardedRef} />;
});

DropdownMenuCheckboxItem.displayName = CHECKBOX_ITEM_NAME;

/* -------------------------------------------------------------------------------------------------
 * DropdownMenuRadioGroup
 * -----------------------------------------------------------------------------------------------*/

const RADIO_GROUP_NAME = 'DropdownMenuRadioGroup';

type DropdownMenuRadioGroupElement = React.ComponentRef<typeof MenuPrimitive.RadioGroup>;
type MenuRadioGroupProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.RadioGroup>;
interface DropdownMenuRadioGroupProps extends MenuRadioGroupProps {}

const DropdownMenuRadioGroup = React.forwardRef<
  DropdownMenuRadioGroupElement,
  DropdownMenuRadioGroupProps
>((props: ScopedProps<DropdownMenuRadioGroupProps>, forwardedRef) => {
  const { __scopeDropdownMenu, ...radioGroupProps } = props;
  const menuScope = useMenuScope(__scopeDropdownMenu);
  return <MenuPrimitive.RadioGroup {...menuScope} {...radioGroupProps} ref={forwardedRef} />;
});

DropdownMenuRadioGroup.displayName = RADIO_GROUP_NAME;

/* -------------------------------------------------------------------------------------------------
 * DropdownMenuRadioItem
 * -----------------------------------------------------------------------------------------------*/

const RADIO_ITEM_NAME = 'DropdownMenuRadioItem';

type DropdownMenuRadioItemElement = React.ComponentRef<typeof MenuPrimitive.RadioItem>;
type MenuRadioItemProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.RadioItem>;
interface DropdownMenuRadioItemProps extends MenuRadioItemProps {}

const DropdownMenuRadioItem = React.forwardRef<
  DropdownMenuRadioItemElement,
  DropdownMenuRadioItemProps
>((props: ScopedProps<DropdownMenuRadioItemProps>, forwardedRef) => {
  const { __scopeDropdownMenu, ...radioItemProps } = props;
  const menuScope = useMenuScope(__scopeDropdownMenu);
  return <MenuPrimitive.RadioItem {...menuScope} {...radioItemProps} ref={forwardedRef} />;
});

DropdownMenuRadioItem.displayName = RADIO_ITEM_NAME;

/* -------------------------------------------------------------------------------------------------
 * DropdownMenuItemIndicator
 * -----------------------------------------------------------------------------------------------*/

const INDICATOR_NAME = 'DropdownMenuItemIndicator';

type DropdownMenuItemIndicatorElement = React.ComponentRef<typeof MenuPrimitive.ItemIndicator>;
type MenuItemIndicatorProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.ItemIndicator>;
interface DropdownMenuItemIndicatorProps extends MenuItemIndicatorProps {}

const DropdownMenuItemIndicator = React.forwardRef<
  DropdownMenuItemIndicatorElement,
  DropdownMenuItemIndicatorProps
>((props: ScopedProps<DropdownMenuItemIndicatorProps>, forwardedRef) => {
  const { __scopeDropdownMenu, ...itemIndicatorProps } = props;
  const menuScope = useMenuScope(__scopeDropdownMenu);
  return <MenuPrimitive.ItemIndicator {...menuScope} {...itemIndicatorProps} ref={forwardedRef} />;
});

DropdownMenuItemIndicator.displayName = INDICATOR_NAME;

/* -------------------------------------------------------------------------------------------------
 * DropdownMenuSeparator
 * -----------------------------------------------------------------------------------------------*/

const SEPARATOR_NAME = 'DropdownMenuSeparator';

type DropdownMenuSeparatorElement = React.ComponentRef<typeof MenuPrimitive.Separator>;
type MenuSeparatorProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.Separator>;
interface DropdownMenuSeparatorProps extends MenuSeparatorProps {}

const DropdownMenuSeparator = React.forwardRef<
  DropdownMenuSeparatorElement,
  DropdownMenuSeparatorProps
>((props: ScopedProps<DropdownMenuSeparatorProps>, forwardedRef) => {
  const { __scopeDropdownMenu, ...separatorProps } = props;
  const menuScope = useMenuScope(__scopeDropdownMenu);
  return <MenuPrimitive.Separator {...menuScope} {...separatorProps} ref={forwardedRef} />;
});

DropdownMenuSeparator.displayName = SEPARATOR_NAME;

/* -------------------------------------------------------------------------------------------------
 * DropdownMenuArrow
 * -----------------------------------------------------------------------------------------------*/

const ARROW_NAME = 'DropdownMenuArrow';

type DropdownMenuArrowElement = React.ComponentRef<typeof MenuPrimitive.Arrow>;
type MenuArrowProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.Arrow>;
interface DropdownMenuArrowProps extends MenuArrowProps {}

const DropdownMenuArrow = React.forwardRef<DropdownMenuArrowElement, DropdownMenuArrowProps>(
  (props: ScopedProps<DropdownMenuArrowProps>, forwardedRef) => {
    const { __scopeDropdownMenu, ...arrowProps } = props;
    const menuScope = useMenuScope(__scopeDropdownMenu);
    return <MenuPrimitive.Arrow {...menuScope} {...arrowProps} ref={forwardedRef} />;
  },
);

DropdownMenuArrow.displayName = ARROW_NAME;

/* -------------------------------------------------------------------------------------------------
 * DropdownMenuSub
 * -----------------------------------------------------------------------------------------------*/

interface DropdownMenuSubProps {
  children?: React.ReactNode;
  open?: boolean;
  defaultOpen?: boolean;
  onOpenChange?(open: boolean): void;
}

const DropdownMenuSub: React.FC<DropdownMenuSubProps> = (
  props: ScopedProps<DropdownMenuSubProps>,
) => {
  const { __scopeDropdownMenu, children, open: openProp, onOpenChange, defaultOpen } = props;
  const menuScope = useMenuScope(__scopeDropdownMenu);
  const [open, setOpen] = useControllableState({
    prop: openProp,
    defaultProp: defaultOpen ?? false,
    onChange: onOpenChange,
    caller: 'DropdownMenuSub',
  });

  return (
    <MenuPrimitive.Sub {...menuScope} open={open} onOpenChange={setOpen}>
      {children}
    </MenuPrimitive.Sub>
  );
};

/* -------------------------------------------------------------------------------------------------
 * DropdownMenuSubTrigger
 * -----------------------------------------------------------------------------------------------*/

const SUB_TRIGGER_NAME = 'DropdownMenuSubTrigger';

type DropdownMenuSubTriggerElement = React.ComponentRef<typeof MenuPrimitive.SubTrigger>;
type MenuSubTriggerProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.SubTrigger>;
interface DropdownMenuSubTriggerProps extends MenuSubTriggerProps {}

const DropdownMenuSubTrigger = React.forwardRef<
  DropdownMenuSubTriggerElement,
  DropdownMenuSubTriggerProps
>((props: ScopedProps<DropdownMenuSubTriggerProps>, forwardedRef) => {
  const { __scopeDropdownMenu, ...subTriggerProps } = props;
  const menuScope = useMenuScope(__scopeDropdownMenu);
  return <MenuPrimitive.SubTrigger {...menuScope} {...subTriggerProps} ref={forwardedRef} />;
});

DropdownMenuSubTrigger.displayName = SUB_TRIGGER_NAME;

/* -------------------------------------------------------------------------------------------------
 * DropdownMenuSubContent
 * -----------------------------------------------------------------------------------------------*/

const SUB_CONTENT_NAME = 'DropdownMenuSubContent';

type DropdownMenuSubContentElement = React.ComponentRef<typeof MenuPrimitive.Content>;
type MenuSubContentProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.SubContent>;
interface DropdownMenuSubContentProps extends MenuSubContentProps {}

const DropdownMenuSubContent = React.forwardRef<
  DropdownMenuSubContentElement,
  DropdownMenuSubContentProps
>((props: ScopedProps<DropdownMenuSubContentProps>, forwardedRef) => {
  const { __scopeDropdownMenu, ...subContentProps } = props;
  const menuScope = useMenuScope(__scopeDropdownMenu);

  return (
    <MenuPrimitive.SubContent
      {...menuScope}
      {...subContentProps}
      ref={forwardedRef}
      style={{
        ...props.style,
        // re-namespace exposed content custom properties
        ...{
          '--radix-dropdown-menu-content-transform-origin': 'var(--radix-popper-transform-origin)',
          '--radix-dropdown-menu-content-available-width': 'var(--radix-popper-available-width)',
          '--radix-dropdown-menu-content-available-height': 'var(--radix-popper-available-height)',
          '--radix-dropdown-menu-trigger-width': 'var(--radix-popper-anchor-width)',
          '--radix-dropdown-menu-trigger-height': 'var(--radix-popper-anchor-height)',
        },
      }}
    />
  );
});

DropdownMenuSubContent.displayName = SUB_CONTENT_NAME;

/* -----------------------------------------------------------------------------------------------*/

const Root = DropdownMenu;
const Trigger = DropdownMenuTrigger;
const Portal = DropdownMenuPortal;
const Content = DropdownMenuContent;
const Group = DropdownMenuGroup;
const Label = DropdownMenuLabel;
const Item = DropdownMenuItem;
const CheckboxItem = DropdownMenuCheckboxItem;
const RadioGroup = DropdownMenuRadioGroup;
const RadioItem = DropdownMenuRadioItem;
const ItemIndicator = DropdownMenuItemIndicator;
const Separator = DropdownMenuSeparator;
const Arrow = DropdownMenuArrow;
const Sub = DropdownMenuSub;
const SubTrigger = DropdownMenuSubTrigger;
const SubContent = DropdownMenuSubContent;

export {
  createDropdownMenuScope,
  //
  DropdownMenu,
  DropdownMenuTrigger,
  DropdownMenuPortal,
  DropdownMenuContent,
  DropdownMenuGroup,
  DropdownMenuLabel,
  DropdownMenuItem,
  DropdownMenuCheckboxItem,
  DropdownMenuRadioGroup,
  DropdownMenuRadioItem,
  DropdownMenuItemIndicator,
  DropdownMenuSeparator,
  DropdownMenuArrow,
  DropdownMenuSub,
  DropdownMenuSubTrigger,
  DropdownMenuSubContent,
  //
  Root,
  Trigger,
  Portal,
  Content,
  Group,
  Label,
  Item,
  CheckboxItem,
  RadioGroup,
  RadioItem,
  ItemIndicator,
  Separator,
  Arrow,
  Sub,
  SubTrigger,
  SubContent,
};
export type {
  DropdownMenuProps,
  DropdownMenuTriggerProps,
  DropdownMenuPortalProps,
  DropdownMenuContentProps,
  DropdownMenuGroupProps,
  DropdownMenuLabelProps,
  DropdownMenuItemProps,
  DropdownMenuCheckboxItemProps,
  DropdownMenuRadioGroupProps,
  DropdownMenuRadioItemProps,
  DropdownMenuItemIndicatorProps,
  DropdownMenuSeparatorProps,
  DropdownMenuArrowProps,
  DropdownMenuSubProps,
  DropdownMenuSubTriggerProps,
  DropdownMenuSubContentProps,
};



================================================
FILE: packages/react/dropdown-menu/src/index.ts
================================================
'use client';
export {
  createDropdownMenuScope,
  //
  DropdownMenu,
  DropdownMenuTrigger,
  DropdownMenuPortal,
  DropdownMenuContent,
  DropdownMenuGroup,
  DropdownMenuLabel,
  DropdownMenuItem,
  DropdownMenuCheckboxItem,
  DropdownMenuRadioGroup,
  DropdownMenuRadioItem,
  DropdownMenuItemIndicator,
  DropdownMenuSeparator,
  DropdownMenuArrow,
  DropdownMenuSub,
  DropdownMenuSubTrigger,
  DropdownMenuSubContent,
  //
  Root,
  Trigger,
  Portal,
  Content,
  Group,
  Label,
  Item,
  CheckboxItem,
  RadioGroup,
  RadioItem,
  ItemIndicator,
  Separator,
  Arrow,
  Sub,
  SubTrigger,
  SubContent,
} from './dropdown-menu';
export type {
  DropdownMenuProps,
  DropdownMenuTriggerProps,
  DropdownMenuPortalProps,
  DropdownMenuContentProps,
  DropdownMenuGroupProps,
  DropdownMenuLabelProps,
  DropdownMenuItemProps,
  DropdownMenuCheckboxItemProps,
  DropdownMenuRadioGroupProps,
  DropdownMenuRadioItemProps,
  DropdownMenuItemIndicatorProps,
  DropdownMenuSeparatorProps,
  DropdownMenuArrowProps,
  DropdownMenuSubProps,
  DropdownMenuSubTriggerProps,
  DropdownMenuSubContentProps,
} from './dropdown-menu';



================================================
FILE: packages/react/focus-guards/README.md
================================================
# `react-focus-guards`

This is an internal utility, not intended for public usage.



================================================
FILE: packages/react/focus-guards/CHANGELOG.md
================================================
# @radix-ui/react-focus-guards

## 1.1.3

- Added internal prop types



================================================
FILE: packages/react/focus-guards/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/focus-guards/package.json
================================================
{
  "name": "@radix-ui/react-focus-guards",
  "version": "1.1.3",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/focus-guards/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/focus-guards/src/focus-guards.tsx
================================================
import * as React from 'react';

/** Number of components which have requested interest to have focus guards */
let count = 0;

interface FocusGuardsProps {
  children?: React.ReactNode;
}

function FocusGuards(props: FocusGuardsProps) {
  useFocusGuards();
  return props.children;
}

/**
 * Injects a pair of focus guards at the edges of the whole DOM tree
 * to ensure `focusin` & `focusout` events can be caught consistently.
 */
function useFocusGuards() {
  React.useEffect(() => {
    const edgeGuards = document.querySelectorAll('[data-radix-focus-guard]');
    document.body.insertAdjacentElement('afterbegin', edgeGuards[0] ?? createFocusGuard());
    document.body.insertAdjacentElement('beforeend', edgeGuards[1] ?? createFocusGuard());
    count++;

    return () => {
      if (count === 1) {
        document.querySelectorAll('[data-radix-focus-guard]').forEach((node) => node.remove());
      }
      count--;
    };
  }, []);
}

function createFocusGuard() {
  const element = document.createElement('span');
  element.setAttribute('data-radix-focus-guard', '');
  element.tabIndex = 0;
  element.style.outline = 'none';
  element.style.opacity = '0';
  element.style.position = 'fixed';
  element.style.pointerEvents = 'none';
  return element;
}

export {
  FocusGuards,
  //
  FocusGuards as Root,
  //
  useFocusGuards,
};



================================================
FILE: packages/react/focus-guards/src/index.ts
================================================
'use client';
export {
  FocusGuards,
  //
  Root,
  //
  useFocusGuards,
} from './focus-guards';



================================================
FILE: packages/react/focus-scope/README.md
================================================
# `react-focus-scope`

This is an internal utility, not intended for public usage.



================================================
FILE: packages/react/focus-scope/CHANGELOG.md
================================================
# @radix-ui/react-focus-scope

## 1.1.8

- Updated dependencies: `@radix-ui/react-primitive@2.1.4`

## 1.1.7

- Replace deprecated 'ElementRef' with 'ComponentRef' (#3426)
- Updated dependencies: `@radix-ui/react-primitive@2.1.3`

## 1.1.6

- Updated dependencies: `@radix-ui/react-primitive@2.1.2`

## 1.1.5

- Updated dependencies: `@radix-ui/react-primitive@2.1.1`

## 1.1.4

- Updated dependencies: `@radix-ui/react-primitive@2.1.0`



================================================
FILE: packages/react/focus-scope/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/focus-scope/package.json
================================================
{
  "name": "@radix-ui/react-focus-scope",
  "version": "1.1.8",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/react-compose-refs": "workspace:*",
    "@radix-ui/react-primitive": "workspace:*",
    "@radix-ui/react-use-callback-ref": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/focus-scope/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/focus-scope/src/focus-scope.test.tsx
================================================
import * as React from 'react';
import userEvent from '@testing-library/user-event';
import { cleanup, render, waitFor } from '@testing-library/react';
import { FocusScope } from './focus-scope';
import type { RenderResult } from '@testing-library/react';
import { afterEach, describe, it, beforeEach, vi, expect } from 'vitest';

const INNER_NAME_INPUT_LABEL = 'Name';
const INNER_EMAIL_INPUT_LABEL = 'Email';
const INNER_SUBMIT_LABEL = 'Submit';

describe('FocusScope', () => {
  afterEach(cleanup);

  describe('given a default FocusScope', () => {
    let rendered: RenderResult;
    let tabbableFirst: HTMLInputElement;
    let tabbableSecond: HTMLInputElement;
    let tabbableLast: HTMLButtonElement;

    beforeEach(() => {
      rendered = render(
        <div>
          <FocusScope asChild loop trapped>
            <form>
              <TestField label={INNER_NAME_INPUT_LABEL} />
              <TestField label={INNER_EMAIL_INPUT_LABEL} />
              <button>{INNER_SUBMIT_LABEL}</button>
            </form>
          </FocusScope>
          <TestField label="other" />
          <button>some outer button</button>
        </div>,
      );
      tabbableFirst = rendered.getByLabelText(INNER_NAME_INPUT_LABEL) as HTMLInputElement;
      tabbableSecond = rendered.getByLabelText(INNER_EMAIL_INPUT_LABEL) as HTMLInputElement;
      tabbableLast = rendered.getByText(INNER_SUBMIT_LABEL) as HTMLButtonElement;
    });

    it('should focus the next element in the scope on tab', () => {
      tabbableFirst.focus();
      userEvent.tab();
      waitFor(() => expect(tabbableSecond).toHaveFocus());
    });

    it('should focus the last element in the scope on shift+tab from the first element in scope', () => {
      tabbableFirst.focus();
      userEvent.tab({ shift: true });
      waitFor(() => expect(tabbableLast).toHaveFocus());
    });

    it('should focus the first element in scope on tab from the last element in scope', async () => {
      tabbableLast.focus();
      userEvent.tab();
      waitFor(() => expect(tabbableFirst).toHaveFocus());
    });
  });

  describe('given a FocusScope where the first focusable has a negative tabindex', () => {
    let rendered: RenderResult;
    let tabbableSecond: HTMLInputElement;
    let tabbableLast: HTMLButtonElement;

    beforeEach(() => {
      rendered = render(
        <div>
          <FocusScope asChild loop trapped>
            <form>
              <TestField label={INNER_NAME_INPUT_LABEL} tabIndex={-1} />
              <TestField label={INNER_EMAIL_INPUT_LABEL} />
              <button>{INNER_SUBMIT_LABEL}</button>
            </form>
          </FocusScope>
          <TestField label="other" />
          <button>some outer button</button>
        </div>,
      );
      tabbableSecond = rendered.getByLabelText(INNER_EMAIL_INPUT_LABEL) as HTMLInputElement;
      tabbableLast = rendered.getByText(INNER_SUBMIT_LABEL) as HTMLButtonElement;
    });

    it('should skip the element with a negative tabindex on tab', () => {
      tabbableLast.focus();
      userEvent.tab();
      waitFor(() => expect(tabbableSecond).toHaveFocus());
    });

    it('should skip the element with a negative tabindex on shift+tab', () => {
      tabbableSecond.focus();
      userEvent.tab({ shift: true });
      waitFor(() => expect(tabbableLast).toHaveFocus());
    });
  });

  describe('given a FocusScope with internal focus handlers', () => {
    const handleLastFocusableElementBlur = vi.fn();
    let rendered: RenderResult;
    let tabbableFirst: HTMLInputElement;
    beforeEach(() => {
      rendered = render(
        <div>
          <FocusScope asChild loop trapped>
            <form>
              <TestField label={INNER_NAME_INPUT_LABEL} />
              <button onBlur={handleLastFocusableElementBlur}>{INNER_SUBMIT_LABEL}</button>
            </form>
          </FocusScope>
        </div>,
      );
      tabbableFirst = rendered.getByLabelText(INNER_NAME_INPUT_LABEL) as HTMLInputElement;
    });

    it('should properly blur the last element in the scope before cycling back', async () => {
      // Tab back and then tab forward to cycle through the scope
      tabbableFirst.focus();
      userEvent.tab({ shift: true });
      userEvent.tab();
      waitFor(() => expect(handleLastFocusableElementBlur).toHaveBeenCalledTimes(1));
    });
  });
});

function TestField({ label, ...props }: { label: string } & React.ComponentProps<'input'>) {
  return (
    <label>
      <span>{label}</span>
      <input type="text" name={label.toLowerCase()} {...props} />
    </label>
  );
}



================================================
FILE: packages/react/focus-scope/src/focus-scope.tsx
================================================
import * as React from 'react';
import { useComposedRefs } from '@radix-ui/react-compose-refs';
import { Primitive } from '@radix-ui/react-primitive';
import { useCallbackRef } from '@radix-ui/react-use-callback-ref';

const AUTOFOCUS_ON_MOUNT = 'focusScope.autoFocusOnMount';
const AUTOFOCUS_ON_UNMOUNT = 'focusScope.autoFocusOnUnmount';
const EVENT_OPTIONS = { bubbles: false, cancelable: true };

type FocusableTarget = HTMLElement | { focus(): void };

/* -------------------------------------------------------------------------------------------------
 * FocusScope
 * -----------------------------------------------------------------------------------------------*/

const FOCUS_SCOPE_NAME = 'FocusScope';

type FocusScopeElement = React.ComponentRef<typeof Primitive.div>;
type PrimitiveDivProps = React.ComponentPropsWithoutRef<typeof Primitive.div>;
interface FocusScopeProps extends PrimitiveDivProps {
  /**
   * When `true`, tabbing from last item will focus first tabbable
   * and shift+tab from first item will focus last tababble.
   * @defaultValue false
   */
  loop?: boolean;

  /**
   * When `true`, focus cannot escape the focus scope via keyboard,
   * pointer, or a programmatic focus.
   * @defaultValue false
   */
  trapped?: boolean;

  /**
   * Event handler called when auto-focusing on mount.
   * Can be prevented.
   */
  onMountAutoFocus?: (event: Event) => void;

  /**
   * Event handler called when auto-focusing on unmount.
   * Can be prevented.
   */
  onUnmountAutoFocus?: (event: Event) => void;
}

const FocusScope = React.forwardRef<FocusScopeElement, FocusScopeProps>((props, forwardedRef) => {
  const {
    loop = false,
    trapped = false,
    onMountAutoFocus: onMountAutoFocusProp,
    onUnmountAutoFocus: onUnmountAutoFocusProp,
    ...scopeProps
  } = props;
  const [container, setContainer] = React.useState<HTMLElement | null>(null);
  const onMountAutoFocus = useCallbackRef(onMountAutoFocusProp);
  const onUnmountAutoFocus = useCallbackRef(onUnmountAutoFocusProp);
  const lastFocusedElementRef = React.useRef<HTMLElement | null>(null);
  const composedRefs = useComposedRefs(forwardedRef, (node) => setContainer(node));

  const focusScope = React.useRef({
    paused: false,
    pause() {
      this.paused = true;
    },
    resume() {
      this.paused = false;
    },
  }).current;

  // Takes care of trapping focus if focus is moved outside programmatically for example
  React.useEffect(() => {
    if (trapped) {
      function handleFocusIn(event: FocusEvent) {
        if (focusScope.paused || !container) return;
        const target = event.target as HTMLElement | null;
        if (container.contains(target)) {
          lastFocusedElementRef.current = target;
        } else {
          focus(lastFocusedElementRef.current, { select: true });
        }
      }

      function handleFocusOut(event: FocusEvent) {
        if (focusScope.paused || !container) return;
        const relatedTarget = event.relatedTarget as HTMLElement | null;

        // A `focusout` event with a `null` `relatedTarget` will happen in at least two cases:
        //
        // 1. When the user switches app/tabs/windows/the browser itself loses focus.
        // 2. In Google Chrome, when the focused element is removed from the DOM.
        //
        // We let the browser do its thing here because:
        //
        // 1. The browser already keeps a memory of what's focused for when the page gets refocused.
        // 2. In Google Chrome, if we try to focus the deleted focused element (as per below), it
        //    throws the CPU to 100%, so we avoid doing anything for this reason here too.
        if (relatedTarget === null) return;

        // If the focus has moved to an actual legitimate element (`relatedTarget !== null`)
        // that is outside the container, we move focus to the last valid focused element inside.
        if (!container.contains(relatedTarget)) {
          focus(lastFocusedElementRef.current, { select: true });
        }
      }

      // When the focused element gets removed from the DOM, browsers move focus
      // back to the document.body. In this case, we move focus to the container
      // to keep focus trapped correctly.
      function handleMutations(mutations: MutationRecord[]) {
        const focusedElement = document.activeElement as HTMLElement | null;
        if (focusedElement !== document.body) return;
        for (const mutation of mutations) {
          if (mutation.removedNodes.length > 0) focus(container);
        }
      }

      document.addEventListener('focusin', handleFocusIn);
      document.addEventListener('focusout', handleFocusOut);
      const mutationObserver = new MutationObserver(handleMutations);
      if (container) mutationObserver.observe(container, { childList: true, subtree: true });

      return () => {
        document.removeEventListener('focusin', handleFocusIn);
        document.removeEventListener('focusout', handleFocusOut);
        mutationObserver.disconnect();
      };
    }
  }, [trapped, container, focusScope.paused]);

  React.useEffect(() => {
    if (container) {
      focusScopesStack.add(focusScope);
      const previouslyFocusedElement = document.activeElement as HTMLElement | null;
      const hasFocusedCandidate = container.contains(previouslyFocusedElement);

      if (!hasFocusedCandidate) {
        const mountEvent = new CustomEvent(AUTOFOCUS_ON_MOUNT, EVENT_OPTIONS);
        container.addEventListener(AUTOFOCUS_ON_MOUNT, onMountAutoFocus);
        container.dispatchEvent(mountEvent);
        if (!mountEvent.defaultPrevented) {
          focusFirst(removeLinks(getTabbableCandidates(container)), { select: true });
          if (document.activeElement === previouslyFocusedElement) {
            focus(container);
          }
        }
      }

      return () => {
        container.removeEventListener(AUTOFOCUS_ON_MOUNT, onMountAutoFocus);

        // We hit a react bug (fixed in v17) with focusing in unmount.
        // We need to delay the focus a little to get around it for now.
        // See: https://github.com/facebook/react/issues/17894
        setTimeout(() => {
          const unmountEvent = new CustomEvent(AUTOFOCUS_ON_UNMOUNT, EVENT_OPTIONS);
          container.addEventListener(AUTOFOCUS_ON_UNMOUNT, onUnmountAutoFocus);
          container.dispatchEvent(unmountEvent);
          if (!unmountEvent.defaultPrevented) {
            focus(previouslyFocusedElement ?? document.body, { select: true });
          }
          // we need to remove the listener after we `dispatchEvent`
          container.removeEventListener(AUTOFOCUS_ON_UNMOUNT, onUnmountAutoFocus);

          focusScopesStack.remove(focusScope);
        }, 0);
      };
    }
  }, [container, onMountAutoFocus, onUnmountAutoFocus, focusScope]);

  // Takes care of looping focus (when tabbing whilst at the edges)
  const handleKeyDown = React.useCallback(
    (event: React.KeyboardEvent) => {
      if (!loop && !trapped) return;
      if (focusScope.paused) return;

      const isTabKey = event.key === 'Tab' && !event.altKey && !event.ctrlKey && !event.metaKey;
      const focusedElement = document.activeElement as HTMLElement | null;

      if (isTabKey && focusedElement) {
        const container = event.currentTarget as HTMLElement;
        const [first, last] = getTabbableEdges(container);
        const hasTabbableElementsInside = first && last;

        // we can only wrap focus if we have tabbable edges
        if (!hasTabbableElementsInside) {
          if (focusedElement === container) event.preventDefault();
        } else {
          if (!event.shiftKey && focusedElement === last) {
            event.preventDefault();
            if (loop) focus(first, { select: true });
          } else if (event.shiftKey && focusedElement === first) {
            event.preventDefault();
            if (loop) focus(last, { select: true });
          }
        }
      }
    },
    [loop, trapped, focusScope.paused],
  );

  return (
    <Primitive.div tabIndex={-1} {...scopeProps} ref={composedRefs} onKeyDown={handleKeyDown} />
  );
});

FocusScope.displayName = FOCUS_SCOPE_NAME;

/* -------------------------------------------------------------------------------------------------
 * Utils
 * -----------------------------------------------------------------------------------------------*/

/**
 * Attempts focusing the first element in a list of candidates.
 * Stops when focus has actually moved.
 */
function focusFirst(candidates: HTMLElement[], { select = false } = {}) {
  const previouslyFocusedElement = document.activeElement;
  for (const candidate of candidates) {
    focus(candidate, { select });
    if (document.activeElement !== previouslyFocusedElement) return;
  }
}

/**
 * Returns the first and last tabbable elements inside a container.
 */
function getTabbableEdges(container: HTMLElement) {
  const candidates = getTabbableCandidates(container);
  const first = findVisible(candidates, container);
  const last = findVisible(candidates.reverse(), container);
  return [first, last] as const;
}

/**
 * Returns a list of potential tabbable candidates.
 *
 * NOTE: This is only a close approximation. For example it doesn't take into account cases like when
 * elements are not visible. This cannot be worked out easily by just reading a property, but rather
 * necessitate runtime knowledge (computed styles, etc). We deal with these cases separately.
 *
 * See: https://developer.mozilla.org/en-US/docs/Web/API/TreeWalker
 * Credit: https://github.com/discord/focus-layers/blob/master/src/util/wrapFocus.tsx#L1
 */
function getTabbableCandidates(container: HTMLElement) {
  const nodes: HTMLElement[] = [];
  const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, {
    acceptNode: (node: any) => {
      const isHiddenInput = node.tagName === 'INPUT' && node.type === 'hidden';
      if (node.disabled || node.hidden || isHiddenInput) return NodeFilter.FILTER_SKIP;
      // `.tabIndex` is not the same as the `tabindex` attribute. It works on the
      // runtime's understanding of tabbability, so this automatically accounts
      // for any kind of element that could be tabbed to.
      return node.tabIndex >= 0 ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
    },
  });
  while (walker.nextNode()) nodes.push(walker.currentNode as HTMLElement);
  // we do not take into account the order of nodes with positive `tabIndex` as it
  // hinders accessibility to have tab order different from visual order.
  return nodes;
}

/**
 * Returns the first visible element in a list.
 * NOTE: Only checks visibility up to the `container`.
 */
function findVisible(elements: HTMLElement[], container: HTMLElement) {
  for (const element of elements) {
    // we stop checking if it's hidden at the `container` level (excluding)
    if (!isHidden(element, { upTo: container })) return element;
  }
}

function isHidden(node: HTMLElement, { upTo }: { upTo?: HTMLElement }) {
  if (getComputedStyle(node).visibility === 'hidden') return true;
  while (node) {
    // we stop at `upTo` (excluding it)
    if (upTo !== undefined && node === upTo) return false;
    if (getComputedStyle(node).display === 'none') return true;
    node = node.parentElement as HTMLElement;
  }
  return false;
}

function isSelectableInput(element: any): element is FocusableTarget & { select: () => void } {
  return element instanceof HTMLInputElement && 'select' in element;
}

function focus(element?: FocusableTarget | null, { select = false } = {}) {
  // only focus if that element is focusable
  if (element && element.focus) {
    const previouslyFocusedElement = document.activeElement;
    // NOTE: we prevent scrolling on focus, to minimize jarring transitions for users
    element.focus({ preventScroll: true });
    // only select if its not the same element, it supports selection and we need to select
    if (element !== previouslyFocusedElement && isSelectableInput(element) && select)
      element.select();
  }
}

/* -------------------------------------------------------------------------------------------------
 * FocusScope stack
 * -----------------------------------------------------------------------------------------------*/

type FocusScopeAPI = { paused: boolean; pause(): void; resume(): void };
const focusScopesStack = createFocusScopesStack();

function createFocusScopesStack() {
  /** A stack of focus scopes, with the active one at the top */
  let stack: FocusScopeAPI[] = [];

  return {
    add(focusScope: FocusScopeAPI) {
      // pause the currently active focus scope (at the top of the stack)
      const activeFocusScope = stack[0];
      if (focusScope !== activeFocusScope) {
        activeFocusScope?.pause();
      }
      // remove in case it already exists (because we'll re-add it at the top of the stack)
      stack = arrayRemove(stack, focusScope);
      stack.unshift(focusScope);
    },

    remove(focusScope: FocusScopeAPI) {
      stack = arrayRemove(stack, focusScope);
      stack[0]?.resume();
    },
  };
}

function arrayRemove<T>(array: T[], item: T) {
  const updatedArray = [...array];
  const index = updatedArray.indexOf(item);
  if (index !== -1) {
    updatedArray.splice(index, 1);
  }
  return updatedArray;
}

function removeLinks(items: HTMLElement[]) {
  return items.filter((item) => item.tagName !== 'A');
}

const Root = FocusScope;

export {
  FocusScope,
  //
  Root,
};
export type { FocusScopeProps };



================================================
FILE: packages/react/focus-scope/src/index.ts
================================================
'use client';
export {
  FocusScope,
  //
  Root,
} from './focus-scope';
export type { FocusScopeProps } from './focus-scope';



================================================
FILE: packages/react/form/README.md
================================================
# `react-form`

View docs [here](https://radix-ui.com/primitives/docs/components/form).



================================================
FILE: packages/react/form/CHANGELOG.md
================================================
# @radix-ui/react-form

## 0.1.8

- Updated dependencies: `@radix-ui/primitive@1.1.3`, `@radix-ui/react-context@1.1.3`, `@radix-ui/react-primitive@2.1.4`, `@radix-ui/react-label@2.1.8`

## 0.1.7

- Replace deprecated 'ElementRef' with 'ComponentRef' (#3426)
- Updated dependencies: `@radix-ui/react-label@2.1.7`, `@radix-ui/react-primitive@2.1.3`

## 0.1.6

- Updated dependencies: `@radix-ui/react-primitive@2.1.2`, `@radix-ui/react-label@2.1.6`

## 0.1.5

- Updated dependencies: `@radix-ui/react-primitive@2.1.1`, `@radix-ui/react-label@2.1.5`

## 0.1.4

- Updated dependencies: `@radix-ui/react-primitive@2.1.0`, `@radix-ui/react-label@2.1.4`



================================================
FILE: packages/react/form/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/form/package.json
================================================
{
  "name": "@radix-ui/react-form",
  "version": "0.1.8",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/primitive": "workspace:*",
    "@radix-ui/react-compose-refs": "workspace:*",
    "@radix-ui/react-context": "workspace:*",
    "@radix-ui/react-id": "workspace:*",
    "@radix-ui/react-label": "workspace:*",
    "@radix-ui/react-primitive": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/form/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/form/src/form.tsx
================================================
import * as React from 'react';
import { composeEventHandlers } from '@radix-ui/primitive';
import { useComposedRefs } from '@radix-ui/react-compose-refs';
import { createContextScope } from '@radix-ui/react-context';
import { useId } from '@radix-ui/react-id';
import { Label as LabelPrimitive } from '@radix-ui/react-label';
import { Primitive } from '@radix-ui/react-primitive';

import type { Scope } from '@radix-ui/react-context';

type ScopedProps<P> = P & { __scopeForm?: Scope };
const [createFormContext, createFormScope] = createContextScope('Form');

/* -------------------------------------------------------------------------------------------------
 * Form
 * -----------------------------------------------------------------------------------------------*/

const FORM_NAME = 'Form';

type ValidityMap = { [fieldName: string]: ValidityState | undefined };
type CustomMatcherEntriesMap = { [fieldName: string]: CustomMatcherEntry[] };
type CustomErrorsMap = { [fieldName: string]: Record<string, boolean> };

type ValidationContextValue = {
  getFieldValidity(fieldName: string): ValidityState | undefined;
  onFieldValidityChange(fieldName: string, validity: ValidityState): void;

  getFieldCustomMatcherEntries(fieldName: string): CustomMatcherEntry[];
  onFieldCustomMatcherEntryAdd(fieldName: string, matcherEntry: CustomMatcherEntry): void;
  onFieldCustomMatcherEntryRemove(fieldName: string, matcherEntryId: string): void;

  getFieldCustomErrors(fieldName: string): Record<string, boolean>;
  onFieldCustomErrorsChange(fieldName: string, errors: Record<string, boolean>): void;

  onFieldValiditionClear(fieldName: string): void;
};
const [ValidationProvider, useValidationContext] =
  createFormContext<ValidationContextValue>(FORM_NAME);

type MessageIdsMap = { [fieldName: string]: Set<string> };

type AriaDescriptionContextValue = {
  onFieldMessageIdAdd(fieldName: string, id: string): void;
  onFieldMessageIdRemove(fieldName: string, id: string): void;
  getFieldDescription(fieldName: string): string | undefined;
};
const [AriaDescriptionProvider, useAriaDescriptionContext] =
  createFormContext<AriaDescriptionContextValue>(FORM_NAME);

type FormElement = React.ComponentRef<typeof Primitive.form>;
type PrimitiveFormProps = React.ComponentPropsWithoutRef<typeof Primitive.form>;
interface FormProps extends PrimitiveFormProps {
  onClearServerErrors?(): void;
}

const Form = React.forwardRef<FormElement, FormProps>(
  (props: ScopedProps<FormProps>, forwardedRef) => {
    const { __scopeForm, onClearServerErrors = () => {}, ...rootProps } = props;
    const formRef = React.useRef<HTMLFormElement>(null);
    const composedFormRef = useComposedRefs(forwardedRef, formRef);

    // native validity per field
    const [validityMap, setValidityMap] = React.useState<ValidityMap>({});
    const getFieldValidity: ValidationContextValue['getFieldValidity'] = React.useCallback(
      (fieldName) => validityMap[fieldName],
      [validityMap],
    );
    const handleFieldValidityChange: ValidationContextValue['onFieldValidityChange'] =
      React.useCallback(
        (fieldName, validity) =>
          setValidityMap((prevValidityMap) => ({
            ...prevValidityMap,
            [fieldName]: { ...(prevValidityMap[fieldName] ?? {}), ...validity },
          })),
        [],
      );
    const handleFieldValiditionClear: ValidationContextValue['onFieldValiditionClear'] =
      React.useCallback((fieldName) => {
        setValidityMap((prevValidityMap) => ({ ...prevValidityMap, [fieldName]: undefined }));
        setCustomErrorsMap((prevCustomErrorsMap) => ({ ...prevCustomErrorsMap, [fieldName]: {} }));
      }, []);

    // custom matcher entries per field
    const [customMatcherEntriesMap, setCustomMatcherEntriesMap] =
      React.useState<CustomMatcherEntriesMap>({});
    const getFieldCustomMatcherEntries: ValidationContextValue['getFieldCustomMatcherEntries'] =
      React.useCallback(
        (fieldName) => customMatcherEntriesMap[fieldName] ?? [],
        [customMatcherEntriesMap],
      );
    const handleFieldCustomMatcherAdd: ValidationContextValue['onFieldCustomMatcherEntryAdd'] =
      React.useCallback((fieldName, matcherEntry) => {
        setCustomMatcherEntriesMap((prevCustomMatcherEntriesMap) => ({
          ...prevCustomMatcherEntriesMap,
          [fieldName]: [...(prevCustomMatcherEntriesMap[fieldName] ?? []), matcherEntry],
        }));
      }, []);
    const handleFieldCustomMatcherRemove: ValidationContextValue['onFieldCustomMatcherEntryRemove'] =
      React.useCallback((fieldName, matcherEntryId) => {
        setCustomMatcherEntriesMap((prevCustomMatcherEntriesMap) => ({
          ...prevCustomMatcherEntriesMap,
          [fieldName]: (prevCustomMatcherEntriesMap[fieldName] ?? []).filter(
            (matcherEntry) => matcherEntry.id !== matcherEntryId,
          ),
        }));
      }, []);

    // custom errors per field
    const [customErrorsMap, setCustomErrorsMap] = React.useState<CustomErrorsMap>({});
    const getFieldCustomErrors: ValidationContextValue['getFieldCustomErrors'] = React.useCallback(
      (fieldName) => customErrorsMap[fieldName] ?? {},
      [customErrorsMap],
    );
    const handleFieldCustomErrorsChange: ValidationContextValue['onFieldCustomErrorsChange'] =
      React.useCallback((fieldName, customErrors) => {
        setCustomErrorsMap((prevCustomErrorsMap) => ({
          ...prevCustomErrorsMap,
          [fieldName]: { ...(prevCustomErrorsMap[fieldName] ?? {}), ...customErrors },
        }));
      }, []);

    // messageIds per field
    const [messageIdsMap, setMessageIdsMap] = React.useState<MessageIdsMap>({});
    const handleFieldMessageIdAdd: AriaDescriptionContextValue['onFieldMessageIdAdd'] =
      React.useCallback((fieldName, id) => {
        setMessageIdsMap((prevMessageIdsMap) => {
          const fieldDescriptionIds = new Set(prevMessageIdsMap[fieldName]).add(id);
          return { ...prevMessageIdsMap, [fieldName]: fieldDescriptionIds };
        });
      }, []);
    const handleFieldMessageIdRemove: AriaDescriptionContextValue['onFieldMessageIdRemove'] =
      React.useCallback((fieldName, id) => {
        setMessageIdsMap((prevMessageIdsMap) => {
          const fieldDescriptionIds = new Set(prevMessageIdsMap[fieldName]);
          fieldDescriptionIds.delete(id);
          return { ...prevMessageIdsMap, [fieldName]: fieldDescriptionIds };
        });
      }, []);
    const getFieldDescription: AriaDescriptionContextValue['getFieldDescription'] =
      React.useCallback(
        (fieldName) => Array.from(messageIdsMap[fieldName] ?? []).join(' ') || undefined,
        [messageIdsMap],
      );

    return (
      <ValidationProvider
        scope={__scopeForm}
        getFieldValidity={getFieldValidity}
        onFieldValidityChange={handleFieldValidityChange}
        getFieldCustomMatcherEntries={getFieldCustomMatcherEntries}
        onFieldCustomMatcherEntryAdd={handleFieldCustomMatcherAdd}
        onFieldCustomMatcherEntryRemove={handleFieldCustomMatcherRemove}
        getFieldCustomErrors={getFieldCustomErrors}
        onFieldCustomErrorsChange={handleFieldCustomErrorsChange}
        onFieldValiditionClear={handleFieldValiditionClear}
      >
        <AriaDescriptionProvider
          scope={__scopeForm}
          onFieldMessageIdAdd={handleFieldMessageIdAdd}
          onFieldMessageIdRemove={handleFieldMessageIdRemove}
          getFieldDescription={getFieldDescription}
        >
          <Primitive.form
            {...rootProps}
            ref={composedFormRef}
            // focus first invalid control when the form is submitted
            onInvalid={composeEventHandlers(props.onInvalid, (event) => {
              const firstInvalidControl = getFirstInvalidControl(event.currentTarget);
              if (firstInvalidControl === event.target) firstInvalidControl.focus();

              // prevent default browser UI for form validation
              event.preventDefault();
            })}
            // clear server errors when the form is re-submitted
            onSubmit={composeEventHandlers(props.onSubmit, onClearServerErrors, {
              checkForDefaultPrevented: false,
            })}
            // clear server errors when the form is reset
            onReset={composeEventHandlers(props.onReset, onClearServerErrors)}
          />
        </AriaDescriptionProvider>
      </ValidationProvider>
    );
  },
);

Form.displayName = FORM_NAME;

/* -------------------------------------------------------------------------------------------------
 * FormField
 * -----------------------------------------------------------------------------------------------*/

const FIELD_NAME = 'FormField';

type FormFieldContextValue = {
  id: string;
  name: string;
  serverInvalid: boolean;
};
const [FormFieldProvider, useFormFieldContext] =
  createFormContext<FormFieldContextValue>(FIELD_NAME);

type FormFieldElement = React.ComponentRef<typeof Primitive.div>;
type PrimitiveDivProps = React.ComponentPropsWithoutRef<typeof Primitive.div>;
interface FormFieldProps extends PrimitiveDivProps {
  name: string;
  serverInvalid?: boolean;
}

const FormField = React.forwardRef<FormFieldElement, FormFieldProps>(
  (props: ScopedProps<FormFieldProps>, forwardedRef) => {
    const { __scopeForm, name, serverInvalid = false, ...fieldProps } = props;
    const validationContext = useValidationContext(FIELD_NAME, __scopeForm);
    const validity = validationContext.getFieldValidity(name);
    const id = useId();

    return (
      <FormFieldProvider scope={__scopeForm} id={id} name={name} serverInvalid={serverInvalid}>
        <Primitive.div
          data-valid={getValidAttribute(validity, serverInvalid)}
          data-invalid={getInvalidAttribute(validity, serverInvalid)}
          {...fieldProps}
          ref={forwardedRef}
        />
      </FormFieldProvider>
    );
  },
);

FormField.displayName = FIELD_NAME;

/* -------------------------------------------------------------------------------------------------
 * FormLabel
 * -----------------------------------------------------------------------------------------------*/

const LABEL_NAME = 'FormLabel';

type FormLabelElement = React.ComponentRef<typeof LabelPrimitive>;
type LabelProps = React.ComponentPropsWithoutRef<typeof LabelPrimitive>;
interface FormLabelProps extends LabelProps {}

const FormLabel = React.forwardRef<FormLabelElement, FormLabelProps>(
  (props: ScopedProps<FormLabelProps>, forwardedRef) => {
    const { __scopeForm, ...labelProps } = props;
    const validationContext = useValidationContext(LABEL_NAME, __scopeForm);
    const fieldContext = useFormFieldContext(LABEL_NAME, __scopeForm);
    const htmlFor = labelProps.htmlFor || fieldContext.id;
    const validity = validationContext.getFieldValidity(fieldContext.name);

    return (
      <LabelPrimitive
        data-valid={getValidAttribute(validity, fieldContext.serverInvalid)}
        data-invalid={getInvalidAttribute(validity, fieldContext.serverInvalid)}
        {...labelProps}
        ref={forwardedRef}
        htmlFor={htmlFor}
      />
    );
  },
);

FormLabel.displayName = LABEL_NAME;

/* -------------------------------------------------------------------------------------------------
 * FormControl
 * -----------------------------------------------------------------------------------------------*/

const CONTROL_NAME = 'FormControl';

type FormControlElement = React.ComponentRef<typeof Primitive.input>;
type PrimitiveInputProps = React.ComponentPropsWithoutRef<typeof Primitive.input>;
interface FormControlProps extends PrimitiveInputProps {}

const FormControl = React.forwardRef<FormControlElement, FormControlProps>(
  (props: ScopedProps<FormControlProps>, forwardedRef) => {
    const { __scopeForm, ...controlProps } = props;

    const validationContext = useValidationContext(CONTROL_NAME, __scopeForm);
    const fieldContext = useFormFieldContext(CONTROL_NAME, __scopeForm);
    const ariaDescriptionContext = useAriaDescriptionContext(CONTROL_NAME, __scopeForm);

    const ref = React.useRef<FormControlElement>(null);
    const composedRef = useComposedRefs(forwardedRef, ref);
    const name = controlProps.name || fieldContext.name;
    const id = controlProps.id || fieldContext.id;
    const customMatcherEntries = validationContext.getFieldCustomMatcherEntries(name);

    const { onFieldValidityChange, onFieldCustomErrorsChange, onFieldValiditionClear } =
      validationContext;
    const updateControlValidity = React.useCallback(
      async (control: FormControlElement) => {
        //------------------------------------------------------------------------------------------
        // 1. first, if we have built-in errors we stop here

        if (hasBuiltInError(control.validity)) {
          const controlValidity = validityStateToObject(control.validity);
          onFieldValidityChange(name, controlValidity);
          return;
        }

        //------------------------------------------------------------------------------------------
        // 2. then gather the form data to give to custom matchers for cross-comparisons

        const formData = control.form ? new FormData(control.form) : new FormData();
        const matcherArgs: CustomMatcherArgs = [control.value, formData];

        //------------------------------------------------------------------------------------------
        // 3. split sync and async custom matcher entries

        const syncCustomMatcherEntries: Array<SyncCustomMatcherEntry> = [];
        const ayncCustomMatcherEntries: Array<AsyncCustomMatcherEntry> = [];
        customMatcherEntries.forEach((customMatcherEntry) => {
          if (isAsyncCustomMatcherEntry(customMatcherEntry, matcherArgs)) {
            ayncCustomMatcherEntries.push(customMatcherEntry);
          } else if (isSyncCustomMatcherEntry(customMatcherEntry)) {
            syncCustomMatcherEntries.push(customMatcherEntry);
          }
        });

        //------------------------------------------------------------------------------------------
        // 4. run sync custom matchers and update control validity / internal validity + errors

        const syncCustomErrors = syncCustomMatcherEntries.map(({ id, match }) => {
          return [id, match(...matcherArgs)] as const;
        });
        const syncCustomErrorsById = Object.fromEntries(syncCustomErrors);
        const hasSyncCustomErrors = Object.values(syncCustomErrorsById).some(Boolean);
        const hasCustomError = hasSyncCustomErrors;
        control.setCustomValidity(hasCustomError ? DEFAULT_INVALID_MESSAGE : '');
        const controlValidity = validityStateToObject(control.validity);
        onFieldValidityChange(name, controlValidity);
        onFieldCustomErrorsChange(name, syncCustomErrorsById);

        //------------------------------------------------------------------------------------------
        // 5. run async custom matchers and update control validity / internal validity + errors

        if (!hasSyncCustomErrors && ayncCustomMatcherEntries.length > 0) {
          const promisedCustomErrors = ayncCustomMatcherEntries.map(({ id, match }) =>
            match(...matcherArgs).then((matches) => [id, matches] as const),
          );
          const asyncCustomErrors = await Promise.all(promisedCustomErrors);
          const asyncCustomErrorsById = Object.fromEntries(asyncCustomErrors);
          const hasAsyncCustomErrors = Object.values(asyncCustomErrorsById).some(Boolean);
          const hasCustomError = hasAsyncCustomErrors;
          control.setCustomValidity(hasCustomError ? DEFAULT_INVALID_MESSAGE : '');
          const controlValidity = validityStateToObject(control.validity);
          onFieldValidityChange(name, controlValidity);
          onFieldCustomErrorsChange(name, asyncCustomErrorsById);
        }
      },
      [customMatcherEntries, name, onFieldCustomErrorsChange, onFieldValidityChange],
    );

    React.useEffect(() => {
      const control = ref.current;
      if (control) {
        // We only want validate on change (native `change` event, not React's `onChange`). This is primarily
        // a UX decision, we don't want to validate on every keystroke and React's `onChange` is the `input` event.
        const handleChange = () => updateControlValidity(control);
        control.addEventListener('change', handleChange);
        return () => control.removeEventListener('change', handleChange);
      }
    }, [updateControlValidity]);

    const resetControlValidity = React.useCallback(() => {
      const control = ref.current;
      if (control) {
        control.setCustomValidity('');
        onFieldValiditionClear(name);
      }
    }, [name, onFieldValiditionClear]);

    // reset validity and errors when the form is reset
    React.useEffect(() => {
      const form = ref.current?.form;
      if (form) {
        form.addEventListener('reset', resetControlValidity);
        return () => form.removeEventListener('reset', resetControlValidity);
      }
    }, [resetControlValidity]);

    // focus first invalid control when fields are set as invalid by server
    React.useEffect(() => {
      const control = ref.current;
      const form = control?.closest('form');
      if (form && fieldContext.serverInvalid) {
        const firstInvalidControl = getFirstInvalidControl(form);
        if (firstInvalidControl === control) firstInvalidControl.focus();
      }
    }, [fieldContext.serverInvalid]);

    const validity = validationContext.getFieldValidity(name);

    return (
      <Primitive.input
        data-valid={getValidAttribute(validity, fieldContext.serverInvalid)}
        data-invalid={getInvalidAttribute(validity, fieldContext.serverInvalid)}
        aria-invalid={fieldContext.serverInvalid ? true : undefined}
        aria-describedby={ariaDescriptionContext.getFieldDescription(name)}
        // disable default browser behaviour of showing built-in error message on hover
        title=""
        {...controlProps}
        ref={composedRef}
        id={id}
        name={name}
        onInvalid={composeEventHandlers(props.onInvalid, (event) => {
          const control = event.currentTarget;
          updateControlValidity(control);
        })}
        onChange={composeEventHandlers(props.onChange, (_event) => {
          // reset validity when user changes value
          resetControlValidity();
        })}
      />
    );
  },
);

FormControl.displayName = CONTROL_NAME;

/* -------------------------------------------------------------------------------------------------
 * FormMessage
 * -----------------------------------------------------------------------------------------------*/

const _validityMatchers = [
  'badInput',
  'patternMismatch',
  'rangeOverflow',
  'rangeUnderflow',
  'stepMismatch',
  'tooLong',
  'tooShort',
  'typeMismatch',
  'valid',
  'valueMissing',
] as const;
type ValidityMatcher = (typeof _validityMatchers)[number];

const DEFAULT_INVALID_MESSAGE = 'This value is not valid';
const DEFAULT_BUILT_IN_MESSAGES: Record<ValidityMatcher, string | undefined> = {
  badInput: DEFAULT_INVALID_MESSAGE,
  patternMismatch: 'This value does not match the required pattern',
  rangeOverflow: 'This value is too large',
  rangeUnderflow: 'This value is too small',
  stepMismatch: 'This value does not match the required step',
  tooLong: 'This value is too long',
  tooShort: 'This value is too short',
  typeMismatch: 'This value does not match the required type',
  valid: undefined,
  valueMissing: 'This value is missing',
};

const MESSAGE_NAME = 'FormMessage';

type FormMessageElement = FormMessageImplElement;
interface FormMessageProps extends Omit<FormMessageImplProps, 'name'> {
  match?: ValidityMatcher | CustomMatcher;
  forceMatch?: boolean;
  name?: string;
}

const FormMessage = React.forwardRef<FormMessageElement, FormMessageProps>(
  (props: ScopedProps<FormMessageProps>, forwardedRef) => {
    const { match, name: nameProp, ...messageProps } = props;
    const fieldContext = useFormFieldContext(MESSAGE_NAME, props.__scopeForm);
    const name = nameProp ?? fieldContext.name;

    if (match === undefined) {
      return (
        <FormMessageImpl {...messageProps} ref={forwardedRef} name={name}>
          {props.children || DEFAULT_INVALID_MESSAGE}
        </FormMessageImpl>
      );
    } else if (typeof match === 'function') {
      return <FormCustomMessage match={match} {...messageProps} ref={forwardedRef} name={name} />;
    } else {
      return <FormBuiltInMessage match={match} {...messageProps} ref={forwardedRef} name={name} />;
    }
  },
);

FormMessage.displayName = MESSAGE_NAME;

type FormBuiltInMessageElement = FormMessageImplElement;
interface FormBuiltInMessageProps extends FormMessageImplProps {
  match: ValidityMatcher;
  forceMatch?: boolean;
  name: string;
}

const FormBuiltInMessage = React.forwardRef<FormBuiltInMessageElement, FormBuiltInMessageProps>(
  (props: ScopedProps<FormBuiltInMessageProps>, forwardedRef) => {
    const { match, forceMatch = false, name, children, ...messageProps } = props;
    const validationContext = useValidationContext(MESSAGE_NAME, messageProps.__scopeForm);
    const validity = validationContext.getFieldValidity(name);
    const matches = forceMatch || validity?.[match];

    if (matches) {
      return (
        <FormMessageImpl ref={forwardedRef} {...messageProps} name={name}>
          {children ?? DEFAULT_BUILT_IN_MESSAGES[match]}
        </FormMessageImpl>
      );
    }

    return null;
  },
);

type FormCustomMessageElement = React.ComponentRef<typeof FormMessageImpl>;
interface FormCustomMessageProps extends React.ComponentPropsWithoutRef<typeof FormMessageImpl> {
  match: CustomMatcher;
  forceMatch?: boolean;
  name: string;
}

const FormCustomMessage = React.forwardRef<FormCustomMessageElement, FormCustomMessageProps>(
  (props: ScopedProps<FormCustomMessageProps>, forwardedRef) => {
    const { match, forceMatch = false, name, id: idProp, children, ...messageProps } = props;
    const validationContext = useValidationContext(MESSAGE_NAME, messageProps.__scopeForm);
    const ref = React.useRef<FormCustomMessageElement>(null);
    const composedRef = useComposedRefs(forwardedRef, ref);
    const _id = useId();
    const id = idProp ?? _id;

    const customMatcherEntry = React.useMemo(() => ({ id, match }), [id, match]);
    const { onFieldCustomMatcherEntryAdd, onFieldCustomMatcherEntryRemove } = validationContext;
    React.useEffect(() => {
      onFieldCustomMatcherEntryAdd(name, customMatcherEntry);
      return () => onFieldCustomMatcherEntryRemove(name, customMatcherEntry.id);
    }, [customMatcherEntry, name, onFieldCustomMatcherEntryAdd, onFieldCustomMatcherEntryRemove]);

    const validity = validationContext.getFieldValidity(name);
    const customErrors = validationContext.getFieldCustomErrors(name);
    const hasMatchingCustomError = customErrors[id];
    const matches =
      forceMatch || (validity && !hasBuiltInError(validity) && hasMatchingCustomError);

    if (matches) {
      return (
        <FormMessageImpl id={id} ref={composedRef} {...messageProps} name={name}>
          {children ?? DEFAULT_INVALID_MESSAGE}
        </FormMessageImpl>
      );
    }

    return null;
  },
);

type FormMessageImplElement = React.ComponentRef<typeof Primitive.span>;
type PrimitiveSpanProps = React.ComponentPropsWithoutRef<typeof Primitive.span>;
interface FormMessageImplProps extends PrimitiveSpanProps {
  name: string;
}

const FormMessageImpl = React.forwardRef<FormMessageImplElement, FormMessageImplProps>(
  (props: ScopedProps<FormMessageImplProps>, forwardedRef) => {
    const { __scopeForm, id: idProp, name, ...messageProps } = props;
    const ariaDescriptionContext = useAriaDescriptionContext(MESSAGE_NAME, __scopeForm);
    const _id = useId();
    const id = idProp ?? _id;

    const { onFieldMessageIdAdd, onFieldMessageIdRemove } = ariaDescriptionContext;
    React.useEffect(() => {
      onFieldMessageIdAdd(name, id);
      return () => onFieldMessageIdRemove(name, id);
    }, [name, id, onFieldMessageIdAdd, onFieldMessageIdRemove]);

    return <Primitive.span id={id} {...messageProps} ref={forwardedRef} />;
  },
);

/* -------------------------------------------------------------------------------------------------
 * FormValidityState
 * -----------------------------------------------------------------------------------------------*/

const VALIDITY_STATE_NAME = 'FormValidityState';

interface FormValidityStateProps {
  children(validity: ValidityState | undefined): React.ReactNode;
  name?: string;
}

const FormValidityState = (props: ScopedProps<FormValidityStateProps>) => {
  const { __scopeForm, name: nameProp, children } = props;
  const validationContext = useValidationContext(VALIDITY_STATE_NAME, __scopeForm);
  const fieldContext = useFormFieldContext(VALIDITY_STATE_NAME, __scopeForm);
  const name = nameProp ?? fieldContext.name;
  const validity = validationContext.getFieldValidity(name);
  return <>{children(validity)}</>;
};

FormValidityState.displayName = VALIDITY_STATE_NAME;

/* -------------------------------------------------------------------------------------------------
 * FormSubmit
 * -----------------------------------------------------------------------------------------------*/

const SUBMIT_NAME = 'FormSubmit';

type FormSubmitElement = React.ComponentRef<typeof Primitive.button>;
type PrimitiveButtonProps = React.ComponentPropsWithoutRef<typeof Primitive.button>;
interface FormSubmitProps extends PrimitiveButtonProps {}

const FormSubmit = React.forwardRef<FormSubmitElement, FormSubmitProps>(
  (props: ScopedProps<FormSubmitProps>, forwardedRef) => {
    const { __scopeForm, ...submitProps } = props;
    return <Primitive.button type="submit" {...submitProps} ref={forwardedRef} />;
  },
);

FormSubmit.displayName = SUBMIT_NAME;

/* -----------------------------------------------------------------------------------------------*/

type ValidityStateKey = keyof ValidityState;
type SyncCustomMatcher = (value: string, formData: FormData) => boolean;
type AsyncCustomMatcher = (value: string, formData: FormData) => Promise<boolean>;
type CustomMatcher = SyncCustomMatcher | AsyncCustomMatcher;
type CustomMatcherEntry = { id: string; match: CustomMatcher };
type SyncCustomMatcherEntry = { id: string; match: SyncCustomMatcher };
type AsyncCustomMatcherEntry = { id: string; match: AsyncCustomMatcher };
type CustomMatcherArgs = [string, FormData];

function validityStateToObject(validity: ValidityState) {
  const object: any = {};
  for (const key in validity) {
    object[key] = validity[key as ValidityStateKey];
  }
  return object as Record<ValidityStateKey, boolean>;
}

function isHTMLElement(element: any): element is HTMLElement {
  return element instanceof HTMLElement;
}

function isFormControl(element: any): element is { validity: ValidityState } {
  return 'validity' in element;
}

function isInvalid(control: HTMLElement) {
  return (
    isFormControl(control) &&
    (control.validity.valid === false || control.getAttribute('aria-invalid') === 'true')
  );
}

function getFirstInvalidControl(form: HTMLFormElement): HTMLElement | undefined {
  const elements = form.elements;
  const [firstInvalidControl] = Array.from(elements).filter(isHTMLElement).filter(isInvalid);
  return firstInvalidControl;
}

function isAsyncCustomMatcherEntry(
  entry: CustomMatcherEntry,
  args: CustomMatcherArgs,
): entry is AsyncCustomMatcherEntry {
  return entry.match.constructor.name === 'AsyncFunction' || returnsPromise(entry.match, args);
}

function isSyncCustomMatcherEntry(entry: CustomMatcherEntry): entry is SyncCustomMatcherEntry {
  return entry.match.constructor.name === 'Function';
}

function returnsPromise(func: Function, args: Array<unknown>) {
  return func(...args) instanceof Promise;
}

function hasBuiltInError(validity: ValidityState) {
  let error = false;
  for (const validityKey in validity) {
    const key = validityKey as ValidityStateKey;
    if (key !== 'valid' && key !== 'customError' && validity[key]) {
      error = true;
      break;
    }
  }
  return error;
}

function getValidAttribute(validity: ValidityState | undefined, serverInvalid: boolean) {
  if (validity?.valid === true && !serverInvalid) return true;
  return undefined;
}
function getInvalidAttribute(validity: ValidityState | undefined, serverInvalid: boolean) {
  if (validity?.valid === false || serverInvalid) return true;
  return undefined;
}

/* -----------------------------------------------------------------------------------------------*/

const Root = Form;
const Field = FormField;
const Label = FormLabel;
const Control = FormControl;
const Message = FormMessage;
const ValidityState = FormValidityState;
const Submit = FormSubmit;

export {
  createFormScope,
  //
  Form,
  FormField,
  FormLabel,
  FormControl,
  FormMessage,
  FormValidityState,
  FormSubmit,
  //
  Root,
  Field,
  Label,
  Control,
  Message,
  ValidityState,
  Submit,
};

export type {
  FormProps,
  FormFieldProps,
  FormLabelProps,
  FormControlProps,
  FormMessageProps,
  FormValidityStateProps,
  FormSubmitProps,
};



================================================
FILE: packages/react/form/src/index.ts
================================================
'use client';
export {
  createFormScope,
  //
  Form,
  FormField,
  FormLabel,
  FormControl,
  FormMessage,
  FormValidityState,
  FormSubmit,
  //
  Root,
  Field,
  Label,
  Control,
  Message,
  ValidityState,
  Submit,
} from './form';

export type {
  FormProps,
  FormFieldProps,
  FormLabelProps,
  FormControlProps,
  FormMessageProps,
  FormValidityStateProps,
  FormSubmitProps,
} from './form';



================================================
FILE: packages/react/hover-card/README.md
================================================
# `react-hover-card`

View docs [here](https://radix-ui.com/primitives/docs/components/hover-card).



================================================
FILE: packages/react/hover-card/CHANGELOG.md
================================================
# @radix-ui/react-hover-card

## 1.1.15

- Updated dependencies: `@radix-ui/react-presence@1.1.5`, `@radix-ui/react-popper@1.2.8`, `@radix-ui/primitive@1.1.3`, `@radix-ui/react-context@1.1.3`, `@radix-ui/react-primitive@2.1.4`, `@radix-ui/react-dismissable-layer@1.1.11`, `@radix-ui/react-portal@1.1.10`

## 1.1.14

- Replace deprecated 'ElementRef' with 'ComponentRef' (#3426)
- Updated dependencies: `@radix-ui/react-dismissable-layer@1.1.10`, `@radix-ui/react-popper@1.2.7`, `@radix-ui/react-portal@1.1.9`, `@radix-ui/react-primitive@2.1.3`

## 1.1.13

- Updated dependencies: `@radix-ui/react-primitive@2.1.2`, `@radix-ui/react-dismissable-layer@1.1.9`, `@radix-ui/react-popper@1.2.6`, `@radix-ui/react-portal@1.1.8`

## 1.1.12

- Updated dependencies: `@radix-ui/react-primitive@2.1.1`, `@radix-ui/react-dismissable-layer@1.1.8`, `@radix-ui/react-popper@1.2.5`, `@radix-ui/react-portal@1.1.7`

## 1.1.11

- Updated dependencies: `@radix-ui/react-presence@1.1.4`

## 1.1.10

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.2`

## 1.1.9

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.1`

## 1.1.8

- Minor improvements to `useControllableState` to enhance performance, reduce surface area for bugs, and log warnings when misused (#3455)
- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.0`, `@radix-ui/react-primitive@2.1.0`, `@radix-ui/react-dismissable-layer@1.1.7`, `@radix-ui/react-popper@1.2.4`, `@radix-ui/react-portal@1.1.6`



================================================
FILE: packages/react/hover-card/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/hover-card/package.json
================================================
{
  "name": "@radix-ui/react-hover-card",
  "version": "1.1.15",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/primitive": "workspace:*",
    "@radix-ui/react-compose-refs": "workspace:*",
    "@radix-ui/react-context": "workspace:*",
    "@radix-ui/react-dismissable-layer": "workspace:*",
    "@radix-ui/react-popper": "workspace:*",
    "@radix-ui/react-portal": "workspace:*",
    "@radix-ui/react-presence": "workspace:*",
    "@radix-ui/react-primitive": "workspace:*",
    "@radix-ui/react-use-controllable-state": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/hover-card/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/hover-card/src/hover-card.tsx
================================================
import * as React from 'react';
import { composeEventHandlers } from '@radix-ui/primitive';
import { createContextScope } from '@radix-ui/react-context';
import { useControllableState } from '@radix-ui/react-use-controllable-state';
import { useComposedRefs } from '@radix-ui/react-compose-refs';
import * as PopperPrimitive from '@radix-ui/react-popper';
import { createPopperScope } from '@radix-ui/react-popper';
import { Portal as PortalPrimitive } from '@radix-ui/react-portal';
import { Presence } from '@radix-ui/react-presence';
import { Primitive } from '@radix-ui/react-primitive';
import { DismissableLayer } from '@radix-ui/react-dismissable-layer';

import type { Scope } from '@radix-ui/react-context';

/* -------------------------------------------------------------------------------------------------
 * HoverCard
 * -----------------------------------------------------------------------------------------------*/

let originalBodyUserSelect: string;

const HOVERCARD_NAME = 'HoverCard';

type ScopedProps<P> = P & { __scopeHoverCard?: Scope };
const [createHoverCardContext, createHoverCardScope] = createContextScope(HOVERCARD_NAME, [
  createPopperScope,
]);
const usePopperScope = createPopperScope();

type HoverCardContextValue = {
  open: boolean;
  onOpenChange(open: boolean): void;
  onOpen(): void;
  onClose(): void;
  onDismiss(): void;
  hasSelectionRef: React.MutableRefObject<boolean>;
  isPointerDownOnContentRef: React.MutableRefObject<boolean>;
};

const [HoverCardProvider, useHoverCardContext] =
  createHoverCardContext<HoverCardContextValue>(HOVERCARD_NAME);

interface HoverCardProps {
  children?: React.ReactNode;
  open?: boolean;
  defaultOpen?: boolean;
  onOpenChange?: (open: boolean) => void;
  openDelay?: number;
  closeDelay?: number;
}

const HoverCard: React.FC<HoverCardProps> = (props: ScopedProps<HoverCardProps>) => {
  const {
    __scopeHoverCard,
    children,
    open: openProp,
    defaultOpen,
    onOpenChange,
    openDelay = 700,
    closeDelay = 300,
  } = props;
  const popperScope = usePopperScope(__scopeHoverCard);
  const openTimerRef = React.useRef(0);
  const closeTimerRef = React.useRef(0);
  const hasSelectionRef = React.useRef(false);
  const isPointerDownOnContentRef = React.useRef(false);

  const [open, setOpen] = useControllableState({
    prop: openProp,
    defaultProp: defaultOpen ?? false,
    onChange: onOpenChange,
    caller: HOVERCARD_NAME,
  });

  const handleOpen = React.useCallback(() => {
    clearTimeout(closeTimerRef.current);
    openTimerRef.current = window.setTimeout(() => setOpen(true), openDelay);
  }, [openDelay, setOpen]);

  const handleClose = React.useCallback(() => {
    clearTimeout(openTimerRef.current);
    if (!hasSelectionRef.current && !isPointerDownOnContentRef.current) {
      closeTimerRef.current = window.setTimeout(() => setOpen(false), closeDelay);
    }
  }, [closeDelay, setOpen]);

  const handleDismiss = React.useCallback(() => setOpen(false), [setOpen]);

  // cleanup any queued state updates on unmount
  React.useEffect(() => {
    return () => {
      clearTimeout(openTimerRef.current);
      clearTimeout(closeTimerRef.current);
    };
  }, []);

  return (
    <HoverCardProvider
      scope={__scopeHoverCard}
      open={open}
      onOpenChange={setOpen}
      onOpen={handleOpen}
      onClose={handleClose}
      onDismiss={handleDismiss}
      hasSelectionRef={hasSelectionRef}
      isPointerDownOnContentRef={isPointerDownOnContentRef}
    >
      <PopperPrimitive.Root {...popperScope}>{children}</PopperPrimitive.Root>
    </HoverCardProvider>
  );
};

HoverCard.displayName = HOVERCARD_NAME;

/* -------------------------------------------------------------------------------------------------
 * HoverCardTrigger
 * -----------------------------------------------------------------------------------------------*/

const TRIGGER_NAME = 'HoverCardTrigger';

type HoverCardTriggerElement = React.ComponentRef<typeof Primitive.a>;
type PrimitiveLinkProps = React.ComponentPropsWithoutRef<typeof Primitive.a>;
interface HoverCardTriggerProps extends PrimitiveLinkProps {}

const HoverCardTrigger = React.forwardRef<HoverCardTriggerElement, HoverCardTriggerProps>(
  (props: ScopedProps<HoverCardTriggerProps>, forwardedRef) => {
    const { __scopeHoverCard, ...triggerProps } = props;
    const context = useHoverCardContext(TRIGGER_NAME, __scopeHoverCard);
    const popperScope = usePopperScope(__scopeHoverCard);
    return (
      <PopperPrimitive.Anchor asChild {...popperScope}>
        <Primitive.a
          data-state={context.open ? 'open' : 'closed'}
          {...triggerProps}
          ref={forwardedRef}
          onPointerEnter={composeEventHandlers(props.onPointerEnter, excludeTouch(context.onOpen))}
          onPointerLeave={composeEventHandlers(props.onPointerLeave, excludeTouch(context.onClose))}
          onFocus={composeEventHandlers(props.onFocus, context.onOpen)}
          onBlur={composeEventHandlers(props.onBlur, context.onClose)}
          // prevent focus event on touch devices
          onTouchStart={composeEventHandlers(props.onTouchStart, (event) => event.preventDefault())}
        />
      </PopperPrimitive.Anchor>
    );
  },
);

HoverCardTrigger.displayName = TRIGGER_NAME;

/* -------------------------------------------------------------------------------------------------
 * HoverCardPortal
 * -----------------------------------------------------------------------------------------------*/

const PORTAL_NAME = 'HoverCardPortal';

type PortalContextValue = { forceMount?: true };
const [PortalProvider, usePortalContext] = createHoverCardContext<PortalContextValue>(PORTAL_NAME, {
  forceMount: undefined,
});

type PortalProps = React.ComponentPropsWithoutRef<typeof PortalPrimitive>;
interface HoverCardPortalProps {
  children?: React.ReactNode;
  /**
   * Specify a container element to portal the content into.
   */
  container?: PortalProps['container'];
  /**
   * Used to force mounting when more control is needed. Useful when
   * controlling animation with React animation libraries.
   */
  forceMount?: true;
}

const HoverCardPortal: React.FC<HoverCardPortalProps> = (
  props: ScopedProps<HoverCardPortalProps>,
) => {
  const { __scopeHoverCard, forceMount, children, container } = props;
  const context = useHoverCardContext(PORTAL_NAME, __scopeHoverCard);
  return (
    <PortalProvider scope={__scopeHoverCard} forceMount={forceMount}>
      <Presence present={forceMount || context.open}>
        <PortalPrimitive asChild container={container}>
          {children}
        </PortalPrimitive>
      </Presence>
    </PortalProvider>
  );
};

HoverCardPortal.displayName = PORTAL_NAME;

/* -------------------------------------------------------------------------------------------------
 * HoverCardContent
 * -----------------------------------------------------------------------------------------------*/

const CONTENT_NAME = 'HoverCardContent';

type HoverCardContentElement = HoverCardContentImplElement;
interface HoverCardContentProps extends HoverCardContentImplProps {
  /**
   * Used to force mounting when more control is needed. Useful when
   * controlling animation with React animation libraries.
   */
  forceMount?: true;
}

const HoverCardContent = React.forwardRef<HoverCardContentElement, HoverCardContentProps>(
  (props: ScopedProps<HoverCardContentProps>, forwardedRef) => {
    const portalContext = usePortalContext(CONTENT_NAME, props.__scopeHoverCard);
    const { forceMount = portalContext.forceMount, ...contentProps } = props;
    const context = useHoverCardContext(CONTENT_NAME, props.__scopeHoverCard);
    return (
      <Presence present={forceMount || context.open}>
        <HoverCardContentImpl
          data-state={context.open ? 'open' : 'closed'}
          {...contentProps}
          onPointerEnter={composeEventHandlers(props.onPointerEnter, excludeTouch(context.onOpen))}
          onPointerLeave={composeEventHandlers(props.onPointerLeave, excludeTouch(context.onClose))}
          ref={forwardedRef}
        />
      </Presence>
    );
  },
);

HoverCardContent.displayName = CONTENT_NAME;

/* ---------------------------------------------------------------------------------------------- */

type HoverCardContentImplElement = React.ComponentRef<typeof PopperPrimitive.Content>;
type DismissableLayerProps = React.ComponentPropsWithoutRef<typeof DismissableLayer>;
type PopperContentProps = React.ComponentPropsWithoutRef<typeof PopperPrimitive.Content>;
interface HoverCardContentImplProps extends Omit<PopperContentProps, 'onPlaced'> {
  /**
   * Event handler called when the escape key is down.
   * Can be prevented.
   */
  onEscapeKeyDown?: DismissableLayerProps['onEscapeKeyDown'];
  /**
   * Event handler called when the a `pointerdown` event happens outside of the `HoverCard`.
   * Can be prevented.
   */
  onPointerDownOutside?: DismissableLayerProps['onPointerDownOutside'];
  /**
   * Event handler called when the focus moves outside of the `HoverCard`.
   * Can be prevented.
   */
  onFocusOutside?: DismissableLayerProps['onFocusOutside'];
  /**
   * Event handler called when an interaction happens outside the `HoverCard`.
   * Specifically, when a `pointerdown` event happens outside or focus moves outside of it.
   * Can be prevented.
   */
  onInteractOutside?: DismissableLayerProps['onInteractOutside'];
}

const HoverCardContentImpl = React.forwardRef<
  HoverCardContentImplElement,
  HoverCardContentImplProps
>((props: ScopedProps<HoverCardContentImplProps>, forwardedRef) => {
  const {
    __scopeHoverCard,
    onEscapeKeyDown,
    onPointerDownOutside,
    onFocusOutside,
    onInteractOutside,
    ...contentProps
  } = props;
  const context = useHoverCardContext(CONTENT_NAME, __scopeHoverCard);
  const popperScope = usePopperScope(__scopeHoverCard);
  const ref = React.useRef<HoverCardContentImplElement>(null);
  const composedRefs = useComposedRefs(forwardedRef, ref);
  const [containSelection, setContainSelection] = React.useState(false);

  React.useEffect(() => {
    if (containSelection) {
      const body = document.body;

      // Safari requires prefix
      originalBodyUserSelect = body.style.userSelect || body.style.webkitUserSelect;

      body.style.userSelect = 'none';
      body.style.webkitUserSelect = 'none';
      return () => {
        body.style.userSelect = originalBodyUserSelect;
        body.style.webkitUserSelect = originalBodyUserSelect;
      };
    }
  }, [containSelection]);

  React.useEffect(() => {
    if (ref.current) {
      const handlePointerUp = () => {
        setContainSelection(false);
        context.isPointerDownOnContentRef.current = false;

        // Delay a frame to ensure we always access the latest selection
        setTimeout(() => {
          const hasSelection = document.getSelection()?.toString() !== '';
          if (hasSelection) context.hasSelectionRef.current = true;
        });
      };

      document.addEventListener('pointerup', handlePointerUp);
      return () => {
        document.removeEventListener('pointerup', handlePointerUp);
        context.hasSelectionRef.current = false;
        context.isPointerDownOnContentRef.current = false;
      };
    }
  }, [context.isPointerDownOnContentRef, context.hasSelectionRef]);

  React.useEffect(() => {
    if (ref.current) {
      const tabbables = getTabbableNodes(ref.current);
      tabbables.forEach((tabbable) => tabbable.setAttribute('tabindex', '-1'));
    }
  });

  return (
    <DismissableLayer
      asChild
      disableOutsidePointerEvents={false}
      onInteractOutside={onInteractOutside}
      onEscapeKeyDown={onEscapeKeyDown}
      onPointerDownOutside={onPointerDownOutside}
      onFocusOutside={composeEventHandlers(onFocusOutside, (event) => {
        event.preventDefault();
      })}
      onDismiss={context.onDismiss}
    >
      <PopperPrimitive.Content
        {...popperScope}
        {...contentProps}
        onPointerDown={composeEventHandlers(contentProps.onPointerDown, (event) => {
          // Contain selection to current layer
          if (event.currentTarget.contains(event.target as HTMLElement)) {
            setContainSelection(true);
          }
          context.hasSelectionRef.current = false;
          context.isPointerDownOnContentRef.current = true;
        })}
        ref={composedRefs}
        style={{
          ...contentProps.style,
          userSelect: containSelection ? 'text' : undefined,
          // Safari requires prefix
          WebkitUserSelect: containSelection ? 'text' : undefined,
          // re-namespace exposed content custom properties
          ...{
            '--radix-hover-card-content-transform-origin': 'var(--radix-popper-transform-origin)',
            '--radix-hover-card-content-available-width': 'var(--radix-popper-available-width)',
            '--radix-hover-card-content-available-height': 'var(--radix-popper-available-height)',
            '--radix-hover-card-trigger-width': 'var(--radix-popper-anchor-width)',
            '--radix-hover-card-trigger-height': 'var(--radix-popper-anchor-height)',
          },
        }}
      />
    </DismissableLayer>
  );
});

/* -------------------------------------------------------------------------------------------------
 * HoverCardArrow
 * -----------------------------------------------------------------------------------------------*/

const ARROW_NAME = 'HoverCardArrow';

type HoverCardArrowElement = React.ComponentRef<typeof PopperPrimitive.Arrow>;
type PopperArrowProps = React.ComponentPropsWithoutRef<typeof PopperPrimitive.Arrow>;
interface HoverCardArrowProps extends PopperArrowProps {}

const HoverCardArrow = React.forwardRef<HoverCardArrowElement, HoverCardArrowProps>(
  (props: ScopedProps<HoverCardArrowProps>, forwardedRef) => {
    const { __scopeHoverCard, ...arrowProps } = props;
    const popperScope = usePopperScope(__scopeHoverCard);
    return <PopperPrimitive.Arrow {...popperScope} {...arrowProps} ref={forwardedRef} />;
  },
);

HoverCardArrow.displayName = ARROW_NAME;

/* -----------------------------------------------------------------------------------------------*/

function excludeTouch<E>(eventHandler: () => void) {
  return (event: React.PointerEvent<E>) =>
    event.pointerType === 'touch' ? undefined : eventHandler();
}

/**
 * Returns a list of nodes that can be in the tab sequence.
 * @see: https://developer.mozilla.org/en-US/docs/Web/API/TreeWalker
 */
function getTabbableNodes(container: HTMLElement) {
  const nodes: HTMLElement[] = [];
  const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, {
    acceptNode: (node: any) => {
      // `.tabIndex` is not the same as the `tabindex` attribute. It works on the
      // runtime's understanding of tabbability, so this automatically accounts
      // for any kind of element that could be tabbed to.
      return node.tabIndex >= 0 ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
    },
  });
  while (walker.nextNode()) nodes.push(walker.currentNode as HTMLElement);
  return nodes;
}

const Root = HoverCard;
const Trigger = HoverCardTrigger;
const Portal = HoverCardPortal;
const Content = HoverCardContent;
const Arrow = HoverCardArrow;

export {
  createHoverCardScope,
  //
  HoverCard,
  HoverCardTrigger,
  HoverCardPortal,
  HoverCardContent,
  HoverCardArrow,
  //
  Root,
  Trigger,
  Portal,
  Content,
  Arrow,
};
export type {
  HoverCardProps,
  HoverCardTriggerProps,
  HoverCardPortalProps,
  HoverCardContentProps,
  HoverCardArrowProps,
};



================================================
FILE: packages/react/hover-card/src/index.ts
================================================
'use client';
export {
  createHoverCardScope,
  //
  HoverCard,
  HoverCardTrigger,
  HoverCardPortal,
  HoverCardContent,
  HoverCardArrow,
  //
  Root,
  Trigger,
  Portal,
  Content,
  Arrow,
} from './hover-card';
export type {
  HoverCardProps,
  HoverCardTriggerProps,
  HoverCardPortalProps,
  HoverCardContentProps,
  HoverCardArrowProps,
} from './hover-card';



================================================
FILE: packages/react/id/README.md
================================================
# `react-id`

View docs [here](https://radix-ui.com/primitives/docs/utilities/id-provider).



================================================
FILE: packages/react/id/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/id/package.json
================================================
{
  "name": "@radix-ui/react-id",
  "version": "1.1.1",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  },
  "dependencies": {
    "@radix-ui/react-use-layout-effect": "workspace:*"
  }
}



================================================
FILE: packages/react/id/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/id/src/id.tsx
================================================
import * as React from 'react';
import { useLayoutEffect } from '@radix-ui/react-use-layout-effect';

// We spaces with `.trim().toString()` to prevent bundlers from trying to `import { useId } from 'react';`
const useReactId = (React as any)[' useId '.trim().toString()] || (() => undefined);
let count = 0;

function useId(deterministicId?: string): string {
  const [id, setId] = React.useState<string | undefined>(useReactId());
  // React versions older than 18 will have client-side ids only.
  useLayoutEffect(() => {
    if (!deterministicId) setId((reactId) => reactId ?? String(count++));
  }, [deterministicId]);
  return deterministicId || (id ? `radix-${id}` : '');
}

export { useId };



================================================
FILE: packages/react/id/src/index.ts
================================================
export { useId } from './id';



================================================
FILE: packages/react/label/README.md
================================================
# `react-label`

View docs [here](https://radix-ui.com/primitives/docs/utilities/label).



================================================
FILE: packages/react/label/CHANGELOG.md
================================================
# @radix-ui/react-label

## 2.1.8

- Updated dependencies: `@radix-ui/react-primitive@2.1.4`

## 2.1.7

- Replace deprecated 'ElementRef' with 'ComponentRef' (#3426)
- Updated dependencies: `@radix-ui/react-primitive@2.1.3`

## 2.1.6

- Updated dependencies: `@radix-ui/react-primitive@2.1.2`

## 2.1.5

- Updated dependencies: `@radix-ui/react-primitive@2.1.1`

## 2.1.4

- Updated dependencies: `@radix-ui/react-primitive@2.1.0`



================================================
FILE: packages/react/label/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/label/package.json
================================================
{
  "name": "@radix-ui/react-label",
  "version": "2.1.8",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/react-primitive": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/label/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/label/src/index.ts
================================================
'use client';
export {
  Label,
  //
  Root,
} from './label';
export type { LabelProps } from './label';



================================================
FILE: packages/react/label/src/label.tsx
================================================
import * as React from 'react';
import { Primitive } from '@radix-ui/react-primitive';

/* -------------------------------------------------------------------------------------------------
 * Label
 * -----------------------------------------------------------------------------------------------*/

const NAME = 'Label';

type LabelElement = React.ComponentRef<typeof Primitive.label>;
type PrimitiveLabelProps = React.ComponentPropsWithoutRef<typeof Primitive.label>;
interface LabelProps extends PrimitiveLabelProps {}

const Label = React.forwardRef<LabelElement, LabelProps>((props, forwardedRef) => {
  return (
    <Primitive.label
      {...props}
      ref={forwardedRef}
      onMouseDown={(event) => {
        // only prevent text selection if clicking inside the label itself
        const target = event.target as HTMLElement;
        if (target.closest('button, input, select, textarea')) return;

        props.onMouseDown?.(event);
        // prevent text selection when double clicking label
        if (!event.defaultPrevented && event.detail > 1) event.preventDefault();
      }}
    />
  );
});

Label.displayName = NAME;

/* -----------------------------------------------------------------------------------------------*/

const Root = Label;

export {
  Label,
  //
  Root,
};
export type { LabelProps };



================================================
FILE: packages/react/menu/README.md
================================================
# `react-menu`

This is an internal utility, not intended for public usage.



================================================
FILE: packages/react/menu/CHANGELOG.md
================================================
# @radix-ui/react-menu

## 2.1.16

- Updated dependencies: `@radix-ui/react-presence@1.1.5`, `@radix-ui/react-slot@1.2.4`, `@radix-ui/react-popper@1.2.8`, `@radix-ui/react-focus-guards@1.1.3`, `@radix-ui/primitive@1.1.3`, `@radix-ui/react-context@1.1.3`, `@radix-ui/react-collection@1.1.8`, `@radix-ui/react-primitive@2.1.4`, `@radix-ui/react-dismissable-layer@1.1.11`, `@radix-ui/react-roving-focus@1.1.11`, `@radix-ui/react-focus-scope@1.1.8`, `@radix-ui/react-portal@1.1.10`

## 2.1.15

- Replace deprecated 'ElementRef' with 'ComponentRef' (#3426)
- Updated dependencies: `@radix-ui/react-dismissable-layer@1.1.10`, `@radix-ui/react-roving-focus@1.1.10`, `@radix-ui/react-focus-scope@1.1.7`, `@radix-ui/react-popper@1.2.7`, `@radix-ui/react-portal@1.1.9`, `@radix-ui/react-slot@1.2.3`, `@radix-ui/react-collection@1.1.7`, `@radix-ui/react-primitive@2.1.3`

## 2.1.14

- Updated dependencies: `@radix-ui/react-slot@1.2.2`, `@radix-ui/react-collection@1.1.6`, `@radix-ui/react-primitive@2.1.2`, `@radix-ui/react-roving-focus@1.1.9`, `@radix-ui/react-dismissable-layer@1.1.9`, `@radix-ui/react-focus-scope@1.1.6`, `@radix-ui/react-popper@1.2.6`, `@radix-ui/react-portal@1.1.8`

## 2.1.13

- Updated dependencies: `@radix-ui/react-slot@1.2.1`, `@radix-ui/react-collection@1.1.5`, `@radix-ui/react-primitive@2.1.1`, `@radix-ui/react-roving-focus@1.1.8`, `@radix-ui/react-dismissable-layer@1.1.8`, `@radix-ui/react-focus-scope@1.1.5`, `@radix-ui/react-popper@1.2.5`, `@radix-ui/react-portal@1.1.7`

## 2.1.12

- Updated dependencies: `@radix-ui/react-presence@1.1.4`

## 2.1.11

- Updated dependencies: `@radix-ui/react-roving-focus@1.1.7`

## 2.1.10

- Updated dependencies: `@radix-ui/react-roving-focus@1.1.6`

## 2.1.9

- Updated dependencies: `@radix-ui/react-roving-focus@1.1.5`

## 2.1.8

- Updated dependencies: `@radix-ui/react-collection@1.1.4`, `@radix-ui/react-roving-focus@1.1.4`, `@radix-ui/react-primitive@2.1.0`, `@radix-ui/react-dismissable-layer@1.1.7`, `@radix-ui/react-focus-scope@1.1.4`, `@radix-ui/react-popper@1.2.4`, `@radix-ui/react-portal@1.1.6`



================================================
FILE: packages/react/menu/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/menu/package.json
================================================
{
  "name": "@radix-ui/react-menu",
  "version": "2.1.16",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/primitive": "workspace:*",
    "@radix-ui/react-collection": "workspace:*",
    "@radix-ui/react-compose-refs": "workspace:*",
    "@radix-ui/react-context": "workspace:*",
    "@radix-ui/react-direction": "workspace:*",
    "@radix-ui/react-dismissable-layer": "workspace:*",
    "@radix-ui/react-focus-guards": "workspace:*",
    "@radix-ui/react-focus-scope": "workspace:*",
    "@radix-ui/react-id": "workspace:*",
    "@radix-ui/react-popper": "workspace:*",
    "@radix-ui/react-portal": "workspace:*",
    "@radix-ui/react-presence": "workspace:*",
    "@radix-ui/react-primitive": "workspace:*",
    "@radix-ui/react-roving-focus": "workspace:*",
    "@radix-ui/react-slot": "workspace:*",
    "@radix-ui/react-use-callback-ref": "workspace:*",
    "aria-hidden": "^1.2.4",
    "react-remove-scroll": "^2.6.3"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/test-data": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/menu/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/menu/src/index.ts
================================================
'use client';
export {
  createMenuScope,
  //
  Menu,
  MenuAnchor,
  MenuPortal,
  MenuContent,
  MenuGroup,
  MenuLabel,
  MenuItem,
  MenuCheckboxItem,
  MenuRadioGroup,
  MenuRadioItem,
  MenuItemIndicator,
  MenuSeparator,
  MenuArrow,
  MenuSub,
  MenuSubTrigger,
  MenuSubContent,
  //
  Root,
  Anchor,
  Portal,
  Content,
  Group,
  Label,
  Item,
  CheckboxItem,
  RadioGroup,
  RadioItem,
  ItemIndicator,
  Separator,
  Arrow,
  Sub,
  SubTrigger,
  SubContent,
} from './menu';
export type {
  MenuProps,
  MenuAnchorProps,
  MenuPortalProps,
  MenuContentProps,
  MenuGroupProps,
  MenuLabelProps,
  MenuItemProps,
  MenuCheckboxItemProps,
  MenuRadioGroupProps,
  MenuRadioItemProps,
  MenuItemIndicatorProps,
  MenuSeparatorProps,
  MenuArrowProps,
  MenuSubProps,
  MenuSubTriggerProps,
  MenuSubContentProps,
} from './menu';



================================================
FILE: packages/react/menubar/README.md
================================================
# `react-menubar`

View docs [here](https://radix-ui.com/primitives/docs/components/menubar).



================================================
FILE: packages/react/menubar/CHANGELOG.md
================================================
# @radix-ui/react-menubar

## 1.1.16

- Updated dependencies: `@radix-ui/primitive@1.1.3`, `@radix-ui/react-context@1.1.3`, `@radix-ui/react-menu@2.1.16`, `@radix-ui/react-collection@1.1.8`, `@radix-ui/react-primitive@2.1.4`, `@radix-ui/react-roving-focus@1.1.11`

## 1.1.15

- Replace deprecated 'ElementRef' with 'ComponentRef' (#3426)
- Updated dependencies: `@radix-ui/react-roving-focus@1.1.10`, `@radix-ui/react-menu@2.1.15`, `@radix-ui/react-collection@1.1.7`, `@radix-ui/react-primitive@2.1.3`

## 1.1.14

- Updated dependencies: `@radix-ui/react-collection@1.1.6`, `@radix-ui/react-menu@2.1.14`, `@radix-ui/react-primitive@2.1.2`, `@radix-ui/react-roving-focus@1.1.9`

## 1.1.13

- Updated dependencies: `@radix-ui/react-collection@1.1.5`, `@radix-ui/react-menu@2.1.13`, `@radix-ui/react-primitive@2.1.1`, `@radix-ui/react-roving-focus@1.1.8`

## 1.1.12

- Updated dependencies: `@radix-ui/react-menu@2.1.12`

## 1.1.11

- Updated dependencies: `@radix-ui/react-roving-focus@1.1.7`, `@radix-ui/react-menu@2.1.11`

## 1.1.10

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.2`, `@radix-ui/react-roving-focus@1.1.6`, `@radix-ui/react-menu@2.1.10`

## 1.1.9

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.1`, `@radix-ui/react-roving-focus@1.1.5`, `@radix-ui/react-menu@2.1.9`

## 1.1.8

- Minor improvements to `useControllableState` to enhance performance, reduce surface area for bugs, and log warnings when misused (#3455)
- Updated dependencies: `@radix-ui/react-collection@1.1.4`, `@radix-ui/react-use-controllable-state@1.2.0`, `@radix-ui/react-roving-focus@1.1.4`, `@radix-ui/react-primitive@2.1.0`, `@radix-ui/react-menu@2.1.8`



================================================
FILE: packages/react/menubar/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/menubar/package.json
================================================
{
  "name": "@radix-ui/react-menubar",
  "version": "1.1.16",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/primitive": "workspace:*",
    "@radix-ui/react-collection": "workspace:*",
    "@radix-ui/react-compose-refs": "workspace:*",
    "@radix-ui/react-context": "workspace:*",
    "@radix-ui/react-direction": "workspace:*",
    "@radix-ui/react-id": "workspace:*",
    "@radix-ui/react-menu": "workspace:*",
    "@radix-ui/react-primitive": "workspace:*",
    "@radix-ui/react-roving-focus": "workspace:*",
    "@radix-ui/react-use-controllable-state": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/test-data": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/menubar/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/menubar/src/index.ts
================================================
'use client';
export {
  createMenubarScope,
  //
  Menubar,
  MenubarMenu,
  MenubarTrigger,
  MenubarPortal,
  MenubarContent,
  MenubarGroup,
  MenubarLabel,
  MenubarItem,
  MenubarCheckboxItem,
  MenubarRadioGroup,
  MenubarRadioItem,
  MenubarItemIndicator,
  MenubarSeparator,
  MenubarArrow,
  MenubarSub,
  MenubarSubTrigger,
  MenubarSubContent,
  //
  Root,
  Menu,
  Trigger,
  Portal,
  Content,
  Group,
  Label,
  Item,
  CheckboxItem,
  RadioGroup,
  RadioItem,
  ItemIndicator,
  Separator,
  Arrow,
  Sub,
  SubTrigger,
  SubContent,
} from './menubar';
export type {
  MenubarProps,
  MenubarMenuProps,
  MenubarTriggerProps,
  MenubarPortalProps,
  MenubarContentProps,
  MenubarGroupProps,
  MenubarLabelProps,
  MenubarItemProps,
  MenubarCheckboxItemProps,
  MenubarRadioGroupProps,
  MenubarRadioItemProps,
  MenubarItemIndicatorProps,
  MenubarSeparatorProps,
  MenubarArrowProps,
  MenubarSubProps,
  MenubarSubTriggerProps,
  MenubarSubContentProps,
} from './menubar';



================================================
FILE: packages/react/menubar/src/menubar.tsx
================================================
import * as React from 'react';
import { createCollection } from '@radix-ui/react-collection';
import { useDirection } from '@radix-ui/react-direction';
import { composeEventHandlers } from '@radix-ui/primitive';
import { useComposedRefs } from '@radix-ui/react-compose-refs';
import { createContextScope } from '@radix-ui/react-context';
import { useId } from '@radix-ui/react-id';
import * as MenuPrimitive from '@radix-ui/react-menu';
import { createMenuScope } from '@radix-ui/react-menu';
import * as RovingFocusGroup from '@radix-ui/react-roving-focus';
import { createRovingFocusGroupScope } from '@radix-ui/react-roving-focus';
import { Primitive } from '@radix-ui/react-primitive';
import { useControllableState } from '@radix-ui/react-use-controllable-state';

import type { Scope } from '@radix-ui/react-context';

type Direction = 'ltr' | 'rtl';

/* -------------------------------------------------------------------------------------------------
 * Menubar
 * -----------------------------------------------------------------------------------------------*/

const MENUBAR_NAME = 'Menubar';

type ItemData = { value: string; disabled: boolean };
const [Collection, useCollection, createCollectionScope] = createCollection<
  MenubarTriggerElement,
  ItemData
>(MENUBAR_NAME);

type ScopedProps<P> = P & { __scopeMenubar?: Scope };
const [createMenubarContext, createMenubarScope] = createContextScope(MENUBAR_NAME, [
  createCollectionScope,
  createRovingFocusGroupScope,
]);

const useMenuScope = createMenuScope();
const useRovingFocusGroupScope = createRovingFocusGroupScope();

type MenubarContextValue = {
  value: string;
  dir: Direction;
  loop: boolean;
  onMenuOpen(value: string): void;
  onMenuClose(): void;
  onMenuToggle(value: string): void;
};

const [MenubarContextProvider, useMenubarContext] =
  createMenubarContext<MenubarContextValue>(MENUBAR_NAME);

type MenubarElement = React.ComponentRef<typeof Primitive.div>;
type RovingFocusGroupProps = React.ComponentPropsWithoutRef<typeof RovingFocusGroup.Root>;
type PrimitiveDivProps = React.ComponentPropsWithoutRef<typeof Primitive.div>;
interface MenubarProps extends PrimitiveDivProps {
  value?: string;
  defaultValue?: string;
  onValueChange?: (value: string) => void;
  loop?: RovingFocusGroupProps['loop'];
  dir?: RovingFocusGroupProps['dir'];
}

const Menubar = React.forwardRef<MenubarElement, MenubarProps>(
  (props: ScopedProps<MenubarProps>, forwardedRef) => {
    const {
      __scopeMenubar,
      value: valueProp,
      onValueChange,
      defaultValue,
      loop = true,
      dir,
      ...menubarProps
    } = props;
    const direction = useDirection(dir);
    const rovingFocusGroupScope = useRovingFocusGroupScope(__scopeMenubar);
    const [value, setValue] = useControllableState({
      prop: valueProp,
      onChange: onValueChange,
      defaultProp: defaultValue ?? '',
      caller: MENUBAR_NAME,
    });

    // We need to manage tab stop id manually as `RovingFocusGroup` updates the stop
    // based on focus, and in some situations our triggers won't ever be given focus
    // (e.g. click to open and then outside to close)
    const [currentTabStopId, setCurrentTabStopId] = React.useState<string | null>(null);

    return (
      <MenubarContextProvider
        scope={__scopeMenubar}
        value={value}
        onMenuOpen={React.useCallback(
          (value) => {
            setValue(value);
            setCurrentTabStopId(value);
          },
          [setValue],
        )}
        onMenuClose={React.useCallback(() => setValue(''), [setValue])}
        onMenuToggle={React.useCallback(
          (value) => {
            setValue((prevValue) => (prevValue ? '' : value));
            // `openMenuOpen` and `onMenuToggle` are called exclusively so we
            // need to update the id in either case.
            setCurrentTabStopId(value);
          },
          [setValue],
        )}
        dir={direction}
        loop={loop}
      >
        <Collection.Provider scope={__scopeMenubar}>
          <Collection.Slot scope={__scopeMenubar}>
            <RovingFocusGroup.Root
              asChild
              {...rovingFocusGroupScope}
              orientation="horizontal"
              loop={loop}
              dir={direction}
              currentTabStopId={currentTabStopId}
              onCurrentTabStopIdChange={setCurrentTabStopId}
            >
              <Primitive.div role="menubar" {...menubarProps} ref={forwardedRef} />
            </RovingFocusGroup.Root>
          </Collection.Slot>
        </Collection.Provider>
      </MenubarContextProvider>
    );
  },
);

Menubar.displayName = MENUBAR_NAME;

/* -------------------------------------------------------------------------------------------------
 * MenubarMenu
 * -----------------------------------------------------------------------------------------------*/

const MENU_NAME = 'MenubarMenu';

type MenubarMenuContextValue = {
  value: string;
  triggerId: string;
  triggerRef: React.RefObject<MenubarTriggerElement | null>;
  contentId: string;
  wasKeyboardTriggerOpenRef: React.MutableRefObject<boolean>;
};

const [MenubarMenuProvider, useMenubarMenuContext] =
  createMenubarContext<MenubarMenuContextValue>(MENU_NAME);

interface MenubarMenuProps {
  value?: string;
  children?: React.ReactNode;
}

const MenubarMenu = (props: ScopedProps<MenubarMenuProps>) => {
  const { __scopeMenubar, value: valueProp, ...menuProps } = props;
  const autoValue = useId();
  // We need to provide an initial deterministic value as `useId` will return
  // empty string on the first render and we don't want to match our internal "closed" value.
  const value = valueProp || autoValue || 'LEGACY_REACT_AUTO_VALUE';
  const context = useMenubarContext(MENU_NAME, __scopeMenubar);
  const menuScope = useMenuScope(__scopeMenubar);
  const triggerRef = React.useRef<MenubarTriggerElement>(null);
  const wasKeyboardTriggerOpenRef = React.useRef(false);
  const open = context.value === value;

  React.useEffect(() => {
    if (!open) wasKeyboardTriggerOpenRef.current = false;
  }, [open]);

  return (
    <MenubarMenuProvider
      scope={__scopeMenubar}
      value={value}
      triggerId={useId()}
      triggerRef={triggerRef}
      contentId={useId()}
      wasKeyboardTriggerOpenRef={wasKeyboardTriggerOpenRef}
    >
      <MenuPrimitive.Root
        {...menuScope}
        open={open}
        onOpenChange={(open) => {
          // Menu only calls `onOpenChange` when dismissing so we
          // want to close our MenuBar based on the same events.
          if (!open) context.onMenuClose();
        }}
        modal={false}
        dir={context.dir}
        {...menuProps}
      />
    </MenubarMenuProvider>
  );
};

MenubarMenu.displayName = MENU_NAME;

/* -------------------------------------------------------------------------------------------------
 * MenubarTrigger
 * -----------------------------------------------------------------------------------------------*/

const TRIGGER_NAME = 'MenubarTrigger';

type MenubarTriggerElement = React.ComponentRef<typeof Primitive.button>;
type PrimitiveButtonProps = React.ComponentPropsWithoutRef<typeof Primitive.button>;
interface MenubarTriggerProps extends PrimitiveButtonProps {}

const MenubarTrigger = React.forwardRef<MenubarTriggerElement, MenubarTriggerProps>(
  (props: ScopedProps<MenubarTriggerProps>, forwardedRef) => {
    const { __scopeMenubar, disabled = false, ...triggerProps } = props;
    const rovingFocusGroupScope = useRovingFocusGroupScope(__scopeMenubar);
    const menuScope = useMenuScope(__scopeMenubar);
    const context = useMenubarContext(TRIGGER_NAME, __scopeMenubar);
    const menuContext = useMenubarMenuContext(TRIGGER_NAME, __scopeMenubar);
    const ref = React.useRef<MenubarTriggerElement>(null);
    const composedRefs = useComposedRefs(forwardedRef, ref, menuContext.triggerRef);
    const [isFocused, setIsFocused] = React.useState(false);
    const open = context.value === menuContext.value;

    return (
      <Collection.ItemSlot scope={__scopeMenubar} value={menuContext.value} disabled={disabled}>
        <RovingFocusGroup.Item
          asChild
          {...rovingFocusGroupScope}
          focusable={!disabled}
          tabStopId={menuContext.value}
        >
          <MenuPrimitive.Anchor asChild {...menuScope}>
            <Primitive.button
              type="button"
              role="menuitem"
              id={menuContext.triggerId}
              aria-haspopup="menu"
              aria-expanded={open}
              aria-controls={open ? menuContext.contentId : undefined}
              data-highlighted={isFocused ? '' : undefined}
              data-state={open ? 'open' : 'closed'}
              data-disabled={disabled ? '' : undefined}
              disabled={disabled}
              {...triggerProps}
              ref={composedRefs}
              onPointerDown={composeEventHandlers(props.onPointerDown, (event) => {
                // only call handler if it's the left button (mousedown gets triggered by all mouse buttons)
                // but not when the control key is pressed (avoiding MacOS right click)
                if (!disabled && event.button === 0 && event.ctrlKey === false) {
                  context.onMenuOpen(menuContext.value);
                  // prevent trigger focusing when opening
                  // this allows the content to be given focus without competition
                  if (!open) event.preventDefault();
                }
              })}
              onPointerEnter={composeEventHandlers(props.onPointerEnter, () => {
                const menubarOpen = Boolean(context.value);
                if (menubarOpen && !open) {
                  context.onMenuOpen(menuContext.value);
                  ref.current?.focus();
                }
              })}
              onKeyDown={composeEventHandlers(props.onKeyDown, (event) => {
                if (disabled) return;
                if (['Enter', ' '].includes(event.key)) context.onMenuToggle(menuContext.value);
                if (event.key === 'ArrowDown') context.onMenuOpen(menuContext.value);
                // prevent keydown from scrolling window / first focused item to execute
                // that keydown (inadvertently closing the menu)
                if (['Enter', ' ', 'ArrowDown'].includes(event.key)) {
                  menuContext.wasKeyboardTriggerOpenRef.current = true;
                  event.preventDefault();
                }
              })}
              onFocus={composeEventHandlers(props.onFocus, () => setIsFocused(true))}
              onBlur={composeEventHandlers(props.onBlur, () => setIsFocused(false))}
            />
          </MenuPrimitive.Anchor>
        </RovingFocusGroup.Item>
      </Collection.ItemSlot>
    );
  },
);

MenubarTrigger.displayName = TRIGGER_NAME;

/* -------------------------------------------------------------------------------------------------
 * MenubarPortal
 * -----------------------------------------------------------------------------------------------*/

const PORTAL_NAME = 'MenubarPortal';

type MenuPortalProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.Portal>;
interface MenubarPortalProps extends MenuPortalProps {}

const MenubarPortal: React.FC<MenubarPortalProps> = (props: ScopedProps<MenubarPortalProps>) => {
  const { __scopeMenubar, ...portalProps } = props;
  const menuScope = useMenuScope(__scopeMenubar);
  return <MenuPrimitive.Portal {...menuScope} {...portalProps} />;
};

MenubarPortal.displayName = PORTAL_NAME;

/* -------------------------------------------------------------------------------------------------
 * MenubarContent
 * -----------------------------------------------------------------------------------------------*/

const CONTENT_NAME = 'MenubarContent';

type MenubarContentElement = React.ComponentRef<typeof MenuPrimitive.Content>;
type MenuContentProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.Content>;
interface MenubarContentProps extends Omit<MenuContentProps, 'onEntryFocus'> {}

const MenubarContent = React.forwardRef<MenubarContentElement, MenubarContentProps>(
  (props: ScopedProps<MenubarContentProps>, forwardedRef) => {
    const { __scopeMenubar, align = 'start', ...contentProps } = props;
    const menuScope = useMenuScope(__scopeMenubar);
    const context = useMenubarContext(CONTENT_NAME, __scopeMenubar);
    const menuContext = useMenubarMenuContext(CONTENT_NAME, __scopeMenubar);
    const getItems = useCollection(__scopeMenubar);
    const hasInteractedOutsideRef = React.useRef(false);

    return (
      <MenuPrimitive.Content
        id={menuContext.contentId}
        aria-labelledby={menuContext.triggerId}
        data-radix-menubar-content=""
        {...menuScope}
        {...contentProps}
        ref={forwardedRef}
        align={align}
        onCloseAutoFocus={composeEventHandlers(props.onCloseAutoFocus, (event) => {
          const menubarOpen = Boolean(context.value);
          if (!menubarOpen && !hasInteractedOutsideRef.current) {
            menuContext.triggerRef.current?.focus();
          }

          hasInteractedOutsideRef.current = false;
          // Always prevent auto focus because we either focus manually or want user agent focus
          event.preventDefault();
        })}
        onFocusOutside={composeEventHandlers(props.onFocusOutside, (event) => {
          const target = event.target as HTMLElement;
          const isMenubarTrigger = getItems().some((item) => item.ref.current?.contains(target));
          if (isMenubarTrigger) event.preventDefault();
        })}
        onInteractOutside={composeEventHandlers(props.onInteractOutside, () => {
          hasInteractedOutsideRef.current = true;
        })}
        onEntryFocus={(event) => {
          if (!menuContext.wasKeyboardTriggerOpenRef.current) event.preventDefault();
        }}
        onKeyDown={composeEventHandlers(
          props.onKeyDown,
          (event) => {
            if (['ArrowRight', 'ArrowLeft'].includes(event.key)) {
              const target = event.target as HTMLElement;
              const targetIsSubTrigger = target.hasAttribute('data-radix-menubar-subtrigger');
              const isKeyDownInsideSubMenu =
                target.closest('[data-radix-menubar-content]') !== event.currentTarget;

              const prevMenuKey = context.dir === 'rtl' ? 'ArrowRight' : 'ArrowLeft';
              const isPrevKey = prevMenuKey === event.key;
              const isNextKey = !isPrevKey;

              // Prevent navigation when we're opening a submenu
              if (isNextKey && targetIsSubTrigger) return;
              // or we're inside a submenu and are moving backwards to close it
              if (isKeyDownInsideSubMenu && isPrevKey) return;

              const items = getItems().filter((item) => !item.disabled);
              let candidateValues = items.map((item) => item.value);
              if (isPrevKey) candidateValues.reverse();

              const currentIndex = candidateValues.indexOf(menuContext.value);

              candidateValues = context.loop
                ? wrapArray(candidateValues, currentIndex + 1)
                : candidateValues.slice(currentIndex + 1);

              const [nextValue] = candidateValues;
              if (nextValue) context.onMenuOpen(nextValue);
            }
          },
          { checkForDefaultPrevented: false },
        )}
        style={{
          ...props.style,
          // re-namespace exposed content custom properties
          ...{
            '--radix-menubar-content-transform-origin': 'var(--radix-popper-transform-origin)',
            '--radix-menubar-content-available-width': 'var(--radix-popper-available-width)',
            '--radix-menubar-content-available-height': 'var(--radix-popper-available-height)',
            '--radix-menubar-trigger-width': 'var(--radix-popper-anchor-width)',
            '--radix-menubar-trigger-height': 'var(--radix-popper-anchor-height)',
          },
        }}
      />
    );
  },
);

MenubarContent.displayName = CONTENT_NAME;

/* -------------------------------------------------------------------------------------------------
 * MenubarGroup
 * -----------------------------------------------------------------------------------------------*/

const GROUP_NAME = 'MenubarGroup';

type MenubarGroupElement = React.ComponentRef<typeof MenuPrimitive.Group>;
type MenuGroupProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.Group>;
interface MenubarGroupProps extends MenuGroupProps {}

const MenubarGroup = React.forwardRef<MenubarGroupElement, MenubarGroupProps>(
  (props: ScopedProps<MenubarGroupProps>, forwardedRef) => {
    const { __scopeMenubar, ...groupProps } = props;
    const menuScope = useMenuScope(__scopeMenubar);
    return <MenuPrimitive.Group {...menuScope} {...groupProps} ref={forwardedRef} />;
  },
);

MenubarGroup.displayName = GROUP_NAME;

/* -------------------------------------------------------------------------------------------------
 * MenubarLabel
 * -----------------------------------------------------------------------------------------------*/

const LABEL_NAME = 'MenubarLabel';

type MenubarLabelElement = React.ComponentRef<typeof MenuPrimitive.Label>;
type MenuLabelProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.Label>;
interface MenubarLabelProps extends MenuLabelProps {}

const MenubarLabel = React.forwardRef<MenubarLabelElement, MenubarLabelProps>(
  (props: ScopedProps<MenubarLabelProps>, forwardedRef) => {
    const { __scopeMenubar, ...labelProps } = props;
    const menuScope = useMenuScope(__scopeMenubar);
    return <MenuPrimitive.Label {...menuScope} {...labelProps} ref={forwardedRef} />;
  },
);

MenubarLabel.displayName = LABEL_NAME;

/* -------------------------------------------------------------------------------------------------
 * MenubarItem
 * -----------------------------------------------------------------------------------------------*/

const ITEM_NAME = 'MenubarItem';

type MenubarItemElement = React.ComponentRef<typeof MenuPrimitive.Item>;
type MenuItemProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.Item>;
interface MenubarItemProps extends MenuItemProps {}

const MenubarItem = React.forwardRef<MenubarItemElement, MenubarItemProps>(
  (props: ScopedProps<MenubarItemProps>, forwardedRef) => {
    const { __scopeMenubar, ...itemProps } = props;
    const menuScope = useMenuScope(__scopeMenubar);
    return <MenuPrimitive.Item {...menuScope} {...itemProps} ref={forwardedRef} />;
  },
);

MenubarItem.displayName = ITEM_NAME;

/* -------------------------------------------------------------------------------------------------
 * MenubarCheckboxItem
 * -----------------------------------------------------------------------------------------------*/

const CHECKBOX_ITEM_NAME = 'MenubarCheckboxItem';

type MenubarCheckboxItemElement = React.ComponentRef<typeof MenuPrimitive.CheckboxItem>;
type MenuCheckboxItemProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.CheckboxItem>;
interface MenubarCheckboxItemProps extends MenuCheckboxItemProps {}

const MenubarCheckboxItem = React.forwardRef<MenubarCheckboxItemElement, MenubarCheckboxItemProps>(
  (props: ScopedProps<MenubarCheckboxItemProps>, forwardedRef) => {
    const { __scopeMenubar, ...checkboxItemProps } = props;
    const menuScope = useMenuScope(__scopeMenubar);
    return <MenuPrimitive.CheckboxItem {...menuScope} {...checkboxItemProps} ref={forwardedRef} />;
  },
);

MenubarCheckboxItem.displayName = CHECKBOX_ITEM_NAME;

/* -------------------------------------------------------------------------------------------------
 * MenubarRadioGroup
 * -----------------------------------------------------------------------------------------------*/

const RADIO_GROUP_NAME = 'MenubarRadioGroup';

type MenubarRadioGroupElement = React.ComponentRef<typeof MenuPrimitive.RadioGroup>;
type MenuRadioGroupProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.RadioGroup>;
interface MenubarRadioGroupProps extends MenuRadioGroupProps {}

const MenubarRadioGroup = React.forwardRef<MenubarRadioGroupElement, MenubarRadioGroupProps>(
  (props: ScopedProps<MenubarRadioGroupProps>, forwardedRef) => {
    const { __scopeMenubar, ...radioGroupProps } = props;
    const menuScope = useMenuScope(__scopeMenubar);
    return <MenuPrimitive.RadioGroup {...menuScope} {...radioGroupProps} ref={forwardedRef} />;
  },
);

MenubarRadioGroup.displayName = RADIO_GROUP_NAME;

/* -------------------------------------------------------------------------------------------------
 * MenubarRadioItem
 * -----------------------------------------------------------------------------------------------*/

const RADIO_ITEM_NAME = 'MenubarRadioItem';

type MenubarRadioItemElement = React.ComponentRef<typeof MenuPrimitive.RadioItem>;
type MenuRadioItemProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.RadioItem>;
interface MenubarRadioItemProps extends MenuRadioItemProps {}

const MenubarRadioItem = React.forwardRef<MenubarRadioItemElement, MenubarRadioItemProps>(
  (props: ScopedProps<MenubarRadioItemProps>, forwardedRef) => {
    const { __scopeMenubar, ...radioItemProps } = props;
    const menuScope = useMenuScope(__scopeMenubar);
    return <MenuPrimitive.RadioItem {...menuScope} {...radioItemProps} ref={forwardedRef} />;
  },
);

MenubarRadioItem.displayName = RADIO_ITEM_NAME;

/* -------------------------------------------------------------------------------------------------
 * MenubarItemIndicator
 * -----------------------------------------------------------------------------------------------*/

const INDICATOR_NAME = 'MenubarItemIndicator';

type MenubarItemIndicatorElement = React.ComponentRef<typeof MenuPrimitive.ItemIndicator>;
type MenuItemIndicatorProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.ItemIndicator>;
interface MenubarItemIndicatorProps extends MenuItemIndicatorProps {}

const MenubarItemIndicator = React.forwardRef<
  MenubarItemIndicatorElement,
  MenubarItemIndicatorProps
>((props: ScopedProps<MenubarItemIndicatorProps>, forwardedRef) => {
  const { __scopeMenubar, ...itemIndicatorProps } = props;
  const menuScope = useMenuScope(__scopeMenubar);
  return <MenuPrimitive.ItemIndicator {...menuScope} {...itemIndicatorProps} ref={forwardedRef} />;
});

MenubarItemIndicator.displayName = INDICATOR_NAME;

/* -------------------------------------------------------------------------------------------------
 * MenubarSeparator
 * -----------------------------------------------------------------------------------------------*/

const SEPARATOR_NAME = 'MenubarSeparator';

type MenubarSeparatorElement = React.ComponentRef<typeof MenuPrimitive.Separator>;
type MenuSeparatorProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.Separator>;
interface MenubarSeparatorProps extends MenuSeparatorProps {}

const MenubarSeparator = React.forwardRef<MenubarSeparatorElement, MenubarSeparatorProps>(
  (props: ScopedProps<MenubarSeparatorProps>, forwardedRef) => {
    const { __scopeMenubar, ...separatorProps } = props;
    const menuScope = useMenuScope(__scopeMenubar);
    return <MenuPrimitive.Separator {...menuScope} {...separatorProps} ref={forwardedRef} />;
  },
);

MenubarSeparator.displayName = SEPARATOR_NAME;

/* -------------------------------------------------------------------------------------------------
 * MenubarArrow
 * -----------------------------------------------------------------------------------------------*/

const ARROW_NAME = 'MenubarArrow';

type MenubarArrowElement = React.ComponentRef<typeof MenuPrimitive.Arrow>;
type MenuArrowProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.Arrow>;
interface MenubarArrowProps extends MenuArrowProps {}

const MenubarArrow = React.forwardRef<MenubarArrowElement, MenubarArrowProps>(
  (props: ScopedProps<MenubarArrowProps>, forwardedRef) => {
    const { __scopeMenubar, ...arrowProps } = props;
    const menuScope = useMenuScope(__scopeMenubar);
    return <MenuPrimitive.Arrow {...menuScope} {...arrowProps} ref={forwardedRef} />;
  },
);

MenubarArrow.displayName = ARROW_NAME;

/* -------------------------------------------------------------------------------------------------
 * MenubarSub
 * -----------------------------------------------------------------------------------------------*/

const SUB_NAME = 'MenubarSub';

interface MenubarSubProps {
  children?: React.ReactNode;
  open?: boolean;
  defaultOpen?: boolean;
  onOpenChange?(open: boolean): void;
}

const MenubarSub: React.FC<MenubarSubProps> = (props: ScopedProps<MenubarSubProps>) => {
  const { __scopeMenubar, children, open: openProp, onOpenChange, defaultOpen } = props;
  const menuScope = useMenuScope(__scopeMenubar);
  const [open, setOpen] = useControllableState({
    prop: openProp,
    defaultProp: defaultOpen ?? false,
    onChange: onOpenChange,
    caller: SUB_NAME,
  });

  return (
    <MenuPrimitive.Sub {...menuScope} open={open} onOpenChange={setOpen}>
      {children}
    </MenuPrimitive.Sub>
  );
};

MenubarSub.displayName = SUB_NAME;

/* -------------------------------------------------------------------------------------------------
 * MenubarSubTrigger
 * -----------------------------------------------------------------------------------------------*/

const SUB_TRIGGER_NAME = 'MenubarSubTrigger';

type MenubarSubTriggerElement = React.ComponentRef<typeof MenuPrimitive.SubTrigger>;
type MenuSubTriggerProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.SubTrigger>;
interface MenubarSubTriggerProps extends MenuSubTriggerProps {}

const MenubarSubTrigger = React.forwardRef<MenubarSubTriggerElement, MenubarSubTriggerProps>(
  (props: ScopedProps<MenubarSubTriggerProps>, forwardedRef) => {
    const { __scopeMenubar, ...subTriggerProps } = props;
    const menuScope = useMenuScope(__scopeMenubar);
    return (
      <MenuPrimitive.SubTrigger
        data-radix-menubar-subtrigger=""
        {...menuScope}
        {...subTriggerProps}
        ref={forwardedRef}
      />
    );
  },
);

MenubarSubTrigger.displayName = SUB_TRIGGER_NAME;

/* -------------------------------------------------------------------------------------------------
 * MenubarSubContent
 * -----------------------------------------------------------------------------------------------*/

const SUB_CONTENT_NAME = 'MenubarSubContent';

type MenubarSubContentElement = React.ComponentRef<typeof MenuPrimitive.Content>;
type MenuSubContentProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.SubContent>;
interface MenubarSubContentProps extends MenuSubContentProps {}

const MenubarSubContent = React.forwardRef<MenubarSubContentElement, MenubarSubContentProps>(
  (props: ScopedProps<MenubarSubContentProps>, forwardedRef) => {
    const { __scopeMenubar, ...subContentProps } = props;
    const menuScope = useMenuScope(__scopeMenubar);

    return (
      <MenuPrimitive.SubContent
        {...menuScope}
        data-radix-menubar-content=""
        {...subContentProps}
        ref={forwardedRef}
        style={{
          ...props.style,
          // re-namespace exposed content custom properties
          ...{
            '--radix-menubar-content-transform-origin': 'var(--radix-popper-transform-origin)',
            '--radix-menubar-content-available-width': 'var(--radix-popper-available-width)',
            '--radix-menubar-content-available-height': 'var(--radix-popper-available-height)',
            '--radix-menubar-trigger-width': 'var(--radix-popper-anchor-width)',
            '--radix-menubar-trigger-height': 'var(--radix-popper-anchor-height)',
          },
        }}
      />
    );
  },
);

MenubarSubContent.displayName = SUB_CONTENT_NAME;

/* -----------------------------------------------------------------------------------------------*/

/**
 * Wraps an array around itself at a given start index
 * Example: `wrapArray(['a', 'b', 'c', 'd'], 2) === ['c', 'd', 'a', 'b']`
 */
function wrapArray<T>(array: T[], startIndex: number) {
  return array.map<T>((_, index) => array[(startIndex + index) % array.length]!);
}

const Root = Menubar;
const Menu = MenubarMenu;
const Trigger = MenubarTrigger;
const Portal = MenubarPortal;
const Content = MenubarContent;
const Group = MenubarGroup;
const Label = MenubarLabel;
const Item = MenubarItem;
const CheckboxItem = MenubarCheckboxItem;
const RadioGroup = MenubarRadioGroup;
const RadioItem = MenubarRadioItem;
const ItemIndicator = MenubarItemIndicator;
const Separator = MenubarSeparator;
const Arrow = MenubarArrow;
const Sub = MenubarSub;
const SubTrigger = MenubarSubTrigger;
const SubContent = MenubarSubContent;

export {
  createMenubarScope,
  //
  Menubar,
  MenubarMenu,
  MenubarTrigger,
  MenubarPortal,
  MenubarContent,
  MenubarGroup,
  MenubarLabel,
  MenubarItem,
  MenubarCheckboxItem,
  MenubarRadioGroup,
  MenubarRadioItem,
  MenubarItemIndicator,
  MenubarSeparator,
  MenubarArrow,
  MenubarSub,
  MenubarSubTrigger,
  MenubarSubContent,
  //
  Root,
  Menu,
  Trigger,
  Portal,
  Content,
  Group,
  Label,
  Item,
  CheckboxItem,
  RadioGroup,
  RadioItem,
  ItemIndicator,
  Separator,
  Arrow,
  Sub,
  SubTrigger,
  SubContent,
};
export type {
  MenubarProps,
  MenubarMenuProps,
  MenubarTriggerProps,
  MenubarPortalProps,
  MenubarContentProps,
  MenubarGroupProps,
  MenubarLabelProps,
  MenubarItemProps,
  MenubarCheckboxItemProps,
  MenubarRadioGroupProps,
  MenubarRadioItemProps,
  MenubarItemIndicatorProps,
  MenubarSeparatorProps,
  MenubarArrowProps,
  MenubarSubProps,
  MenubarSubTriggerProps,
  MenubarSubContentProps,
};



================================================
FILE: packages/react/navigation-menu/README.md
================================================
# `react-navigation-menu`

View docs [here](https://radix-ui.com/primitives/docs/components/navigation-menu).



================================================
FILE: packages/react/navigation-menu/CHANGELOG.md
================================================
# @radix-ui/react-navigation-menu

## 1.2.14

- Updated dependencies: `@radix-ui/react-presence@1.1.5`, `@radix-ui/primitive@1.1.3`, `@radix-ui/react-context@1.1.3`, `@radix-ui/react-collection@1.1.8`, `@radix-ui/react-primitive@2.1.4`, `@radix-ui/react-dismissable-layer@1.1.11`, `@radix-ui/react-visually-hidden@1.2.4`

## 1.2.13

- Replace deprecated 'ElementRef' with 'ComponentRef' (#3426)
- Updated dependencies: `@radix-ui/react-dismissable-layer@1.1.10`, `@radix-ui/react-visually-hidden@1.2.3`, `@radix-ui/react-collection@1.1.7`, `@radix-ui/react-primitive@2.1.3`

## 1.2.12

- Updated dependencies: `@radix-ui/react-collection@1.1.6`, `@radix-ui/react-primitive@2.1.2`, `@radix-ui/react-dismissable-layer@1.1.9`, `@radix-ui/react-visually-hidden@1.2.2`

## 1.2.11

- Updated dependencies: `@radix-ui/react-collection@1.1.5`, `@radix-ui/react-primitive@2.1.1`, `@radix-ui/react-dismissable-layer@1.1.8`, `@radix-ui/react-visually-hidden@1.2.1`

## 1.2.10

- Updated dependencies: `@radix-ui/react-presence@1.1.4`

## 1.2.9

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.2`

## 1.2.8

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.1`

## 1.2.7

- Minor improvements to `useControllableState` to enhance performance, reduce surface area for bugs, and log warnings when misused (#3455)
- Updated dependencies: `@radix-ui/react-collection@1.1.4`, `@radix-ui/react-use-controllable-state@1.2.0`, `@radix-ui/react-visually-hidden@1.2.0`, `@radix-ui/react-primitive@2.1.0`, `@radix-ui/react-dismissable-layer@1.1.7`



================================================
FILE: packages/react/navigation-menu/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/navigation-menu/package.json
================================================
{
  "name": "@radix-ui/react-navigation-menu",
  "version": "1.2.14",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/primitive": "workspace:*",
    "@radix-ui/react-collection": "workspace:*",
    "@radix-ui/react-compose-refs": "workspace:*",
    "@radix-ui/react-context": "workspace:*",
    "@radix-ui/react-direction": "workspace:*",
    "@radix-ui/react-dismissable-layer": "workspace:*",
    "@radix-ui/react-id": "workspace:*",
    "@radix-ui/react-presence": "workspace:*",
    "@radix-ui/react-primitive": "workspace:*",
    "@radix-ui/react-use-callback-ref": "workspace:*",
    "@radix-ui/react-use-controllable-state": "workspace:*",
    "@radix-ui/react-use-layout-effect": "workspace:*",
    "@radix-ui/react-use-previous": "workspace:*",
    "@radix-ui/react-visually-hidden": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/navigation-menu/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/navigation-menu/src/index.ts
================================================
'use client';
export {
  createNavigationMenuScope,
  //
  NavigationMenu,
  NavigationMenuSub,
  NavigationMenuList,
  NavigationMenuItem,
  NavigationMenuTrigger,
  NavigationMenuLink,
  NavigationMenuIndicator,
  NavigationMenuContent,
  NavigationMenuViewport,
  //
  Root,
  Sub,
  List,
  Item,
  Trigger,
  Link,
  Indicator,
  Content,
  Viewport,
} from './navigation-menu';
export type {
  NavigationMenuProps,
  NavigationMenuSubProps,
  NavigationMenuListProps,
  NavigationMenuItemProps,
  NavigationMenuTriggerProps,
  NavigationMenuLinkProps,
  NavigationMenuIndicatorProps,
  NavigationMenuContentProps,
  NavigationMenuViewportProps,
} from './navigation-menu';



================================================
FILE: packages/react/navigation-menu/src/navigation-menu.tsx
================================================
import * as React from 'react';
import ReactDOM from 'react-dom';
import { createContextScope } from '@radix-ui/react-context';
import { composeEventHandlers } from '@radix-ui/primitive';
import { Primitive, dispatchDiscreteCustomEvent } from '@radix-ui/react-primitive';
import { useControllableState } from '@radix-ui/react-use-controllable-state';
import { composeRefs, useComposedRefs } from '@radix-ui/react-compose-refs';
import { useDirection } from '@radix-ui/react-direction';
import { Presence } from '@radix-ui/react-presence';
import { useId } from '@radix-ui/react-id';
import { createCollection } from '@radix-ui/react-collection';
import { DismissableLayer } from '@radix-ui/react-dismissable-layer';
import { usePrevious } from '@radix-ui/react-use-previous';
import { useLayoutEffect } from '@radix-ui/react-use-layout-effect';
import { useCallbackRef } from '@radix-ui/react-use-callback-ref';
import * as VisuallyHiddenPrimitive from '@radix-ui/react-visually-hidden';

import type { Scope } from '@radix-ui/react-context';

type Orientation = 'vertical' | 'horizontal';
type Direction = 'ltr' | 'rtl';

/* -------------------------------------------------------------------------------------------------
 * NavigationMenu
 * -----------------------------------------------------------------------------------------------*/

const NAVIGATION_MENU_NAME = 'NavigationMenu';

const [Collection, useCollection, createCollectionScope] = createCollection<
  NavigationMenuTriggerElement,
  { value: string }
>(NAVIGATION_MENU_NAME);

const [FocusGroupCollection, useFocusGroupCollection, createFocusGroupCollectionScope] =
  createCollection<FocusGroupItemElement, {}>(NAVIGATION_MENU_NAME);

type ScopedProps<P> = P & { __scopeNavigationMenu?: Scope };
const [createNavigationMenuContext, createNavigationMenuScope] = createContextScope(
  NAVIGATION_MENU_NAME,
  [createCollectionScope, createFocusGroupCollectionScope],
);

type ContentData = {
  ref?: React.Ref<ViewportContentMounterElement>;
} & ViewportContentMounterProps;

type NavigationMenuContextValue = {
  isRootMenu: boolean;
  value: string;
  previousValue: string;
  baseId: string;
  dir: Direction;
  orientation: Orientation;
  rootNavigationMenu: NavigationMenuElement | null;
  indicatorTrack: HTMLDivElement | null;
  onIndicatorTrackChange(indicatorTrack: HTMLDivElement | null): void;
  viewport: NavigationMenuViewportElement | null;
  onViewportChange(viewport: NavigationMenuViewportElement | null): void;
  onViewportContentChange(contentValue: string, contentData: ContentData): void;
  onViewportContentRemove(contentValue: string): void;
  onTriggerEnter(itemValue: string): void;
  onTriggerLeave(): void;
  onContentEnter(): void;
  onContentLeave(): void;
  onItemSelect(itemValue: string): void;
  onItemDismiss(): void;
};

const [NavigationMenuProviderImpl, useNavigationMenuContext] =
  createNavigationMenuContext<NavigationMenuContextValue>(NAVIGATION_MENU_NAME);

const [ViewportContentProvider, useViewportContentContext] = createNavigationMenuContext<{
  items: Map<string, ContentData>;
}>(NAVIGATION_MENU_NAME);

type NavigationMenuElement = React.ComponentRef<typeof Primitive.nav>;
type PrimitiveNavProps = React.ComponentPropsWithoutRef<typeof Primitive.nav>;
interface NavigationMenuProps
  extends Omit<NavigationMenuProviderProps, keyof NavigationMenuProviderPrivateProps>,
    PrimitiveNavProps {
  value?: string;
  defaultValue?: string;
  onValueChange?: (value: string) => void;
  dir?: Direction;
  orientation?: Orientation;
  /**
   * The duration from when the pointer enters the trigger until the tooltip gets opened.
   * @defaultValue 200
   */
  delayDuration?: number;
  /**
   * How much time a user has to enter another trigger without incurring a delay again.
   * @defaultValue 300
   */
  skipDelayDuration?: number;
}

const NavigationMenu = React.forwardRef<NavigationMenuElement, NavigationMenuProps>(
  (props: ScopedProps<NavigationMenuProps>, forwardedRef) => {
    const {
      __scopeNavigationMenu,
      value: valueProp,
      onValueChange,
      defaultValue,
      delayDuration = 200,
      skipDelayDuration = 300,
      orientation = 'horizontal',
      dir,
      ...NavigationMenuProps
    } = props;
    const [navigationMenu, setNavigationMenu] = React.useState<NavigationMenuElement | null>(null);
    const composedRef = useComposedRefs(forwardedRef, (node) => setNavigationMenu(node));
    const direction = useDirection(dir);
    const openTimerRef = React.useRef(0);
    const closeTimerRef = React.useRef(0);
    const skipDelayTimerRef = React.useRef(0);
    const [isOpenDelayed, setIsOpenDelayed] = React.useState(true);
    const [value, setValue] = useControllableState({
      prop: valueProp,
      onChange: (value) => {
        const isOpen = value !== '';
        const hasSkipDelayDuration = skipDelayDuration > 0;

        if (isOpen) {
          window.clearTimeout(skipDelayTimerRef.current);
          if (hasSkipDelayDuration) setIsOpenDelayed(false);
        } else {
          window.clearTimeout(skipDelayTimerRef.current);
          skipDelayTimerRef.current = window.setTimeout(
            () => setIsOpenDelayed(true),
            skipDelayDuration,
          );
        }

        onValueChange?.(value);
      },
      defaultProp: defaultValue ?? '',
      caller: NAVIGATION_MENU_NAME,
    });

    const startCloseTimer = React.useCallback(() => {
      window.clearTimeout(closeTimerRef.current);
      closeTimerRef.current = window.setTimeout(() => setValue(''), 150);
    }, [setValue]);

    const handleOpen = React.useCallback(
      (itemValue: string) => {
        window.clearTimeout(closeTimerRef.current);
        setValue(itemValue);
      },
      [setValue],
    );

    const handleDelayedOpen = React.useCallback(
      (itemValue: string) => {
        const isOpenItem = value === itemValue;
        if (isOpenItem) {
          // If the item is already open (e.g. we're transitioning from the content to the trigger)
          // then we want to clear the close timer immediately.
          window.clearTimeout(closeTimerRef.current);
        } else {
          openTimerRef.current = window.setTimeout(() => {
            window.clearTimeout(closeTimerRef.current);
            setValue(itemValue);
          }, delayDuration);
        }
      },
      [value, setValue, delayDuration],
    );

    React.useEffect(() => {
      return () => {
        window.clearTimeout(openTimerRef.current);
        window.clearTimeout(closeTimerRef.current);
        window.clearTimeout(skipDelayTimerRef.current);
      };
    }, []);

    return (
      <NavigationMenuProvider
        scope={__scopeNavigationMenu}
        isRootMenu={true}
        value={value}
        dir={direction}
        orientation={orientation}
        rootNavigationMenu={navigationMenu}
        onTriggerEnter={(itemValue) => {
          window.clearTimeout(openTimerRef.current);
          if (isOpenDelayed) handleDelayedOpen(itemValue);
          else handleOpen(itemValue);
        }}
        onTriggerLeave={() => {
          window.clearTimeout(openTimerRef.current);
          startCloseTimer();
        }}
        onContentEnter={() => window.clearTimeout(closeTimerRef.current)}
        onContentLeave={startCloseTimer}
        onItemSelect={(itemValue) => {
          setValue((prevValue) => (prevValue === itemValue ? '' : itemValue));
        }}
        onItemDismiss={() => setValue('')}
      >
        <Primitive.nav
          aria-label="Main"
          data-orientation={orientation}
          dir={direction}
          {...NavigationMenuProps}
          ref={composedRef}
        />
      </NavigationMenuProvider>
    );
  },
);

NavigationMenu.displayName = NAVIGATION_MENU_NAME;

/* -------------------------------------------------------------------------------------------------
 * NavigationMenuSub
 * -----------------------------------------------------------------------------------------------*/

const SUB_NAME = 'NavigationMenuSub';

type NavigationMenuSubElement = React.ComponentRef<typeof Primitive.div>;
type PrimitiveDivProps = React.ComponentPropsWithoutRef<typeof Primitive.div>;
interface NavigationMenuSubProps
  extends Omit<NavigationMenuProviderProps, keyof NavigationMenuProviderPrivateProps>,
    PrimitiveDivProps {
  value?: string;
  defaultValue?: string;
  onValueChange?: (value: string) => void;
  orientation?: Orientation;
}

const NavigationMenuSub = React.forwardRef<NavigationMenuSubElement, NavigationMenuSubProps>(
  (props: ScopedProps<NavigationMenuSubProps>, forwardedRef) => {
    const {
      __scopeNavigationMenu,
      value: valueProp,
      onValueChange,
      defaultValue,
      orientation = 'horizontal',
      ...subProps
    } = props;
    const context = useNavigationMenuContext(SUB_NAME, __scopeNavigationMenu);
    const [value, setValue] = useControllableState({
      prop: valueProp,
      onChange: onValueChange,
      defaultProp: defaultValue ?? '',
      caller: SUB_NAME,
    });

    return (
      <NavigationMenuProvider
        scope={__scopeNavigationMenu}
        isRootMenu={false}
        value={value}
        dir={context.dir}
        orientation={orientation}
        rootNavigationMenu={context.rootNavigationMenu}
        onTriggerEnter={(itemValue) => setValue(itemValue)}
        onItemSelect={(itemValue) => setValue(itemValue)}
        onItemDismiss={() => setValue('')}
      >
        <Primitive.div data-orientation={orientation} {...subProps} ref={forwardedRef} />
      </NavigationMenuProvider>
    );
  },
);

NavigationMenuSub.displayName = SUB_NAME;

/* -----------------------------------------------------------------------------------------------*/

interface NavigationMenuProviderPrivateProps {
  isRootMenu: boolean;
  scope: Scope;
  children: React.ReactNode;
  orientation: Orientation;
  dir: Direction;
  rootNavigationMenu: NavigationMenuElement | null;
  value: string;
  onTriggerEnter(itemValue: string): void;
  onTriggerLeave?(): void;
  onContentEnter?(): void;
  onContentLeave?(): void;
  onItemSelect(itemValue: string): void;
  onItemDismiss(): void;
}

interface NavigationMenuProviderProps extends NavigationMenuProviderPrivateProps {}

const NavigationMenuProvider: React.FC<NavigationMenuProviderProps> = (
  props: ScopedProps<NavigationMenuProviderProps>,
) => {
  const {
    scope,
    isRootMenu,
    rootNavigationMenu,
    dir,
    orientation,
    children,
    value,
    onItemSelect,
    onItemDismiss,
    onTriggerEnter,
    onTriggerLeave,
    onContentEnter,
    onContentLeave,
  } = props;
  const [viewport, setViewport] = React.useState<NavigationMenuViewportElement | null>(null);
  const [viewportContent, setViewportContent] = React.useState<Map<string, ContentData>>(new Map());
  const [indicatorTrack, setIndicatorTrack] = React.useState<HTMLDivElement | null>(null);

  return (
    <NavigationMenuProviderImpl
      scope={scope}
      isRootMenu={isRootMenu}
      rootNavigationMenu={rootNavigationMenu}
      value={value}
      previousValue={usePrevious(value)}
      baseId={useId()}
      dir={dir}
      orientation={orientation}
      viewport={viewport}
      onViewportChange={setViewport}
      indicatorTrack={indicatorTrack}
      onIndicatorTrackChange={setIndicatorTrack}
      onTriggerEnter={useCallbackRef(onTriggerEnter)}
      onTriggerLeave={useCallbackRef(onTriggerLeave)}
      onContentEnter={useCallbackRef(onContentEnter)}
      onContentLeave={useCallbackRef(onContentLeave)}
      onItemSelect={useCallbackRef(onItemSelect)}
      onItemDismiss={useCallbackRef(onItemDismiss)}
      onViewportContentChange={React.useCallback((contentValue, contentData) => {
        setViewportContent((prevContent) => {
          prevContent.set(contentValue, contentData);
          return new Map(prevContent);
        });
      }, [])}
      onViewportContentRemove={React.useCallback((contentValue) => {
        setViewportContent((prevContent) => {
          if (!prevContent.has(contentValue)) return prevContent;
          prevContent.delete(contentValue);
          return new Map(prevContent);
        });
      }, [])}
    >
      <Collection.Provider scope={scope}>
        <ViewportContentProvider scope={scope} items={viewportContent}>
          {children}
        </ViewportContentProvider>
      </Collection.Provider>
    </NavigationMenuProviderImpl>
  );
};

/* -------------------------------------------------------------------------------------------------
 * NavigationMenuList
 * -----------------------------------------------------------------------------------------------*/

const LIST_NAME = 'NavigationMenuList';

type NavigationMenuListElement = React.ComponentRef<typeof Primitive.ul>;
type PrimitiveUnorderedListProps = React.ComponentPropsWithoutRef<typeof Primitive.ul>;
interface NavigationMenuListProps extends PrimitiveUnorderedListProps {}

const NavigationMenuList = React.forwardRef<NavigationMenuListElement, NavigationMenuListProps>(
  (props: ScopedProps<NavigationMenuListProps>, forwardedRef) => {
    const { __scopeNavigationMenu, ...listProps } = props;
    const context = useNavigationMenuContext(LIST_NAME, __scopeNavigationMenu);

    const list = (
      <Primitive.ul data-orientation={context.orientation} {...listProps} ref={forwardedRef} />
    );

    return (
      <Primitive.div style={{ position: 'relative' }} ref={context.onIndicatorTrackChange}>
        <Collection.Slot scope={__scopeNavigationMenu}>
          {context.isRootMenu ? <FocusGroup asChild>{list}</FocusGroup> : list}
        </Collection.Slot>
      </Primitive.div>
    );
  },
);

NavigationMenuList.displayName = LIST_NAME;

/* -------------------------------------------------------------------------------------------------
 * NavigationMenuItem
 * -----------------------------------------------------------------------------------------------*/

const ITEM_NAME = 'NavigationMenuItem';

type FocusProxyElement = React.ComponentRef<typeof VisuallyHiddenPrimitive.Root>;

type NavigationMenuItemContextValue = {
  value: string;
  triggerRef: React.RefObject<NavigationMenuTriggerElement | null>;
  contentRef: React.RefObject<NavigationMenuContentElement | null>;
  focusProxyRef: React.RefObject<FocusProxyElement | null>;
  wasEscapeCloseRef: React.MutableRefObject<boolean>;
  onEntryKeyDown(): void;
  onFocusProxyEnter(side: 'start' | 'end'): void;
  onRootContentClose(): void;
  onContentFocusOutside(): void;
};

const [NavigationMenuItemContextProvider, useNavigationMenuItemContext] =
  createNavigationMenuContext<NavigationMenuItemContextValue>(ITEM_NAME);

type NavigationMenuItemElement = React.ComponentRef<typeof Primitive.li>;
type PrimitiveListItemProps = React.ComponentPropsWithoutRef<typeof Primitive.li>;
interface NavigationMenuItemProps extends PrimitiveListItemProps {
  value?: string;
}

const NavigationMenuItem = React.forwardRef<NavigationMenuItemElement, NavigationMenuItemProps>(
  (props: ScopedProps<NavigationMenuItemProps>, forwardedRef) => {
    const { __scopeNavigationMenu, value: valueProp, ...itemProps } = props;
    const autoValue = useId();
    // We need to provide an initial deterministic value as `useId` will return
    // empty string on the first render and we don't want to match our internal "closed" value.
    const value = valueProp || autoValue || 'LEGACY_REACT_AUTO_VALUE';
    const contentRef = React.useRef<NavigationMenuContentElement>(null);
    const triggerRef = React.useRef<NavigationMenuTriggerElement>(null);
    const focusProxyRef = React.useRef<FocusProxyElement>(null);
    const restoreContentTabOrderRef = React.useRef(() => {});
    const wasEscapeCloseRef = React.useRef(false);

    const handleContentEntry = React.useCallback((side = 'start') => {
      if (contentRef.current) {
        restoreContentTabOrderRef.current();
        const candidates = getTabbableCandidates(contentRef.current);
        if (candidates.length) focusFirst(side === 'start' ? candidates : candidates.reverse());
      }
    }, []);

    const handleContentExit = React.useCallback(() => {
      if (contentRef.current) {
        const candidates = getTabbableCandidates(contentRef.current);
        if (candidates.length) restoreContentTabOrderRef.current = removeFromTabOrder(candidates);
      }
    }, []);

    return (
      <NavigationMenuItemContextProvider
        scope={__scopeNavigationMenu}
        value={value}
        triggerRef={triggerRef}
        contentRef={contentRef}
        focusProxyRef={focusProxyRef}
        wasEscapeCloseRef={wasEscapeCloseRef}
        onEntryKeyDown={handleContentEntry}
        onFocusProxyEnter={handleContentEntry}
        onRootContentClose={handleContentExit}
        onContentFocusOutside={handleContentExit}
      >
        <Primitive.li {...itemProps} ref={forwardedRef} />
      </NavigationMenuItemContextProvider>
    );
  },
);

NavigationMenuItem.displayName = ITEM_NAME;

/* -------------------------------------------------------------------------------------------------
 * NavigationMenuTrigger
 * -----------------------------------------------------------------------------------------------*/

const TRIGGER_NAME = 'NavigationMenuTrigger';

type NavigationMenuTriggerElement = React.ComponentRef<typeof Primitive.button>;
type PrimitiveButtonProps = React.ComponentPropsWithoutRef<typeof Primitive.button>;
interface NavigationMenuTriggerProps extends PrimitiveButtonProps {}

const NavigationMenuTrigger = React.forwardRef<
  NavigationMenuTriggerElement,
  NavigationMenuTriggerProps
>((props: ScopedProps<NavigationMenuTriggerProps>, forwardedRef) => {
  const { __scopeNavigationMenu, disabled, ...triggerProps } = props;
  const context = useNavigationMenuContext(TRIGGER_NAME, props.__scopeNavigationMenu);
  const itemContext = useNavigationMenuItemContext(TRIGGER_NAME, props.__scopeNavigationMenu);
  const ref = React.useRef<NavigationMenuTriggerElement>(null);
  const composedRefs = useComposedRefs(ref, itemContext.triggerRef, forwardedRef);
  const triggerId = makeTriggerId(context.baseId, itemContext.value);
  const contentId = makeContentId(context.baseId, itemContext.value);
  const hasPointerMoveOpenedRef = React.useRef(false);
  const wasClickCloseRef = React.useRef(false);
  const open = itemContext.value === context.value;

  return (
    <>
      <Collection.ItemSlot scope={__scopeNavigationMenu} value={itemContext.value}>
        <FocusGroupItem asChild>
          <Primitive.button
            id={triggerId}
            disabled={disabled}
            data-disabled={disabled ? '' : undefined}
            data-state={getOpenState(open)}
            aria-expanded={open}
            aria-controls={contentId}
            {...triggerProps}
            ref={composedRefs}
            onPointerEnter={composeEventHandlers(props.onPointerEnter, () => {
              wasClickCloseRef.current = false;
              itemContext.wasEscapeCloseRef.current = false;
            })}
            onPointerMove={composeEventHandlers(
              props.onPointerMove,
              whenMouse(() => {
                if (
                  disabled ||
                  wasClickCloseRef.current ||
                  itemContext.wasEscapeCloseRef.current ||
                  hasPointerMoveOpenedRef.current
                )
                  return;
                context.onTriggerEnter(itemContext.value);
                hasPointerMoveOpenedRef.current = true;
              }),
            )}
            onPointerLeave={composeEventHandlers(
              props.onPointerLeave,
              whenMouse(() => {
                if (disabled) return;
                context.onTriggerLeave();
                hasPointerMoveOpenedRef.current = false;
              }),
            )}
            onClick={composeEventHandlers(props.onClick, () => {
              context.onItemSelect(itemContext.value);
              wasClickCloseRef.current = open;
            })}
            onKeyDown={composeEventHandlers(props.onKeyDown, (event) => {
              const verticalEntryKey = context.dir === 'rtl' ? 'ArrowLeft' : 'ArrowRight';
              const entryKey = { horizontal: 'ArrowDown', vertical: verticalEntryKey }[
                context.orientation
              ];
              if (open && event.key === entryKey) {
                itemContext.onEntryKeyDown();
                // Prevent FocusGroupItem from handling the event
                event.preventDefault();
              }
            })}
          />
        </FocusGroupItem>
      </Collection.ItemSlot>

      {/* Proxy tab order between trigger and content */}
      {open && (
        <>
          <VisuallyHiddenPrimitive.Root
            aria-hidden
            tabIndex={0}
            ref={itemContext.focusProxyRef}
            onFocus={(event) => {
              const content = itemContext.contentRef.current;
              const prevFocusedElement = event.relatedTarget as HTMLElement | null;
              const wasTriggerFocused = prevFocusedElement === ref.current;
              const wasFocusFromContent = content?.contains(prevFocusedElement);

              if (wasTriggerFocused || !wasFocusFromContent) {
                itemContext.onFocusProxyEnter(wasTriggerFocused ? 'start' : 'end');
              }
            }}
          />

          {/* Restructure a11y tree to make content accessible to screen reader when using the viewport */}
          {context.viewport && <span aria-owns={contentId} />}
        </>
      )}
    </>
  );
});

NavigationMenuTrigger.displayName = TRIGGER_NAME;

/* -------------------------------------------------------------------------------------------------
 * NavigationMenuLink
 * -----------------------------------------------------------------------------------------------*/

const LINK_NAME = 'NavigationMenuLink';
const LINK_SELECT = 'navigationMenu.linkSelect';

type NavigationMenuLinkElement = React.ComponentRef<typeof Primitive.a>;
type PrimitiveLinkProps = React.ComponentPropsWithoutRef<typeof Primitive.a>;
interface NavigationMenuLinkProps extends Omit<PrimitiveLinkProps, 'onSelect'> {
  active?: boolean;
  onSelect?: (event: Event) => void;
}

const NavigationMenuLink = React.forwardRef<NavigationMenuLinkElement, NavigationMenuLinkProps>(
  (props: ScopedProps<NavigationMenuLinkProps>, forwardedRef) => {
    const { __scopeNavigationMenu, active, onSelect, ...linkProps } = props;

    return (
      <FocusGroupItem asChild>
        <Primitive.a
          data-active={active ? '' : undefined}
          aria-current={active ? 'page' : undefined}
          {...linkProps}
          ref={forwardedRef}
          onClick={composeEventHandlers(
            props.onClick,
            (event) => {
              const target = event.target as HTMLElement;
              const linkSelectEvent = new CustomEvent(LINK_SELECT, {
                bubbles: true,
                cancelable: true,
              });
              target.addEventListener(LINK_SELECT, (event) => onSelect?.(event), { once: true });
              dispatchDiscreteCustomEvent(target, linkSelectEvent);

              if (!linkSelectEvent.defaultPrevented && !event.metaKey) {
                const rootContentDismissEvent = new CustomEvent(ROOT_CONTENT_DISMISS, {
                  bubbles: true,
                  cancelable: true,
                });
                dispatchDiscreteCustomEvent(target, rootContentDismissEvent);
              }
            },
            { checkForDefaultPrevented: false },
          )}
        />
      </FocusGroupItem>
    );
  },
);

NavigationMenuLink.displayName = LINK_NAME;

/* -------------------------------------------------------------------------------------------------
 * NavigationMenuIndicator
 * -----------------------------------------------------------------------------------------------*/

const INDICATOR_NAME = 'NavigationMenuIndicator';

type NavigationMenuIndicatorElement = NavigationMenuIndicatorImplElement;
interface NavigationMenuIndicatorProps extends NavigationMenuIndicatorImplProps {
  /**
   * Used to force mounting when more control is needed. Useful when
   * controlling animation with React animation libraries.
   */
  forceMount?: true;
}

const NavigationMenuIndicator = React.forwardRef<
  NavigationMenuIndicatorElement,
  NavigationMenuIndicatorProps
>((props: ScopedProps<NavigationMenuIndicatorProps>, forwardedRef) => {
  const { forceMount, ...indicatorProps } = props;
  const context = useNavigationMenuContext(INDICATOR_NAME, props.__scopeNavigationMenu);
  const isVisible = Boolean(context.value);

  return context.indicatorTrack
    ? ReactDOM.createPortal(
        <Presence present={forceMount || isVisible}>
          <NavigationMenuIndicatorImpl {...indicatorProps} ref={forwardedRef} />
        </Presence>,
        context.indicatorTrack,
      )
    : null;
});

NavigationMenuIndicator.displayName = INDICATOR_NAME;

type NavigationMenuIndicatorImplElement = React.ComponentRef<typeof Primitive.div>;
interface NavigationMenuIndicatorImplProps extends PrimitiveDivProps {}

const NavigationMenuIndicatorImpl = React.forwardRef<
  NavigationMenuIndicatorImplElement,
  NavigationMenuIndicatorImplProps
>((props: ScopedProps<NavigationMenuIndicatorImplProps>, forwardedRef) => {
  const { __scopeNavigationMenu, ...indicatorProps } = props;
  const context = useNavigationMenuContext(INDICATOR_NAME, __scopeNavigationMenu);
  const getItems = useCollection(__scopeNavigationMenu);
  const [activeTrigger, setActiveTrigger] = React.useState<NavigationMenuTriggerElement | null>(
    null,
  );
  const [position, setPosition] = React.useState<{ size: number; offset: number } | null>(null);
  const isHorizontal = context.orientation === 'horizontal';
  const isVisible = Boolean(context.value);

  React.useEffect(() => {
    const items = getItems();
    const triggerNode = items.find((item) => item.value === context.value)?.ref.current;
    if (triggerNode) setActiveTrigger(triggerNode);
  }, [getItems, context.value]);

  /**
   * Update position when the indicator or parent track size changes
   */
  const handlePositionChange = () => {
    if (activeTrigger) {
      setPosition({
        size: isHorizontal ? activeTrigger.offsetWidth : activeTrigger.offsetHeight,
        offset: isHorizontal ? activeTrigger.offsetLeft : activeTrigger.offsetTop,
      });
    }
  };
  useResizeObserver(activeTrigger, handlePositionChange);
  useResizeObserver(context.indicatorTrack, handlePositionChange);

  // We need to wait for the indicator position to be available before rendering to
  // snap immediately into position rather than transitioning from initial
  return position ? (
    <Primitive.div
      aria-hidden
      data-state={isVisible ? 'visible' : 'hidden'}
      data-orientation={context.orientation}
      {...indicatorProps}
      ref={forwardedRef}
      style={{
        position: 'absolute',
        ...(isHorizontal
          ? {
              left: 0,
              width: position.size + 'px',
              transform: `translateX(${position.offset}px)`,
            }
          : {
              top: 0,
              height: position.size + 'px',
              transform: `translateY(${position.offset}px)`,
            }),
        ...indicatorProps.style,
      }}
    />
  ) : null;
});

/* -------------------------------------------------------------------------------------------------
 * NavigationMenuContent
 * -----------------------------------------------------------------------------------------------*/

const CONTENT_NAME = 'NavigationMenuContent';

type NavigationMenuContentElement = NavigationMenuContentImplElement;
interface NavigationMenuContentProps
  extends Omit<NavigationMenuContentImplProps, keyof NavigationMenuContentImplPrivateProps> {
  /**
   * Used to force mounting when more control is needed. Useful when
   * controlling animation with React animation libraries.
   */
  forceMount?: true;
}

const NavigationMenuContent = React.forwardRef<
  NavigationMenuContentElement,
  NavigationMenuContentProps
>((props: ScopedProps<NavigationMenuContentProps>, forwardedRef) => {
  const { forceMount, ...contentProps } = props;
  const context = useNavigationMenuContext(CONTENT_NAME, props.__scopeNavigationMenu);
  const itemContext = useNavigationMenuItemContext(CONTENT_NAME, props.__scopeNavigationMenu);
  const composedRefs = useComposedRefs(itemContext.contentRef, forwardedRef);
  const open = itemContext.value === context.value;

  const commonProps = {
    value: itemContext.value,
    triggerRef: itemContext.triggerRef,
    focusProxyRef: itemContext.focusProxyRef,
    wasEscapeCloseRef: itemContext.wasEscapeCloseRef,
    onContentFocusOutside: itemContext.onContentFocusOutside,
    onRootContentClose: itemContext.onRootContentClose,
    ...contentProps,
  };

  return !context.viewport ? (
    <Presence present={forceMount || open}>
      <NavigationMenuContentImpl
        data-state={getOpenState(open)}
        {...commonProps}
        ref={composedRefs}
        onPointerEnter={composeEventHandlers(props.onPointerEnter, context.onContentEnter)}
        onPointerLeave={composeEventHandlers(
          props.onPointerLeave,
          whenMouse(context.onContentLeave),
        )}
        style={{
          // Prevent interaction when animating out
          pointerEvents: !open && context.isRootMenu ? 'none' : undefined,
          ...commonProps.style,
        }}
      />
    </Presence>
  ) : (
    <ViewportContentMounter forceMount={forceMount} {...commonProps} ref={composedRefs} />
  );
});

NavigationMenuContent.displayName = CONTENT_NAME;

/* -----------------------------------------------------------------------------------------------*/

type ViewportContentMounterElement = NavigationMenuContentImplElement;
interface ViewportContentMounterProps extends NavigationMenuContentImplProps {
  /**
   * Used to force mounting when more control is needed. Useful when
   * controlling animation with React animation libraries.
   */
  forceMount?: true;
}

const ViewportContentMounter = React.forwardRef<
  ViewportContentMounterElement,
  ViewportContentMounterProps
>((props: ScopedProps<ViewportContentMounterProps>, forwardedRef) => {
  const context = useNavigationMenuContext(CONTENT_NAME, props.__scopeNavigationMenu);
  const { onViewportContentChange, onViewportContentRemove } = context;

  useLayoutEffect(() => {
    onViewportContentChange(props.value, {
      ref: forwardedRef,
      ...props,
    });
  }, [props, forwardedRef, onViewportContentChange]);

  useLayoutEffect(() => {
    return () => onViewportContentRemove(props.value);
  }, [props.value, onViewportContentRemove]);

  // Content is proxied into the viewport
  return null;
});

/* -----------------------------------------------------------------------------------------------*/

const ROOT_CONTENT_DISMISS = 'navigationMenu.rootContentDismiss';

type MotionAttribute = 'to-start' | 'to-end' | 'from-start' | 'from-end';
type NavigationMenuContentImplElement = React.ComponentRef<typeof DismissableLayer>;
type DismissableLayerProps = React.ComponentPropsWithoutRef<typeof DismissableLayer>;

interface NavigationMenuContentImplPrivateProps {
  value: string;
  triggerRef: React.RefObject<NavigationMenuTriggerElement | null>;
  focusProxyRef: React.RefObject<FocusProxyElement | null>;
  wasEscapeCloseRef: React.MutableRefObject<boolean>;
  onContentFocusOutside(): void;
  onRootContentClose(): void;
}
interface NavigationMenuContentImplProps
  extends Omit<DismissableLayerProps, 'onDismiss' | 'disableOutsidePointerEvents'>,
    NavigationMenuContentImplPrivateProps {}

const NavigationMenuContentImpl = React.forwardRef<
  NavigationMenuContentImplElement,
  NavigationMenuContentImplProps
>((props: ScopedProps<NavigationMenuContentImplProps>, forwardedRef) => {
  const {
    __scopeNavigationMenu,
    value,
    triggerRef,
    focusProxyRef,
    wasEscapeCloseRef,
    onRootContentClose,
    onContentFocusOutside,
    ...contentProps
  } = props;
  const context = useNavigationMenuContext(CONTENT_NAME, __scopeNavigationMenu);
  const ref = React.useRef<NavigationMenuContentImplElement>(null);
  const composedRefs = useComposedRefs(ref, forwardedRef);
  const triggerId = makeTriggerId(context.baseId, value);
  const contentId = makeContentId(context.baseId, value);
  const getItems = useCollection(__scopeNavigationMenu);
  const prevMotionAttributeRef = React.useRef<MotionAttribute | null>(null);

  const { onItemDismiss } = context;

  React.useEffect(() => {
    const content = ref.current;

    // Bubble dismiss to the root content node and focus its trigger
    if (context.isRootMenu && content) {
      const handleClose = () => {
        onItemDismiss();
        onRootContentClose();
        if (content.contains(document.activeElement)) triggerRef.current?.focus();
      };
      content.addEventListener(ROOT_CONTENT_DISMISS, handleClose);
      return () => content.removeEventListener(ROOT_CONTENT_DISMISS, handleClose);
    }
  }, [context.isRootMenu, props.value, triggerRef, onItemDismiss, onRootContentClose]);

  const motionAttribute = React.useMemo(() => {
    const items = getItems();
    const values = items.map((item) => item.value);
    if (context.dir === 'rtl') values.reverse();
    const index = values.indexOf(context.value);
    const prevIndex = values.indexOf(context.previousValue);
    const isSelected = value === context.value;
    const wasSelected = prevIndex === values.indexOf(value);

    // We only want to update selected and the last selected content
    // this avoids animations being interrupted outside of that range
    if (!isSelected && !wasSelected) return prevMotionAttributeRef.current;

    const attribute = (() => {
      // Don't provide a direction on the initial open
      if (index !== prevIndex) {
        // If we're moving to this item from another
        if (isSelected && prevIndex !== -1) return index > prevIndex ? 'from-end' : 'from-start';
        // If we're leaving this item for another
        if (wasSelected && index !== -1) return index > prevIndex ? 'to-start' : 'to-end';
      }
      // Otherwise we're entering from closed or leaving the list
      // entirely and should not animate in any direction
      return null;
    })();

    prevMotionAttributeRef.current = attribute;
    return attribute;
  }, [context.previousValue, context.value, context.dir, getItems, value]);

  return (
    <FocusGroup asChild>
      <DismissableLayer
        id={contentId}
        aria-labelledby={triggerId}
        data-motion={motionAttribute}
        data-orientation={context.orientation}
        {...contentProps}
        ref={composedRefs}
        disableOutsidePointerEvents={false}
        onDismiss={() => {
          const rootContentDismissEvent = new Event(ROOT_CONTENT_DISMISS, {
            bubbles: true,
            cancelable: true,
          });
          ref.current?.dispatchEvent(rootContentDismissEvent);
        }}
        onFocusOutside={composeEventHandlers(props.onFocusOutside, (event) => {
          onContentFocusOutside();
          const target = event.target as HTMLElement;
          // Only dismiss content when focus moves outside of the menu
          if (context.rootNavigationMenu?.contains(target)) event.preventDefault();
        })}
        onPointerDownOutside={composeEventHandlers(props.onPointerDownOutside, (event) => {
          const target = event.target as HTMLElement;
          const isTrigger = getItems().some((item) => item.ref.current?.contains(target));
          const isRootViewport = context.isRootMenu && context.viewport?.contains(target);
          if (isTrigger || isRootViewport || !context.isRootMenu) event.preventDefault();
        })}
        onKeyDown={composeEventHandlers(props.onKeyDown, (event) => {
          const isMetaKey = event.altKey || event.ctrlKey || event.metaKey;
          const isTabKey = event.key === 'Tab' && !isMetaKey;
          if (isTabKey) {
            const candidates = getTabbableCandidates(event.currentTarget);
            const focusedElement = document.activeElement;
            const index = candidates.findIndex((candidate) => candidate === focusedElement);
            const isMovingBackwards = event.shiftKey;
            const nextCandidates = isMovingBackwards
              ? candidates.slice(0, index).reverse()
              : candidates.slice(index + 1, candidates.length);

            if (focusFirst(nextCandidates)) {
              // prevent browser tab keydown because we've handled focus
              event.preventDefault();
            } else {
              // If we can't focus that means we're at the edges
              // so focus the proxy and let browser handle
              // tab/shift+tab keypress on the proxy instead
              focusProxyRef.current?.focus();
            }
          }
        })}
        onEscapeKeyDown={composeEventHandlers(props.onEscapeKeyDown, (_event) => {
          // prevent the dropdown from reopening
          // after the escape key has been pressed
          wasEscapeCloseRef.current = true;
        })}
      />
    </FocusGroup>
  );
});

/* -------------------------------------------------------------------------------------------------
 * NavigationMenuViewport
 * -----------------------------------------------------------------------------------------------*/

const VIEWPORT_NAME = 'NavigationMenuViewport';

type NavigationMenuViewportElement = NavigationMenuViewportImplElement;
interface NavigationMenuViewportProps
  extends Omit<NavigationMenuViewportImplProps, 'activeContentValue'> {
  /**
   * Used to force mounting when more control is needed. Useful when
   * controlling animation with React animation libraries.
   */
  forceMount?: true;
}

const NavigationMenuViewport = React.forwardRef<
  NavigationMenuViewportElement,
  NavigationMenuViewportProps
>((props: ScopedProps<NavigationMenuViewportProps>, forwardedRef) => {
  const { forceMount, ...viewportProps } = props;
  const context = useNavigationMenuContext(VIEWPORT_NAME, props.__scopeNavigationMenu);
  const open = Boolean(context.value);

  return (
    <Presence present={forceMount || open}>
      <NavigationMenuViewportImpl {...viewportProps} ref={forwardedRef} />
    </Presence>
  );
});

NavigationMenuViewport.displayName = VIEWPORT_NAME;

/* -----------------------------------------------------------------------------------------------*/

type NavigationMenuViewportImplElement = React.ComponentRef<typeof Primitive.div>;
interface NavigationMenuViewportImplProps extends PrimitiveDivProps {}

const NavigationMenuViewportImpl = React.forwardRef<
  NavigationMenuViewportImplElement,
  NavigationMenuViewportImplProps
>((props: ScopedProps<NavigationMenuViewportImplProps>, forwardedRef) => {
  const { __scopeNavigationMenu, children, ...viewportImplProps } = props;
  const context = useNavigationMenuContext(VIEWPORT_NAME, __scopeNavigationMenu);
  const composedRefs = useComposedRefs(forwardedRef, context.onViewportChange);
  const viewportContentContext = useViewportContentContext(
    CONTENT_NAME,
    props.__scopeNavigationMenu,
  );
  const [size, setSize] = React.useState<{ width: number; height: number } | null>(null);
  const [content, setContent] = React.useState<NavigationMenuContentElement | null>(null);
  const viewportWidth = size ? size?.width + 'px' : undefined;
  const viewportHeight = size ? size?.height + 'px' : undefined;
  const open = Boolean(context.value);
  // We persist the last active content value as the viewport may be animating out
  // and we want the content to remain mounted for the lifecycle of the viewport.
  const activeContentValue = open ? context.value : context.previousValue;

  /**
   * Update viewport size to match the active content node.
   * We prefer offset dimensions over `getBoundingClientRect` as the latter respects CSS transform.
   * For example, if content animates in from `scale(0.5)` the dimensions would be anything
   * from `0.5` to `1` of the intended size.
   */
  const handleSizeChange = () => {
    if (content) setSize({ width: content.offsetWidth, height: content.offsetHeight });
  };
  useResizeObserver(content, handleSizeChange);

  return (
    <Primitive.div
      data-state={getOpenState(open)}
      data-orientation={context.orientation}
      {...viewportImplProps}
      ref={composedRefs}
      style={{
        // Prevent interaction when animating out
        pointerEvents: !open && context.isRootMenu ? 'none' : undefined,
        ['--radix-navigation-menu-viewport-width' as any]: viewportWidth,
        ['--radix-navigation-menu-viewport-height' as any]: viewportHeight,
        ...viewportImplProps.style,
      }}
      onPointerEnter={composeEventHandlers(props.onPointerEnter, context.onContentEnter)}
      onPointerLeave={composeEventHandlers(props.onPointerLeave, whenMouse(context.onContentLeave))}
    >
      {Array.from(viewportContentContext.items).map(([value, { ref, forceMount, ...props }]) => {
        const isActive = activeContentValue === value;
        return (
          <Presence key={value} present={forceMount || isActive}>
            <NavigationMenuContentImpl
              {...props}
              ref={composeRefs(ref, (node) => {
                // We only want to update the stored node when another is available
                // as we need to smoothly transition between them.
                if (isActive && node) setContent(node);
              })}
            />
          </Presence>
        );
      })}
    </Primitive.div>
  );
});

/* -----------------------------------------------------------------------------------------------*/

const FOCUS_GROUP_NAME = 'FocusGroup';

type FocusGroupElement = React.ComponentRef<typeof Primitive.div>;
interface FocusGroupProps extends PrimitiveDivProps {}

const FocusGroup = React.forwardRef<FocusGroupElement, FocusGroupProps>(
  (props: ScopedProps<FocusGroupProps>, forwardedRef) => {
    const { __scopeNavigationMenu, ...groupProps } = props;
    const context = useNavigationMenuContext(FOCUS_GROUP_NAME, __scopeNavigationMenu);

    return (
      <FocusGroupCollection.Provider scope={__scopeNavigationMenu}>
        <FocusGroupCollection.Slot scope={__scopeNavigationMenu}>
          <Primitive.div dir={context.dir} {...groupProps} ref={forwardedRef} />
        </FocusGroupCollection.Slot>
      </FocusGroupCollection.Provider>
    );
  },
);

/* -----------------------------------------------------------------------------------------------*/

const ARROW_KEYS = ['ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown'];
const FOCUS_GROUP_ITEM_NAME = 'FocusGroupItem';

type FocusGroupItemElement = React.ComponentRef<typeof Primitive.button>;
interface FocusGroupItemProps extends PrimitiveButtonProps {}

const FocusGroupItem = React.forwardRef<FocusGroupItemElement, FocusGroupItemProps>(
  (props: ScopedProps<FocusGroupItemProps>, forwardedRef) => {
    const { __scopeNavigationMenu, ...groupProps } = props;
    const getItems = useFocusGroupCollection(__scopeNavigationMenu);
    const context = useNavigationMenuContext(FOCUS_GROUP_ITEM_NAME, __scopeNavigationMenu);

    return (
      <FocusGroupCollection.ItemSlot scope={__scopeNavigationMenu}>
        <Primitive.button
          {...groupProps}
          ref={forwardedRef}
          onKeyDown={composeEventHandlers(props.onKeyDown, (event) => {
            const isFocusNavigationKey = ['Home', 'End', ...ARROW_KEYS].includes(event.key);
            if (isFocusNavigationKey) {
              let candidateNodes = getItems().map((item) => item.ref.current!);
              const prevItemKey = context.dir === 'rtl' ? 'ArrowRight' : 'ArrowLeft';
              const prevKeys = [prevItemKey, 'ArrowUp', 'End'];
              if (prevKeys.includes(event.key)) candidateNodes.reverse();
              if (ARROW_KEYS.includes(event.key)) {
                const currentIndex = candidateNodes.indexOf(event.currentTarget);
                candidateNodes = candidateNodes.slice(currentIndex + 1);
              }
              /**
               * Imperative focus during keydown is risky so we prevent React's batching updates
               * to avoid potential bugs. See: https://github.com/facebook/react/issues/20332
               */
              setTimeout(() => focusFirst(candidateNodes));

              // Prevent page scroll while navigating
              event.preventDefault();
            }
          })}
        />
      </FocusGroupCollection.ItemSlot>
    );
  },
);

/**
 * Returns a list of potential tabbable candidates.
 *
 * NOTE: This is only a close approximation. For example it doesn't take into account cases like when
 * elements are not visible. This cannot be worked out easily by just reading a property, but rather
 * necessitate runtime knowledge (computed styles, etc). We deal with these cases separately.
 *
 * See: https://developer.mozilla.org/en-US/docs/Web/API/TreeWalker
 * Credit: https://github.com/discord/focus-layers/blob/master/src/util/wrapFocus.tsx#L1
 */
function getTabbableCandidates(container: HTMLElement) {
  const nodes: HTMLElement[] = [];
  const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, {
    acceptNode: (node: any) => {
      const isHiddenInput = node.tagName === 'INPUT' && node.type === 'hidden';
      if (node.disabled || node.hidden || isHiddenInput) return NodeFilter.FILTER_SKIP;
      // `.tabIndex` is not the same as the `tabindex` attribute. It works on the
      // runtime's understanding of tabbability, so this automatically accounts
      // for any kind of element that could be tabbed to.
      return node.tabIndex >= 0 ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
    },
  });
  while (walker.nextNode()) nodes.push(walker.currentNode as HTMLElement);
  // we do not take into account the order of nodes with positive `tabIndex` as it
  // hinders accessibility to have tab order different from visual order.
  return nodes;
}

function focusFirst(candidates: HTMLElement[]) {
  const previouslyFocusedElement = document.activeElement;
  return candidates.some((candidate) => {
    // if focus is already where we want to go, we don't want to keep going through the candidates
    if (candidate === previouslyFocusedElement) return true;
    candidate.focus();
    return document.activeElement !== previouslyFocusedElement;
  });
}

function removeFromTabOrder(candidates: HTMLElement[]) {
  candidates.forEach((candidate) => {
    candidate.dataset.tabindex = candidate.getAttribute('tabindex') || '';
    candidate.setAttribute('tabindex', '-1');
  });
  return () => {
    candidates.forEach((candidate) => {
      const prevTabIndex = candidate.dataset.tabindex as string;
      candidate.setAttribute('tabindex', prevTabIndex);
    });
  };
}

function useResizeObserver(element: HTMLElement | null, onResize: () => void) {
  const handleResize = useCallbackRef(onResize);
  useLayoutEffect(() => {
    let rAF = 0;
    if (element) {
      /**
       * Resize Observer will throw an often benign error that says `ResizeObserver loop
       * completed with undelivered notifications`. This means that ResizeObserver was not
       * able to deliver all observations within a single animation frame, so we use
       * `requestAnimationFrame` to ensure we don't deliver unnecessary observations.
       * Further reading: https://github.com/WICG/resize-observer/issues/38
       */
      const resizeObserver = new ResizeObserver(() => {
        cancelAnimationFrame(rAF);
        rAF = window.requestAnimationFrame(handleResize);
      });
      resizeObserver.observe(element);
      return () => {
        window.cancelAnimationFrame(rAF);
        resizeObserver.unobserve(element);
      };
    }
  }, [element, handleResize]);
}

function getOpenState(open: boolean) {
  return open ? 'open' : 'closed';
}

function makeTriggerId(baseId: string, value: string) {
  return `${baseId}-trigger-${value}`;
}

function makeContentId(baseId: string, value: string) {
  return `${baseId}-content-${value}`;
}

function whenMouse<E>(handler: React.PointerEventHandler<E>): React.PointerEventHandler<E> {
  return (event) => (event.pointerType === 'mouse' ? handler(event) : undefined);
}

/* -----------------------------------------------------------------------------------------------*/

const Root = NavigationMenu;
const Sub = NavigationMenuSub;
const List = NavigationMenuList;
const Item = NavigationMenuItem;
const Trigger = NavigationMenuTrigger;
const Link = NavigationMenuLink;
const Indicator = NavigationMenuIndicator;
const Content = NavigationMenuContent;
const Viewport = NavigationMenuViewport;

export {
  createNavigationMenuScope,
  //
  NavigationMenu,
  NavigationMenuSub,
  NavigationMenuList,
  NavigationMenuItem,
  NavigationMenuTrigger,
  NavigationMenuLink,
  NavigationMenuIndicator,
  NavigationMenuContent,
  NavigationMenuViewport,
  //
  Root,
  Sub,
  List,
  Item,
  Trigger,
  Link,
  Indicator,
  Content,
  Viewport,
};
export type {
  NavigationMenuProps,
  NavigationMenuSubProps,
  NavigationMenuListProps,
  NavigationMenuItemProps,
  NavigationMenuTriggerProps,
  NavigationMenuLinkProps,
  NavigationMenuIndicatorProps,
  NavigationMenuContentProps,
  NavigationMenuViewportProps,
};



================================================
FILE: packages/react/one-time-password-field/README.md
================================================
# `react-one-time-password-field`

## Installation

```sh
$ yarn add radix-ui
# or
$ npm install radix-ui
```

## Usage

View docs [here](https://radix-ui.com/primitives/docs/components/one-time-password-field).



================================================
FILE: packages/react/one-time-password-field/CHANGELOG.md
================================================
# @radix-ui/react-one-time-password-field

## 0.1.8

- Fixed a bug so that all input elements are disabled when the `Root` component is disabled
- Fixed a bug with iOS Chrome autocomplete (#3641)
- Updated dependencies: `@radix-ui/primitive@1.1.3`, `@radix-ui/react-context@1.1.3`, `@radix-ui/react-collection@1.1.8`, `@radix-ui/react-primitive@2.1.4`, `@radix-ui/react-roving-focus@1.1.11`

## 0.1.7

- Updated dependencies: `@radix-ui/react-roving-focus@1.1.10`, `@radix-ui/react-collection@1.1.7`, `@radix-ui/react-primitive@2.1.3`

## 0.1.6

- Updated dependencies: `@radix-ui/react-collection@1.1.6`, `@radix-ui/react-primitive@2.1.2`, `@radix-ui/react-roving-focus@1.1.9`

## 0.1.5

- - Update default input type to `text` and pass to the underlying input element ([#3510](https://github.com/radix-ui/primitives/pull/3510))
- Updated dependencies: `@radix-ui/react-collection@1.1.5`, `@radix-ui/react-primitive@2.1.1`, `@radix-ui/react-roving-focus@1.1.8`

## 0.1.4

- Updated dependencies: `@radix-ui/react-use-is-hydrated@0.1.0`

## 0.1.3

- Fix hydration mismatch error in `OneTimePasswordField` and add opt-in `index` prop
- Updated dependencies: `@radix-ui/react-roving-focus@1.1.7`

## 0.1.2

- Updated dependencies: `@radix-ui/react-use-effect-event@0.0.2`, `@radix-ui/react-use-controllable-state@1.2.2`, `@radix-ui/react-roving-focus@1.1.6`

## 0.1.1

- Updated dependencies: `@radix-ui/react-use-effect-event@0.0.1`, `@radix-ui/react-use-controllable-state@1.2.1`, `@radix-ui/react-roving-focus@1.1.5`

## 0.1.0

### Introduce new One Time Password Field primitive

This new primitive is designed to implement the common design pattern for one-time password fields displayed as separate input fields for each character. This UI is deceptively complex to implement so that interactions follow user expectations. The new primitive handles all of this complexity for you, including:

- Keyboard navigation mimicking the behavior of a single input field
- Overriding values on paste
- Password manager autofill support
- Input validation for numeric and alphanumeric values
- Auto-submit on completion
- Focus management
- Hidden input to provide a single value to form data

### Other updates

- Updated dependencies: `@radix-ui/react-collection@1.1.4`, `@radix-ui/react-use-controllable-state@1.2.0`, `@radix-ui/react-roving-focus@1.1.4`, `@radix-ui/react-primitive@2.1.0`



================================================
FILE: packages/react/one-time-password-field/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/one-time-password-field/package.json
================================================
{
  "name": "@radix-ui/react-one-time-password-field",
  "version": "0.1.8",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "src",
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/primitive": "workspace:*",
    "@radix-ui/react-collection": "workspace:*",
    "@radix-ui/react-compose-refs": "workspace:*",
    "@radix-ui/react-context": "workspace:*",
    "@radix-ui/react-direction": "workspace:*",
    "@radix-ui/number": "workspace:*",
    "@radix-ui/react-primitive": "workspace:*",
    "@radix-ui/react-roving-focus": "workspace:*",
    "@radix-ui/react-use-controllable-state": "workspace:*",
    "@radix-ui/react-use-effect-event": "workspace:*",
    "@radix-ui/react-use-is-hydrated": "workspace:*",
    "@radix-ui/react-use-layout-effect": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/one-time-password-field/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/one-time-password-field/src/index.ts
================================================
'use client';
export type {
  OneTimePasswordFieldProps,
  OneTimePasswordFieldInputProps,
  OneTimePasswordFieldHiddenInputProps,
  InputValidationType,
} from './one-time-password-field';
export {
  OneTimePasswordField,
  OneTimePasswordFieldInput,
  OneTimePasswordFieldHiddenInput,
  //
  Root,
  Input,
  HiddenInput,
} from './one-time-password-field';



================================================
FILE: packages/react/one-time-password-field/src/one-time-password-field.test.tsx
================================================
import { axe } from 'vitest-axe';
import type { RenderResult } from '@testing-library/react';
import { act, cleanup, render, screen, fireEvent } from '@testing-library/react';
import * as OneTimePasswordField from './one-time-password-field';
import { afterEach, describe, it, beforeEach, expect } from 'vitest';
import { userEvent, type UserEvent } from '@testing-library/user-event';

describe('given a default OneTimePasswordField', () => {
  let rendered: RenderResult;
  let user: UserEvent;

  afterEach(cleanup);

  beforeEach(() => {
    user = userEvent.setup();
    rendered = render(
      <OneTimePasswordField.Root>
        <OneTimePasswordField.Input />
        <OneTimePasswordField.Input />
        <OneTimePasswordField.Input />
        <OneTimePasswordField.Input />
        <OneTimePasswordField.Input />
        <OneTimePasswordField.Input />
        <OneTimePasswordField.HiddenInput name="code" />
      </OneTimePasswordField.Root>,
    );
  });

  afterEach(cleanup);

  it('should have no accessibility violations', async () => {
    expect(await axe(rendered.container)).toHaveNoViolations();
  });

  it('should mask input value when type is password', async () => {
    rendered.rerender(
      <OneTimePasswordField.Root type="password">
        <OneTimePasswordField.Input />
        <OneTimePasswordField.HiddenInput name="code" />
      </OneTimePasswordField.Root>,
    );

    const input = rendered.container.querySelector(
      'input:not([type="hidden"])',
    ) as HTMLInputElement;

    await userEvent.type(input, '1');
    expect(input.type).toBe('password');

    const hiddenInput = rendered.container.querySelector(
      'input[type="hidden"]',
    ) as HTMLInputElement;
    expect(hiddenInput.value).toBe('1');
  });

  it('should disable all inputs when Root is disabled', () => {
    rendered.rerender(
      <OneTimePasswordField.Root disabled>
        <OneTimePasswordField.Input />
        <OneTimePasswordField.Input />
        <OneTimePasswordField.HiddenInput name="code" />
      </OneTimePasswordField.Root>,
    );

    const inputs = rendered.container.querySelectorAll('input:not([type="hidden"])');
    inputs.forEach((input) => {
      expect(input).toBeDisabled();
    });
  });

  // TODO: userEvent paste not behaving as expected. Debug and unskip.
  // Replicated in storybook for now.
  it.todo('pastes the code into the input', async () => {
    const inputs = screen.getAllByRole<HTMLInputElement>('textbox', {
      hidden: false,
    });
    const firstInput = inputs[0]!;
    fireEvent.click(firstInput);
    await act(async () => await user.paste('1,2,3,4,5,6'));
    expect(getInputValues(inputs)).toBe('1,2,3,4,5,6');
  });
});

function getInputValues(inputs: HTMLInputElement[]) {
  return inputs.map((input) => input.value).join(',');
}



================================================
FILE: packages/react/one-time-password-field/src/one-time-password-field.tsx
================================================
import * as Primitive from '@radix-ui/react-primitive';
import { useComposedRefs } from '@radix-ui/react-compose-refs';
import { useControllableState } from '@radix-ui/react-use-controllable-state';
import { composeEventHandlers } from '@radix-ui/primitive';
import { unstable_createCollection as createCollection } from '@radix-ui/react-collection';
import * as RovingFocusGroup from '@radix-ui/react-roving-focus';
import { createRovingFocusGroupScope } from '@radix-ui/react-roving-focus';
import { useIsHydrated } from '@radix-ui/react-use-is-hydrated';
import * as React from 'react';
import { flushSync } from 'react-dom';
import type { Scope } from '@radix-ui/react-context';
import { createContextScope } from '@radix-ui/react-context';
import { useDirection } from '@radix-ui/react-direction';
import { clamp } from '@radix-ui/number';
import { useEffectEvent } from '@radix-ui/react-use-effect-event';

type InputValidationType = 'alpha' | 'numeric' | 'alphanumeric' | 'none';

const INPUT_VALIDATION_MAP = {
  numeric: {
    type: 'numeric',
    regexp: /[^\d]/g,
    pattern: '\\d{1}',
    inputMode: 'numeric',
  },
  alpha: {
    type: 'alpha',
    regexp: /[^a-zA-Z]/g,
    pattern: '[a-zA-Z]{1}',
    inputMode: 'text',
  },
  alphanumeric: {
    type: 'alphanumeric',
    regexp: /[^a-zA-Z0-9]/g,
    pattern: '[a-zA-Z0-9]{1}',
    inputMode: 'text',
  },
  none: null,
} satisfies InputValidation;

/* -------------------------------------------------------------------------------------------------
 * OneTimePasswordFieldProvider
 * -----------------------------------------------------------------------------------------------*/

type RovingFocusGroupProps = RovingFocusGroup.RovingFocusGroupProps;

interface OneTimePasswordFieldContextValue {
  attemptSubmit: () => void;
  autoComplete: AutoComplete;
  autoFocus: boolean;
  disabled: boolean;
  dispatch: Dispatcher;
  form: string | undefined;
  hiddenInputRef: React.RefObject<HTMLInputElement | null>;
  isHydrated: boolean;
  name: string | undefined;
  orientation: Exclude<RovingFocusGroupProps['orientation'], undefined>;
  placeholder: string | undefined;
  readOnly: boolean;
  type: InputType;
  userActionRef: React.RefObject<KeyboardActionDetails | null>;
  validationType: InputValidationType;
  value: string[];
  sanitizeValue: (arg: string | string[]) => string[];
}

const ONE_TIME_PASSWORD_FIELD_NAME = 'OneTimePasswordField';
const [Collection, { useCollection, createCollectionScope, useInitCollection }] =
  createCollection<HTMLInputElement>(ONE_TIME_PASSWORD_FIELD_NAME);
const [createOneTimePasswordFieldContext] = createContextScope(ONE_TIME_PASSWORD_FIELD_NAME, [
  createCollectionScope,
  createRovingFocusGroupScope,
]);
const useRovingFocusGroupScope = createRovingFocusGroupScope();

const [OneTimePasswordFieldContext, useOneTimePasswordFieldContext] =
  createOneTimePasswordFieldContext<OneTimePasswordFieldContextValue>(ONE_TIME_PASSWORD_FIELD_NAME);

/* -------------------------------------------------------------------------------------------------
 * OneTimePasswordField
 * -----------------------------------------------------------------------------------------------*/

interface OneTimePasswordFieldOwnProps {
  /**
   * Specifies what—if any—permission the user agent has to provide automated
   * assistance in filling out form field values, as well as guidance to the
   * browser as to the type of information expected in the field. Allows
   * `"one-time-code"` or `"off"`.
   *
   * @defaultValue `"one-time-code"`
   * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/autocomplete
   */
  autoComplete?: AutoComplete;
  /**
   * Whether or not the first fillable input should be focused on page-load.
   *
   * @defaultValue `false`
   * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/autofocus
   */
  autoFocus?: boolean;
  /**
   * Whether or not the component should attempt to automatically submit when
   * all fields are filled. If the field is associated with an HTML `form`
   * element, the form's `requestSubmit` method will be called.
   *
   * @defaultValue `false`
   */
  autoSubmit?: boolean;
  /**
   * The initial value of the uncontrolled field.
   */
  defaultValue?: string;
  /**
   * Indicates the horizontal directionality of the parent element's text.
   *
   * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/dir
   */
  dir?: RovingFocusGroupProps['dir'];
  /**
   * Whether or not the the field's input elements are disabled.
   */
  disabled?: boolean;
  /**
   * A string specifying the `form` element with which the input is associated.
   * This string's value, if present, must match the id of a `form` element in
   * the same document.
   *
   * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input#form
   */
  form?: string | undefined;
  /**
   * A string specifying a name for the input control. This name is submitted
   * along with the control's value when the form data is submitted.
   *
   * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input#name
   */
  name?: string | undefined;
  /**
   * When the `autoSubmit` prop is set to `true`, this callback will be fired
   * before attempting to submit the associated form. It will be called whether
   * or not a form is located, or if submission is not allowed.
   */
  onAutoSubmit?: (value: string) => void;
  /**
   * A callback fired when the field's value changes. When the component is
   * controlled, this should update the state passed to the `value` prop.
   */
  onValueChange?: (value: string) => void;
  /**
   * Indicates the vertical directionality of the input elements.
   *
   * @defaultValue `"horizontal"`
   */
  orientation?: RovingFocusGroupProps['orientation'];
  /**
   * Defines the text displayed in a form control when the control has no value.
   *
   * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/placeholder
   */
  placeholder?: string | undefined;
  /**
   * Whether or not the input elements can be updated by the user.
   *
   * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/readonly
   */
  readOnly?: boolean;
  /**
   * Function for custom sanitization when `validationType` is set to `"none"`.
   * This function will be called before updating values in response to user
   * interactions.
   */
  sanitizeValue?: (value: string) => string;
  /**
   * The input type of the field's input elements. Can be `"password"` or `"text"`.
   */
  type?: InputType;
  /**
   * Specifies the type of input validation to be used. Can be `"alpha"`,
   * `"numeric"`, `"alphanumeric"` or `"none"`.
   *
   * @defaultValue `"numeric"`
   */
  validationType?: InputValidationType;
  /**
   * The controlled value of the field.
   */
  value?: string;
}

type ScopedProps<P> = P & { __scopeOneTimePasswordField?: Scope };

interface OneTimePasswordFieldProps
  extends OneTimePasswordFieldOwnProps,
    Omit<Primitive.PrimitivePropsWithRef<'div'>, keyof OneTimePasswordFieldOwnProps> {}

const OneTimePasswordField = React.forwardRef<HTMLDivElement, OneTimePasswordFieldProps>(
  function OneTimePasswordFieldImpl(
    {
      __scopeOneTimePasswordField,
      defaultValue,
      value: valueProp,
      onValueChange,
      autoSubmit = false,
      children,
      onPaste,
      onAutoSubmit,
      disabled = false,
      readOnly = false,
      autoComplete = 'one-time-code',
      autoFocus = false,
      form,
      name,
      placeholder,
      type = 'text',
      // TODO: Change default to vertical when inputs use vertical writing mode
      orientation = 'horizontal',
      dir,
      validationType = 'numeric',
      sanitizeValue: sanitizeValueProp,
      ...domProps
    }: ScopedProps<OneTimePasswordFieldProps>,
    forwardedRef,
  ) {
    const rovingFocusGroupScope = useRovingFocusGroupScope(__scopeOneTimePasswordField);
    const direction = useDirection(dir);
    const collectionState = useInitCollection();
    const [collection] = collectionState;

    const validation = INPUT_VALIDATION_MAP[validationType]
      ? INPUT_VALIDATION_MAP[validationType as keyof InputValidation]
      : null;

    const sanitizeValue = React.useCallback(
      (value: string | string[]) => {
        if (Array.isArray(value)) {
          value = value.map(removeWhitespace).join('');
        } else {
          value = removeWhitespace(value);
        }

        if (validation) {
          // global regexp is stateful, so we clone it for each call
          const regexp = new RegExp(validation.regexp);
          value = value.replace(regexp, '');
        } else if (sanitizeValueProp) {
          value = sanitizeValueProp(value);
        }

        return value.split('');
      },
      [validation, sanitizeValueProp],
    );

    const controlledValue = React.useMemo(() => {
      return valueProp != null ? sanitizeValue(valueProp) : undefined;
    }, [valueProp, sanitizeValue]);

    const [value, setValue] = useControllableState({
      caller: 'OneTimePasswordField',
      prop: controlledValue,
      defaultProp: defaultValue != null ? sanitizeValue(defaultValue) : [],
      onChange: React.useCallback(
        (value: string[]) => onValueChange?.(value.join('')),
        [onValueChange],
      ),
    });

    // Update function *specifically* for event handlers.
    const dispatch = useEffectEvent<Dispatcher>((action) => {
      switch (action.type) {
        case 'SET_CHAR': {
          const { index, char } = action;
          const currentTarget = collection.at(index)?.element;
          if (value[index] === char) {
            const next = currentTarget && collection.from(currentTarget, 1)?.element;
            focusInput(next);
            return;
          }

          // empty values should be handled in the CLEAR_CHAR action
          if (char === '') {
            return;
          }

          if (validation) {
            const regexp = new RegExp(validation.regexp);
            const clean = char.replace(regexp, '');
            if (clean !== char) {
              // not valid; ignore
              return;
            }
          }

          // no more space
          if (value.length >= collection.size) {
            // replace current value; move to next input
            const newValue = [...value];
            newValue[index] = char;
            flushSync(() => setValue(newValue));
            const next = currentTarget && collection.from(currentTarget, 1)?.element;
            focusInput(next);
            return;
          }

          const newValue = [...value];
          newValue[index] = char;

          const lastElement = collection.at(-1)?.element;
          flushSync(() => setValue(newValue));
          if (currentTarget !== lastElement) {
            const next = currentTarget && collection.from(currentTarget, 1)?.element;
            focusInput(next);
          } else {
            currentTarget?.select();
          }
          return;
        }

        case 'CLEAR_CHAR': {
          const { index, reason } = action;
          if (!value[index]) {
            return;
          }

          const newValue = value.filter((_, i) => i !== index);
          const currentTarget = collection.at(index)?.element;
          const previous = currentTarget && collection.from(currentTarget, -1)?.element;

          flushSync(() => setValue(newValue));
          if (reason === 'Backspace') {
            focusInput(previous);
          } else if (reason === 'Delete' || reason === 'Cut') {
            focusInput(currentTarget);
          }
          return;
        }

        case 'CLEAR': {
          if (value.length === 0) {
            return;
          }

          if (action.reason === 'Backspace' || action.reason === 'Delete') {
            flushSync(() => setValue([]));
            focusInput(collection.at(0)?.element);
          } else {
            setValue([]);
          }
          return;
        }

        case 'PASTE': {
          const { value: pastedValue } = action;
          const value = sanitizeValue(pastedValue);
          if (!value) {
            return;
          }

          flushSync(() => setValue(value));
          focusInput(collection.at(value.length - 1)?.element);
          return;
        }
      }
    });

    // re-validate when the validation type changes
    const validationTypeRef = React.useRef(validation);
    React.useEffect(() => {
      if (!validation) {
        return;
      }

      if (validationTypeRef.current?.type !== validation.type) {
        validationTypeRef.current = validation;
        setValue(sanitizeValue(value.join('')));
      }
    }, [sanitizeValue, setValue, validation, value]);

    const hiddenInputRef = React.useRef<HTMLInputElement>(null);

    const userActionRef = React.useRef<KeyboardActionDetails | null>(null);
    const rootRef = React.useRef<HTMLDivElement | null>(null);
    const composedRefs = useComposedRefs(forwardedRef, rootRef);

    const firstInput = collection.at(0)?.element;
    const locateForm = React.useCallback(() => {
      let formElement: HTMLFormElement | null | undefined;
      if (form) {
        const associatedElement = (rootRef.current?.ownerDocument ?? document).getElementById(form);
        if (isFormElement(associatedElement)) {
          formElement = associatedElement;
        }
      } else if (hiddenInputRef.current) {
        formElement = hiddenInputRef.current.form;
      } else if (firstInput) {
        formElement = firstInput.form;
      }

      return formElement ?? null;
    }, [form, firstInput]);

    const attemptSubmit = React.useCallback(() => {
      const formElement = locateForm();
      formElement?.requestSubmit();
    }, [locateForm]);

    React.useEffect(() => {
      const form = locateForm();
      if (form) {
        const reset = () => dispatch({ type: 'CLEAR', reason: 'Reset' });
        form.addEventListener('reset', reset);
        return () => form.removeEventListener('reset', reset);
      }
    }, [dispatch, locateForm]);

    const currentValue = value.join('');
    const valueRef = React.useRef(currentValue);
    const length = collection.size;
    React.useEffect(() => {
      const previousValue = valueRef.current;
      valueRef.current = currentValue;
      if (previousValue === currentValue) {
        return;
      }

      if (autoSubmit && value.every((char) => char !== '') && value.length === length) {
        onAutoSubmit?.(value.join(''));
        attemptSubmit();
      }
    }, [attemptSubmit, autoSubmit, currentValue, length, onAutoSubmit, value]);
    const isHydrated = useIsHydrated();

    return (
      <OneTimePasswordFieldContext
        scope={__scopeOneTimePasswordField}
        value={value}
        attemptSubmit={attemptSubmit}
        disabled={disabled}
        readOnly={readOnly}
        autoComplete={autoComplete}
        autoFocus={autoFocus}
        form={form}
        name={name}
        placeholder={placeholder}
        type={type}
        hiddenInputRef={hiddenInputRef}
        userActionRef={userActionRef}
        dispatch={dispatch}
        validationType={validationType}
        orientation={orientation}
        isHydrated={isHydrated}
        sanitizeValue={sanitizeValue}
      >
        <Collection.Provider scope={__scopeOneTimePasswordField} state={collectionState}>
          <Collection.Slot scope={__scopeOneTimePasswordField}>
            <RovingFocusGroup.Root
              asChild
              {...rovingFocusGroupScope}
              orientation={orientation}
              dir={direction}
            >
              <Primitive.Root.div
                {...domProps}
                role="group"
                ref={composedRefs}
                onPaste={composeEventHandlers(
                  onPaste,
                  (event: React.ClipboardEvent<HTMLDivElement>) => {
                    event.preventDefault();
                    const pastedValue = event.clipboardData.getData('Text');
                    dispatch({ type: 'PASTE', value: pastedValue });
                  },
                )}
              >
                {children}
              </Primitive.Root.div>
            </RovingFocusGroup.Root>
          </Collection.Slot>
        </Collection.Provider>
      </OneTimePasswordFieldContext>
    );
  },
);

/* -------------------------------------------------------------------------------------------------
 * OneTimePasswordFieldHiddenInput
 * -----------------------------------------------------------------------------------------------*/

interface OneTimePasswordFieldHiddenInputProps
  extends Omit<
    React.ComponentProps<'input'>,
    | keyof 'value'
    | 'defaultValue'
    | 'type'
    | 'onChange'
    | 'readOnly'
    | 'disabled'
    | 'autoComplete'
    | 'autoFocus'
  > {}

const OneTimePasswordFieldHiddenInput = React.forwardRef<
  HTMLInputElement,
  OneTimePasswordFieldHiddenInputProps
>(function OneTimePasswordFieldHiddenInput(
  { __scopeOneTimePasswordField, ...props }: ScopedProps<OneTimePasswordFieldHiddenInputProps>,
  forwardedRef,
) {
  const { value, hiddenInputRef, name } = useOneTimePasswordFieldContext(
    'OneTimePasswordFieldHiddenInput',
    __scopeOneTimePasswordField,
  );
  const ref = useComposedRefs(hiddenInputRef, forwardedRef);
  return (
    <input
      ref={ref}
      name={name}
      value={value.join('').trim()}
      autoComplete="off"
      autoFocus={false}
      autoCapitalize="off"
      autoCorrect="off"
      autoSave="off"
      spellCheck={false}
      {...props}
      type="hidden"
      readOnly
    />
  );
});

/* -------------------------------------------------------------------------------------------------
 * OneTimePasswordFieldInput
 * -----------------------------------------------------------------------------------------------*/

interface OneTimePasswordFieldInputProps
  extends Omit<
    Primitive.PrimitivePropsWithRef<'input'>,
    | 'value'
    | 'defaultValue'
    | 'disabled'
    | 'readOnly'
    | 'autoComplete'
    | 'autoFocus'
    | 'form'
    | 'name'
    | 'placeholder'
    | 'type'
  > {
  /**
   * Callback fired when the user input fails native HTML input validation.
   */
  onInvalidChange?: (character: string) => void;
  /**
   * User-provided index to determine the order of the inputs. This is useful if
   * you need certain index-based attributes to be set on the initial render,
   * often to prevent flickering after hydration.
   */
  index?: number;
}

const OneTimePasswordFieldInput = React.forwardRef<
  HTMLInputElement,
  OneTimePasswordFieldInputProps
>(function OneTimePasswordFieldInput(
  {
    __scopeOneTimePasswordField,
    onInvalidChange,
    index: indexProp,
    ...props
  }: ScopedProps<OneTimePasswordFieldInputProps>,
  forwardedRef,
) {
  // TODO: warn if these values are passed
  const {
    value: _value,
    defaultValue: _defaultValue,
    disabled: _disabled,
    readOnly: _readOnly,
    autoComplete: _autoComplete,
    autoFocus: _autoFocus,
    form: _form,
    name: _name,
    placeholder: _placeholder,
    type: _type,
    ...domProps
  } = props as Primitive.PrimitivePropsWithRef<'input'>;

  const context = useOneTimePasswordFieldContext(
    'OneTimePasswordFieldInput',
    __scopeOneTimePasswordField,
  );
  const { dispatch, userActionRef, validationType, isHydrated, disabled } = context;
  const collection = useCollection(__scopeOneTimePasswordField);
  const rovingFocusGroupScope = useRovingFocusGroupScope(__scopeOneTimePasswordField);

  const inputRef = React.useRef<HTMLInputElement>(null);
  const [element, setElement] = React.useState<HTMLInputElement | null>(null);

  const index = indexProp ?? (element ? collection.indexOf(element) : -1);
  const canSetPlaceholder = indexProp != null || isHydrated;
  let placeholder: string | undefined;
  if (canSetPlaceholder && context.placeholder && context.value.length === 0) {
    // only set placeholder after hydration to prevent flickering when indices
    // are re-calculated
    placeholder = context.placeholder[index];
  }

  const composedInputRef = useComposedRefs(forwardedRef, inputRef, setElement);
  const char = context.value[index] ?? '';

  const keyboardActionTimeoutRef = React.useRef<number | null>(null);
  React.useEffect(() => {
    return () => {
      if (keyboardActionTimeoutRef.current) {
        window.clearTimeout(keyboardActionTimeoutRef.current);
      }
    };
  }, []);

  const totalValue = context.value.join('').trim();
  const lastSelectableIndex = clamp(totalValue.length, [0, collection.size - 1]);
  const isFocusable = index <= lastSelectableIndex;

  const validation =
    validationType in INPUT_VALIDATION_MAP
      ? INPUT_VALIDATION_MAP[validationType as keyof InputValidation]
      : undefined;

  return (
    <Collection.ItemSlot scope={__scopeOneTimePasswordField}>
      <RovingFocusGroup.Item
        {...rovingFocusGroupScope}
        asChild
        focusable={!context.disabled && isFocusable}
        active={index === lastSelectableIndex}
      >
        {({ hasTabStop, isCurrentTabStop }) => {
          const supportsAutoComplete = hasTabStop ? isCurrentTabStop : index === 0;
          return (
            <Primitive.Root.input
              ref={composedInputRef}
              type={context.type}
              disabled={disabled}
              aria-label={`Character ${index + 1} of ${collection.size}`}
              autoComplete={supportsAutoComplete ? context.autoComplete : 'off'}
              data-1p-ignore={supportsAutoComplete ? undefined : 'true'}
              data-lpignore={supportsAutoComplete ? undefined : 'true'}
              data-protonpass-ignore={supportsAutoComplete ? undefined : 'true'}
              data-bwignore={supportsAutoComplete ? undefined : 'true'}
              inputMode={validation?.inputMode}
              maxLength={supportsAutoComplete ? collection.size : 1}
              pattern={validation?.pattern}
              readOnly={context.readOnly}
              value={char}
              placeholder={placeholder}
              data-radix-otp-input=""
              data-radix-index={index}
              {...domProps}
              onFocus={composeEventHandlers(props.onFocus, (event) => {
                event.currentTarget.select();
              })}
              onCut={composeEventHandlers(props.onCut, (event) => {
                const currentValue = event.currentTarget.value;
                if (currentValue !== '') {
                  // In this case the value will be cleared, but we don't want to
                  // set it directly because the user may want to prevent default
                  // behavior in the onChange handler. The userActionRef will
                  // be set temporarily so the change handler can behave correctly
                  // in response to the action.
                  userActionRef.current = { type: 'cut' };
                  // Set a short timeout to clear the action tracker after the change
                  // handler has had time to complete.
                  keyboardActionTimeoutRef.current = window.setTimeout(() => {
                    userActionRef.current = null;
                  }, 10);
                }
              })}
              onInput={composeEventHandlers(props.onInput, (event) => {
                const value = event.currentTarget.value;
                if (value.length > 1) {
                  // Password managers may try to insert the code into a single
                  // input, in which case form validation will fail to prevent
                  // additional input. Handle this the same as if a user were
                  // pasting a value.
                  event.preventDefault();
                  userActionRef.current = { type: 'autocomplete-paste' };
                  dispatch({ type: 'PASTE', value });
                  keyboardActionTimeoutRef.current = window.setTimeout(() => {
                    userActionRef.current = null;
                  }, 10);
                }
              })}
              onChange={composeEventHandlers(props.onChange, (event) => {
                const value = event.target.value;
                event.preventDefault();
                const action = userActionRef.current;
                userActionRef.current = null;

                if (action) {
                  switch (action.type) {
                    case 'cut':
                      // TODO: do we want to assume the user wants to clear the
                      // entire value here and copy the code to the clipboard instead
                      // of just the value of the given input?
                      dispatch({ type: 'CLEAR_CHAR', index, reason: 'Cut' });
                      return;
                    case 'autocomplete-paste':
                      // the PASTE handler will already set the value and focus the final
                      // input; we want to skip focusing the wrong element if the browser fires
                      // onChange for the first input. This sometimes happens during autocomplete.
                      return;
                    case 'keydown': {
                      if (action.key === 'Char') {
                        // update resulting from a keydown event that set a value
                        // directly. Ignore.
                        return;
                      }

                      const isClearing =
                        action.key === 'Backspace' && (action.metaKey || action.ctrlKey);
                      if (action.key === 'Clear' || isClearing) {
                        dispatch({ type: 'CLEAR', reason: 'Backspace' });
                      } else {
                        dispatch({ type: 'CLEAR_CHAR', index, reason: action.key });
                      }
                      return;
                    }
                    default:
                      action satisfies never;
                      return;
                  }
                }

                // Only update the value if it matches the input pattern
                if (event.target.validity.valid) {
                  if (value === '') {
                    let reason: 'Backspace' | 'Delete' | 'Cut' = 'Backspace';
                    if (isInputEvent(event.nativeEvent)) {
                      const inputType = event.nativeEvent.inputType;
                      if (inputType === 'deleteContentBackward') {
                        reason = 'Backspace';
                      } else if (inputType === 'deleteByCut') {
                        reason = 'Cut';
                      }
                    }
                    dispatch({ type: 'CLEAR_CHAR', index, reason });
                  } else {
                    dispatch({ type: 'SET_CHAR', char: value, index, event });
                  }
                } else {
                  const element = event.target;
                  onInvalidChange?.(element.value);
                  requestAnimationFrame(() => {
                    if (element.ownerDocument.activeElement === element) {
                      element.select();
                    }
                  });
                }
              })}
              onKeyDown={composeEventHandlers(props.onKeyDown, (event) => {
                switch (event.key) {
                  case 'Clear':
                  case 'Delete':
                  case 'Backspace': {
                    const currentValue = event.currentTarget.value;
                    // if current value is empty, no change event will fire
                    if (currentValue === '') {
                      // if the user presses delete when there is no value, noop
                      if (event.key === 'Delete') return;

                      const isClearing = event.key === 'Clear' || event.metaKey || event.ctrlKey;
                      if (isClearing) {
                        dispatch({ type: 'CLEAR', reason: 'Backspace' });
                      } else {
                        const element = event.currentTarget;
                        requestAnimationFrame(() => {
                          focusInput(collection.from(element, -1)?.element);
                        });
                      }
                    } else {
                      // In this case the value will be cleared, but we don't want
                      // to set it directly because the user may want to prevent
                      // default behavior in the onChange handler. The userActionRef
                      // will is set temporarily so the change handler can behave
                      // correctly in response to the key vs. clearing the value by
                      // setting state externally.
                      userActionRef.current = {
                        type: 'keydown',
                        key: event.key,
                        metaKey: event.metaKey,
                        ctrlKey: event.ctrlKey,
                      };
                      // Set a short timeout to clear the action tracker after the change
                      // handler has had time to complete.
                      keyboardActionTimeoutRef.current = window.setTimeout(() => {
                        userActionRef.current = null;
                      }, 10);
                    }

                    return;
                  }
                  case 'Enter': {
                    event.preventDefault();
                    context.attemptSubmit();
                    return;
                  }
                  case 'ArrowDown':
                  case 'ArrowUp': {
                    if (context.orientation === 'horizontal') {
                      // in horizontal orientation, the up/down will de-select the
                      // input instead of moving focus
                      event.preventDefault();
                    }
                    return;
                  }
                  // TODO: Handle left/right arrow keys in vertical writing mode
                  default: {
                    if (event.currentTarget.value === event.key) {
                      // if current value is same as the key press, no change event
                      // will fire. Focus the next input.
                      const element = event.currentTarget;
                      event.preventDefault();
                      focusInput(collection.from(element, 1)?.element);
                      return;
                    } else if (
                      // input already has a value, but...
                      event.currentTarget.value &&
                      // the value is not selected
                      !(
                        event.currentTarget.selectionStart === 0 &&
                        event.currentTarget.selectionEnd != null &&
                        event.currentTarget.selectionEnd > 0
                      )
                    ) {
                      const attemptedValue = event.key;
                      if (event.key.length > 1 || event.key === ' ') {
                        // not a character; do nothing
                        return;
                      } else {
                        // user is attempting to enter a character, but the input
                        // will not update by default since it's limited to a single
                        // character.
                        const nextInput = collection.from(event.currentTarget, 1)?.element;
                        const lastInput = collection.at(-1)?.element;
                        if (nextInput !== lastInput && event.currentTarget !== lastInput) {
                          // if selection is before the value, set the value of the
                          // current input. Otherwise set the value of the next
                          // input.
                          if (event.currentTarget.selectionStart === 0) {
                            dispatch({ type: 'SET_CHAR', char: attemptedValue, index, event });
                          } else {
                            dispatch({
                              type: 'SET_CHAR',
                              char: attemptedValue,
                              index: index + 1,
                              event,
                            });
                          }

                          userActionRef.current = {
                            type: 'keydown',
                            key: 'Char',
                            metaKey: event.metaKey,
                            ctrlKey: event.ctrlKey,
                          };
                          keyboardActionTimeoutRef.current = window.setTimeout(() => {
                            userActionRef.current = null;
                          }, 10);
                        }
                      }
                    }
                  }
                }
              })}
              onPointerDown={composeEventHandlers(props.onPointerDown, (event) => {
                event.preventDefault();
                const indexToFocus = Math.min(index, lastSelectableIndex);
                const element = collection.at(indexToFocus)?.element;
                focusInput(element);
              })}
            />
          );
        }}
      </RovingFocusGroup.Item>
    </Collection.ItemSlot>
  );
});

export {
  OneTimePasswordField,
  OneTimePasswordFieldInput,
  OneTimePasswordFieldHiddenInput,
  //
  OneTimePasswordField as Root,
  OneTimePasswordFieldInput as Input,
  OneTimePasswordFieldHiddenInput as HiddenInput,
};
export type {
  OneTimePasswordFieldProps,
  OneTimePasswordFieldInputProps,
  OneTimePasswordFieldHiddenInputProps,
  InputValidationType,
};

/* -----------------------------------------------------------------------------------------------*/

function isFormElement(element: Element | null | undefined): element is HTMLFormElement {
  return element?.tagName === 'FORM';
}

function removeWhitespace(value: string) {
  return value.replace(/\s/g, '');
}

function focusInput(element: HTMLInputElement | null | undefined) {
  if (!element) return;
  if (element.ownerDocument.activeElement === element) {
    // if the element is already focused, select the value in the next
    // animation frame
    window.requestAnimationFrame(() => {
      element.select?.();
    });
  } else {
    element.focus();
  }
}

function isInputEvent(event: Event): event is InputEvent {
  return event.type === 'input';
}

type InputType = 'password' | 'text';
type AutoComplete = 'off' | 'one-time-code';
type KeyboardActionDetails =
  | {
      type: 'keydown';
      key: 'Backspace' | 'Delete' | 'Clear' | 'Char';
      metaKey: boolean;
      ctrlKey: boolean;
    }
  | { type: 'cut' }
  | { type: 'autocomplete-paste' };

type UpdateAction =
  | {
      type: 'SET_CHAR';
      char: string;
      index: number;
      event: React.KeyboardEvent | React.ChangeEvent;
    }
  | { type: 'CLEAR_CHAR'; index: number; reason: 'Backspace' | 'Delete' | 'Cut' }
  | { type: 'CLEAR'; reason: 'Reset' | 'Backspace' | 'Delete' | 'Clear' }
  | { type: 'PASTE'; value: string };
type Dispatcher = React.Dispatch<UpdateAction>;
type InputValidation = Record<
  InputValidationType,
  {
    type: InputValidationType;
    regexp: RegExp;
    pattern: string;
    inputMode: 'text' | 'numeric';
  } | null
>;



================================================
FILE: packages/react/password-toggle-field/README.md
================================================
# `react-password-toggle-field`

## Installation

```sh
$ yarn add radix-ui
# or
$ npm install radix-ui
```

## Usage

View docs [here](https://radix-ui.com/primitives/docs/components/password-toggle-field).



================================================
FILE: packages/react/password-toggle-field/CHANGELOG.md
================================================
# @radix-ui/react-password-toggle-field

## 0.1.3

- Updated dependencies: `@radix-ui/primitive@1.1.3`, `@radix-ui/react-context@1.1.3`, `@radix-ui/react-primitive@2.1.4`

## 0.1.2

- Updated dependencies: `@radix-ui/react-primitive@2.1.3`

## 0.1.1

- Updated dependencies: `@radix-ui/react-primitive@2.1.2`

## 0.1.0

### Introduce new Password Toggle Field primitive

This new primitive provides components for rendering a password input alongside a button to toggle its visibility. Aside from its primary functionality, it also includes:

- Returning focus to the input when toggling with a pointer
- Maintaining focus when toggling with keyboard or virtual navigation
- Resetting visibility to hidden after form submission to prevent accidental storage
- Implicit accessible labeling for icon-based toggle buttons

This API is currently unstable, and we hope you'll help us test it out! Import the primitive using the `unstable_` prefix.

```tsx
import { unstable_PasswordToggleField as PasswordToggleField } from 'radix-ui';

function FieldWithIconToggle() {
  return (
    <PasswordToggleField.Root>
      <PasswordToggleField.Input />
      <PasswordToggleField.Toggle>
        <PasswordToggleField.Icon visible={<EyeOpenIcon />} hidden={<EyeClosedIcon />} />
      </PasswordToggleField.Toggle>
    </PasswordToggleField.Root>
  );
}

function FieldWithTextToggle() {
  return (
    <PasswordToggleField.Root>
      <PasswordToggleField.Input />
      <PasswordToggleField.Toggle>
        <PasswordToggleField.Slot visible="Hide password" hidden="Show password" />
      </PasswordToggleField.Toggle>
    </PasswordToggleField.Root>
  );
}
```

### Other updates

- Updated dependencies: `@radix-ui/react-primitive@2.1.1`



================================================
FILE: packages/react/password-toggle-field/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/password-toggle-field/package.json
================================================
{
  "name": "@radix-ui/react-password-toggle-field",
  "version": "0.1.3",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "src",
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/primitive": "workspace:*",
    "@radix-ui/react-compose-refs": "workspace:*",
    "@radix-ui/react-context": "workspace:*",
    "@radix-ui/react-id": "workspace:*",
    "@radix-ui/react-primitive": "workspace:*",
    "@radix-ui/react-use-controllable-state": "workspace:*",
    "@radix-ui/react-use-effect-event": "workspace:*",
    "@radix-ui/react-use-is-hydrated": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/password-toggle-field/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/password-toggle-field/src/index.ts
================================================
'use client';
export type {
  PasswordToggleFieldProps,
  PasswordToggleFieldInputProps,
  PasswordToggleFieldToggleProps,
  PasswordToggleFieldIconProps,
  PasswordToggleFieldSlotProps,
} from './password-toggle-field';
export {
  PasswordToggleField,
  PasswordToggleFieldInput,
  PasswordToggleFieldToggle,
  PasswordToggleFieldIcon,
  PasswordToggleFieldSlot,
  //
  Root,
  Input,
  Toggle,
  Icon,
  Slot,
} from './password-toggle-field';



================================================
FILE: packages/react/password-toggle-field/src/password-toggle-field.test.tsx
================================================
import { axe } from 'vitest-axe';
import type { RenderResult } from '@testing-library/react';
import { act, cleanup, render, screen } from '@testing-library/react';
import * as PasswordToggleField from './password-toggle-field';
import { afterEach, describe, it, beforeEach, expect } from 'vitest';
import { userEvent, type UserEvent } from '@testing-library/user-event';

describe('given a default PasswordToggleField', () => {
  let rendered: RenderResult;
  let user: UserEvent;

  afterEach(cleanup);

  beforeEach(() => {
    user = userEvent.setup();
    rendered = render(
      <>
        <label htmlFor="password">Password</label>
        <PasswordToggleField.Root>
          <PasswordToggleField.Input id="password" />
          <PasswordToggleField.Toggle>
            <PasswordToggleField.Slot visible="Hide" hidden="Show" />
          </PasswordToggleField.Toggle>
        </PasswordToggleField.Root>
      </>,
    );
  });

  afterEach(cleanup);

  it('should have no accessibility violations', async () => {
    expect(await axe(rendered.container)).toHaveNoViolations();
  });

  it('should initially be hidden', () => {
    const toggle = screen.getByRole('button', { name: 'Show' });
    expect(toggle.textContent).toBe('Show');
  });

  it('toggles the children when clicked', async () => {
    const toggle = screen.getByRole('button', { name: 'Show' });
    await act(async () => await user.click(toggle));
    expect(toggle.textContent).toBe('Hide');
  });

  it('should initially render input as `type=password`', async () => {
    const input = screen.getByLabelText<HTMLInputElement>('Password');
    expect(input.type).toBe('password');
  });

  it('should initially render input as `type=text` when toggled', async () => {
    const input = screen.getByLabelText<HTMLInputElement>('Password');
    const toggle = screen.getByRole('button', { name: 'Show' });
    await act(async () => await user.click(toggle));
    expect(input.type).toBe('text');
  });

  it('should re-focus the input after toggling', async () => {
    const input = screen.getByLabelText<HTMLInputElement>('Password');
    const toggle = screen.getByRole('button', { name: 'Show' });
    await act(async () => await user.click(toggle));
    expect(document.activeElement).toBe(input);
  });

  it("should restore the input's selection after toggling", async () => {
    const input = screen.getByLabelText<HTMLInputElement>('Password');
    const toggle = screen.getByRole('button', { name: 'Show' });
    await act(async () => await user.click(input));
    await act(async () => await user.type(input, 'p'));
    await act(async () => await user.click(toggle));
    // selection should be at the end of the input value
    expect(input.selectionStart).toBe(1);
    expect(input.selectionEnd).toBe(1);

    await act(async () => await user.type(input, 'assword'));
    input.selectionStart = 0;
    input.selectionEnd = 4;

    await act(async () => await user.click(toggle));
    expect(input.selectionStart).toBe(0);
    expect(input.selectionEnd).toBe(4);
  });
});

describe('given a PasswordToggleField with an Icon', () => {
  let rendered: RenderResult;
  let user: UserEvent;

  afterEach(cleanup);

  beforeEach(() => {
    user = userEvent.setup();
    rendered = render(
      <>
        <label htmlFor="password">Password</label>
        <PasswordToggleField.Root>
          <PasswordToggleField.Input id="password" />
          <PasswordToggleField.Toggle>
            <PasswordToggleField.Icon
              visible={<EyeOpenIcon data-testid="open" />}
              hidden={<EyeClosedIcon data-testid="closed" />}
            />
          </PasswordToggleField.Toggle>
        </PasswordToggleField.Root>
      </>,
    );
  });

  afterEach(cleanup);

  it('should have no accessibility violations', async () => {
    expect(await axe(rendered.container)).toHaveNoViolations();
  });

  it('should initially be hidden', () => {
    const icon = screen.getByTestId('closed');
    expect(icon).toBeVisible();
    expect(screen.queryByTestId('open')).not.toBeInTheDocument();
  });

  it('toggles the icon when clicked', async () => {
    const toggle = screen.getByRole('button', { name: 'Show password' });
    await act(async () => await user.click(toggle));
    expect(screen.getByTestId('open')).toBeVisible();
    expect(screen.queryByTestId('closed')).not.toBeInTheDocument();
  });

  it('should initially render input as `type=password`', async () => {
    const input = screen.getByLabelText<HTMLInputElement>('Password');
    expect(input.type).toBe('password');
  });

  it('should initially render input as `type=text` when toggled', async () => {
    const input = screen.getByLabelText<HTMLInputElement>('Password');
    const toggle = screen.getByRole('button', { name: 'Show password' });
    await act(async () => await user.click(toggle));
    expect(input.type).toBe('text');
  });

  it('should retain its value when toggled', async () => {
    const input = screen.getByLabelText('Password');
    const toggle = screen.getByRole('button', { name: 'Show password' });
    await act(async () => await user.type(input, 'pass123'));
    await act(async () => await user.click(toggle));
    expect(input).toHaveValue('pass123');
  });
});

describe('given a PasswordToggleField in a form', () => {
  let user: UserEvent;

  afterEach(cleanup);

  beforeEach(() => {
    user = userEvent.setup();
    render(
      <form onSubmit={(e) => e.preventDefault()}>
        <label htmlFor="password">Password</label>
        <PasswordToggleField.Root>
          <PasswordToggleField.Input id="password" />
          <PasswordToggleField.Toggle>
            <PasswordToggleField.Slot visible="Hide" hidden="Show" />
          </PasswordToggleField.Toggle>
        </PasswordToggleField.Root>
        <button>Submit</button>
      </form>,
    );
  });

  afterEach(cleanup);

  it('should reset visibility to hidden after submission', async () => {
    const toggle = screen.getByRole('button', { name: 'Show' });
    const input = screen.getByLabelText<HTMLInputElement>('Password');
    await act(() => user.click(toggle));
    expect(input.type).toBe('text');
    const submitButton = screen.getByText('Submit');
    await act(() => user.click(submitButton));
    expect(input.type).toBe('password');
  });
});

function EyeClosedIcon(props: React.SVGProps<SVGSVGElement>) {
  return (
    <svg
      width="15"
      height="15"
      viewBox="0 0 15 15"
      fill="currentColor"
      xmlns="http://www.w3.org/2000/svg"
      {...props}
    >
      <path
        d="M14.7649 6.07596C14.9991 6.22231 15.0703 6.53079 14.9239 6.76495C14.4849 7.46743 13.9632 8.10645 13.3702 8.66305L14.5712 9.86406C14.7664 10.0593 14.7664 10.3759 14.5712 10.5712C14.3759 10.7664 14.0593 10.7664 13.8641 10.5712L12.6011 9.30817C11.805 9.90283 10.9089 10.3621 9.93375 10.651L10.383 12.3277C10.4544 12.5944 10.2961 12.8685 10.0294 12.94C9.76267 13.0115 9.4885 12.8532 9.41704 12.5865L8.95917 10.8775C8.48743 10.958 8.00036 10.9999 7.50001 10.9999C6.99965 10.9999 6.51257 10.958 6.04082 10.8775L5.58299 12.5864C5.51153 12.8532 5.23737 13.0115 4.97064 12.94C4.7039 12.8686 4.5456 12.5944 4.61706 12.3277L5.06625 10.651C4.09111 10.3621 3.19503 9.90282 2.3989 9.30815L1.1359 10.5712C0.940638 10.7664 0.624058 10.7664 0.428798 10.5712C0.233537 10.3759 0.233537 10.0593 0.428798 9.86405L1.62982 8.66303C1.03682 8.10643 0.515113 7.46742 0.0760677 6.76495C-0.0702867 6.53079 0.000898544 6.22231 0.235065 6.07596C0.469231 5.9296 0.777703 6.00079 0.924058 6.23496C1.40354 7.00213 1.989 7.68057 2.66233 8.2427C2.67315 8.25096 2.6837 8.25972 2.69397 8.26898C4.00897 9.35527 5.65537 9.99991 7.50001 9.99991C10.3078 9.99991 12.6564 8.5063 14.076 6.23495C14.2223 6.00079 14.5308 5.9296 14.7649 6.07596Z"
        fillRule="evenodd"
        clipRule="evenodd"
      />
    </svg>
  );
}

function EyeOpenIcon(props: React.SVGProps<SVGSVGElement>) {
  return (
    <svg
      width="15"
      height="15"
      viewBox="0 0 15 15"
      fill="currentColor"
      xmlns="http://www.w3.org/2000/svg"
      {...props}
    >
      <path
        d="M7.5 11C4.80285 11 2.52952 9.62184 1.09622 7.50001C2.52952 5.37816 4.80285 4 7.5 4C10.1971 4 12.4705 5.37816 13.9038 7.50001C12.4705 9.62183 10.1971 11 7.5 11ZM7.5 3C4.30786 3 1.65639 4.70638 0.0760002 7.23501C-0.0253338 7.39715 -0.0253334 7.60288 0.0760014 7.76501C1.65639 10.2936 4.30786 12 7.5 12C10.6921 12 13.3436 10.2936 14.924 7.76501C15.0253 7.60288 15.0253 7.39715 14.924 7.23501C13.3436 4.70638 10.6921 3 7.5 3ZM7.5 9.5C8.60457 9.5 9.5 8.60457 9.5 7.5C9.5 6.39543 8.60457 5.5 7.5 5.5C6.39543 5.5 5.5 6.39543 5.5 7.5C5.5 8.60457 6.39543 9.5 7.5 9.5Z"
        fillRule="evenodd"
        clipRule="evenodd"
      />
    </svg>
  );
}



================================================
FILE: packages/react/password-toggle-field/src/password-toggle-field.tsx
================================================
import * as React from 'react';
import { flushSync } from 'react-dom';
import { composeEventHandlers } from '@radix-ui/primitive';
import { useControllableState } from '@radix-ui/react-use-controllable-state';
import { Primitive } from '@radix-ui/react-primitive';
import { useComposedRefs } from '@radix-ui/react-compose-refs';
import { useId } from '@radix-ui/react-id';
import { useIsHydrated } from '@radix-ui/react-use-is-hydrated';
import { useEffectEvent } from '@radix-ui/react-use-effect-event';
import type { Scope } from '@radix-ui/react-context';
import { createContextScope } from '@radix-ui/react-context';

const PASSWORD_TOGGLE_FIELD_NAME = 'PasswordToggleField';

/* -------------------------------------------------------------------------------------------------
 * PasswordToggleFieldProvider
 * -----------------------------------------------------------------------------------------------*/

type InternalFocusState = {
  clickTriggered: boolean;
  selectionStart: number | null;
  selectionEnd: number | null;
};

interface PasswordToggleFieldContextValue {
  inputId: string;
  inputRef: React.RefObject<HTMLInputElement | null>;
  visible: boolean;
  setVisible: React.Dispatch<React.SetStateAction<boolean>>;
  syncInputId: (providedId: string | number | undefined) => void;
  focusState: React.RefObject<InternalFocusState>;
}

const [createPasswordToggleFieldContext] = createContextScope(PASSWORD_TOGGLE_FIELD_NAME);
const [PasswordToggleFieldProvider, usePasswordToggleFieldContext] =
  createPasswordToggleFieldContext<PasswordToggleFieldContextValue>(PASSWORD_TOGGLE_FIELD_NAME);

/* -------------------------------------------------------------------------------------------------
 * PasswordToggleField
 * -----------------------------------------------------------------------------------------------*/

type ScopedProps<P> = P & { __scopePasswordToggleField?: Scope };

interface PasswordToggleFieldProps {
  id?: string;
  visible?: boolean;
  defaultVisible?: boolean;
  onVisiblityChange?: (visible: boolean) => void;
  children?: React.ReactNode;
}

const INITIAL_FOCUS_STATE: InternalFocusState = {
  clickTriggered: false,
  selectionStart: null,
  selectionEnd: null,
};

const PasswordToggleField: React.FC<PasswordToggleFieldProps> = ({
  __scopePasswordToggleField,
  ...props
}: ScopedProps<PasswordToggleFieldProps>) => {
  const baseId = useId(props.id);
  const defaultInputId = `${baseId}-input`;
  const [inputIdState, setInputIdState] = React.useState<null | string>(defaultInputId);
  const inputId = inputIdState ?? defaultInputId;
  const syncInputId = React.useCallback(
    (providedId: string | number | undefined) =>
      setInputIdState(providedId != null ? String(providedId) : null),
    [],
  );

  const { visible: visibleProp, defaultVisible, onVisiblityChange, children } = props;
  const [visible = false, setVisible] = useControllableState({
    caller: PASSWORD_TOGGLE_FIELD_NAME,
    prop: visibleProp,
    defaultProp: defaultVisible ?? false,
    onChange: onVisiblityChange,
  });

  const inputRef = React.useRef<HTMLInputElement | null>(null);
  const focusState = React.useRef<InternalFocusState>(INITIAL_FOCUS_STATE);

  return (
    <PasswordToggleFieldProvider
      scope={__scopePasswordToggleField}
      inputId={inputId}
      inputRef={inputRef}
      setVisible={setVisible}
      syncInputId={syncInputId}
      visible={visible}
      focusState={focusState}
    >
      {children}
    </PasswordToggleFieldProvider>
  );
};
PasswordToggleField.displayName = PASSWORD_TOGGLE_FIELD_NAME;

/* -------------------------------------------------------------------------------------------------
 * PasswordToggleFieldInput
 * -----------------------------------------------------------------------------------------------*/

const PASSWORD_TOGGLE_FIELD_INPUT_NAME = PASSWORD_TOGGLE_FIELD_NAME + 'Input';

type PrimitiveInputProps = React.ComponentPropsWithoutRef<'input'>;

interface PasswordToggleFieldOwnProps {
  autoComplete?: 'current-password' | 'new-password';
}

interface PasswordToggleFieldInputProps
  extends PasswordToggleFieldOwnProps,
    Omit<PrimitiveInputProps, keyof PasswordToggleFieldOwnProps | 'type'> {
  autoComplete?: 'current-password' | 'new-password';
}

const PasswordToggleFieldInput = React.forwardRef<HTMLInputElement, PasswordToggleFieldInputProps>(
  (
    {
      __scopePasswordToggleField,
      autoComplete = 'current-password',
      autoCapitalize = 'off',
      spellCheck = false,
      id: idProp,
      ...props
    }: ScopedProps<PasswordToggleFieldInputProps>,
    forwardedRef,
  ) => {
    const { visible, inputRef, inputId, syncInputId, setVisible, focusState } =
      usePasswordToggleFieldContext(PASSWORD_TOGGLE_FIELD_INPUT_NAME, __scopePasswordToggleField);

    React.useEffect(() => {
      syncInputId(idProp);
    }, [idProp, syncInputId]);

    // We want to reset the visibility to `false` to revert the input to
    // `type="password"` when:
    // - The form is reset (for consistency with other form controls)
    // - The form is submitted (to prevent the browser from remembering the
    //   input's value.
    //
    // See "Keeping things secure":
    //   https://technology.blog.gov.uk/2021/04/19/simple-things-are-complicated-making-a-show-password-option/)
    const _setVisible = useEffectEvent(setVisible);
    React.useEffect(() => {
      const inputElement = inputRef.current;
      const form = inputElement?.form;
      if (!form) {
        return;
      }

      const controller = new AbortController();
      form.addEventListener(
        'reset',
        (event) => {
          if (!event.defaultPrevented) {
            _setVisible(false);
          }
        },
        { signal: controller.signal },
      );
      form.addEventListener(
        'submit',
        () => {
          // always reset the visibility on submit regardless of whether the
          // default action is prevented
          _setVisible(false);
        },
        { signal: controller.signal },
      );
      return () => {
        controller.abort();
      };
    }, [inputRef, _setVisible]);

    return (
      <Primitive.input
        {...props}
        id={idProp ?? inputId}
        autoCapitalize={autoCapitalize}
        autoComplete={autoComplete}
        ref={useComposedRefs(forwardedRef, inputRef)}
        spellCheck={spellCheck}
        type={visible ? 'text' : 'password'}
        onBlur={composeEventHandlers(props.onBlur, (event) => {
          // get the cursor position
          const { selectionStart, selectionEnd } = event.currentTarget;
          focusState.current.selectionStart = selectionStart;
          focusState.current.selectionEnd = selectionEnd;
        })}
      />
    );
  },
);
PasswordToggleFieldInput.displayName = PASSWORD_TOGGLE_FIELD_INPUT_NAME;

/* -------------------------------------------------------------------------------------------------
 * PasswordToggleFieldToggle
 * -----------------------------------------------------------------------------------------------*/

const PASSWORD_TOGGLE_FIELD_TOGGLE_NAME = PASSWORD_TOGGLE_FIELD_NAME + 'Toggle';

type PrimitiveButtonProps = React.ComponentPropsWithoutRef<'button'>;

interface PasswordToggleFieldToggleProps extends Omit<PrimitiveButtonProps, 'type'> {}

const PasswordToggleFieldToggle = React.forwardRef<
  HTMLButtonElement,
  PasswordToggleFieldToggleProps
>(
  (
    {
      __scopePasswordToggleField,
      onClick,
      onPointerDown,
      onPointerCancel,
      onPointerUp,
      onFocus,
      children,
      'aria-label': ariaLabelProp,
      'aria-controls': ariaControls,
      'aria-hidden': ariaHidden,
      tabIndex,
      ...props
    }: ScopedProps<PasswordToggleFieldToggleProps>,
    forwardedRef,
  ) => {
    const { setVisible, visible, inputRef, inputId, focusState } = usePasswordToggleFieldContext(
      PASSWORD_TOGGLE_FIELD_TOGGLE_NAME,
      __scopePasswordToggleField,
    );
    const [internalAriaLabel, setInternalAriaLabel] = React.useState<string | undefined>(undefined);
    const elementRef = React.useRef<HTMLButtonElement>(null);
    const ref = useComposedRefs(forwardedRef, elementRef);
    const isHydrated = useIsHydrated();

    React.useEffect(() => {
      const element = elementRef.current;
      if (!element || ariaLabelProp) {
        setInternalAriaLabel(undefined);
        return;
      }

      const DEFAULT_ARIA_LABEL = visible ? 'Hide password' : 'Show password';

      function checkForInnerTextLabel(textContent: string | undefined | null) {
        const text = textContent ? textContent : undefined;
        // If the element has inner text, no need to force an aria-label.
        setInternalAriaLabel(text ? undefined : DEFAULT_ARIA_LABEL);
      }

      checkForInnerTextLabel(element.textContent);

      const observer = new MutationObserver((entries) => {
        let textContent: string | undefined;
        for (const entry of entries) {
          if (entry.type === 'characterData') {
            if (element.textContent) {
              textContent = element.textContent;
            }
          }
        }
        checkForInnerTextLabel(textContent);
      });
      observer.observe(element, { characterData: true, subtree: true });
      return () => {
        observer.disconnect();
      };
    }, [visible, ariaLabelProp]);

    const ariaLabel = ariaLabelProp || internalAriaLabel;

    // Before hydration the button will not work, but we want to render it
    // regardless to prevent potential layout shift. Hide it from assistive tech
    // by default. Post-hydration it will be visible, focusable and associated
    // with the input via aria-controls.
    if (!isHydrated) {
      ariaHidden ??= true;
      tabIndex ??= -1;
    } else {
      ariaControls ??= inputId;
    }

    React.useEffect(() => {
      let cleanup = () => {};
      const ownerWindow = elementRef.current?.ownerDocument?.defaultView || window;
      const reset = () => (focusState.current.clickTriggered = false);
      const handlePointerUp = () => (cleanup = requestIdleCallback(ownerWindow, reset));
      ownerWindow.addEventListener('pointerup', handlePointerUp);
      return () => {
        cleanup();
        ownerWindow.removeEventListener('pointerup', handlePointerUp);
      };
    }, [focusState]);

    return (
      <Primitive.button
        aria-controls={ariaControls}
        aria-hidden={ariaHidden}
        aria-label={ariaLabel}
        ref={ref}
        id={inputId}
        {...props}
        onPointerDown={composeEventHandlers(onPointerDown, () => {
          focusState.current.clickTriggered = true;
        })}
        onPointerCancel={(event) => {
          // do not use `composeEventHandlers` here because we always want to
          // reset the ref on cancellation, regardless of whether the user has
          // called preventDefault on the event
          onPointerCancel?.(event);
          focusState.current = INITIAL_FOCUS_STATE;
        }}
        // do not use `composeEventHandlers` here because we always want to
        // reset the ref after click, regardless of whether the user has
        // called preventDefault on the event
        onClick={(event) => {
          onClick?.(event);
          if (event.defaultPrevented) {
            focusState.current = INITIAL_FOCUS_STATE;
            return;
          }

          flushSync(() => {
            setVisible((s) => !s);
          });
          if (focusState.current.clickTriggered) {
            const input = inputRef.current;
            if (input) {
              const { selectionStart, selectionEnd } = focusState.current;
              input.focus();
              if (selectionStart !== null || selectionEnd !== null) {
                // wait a tick so that focus has settled, then restore select position
                requestAnimationFrame(() => {
                  // make sure the input still has focus (developer may have
                  // programatically moved focus elsewhere)
                  if (input.ownerDocument.activeElement === input) {
                    input.selectionStart = selectionStart;
                    input.selectionEnd = selectionEnd;
                  }
                });
              }
            }
          }
          focusState.current = INITIAL_FOCUS_STATE;
        }}
        onPointerUp={(event) => {
          onPointerUp?.(event);
          // if click handler hasn't been called at this point, it may have been
          // intercepted, in which case we still want to reset our internal
          // state
          setTimeout(() => {
            focusState.current = INITIAL_FOCUS_STATE;
          }, 50);
        }}
        type="button"
      >
        {children}
      </Primitive.button>
    );
  },
);
PasswordToggleFieldToggle.displayName = PASSWORD_TOGGLE_FIELD_TOGGLE_NAME;

/* -------------------------------------------------------------------------------------------------
 * PasswordToggleFieldSlot
 * -----------------------------------------------------------------------------------------------*/

const PASSWORD_TOGGLE_FIELD_SLOT_NAME = PASSWORD_TOGGLE_FIELD_NAME + 'Slot';

interface PasswordToggleFieldSlotDeclarativeProps {
  visible: React.ReactNode;
  hidden: React.ReactNode;
}

interface PasswordToggleFieldSlotRenderProps {
  render: (args: { visible: boolean }) => React.ReactElement;
}

type PasswordToggleFieldSlotProps =
  | PasswordToggleFieldSlotDeclarativeProps
  | PasswordToggleFieldSlotRenderProps;

const PasswordToggleFieldSlot: React.FC<PasswordToggleFieldSlotProps> = ({
  __scopePasswordToggleField,
  ...props
}: ScopedProps<PasswordToggleFieldSlotProps>) => {
  const { visible } = usePasswordToggleFieldContext(
    PASSWORD_TOGGLE_FIELD_SLOT_NAME,
    __scopePasswordToggleField,
  );

  return 'render' in props
    ? //
      props.render({ visible })
    : visible
      ? props.visible
      : props.hidden;
};
PasswordToggleFieldSlot.displayName = PASSWORD_TOGGLE_FIELD_SLOT_NAME;

/* -------------------------------------------------------------------------------------------------
 * PasswordToggleFieldIcon
 * -----------------------------------------------------------------------------------------------*/

const PASSWORD_TOGGLE_FIELD_ICON_NAME = PASSWORD_TOGGLE_FIELD_NAME + 'Icon';

type PrimitiveSvgProps = React.ComponentPropsWithoutRef<'svg'>;

interface PasswordToggleFieldIconProps extends Omit<PrimitiveSvgProps, 'children'> {
  visible: React.ReactElement;
  hidden: React.ReactElement;
}

const PasswordToggleFieldIcon = React.forwardRef<SVGSVGElement, PasswordToggleFieldIconProps>(
  (
    {
      __scopePasswordToggleField,
      // @ts-expect-error
      children,
      ...props
    }: ScopedProps<PasswordToggleFieldIconProps>,
    forwardedRef,
  ) => {
    const { visible } = usePasswordToggleFieldContext(
      PASSWORD_TOGGLE_FIELD_ICON_NAME,
      __scopePasswordToggleField,
    );
    const { visible: visibleIcon, hidden: hiddenIcon, ...domProps } = props;
    return (
      <Primitive.svg {...domProps} ref={forwardedRef} aria-hidden asChild>
        {visible ? visibleIcon : hiddenIcon}
      </Primitive.svg>
    );
  },
);
PasswordToggleFieldIcon.displayName = PASSWORD_TOGGLE_FIELD_ICON_NAME;

export {
  PasswordToggleField,
  PasswordToggleFieldInput,
  PasswordToggleFieldToggle,
  PasswordToggleFieldSlot,
  PasswordToggleFieldIcon,
  //
  PasswordToggleField as Root,
  PasswordToggleFieldInput as Input,
  PasswordToggleFieldToggle as Toggle,
  PasswordToggleFieldSlot as Slot,
  PasswordToggleFieldIcon as Icon,
};
export type {
  PasswordToggleFieldProps,
  PasswordToggleFieldInputProps,
  PasswordToggleFieldToggleProps,
  PasswordToggleFieldIconProps,
  PasswordToggleFieldSlotProps,
};

function requestIdleCallback(
  window: Window,
  callback: IdleRequestCallback,
  options?: IdleRequestOptions,
): () => void {
  if ((window as any).requestIdleCallback) {
    const id = window.requestIdleCallback(callback, options);
    return () => {
      window.cancelIdleCallback(id);
    };
  }
  const start = Date.now();
  const id = window.setTimeout(() => {
    const timeRemaining = () => Math.max(0, 50 - (Date.now() - start));
    callback({ didTimeout: false, timeRemaining });
  }, 1);
  return () => {
    window.clearTimeout(id);
  };
}



================================================
FILE: packages/react/popover/README.md
================================================
# `react-popover`

View docs [here](https://radix-ui.com/primitives/docs/components/popover).



================================================
FILE: packages/react/popover/CHANGELOG.md
================================================
# @radix-ui/react-popover

## 1.1.15

- Updated dependencies: `@radix-ui/react-presence@1.1.5`, `@radix-ui/react-slot@1.2.4`, `@radix-ui/react-popper@1.2.8`, `@radix-ui/react-focus-guards@1.1.3`, `@radix-ui/primitive@1.1.3`, `@radix-ui/react-context@1.1.3`, `@radix-ui/react-primitive@2.1.4`, `@radix-ui/react-dismissable-layer@1.1.11`, `@radix-ui/react-focus-scope@1.1.8`, `@radix-ui/react-portal@1.1.10`

## 1.1.14

- Replace deprecated 'ElementRef' with 'ComponentRef' (#3426)
- Updated dependencies: `@radix-ui/react-dismissable-layer@1.1.10`, `@radix-ui/react-focus-scope@1.1.7`, `@radix-ui/react-popper@1.2.7`, `@radix-ui/react-portal@1.1.9`, `@radix-ui/react-slot@1.2.3`, `@radix-ui/react-primitive@2.1.3`

## 1.1.13

- Updated dependencies: `@radix-ui/react-slot@1.2.2`, `@radix-ui/react-primitive@2.1.2`, `@radix-ui/react-dismissable-layer@1.1.9`, `@radix-ui/react-focus-scope@1.1.6`, `@radix-ui/react-popper@1.2.6`, `@radix-ui/react-portal@1.1.8`

## 1.1.12

- Updated dependencies: `@radix-ui/react-slot@1.2.1`, `@radix-ui/react-primitive@2.1.1`, `@radix-ui/react-dismissable-layer@1.1.8`, `@radix-ui/react-focus-scope@1.1.5`, `@radix-ui/react-popper@1.2.5`, `@radix-ui/react-portal@1.1.7`

## 1.1.11

- Updated dependencies: `@radix-ui/react-presence@1.1.4`

## 1.1.10

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.2`

## 1.1.9

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.1`

## 1.1.8

- Minor improvements to `useControllableState` to enhance performance, reduce surface area for bugs, and log warnings when misused (#3455)
- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.0`, `@radix-ui/react-primitive@2.1.0`, `@radix-ui/react-dismissable-layer@1.1.7`, `@radix-ui/react-focus-scope@1.1.4`, `@radix-ui/react-popper@1.2.4`, `@radix-ui/react-portal@1.1.6`



================================================
FILE: packages/react/popover/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/popover/package.json
================================================
{
  "name": "@radix-ui/react-popover",
  "version": "1.1.15",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/primitive": "workspace:*",
    "@radix-ui/react-compose-refs": "workspace:*",
    "@radix-ui/react-context": "workspace:*",
    "@radix-ui/react-dismissable-layer": "workspace:*",
    "@radix-ui/react-focus-guards": "workspace:*",
    "@radix-ui/react-focus-scope": "workspace:*",
    "@radix-ui/react-id": "workspace:*",
    "@radix-ui/react-popper": "workspace:*",
    "@radix-ui/react-portal": "workspace:*",
    "@radix-ui/react-presence": "workspace:*",
    "@radix-ui/react-primitive": "workspace:*",
    "@radix-ui/react-slot": "workspace:*",
    "@radix-ui/react-use-controllable-state": "workspace:*",
    "aria-hidden": "^1.2.4",
    "react-remove-scroll": "^2.6.3"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/popover/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/popover/src/index.ts
================================================
'use client';
export {
  createPopoverScope,
  //
  Popover,
  PopoverAnchor,
  PopoverTrigger,
  PopoverPortal,
  PopoverContent,
  PopoverClose,
  PopoverArrow,
  //
  Root,
  Anchor,
  Trigger,
  Portal,
  Content,
  Close,
  Arrow,
} from './popover';
export type {
  PopoverProps,
  PopoverAnchorProps,
  PopoverTriggerProps,
  PopoverPortalProps,
  PopoverContentProps,
  PopoverCloseProps,
  PopoverArrowProps,
} from './popover';



================================================
FILE: packages/react/popover/src/popover.tsx
================================================
import * as React from 'react';
import { composeEventHandlers } from '@radix-ui/primitive';
import { useComposedRefs } from '@radix-ui/react-compose-refs';
import { createContextScope } from '@radix-ui/react-context';
import { DismissableLayer } from '@radix-ui/react-dismissable-layer';
import { useFocusGuards } from '@radix-ui/react-focus-guards';
import { FocusScope } from '@radix-ui/react-focus-scope';
import { useId } from '@radix-ui/react-id';
import * as PopperPrimitive from '@radix-ui/react-popper';
import { createPopperScope } from '@radix-ui/react-popper';
import { Portal as PortalPrimitive } from '@radix-ui/react-portal';
import { Presence } from '@radix-ui/react-presence';
import { Primitive } from '@radix-ui/react-primitive';
import { createSlot } from '@radix-ui/react-slot';
import { useControllableState } from '@radix-ui/react-use-controllable-state';
import { hideOthers } from 'aria-hidden';
import { RemoveScroll } from 'react-remove-scroll';

import type { Scope } from '@radix-ui/react-context';

/* -------------------------------------------------------------------------------------------------
 * Popover
 * -----------------------------------------------------------------------------------------------*/

const POPOVER_NAME = 'Popover';

type ScopedProps<P> = P & { __scopePopover?: Scope };
const [createPopoverContext, createPopoverScope] = createContextScope(POPOVER_NAME, [
  createPopperScope,
]);
const usePopperScope = createPopperScope();

type PopoverContextValue = {
  triggerRef: React.RefObject<HTMLButtonElement | null>;
  contentId: string;
  open: boolean;
  onOpenChange(open: boolean): void;
  onOpenToggle(): void;
  hasCustomAnchor: boolean;
  onCustomAnchorAdd(): void;
  onCustomAnchorRemove(): void;
  modal: boolean;
};

const [PopoverProvider, usePopoverContext] =
  createPopoverContext<PopoverContextValue>(POPOVER_NAME);

interface PopoverProps {
  children?: React.ReactNode;
  open?: boolean;
  defaultOpen?: boolean;
  onOpenChange?: (open: boolean) => void;
  modal?: boolean;
}

const Popover: React.FC<PopoverProps> = (props: ScopedProps<PopoverProps>) => {
  const {
    __scopePopover,
    children,
    open: openProp,
    defaultOpen,
    onOpenChange,
    modal = false,
  } = props;
  const popperScope = usePopperScope(__scopePopover);
  const triggerRef = React.useRef<HTMLButtonElement>(null);
  const [hasCustomAnchor, setHasCustomAnchor] = React.useState(false);
  const [open, setOpen] = useControllableState({
    prop: openProp,
    defaultProp: defaultOpen ?? false,
    onChange: onOpenChange,
    caller: POPOVER_NAME,
  });

  return (
    <PopperPrimitive.Root {...popperScope}>
      <PopoverProvider
        scope={__scopePopover}
        contentId={useId()}
        triggerRef={triggerRef}
        open={open}
        onOpenChange={setOpen}
        onOpenToggle={React.useCallback(() => setOpen((prevOpen) => !prevOpen), [setOpen])}
        hasCustomAnchor={hasCustomAnchor}
        onCustomAnchorAdd={React.useCallback(() => setHasCustomAnchor(true), [])}
        onCustomAnchorRemove={React.useCallback(() => setHasCustomAnchor(false), [])}
        modal={modal}
      >
        {children}
      </PopoverProvider>
    </PopperPrimitive.Root>
  );
};

Popover.displayName = POPOVER_NAME;

/* -------------------------------------------------------------------------------------------------
 * PopoverAnchor
 * -----------------------------------------------------------------------------------------------*/

const ANCHOR_NAME = 'PopoverAnchor';

type PopoverAnchorElement = React.ComponentRef<typeof PopperPrimitive.Anchor>;
type PopperAnchorProps = React.ComponentPropsWithoutRef<typeof PopperPrimitive.Anchor>;
interface PopoverAnchorProps extends PopperAnchorProps {}

const PopoverAnchor = React.forwardRef<PopoverAnchorElement, PopoverAnchorProps>(
  (props: ScopedProps<PopoverAnchorProps>, forwardedRef) => {
    const { __scopePopover, ...anchorProps } = props;
    const context = usePopoverContext(ANCHOR_NAME, __scopePopover);
    const popperScope = usePopperScope(__scopePopover);
    const { onCustomAnchorAdd, onCustomAnchorRemove } = context;

    React.useEffect(() => {
      onCustomAnchorAdd();
      return () => onCustomAnchorRemove();
    }, [onCustomAnchorAdd, onCustomAnchorRemove]);

    return <PopperPrimitive.Anchor {...popperScope} {...anchorProps} ref={forwardedRef} />;
  },
);

PopoverAnchor.displayName = ANCHOR_NAME;

/* -------------------------------------------------------------------------------------------------
 * PopoverTrigger
 * -----------------------------------------------------------------------------------------------*/

const TRIGGER_NAME = 'PopoverTrigger';

type PopoverTriggerElement = React.ComponentRef<typeof Primitive.button>;
type PrimitiveButtonProps = React.ComponentPropsWithoutRef<typeof Primitive.button>;
interface PopoverTriggerProps extends PrimitiveButtonProps {}

const PopoverTrigger = React.forwardRef<PopoverTriggerElement, PopoverTriggerProps>(
  (props: ScopedProps<PopoverTriggerProps>, forwardedRef) => {
    const { __scopePopover, ...triggerProps } = props;
    const context = usePopoverContext(TRIGGER_NAME, __scopePopover);
    const popperScope = usePopperScope(__scopePopover);
    const composedTriggerRef = useComposedRefs(forwardedRef, context.triggerRef);

    const trigger = (
      <Primitive.button
        type="button"
        aria-haspopup="dialog"
        aria-expanded={context.open}
        aria-controls={context.contentId}
        data-state={getState(context.open)}
        {...triggerProps}
        ref={composedTriggerRef}
        onClick={composeEventHandlers(props.onClick, context.onOpenToggle)}
      />
    );

    return context.hasCustomAnchor ? (
      trigger
    ) : (
      <PopperPrimitive.Anchor asChild {...popperScope}>
        {trigger}
      </PopperPrimitive.Anchor>
    );
  },
);

PopoverTrigger.displayName = TRIGGER_NAME;

/* -------------------------------------------------------------------------------------------------
 * PopoverPortal
 * -----------------------------------------------------------------------------------------------*/

const PORTAL_NAME = 'PopoverPortal';

type PortalContextValue = { forceMount?: true };
const [PortalProvider, usePortalContext] = createPopoverContext<PortalContextValue>(PORTAL_NAME, {
  forceMount: undefined,
});

type PortalProps = React.ComponentPropsWithoutRef<typeof PortalPrimitive>;
interface PopoverPortalProps {
  children?: React.ReactNode;
  /**
   * Specify a container element to portal the content into.
   */
  container?: PortalProps['container'];
  /**
   * Used to force mounting when more control is needed. Useful when
   * controlling animation with React animation libraries.
   */
  forceMount?: true;
}

const PopoverPortal: React.FC<PopoverPortalProps> = (props: ScopedProps<PopoverPortalProps>) => {
  const { __scopePopover, forceMount, children, container } = props;
  const context = usePopoverContext(PORTAL_NAME, __scopePopover);
  return (
    <PortalProvider scope={__scopePopover} forceMount={forceMount}>
      <Presence present={forceMount || context.open}>
        <PortalPrimitive asChild container={container}>
          {children}
        </PortalPrimitive>
      </Presence>
    </PortalProvider>
  );
};

PopoverPortal.displayName = PORTAL_NAME;

/* -------------------------------------------------------------------------------------------------
 * PopoverContent
 * -----------------------------------------------------------------------------------------------*/

const CONTENT_NAME = 'PopoverContent';

interface PopoverContentProps extends PopoverContentTypeProps {
  /**
   * Used to force mounting when more control is needed. Useful when
   * controlling animation with React animation libraries.
   */
  forceMount?: true;
}

const PopoverContent = React.forwardRef<PopoverContentTypeElement, PopoverContentProps>(
  (props: ScopedProps<PopoverContentProps>, forwardedRef) => {
    const portalContext = usePortalContext(CONTENT_NAME, props.__scopePopover);
    const { forceMount = portalContext.forceMount, ...contentProps } = props;
    const context = usePopoverContext(CONTENT_NAME, props.__scopePopover);
    return (
      <Presence present={forceMount || context.open}>
        {context.modal ? (
          <PopoverContentModal {...contentProps} ref={forwardedRef} />
        ) : (
          <PopoverContentNonModal {...contentProps} ref={forwardedRef} />
        )}
      </Presence>
    );
  },
);

PopoverContent.displayName = CONTENT_NAME;

/* -----------------------------------------------------------------------------------------------*/

const Slot = createSlot('PopoverContent.RemoveScroll');

type PopoverContentTypeElement = PopoverContentImplElement;
interface PopoverContentTypeProps
  extends Omit<PopoverContentImplProps, 'trapFocus' | 'disableOutsidePointerEvents'> {}

const PopoverContentModal = React.forwardRef<PopoverContentTypeElement, PopoverContentTypeProps>(
  (props: ScopedProps<PopoverContentTypeProps>, forwardedRef) => {
    const context = usePopoverContext(CONTENT_NAME, props.__scopePopover);
    const contentRef = React.useRef<HTMLDivElement>(null);
    const composedRefs = useComposedRefs(forwardedRef, contentRef);
    const isRightClickOutsideRef = React.useRef(false);

    // aria-hide everything except the content (better supported equivalent to setting aria-modal)
    React.useEffect(() => {
      const content = contentRef.current;
      if (content) return hideOthers(content);
    }, []);

    return (
      <RemoveScroll as={Slot} allowPinchZoom>
        <PopoverContentImpl
          {...props}
          ref={composedRefs}
          // we make sure we're not trapping once it's been closed
          // (closed !== unmounted when animating out)
          trapFocus={context.open}
          disableOutsidePointerEvents
          onCloseAutoFocus={composeEventHandlers(props.onCloseAutoFocus, (event) => {
            event.preventDefault();
            if (!isRightClickOutsideRef.current) context.triggerRef.current?.focus();
          })}
          onPointerDownOutside={composeEventHandlers(
            props.onPointerDownOutside,
            (event) => {
              const originalEvent = event.detail.originalEvent;
              const ctrlLeftClick = originalEvent.button === 0 && originalEvent.ctrlKey === true;
              const isRightClick = originalEvent.button === 2 || ctrlLeftClick;

              isRightClickOutsideRef.current = isRightClick;
            },
            { checkForDefaultPrevented: false },
          )}
          // When focus is trapped, a `focusout` event may still happen.
          // We make sure we don't trigger our `onDismiss` in such case.
          onFocusOutside={composeEventHandlers(
            props.onFocusOutside,
            (event) => event.preventDefault(),
            { checkForDefaultPrevented: false },
          )}
        />
      </RemoveScroll>
    );
  },
);

const PopoverContentNonModal = React.forwardRef<PopoverContentTypeElement, PopoverContentTypeProps>(
  (props: ScopedProps<PopoverContentTypeProps>, forwardedRef) => {
    const context = usePopoverContext(CONTENT_NAME, props.__scopePopover);
    const hasInteractedOutsideRef = React.useRef(false);
    const hasPointerDownOutsideRef = React.useRef(false);

    return (
      <PopoverContentImpl
        {...props}
        ref={forwardedRef}
        trapFocus={false}
        disableOutsidePointerEvents={false}
        onCloseAutoFocus={(event) => {
          props.onCloseAutoFocus?.(event);

          if (!event.defaultPrevented) {
            if (!hasInteractedOutsideRef.current) context.triggerRef.current?.focus();
            // Always prevent auto focus because we either focus manually or want user agent focus
            event.preventDefault();
          }

          hasInteractedOutsideRef.current = false;
          hasPointerDownOutsideRef.current = false;
        }}
        onInteractOutside={(event) => {
          props.onInteractOutside?.(event);

          if (!event.defaultPrevented) {
            hasInteractedOutsideRef.current = true;
            if (event.detail.originalEvent.type === 'pointerdown') {
              hasPointerDownOutsideRef.current = true;
            }
          }

          // Prevent dismissing when clicking the trigger.
          // As the trigger is already setup to close, without doing so would
          // cause it to close and immediately open.
          const target = event.target as HTMLElement;
          const targetIsTrigger = context.triggerRef.current?.contains(target);
          if (targetIsTrigger) event.preventDefault();

          // On Safari if the trigger is inside a container with tabIndex={0}, when clicked
          // we will get the pointer down outside event on the trigger, but then a subsequent
          // focus outside event on the container, we ignore any focus outside event when we've
          // already had a pointer down outside event.
          if (event.detail.originalEvent.type === 'focusin' && hasPointerDownOutsideRef.current) {
            event.preventDefault();
          }
        }}
      />
    );
  },
);

/* -----------------------------------------------------------------------------------------------*/

type PopoverContentImplElement = React.ComponentRef<typeof PopperPrimitive.Content>;
type FocusScopeProps = React.ComponentPropsWithoutRef<typeof FocusScope>;
type DismissableLayerProps = React.ComponentPropsWithoutRef<typeof DismissableLayer>;
type PopperContentProps = React.ComponentPropsWithoutRef<typeof PopperPrimitive.Content>;
interface PopoverContentImplProps
  extends Omit<PopperContentProps, 'onPlaced'>,
    Omit<DismissableLayerProps, 'onDismiss'> {
  /**
   * Whether focus should be trapped within the `Popover`
   * (default: false)
   */
  trapFocus?: FocusScopeProps['trapped'];

  /**
   * Event handler called when auto-focusing on open.
   * Can be prevented.
   */
  onOpenAutoFocus?: FocusScopeProps['onMountAutoFocus'];

  /**
   * Event handler called when auto-focusing on close.
   * Can be prevented.
   */
  onCloseAutoFocus?: FocusScopeProps['onUnmountAutoFocus'];
}

const PopoverContentImpl = React.forwardRef<PopoverContentImplElement, PopoverContentImplProps>(
  (props: ScopedProps<PopoverContentImplProps>, forwardedRef) => {
    const {
      __scopePopover,
      trapFocus,
      onOpenAutoFocus,
      onCloseAutoFocus,
      disableOutsidePointerEvents,
      onEscapeKeyDown,
      onPointerDownOutside,
      onFocusOutside,
      onInteractOutside,
      ...contentProps
    } = props;
    const context = usePopoverContext(CONTENT_NAME, __scopePopover);
    const popperScope = usePopperScope(__scopePopover);

    // Make sure the whole tree has focus guards as our `Popover` may be
    // the last element in the DOM (because of the `Portal`)
    useFocusGuards();

    return (
      <FocusScope
        asChild
        loop
        trapped={trapFocus}
        onMountAutoFocus={onOpenAutoFocus}
        onUnmountAutoFocus={onCloseAutoFocus}
      >
        <DismissableLayer
          asChild
          disableOutsidePointerEvents={disableOutsidePointerEvents}
          onInteractOutside={onInteractOutside}
          onEscapeKeyDown={onEscapeKeyDown}
          onPointerDownOutside={onPointerDownOutside}
          onFocusOutside={onFocusOutside}
          onDismiss={() => context.onOpenChange(false)}
        >
          <PopperPrimitive.Content
            data-state={getState(context.open)}
            role="dialog"
            id={context.contentId}
            {...popperScope}
            {...contentProps}
            ref={forwardedRef}
            style={{
              ...contentProps.style,
              // re-namespace exposed content custom properties
              ...{
                '--radix-popover-content-transform-origin': 'var(--radix-popper-transform-origin)',
                '--radix-popover-content-available-width': 'var(--radix-popper-available-width)',
                '--radix-popover-content-available-height': 'var(--radix-popper-available-height)',
                '--radix-popover-trigger-width': 'var(--radix-popper-anchor-width)',
                '--radix-popover-trigger-height': 'var(--radix-popper-anchor-height)',
              },
            }}
          />
        </DismissableLayer>
      </FocusScope>
    );
  },
);

/* -------------------------------------------------------------------------------------------------
 * PopoverClose
 * -----------------------------------------------------------------------------------------------*/

const CLOSE_NAME = 'PopoverClose';

type PopoverCloseElement = React.ComponentRef<typeof Primitive.button>;
interface PopoverCloseProps extends PrimitiveButtonProps {}

const PopoverClose = React.forwardRef<PopoverCloseElement, PopoverCloseProps>(
  (props: ScopedProps<PopoverCloseProps>, forwardedRef) => {
    const { __scopePopover, ...closeProps } = props;
    const context = usePopoverContext(CLOSE_NAME, __scopePopover);
    return (
      <Primitive.button
        type="button"
        {...closeProps}
        ref={forwardedRef}
        onClick={composeEventHandlers(props.onClick, () => context.onOpenChange(false))}
      />
    );
  },
);

PopoverClose.displayName = CLOSE_NAME;

/* -------------------------------------------------------------------------------------------------
 * PopoverArrow
 * -----------------------------------------------------------------------------------------------*/

const ARROW_NAME = 'PopoverArrow';

type PopoverArrowElement = React.ComponentRef<typeof PopperPrimitive.Arrow>;
type PopperArrowProps = React.ComponentPropsWithoutRef<typeof PopperPrimitive.Arrow>;
interface PopoverArrowProps extends PopperArrowProps {}

const PopoverArrow = React.forwardRef<PopoverArrowElement, PopoverArrowProps>(
  (props: ScopedProps<PopoverArrowProps>, forwardedRef) => {
    const { __scopePopover, ...arrowProps } = props;
    const popperScope = usePopperScope(__scopePopover);
    return <PopperPrimitive.Arrow {...popperScope} {...arrowProps} ref={forwardedRef} />;
  },
);

PopoverArrow.displayName = ARROW_NAME;

/* -----------------------------------------------------------------------------------------------*/

function getState(open: boolean) {
  return open ? 'open' : 'closed';
}

const Root = Popover;
const Anchor = PopoverAnchor;
const Trigger = PopoverTrigger;
const Portal = PopoverPortal;
const Content = PopoverContent;
const Close = PopoverClose;
const Arrow = PopoverArrow;

export {
  createPopoverScope,
  //
  Popover,
  PopoverAnchor,
  PopoverTrigger,
  PopoverPortal,
  PopoverContent,
  PopoverClose,
  PopoverArrow,
  //
  Root,
  Anchor,
  Trigger,
  Portal,
  Content,
  Close,
  Arrow,
};
export type {
  PopoverProps,
  PopoverAnchorProps,
  PopoverTriggerProps,
  PopoverPortalProps,
  PopoverContentProps,
  PopoverCloseProps,
  PopoverArrowProps,
};



================================================
FILE: packages/react/popper/README.md
================================================
# `react-popper`

This is an internal utility, not intended for public usage.



================================================
FILE: packages/react/popper/CHANGELOG.md
================================================
# @radix-ui/react-popper

## 1.2.8

- Fixed a bug to prevent infinite render loops
- Updated dependencies: `@radix-ui/react-context@1.1.3`, `@radix-ui/react-primitive@2.1.4`, `@radix-ui/react-arrow@1.1.8`

## 1.2.7

- Replace deprecated 'ElementRef' with 'ComponentRef' (#3426)
- Updated dependencies: `@radix-ui/react-arrow@1.1.7`, `@radix-ui/react-primitive@2.1.3`

## 1.2.6

- Updated dependencies: `@radix-ui/react-primitive@2.1.2`, `@radix-ui/react-arrow@1.1.6`

## 1.2.5

- Updated dependencies: `@radix-ui/react-primitive@2.1.1`, `@radix-ui/react-arrow@1.1.5`

## 1.2.4

- Updated dependencies: `@radix-ui/react-primitive@2.1.0`, `@radix-ui/react-arrow@1.1.4`



================================================
FILE: packages/react/popper/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/popper/package.json
================================================
{
  "name": "@radix-ui/react-popper",
  "version": "1.2.8",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@floating-ui/react-dom": "^2.0.0",
    "@radix-ui/react-arrow": "workspace:*",
    "@radix-ui/react-compose-refs": "workspace:*",
    "@radix-ui/react-context": "workspace:*",
    "@radix-ui/react-primitive": "workspace:*",
    "@radix-ui/react-use-callback-ref": "workspace:*",
    "@radix-ui/react-use-layout-effect": "workspace:*",
    "@radix-ui/react-use-rect": "workspace:*",
    "@radix-ui/react-use-size": "workspace:*",
    "@radix-ui/rect": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/popper/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/popper/src/index.ts
================================================
'use client';
export {
  createPopperScope,
  //
  Popper,
  PopperAnchor,
  PopperContent,
  PopperArrow,
  //
  Root,
  Anchor,
  Content,
  Arrow,
  //
  SIDE_OPTIONS,
  ALIGN_OPTIONS,
} from './popper';
export type {
  PopperProps,
  PopperAnchorProps,
  PopperContentProps,
  PopperArrowProps,
} from './popper';



================================================
FILE: packages/react/popper/src/popper.tsx
================================================
import * as React from 'react';
import {
  useFloating,
  autoUpdate,
  offset,
  shift,
  limitShift,
  hide,
  arrow as floatingUIarrow,
  flip,
  size,
} from '@floating-ui/react-dom';
import * as ArrowPrimitive from '@radix-ui/react-arrow';
import { useComposedRefs } from '@radix-ui/react-compose-refs';
import { createContextScope } from '@radix-ui/react-context';
import { Primitive } from '@radix-ui/react-primitive';
import { useCallbackRef } from '@radix-ui/react-use-callback-ref';
import { useLayoutEffect } from '@radix-ui/react-use-layout-effect';
import { useSize } from '@radix-ui/react-use-size';

import type { Placement, Middleware } from '@floating-ui/react-dom';
import type { Scope } from '@radix-ui/react-context';
import type { Measurable } from '@radix-ui/rect';

const SIDE_OPTIONS = ['top', 'right', 'bottom', 'left'] as const;
const ALIGN_OPTIONS = ['start', 'center', 'end'] as const;

type Side = (typeof SIDE_OPTIONS)[number];
type Align = (typeof ALIGN_OPTIONS)[number];

/* -------------------------------------------------------------------------------------------------
 * Popper
 * -----------------------------------------------------------------------------------------------*/

const POPPER_NAME = 'Popper';

type ScopedProps<P> = P & { __scopePopper?: Scope };
const [createPopperContext, createPopperScope] = createContextScope(POPPER_NAME);

type PopperContextValue = {
  anchor: Measurable | null;
  onAnchorChange(anchor: Measurable | null): void;
};
const [PopperProvider, usePopperContext] = createPopperContext<PopperContextValue>(POPPER_NAME);

interface PopperProps {
  children?: React.ReactNode;
}
const Popper: React.FC<PopperProps> = (props: ScopedProps<PopperProps>) => {
  const { __scopePopper, children } = props;
  const [anchor, setAnchor] = React.useState<Measurable | null>(null);
  return (
    <PopperProvider scope={__scopePopper} anchor={anchor} onAnchorChange={setAnchor}>
      {children}
    </PopperProvider>
  );
};

Popper.displayName = POPPER_NAME;

/* -------------------------------------------------------------------------------------------------
 * PopperAnchor
 * -----------------------------------------------------------------------------------------------*/

const ANCHOR_NAME = 'PopperAnchor';

type PopperAnchorElement = React.ComponentRef<typeof Primitive.div>;
type PrimitiveDivProps = React.ComponentPropsWithoutRef<typeof Primitive.div>;
interface PopperAnchorProps extends PrimitiveDivProps {
  virtualRef?: React.RefObject<Measurable>;
}

const PopperAnchor = React.forwardRef<PopperAnchorElement, PopperAnchorProps>(
  (props: ScopedProps<PopperAnchorProps>, forwardedRef) => {
    const { __scopePopper, virtualRef, ...anchorProps } = props;
    const context = usePopperContext(ANCHOR_NAME, __scopePopper);
    const ref = React.useRef<PopperAnchorElement>(null);
    const composedRefs = useComposedRefs(forwardedRef, ref);

    const anchorRef = React.useRef<Measurable | null>(null);
    React.useEffect(() => {
      const previousAnchor = anchorRef.current;
      anchorRef.current = virtualRef?.current || ref.current;
      if (previousAnchor !== anchorRef.current) {
        // Consumer can anchor the popper to something that isn't
        // a DOM node e.g. pointer position, so we override the
        // `anchorRef` with their virtual ref in this case.
        context.onAnchorChange(anchorRef.current);
      }
    });

    return virtualRef ? null : <Primitive.div {...anchorProps} ref={composedRefs} />;
  },
);

PopperAnchor.displayName = ANCHOR_NAME;

/* -------------------------------------------------------------------------------------------------
 * PopperContent
 * -----------------------------------------------------------------------------------------------*/

const CONTENT_NAME = 'PopperContent';

type PopperContentContextValue = {
  placedSide: Side;
  onArrowChange(arrow: HTMLSpanElement | null): void;
  arrowX?: number;
  arrowY?: number;
  shouldHideArrow: boolean;
};

const [PopperContentProvider, useContentContext] =
  createPopperContext<PopperContentContextValue>(CONTENT_NAME);

type Boundary = Element | null;

type PopperContentElement = React.ComponentRef<typeof Primitive.div>;
interface PopperContentProps extends PrimitiveDivProps {
  side?: Side;
  sideOffset?: number;
  align?: Align;
  alignOffset?: number;
  arrowPadding?: number;
  avoidCollisions?: boolean;
  collisionBoundary?: Boundary | Boundary[];
  collisionPadding?: number | Partial<Record<Side, number>>;
  sticky?: 'partial' | 'always';
  hideWhenDetached?: boolean;
  updatePositionStrategy?: 'optimized' | 'always';
  onPlaced?: () => void;
}

const PopperContent = React.forwardRef<PopperContentElement, PopperContentProps>(
  (props: ScopedProps<PopperContentProps>, forwardedRef) => {
    const {
      __scopePopper,
      side = 'bottom',
      sideOffset = 0,
      align = 'center',
      alignOffset = 0,
      arrowPadding = 0,
      avoidCollisions = true,
      collisionBoundary = [],
      collisionPadding: collisionPaddingProp = 0,
      sticky = 'partial',
      hideWhenDetached = false,
      updatePositionStrategy = 'optimized',
      onPlaced,
      ...contentProps
    } = props;

    const context = usePopperContext(CONTENT_NAME, __scopePopper);

    const [content, setContent] = React.useState<HTMLDivElement | null>(null);
    const composedRefs = useComposedRefs(forwardedRef, (node) => setContent(node));

    const [arrow, setArrow] = React.useState<HTMLSpanElement | null>(null);
    const arrowSize = useSize(arrow);
    const arrowWidth = arrowSize?.width ?? 0;
    const arrowHeight = arrowSize?.height ?? 0;

    const desiredPlacement = (side + (align !== 'center' ? '-' + align : '')) as Placement;

    const collisionPadding =
      typeof collisionPaddingProp === 'number'
        ? collisionPaddingProp
        : { top: 0, right: 0, bottom: 0, left: 0, ...collisionPaddingProp };

    const boundary = Array.isArray(collisionBoundary) ? collisionBoundary : [collisionBoundary];
    const hasExplicitBoundaries = boundary.length > 0;

    const detectOverflowOptions = {
      padding: collisionPadding,
      boundary: boundary.filter(isNotNull),
      // with `strategy: 'fixed'`, this is the only way to get it to respect boundaries
      altBoundary: hasExplicitBoundaries,
    };

    const { refs, floatingStyles, placement, isPositioned, middlewareData } = useFloating({
      // default to `fixed` strategy so users don't have to pick and we also avoid focus scroll issues
      strategy: 'fixed',
      placement: desiredPlacement,
      whileElementsMounted: (...args) => {
        const cleanup = autoUpdate(...args, {
          animationFrame: updatePositionStrategy === 'always',
        });
        return cleanup;
      },
      elements: {
        reference: context.anchor,
      },
      middleware: [
        offset({ mainAxis: sideOffset + arrowHeight, alignmentAxis: alignOffset }),
        avoidCollisions &&
          shift({
            mainAxis: true,
            crossAxis: false,
            limiter: sticky === 'partial' ? limitShift() : undefined,
            ...detectOverflowOptions,
          }),
        avoidCollisions && flip({ ...detectOverflowOptions }),
        size({
          ...detectOverflowOptions,
          apply: ({ elements, rects, availableWidth, availableHeight }) => {
            const { width: anchorWidth, height: anchorHeight } = rects.reference;
            const contentStyle = elements.floating.style;
            contentStyle.setProperty('--radix-popper-available-width', `${availableWidth}px`);
            contentStyle.setProperty('--radix-popper-available-height', `${availableHeight}px`);
            contentStyle.setProperty('--radix-popper-anchor-width', `${anchorWidth}px`);
            contentStyle.setProperty('--radix-popper-anchor-height', `${anchorHeight}px`);
          },
        }),
        arrow && floatingUIarrow({ element: arrow, padding: arrowPadding }),
        transformOrigin({ arrowWidth, arrowHeight }),
        hideWhenDetached && hide({ strategy: 'referenceHidden', ...detectOverflowOptions }),
      ],
    });

    const [placedSide, placedAlign] = getSideAndAlignFromPlacement(placement);

    const handlePlaced = useCallbackRef(onPlaced);
    useLayoutEffect(() => {
      if (isPositioned) {
        handlePlaced?.();
      }
    }, [isPositioned, handlePlaced]);

    const arrowX = middlewareData.arrow?.x;
    const arrowY = middlewareData.arrow?.y;
    const cannotCenterArrow = middlewareData.arrow?.centerOffset !== 0;

    const [contentZIndex, setContentZIndex] = React.useState<string>();
    useLayoutEffect(() => {
      if (content) setContentZIndex(window.getComputedStyle(content).zIndex);
    }, [content]);

    return (
      <div
        ref={refs.setFloating}
        data-radix-popper-content-wrapper=""
        style={{
          ...floatingStyles,
          transform: isPositioned ? floatingStyles.transform : 'translate(0, -200%)', // keep off the page when measuring
          minWidth: 'max-content',
          zIndex: contentZIndex,
          ['--radix-popper-transform-origin' as any]: [
            middlewareData.transformOrigin?.x,
            middlewareData.transformOrigin?.y,
          ].join(' '),

          // hide the content if using the hide middleware and should be hidden
          // set visibility to hidden and disable pointer events so the UI behaves
          // as if the PopperContent isn't there at all
          ...(middlewareData.hide?.referenceHidden && {
            visibility: 'hidden',
            pointerEvents: 'none',
          }),
        }}
        // Floating UI interally calculates logical alignment based the `dir` attribute on
        // the reference/floating node, we must add this attribute here to ensure
        // this is calculated when portalled as well as inline.
        dir={props.dir}
      >
        <PopperContentProvider
          scope={__scopePopper}
          placedSide={placedSide}
          onArrowChange={setArrow}
          arrowX={arrowX}
          arrowY={arrowY}
          shouldHideArrow={cannotCenterArrow}
        >
          <Primitive.div
            data-side={placedSide}
            data-align={placedAlign}
            {...contentProps}
            ref={composedRefs}
            style={{
              ...contentProps.style,
              // if the PopperContent hasn't been placed yet (not all measurements done)
              // we prevent animations so that users's animation don't kick in too early referring wrong sides
              animation: !isPositioned ? 'none' : undefined,
            }}
          />
        </PopperContentProvider>
      </div>
    );
  },
);

PopperContent.displayName = CONTENT_NAME;

/* -------------------------------------------------------------------------------------------------
 * PopperArrow
 * -----------------------------------------------------------------------------------------------*/

const ARROW_NAME = 'PopperArrow';

const OPPOSITE_SIDE: Record<Side, Side> = {
  top: 'bottom',
  right: 'left',
  bottom: 'top',
  left: 'right',
};

type PopperArrowElement = React.ComponentRef<typeof ArrowPrimitive.Root>;
type ArrowProps = React.ComponentPropsWithoutRef<typeof ArrowPrimitive.Root>;
interface PopperArrowProps extends ArrowProps {}

const PopperArrow = React.forwardRef<PopperArrowElement, PopperArrowProps>(function PopperArrow(
  props: ScopedProps<PopperArrowProps>,
  forwardedRef,
) {
  const { __scopePopper, ...arrowProps } = props;
  const contentContext = useContentContext(ARROW_NAME, __scopePopper);
  const baseSide = OPPOSITE_SIDE[contentContext.placedSide];

  return (
    // we have to use an extra wrapper because `ResizeObserver` (used by `useSize`)
    // doesn't report size as we'd expect on SVG elements.
    // it reports their bounding box which is effectively the largest path inside the SVG.
    <span
      ref={contentContext.onArrowChange}
      style={{
        position: 'absolute',
        left: contentContext.arrowX,
        top: contentContext.arrowY,
        [baseSide]: 0,
        transformOrigin: {
          top: '',
          right: '0 0',
          bottom: 'center 0',
          left: '100% 0',
        }[contentContext.placedSide],
        transform: {
          top: 'translateY(100%)',
          right: 'translateY(50%) rotate(90deg) translateX(-50%)',
          bottom: `rotate(180deg)`,
          left: 'translateY(50%) rotate(-90deg) translateX(50%)',
        }[contentContext.placedSide],
        visibility: contentContext.shouldHideArrow ? 'hidden' : undefined,
      }}
    >
      <ArrowPrimitive.Root
        {...arrowProps}
        ref={forwardedRef}
        style={{
          ...arrowProps.style,
          // ensures the element can be measured correctly (mostly for if SVG)
          display: 'block',
        }}
      />
    </span>
  );
});

PopperArrow.displayName = ARROW_NAME;

/* -----------------------------------------------------------------------------------------------*/

function isNotNull<T>(value: T | null): value is T {
  return value !== null;
}

const transformOrigin = (options: { arrowWidth: number; arrowHeight: number }): Middleware => ({
  name: 'transformOrigin',
  options,
  fn(data) {
    const { placement, rects, middlewareData } = data;

    const cannotCenterArrow = middlewareData.arrow?.centerOffset !== 0;
    const isArrowHidden = cannotCenterArrow;
    const arrowWidth = isArrowHidden ? 0 : options.arrowWidth;
    const arrowHeight = isArrowHidden ? 0 : options.arrowHeight;

    const [placedSide, placedAlign] = getSideAndAlignFromPlacement(placement);
    const noArrowAlign = { start: '0%', center: '50%', end: '100%' }[placedAlign];

    const arrowXCenter = (middlewareData.arrow?.x ?? 0) + arrowWidth / 2;
    const arrowYCenter = (middlewareData.arrow?.y ?? 0) + arrowHeight / 2;

    let x = '';
    let y = '';

    if (placedSide === 'bottom') {
      x = isArrowHidden ? noArrowAlign : `${arrowXCenter}px`;
      y = `${-arrowHeight}px`;
    } else if (placedSide === 'top') {
      x = isArrowHidden ? noArrowAlign : `${arrowXCenter}px`;
      y = `${rects.floating.height + arrowHeight}px`;
    } else if (placedSide === 'right') {
      x = `${-arrowHeight}px`;
      y = isArrowHidden ? noArrowAlign : `${arrowYCenter}px`;
    } else if (placedSide === 'left') {
      x = `${rects.floating.width + arrowHeight}px`;
      y = isArrowHidden ? noArrowAlign : `${arrowYCenter}px`;
    }
    return { data: { x, y } };
  },
});

function getSideAndAlignFromPlacement(placement: Placement) {
  const [side, align = 'center'] = placement.split('-');
  return [side as Side, align as Align] as const;
}

const Root = Popper;
const Anchor = PopperAnchor;
const Content = PopperContent;
const Arrow = PopperArrow;

export {
  createPopperScope,
  //
  Popper,
  PopperAnchor,
  PopperContent,
  PopperArrow,
  //
  Root,
  Anchor,
  Content,
  Arrow,
  //
  SIDE_OPTIONS,
  ALIGN_OPTIONS,
};
export type { PopperProps, PopperAnchorProps, PopperContentProps, PopperArrowProps };



================================================
FILE: packages/react/portal/README.md
================================================
# `react-portal`

View docs [here](https://radix-ui.com/primitives/docs/utilities/portal).



================================================
FILE: packages/react/portal/CHANGELOG.md
================================================
# @radix-ui/react-portal

## 1.1.10

- Updated dependencies: `@radix-ui/react-primitive@2.1.4`

## 1.1.9

- Replace deprecated 'ElementRef' with 'ComponentRef' (#3426)
- Updated dependencies: `@radix-ui/react-primitive@2.1.3`

## 1.1.8

- Updated dependencies: `@radix-ui/react-primitive@2.1.2`

## 1.1.7

- Updated dependencies: `@radix-ui/react-primitive@2.1.1`

## 1.1.6

- Updated dependencies: `@radix-ui/react-primitive@2.1.0`



================================================
FILE: packages/react/portal/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/portal/package.json
================================================
{
  "name": "@radix-ui/react-portal",
  "version": "1.1.10",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/react-primitive": "workspace:*",
    "@radix-ui/react-use-layout-effect": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/portal/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/portal/src/index.ts
================================================
'use client';
export {
  Portal,
  //
  Root,
} from './portal';
export type { PortalProps } from './portal';



================================================
FILE: packages/react/portal/src/portal.tsx
================================================
import * as React from 'react';
import ReactDOM from 'react-dom';
import { Primitive } from '@radix-ui/react-primitive';
import { useLayoutEffect } from '@radix-ui/react-use-layout-effect';

/* -------------------------------------------------------------------------------------------------
 * Portal
 * -----------------------------------------------------------------------------------------------*/

const PORTAL_NAME = 'Portal';

type PortalElement = React.ComponentRef<typeof Primitive.div>;
type PrimitiveDivProps = React.ComponentPropsWithoutRef<typeof Primitive.div>;
interface PortalProps extends PrimitiveDivProps {
  /**
   * An optional container where the portaled content should be appended.
   */
  container?: Element | DocumentFragment | null;
}

const Portal = React.forwardRef<PortalElement, PortalProps>((props, forwardedRef) => {
  const { container: containerProp, ...portalProps } = props;
  const [mounted, setMounted] = React.useState(false);
  useLayoutEffect(() => setMounted(true), []);
  const container = containerProp || (mounted && globalThis?.document?.body);
  return container
    ? ReactDOM.createPortal(<Primitive.div {...portalProps} ref={forwardedRef} />, container)
    : null;
});

Portal.displayName = PORTAL_NAME;

/* -----------------------------------------------------------------------------------------------*/

const Root = Portal;

export {
  Portal,
  //
  Root,
};
export type { PortalProps };



================================================
FILE: packages/react/presence/README.md
================================================
# `react-presence`

This is an internal utility, not intended for public usage.



================================================
FILE: packages/react/presence/CHANGELOG.md
================================================
# @radix-ui/react-presence

## 1.1.5

- Ensured that the `animationend` event is handled correctly when the keyframe has escapable characters (#2763)

## 1.1.4

- Fix memory leak in Presence



================================================
FILE: packages/react/presence/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/presence/package.json
================================================
{
  "name": "@radix-ui/react-presence",
  "version": "1.1.5",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/react-compose-refs": "workspace:*",
    "@radix-ui/react-use-layout-effect": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/presence/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/presence/src/index.ts
================================================
'use client';
export { Presence, Root } from './presence';
export type { PresenceProps } from './presence';



================================================
FILE: packages/react/presence/src/presence.tsx
================================================
import * as React from 'react';
import { useComposedRefs } from '@radix-ui/react-compose-refs';
import { useLayoutEffect } from '@radix-ui/react-use-layout-effect';
import { useStateMachine } from './use-state-machine';

interface PresenceProps {
  children: React.ReactElement | ((props: { present: boolean }) => React.ReactElement);
  present: boolean;
}

const Presence: React.FC<PresenceProps> = (props) => {
  const { present, children } = props;
  const presence = usePresence(present);

  const child = (
    typeof children === 'function'
      ? children({ present: presence.isPresent })
      : React.Children.only(children)
  ) as React.ReactElement<{ ref?: React.Ref<HTMLElement> }>;

  const ref = useComposedRefs(presence.ref, getElementRef(child));
  const forceMount = typeof children === 'function';
  return forceMount || presence.isPresent ? React.cloneElement(child, { ref }) : null;
};

Presence.displayName = 'Presence';

/* -------------------------------------------------------------------------------------------------
 * usePresence
 * -----------------------------------------------------------------------------------------------*/

function usePresence(present: boolean) {
  const [node, setNode] = React.useState<HTMLElement>();
  const stylesRef = React.useRef<CSSStyleDeclaration | null>(null);
  const prevPresentRef = React.useRef(present);
  const prevAnimationNameRef = React.useRef<string>('none');
  const initialState = present ? 'mounted' : 'unmounted';
  const [state, send] = useStateMachine(initialState, {
    mounted: {
      UNMOUNT: 'unmounted',
      ANIMATION_OUT: 'unmountSuspended',
    },
    unmountSuspended: {
      MOUNT: 'mounted',
      ANIMATION_END: 'unmounted',
    },
    unmounted: {
      MOUNT: 'mounted',
    },
  });

  React.useEffect(() => {
    const currentAnimationName = getAnimationName(stylesRef.current);
    prevAnimationNameRef.current = state === 'mounted' ? currentAnimationName : 'none';
  }, [state]);

  useLayoutEffect(() => {
    const styles = stylesRef.current;
    const wasPresent = prevPresentRef.current;
    const hasPresentChanged = wasPresent !== present;

    if (hasPresentChanged) {
      const prevAnimationName = prevAnimationNameRef.current;
      const currentAnimationName = getAnimationName(styles);

      if (present) {
        send('MOUNT');
      } else if (currentAnimationName === 'none' || styles?.display === 'none') {
        // If there is no exit animation or the element is hidden, animations won't run
        // so we unmount instantly
        send('UNMOUNT');
      } else {
        /**
         * When `present` changes to `false`, we check changes to animation-name to
         * determine whether an animation has started. We chose this approach (reading
         * computed styles) because there is no `animationrun` event and `animationstart`
         * fires after `animation-delay` has expired which would be too late.
         */
        const isAnimating = prevAnimationName !== currentAnimationName;

        if (wasPresent && isAnimating) {
          send('ANIMATION_OUT');
        } else {
          send('UNMOUNT');
        }
      }

      prevPresentRef.current = present;
    }
  }, [present, send]);

  useLayoutEffect(() => {
    if (node) {
      let timeoutId: number;
      const ownerWindow = node.ownerDocument.defaultView ?? window;
      /**
       * Triggering an ANIMATION_OUT during an ANIMATION_IN will fire an `animationcancel`
       * event for ANIMATION_IN after we have entered `unmountSuspended` state. So, we
       * make sure we only trigger ANIMATION_END for the currently active animation.
       */
      const handleAnimationEnd = (event: AnimationEvent) => {
        const currentAnimationName = getAnimationName(stylesRef.current);
        // The event.animationName is unescaped for CSS syntax,
        // so we need to escape it to compare with the animationName computed from the style.
        const isCurrentAnimation = currentAnimationName.includes(CSS.escape(event.animationName));
        if (event.target === node && isCurrentAnimation) {
          // With React 18 concurrency this update is applied a frame after the
          // animation ends, creating a flash of visible content. By setting the
          // animation fill mode to "forwards", we force the node to keep the
          // styles of the last keyframe, removing the flash.
          //
          // Previously we flushed the update via ReactDom.flushSync, but with
          // exit animations this resulted in the node being removed from the
          // DOM before the synthetic animationEnd event was dispatched, meaning
          // user-provided event handlers would not be called.
          // https://github.com/radix-ui/primitives/pull/1849
          send('ANIMATION_END');
          if (!prevPresentRef.current) {
            const currentFillMode = node.style.animationFillMode;
            node.style.animationFillMode = 'forwards';
            // Reset the style after the node had time to unmount (for cases
            // where the component chooses not to unmount). Doing this any
            // sooner than `setTimeout` (e.g. with `requestAnimationFrame`)
            // still causes a flash.
            timeoutId = ownerWindow.setTimeout(() => {
              if (node.style.animationFillMode === 'forwards') {
                node.style.animationFillMode = currentFillMode;
              }
            });
          }
        }
      };
      const handleAnimationStart = (event: AnimationEvent) => {
        if (event.target === node) {
          // if animation occurred, store its name as the previous animation.
          prevAnimationNameRef.current = getAnimationName(stylesRef.current);
        }
      };
      node.addEventListener('animationstart', handleAnimationStart);
      node.addEventListener('animationcancel', handleAnimationEnd);
      node.addEventListener('animationend', handleAnimationEnd);
      return () => {
        ownerWindow.clearTimeout(timeoutId);
        node.removeEventListener('animationstart', handleAnimationStart);
        node.removeEventListener('animationcancel', handleAnimationEnd);
        node.removeEventListener('animationend', handleAnimationEnd);
      };
    } else {
      // Transition to the unmounted state if the node is removed prematurely.
      // We avoid doing so during cleanup as the node may change but still exist.
      send('ANIMATION_END');
    }
  }, [node, send]);

  return {
    isPresent: ['mounted', 'unmountSuspended'].includes(state),
    ref: React.useCallback((node: HTMLElement) => {
      stylesRef.current = node ? getComputedStyle(node) : null;
      setNode(node);
    }, []),
  };
}

/* -----------------------------------------------------------------------------------------------*/

function getAnimationName(styles: CSSStyleDeclaration | null) {
  return styles?.animationName || 'none';
}

// Before React 19 accessing `element.props.ref` will throw a warning and suggest using `element.ref`
// After React 19 accessing `element.ref` does the opposite.
// https://github.com/facebook/react/pull/28348
//
// Access the ref using the method that doesn't yield a warning.
function getElementRef(element: React.ReactElement<{ ref?: React.Ref<unknown> }>) {
  // React <=18 in DEV
  let getter = Object.getOwnPropertyDescriptor(element.props, 'ref')?.get;
  let mayWarn = getter && 'isReactWarning' in getter && getter.isReactWarning;
  if (mayWarn) {
    return (element as any).ref;
  }

  // React 19 in DEV
  getter = Object.getOwnPropertyDescriptor(element, 'ref')?.get;
  mayWarn = getter && 'isReactWarning' in getter && getter.isReactWarning;
  if (mayWarn) {
    return element.props.ref;
  }

  // Not DEV
  return element.props.ref || (element as any).ref;
}

const Root = Presence;

export {
  Presence,
  //
  Root,
};
export type { PresenceProps };



================================================
FILE: packages/react/presence/src/use-state-machine.tsx
================================================
import * as React from 'react';

type Machine<S> = { [k: string]: { [k: string]: S } };
type MachineState<T> = keyof T;
type MachineEvent<T> = keyof UnionToIntersection<T[keyof T]>;

// 🤯 https://fettblog.eu/typescript-union-to-intersection/
type UnionToIntersection<T> = (T extends any ? (x: T) => any : never) extends (x: infer R) => any
  ? R
  : never;

export function useStateMachine<M>(
  initialState: MachineState<M>,
  machine: M & Machine<MachineState<M>>,
) {
  return React.useReducer((state: MachineState<M>, event: MachineEvent<M>): MachineState<M> => {
    const nextState = (machine[state] as any)[event];
    return nextState ?? state;
  }, initialState);
}



================================================
FILE: packages/react/primitive/README.md
================================================
# `react-primitive`

This is an internal utility, not intended for public usage.



================================================
FILE: packages/react/primitive/CHANGELOG.md
================================================
# @radix-ui/react-primitive

## 2.1.4

- Updated dependencies: `@radix-ui/react-slot@1.2.4`

## 2.1.3

- Updated dependencies: `@radix-ui/react-slot@1.2.3`

## 2.1.2

- Updated dependencies: `@radix-ui/react-slot@1.2.2`

## 2.1.1

- Updated dependencies: `@radix-ui/react-slot@1.2.1`

## 2.1.0

- All form controls with internal bubble inputs now use the Radix `Primitive` component by default. This will allow us to expose these components directly so users can better control this behavior in the future.



================================================
FILE: packages/react/primitive/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/primitive/package.json
================================================
{
  "name": "@radix-ui/react-primitive",
  "version": "2.1.4",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/react-slot": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/primitive/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/primitive/src/index.ts
================================================
export {
  Primitive,
  //
  Root,
  //
  dispatchDiscreteCustomEvent,
} from './primitive';
export type { PrimitivePropsWithRef } from './primitive';



================================================
FILE: packages/react/primitive/src/primitive.tsx
================================================
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { createSlot } from '@radix-ui/react-slot';

const NODES = [
  'a',
  'button',
  'div',
  'form',
  'h2',
  'h3',
  'img',
  'input',
  'label',
  'li',
  'nav',
  'ol',
  'p',
  'select',
  'span',
  'svg',
  'ul',
] as const;

type Primitives = { [E in (typeof NODES)[number]]: PrimitiveForwardRefComponent<E> };
type PrimitivePropsWithRef<E extends React.ElementType> = React.ComponentPropsWithRef<E> & {
  asChild?: boolean;
};

interface PrimitiveForwardRefComponent<E extends React.ElementType>
  extends React.ForwardRefExoticComponent<PrimitivePropsWithRef<E>> {}

/* -------------------------------------------------------------------------------------------------
 * Primitive
 * -----------------------------------------------------------------------------------------------*/

const Primitive = NODES.reduce((primitive, node) => {
  const Slot = createSlot(`Primitive.${node}`);
  const Node = React.forwardRef((props: PrimitivePropsWithRef<typeof node>, forwardedRef: any) => {
    const { asChild, ...primitiveProps } = props;
    const Comp: any = asChild ? Slot : node;

    if (typeof window !== 'undefined') {
      (window as any)[Symbol.for('radix-ui')] = true;
    }

    return <Comp {...primitiveProps} ref={forwardedRef} />;
  });

  Node.displayName = `Primitive.${node}`;

  return { ...primitive, [node]: Node };
}, {} as Primitives);

/* -------------------------------------------------------------------------------------------------
 * Utils
 * -----------------------------------------------------------------------------------------------*/

/**
 * Flush custom event dispatch
 * https://github.com/radix-ui/primitives/pull/1378
 *
 * React batches *all* event handlers since version 18, this introduces certain considerations when using custom event types.
 *
 * Internally, React prioritises events in the following order:
 *  - discrete
 *  - continuous
 *  - default
 *
 * https://github.com/facebook/react/blob/a8a4742f1c54493df00da648a3f9d26e3db9c8b5/packages/react-dom/src/events/ReactDOMEventListener.js#L294-L350
 *
 * `discrete` is an  important distinction as updates within these events are applied immediately.
 * React however, is not able to infer the priority of custom event types due to how they are detected internally.
 * Because of this, it's possible for updates from custom events to be unexpectedly batched when
 * dispatched by another `discrete` event.
 *
 * In order to ensure that updates from custom events are applied predictably, we need to manually flush the batch.
 * This utility should be used when dispatching a custom event from within another `discrete` event, this utility
 * is not necessary when dispatching known event types, or if dispatching a custom type inside a non-discrete event.
 * For example:
 *
 * dispatching a known click 👎
 * target.dispatchEvent(new Event(‘click’))
 *
 * dispatching a custom type within a non-discrete event 👎
 * onScroll={(event) => event.target.dispatchEvent(new CustomEvent(‘customType’))}
 *
 * dispatching a custom type within a `discrete` event 👍
 * onPointerDown={(event) => dispatchDiscreteCustomEvent(event.target, new CustomEvent(‘customType’))}
 *
 * Note: though React classifies `focus`, `focusin` and `focusout` events as `discrete`, it's  not recommended to use
 * this utility with them. This is because it's possible for those handlers to be called implicitly during render
 * e.g. when focus is within a component as it is unmounted, or when managing focus on mount.
 */

function dispatchDiscreteCustomEvent<E extends CustomEvent>(target: E['target'], event: E) {
  if (target) ReactDOM.flushSync(() => target.dispatchEvent(event));
}

/* -----------------------------------------------------------------------------------------------*/

const Root = Primitive;

export {
  Primitive,
  //
  Root,
  //
  dispatchDiscreteCustomEvent,
};
export type { PrimitivePropsWithRef };



================================================
FILE: packages/react/progress/README.md
================================================
# `react-progress`

View docs [here](https://radix-ui.com/primitives/docs/components/progress).



================================================
FILE: packages/react/progress/CHANGELOG.md
================================================
# @radix-ui/react-progress

## 1.1.8

- Updated dependencies: `@radix-ui/react-context@1.1.3`, `@radix-ui/react-primitive@2.1.4`

## 1.1.7

- Replace deprecated 'ElementRef' with 'ComponentRef' (#3426)
- Updated dependencies: `@radix-ui/react-primitive@2.1.3`

## 1.1.6

- Updated dependencies: `@radix-ui/react-primitive@2.1.2`

## 1.1.5

- Updated dependencies: `@radix-ui/react-primitive@2.1.1`

## 1.1.4

- Updated dependencies: `@radix-ui/react-primitive@2.1.0`



================================================
FILE: packages/react/progress/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/progress/package.json
================================================
{
  "name": "@radix-ui/react-progress",
  "version": "1.1.8",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/react-context": "workspace:*",
    "@radix-ui/react-primitive": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/progress/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/progress/src/index.ts
================================================
'use client';
export {
  createProgressScope,
  //
  Progress,
  ProgressIndicator,
  //
  Root,
  Indicator,
} from './progress';
export type { ProgressProps, ProgressIndicatorProps } from './progress';



================================================
FILE: packages/react/progress/src/progress.tsx
================================================
import * as React from 'react';
import { createContextScope } from '@radix-ui/react-context';
import { Primitive } from '@radix-ui/react-primitive';

import type { Scope } from '@radix-ui/react-context';

/* -------------------------------------------------------------------------------------------------
 * Progress
 * -----------------------------------------------------------------------------------------------*/

const PROGRESS_NAME = 'Progress';
const DEFAULT_MAX = 100;

type ScopedProps<P> = P & { __scopeProgress?: Scope };
const [createProgressContext, createProgressScope] = createContextScope(PROGRESS_NAME);

type ProgressState = 'indeterminate' | 'complete' | 'loading';
type ProgressContextValue = { value: number | null; max: number };
const [ProgressProvider, useProgressContext] =
  createProgressContext<ProgressContextValue>(PROGRESS_NAME);

type ProgressElement = React.ComponentRef<typeof Primitive.div>;
type PrimitiveDivProps = React.ComponentPropsWithoutRef<typeof Primitive.div>;
interface ProgressProps extends PrimitiveDivProps {
  value?: number | null | undefined;
  max?: number;
  getValueLabel?(value: number, max: number): string;
}

const Progress = React.forwardRef<ProgressElement, ProgressProps>(
  (props: ScopedProps<ProgressProps>, forwardedRef) => {
    const {
      __scopeProgress,
      value: valueProp = null,
      max: maxProp,
      getValueLabel = defaultGetValueLabel,
      ...progressProps
    } = props;

    if ((maxProp || maxProp === 0) && !isValidMaxNumber(maxProp)) {
      console.error(getInvalidMaxError(`${maxProp}`, 'Progress'));
    }

    const max = isValidMaxNumber(maxProp) ? maxProp : DEFAULT_MAX;

    if (valueProp !== null && !isValidValueNumber(valueProp, max)) {
      console.error(getInvalidValueError(`${valueProp}`, 'Progress'));
    }

    const value = isValidValueNumber(valueProp, max) ? valueProp : null;
    const valueLabel = isNumber(value) ? getValueLabel(value, max) : undefined;

    return (
      <ProgressProvider scope={__scopeProgress} value={value} max={max}>
        <Primitive.div
          aria-valuemax={max}
          aria-valuemin={0}
          aria-valuenow={isNumber(value) ? value : undefined}
          aria-valuetext={valueLabel}
          role="progressbar"
          data-state={getProgressState(value, max)}
          data-value={value ?? undefined}
          data-max={max}
          {...progressProps}
          ref={forwardedRef}
        />
      </ProgressProvider>
    );
  },
);

Progress.displayName = PROGRESS_NAME;

/* -------------------------------------------------------------------------------------------------
 * ProgressIndicator
 * -----------------------------------------------------------------------------------------------*/

const INDICATOR_NAME = 'ProgressIndicator';

type ProgressIndicatorElement = React.ComponentRef<typeof Primitive.div>;
interface ProgressIndicatorProps extends PrimitiveDivProps {}

const ProgressIndicator = React.forwardRef<ProgressIndicatorElement, ProgressIndicatorProps>(
  (props: ScopedProps<ProgressIndicatorProps>, forwardedRef) => {
    const { __scopeProgress, ...indicatorProps } = props;
    const context = useProgressContext(INDICATOR_NAME, __scopeProgress);
    return (
      <Primitive.div
        data-state={getProgressState(context.value, context.max)}
        data-value={context.value ?? undefined}
        data-max={context.max}
        {...indicatorProps}
        ref={forwardedRef}
      />
    );
  },
);

ProgressIndicator.displayName = INDICATOR_NAME;

/* ---------------------------------------------------------------------------------------------- */

function defaultGetValueLabel(value: number, max: number) {
  return `${Math.round((value / max) * 100)}%`;
}

function getProgressState(value: number | undefined | null, maxValue: number): ProgressState {
  return value == null ? 'indeterminate' : value === maxValue ? 'complete' : 'loading';
}

function isNumber(value: any): value is number {
  return typeof value === 'number';
}

function isValidMaxNumber(max: any): max is number {
  // prettier-ignore
  return (
    isNumber(max) &&
    !isNaN(max) &&
    max > 0
  );
}

function isValidValueNumber(value: any, max: number): value is number {
  // prettier-ignore
  return (
    isNumber(value) &&
    !isNaN(value) &&
    value <= max &&
    value >= 0
  );
}

// Split this out for clearer readability of the error message.
function getInvalidMaxError(propValue: string, componentName: string) {
  return `Invalid prop \`max\` of value \`${propValue}\` supplied to \`${componentName}\`. Only numbers greater than 0 are valid max values. Defaulting to \`${DEFAULT_MAX}\`.`;
}

function getInvalidValueError(propValue: string, componentName: string) {
  return `Invalid prop \`value\` of value \`${propValue}\` supplied to \`${componentName}\`. The \`value\` prop must be:
  - a positive number
  - less than the value passed to \`max\` (or ${DEFAULT_MAX} if no \`max\` prop is set)
  - \`null\` or \`undefined\` if the progress is indeterminate.

Defaulting to \`null\`.`;
}

const Root = Progress;
const Indicator = ProgressIndicator;

export {
  createProgressScope,
  //
  Progress,
  ProgressIndicator,
  //
  Root,
  Indicator,
};
export type { ProgressProps, ProgressIndicatorProps };



================================================
FILE: packages/react/radio-group/README.md
================================================
# `react-radio-group`

View docs [here](https://radix-ui.com/primitives/docs/components/radio-group).



================================================
FILE: packages/react/radio-group/CHANGELOG.md
================================================
# @radix-ui/react-radio-group

## 1.3.8

- Updated dependencies: `@radix-ui/react-presence@1.1.5`, `@radix-ui/primitive@1.1.3`, `@radix-ui/react-context@1.1.3`, `@radix-ui/react-primitive@2.1.4`, `@radix-ui/react-roving-focus@1.1.11`

## 1.3.7

- Replace deprecated 'ElementRef' with 'ComponentRef' (#3426)
- Updated dependencies: `@radix-ui/react-roving-focus@1.1.10`, `@radix-ui/react-primitive@2.1.3`

## 1.3.6

- Updated dependencies: `@radix-ui/react-primitive@2.1.2`, `@radix-ui/react-roving-focus@1.1.9`

## 1.3.5

- Allow passing value of `null` to controlled Radio Group when all items are unchecked
- Updated dependencies: `@radix-ui/react-primitive@2.1.1`, `@radix-ui/react-roving-focus@1.1.8`

## 1.3.4

- Updated dependencies: `@radix-ui/react-presence@1.1.4`

## 1.3.3

- Updated dependencies: `@radix-ui/react-roving-focus@1.1.7`

## 1.3.2

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.2`, `@radix-ui/react-roving-focus@1.1.6`

## 1.3.1

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.1`, `@radix-ui/react-roving-focus@1.1.5`

## 1.3.0

- All form controls with internal bubble inputs now use the Radix `Primitive` component by default. This will allow us to expose these components directly so users can better control this behavior in the future.
- Minor improvements to `useControllableState` to enhance performance, reduce surface area for bugs, and log warnings when misused (#3455)
- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.0`, `@radix-ui/react-roving-focus@1.1.4`, `@radix-ui/react-primitive@2.1.0`



================================================
FILE: packages/react/radio-group/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/radio-group/package.json
================================================
{
  "name": "@radix-ui/react-radio-group",
  "version": "1.3.8",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/primitive": "workspace:*",
    "@radix-ui/react-compose-refs": "workspace:*",
    "@radix-ui/react-context": "workspace:*",
    "@radix-ui/react-direction": "workspace:*",
    "@radix-ui/react-presence": "workspace:*",
    "@radix-ui/react-primitive": "workspace:*",
    "@radix-ui/react-roving-focus": "workspace:*",
    "@radix-ui/react-use-controllable-state": "workspace:*",
    "@radix-ui/react-use-previous": "workspace:*",
    "@radix-ui/react-use-size": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/radio-group/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/radio-group/src/index.ts
================================================
'use client';
export {
  createRadioGroupScope,
  //
  RadioGroup,
  RadioGroupItem,
  RadioGroupIndicator,
  //
  Root,
  Item,
  Indicator,
} from './radio-group';
export type { RadioGroupProps, RadioGroupItemProps, RadioGroupIndicatorProps } from './radio-group';



================================================
FILE: packages/react/radio-group/src/radio-group.tsx
================================================
import * as React from 'react';
import { composeEventHandlers } from '@radix-ui/primitive';
import { useComposedRefs } from '@radix-ui/react-compose-refs';
import { createContextScope } from '@radix-ui/react-context';
import { Primitive } from '@radix-ui/react-primitive';
import * as RovingFocusGroup from '@radix-ui/react-roving-focus';
import { createRovingFocusGroupScope } from '@radix-ui/react-roving-focus';
import { useControllableState } from '@radix-ui/react-use-controllable-state';
import { useDirection } from '@radix-ui/react-direction';
import { Radio, RadioIndicator, createRadioScope } from './radio';

import type { Scope } from '@radix-ui/react-context';

const ARROW_KEYS = ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'];

/* -------------------------------------------------------------------------------------------------
 * RadioGroup
 * -----------------------------------------------------------------------------------------------*/
const RADIO_GROUP_NAME = 'RadioGroup';

type ScopedProps<P> = P & { __scopeRadioGroup?: Scope };
const [createRadioGroupContext, createRadioGroupScope] = createContextScope(RADIO_GROUP_NAME, [
  createRovingFocusGroupScope,
  createRadioScope,
]);
const useRovingFocusGroupScope = createRovingFocusGroupScope();
const useRadioScope = createRadioScope();

type RadioGroupContextValue = {
  name?: string;
  required: boolean;
  disabled: boolean;
  value: string | null;
  onValueChange(value: string): void;
};

const [RadioGroupProvider, useRadioGroupContext] =
  createRadioGroupContext<RadioGroupContextValue>(RADIO_GROUP_NAME);

type RadioGroupElement = React.ComponentRef<typeof Primitive.div>;
type RovingFocusGroupProps = React.ComponentPropsWithoutRef<typeof RovingFocusGroup.Root>;
type PrimitiveDivProps = React.ComponentPropsWithoutRef<typeof Primitive.div>;
interface RadioGroupProps extends PrimitiveDivProps {
  name?: RadioGroupContextValue['name'];
  required?: React.ComponentPropsWithoutRef<typeof Radio>['required'];
  disabled?: React.ComponentPropsWithoutRef<typeof Radio>['disabled'];
  dir?: RovingFocusGroupProps['dir'];
  orientation?: RovingFocusGroupProps['orientation'];
  loop?: RovingFocusGroupProps['loop'];
  defaultValue?: string;
  value?: string | null;
  onValueChange?: RadioGroupContextValue['onValueChange'];
}

const RadioGroup = React.forwardRef<RadioGroupElement, RadioGroupProps>(
  (props: ScopedProps<RadioGroupProps>, forwardedRef) => {
    const {
      __scopeRadioGroup,
      name,
      defaultValue,
      value: valueProp,
      required = false,
      disabled = false,
      orientation,
      dir,
      loop = true,
      onValueChange,
      ...groupProps
    } = props;
    const rovingFocusGroupScope = useRovingFocusGroupScope(__scopeRadioGroup);
    const direction = useDirection(dir);
    const [value, setValue] = useControllableState({
      prop: valueProp,
      defaultProp: defaultValue ?? null,
      onChange: onValueChange as (value: string | null) => void,
      caller: RADIO_GROUP_NAME,
    });

    return (
      <RadioGroupProvider
        scope={__scopeRadioGroup}
        name={name}
        required={required}
        disabled={disabled}
        value={value}
        onValueChange={setValue}
      >
        <RovingFocusGroup.Root
          asChild
          {...rovingFocusGroupScope}
          orientation={orientation}
          dir={direction}
          loop={loop}
        >
          <Primitive.div
            role="radiogroup"
            aria-required={required}
            aria-orientation={orientation}
            data-disabled={disabled ? '' : undefined}
            dir={direction}
            {...groupProps}
            ref={forwardedRef}
          />
        </RovingFocusGroup.Root>
      </RadioGroupProvider>
    );
  },
);

RadioGroup.displayName = RADIO_GROUP_NAME;

/* -------------------------------------------------------------------------------------------------
 * RadioGroupItem
 * -----------------------------------------------------------------------------------------------*/

const ITEM_NAME = 'RadioGroupItem';

type RadioGroupItemElement = React.ComponentRef<typeof Radio>;
type RadioProps = React.ComponentPropsWithoutRef<typeof Radio>;
interface RadioGroupItemProps extends Omit<RadioProps, 'onCheck' | 'name'> {
  value: string;
}

const RadioGroupItem = React.forwardRef<RadioGroupItemElement, RadioGroupItemProps>(
  (props: ScopedProps<RadioGroupItemProps>, forwardedRef) => {
    const { __scopeRadioGroup, disabled, ...itemProps } = props;
    const context = useRadioGroupContext(ITEM_NAME, __scopeRadioGroup);
    const isDisabled = context.disabled || disabled;
    const rovingFocusGroupScope = useRovingFocusGroupScope(__scopeRadioGroup);
    const radioScope = useRadioScope(__scopeRadioGroup);
    const ref = React.useRef<React.ComponentRef<typeof Radio>>(null);
    const composedRefs = useComposedRefs(forwardedRef, ref);
    const checked = context.value === itemProps.value;
    const isArrowKeyPressedRef = React.useRef(false);

    React.useEffect(() => {
      const handleKeyDown = (event: KeyboardEvent) => {
        if (ARROW_KEYS.includes(event.key)) {
          isArrowKeyPressedRef.current = true;
        }
      };
      const handleKeyUp = () => (isArrowKeyPressedRef.current = false);
      document.addEventListener('keydown', handleKeyDown);
      document.addEventListener('keyup', handleKeyUp);
      return () => {
        document.removeEventListener('keydown', handleKeyDown);
        document.removeEventListener('keyup', handleKeyUp);
      };
    }, []);

    return (
      <RovingFocusGroup.Item
        asChild
        {...rovingFocusGroupScope}
        focusable={!isDisabled}
        active={checked}
      >
        <Radio
          disabled={isDisabled}
          required={context.required}
          checked={checked}
          {...radioScope}
          {...itemProps}
          name={context.name}
          ref={composedRefs}
          onCheck={() => context.onValueChange(itemProps.value)}
          onKeyDown={composeEventHandlers((event) => {
            // According to WAI ARIA, radio groups don't activate items on enter keypress
            if (event.key === 'Enter') event.preventDefault();
          })}
          onFocus={composeEventHandlers(itemProps.onFocus, () => {
            /**
             * Our `RovingFocusGroup` will focus the radio when navigating with arrow keys
             * and we need to "check" it in that case. We click it to "check" it (instead
             * of updating `context.value`) so that the radio change event fires.
             */
            if (isArrowKeyPressedRef.current) ref.current?.click();
          })}
        />
      </RovingFocusGroup.Item>
    );
  },
);

RadioGroupItem.displayName = ITEM_NAME;

/* -------------------------------------------------------------------------------------------------
 * RadioGroupIndicator
 * -----------------------------------------------------------------------------------------------*/

const INDICATOR_NAME = 'RadioGroupIndicator';

type RadioGroupIndicatorElement = React.ComponentRef<typeof RadioIndicator>;
type RadioIndicatorProps = React.ComponentPropsWithoutRef<typeof RadioIndicator>;
interface RadioGroupIndicatorProps extends RadioIndicatorProps {}

const RadioGroupIndicator = React.forwardRef<RadioGroupIndicatorElement, RadioGroupIndicatorProps>(
  (props: ScopedProps<RadioGroupIndicatorProps>, forwardedRef) => {
    const { __scopeRadioGroup, ...indicatorProps } = props;
    const radioScope = useRadioScope(__scopeRadioGroup);
    return <RadioIndicator {...radioScope} {...indicatorProps} ref={forwardedRef} />;
  },
);

RadioGroupIndicator.displayName = INDICATOR_NAME;

/* ---------------------------------------------------------------------------------------------- */

const Root = RadioGroup;
const Item = RadioGroupItem;
const Indicator = RadioGroupIndicator;

export {
  createRadioGroupScope,
  //
  RadioGroup,
  RadioGroupItem,
  RadioGroupIndicator,
  //
  Root,
  Item,
  Indicator,
};
export type { RadioGroupProps, RadioGroupItemProps, RadioGroupIndicatorProps };



================================================
FILE: packages/react/radio-group/src/radio.tsx
================================================
import * as React from 'react';
import { composeEventHandlers } from '@radix-ui/primitive';
import { useComposedRefs } from '@radix-ui/react-compose-refs';
import { createContextScope } from '@radix-ui/react-context';
import { useSize } from '@radix-ui/react-use-size';
import { usePrevious } from '@radix-ui/react-use-previous';
import { Presence } from '@radix-ui/react-presence';
import { Primitive } from '@radix-ui/react-primitive';

import type { Scope } from '@radix-ui/react-context';

/* -------------------------------------------------------------------------------------------------
 * Radio
 * -----------------------------------------------------------------------------------------------*/

const RADIO_NAME = 'Radio';

type ScopedProps<P> = P & { __scopeRadio?: Scope };
const [createRadioContext, createRadioScope] = createContextScope(RADIO_NAME);

type RadioContextValue = { checked: boolean; disabled?: boolean };
const [RadioProvider, useRadioContext] = createRadioContext<RadioContextValue>(RADIO_NAME);

type RadioElement = React.ComponentRef<typeof Primitive.button>;
type PrimitiveButtonProps = React.ComponentPropsWithoutRef<typeof Primitive.button>;
interface RadioProps extends PrimitiveButtonProps {
  checked?: boolean;
  required?: boolean;
  onCheck?(): void;
}

const Radio = React.forwardRef<RadioElement, RadioProps>(
  (props: ScopedProps<RadioProps>, forwardedRef) => {
    const {
      __scopeRadio,
      name,
      checked = false,
      required,
      disabled,
      value = 'on',
      onCheck,
      form,
      ...radioProps
    } = props;
    const [button, setButton] = React.useState<HTMLButtonElement | null>(null);
    const composedRefs = useComposedRefs(forwardedRef, (node) => setButton(node));
    const hasConsumerStoppedPropagationRef = React.useRef(false);
    // We set this to true by default so that events bubble to forms without JS (SSR)
    const isFormControl = button ? form || !!button.closest('form') : true;

    return (
      <RadioProvider scope={__scopeRadio} checked={checked} disabled={disabled}>
        <Primitive.button
          type="button"
          role="radio"
          aria-checked={checked}
          data-state={getState(checked)}
          data-disabled={disabled ? '' : undefined}
          disabled={disabled}
          value={value}
          {...radioProps}
          ref={composedRefs}
          onClick={composeEventHandlers(props.onClick, (event) => {
            // radios cannot be unchecked so we only communicate a checked state
            if (!checked) onCheck?.();
            if (isFormControl) {
              hasConsumerStoppedPropagationRef.current = event.isPropagationStopped();
              // if radio is in a form, stop propagation from the button so that we only propagate
              // one click event (from the input). We propagate changes from an input so that native
              // form validation works and form events reflect radio updates.
              if (!hasConsumerStoppedPropagationRef.current) event.stopPropagation();
            }
          })}
        />
        {isFormControl && (
          <RadioBubbleInput
            control={button}
            bubbles={!hasConsumerStoppedPropagationRef.current}
            name={name}
            value={value}
            checked={checked}
            required={required}
            disabled={disabled}
            form={form}
            // We transform because the input is absolutely positioned but we have
            // rendered it **after** the button. This pulls it back to sit on top
            // of the button.
            style={{ transform: 'translateX(-100%)' }}
          />
        )}
      </RadioProvider>
    );
  },
);

Radio.displayName = RADIO_NAME;

/* -------------------------------------------------------------------------------------------------
 * RadioIndicator
 * -----------------------------------------------------------------------------------------------*/

const INDICATOR_NAME = 'RadioIndicator';

type RadioIndicatorElement = React.ComponentRef<typeof Primitive.span>;
type PrimitiveSpanProps = React.ComponentPropsWithoutRef<typeof Primitive.span>;
export interface RadioIndicatorProps extends PrimitiveSpanProps {
  /**
   * Used to force mounting when more control is needed. Useful when
   * controlling animation with React animation libraries.
   */
  forceMount?: true;
}

const RadioIndicator = React.forwardRef<RadioIndicatorElement, RadioIndicatorProps>(
  (props: ScopedProps<RadioIndicatorProps>, forwardedRef) => {
    const { __scopeRadio, forceMount, ...indicatorProps } = props;
    const context = useRadioContext(INDICATOR_NAME, __scopeRadio);
    return (
      <Presence present={forceMount || context.checked}>
        <Primitive.span
          data-state={getState(context.checked)}
          data-disabled={context.disabled ? '' : undefined}
          {...indicatorProps}
          ref={forwardedRef}
        />
      </Presence>
    );
  },
);

RadioIndicator.displayName = INDICATOR_NAME;

/* -------------------------------------------------------------------------------------------------
 * RadioBubbleInput
 * -----------------------------------------------------------------------------------------------*/

const BUBBLE_INPUT_NAME = 'RadioBubbleInput';

type InputProps = React.ComponentPropsWithoutRef<typeof Primitive.input>;
interface RadioBubbleInputProps extends Omit<InputProps, 'checked'> {
  checked: boolean;
  control: HTMLElement | null;
  bubbles: boolean;
}

const RadioBubbleInput = React.forwardRef<HTMLInputElement, RadioBubbleInputProps>(
  (
    {
      __scopeRadio,
      control,
      checked,
      bubbles = true,
      ...props
    }: ScopedProps<RadioBubbleInputProps>,
    forwardedRef,
  ) => {
    const ref = React.useRef<HTMLInputElement>(null);
    const composedRefs = useComposedRefs(ref, forwardedRef);
    const prevChecked = usePrevious(checked);
    const controlSize = useSize(control);

    // Bubble checked change to parents (e.g form change event)
    React.useEffect(() => {
      const input = ref.current;
      if (!input) return;

      const inputProto = window.HTMLInputElement.prototype;
      const descriptor = Object.getOwnPropertyDescriptor(
        inputProto,
        'checked',
      ) as PropertyDescriptor;
      const setChecked = descriptor.set;
      if (prevChecked !== checked && setChecked) {
        const event = new Event('click', { bubbles });
        setChecked.call(input, checked);
        input.dispatchEvent(event);
      }
    }, [prevChecked, checked, bubbles]);

    return (
      <Primitive.input
        type="radio"
        aria-hidden
        defaultChecked={checked}
        {...props}
        tabIndex={-1}
        ref={composedRefs}
        style={{
          ...props.style,
          ...controlSize,
          position: 'absolute',
          pointerEvents: 'none',
          opacity: 0,
          margin: 0,
        }}
      />
    );
  },
);

RadioBubbleInput.displayName = BUBBLE_INPUT_NAME;

/* ---------------------------------------------------------------------------------------------- */

function getState(checked: boolean) {
  return checked ? 'checked' : 'unchecked';
}

export {
  createRadioScope,
  //
  Radio,
  RadioIndicator,
};
export type { RadioProps };



================================================
FILE: packages/react/radix-ui/README.md
================================================
[![Radix Primitives Logo](https://raw.githubusercontent.com/radix-ui/primitives/main/primitives.png)](https://radix-ui.com/primitives)

# Radix Primitives

**An open-source UI component library for building high-quality, accessible design systems and web apps.**

Radix Primitives is a low-level UI component library with a focus on accessibility, customization and developer experience. You can use these components either as the base layer of your design system, or adopt them incrementally.

---

## Documentation

For full documentation, visit [radix-ui.com/docs/primitives](https://radix-ui.com/docs/primitives).

## Releases

For changelog, visit [radix-ui.com/docs/primitives/overview/releases](https://radix-ui.com/docs/primitives/overview/releases).

---

## Community

- [Discord](https://discord.com/invite/7Xb99uG) - To get involved with the Radix community, ask questions and share tips.
- [Twitter](https://twitter.com/radix_ui) - To receive updates, announcements, blog posts, and general Radix tips.

## Thanks

<a href="https://www.chromatic.com/"><img src="https://user-images.githubusercontent.com/321738/84662277-e3db4f80-af1b-11ea-88f5-91d67a5e59f6.png" width="153" height="30" alt="Chromatic" /></a>

Thanks to [Chromatic](https://www.chromatic.com/) for providing the visual testing platform that helps us review UI changes and catch visual regressions.

---

## License

Licensed under the MIT License, Copyright © 2022-present [WorkOS](https://workos.com).



================================================
FILE: packages/react/radix-ui/CHANGELOG.md
================================================
# radix-ui

## 1.4.3

### One-Time Password Field

- Fixed a bug so that all input elements are disabled when the `Root` component is disabled
- Fixed a bug with iOS Chrome autocomplete (#3641)

### Popper

- Fixed a bug causing infinite render loops

### Presence

- Ensured that the `animationend` event is handled correctly when the keyframe has escapable characters (#2763)

### Slot

- Fixed an issue with how slot components interact with lazy React components in React 19. In the case of a lazy component instance, the resulting promise must be consumed to render the desired component.

### Toast

- Fixed several accessibility issues:
  - Removed `aria-hidden` from the focusable element, as these elements are already empty and won't be read by screen readers
  - Removed `role=status` from list item element (see [w3.org documentation for List Item](https://www.w3.org/TR/html-aria/#docconformance))
  - Remove useless default `aria-atomic` from `role=status`

### Other changes

- Added `displayName` to internal context objects for improved debugging

## 1.4.2

- Updated dependencies: `@radix-ui/react-dismissable-layer@1.1.10`, `@radix-ui/react-navigation-menu@1.2.13`, `@radix-ui/react-visually-hidden@1.2.3`, `@radix-ui/react-dropdown-menu@2.1.15`, `@radix-ui/react-alert-dialog@1.1.14`, `@radix-ui/react-aspect-ratio@1.1.7`, `@radix-ui/react-context-menu@2.2.15`, `@radix-ui/react-roving-focus@1.1.10`, `@radix-ui/react-toggle-group@1.1.10`, `@radix-ui/react-collapsible@1.1.11`, `@radix-ui/react-focus-scope@1.1.7`, `@radix-ui/react-radio-group@1.3.7`, `@radix-ui/react-scroll-area@1.2.9`, `@radix-ui/react-hover-card@1.1.14`, `@radix-ui/react-accordion@1.2.11`, `@radix-ui/react-separator@1.1.7`, `@radix-ui/react-checkbox@1.3.2`, `@radix-ui/react-progress@1.1.7`, `@radix-ui/react-menubar@1.1.15`, `@radix-ui/react-popover@1.1.14`, `@radix-ui/react-toolbar@1.1.10`, `@radix-ui/react-tooltip@1.2.7`, `@radix-ui/react-avatar@1.1.10`, `@radix-ui/react-dialog@1.1.14`, `@radix-ui/react-popper@1.2.7`, `@radix-ui/react-portal@1.1.9`, `@radix-ui/react-select@2.2.5`, `@radix-ui/react-slider@1.3.5`, `@radix-ui/react-switch@1.2.5`, `@radix-ui/react-toggle@1.1.9`, `@radix-ui/react-arrow@1.1.7`, `@radix-ui/react-label@2.1.7`, `@radix-ui/react-toast@1.2.14`, `@radix-ui/react-form@0.1.7`, `@radix-ui/react-menu@2.1.15`, `@radix-ui/react-slot@1.2.3`, `@radix-ui/react-tabs@1.1.12`, `@radix-ui/react-accessible-icon@1.1.7`, `@radix-ui/react-one-time-password-field@0.1.7`, `@radix-ui/react-collection@1.1.7`, `@radix-ui/react-primitive@2.1.3`, `@radix-ui/react-password-toggle-field@0.1.2`

## 1.4.1

- Updated dependencies: `@radix-ui/react-slot@1.2.2`, `@radix-ui/react-checkbox@1.3.1`, `@radix-ui/react-alert-dialog@1.1.13`, `@radix-ui/react-collection@1.1.6`, `@radix-ui/react-dialog@1.1.13`, `@radix-ui/react-menu@2.1.14`, `@radix-ui/react-popover@1.1.13`, `@radix-ui/react-primitive@2.1.2`, `@radix-ui/react-select@2.2.4`, `@radix-ui/react-tooltip@1.2.6`, `@radix-ui/react-accordion@1.2.10`, `@radix-ui/react-menubar@1.1.14`, `@radix-ui/react-navigation-menu@1.2.12`, `@radix-ui/react-one-time-password-field@0.1.6`, `@radix-ui/react-roving-focus@1.1.9`, `@radix-ui/react-slider@1.3.4`, `@radix-ui/react-toast@1.2.13`, `@radix-ui/react-context-menu@2.2.14`, `@radix-ui/react-dropdown-menu@2.1.14`, `@radix-ui/react-arrow@1.1.6`, `@radix-ui/react-aspect-ratio@1.1.6`, `@radix-ui/react-avatar@1.1.9`, `@radix-ui/react-collapsible@1.1.10`, `@radix-ui/react-dismissable-layer@1.1.9`, `@radix-ui/react-focus-scope@1.1.6`, `@radix-ui/react-form@0.1.6`, `@radix-ui/react-hover-card@1.1.13`, `@radix-ui/react-label@2.1.6`, `@radix-ui/react-password-toggle-field@0.1.1`, `@radix-ui/react-popper@1.2.6`, `@radix-ui/react-portal@1.1.8`, `@radix-ui/react-progress@1.1.6`, `@radix-ui/react-radio-group@1.3.6`, `@radix-ui/react-scroll-area@1.2.8`, `@radix-ui/react-separator@1.1.6`, `@radix-ui/react-switch@1.2.4`, `@radix-ui/react-tabs@1.1.11`, `@radix-ui/react-toggle@1.1.8`, `@radix-ui/react-toggle-group@1.1.9`, `@radix-ui/react-toolbar@1.1.9`, `@radix-ui/react-visually-hidden@1.2.2`, `@radix-ui/react-accessible-icon@1.1.6`

## 1.4.0

### Introduce new Password Toggle Field primitive

This new primitive provides components for rendering a password input alongside a button to toggle its visibility. Aside from its primary functionality, it also includes:

- Returning focus to the input when toggling with a pointer
- Maintaining focus when toggling with keyboard or virtual navigation
- Resetting visibility to hidden after form submission to prevent accidental storage
- Implicit accessible labeling for icon-based toggle buttons

This API is currently unstable, and we hope you'll help us test it out! Import the primitive using the `unstable_` prefix.

```tsx
import { unstable_PasswordToggleField as PasswordToggleField } from 'radix-ui';

function FieldWithIconToggle() {
  return (
    <PasswordToggleField.Root>
      <PasswordToggleField.Input />
      <PasswordToggleField.Toggle>
        <PasswordToggleField.Icon visible={<EyeOpenIcon />} hidden={<EyeClosedIcon />} />
      </PasswordToggleField.Toggle>
    </PasswordToggleField.Root>
  );
}

function FieldWithTextToggle() {
  return (
    <PasswordToggleField.Root>
      <PasswordToggleField.Input />
      <PasswordToggleField.Toggle>
        <PasswordToggleField.Slot visible="Hide password" hidden="Show password" />
      </PasswordToggleField.Toggle>
    </PasswordToggleField.Root>
  );
}
```

### Other updates

- Add unstable `Provider`, `Trigger` and `BubbleInput` parts to Checkbox ([#3459](https://github.com/radix-ui/primitives/pull/3459))
- Updated dependencies: `@radix-ui/react-slot@1.2.1`, `@radix-ui/react-one-time-password-field@0.1.5`, `@radix-ui/react-checkbox@1.3.0`, `@radix-ui/react-radio-group@1.3.5`, `@radix-ui/react-password-toggle-field@0.1.0`, `@radix-ui/react-alert-dialog@1.1.12`, `@radix-ui/react-collection@1.1.5`, `@radix-ui/react-dialog@1.1.12`, `@radix-ui/react-menu@2.1.13`, `@radix-ui/react-popover@1.1.12`, `@radix-ui/react-primitive@2.1.1`, `@radix-ui/react-select@2.2.3`, `@radix-ui/react-tooltip@1.2.5`, `@radix-ui/react-accordion@1.2.9`, `@radix-ui/react-menubar@1.1.13`, `@radix-ui/react-navigation-menu@1.2.11`, `@radix-ui/react-roving-focus@1.1.8`, `@radix-ui/react-slider@1.3.3`, `@radix-ui/react-toast@1.2.12`, `@radix-ui/react-context-menu@2.2.13`, `@radix-ui/react-dropdown-menu@2.1.13`, `@radix-ui/react-arrow@1.1.5`, `@radix-ui/react-aspect-ratio@1.1.5`, `@radix-ui/react-avatar@1.1.8`, `@radix-ui/react-collapsible@1.1.9`, `@radix-ui/react-dismissable-layer@1.1.8`, `@radix-ui/react-focus-scope@1.1.5`, `@radix-ui/react-form@0.1.5`, `@radix-ui/react-hover-card@1.1.12`, `@radix-ui/react-label@2.1.5`, `@radix-ui/react-popper@1.2.5`, `@radix-ui/react-portal@1.1.7`, `@radix-ui/react-progress@1.1.5`, `@radix-ui/react-scroll-area@1.2.7`, `@radix-ui/react-separator@1.1.5`, `@radix-ui/react-switch@1.2.3`, `@radix-ui/react-tabs@1.1.10`, `@radix-ui/react-toggle@1.1.7`, `@radix-ui/react-toggle-group@1.1.8`, `@radix-ui/react-toolbar@1.1.8`, `@radix-ui/react-visually-hidden@1.2.1`, `@radix-ui/react-accessible-icon@1.1.5`

## 1.3.4

- Updated dependencies: `@radix-ui/react-use-is-hydrated@0.1.0`, `@radix-ui/react-presence@1.1.4`, `@radix-ui/react-avatar@1.1.7`, `@radix-ui/react-one-time-password-field@0.1.4`, `@radix-ui/react-checkbox@1.2.3`, `@radix-ui/react-collapsible@1.1.8`, `@radix-ui/react-dialog@1.1.11`, `@radix-ui/react-hover-card@1.1.11`, `@radix-ui/react-menu@2.1.12`, `@radix-ui/react-navigation-menu@1.2.10`, `@radix-ui/react-popover@1.1.11`, `@radix-ui/react-radio-group@1.3.4`, `@radix-ui/react-scroll-area@1.2.6`, `@radix-ui/react-tabs@1.1.9`, `@radix-ui/react-toast@1.2.11`, `@radix-ui/react-tooltip@1.2.4`, `@radix-ui/react-accordion@1.2.8`, `@radix-ui/react-alert-dialog@1.1.11`, `@radix-ui/react-context-menu@2.2.12`, `@radix-ui/react-dropdown-menu@2.1.12`, `@radix-ui/react-menubar@1.1.12`

## 1.3.3

- Updated dependencies: `@radix-ui/react-one-time-password-field@0.1.3`, `@radix-ui/react-roving-focus@1.1.7`, `@radix-ui/react-menu@2.1.11`, `@radix-ui/react-menubar@1.1.11`, `@radix-ui/react-radio-group@1.3.3`, `@radix-ui/react-tabs@1.1.8`, `@radix-ui/react-toggle-group@1.1.7`, `@radix-ui/react-toolbar@1.1.7`, `@radix-ui/react-context-menu@2.2.11`, `@radix-ui/react-dropdown-menu@2.1.11`

## 1.3.2

- Updated dependencies: `@radix-ui/react-use-effect-event@0.0.2`, `@radix-ui/react-avatar@1.1.6`, `@radix-ui/react-one-time-password-field@0.1.2`, `@radix-ui/react-use-controllable-state@1.2.2`, `@radix-ui/react-accordion@1.2.7`, `@radix-ui/react-checkbox@1.2.2`, `@radix-ui/react-collapsible@1.1.7`, `@radix-ui/react-context-menu@2.2.10`, `@radix-ui/react-dialog@1.1.10`, `@radix-ui/react-dropdown-menu@2.1.10`, `@radix-ui/react-hover-card@1.1.10`, `@radix-ui/react-menubar@1.1.10`, `@radix-ui/react-navigation-menu@1.2.9`, `@radix-ui/react-popover@1.1.10`, `@radix-ui/react-radio-group@1.3.2`, `@radix-ui/react-roving-focus@1.1.6`, `@radix-ui/react-select@2.2.2`, `@radix-ui/react-slider@1.3.2`, `@radix-ui/react-switch@1.2.2`, `@radix-ui/react-tabs@1.1.7`, `@radix-ui/react-toast@1.2.10`, `@radix-ui/react-toggle@1.1.6`, `@radix-ui/react-toggle-group@1.1.6`, `@radix-ui/react-tooltip@1.2.3`, `@radix-ui/react-alert-dialog@1.1.10`, `@radix-ui/react-menu@2.1.10`, `@radix-ui/react-toolbar@1.1.6`

## 1.3.1

- Updated dependencies: `@radix-ui/react-use-effect-event@0.0.1`, `@radix-ui/react-one-time-password-field@0.1.1`, `@radix-ui/react-use-controllable-state@1.2.1`, `@radix-ui/react-accordion@1.2.6`, `@radix-ui/react-checkbox@1.2.1`, `@radix-ui/react-collapsible@1.1.6`, `@radix-ui/react-context-menu@2.2.9`, `@radix-ui/react-dialog@1.1.9`, `@radix-ui/react-dropdown-menu@2.1.9`, `@radix-ui/react-hover-card@1.1.9`, `@radix-ui/react-menubar@1.1.9`, `@radix-ui/react-navigation-menu@1.2.8`, `@radix-ui/react-popover@1.1.9`, `@radix-ui/react-radio-group@1.3.1`, `@radix-ui/react-roving-focus@1.1.5`, `@radix-ui/react-select@2.2.1`, `@radix-ui/react-slider@1.3.1`, `@radix-ui/react-switch@1.2.1`, `@radix-ui/react-tabs@1.1.6`, `@radix-ui/react-toast@1.2.9`, `@radix-ui/react-toggle@1.1.5`, `@radix-ui/react-toggle-group@1.1.5`, `@radix-ui/react-tooltip@1.2.2`, `@radix-ui/react-alert-dialog@1.1.9`, `@radix-ui/react-menu@2.1.9`, `@radix-ui/react-toolbar@1.1.5`

## 1.3.0

### Introduce new One Time Password Field primitive

This new primitive is designed to implement the common design pattern for one-time password fields displayed as separate input fields for each character. This UI is deceptively complex to implement so that interactions follow user expectations. The new primitive handles all of this complexity for you, including:

- Keyboard navigation mimicking the behavior of a single input field
- Overriding values on paste
- Password manager autofill support
- Input validation for numeric and alphanumeric values
- Auto-submit on completion
- Focus management
- Hidden input to provide a single value to form data

This API is currently unstable, and we hope you'll help us test it out! Import the primitive using the `unstable_` prefix.

```tsx
import { unstable_OneTimePasswordField as OneTimePasswordField } from 'radix-ui';

export function Verify() {
  return (
    <OneTimePasswordField.Root>
      <OneTimePasswordField.Input />
      <OneTimePasswordField.Input />
      <OneTimePasswordField.Input />
      <OneTimePasswordField.Input />
      <OneTimePasswordField.Input />
      <OneTimePasswordField.Input />
      <OneTimePasswordField.HiddenInput />
    </OneTimePasswordField.Root>
  );
}
```

### Other updates

- Updated dependencies: `@radix-ui/react-collection@1.1.4`, `@radix-ui/react-use-controllable-state@1.2.0`, `@radix-ui/react-navigation-menu@1.2.7`, `@radix-ui/react-dropdown-menu@2.1.8`, `@radix-ui/react-context-menu@2.2.8`, `@radix-ui/react-roving-focus@1.1.4`, `@radix-ui/react-toggle-group@1.1.4`, `@radix-ui/react-collapsible@1.1.5`, `@radix-ui/react-radio-group@1.3.0`, `@radix-ui/react-hover-card@1.1.8`, `@radix-ui/react-accordion@1.2.5`, `@radix-ui/react-checkbox@1.2.0`, `@radix-ui/react-menubar@1.1.8`, `@radix-ui/react-popover@1.1.8`, `@radix-ui/react-tooltip@1.2.1`, `@radix-ui/react-dialog@1.1.8`, `@radix-ui/react-select@2.2.0`, `@radix-ui/react-switch@1.2.0`, `@radix-ui/react-toggle@1.1.4`, `@radix-ui/react-toast@1.2.8`, `@radix-ui/react-tabs@1.1.5`, `@radix-ui/react-one-time-password-field@0.1.0`, `@radix-ui/react-visually-hidden@1.2.0`, `@radix-ui/react-primitive@2.1.0`, `@radix-ui/react-slider@1.3.0`, `@radix-ui/react-menu@2.1.8`, `@radix-ui/react-toolbar@1.1.4`, `@radix-ui/react-alert-dialog@1.1.8`, `@radix-ui/react-accessible-icon@1.1.4`, `@radix-ui/react-arrow@1.1.4`, `@radix-ui/react-aspect-ratio@1.1.4`, `@radix-ui/react-avatar@1.1.5`, `@radix-ui/react-dismissable-layer@1.1.7`, `@radix-ui/react-focus-scope@1.1.4`, `@radix-ui/react-form@0.1.4`, `@radix-ui/react-label@2.1.4`, `@radix-ui/react-popper@1.2.4`, `@radix-ui/react-portal@1.1.6`, `@radix-ui/react-progress@1.1.4`, `@radix-ui/react-scroll-area@1.2.5`, `@radix-ui/react-separator@1.1.4`



================================================
FILE: packages/react/radix-ui/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/radix-ui/package.json
================================================
{
  "name": "radix-ui",
  "version": "1.4.3",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "exports": {
    ".": "./src/index.ts",
    "./*": "./src/*.ts"
  },
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      },
      "./*": {
        "import": {
          "types": "./dist/*.d.mts",
          "default": "./dist/*.mjs"
        },
        "require": {
          "types": "./dist/*.d.ts",
          "default": "./dist/*.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "src",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build:esm": "tsc",
    "build:cjs": "tsc --module commonjs --moduleResolution node --outDir dist/cjs",
    "// build": "pnpm run --parallel \"/^build:.*/\"",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/primitive": "workspace:*",
    "@radix-ui/react-accessible-icon": "workspace:*",
    "@radix-ui/react-accordion": "workspace:*",
    "@radix-ui/react-alert-dialog": "workspace:*",
    "@radix-ui/react-arrow": "workspace:*",
    "@radix-ui/react-aspect-ratio": "workspace:*",
    "@radix-ui/react-avatar": "workspace:*",
    "@radix-ui/react-checkbox": "workspace:*",
    "@radix-ui/react-collapsible": "workspace:*",
    "@radix-ui/react-collection": "workspace:*",
    "@radix-ui/react-compose-refs": "workspace:*",
    "@radix-ui/react-context": "workspace:*",
    "@radix-ui/react-context-menu": "workspace:*",
    "@radix-ui/react-dialog": "workspace:*",
    "@radix-ui/react-direction": "workspace:*",
    "@radix-ui/react-dismissable-layer": "workspace:*",
    "@radix-ui/react-dropdown-menu": "workspace:*",
    "@radix-ui/react-focus-guards": "workspace:*",
    "@radix-ui/react-focus-scope": "workspace:*",
    "@radix-ui/react-form": "workspace:*",
    "@radix-ui/react-hover-card": "workspace:*",
    "@radix-ui/react-label": "workspace:*",
    "@radix-ui/react-menu": "workspace:*",
    "@radix-ui/react-menubar": "workspace:*",
    "@radix-ui/react-navigation-menu": "workspace:*",
    "@radix-ui/react-one-time-password-field": "workspace:*",
    "@radix-ui/react-password-toggle-field": "workspace:*",
    "@radix-ui/react-popover": "workspace:*",
    "@radix-ui/react-popper": "workspace:*",
    "@radix-ui/react-portal": "workspace:*",
    "@radix-ui/react-presence": "workspace:*",
    "@radix-ui/react-primitive": "workspace:*",
    "@radix-ui/react-progress": "workspace:*",
    "@radix-ui/react-radio-group": "workspace:*",
    "@radix-ui/react-roving-focus": "workspace:*",
    "@radix-ui/react-scroll-area": "workspace:*",
    "@radix-ui/react-select": "workspace:*",
    "@radix-ui/react-separator": "workspace:*",
    "@radix-ui/react-slider": "workspace:*",
    "@radix-ui/react-slot": "workspace:*",
    "@radix-ui/react-switch": "workspace:*",
    "@radix-ui/react-tabs": "workspace:*",
    "@radix-ui/react-toast": "workspace:*",
    "@radix-ui/react-toggle": "workspace:*",
    "@radix-ui/react-toggle-group": "workspace:*",
    "@radix-ui/react-toolbar": "workspace:*",
    "@radix-ui/react-tooltip": "workspace:*",
    "@radix-ui/react-use-callback-ref": "workspace:*",
    "@radix-ui/react-use-controllable-state": "workspace:*",
    "@radix-ui/react-use-effect-event": "workspace:*",
    "@radix-ui/react-use-escape-keydown": "workspace:*",
    "@radix-ui/react-use-is-hydrated": "workspace:*",
    "@radix-ui/react-use-layout-effect": "workspace:*",
    "@radix-ui/react-use-size": "workspace:*",
    "@radix-ui/react-visually-hidden": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/radix-ui/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/radix-ui/src/index.ts
================================================
export * as AccessibleIcon from '@radix-ui/react-accessible-icon';
export * as Accordion from '@radix-ui/react-accordion';
export * as AlertDialog from '@radix-ui/react-alert-dialog';
export * as AspectRatio from '@radix-ui/react-aspect-ratio';
export * as Avatar from '@radix-ui/react-avatar';
export * as Checkbox from '@radix-ui/react-checkbox';
export * as Collapsible from '@radix-ui/react-collapsible';
export * as ContextMenu from '@radix-ui/react-context-menu';
export * as Dialog from '@radix-ui/react-dialog';
export * as Direction from '@radix-ui/react-direction';
export * as DropdownMenu from '@radix-ui/react-dropdown-menu';
export * as Form from '@radix-ui/react-form';
export * as HoverCard from '@radix-ui/react-hover-card';
export * as Label from '@radix-ui/react-label';
export * as Menubar from '@radix-ui/react-menubar';
export * as NavigationMenu from '@radix-ui/react-navigation-menu';
export * as unstable_OneTimePasswordField from '@radix-ui/react-one-time-password-field';
export * as unstable_PasswordToggleField from '@radix-ui/react-password-toggle-field';
export * as Popover from '@radix-ui/react-popover';
export * as Portal from '@radix-ui/react-portal';
export * as Progress from '@radix-ui/react-progress';
export * as RadioGroup from '@radix-ui/react-radio-group';
export * as ScrollArea from '@radix-ui/react-scroll-area';
export * as Select from '@radix-ui/react-select';
export * as Separator from '@radix-ui/react-separator';
export * as Slider from '@radix-ui/react-slider';
export * as Slot from '@radix-ui/react-slot';
export * as Switch from '@radix-ui/react-switch';
export * as Tabs from '@radix-ui/react-tabs';
export * as Toast from '@radix-ui/react-toast';
export * as Toggle from '@radix-ui/react-toggle';
export * as ToggleGroup from '@radix-ui/react-toggle-group';
export * as Toolbar from '@radix-ui/react-toolbar';
export * as Tooltip from '@radix-ui/react-tooltip';
export * as VisuallyHidden from '@radix-ui/react-visually-hidden';



================================================
FILE: packages/react/radix-ui/src/internal.ts
================================================
import { Primitive as BasePrimitive, dispatchDiscreteCustomEvent } from '@radix-ui/react-primitive';
export * as Arrow from '@radix-ui/react-arrow';
export * as Collection from '@radix-ui/react-collection';
export { composeRefs, useComposedRefs } from '@radix-ui/react-compose-refs';
export * as Context from '@radix-ui/react-context';
export * as DismissableLayer from '@radix-ui/react-dismissable-layer';
export * as FocusGuards from '@radix-ui/react-focus-guards';
export * as FocusScope from '@radix-ui/react-focus-scope';
export * as Menu from '@radix-ui/react-menu';
export * as Popper from '@radix-ui/react-popper';
export * as Presence from '@radix-ui/react-presence';
export type { PrimitivePropsWithRef } from '@radix-ui/react-primitive';
export * as RovingFocus from '@radix-ui/react-roving-focus';
export { useCallbackRef } from '@radix-ui/react-use-callback-ref';
export {
  useControllableState,
  useControllableStateReducer,
} from '@radix-ui/react-use-controllable-state';
export { useEffectEvent } from '@radix-ui/react-use-effect-event';
export { useEscapeKeydown } from '@radix-ui/react-use-escape-keydown';
export { useIsHydrated } from '@radix-ui/react-use-is-hydrated';
export { useLayoutEffect } from '@radix-ui/react-use-layout-effect';
export { useSize } from '@radix-ui/react-use-size';
export { composeEventHandlers } from '@radix-ui/primitive';

const Primitive = BasePrimitive as typeof BasePrimitive & {
  Root: typeof BasePrimitive;
  dispatchDiscreteCustomEvent: typeof dispatchDiscreteCustomEvent;
};
Primitive.dispatchDiscreteCustomEvent = dispatchDiscreteCustomEvent;
Primitive.Root = BasePrimitive;
export { Primitive };



================================================
FILE: packages/react/roving-focus/README.md
================================================
# `react-roving-focus`

This is an internal utility, not intended for public usage.



================================================
FILE: packages/react/roving-focus/CHANGELOG.md
================================================
# @radix-ui/react-roving-focus

## 1.1.11

- Updated dependencies: `@radix-ui/primitive@1.1.3`, `@radix-ui/react-context@1.1.3`, `@radix-ui/react-collection@1.1.8`, `@radix-ui/react-primitive@2.1.4`

## 1.1.10

- Replace deprecated 'ElementRef' with 'ComponentRef' (#3426)
- Updated dependencies: `@radix-ui/react-collection@1.1.7`, `@radix-ui/react-primitive@2.1.3`

## 1.1.9

- Updated dependencies: `@radix-ui/react-collection@1.1.6`, `@radix-ui/react-primitive@2.1.2`

## 1.1.8

- Updated dependencies: `@radix-ui/react-collection@1.1.5`, `@radix-ui/react-primitive@2.1.1`

## 1.1.7

- Internal changes to render props

## 1.1.6

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.2`

## 1.1.5

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.1`

## 1.1.4

- Minor improvements to `useControllableState` to enhance performance, reduce surface area for bugs, and log warnings when misused (#3455)
- Accept function as child
- Updated dependencies: `@radix-ui/react-collection@1.1.4`, `@radix-ui/react-use-controllable-state@1.2.0`, `@radix-ui/react-primitive@2.1.0`



================================================
FILE: packages/react/roving-focus/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/roving-focus/package.json
================================================
{
  "name": "@radix-ui/react-roving-focus",
  "version": "1.1.11",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/primitive": "workspace:*",
    "@radix-ui/react-collection": "workspace:*",
    "@radix-ui/react-compose-refs": "workspace:*",
    "@radix-ui/react-context": "workspace:*",
    "@radix-ui/react-direction": "workspace:*",
    "@radix-ui/react-id": "workspace:*",
    "@radix-ui/react-primitive": "workspace:*",
    "@radix-ui/react-use-callback-ref": "workspace:*",
    "@radix-ui/react-use-controllable-state": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/roving-focus/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/roving-focus/src/index.ts
================================================
'use client';
export {
  createRovingFocusGroupScope,
  //
  RovingFocusGroup,
  RovingFocusGroupItem,
  //
  Root,
  Item,
} from './roving-focus-group';
export type { RovingFocusGroupProps, RovingFocusItemProps } from './roving-focus-group';



================================================
FILE: packages/react/roving-focus/src/roving-focus-group.tsx
================================================
import * as React from 'react';
import { composeEventHandlers } from '@radix-ui/primitive';
import { createCollection } from '@radix-ui/react-collection';
import { useComposedRefs } from '@radix-ui/react-compose-refs';
import { createContextScope } from '@radix-ui/react-context';
import { useId } from '@radix-ui/react-id';
import { Primitive } from '@radix-ui/react-primitive';
import { useCallbackRef } from '@radix-ui/react-use-callback-ref';
import { useControllableState } from '@radix-ui/react-use-controllable-state';
import { useDirection } from '@radix-ui/react-direction';

import type { Scope } from '@radix-ui/react-context';

const ENTRY_FOCUS = 'rovingFocusGroup.onEntryFocus';
const EVENT_OPTIONS = { bubbles: false, cancelable: true };

/* -------------------------------------------------------------------------------------------------
 * RovingFocusGroup
 * -----------------------------------------------------------------------------------------------*/

const GROUP_NAME = 'RovingFocusGroup';

type ItemData = { id: string; focusable: boolean; active: boolean };
const [Collection, useCollection, createCollectionScope] = createCollection<
  HTMLSpanElement,
  ItemData
>(GROUP_NAME);

type ScopedProps<P> = P & { __scopeRovingFocusGroup?: Scope };
const [createRovingFocusGroupContext, createRovingFocusGroupScope] = createContextScope(
  GROUP_NAME,
  [createCollectionScope],
);

type Orientation = React.AriaAttributes['aria-orientation'];
type Direction = 'ltr' | 'rtl';

interface RovingFocusGroupOptions {
  /**
   * The orientation of the group.
   * Mainly so arrow navigation is done accordingly (left & right vs. up & down)
   */
  orientation?: Orientation;
  /**
   * The direction of navigation between items.
   */
  dir?: Direction;
  /**
   * Whether keyboard navigation should loop around
   * @defaultValue false
   */
  loop?: boolean;
}

type RovingContextValue = RovingFocusGroupOptions & {
  currentTabStopId: string | null;
  onItemFocus(tabStopId: string): void;
  onItemShiftTab(): void;
  onFocusableItemAdd(): void;
  onFocusableItemRemove(): void;
};

const [RovingFocusProvider, useRovingFocusContext] =
  createRovingFocusGroupContext<RovingContextValue>(GROUP_NAME);

type RovingFocusGroupElement = RovingFocusGroupImplElement;
interface RovingFocusGroupProps extends RovingFocusGroupImplProps {}

const RovingFocusGroup = React.forwardRef<RovingFocusGroupElement, RovingFocusGroupProps>(
  (props: ScopedProps<RovingFocusGroupProps>, forwardedRef) => {
    return (
      <Collection.Provider scope={props.__scopeRovingFocusGroup}>
        <Collection.Slot scope={props.__scopeRovingFocusGroup}>
          <RovingFocusGroupImpl {...props} ref={forwardedRef} />
        </Collection.Slot>
      </Collection.Provider>
    );
  },
);

RovingFocusGroup.displayName = GROUP_NAME;

/* -----------------------------------------------------------------------------------------------*/

type RovingFocusGroupImplElement = React.ComponentRef<typeof Primitive.div>;
type PrimitiveDivProps = React.ComponentPropsWithoutRef<typeof Primitive.div>;
interface RovingFocusGroupImplProps
  extends Omit<PrimitiveDivProps, 'dir'>,
    RovingFocusGroupOptions {
  currentTabStopId?: string | null;
  defaultCurrentTabStopId?: string;
  onCurrentTabStopIdChange?: (tabStopId: string | null) => void;
  onEntryFocus?: (event: Event) => void;
  preventScrollOnEntryFocus?: boolean;
}

const RovingFocusGroupImpl = React.forwardRef<
  RovingFocusGroupImplElement,
  RovingFocusGroupImplProps
>((props: ScopedProps<RovingFocusGroupImplProps>, forwardedRef) => {
  const {
    __scopeRovingFocusGroup,
    orientation,
    loop = false,
    dir,
    currentTabStopId: currentTabStopIdProp,
    defaultCurrentTabStopId,
    onCurrentTabStopIdChange,
    onEntryFocus,
    preventScrollOnEntryFocus = false,
    ...groupProps
  } = props;
  const ref = React.useRef<RovingFocusGroupImplElement>(null);
  const composedRefs = useComposedRefs(forwardedRef, ref);
  const direction = useDirection(dir);
  const [currentTabStopId, setCurrentTabStopId] = useControllableState({
    prop: currentTabStopIdProp,
    defaultProp: defaultCurrentTabStopId ?? null,
    onChange: onCurrentTabStopIdChange,
    caller: GROUP_NAME,
  });
  const [isTabbingBackOut, setIsTabbingBackOut] = React.useState(false);
  const handleEntryFocus = useCallbackRef(onEntryFocus);
  const getItems = useCollection(__scopeRovingFocusGroup);
  const isClickFocusRef = React.useRef(false);
  const [focusableItemsCount, setFocusableItemsCount] = React.useState(0);

  React.useEffect(() => {
    const node = ref.current;
    if (node) {
      node.addEventListener(ENTRY_FOCUS, handleEntryFocus);
      return () => node.removeEventListener(ENTRY_FOCUS, handleEntryFocus);
    }
  }, [handleEntryFocus]);

  return (
    <RovingFocusProvider
      scope={__scopeRovingFocusGroup}
      orientation={orientation}
      dir={direction}
      loop={loop}
      currentTabStopId={currentTabStopId}
      onItemFocus={React.useCallback(
        (tabStopId) => setCurrentTabStopId(tabStopId),
        [setCurrentTabStopId],
      )}
      onItemShiftTab={React.useCallback(() => setIsTabbingBackOut(true), [])}
      onFocusableItemAdd={React.useCallback(
        () => setFocusableItemsCount((prevCount) => prevCount + 1),
        [],
      )}
      onFocusableItemRemove={React.useCallback(
        () => setFocusableItemsCount((prevCount) => prevCount - 1),
        [],
      )}
    >
      <Primitive.div
        tabIndex={isTabbingBackOut || focusableItemsCount === 0 ? -1 : 0}
        data-orientation={orientation}
        {...groupProps}
        ref={composedRefs}
        style={{ outline: 'none', ...props.style }}
        onMouseDown={composeEventHandlers(props.onMouseDown, () => {
          isClickFocusRef.current = true;
        })}
        onFocus={composeEventHandlers(props.onFocus, (event) => {
          // We normally wouldn't need this check, because we already check
          // that the focus is on the current target and not bubbling to it.
          // We do this because Safari doesn't focus buttons when clicked, and
          // instead, the wrapper will get focused and not through a bubbling event.
          const isKeyboardFocus = !isClickFocusRef.current;

          if (event.target === event.currentTarget && isKeyboardFocus && !isTabbingBackOut) {
            const entryFocusEvent = new CustomEvent(ENTRY_FOCUS, EVENT_OPTIONS);
            event.currentTarget.dispatchEvent(entryFocusEvent);

            if (!entryFocusEvent.defaultPrevented) {
              const items = getItems().filter((item) => item.focusable);
              const activeItem = items.find((item) => item.active);
              const currentItem = items.find((item) => item.id === currentTabStopId);
              const candidateItems = [activeItem, currentItem, ...items].filter(
                Boolean,
              ) as typeof items;
              const candidateNodes = candidateItems.map((item) => item.ref.current!);
              focusFirst(candidateNodes, preventScrollOnEntryFocus);
            }
          }

          isClickFocusRef.current = false;
        })}
        onBlur={composeEventHandlers(props.onBlur, () => setIsTabbingBackOut(false))}
      />
    </RovingFocusProvider>
  );
});

/* -------------------------------------------------------------------------------------------------
 * RovingFocusGroupItem
 * -----------------------------------------------------------------------------------------------*/

const ITEM_NAME = 'RovingFocusGroupItem';

type RovingFocusItemElement = React.ComponentRef<typeof Primitive.span>;
type PrimitiveSpanProps = React.ComponentPropsWithoutRef<typeof Primitive.span>;
interface RovingFocusItemProps extends Omit<PrimitiveSpanProps, 'children'> {
  tabStopId?: string;
  focusable?: boolean;
  active?: boolean;
  children?:
    | React.ReactNode
    | ((props: { hasTabStop: boolean; isCurrentTabStop: boolean }) => React.ReactNode);
}

const RovingFocusGroupItem = React.forwardRef<RovingFocusItemElement, RovingFocusItemProps>(
  (props: ScopedProps<RovingFocusItemProps>, forwardedRef) => {
    const {
      __scopeRovingFocusGroup,
      focusable = true,
      active = false,
      tabStopId,
      children,
      ...itemProps
    } = props;
    const autoId = useId();
    const id = tabStopId || autoId;
    const context = useRovingFocusContext(ITEM_NAME, __scopeRovingFocusGroup);
    const isCurrentTabStop = context.currentTabStopId === id;
    const getItems = useCollection(__scopeRovingFocusGroup);

    const { onFocusableItemAdd, onFocusableItemRemove, currentTabStopId } = context;

    React.useEffect(() => {
      if (focusable) {
        onFocusableItemAdd();
        return () => onFocusableItemRemove();
      }
    }, [focusable, onFocusableItemAdd, onFocusableItemRemove]);

    return (
      <Collection.ItemSlot
        scope={__scopeRovingFocusGroup}
        id={id}
        focusable={focusable}
        active={active}
      >
        <Primitive.span
          tabIndex={isCurrentTabStop ? 0 : -1}
          data-orientation={context.orientation}
          {...itemProps}
          ref={forwardedRef}
          onMouseDown={composeEventHandlers(props.onMouseDown, (event) => {
            // We prevent focusing non-focusable items on `mousedown`.
            // Even though the item has tabIndex={-1}, that only means take it out of the tab order.
            if (!focusable) event.preventDefault();
            // Safari doesn't focus a button when clicked so we run our logic on mousedown also
            else context.onItemFocus(id);
          })}
          onFocus={composeEventHandlers(props.onFocus, () => context.onItemFocus(id))}
          onKeyDown={composeEventHandlers(props.onKeyDown, (event) => {
            if (event.key === 'Tab' && event.shiftKey) {
              context.onItemShiftTab();
              return;
            }

            if (event.target !== event.currentTarget) return;

            const focusIntent = getFocusIntent(event, context.orientation, context.dir);

            if (focusIntent !== undefined) {
              if (event.metaKey || event.ctrlKey || event.altKey || event.shiftKey) return;
              event.preventDefault();
              const items = getItems().filter((item) => item.focusable);
              let candidateNodes = items.map((item) => item.ref.current!);

              if (focusIntent === 'last') candidateNodes.reverse();
              else if (focusIntent === 'prev' || focusIntent === 'next') {
                if (focusIntent === 'prev') candidateNodes.reverse();
                const currentIndex = candidateNodes.indexOf(event.currentTarget);
                candidateNodes = context.loop
                  ? wrapArray(candidateNodes, currentIndex + 1)
                  : candidateNodes.slice(currentIndex + 1);
              }

              /**
               * Imperative focus during keydown is risky so we prevent React's batching updates
               * to avoid potential bugs. See: https://github.com/facebook/react/issues/20332
               */
              setTimeout(() => focusFirst(candidateNodes));
            }
          })}
        >
          {typeof children === 'function'
            ? children({ isCurrentTabStop, hasTabStop: currentTabStopId != null })
            : children}
        </Primitive.span>
      </Collection.ItemSlot>
    );
  },
);

RovingFocusGroupItem.displayName = ITEM_NAME;

/* -----------------------------------------------------------------------------------------------*/

// prettier-ignore
const MAP_KEY_TO_FOCUS_INTENT: Record<string, FocusIntent> = {
  ArrowLeft: 'prev', ArrowUp: 'prev',
  ArrowRight: 'next', ArrowDown: 'next',
  PageUp: 'first', Home: 'first',
  PageDown: 'last', End: 'last',
};

function getDirectionAwareKey(key: string, dir?: Direction) {
  if (dir !== 'rtl') return key;
  return key === 'ArrowLeft' ? 'ArrowRight' : key === 'ArrowRight' ? 'ArrowLeft' : key;
}

type FocusIntent = 'first' | 'last' | 'prev' | 'next';

function getFocusIntent(event: React.KeyboardEvent, orientation?: Orientation, dir?: Direction) {
  const key = getDirectionAwareKey(event.key, dir);
  if (orientation === 'vertical' && ['ArrowLeft', 'ArrowRight'].includes(key)) return undefined;
  if (orientation === 'horizontal' && ['ArrowUp', 'ArrowDown'].includes(key)) return undefined;
  return MAP_KEY_TO_FOCUS_INTENT[key];
}

function focusFirst(candidates: HTMLElement[], preventScroll = false) {
  const PREVIOUSLY_FOCUSED_ELEMENT = document.activeElement;
  for (const candidate of candidates) {
    // if focus is already where we want to go, we don't want to keep going through the candidates
    if (candidate === PREVIOUSLY_FOCUSED_ELEMENT) return;
    candidate.focus({ preventScroll });
    if (document.activeElement !== PREVIOUSLY_FOCUSED_ELEMENT) return;
  }
}

/**
 * Wraps an array around itself at a given start index
 * Example: `wrapArray(['a', 'b', 'c', 'd'], 2) === ['c', 'd', 'a', 'b']`
 */
function wrapArray<T>(array: T[], startIndex: number) {
  return array.map<T>((_, index) => array[(startIndex + index) % array.length]!);
}

const Root = RovingFocusGroup;
const Item = RovingFocusGroupItem;

export {
  createRovingFocusGroupScope,
  //
  RovingFocusGroup,
  RovingFocusGroupItem,
  //
  Root,
  Item,
};
export type { RovingFocusGroupProps, RovingFocusItemProps };



================================================
FILE: packages/react/scroll-area/README.md
================================================
# `react-scroll-area`

View docs [here](https://radix-ui.com/primitives/docs/components/scroll-area).



================================================
FILE: packages/react/scroll-area/CHANGELOG.md
================================================
# @radix-ui/react-scroll-area

## 1.2.10

- Updated dependencies: `@radix-ui/react-presence@1.1.5`, `@radix-ui/primitive@1.1.3`, `@radix-ui/react-context@1.1.3`, `@radix-ui/react-primitive@2.1.4`

## 1.2.9

- Replace deprecated 'ElementRef' with 'ComponentRef' (#3426)
- Updated dependencies: `@radix-ui/react-primitive@2.1.3`

## 1.2.8

- Updated dependencies: `@radix-ui/react-primitive@2.1.2`

## 1.2.7

- Updated dependencies: `@radix-ui/react-primitive@2.1.1`

## 1.2.6

- Updated dependencies: `@radix-ui/react-presence@1.1.4`

## 1.2.5

- Updated dependencies: `@radix-ui/react-primitive@2.1.0`



================================================
FILE: packages/react/scroll-area/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/scroll-area/package.json
================================================
{
  "name": "@radix-ui/react-scroll-area",
  "version": "1.2.10",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/number": "workspace:*",
    "@radix-ui/primitive": "workspace:*",
    "@radix-ui/react-compose-refs": "workspace:*",
    "@radix-ui/react-context": "workspace:*",
    "@radix-ui/react-direction": "workspace:*",
    "@radix-ui/react-presence": "workspace:*",
    "@radix-ui/react-primitive": "workspace:*",
    "@radix-ui/react-use-callback-ref": "workspace:*",
    "@radix-ui/react-use-layout-effect": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/scroll-area/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/scroll-area/src/index.ts
================================================
'use client';
export {
  createScrollAreaScope,
  //
  ScrollArea,
  ScrollAreaViewport,
  ScrollAreaScrollbar,
  ScrollAreaThumb,
  ScrollAreaCorner,
  //
  Root,
  Viewport,
  Scrollbar,
  Thumb,
  Corner,
} from './scroll-area';
export type {
  ScrollAreaProps,
  ScrollAreaViewportProps,
  ScrollAreaScrollbarProps,
  ScrollAreaThumbProps,
  ScrollAreaCornerProps,
} from './scroll-area';



================================================
FILE: packages/react/scroll-area/src/scroll-area.tsx
================================================
import * as React from 'react';
import { Primitive } from '@radix-ui/react-primitive';
import { Presence } from '@radix-ui/react-presence';
import { createContextScope } from '@radix-ui/react-context';
import { useComposedRefs } from '@radix-ui/react-compose-refs';
import { useCallbackRef } from '@radix-ui/react-use-callback-ref';
import { useDirection } from '@radix-ui/react-direction';
import { useLayoutEffect } from '@radix-ui/react-use-layout-effect';
import { clamp } from '@radix-ui/number';
import { composeEventHandlers } from '@radix-ui/primitive';
import { useStateMachine } from './use-state-machine';

import type { Scope } from '@radix-ui/react-context';

type Direction = 'ltr' | 'rtl';
type Sizes = {
  content: number;
  viewport: number;
  scrollbar: {
    size: number;
    paddingStart: number;
    paddingEnd: number;
  };
};

/* -------------------------------------------------------------------------------------------------
 * ScrollArea
 * -----------------------------------------------------------------------------------------------*/

const SCROLL_AREA_NAME = 'ScrollArea';

type ScopedProps<P> = P & { __scopeScrollArea?: Scope };
const [createScrollAreaContext, createScrollAreaScope] = createContextScope(SCROLL_AREA_NAME);

type ScrollAreaContextValue = {
  type: 'auto' | 'always' | 'scroll' | 'hover';
  dir: Direction;
  scrollHideDelay: number;
  scrollArea: ScrollAreaElement | null;
  viewport: ScrollAreaViewportElement | null;
  onViewportChange(viewport: ScrollAreaViewportElement | null): void;
  content: HTMLDivElement | null;
  onContentChange(content: HTMLDivElement): void;
  scrollbarX: ScrollAreaScrollbarElement | null;
  onScrollbarXChange(scrollbar: ScrollAreaScrollbarElement | null): void;
  scrollbarXEnabled: boolean;
  onScrollbarXEnabledChange(rendered: boolean): void;
  scrollbarY: ScrollAreaScrollbarElement | null;
  onScrollbarYChange(scrollbar: ScrollAreaScrollbarElement | null): void;
  scrollbarYEnabled: boolean;
  onScrollbarYEnabledChange(rendered: boolean): void;
  onCornerWidthChange(width: number): void;
  onCornerHeightChange(height: number): void;
};

const [ScrollAreaProvider, useScrollAreaContext] =
  createScrollAreaContext<ScrollAreaContextValue>(SCROLL_AREA_NAME);

type ScrollAreaElement = React.ComponentRef<typeof Primitive.div>;
type PrimitiveDivProps = React.ComponentPropsWithoutRef<typeof Primitive.div>;
interface ScrollAreaProps extends PrimitiveDivProps {
  type?: ScrollAreaContextValue['type'];
  dir?: ScrollAreaContextValue['dir'];
  scrollHideDelay?: number;
}

const ScrollArea = React.forwardRef<ScrollAreaElement, ScrollAreaProps>(
  (props: ScopedProps<ScrollAreaProps>, forwardedRef) => {
    const {
      __scopeScrollArea,
      type = 'hover',
      dir,
      scrollHideDelay = 600,
      ...scrollAreaProps
    } = props;
    const [scrollArea, setScrollArea] = React.useState<ScrollAreaElement | null>(null);
    const [viewport, setViewport] = React.useState<ScrollAreaViewportElement | null>(null);
    const [content, setContent] = React.useState<HTMLDivElement | null>(null);
    const [scrollbarX, setScrollbarX] = React.useState<ScrollAreaScrollbarElement | null>(null);
    const [scrollbarY, setScrollbarY] = React.useState<ScrollAreaScrollbarElement | null>(null);
    const [cornerWidth, setCornerWidth] = React.useState(0);
    const [cornerHeight, setCornerHeight] = React.useState(0);
    const [scrollbarXEnabled, setScrollbarXEnabled] = React.useState(false);
    const [scrollbarYEnabled, setScrollbarYEnabled] = React.useState(false);
    const composedRefs = useComposedRefs(forwardedRef, (node) => setScrollArea(node));
    const direction = useDirection(dir);

    return (
      <ScrollAreaProvider
        scope={__scopeScrollArea}
        type={type}
        dir={direction}
        scrollHideDelay={scrollHideDelay}
        scrollArea={scrollArea}
        viewport={viewport}
        onViewportChange={setViewport}
        content={content}
        onContentChange={setContent}
        scrollbarX={scrollbarX}
        onScrollbarXChange={setScrollbarX}
        scrollbarXEnabled={scrollbarXEnabled}
        onScrollbarXEnabledChange={setScrollbarXEnabled}
        scrollbarY={scrollbarY}
        onScrollbarYChange={setScrollbarY}
        scrollbarYEnabled={scrollbarYEnabled}
        onScrollbarYEnabledChange={setScrollbarYEnabled}
        onCornerWidthChange={setCornerWidth}
        onCornerHeightChange={setCornerHeight}
      >
        <Primitive.div
          dir={direction}
          {...scrollAreaProps}
          ref={composedRefs}
          style={{
            position: 'relative',
            // Pass corner sizes as CSS vars to reduce re-renders of context consumers
            ['--radix-scroll-area-corner-width' as any]: cornerWidth + 'px',
            ['--radix-scroll-area-corner-height' as any]: cornerHeight + 'px',
            ...props.style,
          }}
        />
      </ScrollAreaProvider>
    );
  },
);

ScrollArea.displayName = SCROLL_AREA_NAME;

/* -------------------------------------------------------------------------------------------------
 * ScrollAreaViewport
 * -----------------------------------------------------------------------------------------------*/

const VIEWPORT_NAME = 'ScrollAreaViewport';

type ScrollAreaViewportElement = React.ComponentRef<typeof Primitive.div>;
interface ScrollAreaViewportProps extends PrimitiveDivProps {
  nonce?: string;
}

const ScrollAreaViewport = React.forwardRef<ScrollAreaViewportElement, ScrollAreaViewportProps>(
  (props: ScopedProps<ScrollAreaViewportProps>, forwardedRef) => {
    const { __scopeScrollArea, children, nonce, ...viewportProps } = props;
    const context = useScrollAreaContext(VIEWPORT_NAME, __scopeScrollArea);
    const ref = React.useRef<ScrollAreaViewportElement>(null);
    const composedRefs = useComposedRefs(forwardedRef, ref, context.onViewportChange);
    return (
      <>
        {/* Hide scrollbars cross-browser and enable momentum scroll for touch devices */}
        <style
          dangerouslySetInnerHTML={{
            __html: `[data-radix-scroll-area-viewport]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}[data-radix-scroll-area-viewport]::-webkit-scrollbar{display:none}`,
          }}
          nonce={nonce}
        />
        <Primitive.div
          data-radix-scroll-area-viewport=""
          {...viewportProps}
          ref={composedRefs}
          style={{
            /**
             * We don't support `visible` because the intention is to have at least one scrollbar
             * if this component is used and `visible` will behave like `auto` in that case
             * https://developer.mozilla.org/en-US/docs/Web/CSS/overflow#description
             *
             * We don't handle `auto` because the intention is for the native implementation
             * to be hidden if using this component. We just want to ensure the node is scrollable
             * so could have used either `scroll` or `auto` here. We picked `scroll` to prevent
             * the browser from having to work out whether to render native scrollbars or not,
             * we tell it to with the intention of hiding them in CSS.
             */
            overflowX: context.scrollbarXEnabled ? 'scroll' : 'hidden',
            overflowY: context.scrollbarYEnabled ? 'scroll' : 'hidden',
            ...props.style,
          }}
        >
          {/**
           * `display: table` ensures our content div will match the size of its children in both
           * horizontal and vertical axis so we can determine if scroll width/height changed and
           * recalculate thumb sizes. This doesn't account for children with *percentage*
           * widths that change. We'll wait to see what use-cases consumers come up with there
           * before trying to resolve it.
           */}
          <div ref={context.onContentChange} style={{ minWidth: '100%', display: 'table' }}>
            {children}
          </div>
        </Primitive.div>
      </>
    );
  },
);

ScrollAreaViewport.displayName = VIEWPORT_NAME;

/* -------------------------------------------------------------------------------------------------
 * ScrollAreaScrollbar
 * -----------------------------------------------------------------------------------------------*/

const SCROLLBAR_NAME = 'ScrollAreaScrollbar';

type ScrollAreaScrollbarElement = ScrollAreaScrollbarVisibleElement;
interface ScrollAreaScrollbarProps extends ScrollAreaScrollbarVisibleProps {
  forceMount?: true;
}

const ScrollAreaScrollbar = React.forwardRef<ScrollAreaScrollbarElement, ScrollAreaScrollbarProps>(
  (props: ScopedProps<ScrollAreaScrollbarProps>, forwardedRef) => {
    const { forceMount, ...scrollbarProps } = props;
    const context = useScrollAreaContext(SCROLLBAR_NAME, props.__scopeScrollArea);
    const { onScrollbarXEnabledChange, onScrollbarYEnabledChange } = context;
    const isHorizontal = props.orientation === 'horizontal';

    React.useEffect(() => {
      isHorizontal ? onScrollbarXEnabledChange(true) : onScrollbarYEnabledChange(true);
      return () => {
        isHorizontal ? onScrollbarXEnabledChange(false) : onScrollbarYEnabledChange(false);
      };
    }, [isHorizontal, onScrollbarXEnabledChange, onScrollbarYEnabledChange]);

    return context.type === 'hover' ? (
      <ScrollAreaScrollbarHover {...scrollbarProps} ref={forwardedRef} forceMount={forceMount} />
    ) : context.type === 'scroll' ? (
      <ScrollAreaScrollbarScroll {...scrollbarProps} ref={forwardedRef} forceMount={forceMount} />
    ) : context.type === 'auto' ? (
      <ScrollAreaScrollbarAuto {...scrollbarProps} ref={forwardedRef} forceMount={forceMount} />
    ) : context.type === 'always' ? (
      <ScrollAreaScrollbarVisible {...scrollbarProps} ref={forwardedRef} />
    ) : null;
  },
);

ScrollAreaScrollbar.displayName = SCROLLBAR_NAME;

/* -----------------------------------------------------------------------------------------------*/

type ScrollAreaScrollbarHoverElement = ScrollAreaScrollbarAutoElement;
interface ScrollAreaScrollbarHoverProps extends ScrollAreaScrollbarAutoProps {
  forceMount?: true;
}

const ScrollAreaScrollbarHover = React.forwardRef<
  ScrollAreaScrollbarHoverElement,
  ScrollAreaScrollbarHoverProps
>((props: ScopedProps<ScrollAreaScrollbarHoverProps>, forwardedRef) => {
  const { forceMount, ...scrollbarProps } = props;
  const context = useScrollAreaContext(SCROLLBAR_NAME, props.__scopeScrollArea);
  const [visible, setVisible] = React.useState(false);

  React.useEffect(() => {
    const scrollArea = context.scrollArea;
    let hideTimer = 0;
    if (scrollArea) {
      const handlePointerEnter = () => {
        window.clearTimeout(hideTimer);
        setVisible(true);
      };
      const handlePointerLeave = () => {
        hideTimer = window.setTimeout(() => setVisible(false), context.scrollHideDelay);
      };
      scrollArea.addEventListener('pointerenter', handlePointerEnter);
      scrollArea.addEventListener('pointerleave', handlePointerLeave);
      return () => {
        window.clearTimeout(hideTimer);
        scrollArea.removeEventListener('pointerenter', handlePointerEnter);
        scrollArea.removeEventListener('pointerleave', handlePointerLeave);
      };
    }
  }, [context.scrollArea, context.scrollHideDelay]);

  return (
    <Presence present={forceMount || visible}>
      <ScrollAreaScrollbarAuto
        data-state={visible ? 'visible' : 'hidden'}
        {...scrollbarProps}
        ref={forwardedRef}
      />
    </Presence>
  );
});

type ScrollAreaScrollbarScrollElement = ScrollAreaScrollbarVisibleElement;
interface ScrollAreaScrollbarScrollProps extends ScrollAreaScrollbarVisibleProps {
  forceMount?: true;
}

const ScrollAreaScrollbarScroll = React.forwardRef<
  ScrollAreaScrollbarScrollElement,
  ScrollAreaScrollbarScrollProps
>((props: ScopedProps<ScrollAreaScrollbarScrollProps>, forwardedRef) => {
  const { forceMount, ...scrollbarProps } = props;
  const context = useScrollAreaContext(SCROLLBAR_NAME, props.__scopeScrollArea);
  const isHorizontal = props.orientation === 'horizontal';
  const debounceScrollEnd = useDebounceCallback(() => send('SCROLL_END'), 100);
  const [state, send] = useStateMachine('hidden', {
    hidden: {
      SCROLL: 'scrolling',
    },
    scrolling: {
      SCROLL_END: 'idle',
      POINTER_ENTER: 'interacting',
    },
    interacting: {
      SCROLL: 'interacting',
      POINTER_LEAVE: 'idle',
    },
    idle: {
      HIDE: 'hidden',
      SCROLL: 'scrolling',
      POINTER_ENTER: 'interacting',
    },
  });

  React.useEffect(() => {
    if (state === 'idle') {
      const hideTimer = window.setTimeout(() => send('HIDE'), context.scrollHideDelay);
      return () => window.clearTimeout(hideTimer);
    }
  }, [state, context.scrollHideDelay, send]);

  React.useEffect(() => {
    const viewport = context.viewport;
    const scrollDirection = isHorizontal ? 'scrollLeft' : 'scrollTop';

    if (viewport) {
      let prevScrollPos = viewport[scrollDirection];
      const handleScroll = () => {
        const scrollPos = viewport[scrollDirection];
        const hasScrollInDirectionChanged = prevScrollPos !== scrollPos;
        if (hasScrollInDirectionChanged) {
          send('SCROLL');
          debounceScrollEnd();
        }
        prevScrollPos = scrollPos;
      };
      viewport.addEventListener('scroll', handleScroll);
      return () => viewport.removeEventListener('scroll', handleScroll);
    }
  }, [context.viewport, isHorizontal, send, debounceScrollEnd]);

  return (
    <Presence present={forceMount || state !== 'hidden'}>
      <ScrollAreaScrollbarVisible
        data-state={state === 'hidden' ? 'hidden' : 'visible'}
        {...scrollbarProps}
        ref={forwardedRef}
        onPointerEnter={composeEventHandlers(props.onPointerEnter, () => send('POINTER_ENTER'))}
        onPointerLeave={composeEventHandlers(props.onPointerLeave, () => send('POINTER_LEAVE'))}
      />
    </Presence>
  );
});

type ScrollAreaScrollbarAutoElement = ScrollAreaScrollbarVisibleElement;
interface ScrollAreaScrollbarAutoProps extends ScrollAreaScrollbarVisibleProps {
  forceMount?: true;
}

const ScrollAreaScrollbarAuto = React.forwardRef<
  ScrollAreaScrollbarAutoElement,
  ScrollAreaScrollbarAutoProps
>((props: ScopedProps<ScrollAreaScrollbarAutoProps>, forwardedRef) => {
  const context = useScrollAreaContext(SCROLLBAR_NAME, props.__scopeScrollArea);
  const { forceMount, ...scrollbarProps } = props;
  const [visible, setVisible] = React.useState(false);
  const isHorizontal = props.orientation === 'horizontal';
  const handleResize = useDebounceCallback(() => {
    if (context.viewport) {
      const isOverflowX = context.viewport.offsetWidth < context.viewport.scrollWidth;
      const isOverflowY = context.viewport.offsetHeight < context.viewport.scrollHeight;
      setVisible(isHorizontal ? isOverflowX : isOverflowY);
    }
  }, 10);

  useResizeObserver(context.viewport, handleResize);
  useResizeObserver(context.content, handleResize);

  return (
    <Presence present={forceMount || visible}>
      <ScrollAreaScrollbarVisible
        data-state={visible ? 'visible' : 'hidden'}
        {...scrollbarProps}
        ref={forwardedRef}
      />
    </Presence>
  );
});

/* -----------------------------------------------------------------------------------------------*/

type ScrollAreaScrollbarVisibleElement = ScrollAreaScrollbarAxisElement;
interface ScrollAreaScrollbarVisibleProps
  extends Omit<ScrollAreaScrollbarAxisProps, keyof ScrollAreaScrollbarAxisPrivateProps> {
  orientation?: 'horizontal' | 'vertical';
}

const ScrollAreaScrollbarVisible = React.forwardRef<
  ScrollAreaScrollbarVisibleElement,
  ScrollAreaScrollbarVisibleProps
>((props: ScopedProps<ScrollAreaScrollbarVisibleProps>, forwardedRef) => {
  const { orientation = 'vertical', ...scrollbarProps } = props;
  const context = useScrollAreaContext(SCROLLBAR_NAME, props.__scopeScrollArea);
  const thumbRef = React.useRef<ScrollAreaThumbElement | null>(null);
  const pointerOffsetRef = React.useRef(0);
  const [sizes, setSizes] = React.useState<Sizes>({
    content: 0,
    viewport: 0,
    scrollbar: { size: 0, paddingStart: 0, paddingEnd: 0 },
  });
  const thumbRatio = getThumbRatio(sizes.viewport, sizes.content);

  type UncommonProps = 'onThumbPositionChange' | 'onDragScroll' | 'onWheelScroll';
  const commonProps: Omit<ScrollAreaScrollbarAxisPrivateProps, UncommonProps> = {
    ...scrollbarProps,
    sizes,
    onSizesChange: setSizes,
    hasThumb: Boolean(thumbRatio > 0 && thumbRatio < 1),
    onThumbChange: (thumb) => (thumbRef.current = thumb),
    onThumbPointerUp: () => (pointerOffsetRef.current = 0),
    onThumbPointerDown: (pointerPos) => (pointerOffsetRef.current = pointerPos),
  };

  function getScrollPosition(pointerPos: number, dir?: Direction) {
    return getScrollPositionFromPointer(pointerPos, pointerOffsetRef.current, sizes, dir);
  }

  if (orientation === 'horizontal') {
    return (
      <ScrollAreaScrollbarX
        {...commonProps}
        ref={forwardedRef}
        onThumbPositionChange={() => {
          if (context.viewport && thumbRef.current) {
            const scrollPos = context.viewport.scrollLeft;
            const offset = getThumbOffsetFromScroll(scrollPos, sizes, context.dir);
            thumbRef.current.style.transform = `translate3d(${offset}px, 0, 0)`;
          }
        }}
        onWheelScroll={(scrollPos) => {
          if (context.viewport) context.viewport.scrollLeft = scrollPos;
        }}
        onDragScroll={(pointerPos) => {
          if (context.viewport) {
            context.viewport.scrollLeft = getScrollPosition(pointerPos, context.dir);
          }
        }}
      />
    );
  }

  if (orientation === 'vertical') {
    return (
      <ScrollAreaScrollbarY
        {...commonProps}
        ref={forwardedRef}
        onThumbPositionChange={() => {
          if (context.viewport && thumbRef.current) {
            const scrollPos = context.viewport.scrollTop;
            const offset = getThumbOffsetFromScroll(scrollPos, sizes);
            thumbRef.current.style.transform = `translate3d(0, ${offset}px, 0)`;
          }
        }}
        onWheelScroll={(scrollPos) => {
          if (context.viewport) context.viewport.scrollTop = scrollPos;
        }}
        onDragScroll={(pointerPos) => {
          if (context.viewport) context.viewport.scrollTop = getScrollPosition(pointerPos);
        }}
      />
    );
  }

  return null;
});

/* -----------------------------------------------------------------------------------------------*/

type ScrollAreaScrollbarAxisPrivateProps = {
  hasThumb: boolean;
  sizes: Sizes;
  onSizesChange(sizes: Sizes): void;
  onThumbChange(thumb: ScrollAreaThumbElement | null): void;
  onThumbPointerDown(pointerPos: number): void;
  onThumbPointerUp(): void;
  onThumbPositionChange(): void;
  onWheelScroll(scrollPos: number): void;
  onDragScroll(pointerPos: number): void;
};

type ScrollAreaScrollbarAxisElement = ScrollAreaScrollbarImplElement;
interface ScrollAreaScrollbarAxisProps
  extends Omit<ScrollAreaScrollbarImplProps, keyof ScrollAreaScrollbarImplPrivateProps>,
    ScrollAreaScrollbarAxisPrivateProps {}

const ScrollAreaScrollbarX = React.forwardRef<
  ScrollAreaScrollbarAxisElement,
  ScrollAreaScrollbarAxisProps
>((props: ScopedProps<ScrollAreaScrollbarAxisProps>, forwardedRef) => {
  const { sizes, onSizesChange, ...scrollbarProps } = props;
  const context = useScrollAreaContext(SCROLLBAR_NAME, props.__scopeScrollArea);
  const [computedStyle, setComputedStyle] = React.useState<CSSStyleDeclaration>();
  const ref = React.useRef<ScrollAreaScrollbarAxisElement>(null);
  const composeRefs = useComposedRefs(forwardedRef, ref, context.onScrollbarXChange);

  React.useEffect(() => {
    if (ref.current) setComputedStyle(getComputedStyle(ref.current));
  }, [ref]);

  return (
    <ScrollAreaScrollbarImpl
      data-orientation="horizontal"
      {...scrollbarProps}
      ref={composeRefs}
      sizes={sizes}
      style={{
        bottom: 0,
        left: context.dir === 'rtl' ? 'var(--radix-scroll-area-corner-width)' : 0,
        right: context.dir === 'ltr' ? 'var(--radix-scroll-area-corner-width)' : 0,
        ['--radix-scroll-area-thumb-width' as any]: getThumbSize(sizes) + 'px',
        ...props.style,
      }}
      onThumbPointerDown={(pointerPos) => props.onThumbPointerDown(pointerPos.x)}
      onDragScroll={(pointerPos) => props.onDragScroll(pointerPos.x)}
      onWheelScroll={(event, maxScrollPos) => {
        if (context.viewport) {
          const scrollPos = context.viewport.scrollLeft + event.deltaX;
          props.onWheelScroll(scrollPos);
          // prevent window scroll when wheeling on scrollbar
          if (isScrollingWithinScrollbarBounds(scrollPos, maxScrollPos)) {
            event.preventDefault();
          }
        }
      }}
      onResize={() => {
        if (ref.current && context.viewport && computedStyle) {
          onSizesChange({
            content: context.viewport.scrollWidth,
            viewport: context.viewport.offsetWidth,
            scrollbar: {
              size: ref.current.clientWidth,
              paddingStart: toInt(computedStyle.paddingLeft),
              paddingEnd: toInt(computedStyle.paddingRight),
            },
          });
        }
      }}
    />
  );
});

const ScrollAreaScrollbarY = React.forwardRef<
  ScrollAreaScrollbarAxisElement,
  ScrollAreaScrollbarAxisProps
>((props: ScopedProps<ScrollAreaScrollbarAxisProps>, forwardedRef) => {
  const { sizes, onSizesChange, ...scrollbarProps } = props;
  const context = useScrollAreaContext(SCROLLBAR_NAME, props.__scopeScrollArea);
  const [computedStyle, setComputedStyle] = React.useState<CSSStyleDeclaration>();
  const ref = React.useRef<ScrollAreaScrollbarAxisElement>(null);
  const composeRefs = useComposedRefs(forwardedRef, ref, context.onScrollbarYChange);

  React.useEffect(() => {
    if (ref.current) setComputedStyle(getComputedStyle(ref.current));
  }, [ref]);

  return (
    <ScrollAreaScrollbarImpl
      data-orientation="vertical"
      {...scrollbarProps}
      ref={composeRefs}
      sizes={sizes}
      style={{
        top: 0,
        right: context.dir === 'ltr' ? 0 : undefined,
        left: context.dir === 'rtl' ? 0 : undefined,
        bottom: 'var(--radix-scroll-area-corner-height)',
        ['--radix-scroll-area-thumb-height' as any]: getThumbSize(sizes) + 'px',
        ...props.style,
      }}
      onThumbPointerDown={(pointerPos) => props.onThumbPointerDown(pointerPos.y)}
      onDragScroll={(pointerPos) => props.onDragScroll(pointerPos.y)}
      onWheelScroll={(event, maxScrollPos) => {
        if (context.viewport) {
          const scrollPos = context.viewport.scrollTop + event.deltaY;
          props.onWheelScroll(scrollPos);
          // prevent window scroll when wheeling on scrollbar
          if (isScrollingWithinScrollbarBounds(scrollPos, maxScrollPos)) {
            event.preventDefault();
          }
        }
      }}
      onResize={() => {
        if (ref.current && context.viewport && computedStyle) {
          onSizesChange({
            content: context.viewport.scrollHeight,
            viewport: context.viewport.offsetHeight,
            scrollbar: {
              size: ref.current.clientHeight,
              paddingStart: toInt(computedStyle.paddingTop),
              paddingEnd: toInt(computedStyle.paddingBottom),
            },
          });
        }
      }}
    />
  );
});

/* -----------------------------------------------------------------------------------------------*/

type ScrollbarContext = {
  hasThumb: boolean;
  scrollbar: ScrollAreaScrollbarElement | null;
  onThumbChange(thumb: ScrollAreaThumbElement | null): void;
  onThumbPointerUp(): void;
  onThumbPointerDown(pointerPos: { x: number; y: number }): void;
  onThumbPositionChange(): void;
};

const [ScrollbarProvider, useScrollbarContext] =
  createScrollAreaContext<ScrollbarContext>(SCROLLBAR_NAME);

type ScrollAreaScrollbarImplElement = React.ComponentRef<typeof Primitive.div>;
type ScrollAreaScrollbarImplPrivateProps = {
  sizes: Sizes;
  hasThumb: boolean;
  onThumbChange: ScrollbarContext['onThumbChange'];
  onThumbPointerUp: ScrollbarContext['onThumbPointerUp'];
  onThumbPointerDown: ScrollbarContext['onThumbPointerDown'];
  onThumbPositionChange: ScrollbarContext['onThumbPositionChange'];
  onWheelScroll(event: WheelEvent, maxScrollPos: number): void;
  onDragScroll(pointerPos: { x: number; y: number }): void;
  onResize(): void;
};
interface ScrollAreaScrollbarImplProps
  extends Omit<PrimitiveDivProps, keyof ScrollAreaScrollbarImplPrivateProps>,
    ScrollAreaScrollbarImplPrivateProps {}

const ScrollAreaScrollbarImpl = React.forwardRef<
  ScrollAreaScrollbarImplElement,
  ScrollAreaScrollbarImplProps
>((props: ScopedProps<ScrollAreaScrollbarImplProps>, forwardedRef) => {
  const {
    __scopeScrollArea,
    sizes,
    hasThumb,
    onThumbChange,
    onThumbPointerUp,
    onThumbPointerDown,
    onThumbPositionChange,
    onDragScroll,
    onWheelScroll,
    onResize,
    ...scrollbarProps
  } = props;
  const context = useScrollAreaContext(SCROLLBAR_NAME, __scopeScrollArea);
  const [scrollbar, setScrollbar] = React.useState<ScrollAreaScrollbarElement | null>(null);
  const composeRefs = useComposedRefs(forwardedRef, (node) => setScrollbar(node));
  const rectRef = React.useRef<DOMRect | null>(null);
  const prevWebkitUserSelectRef = React.useRef<string>('');
  const viewport = context.viewport;
  const maxScrollPos = sizes.content - sizes.viewport;
  const handleWheelScroll = useCallbackRef(onWheelScroll);
  const handleThumbPositionChange = useCallbackRef(onThumbPositionChange);
  const handleResize = useDebounceCallback(onResize, 10);

  function handleDragScroll(event: React.PointerEvent<HTMLElement>) {
    if (rectRef.current) {
      const x = event.clientX - rectRef.current.left;
      const y = event.clientY - rectRef.current.top;
      onDragScroll({ x, y });
    }
  }

  /**
   * We bind wheel event imperatively so we can switch off passive
   * mode for document wheel event to allow it to be prevented
   */
  React.useEffect(() => {
    const handleWheel = (event: WheelEvent) => {
      const element = event.target as HTMLElement;
      const isScrollbarWheel = scrollbar?.contains(element);
      if (isScrollbarWheel) handleWheelScroll(event, maxScrollPos);
    };
    document.addEventListener('wheel', handleWheel, { passive: false });
    return () => document.removeEventListener('wheel', handleWheel, { passive: false } as any);
  }, [viewport, scrollbar, maxScrollPos, handleWheelScroll]);

  /**
   * Update thumb position on sizes change
   */
  React.useEffect(handleThumbPositionChange, [sizes, handleThumbPositionChange]);

  useResizeObserver(scrollbar, handleResize);
  useResizeObserver(context.content, handleResize);

  return (
    <ScrollbarProvider
      scope={__scopeScrollArea}
      scrollbar={scrollbar}
      hasThumb={hasThumb}
      onThumbChange={useCallbackRef(onThumbChange)}
      onThumbPointerUp={useCallbackRef(onThumbPointerUp)}
      onThumbPositionChange={handleThumbPositionChange}
      onThumbPointerDown={useCallbackRef(onThumbPointerDown)}
    >
      <Primitive.div
        {...scrollbarProps}
        ref={composeRefs}
        style={{ position: 'absolute', ...scrollbarProps.style }}
        onPointerDown={composeEventHandlers(props.onPointerDown, (event) => {
          const mainPointer = 0;
          if (event.button === mainPointer) {
            const element = event.target as HTMLElement;
            element.setPointerCapture(event.pointerId);
            rectRef.current = scrollbar!.getBoundingClientRect();
            // pointer capture doesn't prevent text selection in Safari
            // so we remove text selection manually when scrolling
            prevWebkitUserSelectRef.current = document.body.style.webkitUserSelect;
            document.body.style.webkitUserSelect = 'none';
            if (context.viewport) context.viewport.style.scrollBehavior = 'auto';
            handleDragScroll(event);
          }
        })}
        onPointerMove={composeEventHandlers(props.onPointerMove, handleDragScroll)}
        onPointerUp={composeEventHandlers(props.onPointerUp, (event) => {
          const element = event.target as HTMLElement;
          if (element.hasPointerCapture(event.pointerId)) {
            element.releasePointerCapture(event.pointerId);
          }
          document.body.style.webkitUserSelect = prevWebkitUserSelectRef.current;
          if (context.viewport) context.viewport.style.scrollBehavior = '';
          rectRef.current = null;
        })}
      />
    </ScrollbarProvider>
  );
});

/* -------------------------------------------------------------------------------------------------
 * ScrollAreaThumb
 * -----------------------------------------------------------------------------------------------*/

const THUMB_NAME = 'ScrollAreaThumb';

type ScrollAreaThumbElement = ScrollAreaThumbImplElement;
interface ScrollAreaThumbProps extends ScrollAreaThumbImplProps {
  /**
   * Used to force mounting when more control is needed. Useful when
   * controlling animation with React animation libraries.
   */
  forceMount?: true;
}

const ScrollAreaThumb = React.forwardRef<ScrollAreaThumbElement, ScrollAreaThumbProps>(
  (props: ScopedProps<ScrollAreaThumbProps>, forwardedRef) => {
    const { forceMount, ...thumbProps } = props;
    const scrollbarContext = useScrollbarContext(THUMB_NAME, props.__scopeScrollArea);
    return (
      <Presence present={forceMount || scrollbarContext.hasThumb}>
        <ScrollAreaThumbImpl ref={forwardedRef} {...thumbProps} />
      </Presence>
    );
  },
);

type ScrollAreaThumbImplElement = React.ComponentRef<typeof Primitive.div>;
interface ScrollAreaThumbImplProps extends PrimitiveDivProps {}

const ScrollAreaThumbImpl = React.forwardRef<ScrollAreaThumbImplElement, ScrollAreaThumbImplProps>(
  (props: ScopedProps<ScrollAreaThumbImplProps>, forwardedRef) => {
    const { __scopeScrollArea, style, ...thumbProps } = props;
    const scrollAreaContext = useScrollAreaContext(THUMB_NAME, __scopeScrollArea);
    const scrollbarContext = useScrollbarContext(THUMB_NAME, __scopeScrollArea);
    const { onThumbPositionChange } = scrollbarContext;
    const composedRef = useComposedRefs(forwardedRef, (node) =>
      scrollbarContext.onThumbChange(node),
    );
    const removeUnlinkedScrollListenerRef = React.useRef<() => void>(undefined);
    const debounceScrollEnd = useDebounceCallback(() => {
      if (removeUnlinkedScrollListenerRef.current) {
        removeUnlinkedScrollListenerRef.current();
        removeUnlinkedScrollListenerRef.current = undefined;
      }
    }, 100);

    React.useEffect(() => {
      const viewport = scrollAreaContext.viewport;
      if (viewport) {
        /**
         * We only bind to native scroll event so we know when scroll starts and ends.
         * When scroll starts we start a requestAnimationFrame loop that checks for
         * changes to scroll position. That rAF loop triggers our thumb position change
         * when relevant to avoid scroll-linked effects. We cancel the loop when scroll ends.
         * https://developer.mozilla.org/en-US/docs/Mozilla/Performance/Scroll-linked_effects
         */
        const handleScroll = () => {
          debounceScrollEnd();
          if (!removeUnlinkedScrollListenerRef.current) {
            const listener = addUnlinkedScrollListener(viewport, onThumbPositionChange);
            removeUnlinkedScrollListenerRef.current = listener;
            onThumbPositionChange();
          }
        };
        onThumbPositionChange();
        viewport.addEventListener('scroll', handleScroll);
        return () => viewport.removeEventListener('scroll', handleScroll);
      }
    }, [scrollAreaContext.viewport, debounceScrollEnd, onThumbPositionChange]);

    return (
      <Primitive.div
        data-state={scrollbarContext.hasThumb ? 'visible' : 'hidden'}
        {...thumbProps}
        ref={composedRef}
        style={{
          width: 'var(--radix-scroll-area-thumb-width)',
          height: 'var(--radix-scroll-area-thumb-height)',
          ...style,
        }}
        onPointerDownCapture={composeEventHandlers(props.onPointerDownCapture, (event) => {
          const thumb = event.target as HTMLElement;
          const thumbRect = thumb.getBoundingClientRect();
          const x = event.clientX - thumbRect.left;
          const y = event.clientY - thumbRect.top;
          scrollbarContext.onThumbPointerDown({ x, y });
        })}
        onPointerUp={composeEventHandlers(props.onPointerUp, scrollbarContext.onThumbPointerUp)}
      />
    );
  },
);

ScrollAreaThumb.displayName = THUMB_NAME;

/* -------------------------------------------------------------------------------------------------
 * ScrollAreaCorner
 * -----------------------------------------------------------------------------------------------*/

const CORNER_NAME = 'ScrollAreaCorner';

type ScrollAreaCornerElement = ScrollAreaCornerImplElement;
interface ScrollAreaCornerProps extends ScrollAreaCornerImplProps {}

const ScrollAreaCorner = React.forwardRef<ScrollAreaCornerElement, ScrollAreaCornerProps>(
  (props: ScopedProps<ScrollAreaCornerProps>, forwardedRef) => {
    const context = useScrollAreaContext(CORNER_NAME, props.__scopeScrollArea);
    const hasBothScrollbarsVisible = Boolean(context.scrollbarX && context.scrollbarY);
    const hasCorner = context.type !== 'scroll' && hasBothScrollbarsVisible;
    return hasCorner ? <ScrollAreaCornerImpl {...props} ref={forwardedRef} /> : null;
  },
);

ScrollAreaCorner.displayName = CORNER_NAME;

/* -----------------------------------------------------------------------------------------------*/

type ScrollAreaCornerImplElement = React.ComponentRef<typeof Primitive.div>;
interface ScrollAreaCornerImplProps extends PrimitiveDivProps {}

const ScrollAreaCornerImpl = React.forwardRef<
  ScrollAreaCornerImplElement,
  ScrollAreaCornerImplProps
>((props: ScopedProps<ScrollAreaCornerImplProps>, forwardedRef) => {
  const { __scopeScrollArea, ...cornerProps } = props;
  const context = useScrollAreaContext(CORNER_NAME, __scopeScrollArea);
  const [width, setWidth] = React.useState(0);
  const [height, setHeight] = React.useState(0);
  const hasSize = Boolean(width && height);

  useResizeObserver(context.scrollbarX, () => {
    const height = context.scrollbarX?.offsetHeight || 0;
    context.onCornerHeightChange(height);
    setHeight(height);
  });

  useResizeObserver(context.scrollbarY, () => {
    const width = context.scrollbarY?.offsetWidth || 0;
    context.onCornerWidthChange(width);
    setWidth(width);
  });

  return hasSize ? (
    <Primitive.div
      {...cornerProps}
      ref={forwardedRef}
      style={{
        width,
        height,
        position: 'absolute',
        right: context.dir === 'ltr' ? 0 : undefined,
        left: context.dir === 'rtl' ? 0 : undefined,
        bottom: 0,
        ...props.style,
      }}
    />
  ) : null;
});

/* -----------------------------------------------------------------------------------------------*/

function toInt(value?: string) {
  return value ? parseInt(value, 10) : 0;
}

function getThumbRatio(viewportSize: number, contentSize: number) {
  const ratio = viewportSize / contentSize;
  return isNaN(ratio) ? 0 : ratio;
}

function getThumbSize(sizes: Sizes) {
  const ratio = getThumbRatio(sizes.viewport, sizes.content);
  const scrollbarPadding = sizes.scrollbar.paddingStart + sizes.scrollbar.paddingEnd;
  const thumbSize = (sizes.scrollbar.size - scrollbarPadding) * ratio;
  // minimum of 18 matches macOS minimum
  return Math.max(thumbSize, 18);
}

function getScrollPositionFromPointer(
  pointerPos: number,
  pointerOffset: number,
  sizes: Sizes,
  dir: Direction = 'ltr',
) {
  const thumbSizePx = getThumbSize(sizes);
  const thumbCenter = thumbSizePx / 2;
  const offset = pointerOffset || thumbCenter;
  const thumbOffsetFromEnd = thumbSizePx - offset;
  const minPointerPos = sizes.scrollbar.paddingStart + offset;
  const maxPointerPos = sizes.scrollbar.size - sizes.scrollbar.paddingEnd - thumbOffsetFromEnd;
  const maxScrollPos = sizes.content - sizes.viewport;
  const scrollRange = dir === 'ltr' ? [0, maxScrollPos] : [maxScrollPos * -1, 0];
  const interpolate = linearScale([minPointerPos, maxPointerPos], scrollRange as [number, number]);
  return interpolate(pointerPos);
}

function getThumbOffsetFromScroll(scrollPos: number, sizes: Sizes, dir: Direction = 'ltr') {
  const thumbSizePx = getThumbSize(sizes);
  const scrollbarPadding = sizes.scrollbar.paddingStart + sizes.scrollbar.paddingEnd;
  const scrollbar = sizes.scrollbar.size - scrollbarPadding;
  const maxScrollPos = sizes.content - sizes.viewport;
  const maxThumbPos = scrollbar - thumbSizePx;
  const scrollClampRange = dir === 'ltr' ? [0, maxScrollPos] : [maxScrollPos * -1, 0];
  const scrollWithoutMomentum = clamp(scrollPos, scrollClampRange as [number, number]);
  const interpolate = linearScale([0, maxScrollPos], [0, maxThumbPos]);
  return interpolate(scrollWithoutMomentum);
}

// https://github.com/tmcw-up-for-adoption/simple-linear-scale/blob/master/index.js
function linearScale(input: readonly [number, number], output: readonly [number, number]) {
  return (value: number) => {
    if (input[0] === input[1] || output[0] === output[1]) return output[0];
    const ratio = (output[1] - output[0]) / (input[1] - input[0]);
    return output[0] + ratio * (value - input[0]);
  };
}

function isScrollingWithinScrollbarBounds(scrollPos: number, maxScrollPos: number) {
  return scrollPos > 0 && scrollPos < maxScrollPos;
}

// Custom scroll handler to avoid scroll-linked effects
// https://developer.mozilla.org/en-US/docs/Mozilla/Performance/Scroll-linked_effects
const addUnlinkedScrollListener = (node: HTMLElement, handler = () => {}) => {
  let prevPosition = { left: node.scrollLeft, top: node.scrollTop };
  let rAF = 0;
  (function loop() {
    const position = { left: node.scrollLeft, top: node.scrollTop };
    const isHorizontalScroll = prevPosition.left !== position.left;
    const isVerticalScroll = prevPosition.top !== position.top;
    if (isHorizontalScroll || isVerticalScroll) handler();
    prevPosition = position;
    rAF = window.requestAnimationFrame(loop);
  })();
  return () => window.cancelAnimationFrame(rAF);
};

function useDebounceCallback(callback: () => void, delay: number) {
  const handleCallback = useCallbackRef(callback);
  const debounceTimerRef = React.useRef(0);
  React.useEffect(() => () => window.clearTimeout(debounceTimerRef.current), []);
  return React.useCallback(() => {
    window.clearTimeout(debounceTimerRef.current);
    debounceTimerRef.current = window.setTimeout(handleCallback, delay);
  }, [handleCallback, delay]);
}

function useResizeObserver(element: HTMLElement | null, onResize: () => void) {
  const handleResize = useCallbackRef(onResize);
  useLayoutEffect(() => {
    let rAF = 0;
    if (element) {
      /**
       * Resize Observer will throw an often benign error that says `ResizeObserver loop
       * completed with undelivered notifications`. This means that ResizeObserver was not
       * able to deliver all observations within a single animation frame, so we use
       * `requestAnimationFrame` to ensure we don't deliver unnecessary observations.
       * Further reading: https://github.com/WICG/resize-observer/issues/38
       */
      const resizeObserver = new ResizeObserver(() => {
        cancelAnimationFrame(rAF);
        rAF = window.requestAnimationFrame(handleResize);
      });
      resizeObserver.observe(element);
      return () => {
        window.cancelAnimationFrame(rAF);
        resizeObserver.unobserve(element);
      };
    }
  }, [element, handleResize]);
}

/* -----------------------------------------------------------------------------------------------*/

const Root = ScrollArea;
const Viewport = ScrollAreaViewport;
const Scrollbar = ScrollAreaScrollbar;
const Thumb = ScrollAreaThumb;
const Corner = ScrollAreaCorner;

export {
  createScrollAreaScope,
  //
  ScrollArea,
  ScrollAreaViewport,
  ScrollAreaScrollbar,
  ScrollAreaThumb,
  ScrollAreaCorner,
  //
  Root,
  Viewport,
  Scrollbar,
  Thumb,
  Corner,
};
export type {
  ScrollAreaProps,
  ScrollAreaViewportProps,
  ScrollAreaScrollbarProps,
  ScrollAreaThumbProps,
  ScrollAreaCornerProps,
};



================================================
FILE: packages/react/scroll-area/src/use-state-machine.ts
================================================
import * as React from 'react';

type Machine<S> = { [k: string]: { [k: string]: S } };
type MachineState<T> = keyof T;
type MachineEvent<T> = keyof UnionToIntersection<T[keyof T]>;

// 🤯 https://fettblog.eu/typescript-union-to-intersection/
type UnionToIntersection<T> = (T extends any ? (x: T) => any : never) extends (x: infer R) => any
  ? R
  : never;

export function useStateMachine<M>(
  initialState: MachineState<M>,
  machine: M & Machine<MachineState<M>>,
) {
  return React.useReducer((state: MachineState<M>, event: MachineEvent<M>): MachineState<M> => {
    const nextState = (machine[state] as any)[event];
    return nextState ?? state;
  }, initialState);
}



================================================
FILE: packages/react/select/README.md
================================================
# `react-select`

View docs [here](https://radix-ui.com/primitives/docs/components/select).



================================================
FILE: packages/react/select/CHANGELOG.md
================================================
# @radix-ui/react-select

## 2.2.6

- Updated dependencies: `@radix-ui/react-slot@1.2.4`, `@radix-ui/react-popper@1.2.8`, `@radix-ui/react-focus-guards@1.1.3`, `@radix-ui/primitive@1.1.3`, `@radix-ui/react-context@1.1.3`, `@radix-ui/react-collection@1.1.8`, `@radix-ui/react-primitive@2.1.4`, `@radix-ui/react-dismissable-layer@1.1.11`, `@radix-ui/react-focus-scope@1.1.8`, `@radix-ui/react-portal@1.1.10`, `@radix-ui/react-visually-hidden@1.2.4`

## 2.2.5

- Replace deprecated 'ElementRef' with 'ComponentRef' (#3426)
- Updated dependencies: `@radix-ui/react-dismissable-layer@1.1.10`, `@radix-ui/react-visually-hidden@1.2.3`, `@radix-ui/react-focus-scope@1.1.7`, `@radix-ui/react-popper@1.2.7`, `@radix-ui/react-portal@1.1.9`, `@radix-ui/react-slot@1.2.3`, `@radix-ui/react-collection@1.1.7`, `@radix-ui/react-primitive@2.1.3`

## 2.2.4

- Updated dependencies: `@radix-ui/react-slot@1.2.2`, `@radix-ui/react-collection@1.1.6`, `@radix-ui/react-primitive@2.1.2`, `@radix-ui/react-dismissable-layer@1.1.9`, `@radix-ui/react-focus-scope@1.1.6`, `@radix-ui/react-popper@1.2.6`, `@radix-ui/react-portal@1.1.8`, `@radix-ui/react-visually-hidden@1.2.2`

## 2.2.3

- Updated dependencies: `@radix-ui/react-slot@1.2.1`, `@radix-ui/react-collection@1.1.5`, `@radix-ui/react-primitive@2.1.1`, `@radix-ui/react-dismissable-layer@1.1.8`, `@radix-ui/react-focus-scope@1.1.5`, `@radix-ui/react-popper@1.2.5`, `@radix-ui/react-portal@1.1.7`, `@radix-ui/react-visually-hidden@1.2.1`

## 2.2.2

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.2`

## 2.2.1

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.1`

## 2.2.0

- All form controls with internal bubble inputs now use the Radix `Primitive` component by default. This will allow us to expose these components directly so users can better control this behavior in the future.
- Minor improvements to `useControllableState` to enhance performance, reduce surface area for bugs, and log warnings when misused (#3455)
- Updated dependencies: `@radix-ui/react-collection@1.1.4`, `@radix-ui/react-use-controllable-state@1.2.0`, `@radix-ui/react-visually-hidden@1.2.0`, `@radix-ui/react-primitive@2.1.0`, `@radix-ui/react-dismissable-layer@1.1.7`, `@radix-ui/react-focus-scope@1.1.4`, `@radix-ui/react-popper@1.2.4`, `@radix-ui/react-portal@1.1.6`



================================================
FILE: packages/react/select/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/select/package.json
================================================
{
  "name": "@radix-ui/react-select",
  "version": "2.2.6",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/number": "workspace:*",
    "@radix-ui/primitive": "workspace:*",
    "@radix-ui/react-collection": "workspace:*",
    "@radix-ui/react-compose-refs": "workspace:*",
    "@radix-ui/react-context": "workspace:*",
    "@radix-ui/react-direction": "workspace:*",
    "@radix-ui/react-dismissable-layer": "workspace:*",
    "@radix-ui/react-focus-guards": "workspace:*",
    "@radix-ui/react-focus-scope": "workspace:*",
    "@radix-ui/react-id": "workspace:*",
    "@radix-ui/react-popper": "workspace:*",
    "@radix-ui/react-portal": "workspace:*",
    "@radix-ui/react-primitive": "workspace:*",
    "@radix-ui/react-slot": "workspace:*",
    "@radix-ui/react-use-callback-ref": "workspace:*",
    "@radix-ui/react-use-controllable-state": "workspace:*",
    "@radix-ui/react-use-layout-effect": "workspace:*",
    "@radix-ui/react-use-previous": "workspace:*",
    "@radix-ui/react-visually-hidden": "workspace:*",
    "aria-hidden": "^1.2.4",
    "react-remove-scroll": "^2.6.3"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/test-data": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/select/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/select/src/index.ts
================================================
'use client';
export {
  createSelectScope,
  //
  Select,
  SelectTrigger,
  SelectValue,
  SelectIcon,
  SelectPortal,
  SelectContent,
  SelectViewport,
  SelectGroup,
  SelectLabel,
  SelectItem,
  SelectItemText,
  SelectItemIndicator,
  SelectScrollUpButton,
  SelectScrollDownButton,
  SelectSeparator,
  SelectArrow,
  //
  Root,
  Trigger,
  Value,
  Icon,
  Portal,
  Content,
  Viewport,
  Group,
  Label,
  Item,
  ItemText,
  ItemIndicator,
  ScrollUpButton,
  ScrollDownButton,
  Separator,
  Arrow,
} from './select';
export type {
  SelectProps,
  SelectTriggerProps,
  SelectValueProps,
  SelectIconProps,
  SelectPortalProps,
  SelectContentProps,
  SelectViewportProps,
  SelectGroupProps,
  SelectLabelProps,
  SelectItemProps,
  SelectItemTextProps,
  SelectItemIndicatorProps,
  SelectScrollUpButtonProps,
  SelectScrollDownButtonProps,
  SelectSeparatorProps,
  SelectArrowProps,
} from './select';



================================================
FILE: packages/react/separator/README.md
================================================
# `react-separator`

View docs [here](https://radix-ui.com/primitives/docs/components/separator).



================================================
FILE: packages/react/separator/CHANGELOG.md
================================================
# @radix-ui/react-separator

## 1.1.8

- Updated dependencies: `@radix-ui/react-primitive@2.1.4`

## 1.1.7

- Replace deprecated 'ElementRef' with 'ComponentRef' (#3426)
- Updated dependencies: `@radix-ui/react-primitive@2.1.3`

## 1.1.6

- Updated dependencies: `@radix-ui/react-primitive@2.1.2`

## 1.1.5

- Updated dependencies: `@radix-ui/react-primitive@2.1.1`

## 1.1.4

- Updated dependencies: `@radix-ui/react-primitive@2.1.0`



================================================
FILE: packages/react/separator/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/separator/package.json
================================================
{
  "name": "@radix-ui/react-separator",
  "version": "1.1.8",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/react-primitive": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/separator/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/separator/src/index.ts
================================================
export {
  Separator,
  //
  Root,
} from './separator';
export type { SeparatorProps } from './separator';



================================================
FILE: packages/react/separator/src/separator.tsx
================================================
import * as React from 'react';
import { Primitive } from '@radix-ui/react-primitive';

/* -------------------------------------------------------------------------------------------------
 *  Separator
 * -----------------------------------------------------------------------------------------------*/

const NAME = 'Separator';
const DEFAULT_ORIENTATION = 'horizontal';
const ORIENTATIONS = ['horizontal', 'vertical'] as const;

type Orientation = (typeof ORIENTATIONS)[number];
type SeparatorElement = React.ComponentRef<typeof Primitive.div>;
type PrimitiveDivProps = React.ComponentPropsWithoutRef<typeof Primitive.div>;
interface SeparatorProps extends PrimitiveDivProps {
  /**
   * Either `vertical` or `horizontal`. Defaults to `horizontal`.
   */
  orientation?: Orientation;
  /**
   * Whether or not the component is purely decorative. When true, accessibility-related attributes
   * are updated so that that the rendered element is removed from the accessibility tree.
   */
  decorative?: boolean;
}

const Separator = React.forwardRef<SeparatorElement, SeparatorProps>((props, forwardedRef) => {
  const { decorative, orientation: orientationProp = DEFAULT_ORIENTATION, ...domProps } = props;
  const orientation = isValidOrientation(orientationProp) ? orientationProp : DEFAULT_ORIENTATION;
  // `aria-orientation` defaults to `horizontal` so we only need it if `orientation` is vertical
  const ariaOrientation = orientation === 'vertical' ? orientation : undefined;
  const semanticProps = decorative
    ? { role: 'none' }
    : { 'aria-orientation': ariaOrientation, role: 'separator' };

  return (
    <Primitive.div
      data-orientation={orientation}
      {...semanticProps}
      {...domProps}
      ref={forwardedRef}
    />
  );
});

Separator.displayName = NAME;

/* -----------------------------------------------------------------------------------------------*/

function isValidOrientation(orientation: any): orientation is Orientation {
  return ORIENTATIONS.includes(orientation);
}

const Root = Separator;

export {
  Separator,
  //
  Root,
};
export type { SeparatorProps };



================================================
FILE: packages/react/slider/README.md
================================================
# `react-slider`

View docs [here](https://radix-ui.com/primitives/docs/components/slider).



================================================
FILE: packages/react/slider/CHANGELOG.md
================================================
# @radix-ui/react-slider

## 1.3.6

- Updated dependencies: `@radix-ui/primitive@1.1.3`, `@radix-ui/react-context@1.1.3`, `@radix-ui/react-collection@1.1.8`, `@radix-ui/react-primitive@2.1.4`

## 1.3.5

- Replace deprecated 'ElementRef' with 'ComponentRef' (#3426)
- Updated dependencies: `@radix-ui/react-collection@1.1.7`, `@radix-ui/react-primitive@2.1.3`

## 1.3.4

- Updated dependencies: `@radix-ui/react-collection@1.1.6`, `@radix-ui/react-primitive@2.1.2`

## 1.3.3

- Updated dependencies: `@radix-ui/react-collection@1.1.5`, `@radix-ui/react-primitive@2.1.1`

## 1.3.2

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.2`

## 1.3.1

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.1`

## 1.3.0

- All form controls with internal bubble inputs now use the Radix `Primitive` component by default. This will allow us to expose these components directly so users can better control this behavior in the future.
- Updated dependencies: `@radix-ui/react-collection@1.1.4`, `@radix-ui/react-use-controllable-state@1.2.0`, `@radix-ui/react-primitive@2.1.0`



================================================
FILE: packages/react/slider/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/slider/package.json
================================================
{
  "name": "@radix-ui/react-slider",
  "version": "1.3.6",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/number": "workspace:*",
    "@radix-ui/primitive": "workspace:*",
    "@radix-ui/react-collection": "workspace:*",
    "@radix-ui/react-compose-refs": "workspace:*",
    "@radix-ui/react-context": "workspace:*",
    "@radix-ui/react-direction": "workspace:*",
    "@radix-ui/react-primitive": "workspace:*",
    "@radix-ui/react-use-controllable-state": "workspace:*",
    "@radix-ui/react-use-layout-effect": "workspace:*",
    "@radix-ui/react-use-previous": "workspace:*",
    "@radix-ui/react-use-size": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/slider/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/slider/src/index.ts
================================================
'use client';
export {
  createSliderScope,
  //
  Slider,
  SliderTrack,
  SliderRange,
  SliderThumb,
  //
  Root,
  Track,
  Range,
  Thumb,
} from './slider';
export type { SliderProps, SliderTrackProps, SliderRangeProps, SliderThumbProps } from './slider';



================================================
FILE: packages/react/slider/src/slider.tsx
================================================
import * as React from 'react';
import { clamp } from '@radix-ui/number';
import { composeEventHandlers } from '@radix-ui/primitive';
import { useComposedRefs } from '@radix-ui/react-compose-refs';
import { createContextScope } from '@radix-ui/react-context';
import { useControllableState } from '@radix-ui/react-use-controllable-state';
import { useDirection } from '@radix-ui/react-direction';
import { usePrevious } from '@radix-ui/react-use-previous';
import { useSize } from '@radix-ui/react-use-size';
import { Primitive } from '@radix-ui/react-primitive';
import { createCollection } from '@radix-ui/react-collection';

import type { Scope } from '@radix-ui/react-context';

type Direction = 'ltr' | 'rtl';

const PAGE_KEYS = ['PageUp', 'PageDown'];
const ARROW_KEYS = ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'];

type SlideDirection = 'from-left' | 'from-right' | 'from-bottom' | 'from-top';
const BACK_KEYS: Record<SlideDirection, string[]> = {
  'from-left': ['Home', 'PageDown', 'ArrowDown', 'ArrowLeft'],
  'from-right': ['Home', 'PageDown', 'ArrowDown', 'ArrowRight'],
  'from-bottom': ['Home', 'PageDown', 'ArrowDown', 'ArrowLeft'],
  'from-top': ['Home', 'PageDown', 'ArrowUp', 'ArrowLeft'],
};

/* -------------------------------------------------------------------------------------------------
 * Slider
 * -----------------------------------------------------------------------------------------------*/

const SLIDER_NAME = 'Slider';

const [Collection, useCollection, createCollectionScope] =
  createCollection<SliderThumbElement>(SLIDER_NAME);

type ScopedProps<P> = P & { __scopeSlider?: Scope };
const [createSliderContext, createSliderScope] = createContextScope(SLIDER_NAME, [
  createCollectionScope,
]);

type SliderContextValue = {
  name: string | undefined;
  disabled: boolean | undefined;
  min: number;
  max: number;
  values: number[];
  valueIndexToChangeRef: React.MutableRefObject<number>;
  thumbs: Set<SliderThumbElement>;
  orientation: SliderProps['orientation'];
  form: string | undefined;
};

const [SliderProvider, useSliderContext] = createSliderContext<SliderContextValue>(SLIDER_NAME);

type SliderElement = SliderHorizontalElement | SliderVerticalElement;
interface SliderProps
  extends Omit<
    SliderHorizontalProps | SliderVerticalProps,
    keyof SliderOrientationPrivateProps | 'defaultValue'
  > {
  name?: string;
  disabled?: boolean;
  orientation?: React.AriaAttributes['aria-orientation'];
  dir?: Direction;
  min?: number;
  max?: number;
  step?: number;
  minStepsBetweenThumbs?: number;
  value?: number[];
  defaultValue?: number[];
  onValueChange?(value: number[]): void;
  onValueCommit?(value: number[]): void;
  inverted?: boolean;
  form?: string;
}

const Slider = React.forwardRef<SliderElement, SliderProps>(
  (props: ScopedProps<SliderProps>, forwardedRef) => {
    const {
      name,
      min = 0,
      max = 100,
      step = 1,
      orientation = 'horizontal',
      disabled = false,
      minStepsBetweenThumbs = 0,
      defaultValue = [min],
      value,
      onValueChange = () => {},
      onValueCommit = () => {},
      inverted = false,
      form,
      ...sliderProps
    } = props;
    const thumbRefs = React.useRef<SliderContextValue['thumbs']>(new Set());
    const valueIndexToChangeRef = React.useRef<number>(0);
    const isHorizontal = orientation === 'horizontal';
    const SliderOrientation = isHorizontal ? SliderHorizontal : SliderVertical;

    const [values = [], setValues] = useControllableState({
      prop: value,
      defaultProp: defaultValue,
      onChange: (value) => {
        const thumbs = [...thumbRefs.current];
        thumbs[valueIndexToChangeRef.current]?.focus();
        onValueChange(value);
      },
    });
    const valuesBeforeSlideStartRef = React.useRef(values);

    function handleSlideStart(value: number) {
      const closestIndex = getClosestValueIndex(values, value);
      updateValues(value, closestIndex);
    }

    function handleSlideMove(value: number) {
      updateValues(value, valueIndexToChangeRef.current);
    }

    function handleSlideEnd() {
      const prevValue = valuesBeforeSlideStartRef.current[valueIndexToChangeRef.current];
      const nextValue = values[valueIndexToChangeRef.current];
      const hasChanged = nextValue !== prevValue;
      if (hasChanged) onValueCommit(values);
    }

    function updateValues(value: number, atIndex: number, { commit } = { commit: false }) {
      const decimalCount = getDecimalCount(step);
      const snapToStep = roundValue(Math.round((value - min) / step) * step + min, decimalCount);
      const nextValue = clamp(snapToStep, [min, max]);

      setValues((prevValues = []) => {
        const nextValues = getNextSortedValues(prevValues, nextValue, atIndex);
        if (hasMinStepsBetweenValues(nextValues, minStepsBetweenThumbs * step)) {
          valueIndexToChangeRef.current = nextValues.indexOf(nextValue);
          const hasChanged = String(nextValues) !== String(prevValues);
          if (hasChanged && commit) onValueCommit(nextValues);
          return hasChanged ? nextValues : prevValues;
        } else {
          return prevValues;
        }
      });
    }

    return (
      <SliderProvider
        scope={props.__scopeSlider}
        name={name}
        disabled={disabled}
        min={min}
        max={max}
        valueIndexToChangeRef={valueIndexToChangeRef}
        thumbs={thumbRefs.current}
        values={values}
        orientation={orientation}
        form={form}
      >
        <Collection.Provider scope={props.__scopeSlider}>
          <Collection.Slot scope={props.__scopeSlider}>
            <SliderOrientation
              aria-disabled={disabled}
              data-disabled={disabled ? '' : undefined}
              {...sliderProps}
              ref={forwardedRef}
              onPointerDown={composeEventHandlers(sliderProps.onPointerDown, () => {
                if (!disabled) valuesBeforeSlideStartRef.current = values;
              })}
              min={min}
              max={max}
              inverted={inverted}
              onSlideStart={disabled ? undefined : handleSlideStart}
              onSlideMove={disabled ? undefined : handleSlideMove}
              onSlideEnd={disabled ? undefined : handleSlideEnd}
              onHomeKeyDown={() => !disabled && updateValues(min, 0, { commit: true })}
              onEndKeyDown={() =>
                !disabled && updateValues(max, values.length - 1, { commit: true })
              }
              onStepKeyDown={({ event, direction: stepDirection }) => {
                if (!disabled) {
                  const isPageKey = PAGE_KEYS.includes(event.key);
                  const isSkipKey = isPageKey || (event.shiftKey && ARROW_KEYS.includes(event.key));
                  const multiplier = isSkipKey ? 10 : 1;
                  const atIndex = valueIndexToChangeRef.current;
                  const value = values[atIndex]!;
                  const stepInDirection = step * multiplier * stepDirection;
                  updateValues(value + stepInDirection, atIndex, { commit: true });
                }
              }}
            />
          </Collection.Slot>
        </Collection.Provider>
      </SliderProvider>
    );
  },
);

Slider.displayName = SLIDER_NAME;

/* -------------------------------------------------------------------------------------------------
 * SliderHorizontal
 * -----------------------------------------------------------------------------------------------*/

type Side = 'top' | 'right' | 'bottom' | 'left';

const [SliderOrientationProvider, useSliderOrientationContext] = createSliderContext<{
  startEdge: Side;
  endEdge: Side;
  size: keyof NonNullable<ReturnType<typeof useSize>>;
  direction: number;
}>(SLIDER_NAME, {
  startEdge: 'left',
  endEdge: 'right',
  size: 'width',
  direction: 1,
});

type SliderOrientationPrivateProps = {
  min: number;
  max: number;
  inverted: boolean;
  onSlideStart?(value: number): void;
  onSlideMove?(value: number): void;
  onSlideEnd?(): void;
  onHomeKeyDown(event: React.KeyboardEvent): void;
  onEndKeyDown(event: React.KeyboardEvent): void;
  onStepKeyDown(step: { event: React.KeyboardEvent; direction: number }): void;
};
interface SliderOrientationProps
  extends Omit<SliderImplProps, keyof SliderImplPrivateProps>,
    SliderOrientationPrivateProps {}

type SliderHorizontalElement = SliderImplElement;
interface SliderHorizontalProps extends SliderOrientationProps {
  dir?: Direction;
}

const SliderHorizontal = React.forwardRef<SliderHorizontalElement, SliderHorizontalProps>(
  (props: ScopedProps<SliderHorizontalProps>, forwardedRef) => {
    const {
      min,
      max,
      dir,
      inverted,
      onSlideStart,
      onSlideMove,
      onSlideEnd,
      onStepKeyDown,
      ...sliderProps
    } = props;
    const [slider, setSlider] = React.useState<SliderImplElement | null>(null);
    const composedRefs = useComposedRefs(forwardedRef, (node) => setSlider(node));
    const rectRef = React.useRef<DOMRect>(undefined);
    const direction = useDirection(dir);
    const isDirectionLTR = direction === 'ltr';
    const isSlidingFromLeft = (isDirectionLTR && !inverted) || (!isDirectionLTR && inverted);

    function getValueFromPointer(pointerPosition: number) {
      const rect = rectRef.current || slider!.getBoundingClientRect();
      const input: [number, number] = [0, rect.width];
      const output: [number, number] = isSlidingFromLeft ? [min, max] : [max, min];
      const value = linearScale(input, output);

      rectRef.current = rect;
      return value(pointerPosition - rect.left);
    }

    return (
      <SliderOrientationProvider
        scope={props.__scopeSlider}
        startEdge={isSlidingFromLeft ? 'left' : 'right'}
        endEdge={isSlidingFromLeft ? 'right' : 'left'}
        direction={isSlidingFromLeft ? 1 : -1}
        size="width"
      >
        <SliderImpl
          dir={direction}
          data-orientation="horizontal"
          {...sliderProps}
          ref={composedRefs}
          style={{
            ...sliderProps.style,
            ['--radix-slider-thumb-transform' as any]: 'translateX(-50%)',
          }}
          onSlideStart={(event) => {
            const value = getValueFromPointer(event.clientX);
            onSlideStart?.(value);
          }}
          onSlideMove={(event) => {
            const value = getValueFromPointer(event.clientX);
            onSlideMove?.(value);
          }}
          onSlideEnd={() => {
            rectRef.current = undefined;
            onSlideEnd?.();
          }}
          onStepKeyDown={(event) => {
            const slideDirection = isSlidingFromLeft ? 'from-left' : 'from-right';
            const isBackKey = BACK_KEYS[slideDirection].includes(event.key);
            onStepKeyDown?.({ event, direction: isBackKey ? -1 : 1 });
          }}
        />
      </SliderOrientationProvider>
    );
  },
);

/* -------------------------------------------------------------------------------------------------
 * SliderVertical
 * -----------------------------------------------------------------------------------------------*/

type SliderVerticalElement = SliderImplElement;
interface SliderVerticalProps extends SliderOrientationProps {}

const SliderVertical = React.forwardRef<SliderVerticalElement, SliderVerticalProps>(
  (props: ScopedProps<SliderVerticalProps>, forwardedRef) => {
    const {
      min,
      max,
      inverted,
      onSlideStart,
      onSlideMove,
      onSlideEnd,
      onStepKeyDown,
      ...sliderProps
    } = props;
    const sliderRef = React.useRef<SliderImplElement>(null);
    const ref = useComposedRefs(forwardedRef, sliderRef);
    const rectRef = React.useRef<DOMRect>(undefined);
    const isSlidingFromBottom = !inverted;

    function getValueFromPointer(pointerPosition: number) {
      const rect = rectRef.current || sliderRef.current!.getBoundingClientRect();
      const input: [number, number] = [0, rect.height];
      const output: [number, number] = isSlidingFromBottom ? [max, min] : [min, max];
      const value = linearScale(input, output);

      rectRef.current = rect;
      return value(pointerPosition - rect.top);
    }

    return (
      <SliderOrientationProvider
        scope={props.__scopeSlider}
        startEdge={isSlidingFromBottom ? 'bottom' : 'top'}
        endEdge={isSlidingFromBottom ? 'top' : 'bottom'}
        size="height"
        direction={isSlidingFromBottom ? 1 : -1}
      >
        <SliderImpl
          data-orientation="vertical"
          {...sliderProps}
          ref={ref}
          style={{
            ...sliderProps.style,
            ['--radix-slider-thumb-transform' as any]: 'translateY(50%)',
          }}
          onSlideStart={(event) => {
            const value = getValueFromPointer(event.clientY);
            onSlideStart?.(value);
          }}
          onSlideMove={(event) => {
            const value = getValueFromPointer(event.clientY);
            onSlideMove?.(value);
          }}
          onSlideEnd={() => {
            rectRef.current = undefined;
            onSlideEnd?.();
          }}
          onStepKeyDown={(event) => {
            const slideDirection = isSlidingFromBottom ? 'from-bottom' : 'from-top';
            const isBackKey = BACK_KEYS[slideDirection].includes(event.key);
            onStepKeyDown?.({ event, direction: isBackKey ? -1 : 1 });
          }}
        />
      </SliderOrientationProvider>
    );
  },
);

/* -------------------------------------------------------------------------------------------------
 * SliderImpl
 * -----------------------------------------------------------------------------------------------*/

type SliderImplElement = React.ComponentRef<typeof Primitive.span>;
type PrimitiveDivProps = React.ComponentPropsWithoutRef<typeof Primitive.div>;
type SliderImplPrivateProps = {
  onSlideStart(event: React.PointerEvent): void;
  onSlideMove(event: React.PointerEvent): void;
  onSlideEnd(event: React.PointerEvent): void;
  onHomeKeyDown(event: React.KeyboardEvent): void;
  onEndKeyDown(event: React.KeyboardEvent): void;
  onStepKeyDown(event: React.KeyboardEvent): void;
};
interface SliderImplProps extends PrimitiveDivProps, SliderImplPrivateProps {}

const SliderImpl = React.forwardRef<SliderImplElement, SliderImplProps>(
  (props: ScopedProps<SliderImplProps>, forwardedRef) => {
    const {
      __scopeSlider,
      onSlideStart,
      onSlideMove,
      onSlideEnd,
      onHomeKeyDown,
      onEndKeyDown,
      onStepKeyDown,
      ...sliderProps
    } = props;
    const context = useSliderContext(SLIDER_NAME, __scopeSlider);

    return (
      <Primitive.span
        {...sliderProps}
        ref={forwardedRef}
        onKeyDown={composeEventHandlers(props.onKeyDown, (event) => {
          if (event.key === 'Home') {
            onHomeKeyDown(event);
            // Prevent scrolling to page start
            event.preventDefault();
          } else if (event.key === 'End') {
            onEndKeyDown(event);
            // Prevent scrolling to page end
            event.preventDefault();
          } else if (PAGE_KEYS.concat(ARROW_KEYS).includes(event.key)) {
            onStepKeyDown(event);
            // Prevent scrolling for directional key presses
            event.preventDefault();
          }
        })}
        onPointerDown={composeEventHandlers(props.onPointerDown, (event) => {
          const target = event.target as HTMLElement;
          target.setPointerCapture(event.pointerId);
          // Prevent browser focus behaviour because we focus a thumb manually when values change.
          event.preventDefault();
          // Touch devices have a delay before focusing so won't focus if touch immediately moves
          // away from target (sliding). We want thumb to focus regardless.
          if (context.thumbs.has(target)) {
            target.focus();
          } else {
            onSlideStart(event);
          }
        })}
        onPointerMove={composeEventHandlers(props.onPointerMove, (event) => {
          const target = event.target as HTMLElement;
          if (target.hasPointerCapture(event.pointerId)) onSlideMove(event);
        })}
        onPointerUp={composeEventHandlers(props.onPointerUp, (event) => {
          const target = event.target as HTMLElement;
          if (target.hasPointerCapture(event.pointerId)) {
            target.releasePointerCapture(event.pointerId);
            onSlideEnd(event);
          }
        })}
      />
    );
  },
);

/* -------------------------------------------------------------------------------------------------
 * SliderTrack
 * -----------------------------------------------------------------------------------------------*/

const TRACK_NAME = 'SliderTrack';

type SliderTrackElement = React.ComponentRef<typeof Primitive.span>;
type PrimitiveSpanProps = React.ComponentPropsWithoutRef<typeof Primitive.span>;
interface SliderTrackProps extends PrimitiveSpanProps {}

const SliderTrack = React.forwardRef<SliderTrackElement, SliderTrackProps>(
  (props: ScopedProps<SliderTrackProps>, forwardedRef) => {
    const { __scopeSlider, ...trackProps } = props;
    const context = useSliderContext(TRACK_NAME, __scopeSlider);
    return (
      <Primitive.span
        data-disabled={context.disabled ? '' : undefined}
        data-orientation={context.orientation}
        {...trackProps}
        ref={forwardedRef}
      />
    );
  },
);

SliderTrack.displayName = TRACK_NAME;

/* -------------------------------------------------------------------------------------------------
 * SliderRange
 * -----------------------------------------------------------------------------------------------*/

const RANGE_NAME = 'SliderRange';

type SliderRangeElement = React.ComponentRef<typeof Primitive.span>;
interface SliderRangeProps extends PrimitiveSpanProps {}

const SliderRange = React.forwardRef<SliderRangeElement, SliderRangeProps>(
  (props: ScopedProps<SliderRangeProps>, forwardedRef) => {
    const { __scopeSlider, ...rangeProps } = props;
    const context = useSliderContext(RANGE_NAME, __scopeSlider);
    const orientation = useSliderOrientationContext(RANGE_NAME, __scopeSlider);
    const ref = React.useRef<HTMLSpanElement>(null);
    const composedRefs = useComposedRefs(forwardedRef, ref);
    const valuesCount = context.values.length;
    const percentages = context.values.map((value) =>
      convertValueToPercentage(value, context.min, context.max),
    );
    const offsetStart = valuesCount > 1 ? Math.min(...percentages) : 0;
    const offsetEnd = 100 - Math.max(...percentages);

    return (
      <Primitive.span
        data-orientation={context.orientation}
        data-disabled={context.disabled ? '' : undefined}
        {...rangeProps}
        ref={composedRefs}
        style={{
          ...props.style,
          [orientation.startEdge]: offsetStart + '%',
          [orientation.endEdge]: offsetEnd + '%',
        }}
      />
    );
  },
);

SliderRange.displayName = RANGE_NAME;

/* -------------------------------------------------------------------------------------------------
 * SliderThumb
 * -----------------------------------------------------------------------------------------------*/

const THUMB_NAME = 'SliderThumb';

type SliderThumbElement = SliderThumbImplElement;
interface SliderThumbProps extends Omit<SliderThumbImplProps, 'index'> {}

const SliderThumb = React.forwardRef<SliderThumbElement, SliderThumbProps>(
  (props: ScopedProps<SliderThumbProps>, forwardedRef) => {
    const getItems = useCollection(props.__scopeSlider);
    const [thumb, setThumb] = React.useState<SliderThumbImplElement | null>(null);
    const composedRefs = useComposedRefs(forwardedRef, (node) => setThumb(node));
    const index = React.useMemo(
      () => (thumb ? getItems().findIndex((item) => item.ref.current === thumb) : -1),
      [getItems, thumb],
    );
    return <SliderThumbImpl {...props} ref={composedRefs} index={index} />;
  },
);

type SliderThumbImplElement = React.ComponentRef<typeof Primitive.span>;
interface SliderThumbImplProps extends PrimitiveSpanProps {
  index: number;
  name?: string;
}

const SliderThumbImpl = React.forwardRef<SliderThumbImplElement, SliderThumbImplProps>(
  (props: ScopedProps<SliderThumbImplProps>, forwardedRef) => {
    const { __scopeSlider, index, name, ...thumbProps } = props;
    const context = useSliderContext(THUMB_NAME, __scopeSlider);
    const orientation = useSliderOrientationContext(THUMB_NAME, __scopeSlider);
    const [thumb, setThumb] = React.useState<HTMLSpanElement | null>(null);
    const composedRefs = useComposedRefs(forwardedRef, (node) => setThumb(node));
    // We set this to true by default so that events bubble to forms without JS (SSR)
    const isFormControl = thumb ? context.form || !!thumb.closest('form') : true;
    const size = useSize(thumb);
    // We cast because index could be `-1` which would return undefined
    const value = context.values[index] as number | undefined;
    const percent =
      value === undefined ? 0 : convertValueToPercentage(value, context.min, context.max);
    const label = getLabel(index, context.values.length);
    const orientationSize = size?.[orientation.size];
    const thumbInBoundsOffset = orientationSize
      ? getThumbInBoundsOffset(orientationSize, percent, orientation.direction)
      : 0;

    React.useEffect(() => {
      if (thumb) {
        context.thumbs.add(thumb);
        return () => {
          context.thumbs.delete(thumb);
        };
      }
    }, [thumb, context.thumbs]);

    return (
      <span
        style={{
          transform: 'var(--radix-slider-thumb-transform)',
          position: 'absolute',
          [orientation.startEdge]: `calc(${percent}% + ${thumbInBoundsOffset}px)`,
        }}
      >
        <Collection.ItemSlot scope={props.__scopeSlider}>
          <Primitive.span
            role="slider"
            aria-label={props['aria-label'] || label}
            aria-valuemin={context.min}
            aria-valuenow={value}
            aria-valuemax={context.max}
            aria-orientation={context.orientation}
            data-orientation={context.orientation}
            data-disabled={context.disabled ? '' : undefined}
            tabIndex={context.disabled ? undefined : 0}
            {...thumbProps}
            ref={composedRefs}
            /**
             * There will be no value on initial render while we work out the index so we hide thumbs
             * without a value, otherwise SSR will render them in the wrong position before they
             * snap into the correct position during hydration which would be visually jarring for
             * slower connections.
             */
            style={value === undefined ? { display: 'none' } : props.style}
            onFocus={composeEventHandlers(props.onFocus, () => {
              context.valueIndexToChangeRef.current = index;
            })}
          />
        </Collection.ItemSlot>

        {isFormControl && (
          <SliderBubbleInput
            key={index}
            name={
              name ??
              (context.name ? context.name + (context.values.length > 1 ? '[]' : '') : undefined)
            }
            form={context.form}
            value={value}
          />
        )}
      </span>
    );
  },
);

SliderThumb.displayName = THUMB_NAME;

/* -------------------------------------------------------------------------------------------------
 * SliderBubbleInput
 * -----------------------------------------------------------------------------------------------*/

const BUBBLE_INPUT_NAME = 'RadioBubbleInput';

type InputProps = React.ComponentPropsWithoutRef<typeof Primitive.input>;
interface SliderBubbleInputProps extends InputProps {}

const SliderBubbleInput = React.forwardRef<HTMLInputElement, SliderBubbleInputProps>(
  ({ __scopeSlider, value, ...props }: ScopedProps<SliderBubbleInputProps>, forwardedRef) => {
    const ref = React.useRef<HTMLInputElement>(null);
    const composedRefs = useComposedRefs(ref, forwardedRef);
    const prevValue = usePrevious(value);

    // Bubble value change to parents (e.g form change event)
    React.useEffect(() => {
      const input = ref.current;
      if (!input) return;

      const inputProto = window.HTMLInputElement.prototype;
      const descriptor = Object.getOwnPropertyDescriptor(inputProto, 'value') as PropertyDescriptor;
      const setValue = descriptor.set;
      if (prevValue !== value && setValue) {
        const event = new Event('input', { bubbles: true });
        setValue.call(input, value);
        input.dispatchEvent(event);
      }
    }, [prevValue, value]);

    /**
     * We purposefully do not use `type="hidden"` here otherwise forms that
     * wrap it will not be able to access its value via the FormData API.
     *
     * We purposefully do not add the `value` attribute here to allow the value
     * to be set programmatically and bubble to any parent form `onChange` event.
     * Adding the `value` will cause React to consider the programmatic
     * dispatch a duplicate and it will get swallowed.
     */
    return (
      <Primitive.input
        style={{ display: 'none' }}
        {...props}
        ref={composedRefs}
        defaultValue={value}
      />
    );
  },
);

SliderBubbleInput.displayName = BUBBLE_INPUT_NAME;

/* -----------------------------------------------------------------------------------------------*/

function getNextSortedValues(prevValues: number[] = [], nextValue: number, atIndex: number) {
  const nextValues = [...prevValues];
  nextValues[atIndex] = nextValue;
  return nextValues.sort((a, b) => a - b);
}

function convertValueToPercentage(value: number, min: number, max: number) {
  const maxSteps = max - min;
  const percentPerStep = 100 / maxSteps;
  const percentage = percentPerStep * (value - min);
  return clamp(percentage, [0, 100]);
}

/**
 * Returns a label for each thumb when there are two or more thumbs
 */
function getLabel(index: number, totalValues: number) {
  if (totalValues > 2) {
    return `Value ${index + 1} of ${totalValues}`;
  } else if (totalValues === 2) {
    return ['Minimum', 'Maximum'][index];
  } else {
    return undefined;
  }
}

/**
 * Given a `values` array and a `nextValue`, determine which value in
 * the array is closest to `nextValue` and return its index.
 *
 * @example
 * // returns 1
 * getClosestValueIndex([10, 30], 25);
 */
function getClosestValueIndex(values: number[], nextValue: number) {
  if (values.length === 1) return 0;
  const distances = values.map((value) => Math.abs(value - nextValue));
  const closestDistance = Math.min(...distances);
  return distances.indexOf(closestDistance);
}

/**
 * Offsets the thumb centre point while sliding to ensure it remains
 * within the bounds of the slider when reaching the edges
 */
function getThumbInBoundsOffset(width: number, left: number, direction: number) {
  const halfWidth = width / 2;
  const halfPercent = 50;
  const offset = linearScale([0, halfPercent], [0, halfWidth]);
  return (halfWidth - offset(left) * direction) * direction;
}

/**
 * Gets an array of steps between each value.
 *
 * @example
 * // returns [1, 9]
 * getStepsBetweenValues([10, 11, 20]);
 */
function getStepsBetweenValues(values: number[]) {
  return values.slice(0, -1).map((value, index) => values[index + 1]! - value);
}

/**
 * Verifies the minimum steps between all values is greater than or equal
 * to the expected minimum steps.
 *
 * @example
 * // returns false
 * hasMinStepsBetweenValues([1,2,3], 2);
 *
 * @example
 * // returns true
 * hasMinStepsBetweenValues([1,2,3], 1);
 */
function hasMinStepsBetweenValues(values: number[], minStepsBetweenValues: number) {
  if (minStepsBetweenValues > 0) {
    const stepsBetweenValues = getStepsBetweenValues(values);
    const actualMinStepsBetweenValues = Math.min(...stepsBetweenValues);
    return actualMinStepsBetweenValues >= minStepsBetweenValues;
  }
  return true;
}

// https://github.com/tmcw-up-for-adoption/simple-linear-scale/blob/master/index.js
function linearScale(input: readonly [number, number], output: readonly [number, number]) {
  return (value: number) => {
    if (input[0] === input[1] || output[0] === output[1]) return output[0];
    const ratio = (output[1] - output[0]) / (input[1] - input[0]);
    return output[0] + ratio * (value - input[0]);
  };
}

function getDecimalCount(value: number) {
  return (String(value).split('.')[1] || '').length;
}

function roundValue(value: number, decimalCount: number) {
  const rounder = Math.pow(10, decimalCount);
  return Math.round(value * rounder) / rounder;
}

const Root = Slider;
const Track = SliderTrack;
const Range = SliderRange;
const Thumb = SliderThumb;

export {
  createSliderScope,
  //
  Slider,
  SliderTrack,
  SliderRange,
  SliderThumb,
  //
  Root,
  Track,
  Range,
  Thumb,
};
export type { SliderProps, SliderTrackProps, SliderRangeProps, SliderThumbProps };



================================================
FILE: packages/react/slot/README.md
================================================
# `react-slot`

View docs [here](https://radix-ui.com/primitives/docs/utilities/slot).



================================================
FILE: packages/react/slot/CHANGELOG.md
================================================
# @radix-ui/react-slot

## 1.2.4

- Fixed an issue with how slot components interact with lazy React components. In the case of a lazy component instance, the resulting promise must be consumed to render the desired component.

## 1.2.3

- Replace deprecated 'ElementRef' with 'ComponentRef' (#3426)
- Revert slot changes causing errors in server components

## 1.2.2

- Add `use client` to slot entry to prevent RSC errors

## 1.2.1

- Use stable composed refs in SlotClone ([#3477](https://github.com/radix-ui/primitives/pull/3477))



================================================
FILE: packages/react/slot/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/slot/package.json
================================================
{
  "name": "@radix-ui/react-slot",
  "version": "1.2.4",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/react-compose-refs": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/slot/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/slot/src/index.ts
================================================
export {
  Slot,
  Slottable,
  //
  Root,
  createSlot,
  createSlottable,
} from './slot';
export type { SlotProps } from './slot';



================================================
FILE: packages/react/slot/src/slot.test.tsx
================================================
import * as React from 'react';
import { cleanup, render, screen, fireEvent } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { Slot, Slottable } from './slot';
import { afterEach, describe, it, beforeEach, vi, expect } from 'vitest';

describe('given a slotted Trigger', () => {
  afterEach(cleanup);
  describe('with onClick on itself', () => {
    const handleClick = vi.fn();

    beforeEach(() => {
      handleClick.mockReset();
      render(
        <Trigger as={Slot} onClick={handleClick}>
          <button type="button">Click me</button>
        </Trigger>,
      );
      fireEvent.click(screen.getByRole('button'));
    });

    it('should call the onClick passed to the Trigger', async () => {
      expect(handleClick).toHaveBeenCalledTimes(1);
    });
  });

  describe('with onClick on the child', () => {
    const handleClick = vi.fn();

    beforeEach(() => {
      handleClick.mockReset();
      render(
        <Trigger as={Slot}>
          <button type="button" onClick={handleClick}>
            Click me
          </button>
        </Trigger>,
      );
      fireEvent.click(screen.getByRole('button'));
    });

    it("should call the child's onClick", async () => {
      expect(handleClick).toHaveBeenCalledTimes(1);
    });
  });

  describe('with onClick on itself AND the child', () => {
    const handleTriggerClick = vi.fn();
    const handleChildClick = vi.fn();

    beforeEach(() => {
      handleTriggerClick.mockReset();
      handleChildClick.mockReset();
      render(
        <Trigger as={Slot} onClick={handleTriggerClick}>
          <button type="button" onClick={handleChildClick}>
            Click me
          </button>
        </Trigger>,
      );
      fireEvent.click(screen.getByRole('button'));
    });

    it("should call the Trigger's onClick", async () => {
      expect(handleTriggerClick).toHaveBeenCalledTimes(1);
    });

    it("should call the child's onClick", async () => {
      expect(handleChildClick).toHaveBeenCalledTimes(1);
    });
  });

  describe('with onClick on itself AND undefined onClick on the child', () => {
    const handleTriggerClick = vi.fn();

    beforeEach(() => {
      handleTriggerClick.mockReset();
      render(
        <Trigger as={Slot} onClick={handleTriggerClick}>
          <button type="button" onClick={undefined}>
            Click me
          </button>
        </Trigger>,
      );
      fireEvent.click(screen.getByRole('button'));
    });

    it("should call the Trigger's onClick", async () => {
      expect(handleTriggerClick).toHaveBeenCalledTimes(1);
    });
  });

  describe('with undefined onClick on itself AND onClick on the child', () => {
    const handleChildClick = vi.fn();

    beforeEach(() => {
      handleChildClick.mockReset();
      render(
        <Trigger as={Slot} onClick={undefined}>
          <button type="button" onClick={handleChildClick}>
            Click me
          </button>
        </Trigger>,
      );
      fireEvent.click(screen.getByRole('button'));
    });

    it("should call the child's onClick", async () => {
      expect(handleChildClick).toHaveBeenCalledTimes(1);
    });
  });
});

describe('given a Button with Slottable', () => {
  afterEach(cleanup);
  describe('without asChild', () => {
    it('should render a button with icon on the left/right', async () => {
      const tree = render(
        <Button iconLeft={<span>left</span>} iconRight={<span>right</span>}>
          Button <em>text</em>
        </Button>,
      );

      expect(tree.container).toMatchSnapshot();
    });
  });

  describe('with asChild', () => {
    it('should render a link with icon on the left/right', async () => {
      const tree = render(
        <Button iconLeft={<span>left</span>} iconRight={<span>right</span>} asChild>
          <a href="https://radix-ui.com">
            Button <em>text</em>
          </a>
        </Button>,
      );

      expect(tree.container).toMatchSnapshot();
    });
  });
});

// TODO: Unskip when underlying issue is resolved
// Reverted in https://github.com/radix-ui/primitives/pull/3554
describe.skip('given an Input', () => {
  const handleRef = vi.fn();

  beforeEach(() => {
    handleRef.mockReset();
  });

  afterEach(cleanup);

  describe('without asChild', () => {
    it('should only call function refs once', async () => {
      render(<Input ref={handleRef} />);
      await userEvent.type(screen.getByRole('textbox'), 'foo');
      expect(handleRef).toHaveBeenCalledTimes(1);
    });
  });

  describe('with asChild', () => {
    it('should only call function refs once', async () => {
      render(
        <Input asChild ref={handleRef}>
          <input />
        </Input>,
      );
      await userEvent.type(screen.getByRole('textbox'), 'foo');
      expect(handleRef).toHaveBeenCalledTimes(1);
    });
  });
});

describe('given a Slot with React lazy components', () => {
  afterEach(cleanup);

  describe('with a lazy component as child', () => {
    const LazyButton = React.lazy(() =>
      Promise.resolve({
        default: ({ children, ...props }: React.ComponentProps<'button'>) => (
          <button {...props}>{children}</button>
        ),
      }),
    );

    it('should render the lazy component correctly', async () => {
      const handleClick = vi.fn();

      render(
        <React.Suspense fallback={<div>Loading...</div>}>
          <Slot onClick={handleClick}>
            <LazyButton>Click me</LazyButton>
          </Slot>
        </React.Suspense>,
      );

      // Wait for lazy component to load
      await screen.findByRole('button');

      fireEvent.click(screen.getByRole('button'));
      expect(handleClick).toHaveBeenCalledTimes(1);
    });
  });

  describe('with a lazy component in Button with Slottable', () => {
    const LazyLink = React.lazy(() =>
      Promise.resolve({
        default: ({ children, ...props }: React.ComponentProps<'a'>) => (
          <a {...props}>{children}</a>
        ),
      }),
    );

    it('should render a lazy link with icon on the left/right', async () => {
      const tree = render(
        <React.Suspense fallback={<div>Loading...</div>}>
          <Button iconLeft={<span>left</span>} iconRight={<span>right</span>} asChild>
            <LazyLink href="https://radix-ui.com">
              Button <em>text</em>
            </LazyLink>
          </Button>
        </React.Suspense>,
      );

      // Wait for lazy component to load
      await screen.findByRole('link');

      expect(tree.container).toMatchSnapshot();
    });
  });
});

type TriggerProps = React.ComponentProps<'button'> & { as: React.ElementType };

const Trigger = ({ as: Comp = 'button', ...props }: TriggerProps) => <Comp {...props} />;

const Button = React.forwardRef<
  React.ComponentRef<'button'>,
  React.ComponentProps<'button'> & {
    asChild?: boolean;
    iconLeft?: React.ReactNode;
    iconRight?: React.ReactNode;
  }
>(({ children, asChild = false, iconLeft, iconRight, ...props }, forwardedRef) => {
  const Comp = asChild ? Slot : 'button';
  return (
    <Comp {...props} ref={forwardedRef}>
      {iconLeft}
      <Slottable>{children}</Slottable>
      {iconRight}
    </Comp>
  );
});

const Input = React.forwardRef<
  React.ComponentRef<'input'>,
  React.ComponentProps<'input'> & {
    asChild?: boolean;
  }
>(({ asChild, children, ...props }, forwardedRef) => {
  const Comp = asChild ? Slot : 'input';
  const [value, setValue] = React.useState('');

  return (
    <Comp
      {...props}
      onChange={(event) => setValue(event.target.value)}
      ref={forwardedRef}
      value={value}
    >
      {children}
    </Comp>
  );
});



================================================
FILE: packages/react/slot/src/slot.tsx
================================================
import * as React from 'react';
import { composeRefs } from '@radix-ui/react-compose-refs';

declare module 'react' {
  interface ReactElement {
    $$typeof?: symbol | string;
  }
}

const REACT_LAZY_TYPE = Symbol.for('react.lazy');

interface LazyReactElement extends React.ReactElement {
  $$typeof: typeof REACT_LAZY_TYPE;
  _payload: PromiseLike<Exclude<React.ReactNode, PromiseLike<any>>>;
}

/* -------------------------------------------------------------------------------------------------
 * Slot
 * -----------------------------------------------------------------------------------------------*/

export type Usable<T> = PromiseLike<T> | React.Context<T>;
const use: typeof React.use | undefined = (React as any)[' use '.trim().toString()];

interface SlotProps extends React.HTMLAttributes<HTMLElement> {
  children?: React.ReactNode;
}

function isPromiseLike(value: unknown): value is PromiseLike<unknown> {
  return typeof value === 'object' && value !== null && 'then' in value;
}

function isLazyComponent(element: React.ReactNode): element is LazyReactElement {
  return (
    element != null &&
    typeof element === 'object' &&
    '$$typeof' in element &&
    element.$$typeof === REACT_LAZY_TYPE &&
    '_payload' in element &&
    isPromiseLike(element._payload)
  );
}

/* @__NO_SIDE_EFFECTS__ */ export function createSlot(ownerName: string) {
  const SlotClone = createSlotClone(ownerName);
  const Slot = React.forwardRef<HTMLElement, SlotProps>((props, forwardedRef) => {
    let { children, ...slotProps } = props;
    if (isLazyComponent(children) && typeof use === 'function') {
      children = use(children._payload);
    }
    const childrenArray = React.Children.toArray(children);
    const slottable = childrenArray.find(isSlottable);

    if (slottable) {
      // the new element to render is the one passed as a child of `Slottable`
      const newElement = slottable.props.children;

      const newChildren = childrenArray.map((child) => {
        if (child === slottable) {
          // because the new element will be the one rendered, we are only interested
          // in grabbing its children (`newElement.props.children`)
          if (React.Children.count(newElement) > 1) return React.Children.only(null);
          return React.isValidElement(newElement)
            ? (newElement.props as { children: React.ReactNode }).children
            : null;
        } else {
          return child;
        }
      });

      return (
        <SlotClone {...slotProps} ref={forwardedRef}>
          {React.isValidElement(newElement)
            ? React.cloneElement(newElement, undefined, newChildren)
            : null}
        </SlotClone>
      );
    }

    return (
      <SlotClone {...slotProps} ref={forwardedRef}>
        {children}
      </SlotClone>
    );
  });

  Slot.displayName = `${ownerName}.Slot`;
  return Slot;
}

const Slot = createSlot('Slot');

/* -------------------------------------------------------------------------------------------------
 * SlotClone
 * -----------------------------------------------------------------------------------------------*/

interface SlotCloneProps {
  children: React.ReactNode;
}

/* @__NO_SIDE_EFFECTS__ */ function createSlotClone(ownerName: string) {
  const SlotClone = React.forwardRef<any, SlotCloneProps>((props, forwardedRef) => {
    let { children, ...slotProps } = props;
    if (isLazyComponent(children) && typeof use === 'function') {
      children = use(children._payload);
    }

    if (React.isValidElement(children)) {
      const childrenRef = getElementRef(children);
      const props = mergeProps(slotProps, children.props as AnyProps);
      // do not pass ref to React.Fragment for React 19 compatibility
      if (children.type !== React.Fragment) {
        props.ref = forwardedRef ? composeRefs(forwardedRef, childrenRef) : childrenRef;
      }
      return React.cloneElement(children, props);
    }

    return React.Children.count(children) > 1 ? React.Children.only(null) : null;
  });

  SlotClone.displayName = `${ownerName}.SlotClone`;
  return SlotClone;
}

/* -------------------------------------------------------------------------------------------------
 * Slottable
 * -----------------------------------------------------------------------------------------------*/

const SLOTTABLE_IDENTIFIER = Symbol('radix.slottable');

interface SlottableProps {
  children: React.ReactNode;
}

interface SlottableComponent extends React.FC<SlottableProps> {
  __radixId: symbol;
}

/* @__NO_SIDE_EFFECTS__ */ export function createSlottable(ownerName: string) {
  const Slottable: SlottableComponent = ({ children }) => {
    return <>{children}</>;
  };
  Slottable.displayName = `${ownerName}.Slottable`;
  Slottable.__radixId = SLOTTABLE_IDENTIFIER;
  return Slottable;
}

const Slottable = createSlottable('Slottable');

/* ---------------------------------------------------------------------------------------------- */

type AnyProps = Record<string, any>;

function isSlottable(
  child: React.ReactNode,
): child is React.ReactElement<SlottableProps, typeof Slottable> {
  return (
    React.isValidElement(child) &&
    typeof child.type === 'function' &&
    '__radixId' in child.type &&
    child.type.__radixId === SLOTTABLE_IDENTIFIER
  );
}

function mergeProps(slotProps: AnyProps, childProps: AnyProps) {
  // all child props should override
  const overrideProps = { ...childProps };

  for (const propName in childProps) {
    const slotPropValue = slotProps[propName];
    const childPropValue = childProps[propName];

    const isHandler = /^on[A-Z]/.test(propName);
    if (isHandler) {
      // if the handler exists on both, we compose them
      if (slotPropValue && childPropValue) {
        overrideProps[propName] = (...args: unknown[]) => {
          const result = childPropValue(...args);
          slotPropValue(...args);
          return result;
        };
      }
      // but if it exists only on the slot, we use only this one
      else if (slotPropValue) {
        overrideProps[propName] = slotPropValue;
      }
    }
    // if it's `style`, we merge them
    else if (propName === 'style') {
      overrideProps[propName] = { ...slotPropValue, ...childPropValue };
    } else if (propName === 'className') {
      overrideProps[propName] = [slotPropValue, childPropValue].filter(Boolean).join(' ');
    }
  }

  return { ...slotProps, ...overrideProps };
}

// Before React 19 accessing `element.props.ref` will throw a warning and suggest using `element.ref`
// After React 19 accessing `element.ref` does the opposite.
// https://github.com/facebook/react/pull/28348
//
// Access the ref using the method that doesn't yield a warning.
function getElementRef(element: React.ReactElement) {
  // React <=18 in DEV
  let getter = Object.getOwnPropertyDescriptor(element.props, 'ref')?.get;
  let mayWarn = getter && 'isReactWarning' in getter && getter.isReactWarning;
  if (mayWarn) {
    return (element as any).ref;
  }

  // React 19 in DEV
  getter = Object.getOwnPropertyDescriptor(element, 'ref')?.get;
  mayWarn = getter && 'isReactWarning' in getter && getter.isReactWarning;
  if (mayWarn) {
    return (element.props as { ref?: React.Ref<unknown> }).ref;
  }

  // Not DEV
  return (element.props as { ref?: React.Ref<unknown> }).ref || (element as any).ref;
}

export {
  Slot,
  Slottable,
  //
  Slot as Root,
};
export type { SlotProps };



================================================
FILE: packages/react/slot/src/__snapshots__/slot.test.tsx.snap
================================================
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`given a Button with Slottable > with asChild > should render a link with icon on the left/right 1`] = `
<div>
  <a
    href="https://radix-ui.com"
  >
    <span>
      left
    </span>
    Button 
    <em>
      text
    </em>
    <span>
      right
    </span>
  </a>
</div>
`;

exports[`given a Button with Slottable > without asChild > should render a button with icon on the left/right 1`] = `
<div>
  <button>
    <span>
      left
    </span>
    Button 
    <em>
      text
    </em>
    <span>
      right
    </span>
  </button>
</div>
`;

exports[`given a Slot with React lazy components > with a lazy component in Button with Slottable > should render a lazy link with icon on the left/right 1`] = `
<div>
  <a
    href="https://radix-ui.com"
  >
    <span>
      left
    </span>
    Button 
    <em>
      text
    </em>
    <span>
      right
    </span>
  </a>
</div>
`;



================================================
FILE: packages/react/switch/README.md
================================================
# `react-switch`

View docs [here](https://radix-ui.com/primitives/docs/components/switch).



================================================
FILE: packages/react/switch/CHANGELOG.md
================================================
# @radix-ui/react-switch

## 1.2.6

- Updated dependencies: `@radix-ui/primitive@1.1.3`, `@radix-ui/react-context@1.1.3`, `@radix-ui/react-primitive@2.1.4`

## 1.2.5

- Replace deprecated 'ElementRef' with 'ComponentRef' (#3426)
- Updated dependencies: `@radix-ui/react-primitive@2.1.3`

## 1.2.4

- Updated dependencies: `@radix-ui/react-primitive@2.1.2`

## 1.2.3

- Updated dependencies: `@radix-ui/react-primitive@2.1.1`

## 1.2.2

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.2`

## 1.2.1

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.1`

## 1.2.0

- All form controls with internal bubble inputs now use the Radix `Primitive` component by default. This will allow us to expose these components directly so users can better control this behavior in the future.
- Minor improvements to `useControllableState` to enhance performance, reduce surface area for bugs, and log warnings when misused (#3455)
- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.0`, `@radix-ui/react-primitive@2.1.0`



================================================
FILE: packages/react/switch/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/switch/package.json
================================================
{
  "name": "@radix-ui/react-switch",
  "version": "1.2.6",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/primitive": "workspace:*",
    "@radix-ui/react-compose-refs": "workspace:*",
    "@radix-ui/react-context": "workspace:*",
    "@radix-ui/react-primitive": "workspace:*",
    "@radix-ui/react-use-controllable-state": "workspace:*",
    "@radix-ui/react-use-previous": "workspace:*",
    "@radix-ui/react-use-size": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/switch/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/switch/src/index.ts
================================================
'use client';
export {
  createSwitchScope,
  //
  Switch,
  SwitchThumb,
  //
  Root,
  Thumb,
} from './switch';
export type { SwitchProps, SwitchThumbProps } from './switch';



================================================
FILE: packages/react/switch/src/switch.test.tsx
================================================
import * as Switch from './switch';
import { cleanup, render } from '@testing-library/react';
import { afterEach, describe, it, expect } from 'vitest';

describe('given a default Switch', () => {
  afterEach(cleanup);

  let cleanedUp = false;

  function Test() {
    return (
      <Switch.Root
        ref={() => () => {
          cleanedUp = true;
        }}
      >
        <Switch.Thumb />
      </Switch.Root>
    );
  }

  it('should correctly invoke the cleanup function of a ref callback', () => {
    const rendered = render(<Test />);
    rendered.unmount();
    expect(cleanedUp).toBe(true);
  });
});



================================================
FILE: packages/react/switch/src/switch.tsx
================================================
import * as React from 'react';
import { composeEventHandlers } from '@radix-ui/primitive';
import { useComposedRefs } from '@radix-ui/react-compose-refs';
import { createContextScope } from '@radix-ui/react-context';
import { useControllableState } from '@radix-ui/react-use-controllable-state';
import { usePrevious } from '@radix-ui/react-use-previous';
import { useSize } from '@radix-ui/react-use-size';
import { Primitive } from '@radix-ui/react-primitive';

import type { Scope } from '@radix-ui/react-context';

/* -------------------------------------------------------------------------------------------------
 * Switch
 * -----------------------------------------------------------------------------------------------*/

const SWITCH_NAME = 'Switch';

type ScopedProps<P> = P & { __scopeSwitch?: Scope };
const [createSwitchContext, createSwitchScope] = createContextScope(SWITCH_NAME);

type SwitchContextValue = { checked: boolean; disabled?: boolean };
const [SwitchProvider, useSwitchContext] = createSwitchContext<SwitchContextValue>(SWITCH_NAME);

type SwitchElement = React.ComponentRef<typeof Primitive.button>;
type PrimitiveButtonProps = React.ComponentPropsWithoutRef<typeof Primitive.button>;
interface SwitchProps extends PrimitiveButtonProps {
  checked?: boolean;
  defaultChecked?: boolean;
  required?: boolean;
  onCheckedChange?(checked: boolean): void;
}

const Switch = React.forwardRef<SwitchElement, SwitchProps>(
  (props: ScopedProps<SwitchProps>, forwardedRef) => {
    const {
      __scopeSwitch,
      name,
      checked: checkedProp,
      defaultChecked,
      required,
      disabled,
      value = 'on',
      onCheckedChange,
      form,
      ...switchProps
    } = props;
    const [button, setButton] = React.useState<HTMLButtonElement | null>(null);
    const composedRefs = useComposedRefs(forwardedRef, (node) => setButton(node));
    const hasConsumerStoppedPropagationRef = React.useRef(false);
    // We set this to true by default so that events bubble to forms without JS (SSR)
    const isFormControl = button ? form || !!button.closest('form') : true;
    const [checked, setChecked] = useControllableState({
      prop: checkedProp,
      defaultProp: defaultChecked ?? false,
      onChange: onCheckedChange,
      caller: SWITCH_NAME,
    });

    return (
      <SwitchProvider scope={__scopeSwitch} checked={checked} disabled={disabled}>
        <Primitive.button
          type="button"
          role="switch"
          aria-checked={checked}
          aria-required={required}
          data-state={getState(checked)}
          data-disabled={disabled ? '' : undefined}
          disabled={disabled}
          value={value}
          {...switchProps}
          ref={composedRefs}
          onClick={composeEventHandlers(props.onClick, (event) => {
            setChecked((prevChecked) => !prevChecked);
            if (isFormControl) {
              hasConsumerStoppedPropagationRef.current = event.isPropagationStopped();
              // if switch is in a form, stop propagation from the button so that we only propagate
              // one click event (from the input). We propagate changes from an input so that native
              // form validation works and form events reflect switch updates.
              if (!hasConsumerStoppedPropagationRef.current) event.stopPropagation();
            }
          })}
        />
        {isFormControl && (
          <SwitchBubbleInput
            control={button}
            bubbles={!hasConsumerStoppedPropagationRef.current}
            name={name}
            value={value}
            checked={checked}
            required={required}
            disabled={disabled}
            form={form}
            // We transform because the input is absolutely positioned but we have
            // rendered it **after** the button. This pulls it back to sit on top
            // of the button.
            style={{ transform: 'translateX(-100%)' }}
          />
        )}
      </SwitchProvider>
    );
  },
);

Switch.displayName = SWITCH_NAME;

/* -------------------------------------------------------------------------------------------------
 * SwitchThumb
 * -----------------------------------------------------------------------------------------------*/

const THUMB_NAME = 'SwitchThumb';

type SwitchThumbElement = React.ComponentRef<typeof Primitive.span>;
type PrimitiveSpanProps = React.ComponentPropsWithoutRef<typeof Primitive.span>;
interface SwitchThumbProps extends PrimitiveSpanProps {}

const SwitchThumb = React.forwardRef<SwitchThumbElement, SwitchThumbProps>(
  (props: ScopedProps<SwitchThumbProps>, forwardedRef) => {
    const { __scopeSwitch, ...thumbProps } = props;
    const context = useSwitchContext(THUMB_NAME, __scopeSwitch);
    return (
      <Primitive.span
        data-state={getState(context.checked)}
        data-disabled={context.disabled ? '' : undefined}
        {...thumbProps}
        ref={forwardedRef}
      />
    );
  },
);

SwitchThumb.displayName = THUMB_NAME;

/* -------------------------------------------------------------------------------------------------
 * SwitchBubbleInput
 * -----------------------------------------------------------------------------------------------*/

const BUBBLE_INPUT_NAME = 'SwitchBubbleInput';

type InputProps = React.ComponentPropsWithoutRef<typeof Primitive.input>;
interface SwitchBubbleInputProps extends Omit<InputProps, 'checked'> {
  checked: boolean;
  control: HTMLElement | null;
  bubbles: boolean;
}

const SwitchBubbleInput = React.forwardRef<HTMLInputElement, SwitchBubbleInputProps>(
  (
    {
      __scopeSwitch,
      control,
      checked,
      bubbles = true,
      ...props
    }: ScopedProps<SwitchBubbleInputProps>,
    forwardedRef,
  ) => {
    const ref = React.useRef<HTMLInputElement>(null);
    const composedRefs = useComposedRefs(ref, forwardedRef);
    const prevChecked = usePrevious(checked);
    const controlSize = useSize(control);

    // Bubble checked change to parents (e.g form change event)
    React.useEffect(() => {
      const input = ref.current;
      if (!input) return;

      const inputProto = window.HTMLInputElement.prototype;
      const descriptor = Object.getOwnPropertyDescriptor(
        inputProto,
        'checked',
      ) as PropertyDescriptor;
      const setChecked = descriptor.set;
      if (prevChecked !== checked && setChecked) {
        const event = new Event('click', { bubbles });
        setChecked.call(input, checked);
        input.dispatchEvent(event);
      }
    }, [prevChecked, checked, bubbles]);

    return (
      <input
        type="checkbox"
        aria-hidden
        defaultChecked={checked}
        {...props}
        tabIndex={-1}
        ref={composedRefs}
        style={{
          ...props.style,
          ...controlSize,
          position: 'absolute',
          pointerEvents: 'none',
          opacity: 0,
          margin: 0,
        }}
      />
    );
  },
);

SwitchBubbleInput.displayName = BUBBLE_INPUT_NAME;

/* -----------------------------------------------------------------------------------------------*/

function getState(checked: boolean) {
  return checked ? 'checked' : 'unchecked';
}

const Root = Switch;
const Thumb = SwitchThumb;

export {
  createSwitchScope,
  //
  Switch,
  SwitchThumb,
  //
  Root,
  Thumb,
};
export type { SwitchProps, SwitchThumbProps };



================================================
FILE: packages/react/tabs/README.md
================================================
# `react-tabs`

View docs [here](https://radix-ui.com/primitives/docs/components/tabs).



================================================
FILE: packages/react/tabs/CHANGELOG.md
================================================
# @radix-ui/react-tabs

## 1.1.13

- Updated dependencies: `@radix-ui/react-presence@1.1.5`, `@radix-ui/primitive@1.1.3`, `@radix-ui/react-context@1.1.3`, `@radix-ui/react-primitive@2.1.4`, `@radix-ui/react-roving-focus@1.1.11`

## 1.1.12

- Replace deprecated 'ElementRef' with 'ComponentRef' (#3426)
- Updated dependencies: `@radix-ui/react-roving-focus@1.1.10`, `@radix-ui/react-primitive@2.1.3`

## 1.1.11

- Updated dependencies: `@radix-ui/react-primitive@2.1.2`, `@radix-ui/react-roving-focus@1.1.9`

## 1.1.10

- Updated dependencies: `@radix-ui/react-primitive@2.1.1`, `@radix-ui/react-roving-focus@1.1.8`

## 1.1.9

- Updated dependencies: `@radix-ui/react-presence@1.1.4`

## 1.1.8

- Updated dependencies: `@radix-ui/react-roving-focus@1.1.7`

## 1.1.7

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.2`, `@radix-ui/react-roving-focus@1.1.6`

## 1.1.6

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.1`, `@radix-ui/react-roving-focus@1.1.5`

## 1.1.5

- Minor improvements to `useControllableState` to enhance performance, reduce surface area for bugs, and log warnings when misused (#3455)
- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.0`, `@radix-ui/react-roving-focus@1.1.4`, `@radix-ui/react-primitive@2.1.0`



================================================
FILE: packages/react/tabs/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/tabs/package.json
================================================
{
  "name": "@radix-ui/react-tabs",
  "version": "1.1.13",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/primitive": "workspace:*",
    "@radix-ui/react-context": "workspace:*",
    "@radix-ui/react-direction": "workspace:*",
    "@radix-ui/react-id": "workspace:*",
    "@radix-ui/react-presence": "workspace:*",
    "@radix-ui/react-primitive": "workspace:*",
    "@radix-ui/react-roving-focus": "workspace:*",
    "@radix-ui/react-use-controllable-state": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/tabs/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/tabs/src/index.ts
================================================
'use client';
export {
  createTabsScope,
  //
  Tabs,
  TabsList,
  TabsTrigger,
  TabsContent,
  //
  Root,
  List,
  Trigger,
  Content,
} from './tabs';
export type { TabsProps, TabsListProps, TabsTriggerProps, TabsContentProps } from './tabs';



================================================
FILE: packages/react/tabs/src/tabs.tsx
================================================
import * as React from 'react';
import { composeEventHandlers } from '@radix-ui/primitive';
import { createContextScope } from '@radix-ui/react-context';
import { createRovingFocusGroupScope } from '@radix-ui/react-roving-focus';
import { Presence } from '@radix-ui/react-presence';
import { Primitive } from '@radix-ui/react-primitive';
import * as RovingFocusGroup from '@radix-ui/react-roving-focus';
import { useDirection } from '@radix-ui/react-direction';
import { useControllableState } from '@radix-ui/react-use-controllable-state';
import { useId } from '@radix-ui/react-id';

import type { Scope } from '@radix-ui/react-context';

/* -------------------------------------------------------------------------------------------------
 * Tabs
 * -----------------------------------------------------------------------------------------------*/

const TABS_NAME = 'Tabs';

type ScopedProps<P> = P & { __scopeTabs?: Scope };
const [createTabsContext, createTabsScope] = createContextScope(TABS_NAME, [
  createRovingFocusGroupScope,
]);
const useRovingFocusGroupScope = createRovingFocusGroupScope();

type TabsContextValue = {
  baseId: string;
  value: string;
  onValueChange: (value: string) => void;
  orientation?: TabsProps['orientation'];
  dir?: TabsProps['dir'];
  activationMode?: TabsProps['activationMode'];
};

const [TabsProvider, useTabsContext] = createTabsContext<TabsContextValue>(TABS_NAME);

type TabsElement = React.ComponentRef<typeof Primitive.div>;
type RovingFocusGroupProps = React.ComponentPropsWithoutRef<typeof RovingFocusGroup.Root>;
type PrimitiveDivProps = React.ComponentPropsWithoutRef<typeof Primitive.div>;
interface TabsProps extends PrimitiveDivProps {
  /** The value for the selected tab, if controlled */
  value?: string;
  /** The value of the tab to select by default, if uncontrolled */
  defaultValue?: string;
  /** A function called when a new tab is selected */
  onValueChange?: (value: string) => void;
  /**
   * The orientation the tabs are layed out.
   * Mainly so arrow navigation is done accordingly (left & right vs. up & down)
   * @defaultValue horizontal
   */
  orientation?: RovingFocusGroupProps['orientation'];
  /**
   * The direction of navigation between toolbar items.
   */
  dir?: RovingFocusGroupProps['dir'];
  /**
   * Whether a tab is activated automatically or manually.
   * @defaultValue automatic
   * */
  activationMode?: 'automatic' | 'manual';
}

const Tabs = React.forwardRef<TabsElement, TabsProps>(
  (props: ScopedProps<TabsProps>, forwardedRef) => {
    const {
      __scopeTabs,
      value: valueProp,
      onValueChange,
      defaultValue,
      orientation = 'horizontal',
      dir,
      activationMode = 'automatic',
      ...tabsProps
    } = props;
    const direction = useDirection(dir);
    const [value, setValue] = useControllableState({
      prop: valueProp,
      onChange: onValueChange,
      defaultProp: defaultValue ?? '',
      caller: TABS_NAME,
    });

    return (
      <TabsProvider
        scope={__scopeTabs}
        baseId={useId()}
        value={value}
        onValueChange={setValue}
        orientation={orientation}
        dir={direction}
        activationMode={activationMode}
      >
        <Primitive.div
          dir={direction}
          data-orientation={orientation}
          {...tabsProps}
          ref={forwardedRef}
        />
      </TabsProvider>
    );
  },
);

Tabs.displayName = TABS_NAME;

/* -------------------------------------------------------------------------------------------------
 * TabsList
 * -----------------------------------------------------------------------------------------------*/

const TAB_LIST_NAME = 'TabsList';

type TabsListElement = React.ComponentRef<typeof Primitive.div>;
interface TabsListProps extends PrimitiveDivProps {
  loop?: RovingFocusGroupProps['loop'];
}

const TabsList = React.forwardRef<TabsListElement, TabsListProps>(
  (props: ScopedProps<TabsListProps>, forwardedRef) => {
    const { __scopeTabs, loop = true, ...listProps } = props;
    const context = useTabsContext(TAB_LIST_NAME, __scopeTabs);
    const rovingFocusGroupScope = useRovingFocusGroupScope(__scopeTabs);
    return (
      <RovingFocusGroup.Root
        asChild
        {...rovingFocusGroupScope}
        orientation={context.orientation}
        dir={context.dir}
        loop={loop}
      >
        <Primitive.div
          role="tablist"
          aria-orientation={context.orientation}
          {...listProps}
          ref={forwardedRef}
        />
      </RovingFocusGroup.Root>
    );
  },
);

TabsList.displayName = TAB_LIST_NAME;

/* -------------------------------------------------------------------------------------------------
 * TabsTrigger
 * -----------------------------------------------------------------------------------------------*/

const TRIGGER_NAME = 'TabsTrigger';

type TabsTriggerElement = React.ComponentRef<typeof Primitive.button>;
type PrimitiveButtonProps = React.ComponentPropsWithoutRef<typeof Primitive.button>;
interface TabsTriggerProps extends PrimitiveButtonProps {
  value: string;
}

const TabsTrigger = React.forwardRef<TabsTriggerElement, TabsTriggerProps>(
  (props: ScopedProps<TabsTriggerProps>, forwardedRef) => {
    const { __scopeTabs, value, disabled = false, ...triggerProps } = props;
    const context = useTabsContext(TRIGGER_NAME, __scopeTabs);
    const rovingFocusGroupScope = useRovingFocusGroupScope(__scopeTabs);
    const triggerId = makeTriggerId(context.baseId, value);
    const contentId = makeContentId(context.baseId, value);
    const isSelected = value === context.value;
    return (
      <RovingFocusGroup.Item
        asChild
        {...rovingFocusGroupScope}
        focusable={!disabled}
        active={isSelected}
      >
        <Primitive.button
          type="button"
          role="tab"
          aria-selected={isSelected}
          aria-controls={contentId}
          data-state={isSelected ? 'active' : 'inactive'}
          data-disabled={disabled ? '' : undefined}
          disabled={disabled}
          id={triggerId}
          {...triggerProps}
          ref={forwardedRef}
          onMouseDown={composeEventHandlers(props.onMouseDown, (event) => {
            // only call handler if it's the left button (mousedown gets triggered by all mouse buttons)
            // but not when the control key is pressed (avoiding MacOS right click)
            if (!disabled && event.button === 0 && event.ctrlKey === false) {
              context.onValueChange(value);
            } else {
              // prevent focus to avoid accidental activation
              event.preventDefault();
            }
          })}
          onKeyDown={composeEventHandlers(props.onKeyDown, (event) => {
            if ([' ', 'Enter'].includes(event.key)) context.onValueChange(value);
          })}
          onFocus={composeEventHandlers(props.onFocus, () => {
            // handle "automatic" activation if necessary
            // ie. activate tab following focus
            const isAutomaticActivation = context.activationMode !== 'manual';
            if (!isSelected && !disabled && isAutomaticActivation) {
              context.onValueChange(value);
            }
          })}
        />
      </RovingFocusGroup.Item>
    );
  },
);

TabsTrigger.displayName = TRIGGER_NAME;

/* -------------------------------------------------------------------------------------------------
 * TabsContent
 * -----------------------------------------------------------------------------------------------*/

const CONTENT_NAME = 'TabsContent';

type TabsContentElement = React.ComponentRef<typeof Primitive.div>;
interface TabsContentProps extends PrimitiveDivProps {
  value: string;

  /**
   * Used to force mounting when more control is needed. Useful when
   * controlling animation with React animation libraries.
   */
  forceMount?: true;
}

const TabsContent = React.forwardRef<TabsContentElement, TabsContentProps>(
  (props: ScopedProps<TabsContentProps>, forwardedRef) => {
    const { __scopeTabs, value, forceMount, children, ...contentProps } = props;
    const context = useTabsContext(CONTENT_NAME, __scopeTabs);
    const triggerId = makeTriggerId(context.baseId, value);
    const contentId = makeContentId(context.baseId, value);
    const isSelected = value === context.value;
    const isMountAnimationPreventedRef = React.useRef(isSelected);

    React.useEffect(() => {
      const rAF = requestAnimationFrame(() => (isMountAnimationPreventedRef.current = false));
      return () => cancelAnimationFrame(rAF);
    }, []);

    return (
      <Presence present={forceMount || isSelected}>
        {({ present }) => (
          <Primitive.div
            data-state={isSelected ? 'active' : 'inactive'}
            data-orientation={context.orientation}
            role="tabpanel"
            aria-labelledby={triggerId}
            hidden={!present}
            id={contentId}
            tabIndex={0}
            {...contentProps}
            ref={forwardedRef}
            style={{
              ...props.style,
              animationDuration: isMountAnimationPreventedRef.current ? '0s' : undefined,
            }}
          >
            {present && children}
          </Primitive.div>
        )}
      </Presence>
    );
  },
);

TabsContent.displayName = CONTENT_NAME;

/* ---------------------------------------------------------------------------------------------- */

function makeTriggerId(baseId: string, value: string) {
  return `${baseId}-trigger-${value}`;
}

function makeContentId(baseId: string, value: string) {
  return `${baseId}-content-${value}`;
}

const Root = Tabs;
const List = TabsList;
const Trigger = TabsTrigger;
const Content = TabsContent;

export {
  createTabsScope,
  //
  Tabs,
  TabsList,
  TabsTrigger,
  TabsContent,
  //
  Root,
  List,
  Trigger,
  Content,
};
export type { TabsProps, TabsListProps, TabsTriggerProps, TabsContentProps };



================================================
FILE: packages/react/toast/README.md
================================================
# `react-toast`

View docs [here](https://radix-ui.com/primitives/docs/components/toast).



================================================
FILE: packages/react/toast/CHANGELOG.md
================================================
# @radix-ui/react-toast

## 1.2.15

### Fixed accessibility issues:

- Removed `aria-hidden` from the focusable element, as these elements are already empty and won't be read by screen readers
- Removed `role=status` from list item element (see [w3.org documentation for List Item](https://www.w3.org/TR/html-aria/#docconformance))
- Remove useless default `aria-atomic` from `role=status`

### Other updates

- Updated dependencies: `@radix-ui/react-presence@1.1.5`, `@radix-ui/primitive@1.1.3`, `@radix-ui/react-context@1.1.3`, `@radix-ui/react-collection@1.1.8`, `@radix-ui/react-primitive@2.1.4`, `@radix-ui/react-dismissable-layer@1.1.11`, `@radix-ui/react-portal@1.1.10`, `@radix-ui/react-visually-hidden@1.2.4`

## 1.2.14

- Replace deprecated 'ElementRef' with 'ComponentRef' (#3426)
- Updated dependencies: `@radix-ui/react-dismissable-layer@1.1.10`, `@radix-ui/react-visually-hidden@1.2.3`, `@radix-ui/react-portal@1.1.9`, `@radix-ui/react-collection@1.1.7`, `@radix-ui/react-primitive@2.1.3`

## 1.2.13

- Updated dependencies: `@radix-ui/react-collection@1.1.6`, `@radix-ui/react-primitive@2.1.2`, `@radix-ui/react-dismissable-layer@1.1.9`, `@radix-ui/react-portal@1.1.8`, `@radix-ui/react-visually-hidden@1.2.2`

## 1.2.12

- Updated dependencies: `@radix-ui/react-collection@1.1.5`, `@radix-ui/react-primitive@2.1.1`, `@radix-ui/react-dismissable-layer@1.1.8`, `@radix-ui/react-portal@1.1.7`, `@radix-ui/react-visually-hidden@1.2.1`

## 1.2.11

- Updated dependencies: `@radix-ui/react-presence@1.1.4`

## 1.2.10

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.2`

## 1.2.9

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.1`

## 1.2.8

- Minor improvements to `useControllableState` to enhance performance, reduce surface area for bugs, and log warnings when misused (#3455)
- Updated dependencies: `@radix-ui/react-collection@1.1.4`, `@radix-ui/react-use-controllable-state@1.2.0`, `@radix-ui/react-visually-hidden@1.2.0`, `@radix-ui/react-primitive@2.1.0`, `@radix-ui/react-dismissable-layer@1.1.7`, `@radix-ui/react-portal@1.1.6`



================================================
FILE: packages/react/toast/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/toast/package.json
================================================
{
  "name": "@radix-ui/react-toast",
  "version": "1.2.15",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/primitive": "workspace:*",
    "@radix-ui/react-collection": "workspace:*",
    "@radix-ui/react-compose-refs": "workspace:*",
    "@radix-ui/react-context": "workspace:*",
    "@radix-ui/react-dismissable-layer": "workspace:*",
    "@radix-ui/react-portal": "workspace:*",
    "@radix-ui/react-presence": "workspace:*",
    "@radix-ui/react-primitive": "workspace:*",
    "@radix-ui/react-use-callback-ref": "workspace:*",
    "@radix-ui/react-use-controllable-state": "workspace:*",
    "@radix-ui/react-use-layout-effect": "workspace:*",
    "@radix-ui/react-visually-hidden": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/toast/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/toast/src/index.ts
================================================
'use client';
export {
  createToastScope,
  //
  ToastProvider,
  ToastViewport,
  Toast,
  ToastTitle,
  ToastDescription,
  ToastAction,
  ToastClose,
  //
  Provider,
  Viewport,
  Root,
  Title,
  Description,
  Action,
  Close,
} from './toast';
export type {
  ToastProviderProps,
  ToastViewportProps,
  ToastProps,
  ToastTitleProps,
  ToastDescriptionProps,
  ToastActionProps,
  ToastCloseProps,
} from './toast';



================================================
FILE: packages/react/toast/src/toast.tsx
================================================
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { composeEventHandlers } from '@radix-ui/primitive';
import { useComposedRefs } from '@radix-ui/react-compose-refs';
import { createCollection } from '@radix-ui/react-collection';
import { createContextScope } from '@radix-ui/react-context';
import * as DismissableLayer from '@radix-ui/react-dismissable-layer';
import { Portal } from '@radix-ui/react-portal';
import { Presence } from '@radix-ui/react-presence';
import { Primitive, dispatchDiscreteCustomEvent } from '@radix-ui/react-primitive';
import { useCallbackRef } from '@radix-ui/react-use-callback-ref';
import { useControllableState } from '@radix-ui/react-use-controllable-state';
import { useLayoutEffect } from '@radix-ui/react-use-layout-effect';
import { VisuallyHidden } from '@radix-ui/react-visually-hidden';

import type { Scope } from '@radix-ui/react-context';

/* -------------------------------------------------------------------------------------------------
 * ToastProvider
 * -----------------------------------------------------------------------------------------------*/

const PROVIDER_NAME = 'ToastProvider';

const [Collection, useCollection, createCollectionScope] = createCollection<ToastElement>('Toast');

type SwipeDirection = 'up' | 'down' | 'left' | 'right';
type ToastProviderContextValue = {
  label: string;
  duration: number;
  swipeDirection: SwipeDirection;
  swipeThreshold: number;
  toastCount: number;
  viewport: ToastViewportElement | null;
  onViewportChange(viewport: ToastViewportElement): void;
  onToastAdd(): void;
  onToastRemove(): void;
  isFocusedToastEscapeKeyDownRef: React.MutableRefObject<boolean>;
  isClosePausedRef: React.MutableRefObject<boolean>;
};

type ScopedProps<P> = P & { __scopeToast?: Scope };
const [createToastContext, createToastScope] = createContextScope('Toast', [createCollectionScope]);
const [ToastProviderProvider, useToastProviderContext] =
  createToastContext<ToastProviderContextValue>(PROVIDER_NAME);

interface ToastProviderProps {
  children?: React.ReactNode;
  /**
   * An author-localized label for each toast. Used to help screen reader users
   * associate the interruption with a toast.
   * @defaultValue 'Notification'
   */
  label?: string;
  /**
   * Time in milliseconds that each toast should remain visible for.
   * @defaultValue 5000
   */
  duration?: number;
  /**
   * Direction of pointer swipe that should close the toast.
   * @defaultValue 'right'
   */
  swipeDirection?: SwipeDirection;
  /**
   * Distance in pixels that the swipe must pass before a close is triggered.
   * @defaultValue 50
   */
  swipeThreshold?: number;
}

const ToastProvider: React.FC<ToastProviderProps> = (props: ScopedProps<ToastProviderProps>) => {
  const {
    __scopeToast,
    label = 'Notification',
    duration = 5000,
    swipeDirection = 'right',
    swipeThreshold = 50,
    children,
  } = props;
  const [viewport, setViewport] = React.useState<ToastViewportElement | null>(null);
  const [toastCount, setToastCount] = React.useState(0);
  const isFocusedToastEscapeKeyDownRef = React.useRef(false);
  const isClosePausedRef = React.useRef(false);

  if (!label.trim()) {
    console.error(
      `Invalid prop \`label\` supplied to \`${PROVIDER_NAME}\`. Expected non-empty \`string\`.`,
    );
  }

  return (
    <Collection.Provider scope={__scopeToast}>
      <ToastProviderProvider
        scope={__scopeToast}
        label={label}
        duration={duration}
        swipeDirection={swipeDirection}
        swipeThreshold={swipeThreshold}
        toastCount={toastCount}
        viewport={viewport}
        onViewportChange={setViewport}
        onToastAdd={React.useCallback(() => setToastCount((prevCount) => prevCount + 1), [])}
        onToastRemove={React.useCallback(() => setToastCount((prevCount) => prevCount - 1), [])}
        isFocusedToastEscapeKeyDownRef={isFocusedToastEscapeKeyDownRef}
        isClosePausedRef={isClosePausedRef}
      >
        {children}
      </ToastProviderProvider>
    </Collection.Provider>
  );
};

ToastProvider.displayName = PROVIDER_NAME;

/* -------------------------------------------------------------------------------------------------
 * ToastViewport
 * -----------------------------------------------------------------------------------------------*/

const VIEWPORT_NAME = 'ToastViewport';
const VIEWPORT_DEFAULT_HOTKEY = ['F8'];
const VIEWPORT_PAUSE = 'toast.viewportPause';
const VIEWPORT_RESUME = 'toast.viewportResume';

type ToastViewportElement = React.ComponentRef<typeof Primitive.ol>;
type PrimitiveOrderedListProps = React.ComponentPropsWithoutRef<typeof Primitive.ol>;
interface ToastViewportProps extends PrimitiveOrderedListProps {
  /**
   * The keys to use as the keyboard shortcut that will move focus to the toast viewport.
   * @defaultValue ['F8']
   */
  hotkey?: string[];
  /**
   * An author-localized label for the toast viewport to provide context for screen reader users
   * when navigating page landmarks. The available `{hotkey}` placeholder will be replaced for you.
   * @defaultValue 'Notifications ({hotkey})'
   */
  label?: string;
}

const ToastViewport = React.forwardRef<ToastViewportElement, ToastViewportProps>(
  (props: ScopedProps<ToastViewportProps>, forwardedRef) => {
    const {
      __scopeToast,
      hotkey = VIEWPORT_DEFAULT_HOTKEY,
      label = 'Notifications ({hotkey})',
      ...viewportProps
    } = props;
    const context = useToastProviderContext(VIEWPORT_NAME, __scopeToast);
    const getItems = useCollection(__scopeToast);
    const wrapperRef = React.useRef<HTMLDivElement>(null);
    const headFocusProxyRef = React.useRef<FocusProxyElement>(null);
    const tailFocusProxyRef = React.useRef<FocusProxyElement>(null);
    const ref = React.useRef<ToastViewportElement>(null);
    const composedRefs = useComposedRefs(forwardedRef, ref, context.onViewportChange);
    const hotkeyLabel = hotkey.join('+').replace(/Key/g, '').replace(/Digit/g, '');
    const hasToasts = context.toastCount > 0;

    React.useEffect(() => {
      const handleKeyDown = (event: KeyboardEvent) => {
        // we use `event.code` as it is consistent regardless of meta keys that were pressed.
        // for example, `event.key` for `Control+Alt+t` is `†` and `t !== †`
        const isHotkeyPressed =
          hotkey.length !== 0 && hotkey.every((key) => (event as any)[key] || event.code === key);
        if (isHotkeyPressed) ref.current?.focus();
      };
      document.addEventListener('keydown', handleKeyDown);
      return () => document.removeEventListener('keydown', handleKeyDown);
    }, [hotkey]);

    React.useEffect(() => {
      const wrapper = wrapperRef.current;
      const viewport = ref.current;
      if (hasToasts && wrapper && viewport) {
        const handlePause = () => {
          if (!context.isClosePausedRef.current) {
            const pauseEvent = new CustomEvent(VIEWPORT_PAUSE);
            viewport.dispatchEvent(pauseEvent);
            context.isClosePausedRef.current = true;
          }
        };

        const handleResume = () => {
          if (context.isClosePausedRef.current) {
            const resumeEvent = new CustomEvent(VIEWPORT_RESUME);
            viewport.dispatchEvent(resumeEvent);
            context.isClosePausedRef.current = false;
          }
        };

        const handleFocusOutResume = (event: FocusEvent) => {
          const isFocusMovingOutside = !wrapper.contains(event.relatedTarget as HTMLElement);
          if (isFocusMovingOutside) handleResume();
        };

        const handlePointerLeaveResume = () => {
          const isFocusInside = wrapper.contains(document.activeElement);
          if (!isFocusInside) handleResume();
        };

        // Toasts are not in the viewport React tree so we need to bind DOM events
        wrapper.addEventListener('focusin', handlePause);
        wrapper.addEventListener('focusout', handleFocusOutResume);
        wrapper.addEventListener('pointermove', handlePause);
        wrapper.addEventListener('pointerleave', handlePointerLeaveResume);
        window.addEventListener('blur', handlePause);
        window.addEventListener('focus', handleResume);
        return () => {
          wrapper.removeEventListener('focusin', handlePause);
          wrapper.removeEventListener('focusout', handleFocusOutResume);
          wrapper.removeEventListener('pointermove', handlePause);
          wrapper.removeEventListener('pointerleave', handlePointerLeaveResume);
          window.removeEventListener('blur', handlePause);
          window.removeEventListener('focus', handleResume);
        };
      }
    }, [hasToasts, context.isClosePausedRef]);

    const getSortedTabbableCandidates = React.useCallback(
      ({ tabbingDirection }: { tabbingDirection: 'forwards' | 'backwards' }) => {
        const toastItems = getItems();
        const tabbableCandidates = toastItems.map((toastItem) => {
          const toastNode = toastItem.ref.current!;
          const toastTabbableCandidates = [toastNode, ...getTabbableCandidates(toastNode)];
          return tabbingDirection === 'forwards'
            ? toastTabbableCandidates
            : toastTabbableCandidates.reverse();
        });
        return (
          tabbingDirection === 'forwards' ? tabbableCandidates.reverse() : tabbableCandidates
        ).flat();
      },
      [getItems],
    );

    React.useEffect(() => {
      const viewport = ref.current;
      // We programmatically manage tabbing as we are unable to influence
      // the source order with portals, this allows us to reverse the
      // tab order so that it runs from most recent toast to least
      if (viewport) {
        const handleKeyDown = (event: KeyboardEvent) => {
          const isMetaKey = event.altKey || event.ctrlKey || event.metaKey;
          const isTabKey = event.key === 'Tab' && !isMetaKey;

          if (isTabKey) {
            const focusedElement = document.activeElement;
            const isTabbingBackwards = event.shiftKey;
            const targetIsViewport = event.target === viewport;

            // If we're back tabbing after jumping to the viewport then we simply
            // proxy focus out to the preceding document
            if (targetIsViewport && isTabbingBackwards) {
              headFocusProxyRef.current?.focus();
              return;
            }

            const tabbingDirection = isTabbingBackwards ? 'backwards' : 'forwards';
            const sortedCandidates = getSortedTabbableCandidates({ tabbingDirection });
            const index = sortedCandidates.findIndex((candidate) => candidate === focusedElement);
            if (focusFirst(sortedCandidates.slice(index + 1))) {
              event.preventDefault();
            } else {
              // If we can't focus that means we're at the edges so we
              // proxy to the corresponding exit point and let the browser handle
              // tab/shift+tab keypress and implicitly pass focus to the next valid element in the document
              isTabbingBackwards
                ? headFocusProxyRef.current?.focus()
                : tailFocusProxyRef.current?.focus();
            }
          }
        };

        // Toasts are not in the viewport React tree so we need to bind DOM events
        viewport.addEventListener('keydown', handleKeyDown);
        return () => viewport.removeEventListener('keydown', handleKeyDown);
      }
    }, [getItems, getSortedTabbableCandidates]);

    return (
      <DismissableLayer.Branch
        ref={wrapperRef}
        role="region"
        aria-label={label.replace('{hotkey}', hotkeyLabel)}
        // Ensure virtual cursor from landmarks menus triggers focus/blur for pause/resume
        tabIndex={-1}
        // incase list has size when empty (e.g. padding), we remove pointer events so
        // it doesn't prevent interactions with page elements that it overlays
        style={{ pointerEvents: hasToasts ? undefined : 'none' }}
      >
        {hasToasts && (
          <FocusProxy
            ref={headFocusProxyRef}
            onFocusFromOutsideViewport={() => {
              const tabbableCandidates = getSortedTabbableCandidates({
                tabbingDirection: 'forwards',
              });
              focusFirst(tabbableCandidates);
            }}
          />
        )}
        {/**
         * tabindex on the the list so that it can be focused when items are removed. we focus
         * the list instead of the viewport so it announces number of items remaining.
         */}
        <Collection.Slot scope={__scopeToast}>
          <Primitive.ol tabIndex={-1} {...viewportProps} ref={composedRefs} />
        </Collection.Slot>
        {hasToasts && (
          <FocusProxy
            ref={tailFocusProxyRef}
            onFocusFromOutsideViewport={() => {
              const tabbableCandidates = getSortedTabbableCandidates({
                tabbingDirection: 'backwards',
              });
              focusFirst(tabbableCandidates);
            }}
          />
        )}
      </DismissableLayer.Branch>
    );
  },
);

ToastViewport.displayName = VIEWPORT_NAME;

/* -----------------------------------------------------------------------------------------------*/

const FOCUS_PROXY_NAME = 'ToastFocusProxy';

type FocusProxyElement = React.ComponentRef<typeof VisuallyHidden>;
type VisuallyHiddenProps = React.ComponentPropsWithoutRef<typeof VisuallyHidden>;
interface FocusProxyProps extends VisuallyHiddenProps {
  onFocusFromOutsideViewport(): void;
}

const FocusProxy = React.forwardRef<FocusProxyElement, ScopedProps<FocusProxyProps>>(
  (props, forwardedRef) => {
    const { __scopeToast, onFocusFromOutsideViewport, ...proxyProps } = props;
    const context = useToastProviderContext(FOCUS_PROXY_NAME, __scopeToast);

    return (
      <VisuallyHidden
        tabIndex={0}
        {...proxyProps}
        ref={forwardedRef}
        // Avoid page scrolling when focus is on the focus proxy
        style={{ position: 'fixed' }}
        onFocus={(event) => {
          const prevFocusedElement = event.relatedTarget as HTMLElement | null;
          const isFocusFromOutsideViewport = !context.viewport?.contains(prevFocusedElement);
          if (isFocusFromOutsideViewport) onFocusFromOutsideViewport();
        }}
      />
    );
  },
);

FocusProxy.displayName = FOCUS_PROXY_NAME;

/* -------------------------------------------------------------------------------------------------
 * Toast
 * -----------------------------------------------------------------------------------------------*/

const TOAST_NAME = 'Toast';
const TOAST_SWIPE_START = 'toast.swipeStart';
const TOAST_SWIPE_MOVE = 'toast.swipeMove';
const TOAST_SWIPE_CANCEL = 'toast.swipeCancel';
const TOAST_SWIPE_END = 'toast.swipeEnd';

type ToastElement = ToastImplElement;
interface ToastProps extends Omit<ToastImplProps, keyof ToastImplPrivateProps> {
  open?: boolean;
  defaultOpen?: boolean;
  onOpenChange?(open: boolean): void;
  /**
   * Used to force mounting when more control is needed. Useful when
   * controlling animation with React animation libraries.
   */
  forceMount?: true;
}

const Toast = React.forwardRef<ToastElement, ToastProps>(
  (props: ScopedProps<ToastProps>, forwardedRef) => {
    const { forceMount, open: openProp, defaultOpen, onOpenChange, ...toastProps } = props;
    const [open, setOpen] = useControllableState({
      prop: openProp,
      defaultProp: defaultOpen ?? true,
      onChange: onOpenChange,
      caller: TOAST_NAME,
    });
    return (
      <Presence present={forceMount || open}>
        <ToastImpl
          open={open}
          {...toastProps}
          ref={forwardedRef}
          onClose={() => setOpen(false)}
          onPause={useCallbackRef(props.onPause)}
          onResume={useCallbackRef(props.onResume)}
          onSwipeStart={composeEventHandlers(props.onSwipeStart, (event) => {
            event.currentTarget.setAttribute('data-swipe', 'start');
          })}
          onSwipeMove={composeEventHandlers(props.onSwipeMove, (event) => {
            const { x, y } = event.detail.delta;
            event.currentTarget.setAttribute('data-swipe', 'move');
            event.currentTarget.style.setProperty('--radix-toast-swipe-move-x', `${x}px`);
            event.currentTarget.style.setProperty('--radix-toast-swipe-move-y', `${y}px`);
          })}
          onSwipeCancel={composeEventHandlers(props.onSwipeCancel, (event) => {
            event.currentTarget.setAttribute('data-swipe', 'cancel');
            event.currentTarget.style.removeProperty('--radix-toast-swipe-move-x');
            event.currentTarget.style.removeProperty('--radix-toast-swipe-move-y');
            event.currentTarget.style.removeProperty('--radix-toast-swipe-end-x');
            event.currentTarget.style.removeProperty('--radix-toast-swipe-end-y');
          })}
          onSwipeEnd={composeEventHandlers(props.onSwipeEnd, (event) => {
            const { x, y } = event.detail.delta;
            event.currentTarget.setAttribute('data-swipe', 'end');
            event.currentTarget.style.removeProperty('--radix-toast-swipe-move-x');
            event.currentTarget.style.removeProperty('--radix-toast-swipe-move-y');
            event.currentTarget.style.setProperty('--radix-toast-swipe-end-x', `${x}px`);
            event.currentTarget.style.setProperty('--radix-toast-swipe-end-y', `${y}px`);
            setOpen(false);
          })}
        />
      </Presence>
    );
  },
);

Toast.displayName = TOAST_NAME;

/* -----------------------------------------------------------------------------------------------*/

type SwipeEvent = { currentTarget: EventTarget & ToastElement } & Omit<
  CustomEvent<{ originalEvent: React.PointerEvent; delta: { x: number; y: number } }>,
  'currentTarget'
>;

const [ToastInteractiveProvider, useToastInteractiveContext] = createToastContext(TOAST_NAME, {
  onClose() {},
});

type ToastImplElement = React.ComponentRef<typeof Primitive.li>;
type DismissableLayerProps = React.ComponentPropsWithoutRef<typeof DismissableLayer.Root>;
type ToastImplPrivateProps = { open: boolean; onClose(): void };
type PrimitiveListItemProps = React.ComponentPropsWithoutRef<typeof Primitive.li>;
interface ToastImplProps extends ToastImplPrivateProps, PrimitiveListItemProps {
  type?: 'foreground' | 'background';
  /**
   * Time in milliseconds that toast should remain visible for. Overrides value
   * given to `ToastProvider`.
   */
  duration?: number;
  onEscapeKeyDown?: DismissableLayerProps['onEscapeKeyDown'];
  onPause?(): void;
  onResume?(): void;
  onSwipeStart?(event: SwipeEvent): void;
  onSwipeMove?(event: SwipeEvent): void;
  onSwipeCancel?(event: SwipeEvent): void;
  onSwipeEnd?(event: SwipeEvent): void;
}

const ToastImpl = React.forwardRef<ToastImplElement, ToastImplProps>(
  (props: ScopedProps<ToastImplProps>, forwardedRef) => {
    const {
      __scopeToast,
      type = 'foreground',
      duration: durationProp,
      open,
      onClose,
      onEscapeKeyDown,
      onPause,
      onResume,
      onSwipeStart,
      onSwipeMove,
      onSwipeCancel,
      onSwipeEnd,
      ...toastProps
    } = props;
    const context = useToastProviderContext(TOAST_NAME, __scopeToast);
    const [node, setNode] = React.useState<ToastImplElement | null>(null);
    const composedRefs = useComposedRefs(forwardedRef, (node) => setNode(node));
    const pointerStartRef = React.useRef<{ x: number; y: number } | null>(null);
    const swipeDeltaRef = React.useRef<{ x: number; y: number } | null>(null);
    const duration = durationProp || context.duration;
    const closeTimerStartTimeRef = React.useRef(0);
    const closeTimerRemainingTimeRef = React.useRef(duration);
    const closeTimerRef = React.useRef(0);
    const { onToastAdd, onToastRemove } = context;
    const handleClose = useCallbackRef(() => {
      // focus viewport if focus is within toast to read the remaining toast
      // count to SR users and ensure focus isn't lost
      const isFocusInToast = node?.contains(document.activeElement);
      if (isFocusInToast) context.viewport?.focus();
      onClose();
    });

    const startTimer = React.useCallback(
      (duration: number) => {
        if (!duration || duration === Infinity) return;
        window.clearTimeout(closeTimerRef.current);
        closeTimerStartTimeRef.current = new Date().getTime();
        closeTimerRef.current = window.setTimeout(handleClose, duration);
      },
      [handleClose],
    );

    React.useEffect(() => {
      const viewport = context.viewport;
      if (viewport) {
        const handleResume = () => {
          startTimer(closeTimerRemainingTimeRef.current);
          onResume?.();
        };
        const handlePause = () => {
          const elapsedTime = new Date().getTime() - closeTimerStartTimeRef.current;
          closeTimerRemainingTimeRef.current = closeTimerRemainingTimeRef.current - elapsedTime;
          window.clearTimeout(closeTimerRef.current);
          onPause?.();
        };
        viewport.addEventListener(VIEWPORT_PAUSE, handlePause);
        viewport.addEventListener(VIEWPORT_RESUME, handleResume);
        return () => {
          viewport.removeEventListener(VIEWPORT_PAUSE, handlePause);
          viewport.removeEventListener(VIEWPORT_RESUME, handleResume);
        };
      }
    }, [context.viewport, duration, onPause, onResume, startTimer]);

    // start timer when toast opens or duration changes.
    // we include `open` in deps because closed !== unmounted when animating
    // so it could reopen before being completely unmounted
    React.useEffect(() => {
      if (open && !context.isClosePausedRef.current) startTimer(duration);
    }, [open, duration, context.isClosePausedRef, startTimer]);

    React.useEffect(() => {
      onToastAdd();
      return () => onToastRemove();
    }, [onToastAdd, onToastRemove]);

    const announceTextContent = React.useMemo(() => {
      return node ? getAnnounceTextContent(node) : null;
    }, [node]);

    if (!context.viewport) return null;

    return (
      <>
        {announceTextContent && (
          <ToastAnnounce
            __scopeToast={__scopeToast}
            // Toasts are always role=status to avoid stuttering issues with role=alert in SRs.
            role="status"
            aria-live={type === 'foreground' ? 'assertive' : 'polite'}
          >
            {announceTextContent}
          </ToastAnnounce>
        )}

        <ToastInteractiveProvider scope={__scopeToast} onClose={handleClose}>
          {ReactDOM.createPortal(
            <Collection.ItemSlot scope={__scopeToast}>
              <DismissableLayer.Root
                asChild
                onEscapeKeyDown={composeEventHandlers(onEscapeKeyDown, () => {
                  if (!context.isFocusedToastEscapeKeyDownRef.current) handleClose();
                  context.isFocusedToastEscapeKeyDownRef.current = false;
                })}
              >
                <Primitive.li
                  tabIndex={0}
                  data-state={open ? 'open' : 'closed'}
                  data-swipe-direction={context.swipeDirection}
                  {...toastProps}
                  ref={composedRefs}
                  style={{ userSelect: 'none', touchAction: 'none', ...props.style }}
                  onKeyDown={composeEventHandlers(props.onKeyDown, (event) => {
                    if (event.key !== 'Escape') return;
                    onEscapeKeyDown?.(event.nativeEvent);
                    if (!event.nativeEvent.defaultPrevented) {
                      context.isFocusedToastEscapeKeyDownRef.current = true;
                      handleClose();
                    }
                  })}
                  onPointerDown={composeEventHandlers(props.onPointerDown, (event) => {
                    if (event.button !== 0) return;
                    pointerStartRef.current = { x: event.clientX, y: event.clientY };
                  })}
                  onPointerMove={composeEventHandlers(props.onPointerMove, (event) => {
                    if (!pointerStartRef.current) return;
                    const x = event.clientX - pointerStartRef.current.x;
                    const y = event.clientY - pointerStartRef.current.y;
                    const hasSwipeMoveStarted = Boolean(swipeDeltaRef.current);
                    const isHorizontalSwipe = ['left', 'right'].includes(context.swipeDirection);
                    const clamp = ['left', 'up'].includes(context.swipeDirection)
                      ? Math.min
                      : Math.max;
                    const clampedX = isHorizontalSwipe ? clamp(0, x) : 0;
                    const clampedY = !isHorizontalSwipe ? clamp(0, y) : 0;
                    const moveStartBuffer = event.pointerType === 'touch' ? 10 : 2;
                    const delta = { x: clampedX, y: clampedY };
                    const eventDetail = { originalEvent: event, delta };
                    if (hasSwipeMoveStarted) {
                      swipeDeltaRef.current = delta;
                      handleAndDispatchCustomEvent(TOAST_SWIPE_MOVE, onSwipeMove, eventDetail, {
                        discrete: false,
                      });
                    } else if (isDeltaInDirection(delta, context.swipeDirection, moveStartBuffer)) {
                      swipeDeltaRef.current = delta;
                      handleAndDispatchCustomEvent(TOAST_SWIPE_START, onSwipeStart, eventDetail, {
                        discrete: false,
                      });
                      (event.target as HTMLElement).setPointerCapture(event.pointerId);
                    } else if (Math.abs(x) > moveStartBuffer || Math.abs(y) > moveStartBuffer) {
                      // User is swiping in wrong direction so we disable swipe gesture
                      // for the current pointer down interaction
                      pointerStartRef.current = null;
                    }
                  })}
                  onPointerUp={composeEventHandlers(props.onPointerUp, (event) => {
                    const delta = swipeDeltaRef.current;
                    const target = event.target as HTMLElement;
                    if (target.hasPointerCapture(event.pointerId)) {
                      target.releasePointerCapture(event.pointerId);
                    }
                    swipeDeltaRef.current = null;
                    pointerStartRef.current = null;
                    if (delta) {
                      const toast = event.currentTarget;
                      const eventDetail = { originalEvent: event, delta };
                      if (
                        isDeltaInDirection(delta, context.swipeDirection, context.swipeThreshold)
                      ) {
                        handleAndDispatchCustomEvent(TOAST_SWIPE_END, onSwipeEnd, eventDetail, {
                          discrete: true,
                        });
                      } else {
                        handleAndDispatchCustomEvent(
                          TOAST_SWIPE_CANCEL,
                          onSwipeCancel,
                          eventDetail,
                          {
                            discrete: true,
                          },
                        );
                      }
                      // Prevent click event from triggering on items within the toast when
                      // pointer up is part of a swipe gesture
                      toast.addEventListener('click', (event) => event.preventDefault(), {
                        once: true,
                      });
                    }
                  })}
                />
              </DismissableLayer.Root>
            </Collection.ItemSlot>,
            context.viewport,
          )}
        </ToastInteractiveProvider>
      </>
    );
  },
);

/* -----------------------------------------------------------------------------------------------*/

interface ToastAnnounceProps
  extends Omit<React.ComponentPropsWithoutRef<'div'>, 'children'>,
    ScopedProps<{ children: string[] }> {}

const ToastAnnounce: React.FC<ToastAnnounceProps> = (props: ScopedProps<ToastAnnounceProps>) => {
  const { __scopeToast, children, ...announceProps } = props;
  const context = useToastProviderContext(TOAST_NAME, __scopeToast);
  const [renderAnnounceText, setRenderAnnounceText] = React.useState(false);
  const [isAnnounced, setIsAnnounced] = React.useState(false);

  // render text content in the next frame to ensure toast is announced in NVDA
  useNextFrame(() => setRenderAnnounceText(true));

  // cleanup after announcing
  React.useEffect(() => {
    const timer = window.setTimeout(() => setIsAnnounced(true), 1000);
    return () => window.clearTimeout(timer);
  }, []);

  return isAnnounced ? null : (
    <Portal asChild>
      <VisuallyHidden {...announceProps}>
        {renderAnnounceText && (
          <>
            {context.label} {children}
          </>
        )}
      </VisuallyHidden>
    </Portal>
  );
};

/* -------------------------------------------------------------------------------------------------
 * ToastTitle
 * -----------------------------------------------------------------------------------------------*/

const TITLE_NAME = 'ToastTitle';

type ToastTitleElement = React.ComponentRef<typeof Primitive.div>;
type PrimitiveDivProps = React.ComponentPropsWithoutRef<typeof Primitive.div>;
interface ToastTitleProps extends PrimitiveDivProps {}

const ToastTitle = React.forwardRef<ToastTitleElement, ToastTitleProps>(
  (props: ScopedProps<ToastTitleProps>, forwardedRef) => {
    const { __scopeToast, ...titleProps } = props;
    return <Primitive.div {...titleProps} ref={forwardedRef} />;
  },
);

ToastTitle.displayName = TITLE_NAME;

/* -------------------------------------------------------------------------------------------------
 * ToastDescription
 * -----------------------------------------------------------------------------------------------*/

const DESCRIPTION_NAME = 'ToastDescription';

type ToastDescriptionElement = React.ComponentRef<typeof Primitive.div>;
interface ToastDescriptionProps extends PrimitiveDivProps {}

const ToastDescription = React.forwardRef<ToastDescriptionElement, ToastDescriptionProps>(
  (props: ScopedProps<ToastDescriptionProps>, forwardedRef) => {
    const { __scopeToast, ...descriptionProps } = props;
    return <Primitive.div {...descriptionProps} ref={forwardedRef} />;
  },
);

ToastDescription.displayName = DESCRIPTION_NAME;

/* -------------------------------------------------------------------------------------------------
 * ToastAction
 * -----------------------------------------------------------------------------------------------*/

const ACTION_NAME = 'ToastAction';

type ToastActionElement = ToastCloseElement;
interface ToastActionProps extends ToastCloseProps {
  /**
   * A short description for an alternate way to carry out the action. For screen reader users
   * who will not be able to navigate to the button easily/quickly.
   * @example <ToastAction altText="Goto account settings to upgrade">Upgrade</ToastAction>
   * @example <ToastAction altText="Undo (Alt+U)">Undo</ToastAction>
   */
  altText: string;
}

const ToastAction = React.forwardRef<ToastActionElement, ToastActionProps>(
  (props: ScopedProps<ToastActionProps>, forwardedRef) => {
    const { altText, ...actionProps } = props;

    if (!altText.trim()) {
      console.error(
        `Invalid prop \`altText\` supplied to \`${ACTION_NAME}\`. Expected non-empty \`string\`.`,
      );
      return null;
    }

    return (
      <ToastAnnounceExclude altText={altText} asChild>
        <ToastClose {...actionProps} ref={forwardedRef} />
      </ToastAnnounceExclude>
    );
  },
);

ToastAction.displayName = ACTION_NAME;

/* -------------------------------------------------------------------------------------------------
 * ToastClose
 * -----------------------------------------------------------------------------------------------*/

const CLOSE_NAME = 'ToastClose';

type ToastCloseElement = React.ComponentRef<typeof Primitive.button>;
type PrimitiveButtonProps = React.ComponentPropsWithoutRef<typeof Primitive.button>;
interface ToastCloseProps extends PrimitiveButtonProps {}

const ToastClose = React.forwardRef<ToastCloseElement, ToastCloseProps>(
  (props: ScopedProps<ToastCloseProps>, forwardedRef) => {
    const { __scopeToast, ...closeProps } = props;
    const interactiveContext = useToastInteractiveContext(CLOSE_NAME, __scopeToast);

    return (
      <ToastAnnounceExclude asChild>
        <Primitive.button
          type="button"
          {...closeProps}
          ref={forwardedRef}
          onClick={composeEventHandlers(props.onClick, interactiveContext.onClose)}
        />
      </ToastAnnounceExclude>
    );
  },
);

ToastClose.displayName = CLOSE_NAME;

/* ---------------------------------------------------------------------------------------------- */

type ToastAnnounceExcludeElement = React.ComponentRef<typeof Primitive.div>;
interface ToastAnnounceExcludeProps extends PrimitiveDivProps {
  altText?: string;
}

const ToastAnnounceExclude = React.forwardRef<
  ToastAnnounceExcludeElement,
  ToastAnnounceExcludeProps
>((props: ScopedProps<ToastAnnounceExcludeProps>, forwardedRef) => {
  const { __scopeToast, altText, ...announceExcludeProps } = props;

  return (
    <Primitive.div
      data-radix-toast-announce-exclude=""
      data-radix-toast-announce-alt={altText || undefined}
      {...announceExcludeProps}
      ref={forwardedRef}
    />
  );
});

function getAnnounceTextContent(container: HTMLElement) {
  const textContent: string[] = [];
  const childNodes = Array.from(container.childNodes);

  childNodes.forEach((node) => {
    if (node.nodeType === node.TEXT_NODE && node.textContent) textContent.push(node.textContent);
    if (isHTMLElement(node)) {
      const isHidden = node.ariaHidden || node.hidden || node.style.display === 'none';
      const isExcluded = node.dataset.radixToastAnnounceExclude === '';

      if (!isHidden) {
        if (isExcluded) {
          const altText = node.dataset.radixToastAnnounceAlt;
          if (altText) textContent.push(altText);
        } else {
          textContent.push(...getAnnounceTextContent(node));
        }
      }
    }
  });

  // We return a collection of text rather than a single concatenated string.
  // This allows SR VO to naturally pause break between nodes while announcing.
  return textContent;
}

/* ---------------------------------------------------------------------------------------------- */

function handleAndDispatchCustomEvent<
  E extends CustomEvent,
  ReactEvent extends React.SyntheticEvent,
>(
  name: string,
  handler: ((event: E) => void) | undefined,
  detail: { originalEvent: ReactEvent } & (E extends CustomEvent<infer D> ? D : never),
  { discrete }: { discrete: boolean },
) {
  const currentTarget = detail.originalEvent.currentTarget as HTMLElement;
  const event = new CustomEvent(name, { bubbles: true, cancelable: true, detail });
  if (handler) currentTarget.addEventListener(name, handler as EventListener, { once: true });

  if (discrete) {
    dispatchDiscreteCustomEvent(currentTarget, event);
  } else {
    currentTarget.dispatchEvent(event);
  }
}

const isDeltaInDirection = (
  delta: { x: number; y: number },
  direction: SwipeDirection,
  threshold = 0,
) => {
  const deltaX = Math.abs(delta.x);
  const deltaY = Math.abs(delta.y);
  const isDeltaX = deltaX > deltaY;
  if (direction === 'left' || direction === 'right') {
    return isDeltaX && deltaX > threshold;
  } else {
    return !isDeltaX && deltaY > threshold;
  }
};

function useNextFrame(callback = () => {}) {
  const fn = useCallbackRef(callback);
  useLayoutEffect(() => {
    let raf1 = 0;
    let raf2 = 0;
    raf1 = window.requestAnimationFrame(() => (raf2 = window.requestAnimationFrame(fn)));
    return () => {
      window.cancelAnimationFrame(raf1);
      window.cancelAnimationFrame(raf2);
    };
  }, [fn]);
}

function isHTMLElement(node: any): node is HTMLElement {
  return node.nodeType === node.ELEMENT_NODE;
}

/**
 * Returns a list of potential tabbable candidates.
 *
 * NOTE: This is only a close approximation. For example it doesn't take into account cases like when
 * elements are not visible. This cannot be worked out easily by just reading a property, but rather
 * necessitate runtime knowledge (computed styles, etc). We deal with these cases separately.
 *
 * See: https://developer.mozilla.org/en-US/docs/Web/API/TreeWalker
 * Credit: https://github.com/discord/focus-layers/blob/master/src/util/wrapFocus.tsx#L1
 */
function getTabbableCandidates(container: HTMLElement) {
  const nodes: HTMLElement[] = [];
  const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, {
    acceptNode: (node: any) => {
      const isHiddenInput = node.tagName === 'INPUT' && node.type === 'hidden';
      if (node.disabled || node.hidden || isHiddenInput) return NodeFilter.FILTER_SKIP;
      // `.tabIndex` is not the same as the `tabindex` attribute. It works on the
      // runtime's understanding of tabbability, so this automatically accounts
      // for any kind of element that could be tabbed to.
      return node.tabIndex >= 0 ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
    },
  });
  while (walker.nextNode()) nodes.push(walker.currentNode as HTMLElement);
  // we do not take into account the order of nodes with positive `tabIndex` as it
  // hinders accessibility to have tab order different from visual order.
  return nodes;
}

function focusFirst(candidates: HTMLElement[]) {
  const previouslyFocusedElement = document.activeElement;
  return candidates.some((candidate) => {
    // if focus is already where we want to go, we don't want to keep going through the candidates
    if (candidate === previouslyFocusedElement) return true;
    candidate.focus();
    return document.activeElement !== previouslyFocusedElement;
  });
}

const Provider = ToastProvider;
const Viewport = ToastViewport;
const Root = Toast;
const Title = ToastTitle;
const Description = ToastDescription;
const Action = ToastAction;
const Close = ToastClose;

export {
  createToastScope,
  //
  ToastProvider,
  ToastViewport,
  Toast,
  ToastTitle,
  ToastDescription,
  ToastAction,
  ToastClose,
  //
  Provider,
  Viewport,
  Root,
  Title,
  Description,
  Action,
  Close,
};
export type {
  ToastProviderProps,
  ToastViewportProps,
  ToastProps,
  ToastTitleProps,
  ToastDescriptionProps,
  ToastActionProps,
  ToastCloseProps,
};



================================================
FILE: packages/react/toggle/README.md
================================================
# `react-toggle`

View docs [here](https://radix-ui.com/primitives/docs/components/toggle).



================================================
FILE: packages/react/toggle/CHANGELOG.md
================================================
# @radix-ui/react-toggle

## 1.1.10

- Updated dependencies: `@radix-ui/primitive@1.1.3`, `@radix-ui/react-primitive@2.1.4`

## 1.1.9

- Replace deprecated 'ElementRef' with 'ComponentRef' (#3426)
- Updated dependencies: `@radix-ui/react-primitive@2.1.3`

## 1.1.8

- Updated dependencies: `@radix-ui/react-primitive@2.1.2`

## 1.1.7

- Updated dependencies: `@radix-ui/react-primitive@2.1.1`

## 1.1.6

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.2`

## 1.1.5

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.1`

## 1.1.4

- Minor improvements to `useControllableState` to enhance performance, reduce surface area for bugs, and log warnings when misused (#3455)
- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.0`, `@radix-ui/react-primitive@2.1.0`



================================================
FILE: packages/react/toggle/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/toggle/package.json
================================================
{
  "name": "@radix-ui/react-toggle",
  "version": "1.1.10",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/primitive": "workspace:*",
    "@radix-ui/react-primitive": "workspace:*",
    "@radix-ui/react-use-controllable-state": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/toggle/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/toggle/src/index.ts
================================================
'use client';
export {
  Toggle,
  //
  Root,
} from './toggle';
export type { ToggleProps } from './toggle';



================================================
FILE: packages/react/toggle/src/toggle.test.tsx
================================================
import type { RenderResult } from '@testing-library/react';
import { cleanup, fireEvent, render } from '@testing-library/react';
import * as Toggle from './toggle';
import { axe } from 'vitest-axe';
import { afterEach, describe, it, beforeEach, vi, expect } from 'vitest';

const TEXT_CHILD = 'Like';

describe('given a Toggle with text', () => {
  let rendered: RenderResult;

  beforeEach(() => {
    rendered = render(<Toggle.Root>{TEXT_CHILD}</Toggle.Root>);
  });

  afterEach(cleanup);

  it('should have no accessibility violations', async () => {
    expect(await axe(rendered.container)).toHaveNoViolations();
  });

  it('should render with attributes as false/off by default', () => {
    const button = rendered.getByRole('button', { name: TEXT_CHILD });

    expect(button).toHaveAttribute('aria-pressed', 'false');
    expect(button).toHaveAttribute('data-state', 'off');
  });

  it('Click event should change pressed attributes to true/on', () => {
    const button = rendered.getByRole('button', { name: TEXT_CHILD });

    fireEvent(
      button,
      new MouseEvent('click', {
        bubbles: true,
        cancelable: true,
      }),
    );

    expect(button).toHaveAttribute('aria-pressed', 'true');
    expect(button).toHaveAttribute('data-state', 'on');
  });
});

describe('given a Toggle with text and defaultPressed="true"', () => {
  let rendered: RenderResult;

  beforeEach(() => {
    rendered = render(<Toggle.Root defaultPressed>{TEXT_CHILD}</Toggle.Root>);
  });

  afterEach(cleanup);

  it('should render with attributes true/on by default', () => {
    const button = rendered.getByRole('button', { name: TEXT_CHILD });

    expect(button).toHaveAttribute('aria-pressed', 'true');
    expect(button).toHaveAttribute('data-state', 'on');
  });

  it('Click event should change attributes back to off/false', () => {
    const button = rendered.getByRole('button', { name: TEXT_CHILD });

    fireEvent(
      button,
      new MouseEvent('click', {
        bubbles: true,
        cancelable: true,
      }),
    );

    expect(button).toHaveAttribute('aria-pressed', 'false');
    expect(button).toHaveAttribute('data-state', 'off');
  });
});

describe('given a Toggle with text and disabled="true"', () => {
  let rendered: RenderResult;

  beforeEach(() => {
    rendered = render(<Toggle.Root disabled>{TEXT_CHILD}</Toggle.Root>);
  });

  afterEach(cleanup);

  it('on click the attributes do not change', () => {
    const button = rendered.getByRole('button', { name: TEXT_CHILD });

    expect(button).toHaveAttribute('aria-pressed', 'false');
    expect(button).toHaveAttribute('data-state', 'off');
    expect(button).toHaveAttribute('disabled', '');

    fireEvent(
      button,
      new MouseEvent('click', {
        bubbles: true,
        cancelable: true,
      }),
    );

    expect(button).toHaveAttribute('aria-pressed', 'false');
    expect(button).toHaveAttribute('data-state', 'off');
  });
});

describe('given a controlled Toggle (with pressed and onPressedChange)', () => {
  let rendered: RenderResult;
  const onPressedChangeMock = vi.fn();

  beforeEach(() => {
    rendered = render(
      <Toggle.Root pressed onPressedChange={onPressedChangeMock}>
        {TEXT_CHILD}
      </Toggle.Root>,
    );
  });

  afterEach(cleanup);

  it('Click event should keep the same attributes, and pass the new state to onPressedChange', () => {
    const button = rendered.getByRole('button', { name: TEXT_CHILD });

    expect(button).toHaveAttribute('aria-pressed', 'true');
    expect(button).toHaveAttribute('data-state', 'on');

    fireEvent(
      button,
      new MouseEvent('click', {
        bubbles: true,
        cancelable: true,
      }),
    );

    expect(onPressedChangeMock).toHaveBeenCalledTimes(1);
    expect(onPressedChangeMock).toHaveBeenCalledWith(false);

    // The attributes do not change, they keep the same
    // because it's a controlled component.
    expect(button).toHaveAttribute('aria-pressed', 'true');
    expect(button).toHaveAttribute('data-state', 'on');
  });
});



================================================
FILE: packages/react/toggle/src/toggle.tsx
================================================
import * as React from 'react';
import { composeEventHandlers } from '@radix-ui/primitive';
import { useControllableState } from '@radix-ui/react-use-controllable-state';
import { Primitive } from '@radix-ui/react-primitive';

/* -------------------------------------------------------------------------------------------------
 * Toggle
 * -----------------------------------------------------------------------------------------------*/

const NAME = 'Toggle';

type ToggleElement = React.ComponentRef<typeof Primitive.button>;
type PrimitiveButtonProps = React.ComponentPropsWithoutRef<typeof Primitive.button>;
interface ToggleProps extends PrimitiveButtonProps {
  /**
   * The controlled state of the toggle.
   */
  pressed?: boolean;
  /**
   * The state of the toggle when initially rendered. Use `defaultPressed`
   * if you do not need to control the state of the toggle.
   * @defaultValue false
   */
  defaultPressed?: boolean;
  /**
   * The callback that fires when the state of the toggle changes.
   */
  onPressedChange?(pressed: boolean): void;
}

const Toggle = React.forwardRef<ToggleElement, ToggleProps>((props, forwardedRef) => {
  const { pressed: pressedProp, defaultPressed, onPressedChange, ...buttonProps } = props;

  const [pressed, setPressed] = useControllableState({
    prop: pressedProp,
    onChange: onPressedChange,
    defaultProp: defaultPressed ?? false,
    caller: NAME,
  });

  return (
    <Primitive.button
      type="button"
      aria-pressed={pressed}
      data-state={pressed ? 'on' : 'off'}
      data-disabled={props.disabled ? '' : undefined}
      {...buttonProps}
      ref={forwardedRef}
      onClick={composeEventHandlers(props.onClick, () => {
        if (!props.disabled) {
          setPressed(!pressed);
        }
      })}
    />
  );
});

Toggle.displayName = NAME;

/* ---------------------------------------------------------------------------------------------- */

const Root = Toggle;

export {
  Toggle,
  //
  Root,
};
export type { ToggleProps };



================================================
FILE: packages/react/toggle-group/README.md
================================================
# `react-toggle-group`

View docs [here](https://radix-ui.com/primitives/docs/components/toggle-group).



================================================
FILE: packages/react/toggle-group/CHANGELOG.md
================================================
# @radix-ui/react-toggle-group

## 1.1.11

- Updated dependencies: `@radix-ui/primitive@1.1.3`, `@radix-ui/react-context@1.1.3`, `@radix-ui/react-primitive@2.1.4`, `@radix-ui/react-roving-focus@1.1.11`, `@radix-ui/react-toggle@1.1.10`

## 1.1.10

- Replace deprecated 'ElementRef' with 'ComponentRef' (#3426)
- Updated dependencies: `@radix-ui/react-roving-focus@1.1.10`, `@radix-ui/react-toggle@1.1.9`, `@radix-ui/react-primitive@2.1.3`

## 1.1.9

- Updated dependencies: `@radix-ui/react-primitive@2.1.2`, `@radix-ui/react-roving-focus@1.1.9`, `@radix-ui/react-toggle@1.1.8`

## 1.1.8

- Updated dependencies: `@radix-ui/react-primitive@2.1.1`, `@radix-ui/react-roving-focus@1.1.8`, `@radix-ui/react-toggle@1.1.7`

## 1.1.7

- Updated dependencies: `@radix-ui/react-roving-focus@1.1.7`

## 1.1.6

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.2`, `@radix-ui/react-roving-focus@1.1.6`, `@radix-ui/react-toggle@1.1.6`

## 1.1.5

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.1`, `@radix-ui/react-roving-focus@1.1.5`, `@radix-ui/react-toggle@1.1.5`

## 1.1.4

- Minor improvements to `useControllableState` to enhance performance, reduce surface area for bugs, and log warnings when misused (#3455)
- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.0`, `@radix-ui/react-roving-focus@1.1.4`, `@radix-ui/react-toggle@1.1.4`, `@radix-ui/react-primitive@2.1.0`



================================================
FILE: packages/react/toggle-group/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/toggle-group/package.json
================================================
{
  "name": "@radix-ui/react-toggle-group",
  "version": "1.1.11",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/primitive": "workspace:*",
    "@radix-ui/react-context": "workspace:*",
    "@radix-ui/react-direction": "workspace:*",
    "@radix-ui/react-primitive": "workspace:*",
    "@radix-ui/react-roving-focus": "workspace:*",
    "@radix-ui/react-toggle": "workspace:*",
    "@radix-ui/react-use-controllable-state": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/toggle-group/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/toggle-group/src/index.ts
================================================
'use client';
export {
  createToggleGroupScope,
  //
  ToggleGroup,
  ToggleGroupItem,
  //
  Root,
  Item,
} from './toggle-group';
export type {
  ToggleGroupSingleProps,
  ToggleGroupMultipleProps,
  ToggleGroupItemProps,
} from './toggle-group';



================================================
FILE: packages/react/toggle-group/src/toggle-group.test.tsx
================================================
import * as React from 'react';
import { axe } from 'vitest-axe';
import type { RenderResult } from '@testing-library/react';
import { cleanup, render, fireEvent } from '@testing-library/react';
import * as ToggleGroup from './toggle-group';
import type { Mock } from 'vitest';
import { afterEach, describe, it, beforeEach, vi, expect } from 'vitest';

describe('given a single ToggleGroup', () => {
  let handleValueChange: Mock;
  let rendered: RenderResult;
  let one: HTMLElement;
  let two: HTMLElement;

  beforeEach(() => {
    handleValueChange = vi.fn();
    rendered = render(<ToggleGroupTest type="single" onValueChange={handleValueChange} />);
    one = rendered.getByText('One');
    two = rendered.getByText('Two');
  });

  afterEach(cleanup);

  it('should have no accessibility violations', async () => {
    expect(await axe(rendered.container)).toHaveNoViolations();
  });

  describe('when clicking `One`', () => {
    beforeEach(() => {
      fireEvent.click(one);
    });

    it('should have no accessibility violations', async () => {
      expect(await axe(rendered.container)).toHaveNoViolations();
    });

    it('should change value to `One`', () => {
      expect(handleValueChange).toHaveBeenCalledWith('One');
    });

    describe('then clicking `Two`', () => {
      beforeEach(() => {
        fireEvent.click(two);
      });

      it('should change value to `Two`', () => {
        expect(handleValueChange).toHaveBeenCalledWith('Two');
      });

      describe('and clicking `Two` again`', () => {
        beforeEach(() => {
          fireEvent.click(two);
        });

        it('should change value to empty string', () => {
          expect(handleValueChange).toHaveBeenCalledWith('');
        });
      });
    });
  });
});

describe('given a multiple ToggleGroup', () => {
  let handleValueChange: Mock;
  let rendered: RenderResult;
  let one: HTMLElement;
  let two: HTMLElement;

  beforeEach(() => {
    handleValueChange = vi.fn();
    rendered = render(<ToggleGroupTest type="multiple" onValueChange={handleValueChange} />);
    one = rendered.getByText('One');
    two = rendered.getByText('Two');
  });

  afterEach(cleanup);

  it('should have no accessibility violations', async () => {
    expect(await axe(rendered.container)).toHaveNoViolations();
  });

  describe('when clicking `One`', () => {
    beforeEach(() => {
      fireEvent.click(one);
    });

    it('should have no accessibility violations', async () => {
      expect(await axe(rendered.container)).toHaveNoViolations();
    });

    it('should change value to `One`', () => {
      expect(handleValueChange).toHaveBeenCalledWith(['One']);
    });

    describe('and clicking `One` again`', () => {
      beforeEach(() => {
        fireEvent.click(one);
      });

      it('should change value to empty array', () => {
        expect(handleValueChange).toHaveBeenCalledWith([]);
      });
    });

    describe('then clicking `Two`', () => {
      beforeEach(() => {
        fireEvent.click(two);
      });

      it('should add `Two` to value', () => {
        expect(handleValueChange).toHaveBeenCalledWith(['One', 'Two']);
      });

      describe('and clicking `Two` again`', () => {
        beforeEach(() => {
          fireEvent.click(two);
        });

        it('should change value to `One`', () => {
          expect(handleValueChange).toHaveBeenCalledWith(['One']);
        });
      });
    });
  });
});

const ToggleGroupTest = (props: React.ComponentProps<typeof ToggleGroup.Root>) => (
  <ToggleGroup.Root {...props}>
    <ToggleGroup.Item value="One">One</ToggleGroup.Item>
    <ToggleGroup.Item value="Two">Two</ToggleGroup.Item>
    <ToggleGroup.Item value="Three">Three</ToggleGroup.Item>
  </ToggleGroup.Root>
);



================================================
FILE: packages/react/toggle-group/src/toggle-group.tsx
================================================
import React from 'react';
import { createContextScope } from '@radix-ui/react-context';
import { Primitive } from '@radix-ui/react-primitive';
import * as RovingFocusGroup from '@radix-ui/react-roving-focus';
import { createRovingFocusGroupScope } from '@radix-ui/react-roving-focus';
import { Toggle } from '@radix-ui/react-toggle';
import { useControllableState } from '@radix-ui/react-use-controllable-state';
import { useDirection } from '@radix-ui/react-direction';

import type { Scope } from '@radix-ui/react-context';

/* -------------------------------------------------------------------------------------------------
 * ToggleGroup
 * -----------------------------------------------------------------------------------------------*/

const TOGGLE_GROUP_NAME = 'ToggleGroup';

type ScopedProps<P> = P & { __scopeToggleGroup?: Scope };
const [createToggleGroupContext, createToggleGroupScope] = createContextScope(TOGGLE_GROUP_NAME, [
  createRovingFocusGroupScope,
]);
const useRovingFocusGroupScope = createRovingFocusGroupScope();

type ToggleGroupElement = ToggleGroupImplSingleElement | ToggleGroupImplMultipleElement;
interface ToggleGroupSingleProps extends ToggleGroupImplSingleProps {
  type: 'single';
}
interface ToggleGroupMultipleProps extends ToggleGroupImplMultipleProps {
  type: 'multiple';
}

const ToggleGroup = React.forwardRef<
  ToggleGroupElement,
  ToggleGroupSingleProps | ToggleGroupMultipleProps
>((props, forwardedRef) => {
  const { type, ...toggleGroupProps } = props;

  if (type === 'single') {
    const singleProps = toggleGroupProps as ToggleGroupImplSingleProps;
    return <ToggleGroupImplSingle {...singleProps} ref={forwardedRef} />;
  }

  if (type === 'multiple') {
    const multipleProps = toggleGroupProps as ToggleGroupImplMultipleProps;
    return <ToggleGroupImplMultiple {...multipleProps} ref={forwardedRef} />;
  }

  throw new Error(`Missing prop \`type\` expected on \`${TOGGLE_GROUP_NAME}\``);
});

ToggleGroup.displayName = TOGGLE_GROUP_NAME;

/* -----------------------------------------------------------------------------------------------*/

type ToggleGroupValueContextValue = {
  type: 'single' | 'multiple';
  value: string[];
  onItemActivate(value: string): void;
  onItemDeactivate(value: string): void;
};

const [ToggleGroupValueProvider, useToggleGroupValueContext] =
  createToggleGroupContext<ToggleGroupValueContextValue>(TOGGLE_GROUP_NAME);

type ToggleGroupImplSingleElement = ToggleGroupImplElement;
interface ToggleGroupImplSingleProps extends ToggleGroupImplProps {
  /**
   * The controlled stateful value of the item that is pressed.
   */
  value?: string;
  /**
   * The value of the item that is pressed when initially rendered. Use
   * `defaultValue` if you do not need to control the state of a toggle group.
   */
  defaultValue?: string;
  /**
   * The callback that fires when the value of the toggle group changes.
   */
  onValueChange?(value: string): void;
}

const ToggleGroupImplSingle = React.forwardRef<
  ToggleGroupImplSingleElement,
  ToggleGroupImplSingleProps
>((props: ScopedProps<ToggleGroupImplSingleProps>, forwardedRef) => {
  const {
    value: valueProp,
    defaultValue,
    onValueChange = () => {},
    ...toggleGroupSingleProps
  } = props;

  const [value, setValue] = useControllableState({
    prop: valueProp,
    defaultProp: defaultValue ?? '',
    onChange: onValueChange,
    caller: TOGGLE_GROUP_NAME,
  });

  return (
    <ToggleGroupValueProvider
      scope={props.__scopeToggleGroup}
      type="single"
      value={React.useMemo(() => (value ? [value] : []), [value])}
      onItemActivate={setValue}
      onItemDeactivate={React.useCallback(() => setValue(''), [setValue])}
    >
      <ToggleGroupImpl {...toggleGroupSingleProps} ref={forwardedRef} />
    </ToggleGroupValueProvider>
  );
});

type ToggleGroupImplMultipleElement = ToggleGroupImplElement;
interface ToggleGroupImplMultipleProps extends ToggleGroupImplProps {
  /**
   * The controlled stateful value of the items that are pressed.
   */
  value?: string[];
  /**
   * The value of the items that are pressed when initially rendered. Use
   * `defaultValue` if you do not need to control the state of a toggle group.
   */
  defaultValue?: string[];
  /**
   * The callback that fires when the state of the toggle group changes.
   */
  onValueChange?(value: string[]): void;
}

const ToggleGroupImplMultiple = React.forwardRef<
  ToggleGroupImplMultipleElement,
  ToggleGroupImplMultipleProps
>((props: ScopedProps<ToggleGroupImplMultipleProps>, forwardedRef) => {
  const {
    value: valueProp,
    defaultValue,
    onValueChange = () => {},
    ...toggleGroupMultipleProps
  } = props;

  const [value, setValue] = useControllableState({
    prop: valueProp,
    defaultProp: defaultValue ?? [],
    onChange: onValueChange,
    caller: TOGGLE_GROUP_NAME,
  });

  const handleButtonActivate = React.useCallback(
    (itemValue: string) => setValue((prevValue = []) => [...prevValue, itemValue]),
    [setValue],
  );

  const handleButtonDeactivate = React.useCallback(
    (itemValue: string) =>
      setValue((prevValue = []) => prevValue.filter((value) => value !== itemValue)),
    [setValue],
  );

  return (
    <ToggleGroupValueProvider
      scope={props.__scopeToggleGroup}
      type="multiple"
      value={value}
      onItemActivate={handleButtonActivate}
      onItemDeactivate={handleButtonDeactivate}
    >
      <ToggleGroupImpl {...toggleGroupMultipleProps} ref={forwardedRef} />
    </ToggleGroupValueProvider>
  );
});

ToggleGroup.displayName = TOGGLE_GROUP_NAME;

/* -----------------------------------------------------------------------------------------------*/

type ToggleGroupContextValue = { rovingFocus: boolean; disabled: boolean };

const [ToggleGroupContext, useToggleGroupContext] =
  createToggleGroupContext<ToggleGroupContextValue>(TOGGLE_GROUP_NAME);

type RovingFocusGroupProps = React.ComponentPropsWithoutRef<typeof RovingFocusGroup.Root>;
type ToggleGroupImplElement = React.ComponentRef<typeof Primitive.div>;
type PrimitiveDivProps = React.ComponentPropsWithoutRef<typeof Primitive.div>;
interface ToggleGroupImplProps extends PrimitiveDivProps {
  /**
   * Whether the group is disabled from user interaction.
   * @defaultValue false
   */
  disabled?: boolean;
  /**
   * Whether the group should maintain roving focus of its buttons.
   * @defaultValue true
   */
  rovingFocus?: boolean;
  loop?: RovingFocusGroupProps['loop'];
  orientation?: RovingFocusGroupProps['orientation'];
  dir?: RovingFocusGroupProps['dir'];
}

const ToggleGroupImpl = React.forwardRef<ToggleGroupImplElement, ToggleGroupImplProps>(
  (props: ScopedProps<ToggleGroupImplProps>, forwardedRef) => {
    const {
      __scopeToggleGroup,
      disabled = false,
      rovingFocus = true,
      orientation,
      dir,
      loop = true,
      ...toggleGroupProps
    } = props;
    const rovingFocusGroupScope = useRovingFocusGroupScope(__scopeToggleGroup);
    const direction = useDirection(dir);
    const commonProps = { role: 'group', dir: direction, ...toggleGroupProps };
    return (
      <ToggleGroupContext scope={__scopeToggleGroup} rovingFocus={rovingFocus} disabled={disabled}>
        {rovingFocus ? (
          <RovingFocusGroup.Root
            asChild
            {...rovingFocusGroupScope}
            orientation={orientation}
            dir={direction}
            loop={loop}
          >
            <Primitive.div {...commonProps} ref={forwardedRef} />
          </RovingFocusGroup.Root>
        ) : (
          <Primitive.div {...commonProps} ref={forwardedRef} />
        )}
      </ToggleGroupContext>
    );
  },
);

/* -------------------------------------------------------------------------------------------------
 * ToggleGroupItem
 * -----------------------------------------------------------------------------------------------*/

const ITEM_NAME = 'ToggleGroupItem';

type ToggleGroupItemElement = ToggleGroupItemImplElement;
interface ToggleGroupItemProps extends Omit<ToggleGroupItemImplProps, 'pressed'> {}

const ToggleGroupItem = React.forwardRef<ToggleGroupItemElement, ToggleGroupItemProps>(
  (props: ScopedProps<ToggleGroupItemProps>, forwardedRef) => {
    const valueContext = useToggleGroupValueContext(ITEM_NAME, props.__scopeToggleGroup);
    const context = useToggleGroupContext(ITEM_NAME, props.__scopeToggleGroup);
    const rovingFocusGroupScope = useRovingFocusGroupScope(props.__scopeToggleGroup);
    const pressed = valueContext.value.includes(props.value);
    const disabled = context.disabled || props.disabled;
    const commonProps = { ...props, pressed, disabled };
    const ref = React.useRef<HTMLDivElement>(null);
    return context.rovingFocus ? (
      <RovingFocusGroup.Item
        asChild
        {...rovingFocusGroupScope}
        focusable={!disabled}
        active={pressed}
        ref={ref}
      >
        <ToggleGroupItemImpl {...commonProps} ref={forwardedRef} />
      </RovingFocusGroup.Item>
    ) : (
      <ToggleGroupItemImpl {...commonProps} ref={forwardedRef} />
    );
  },
);

ToggleGroupItem.displayName = ITEM_NAME;

/* -----------------------------------------------------------------------------------------------*/

type ToggleGroupItemImplElement = React.ComponentRef<typeof Toggle>;
type ToggleProps = React.ComponentPropsWithoutRef<typeof Toggle>;
interface ToggleGroupItemImplProps extends Omit<ToggleProps, 'defaultPressed' | 'onPressedChange'> {
  /**
   * A string value for the toggle group item. All items within a toggle group should use a unique value.
   */
  value: string;
}

const ToggleGroupItemImpl = React.forwardRef<ToggleGroupItemImplElement, ToggleGroupItemImplProps>(
  (props: ScopedProps<ToggleGroupItemImplProps>, forwardedRef) => {
    const { __scopeToggleGroup, value, ...itemProps } = props;
    const valueContext = useToggleGroupValueContext(ITEM_NAME, __scopeToggleGroup);
    const singleProps = { role: 'radio', 'aria-checked': props.pressed, 'aria-pressed': undefined };
    const typeProps = valueContext.type === 'single' ? singleProps : undefined;
    return (
      <Toggle
        {...typeProps}
        {...itemProps}
        ref={forwardedRef}
        onPressedChange={(pressed) => {
          if (pressed) {
            valueContext.onItemActivate(value);
          } else {
            valueContext.onItemDeactivate(value);
          }
        }}
      />
    );
  },
);

/* -----------------------------------------------------------------------------------------------*/

const Root = ToggleGroup;
const Item = ToggleGroupItem;

export {
  createToggleGroupScope,
  //
  ToggleGroup,
  ToggleGroupItem,
  //
  Root,
  Item,
};
export type { ToggleGroupSingleProps, ToggleGroupMultipleProps, ToggleGroupItemProps };



================================================
FILE: packages/react/toolbar/README.md
================================================
# `react-toolbar`

View docs [here](https://radix-ui.com/primitives/docs/components/toolbar).



================================================
FILE: packages/react/toolbar/CHANGELOG.md
================================================
# @radix-ui/react-toolbar

## 1.1.11

- Updated dependencies: `@radix-ui/primitive@1.1.3`, `@radix-ui/react-context@1.1.3`, `@radix-ui/react-primitive@2.1.4`, `@radix-ui/react-roving-focus@1.1.11`, `@radix-ui/react-toggle-group@1.1.11`, `@radix-ui/react-separator@1.1.8`

## 1.1.10

- Replace deprecated 'ElementRef' with 'ComponentRef' (#3426)
- Updated dependencies: `@radix-ui/react-roving-focus@1.1.10`, `@radix-ui/react-toggle-group@1.1.10`, `@radix-ui/react-separator@1.1.7`, `@radix-ui/react-primitive@2.1.3`

## 1.1.9

- Updated dependencies: `@radix-ui/react-primitive@2.1.2`, `@radix-ui/react-roving-focus@1.1.9`, `@radix-ui/react-separator@1.1.6`, `@radix-ui/react-toggle-group@1.1.9`

## 1.1.8

- Updated dependencies: `@radix-ui/react-primitive@2.1.1`, `@radix-ui/react-roving-focus@1.1.8`, `@radix-ui/react-separator@1.1.5`, `@radix-ui/react-toggle-group@1.1.8`

## 1.1.7

- Updated dependencies: `@radix-ui/react-roving-focus@1.1.7`, `@radix-ui/react-toggle-group@1.1.7`

## 1.1.6

- Updated dependencies: `@radix-ui/react-roving-focus@1.1.6`, `@radix-ui/react-toggle-group@1.1.6`

## 1.1.5

- Updated dependencies: `@radix-ui/react-roving-focus@1.1.5`, `@radix-ui/react-toggle-group@1.1.5`

## 1.1.4

- Updated dependencies: `@radix-ui/react-roving-focus@1.1.4`, `@radix-ui/react-toggle-group@1.1.4`, `@radix-ui/react-primitive@2.1.0`, `@radix-ui/react-separator@1.1.4`



================================================
FILE: packages/react/toolbar/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/toolbar/package.json
================================================
{
  "name": "@radix-ui/react-toolbar",
  "version": "1.1.11",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/primitive": "workspace:*",
    "@radix-ui/react-context": "workspace:*",
    "@radix-ui/react-direction": "workspace:*",
    "@radix-ui/react-primitive": "workspace:*",
    "@radix-ui/react-roving-focus": "workspace:*",
    "@radix-ui/react-separator": "workspace:*",
    "@radix-ui/react-toggle-group": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/toolbar/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/toolbar/src/index.ts
================================================
'use client';
export {
  createToolbarScope,
  //
  Toolbar,
  ToolbarSeparator,
  ToolbarButton,
  ToolbarLink,
  ToolbarToggleGroup,
  ToolbarToggleItem,
  //
  Root,
  Separator,
  Button,
  Link,
  ToggleGroup,
  ToggleItem,
} from './toolbar';
export type {
  ToolbarProps,
  ToolbarSeparatorProps,
  ToolbarButtonProps,
  ToolbarLinkProps,
  ToolbarToggleGroupSingleProps,
  ToolbarToggleGroupMultipleProps,
  ToolbarToggleItemProps,
} from './toolbar';



================================================
FILE: packages/react/toolbar/src/toolbar.test.tsx
================================================
import { cleanup, render, fireEvent, getByText } from '@testing-library/react';
import * as Toolbar from './toolbar';
import { afterEach, describe, it, vi, expect } from 'vitest';

const component = (props: any) => {
  return render(
    <Toolbar.Root>
      <Toolbar.ToggleGroup type="single">
        <Toolbar.ToggleItem value="left" onClick={props.onClick}>
          Left
        </Toolbar.ToggleItem>
      </Toolbar.ToggleGroup>
    </Toolbar.Root>,
  );
};

describe('given a default Toolbar', () => {
  afterEach(cleanup);
  it('Click event should be called just once', async () => {
    const spy = vi.fn();

    const rendered = component({
      onClick: spy,
    });

    fireEvent(
      getByText(rendered.container, 'Left'),
      new MouseEvent('click', {
        bubbles: true,
        cancelable: true,
      }),
    );

    expect(spy).toHaveBeenCalledTimes(1);
  });
});



================================================
FILE: packages/react/toolbar/src/toolbar.tsx
================================================
import * as React from 'react';
import { composeEventHandlers } from '@radix-ui/primitive';
import { createContextScope } from '@radix-ui/react-context';
import * as RovingFocusGroup from '@radix-ui/react-roving-focus';
import { createRovingFocusGroupScope } from '@radix-ui/react-roving-focus';
import { Primitive } from '@radix-ui/react-primitive';
import * as SeparatorPrimitive from '@radix-ui/react-separator';
import * as ToggleGroupPrimitive from '@radix-ui/react-toggle-group';
import { createToggleGroupScope } from '@radix-ui/react-toggle-group';
import { useDirection } from '@radix-ui/react-direction';

import type { Scope } from '@radix-ui/react-context';

/* -------------------------------------------------------------------------------------------------
 * Toolbar
 * -----------------------------------------------------------------------------------------------*/

const TOOLBAR_NAME = 'Toolbar';

type ScopedProps<P> = P & { __scopeToolbar?: Scope };
const [createToolbarContext, createToolbarScope] = createContextScope(TOOLBAR_NAME, [
  createRovingFocusGroupScope,
  createToggleGroupScope,
]);
const useRovingFocusGroupScope = createRovingFocusGroupScope();
const useToggleGroupScope = createToggleGroupScope();

type RovingFocusGroupProps = React.ComponentPropsWithoutRef<typeof RovingFocusGroup.Root>;
type ToolbarContextValue = {
  orientation: RovingFocusGroupProps['orientation'];
  dir: RovingFocusGroupProps['dir'];
};
const [ToolbarProvider, useToolbarContext] =
  createToolbarContext<ToolbarContextValue>(TOOLBAR_NAME);

type ToolbarElement = React.ComponentRef<typeof Primitive.div>;
type PrimitiveDivProps = React.ComponentPropsWithoutRef<typeof Primitive.div>;
interface ToolbarProps extends PrimitiveDivProps {
  orientation?: RovingFocusGroupProps['orientation'];
  loop?: RovingFocusGroupProps['loop'];
  dir?: RovingFocusGroupProps['dir'];
}

const Toolbar = React.forwardRef<ToolbarElement, ToolbarProps>(
  (props: ScopedProps<ToolbarProps>, forwardedRef) => {
    const { __scopeToolbar, orientation = 'horizontal', dir, loop = true, ...toolbarProps } = props;
    const rovingFocusGroupScope = useRovingFocusGroupScope(__scopeToolbar);
    const direction = useDirection(dir);
    return (
      <ToolbarProvider scope={__scopeToolbar} orientation={orientation} dir={direction}>
        <RovingFocusGroup.Root
          asChild
          {...rovingFocusGroupScope}
          orientation={orientation}
          dir={direction}
          loop={loop}
        >
          <Primitive.div
            role="toolbar"
            aria-orientation={orientation}
            dir={direction}
            {...toolbarProps}
            ref={forwardedRef}
          />
        </RovingFocusGroup.Root>
      </ToolbarProvider>
    );
  },
);

Toolbar.displayName = TOOLBAR_NAME;

/* -------------------------------------------------------------------------------------------------
 * ToolbarSeparator
 * -----------------------------------------------------------------------------------------------*/

const SEPARATOR_NAME = 'ToolbarSeparator';

type ToolbarSeparatorElement = React.ComponentRef<typeof SeparatorPrimitive.Root>;
type SeparatorProps = React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>;
interface ToolbarSeparatorProps extends SeparatorProps {}

const ToolbarSeparator = React.forwardRef<ToolbarSeparatorElement, ToolbarSeparatorProps>(
  (props: ScopedProps<ToolbarSeparatorProps>, forwardedRef) => {
    const { __scopeToolbar, ...separatorProps } = props;
    const context = useToolbarContext(SEPARATOR_NAME, __scopeToolbar);
    return (
      <SeparatorPrimitive.Root
        orientation={context.orientation === 'horizontal' ? 'vertical' : 'horizontal'}
        {...separatorProps}
        ref={forwardedRef}
      />
    );
  },
);

ToolbarSeparator.displayName = SEPARATOR_NAME;

/* -------------------------------------------------------------------------------------------------
 * ToolbarButton
 * -----------------------------------------------------------------------------------------------*/

const BUTTON_NAME = 'ToolbarButton';

type ToolbarButtonElement = React.ComponentRef<typeof Primitive.button>;
type PrimitiveButtonProps = React.ComponentPropsWithoutRef<typeof Primitive.button>;
interface ToolbarButtonProps extends PrimitiveButtonProps {}

const ToolbarButton = React.forwardRef<ToolbarButtonElement, ToolbarButtonProps>(
  (props: ScopedProps<ToolbarButtonProps>, forwardedRef) => {
    const { __scopeToolbar, ...buttonProps } = props;
    const rovingFocusGroupScope = useRovingFocusGroupScope(__scopeToolbar);
    return (
      <RovingFocusGroup.Item asChild {...rovingFocusGroupScope} focusable={!props.disabled}>
        <Primitive.button type="button" {...buttonProps} ref={forwardedRef} />
      </RovingFocusGroup.Item>
    );
  },
);

ToolbarButton.displayName = BUTTON_NAME;

/* -------------------------------------------------------------------------------------------------
 * ToolbarLink
 * -----------------------------------------------------------------------------------------------*/

const LINK_NAME = 'ToolbarLink';

type ToolbarLinkElement = React.ComponentRef<typeof Primitive.a>;
type PrimitiveLinkProps = React.ComponentPropsWithoutRef<typeof Primitive.a>;
interface ToolbarLinkProps extends PrimitiveLinkProps {}

const ToolbarLink = React.forwardRef<ToolbarLinkElement, ToolbarLinkProps>(
  (props: ScopedProps<ToolbarLinkProps>, forwardedRef) => {
    const { __scopeToolbar, ...linkProps } = props;
    const rovingFocusGroupScope = useRovingFocusGroupScope(__scopeToolbar);
    return (
      <RovingFocusGroup.Item asChild {...rovingFocusGroupScope} focusable>
        <Primitive.a
          {...linkProps}
          ref={forwardedRef}
          onKeyDown={composeEventHandlers(props.onKeyDown, (event) => {
            if (event.key === ' ') event.currentTarget.click();
          })}
        />
      </RovingFocusGroup.Item>
    );
  },
);

ToolbarLink.displayName = LINK_NAME;

/* -------------------------------------------------------------------------------------------------
 * ToolbarToggleGroup
 * -----------------------------------------------------------------------------------------------*/

const TOGGLE_GROUP_NAME = 'ToolbarToggleGroup';

type ToolbarToggleGroupElement = React.ComponentRef<typeof ToggleGroupPrimitive.Root>;
type ToggleGroupProps = React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Root>;
interface ToolbarToggleGroupSingleProps extends Extract<ToggleGroupProps, { type: 'single' }> {}
interface ToolbarToggleGroupMultipleProps extends Extract<ToggleGroupProps, { type: 'multiple' }> {}

const ToolbarToggleGroup = React.forwardRef<
  ToolbarToggleGroupElement,
  ToolbarToggleGroupSingleProps | ToolbarToggleGroupMultipleProps
>(
  (
    props: ScopedProps<ToolbarToggleGroupSingleProps | ToolbarToggleGroupMultipleProps>,
    forwardedRef,
  ) => {
    const { __scopeToolbar, ...toggleGroupProps } = props;
    const context = useToolbarContext(TOGGLE_GROUP_NAME, __scopeToolbar);
    const toggleGroupScope = useToggleGroupScope(__scopeToolbar);
    return (
      <ToggleGroupPrimitive.Root
        data-orientation={context.orientation}
        dir={context.dir}
        {...toggleGroupScope}
        {...toggleGroupProps}
        ref={forwardedRef}
        rovingFocus={false}
      />
    );
  },
);

ToolbarToggleGroup.displayName = TOGGLE_GROUP_NAME;

/* -------------------------------------------------------------------------------------------------
 * ToolbarToggleItem
 * -----------------------------------------------------------------------------------------------*/

const TOGGLE_ITEM_NAME = 'ToolbarToggleItem';

type ToolbarToggleItemElement = React.ComponentRef<typeof ToggleGroupPrimitive.Item>;
type ToggleGroupItemProps = React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Item>;
interface ToolbarToggleItemProps extends ToggleGroupItemProps {}

const ToolbarToggleItem = React.forwardRef<ToolbarToggleItemElement, ToolbarToggleItemProps>(
  (props: ScopedProps<ToolbarToggleItemProps>, forwardedRef) => {
    const { __scopeToolbar, ...toggleItemProps } = props;
    const toggleGroupScope = useToggleGroupScope(__scopeToolbar);
    const scope = { __scopeToolbar: props.__scopeToolbar };

    return (
      <ToolbarButton asChild {...scope}>
        <ToggleGroupPrimitive.Item {...toggleGroupScope} {...toggleItemProps} ref={forwardedRef} />
      </ToolbarButton>
    );
  },
);

ToolbarToggleItem.displayName = TOGGLE_ITEM_NAME;

/* ---------------------------------------------------------------------------------------------- */

const Root = Toolbar;
const Separator = ToolbarSeparator;
const Button = ToolbarButton;
const Link = ToolbarLink;
const ToggleGroup = ToolbarToggleGroup;
const ToggleItem = ToolbarToggleItem;

export {
  createToolbarScope,
  //
  Toolbar,
  ToolbarSeparator,
  ToolbarButton,
  ToolbarLink,
  ToolbarToggleGroup,
  ToolbarToggleItem,
  //
  Root,
  Separator,
  Button,
  Link,
  ToggleGroup,
  ToggleItem,
};
export type {
  ToolbarProps,
  ToolbarSeparatorProps,
  ToolbarButtonProps,
  ToolbarLinkProps,
  ToolbarToggleGroupSingleProps,
  ToolbarToggleGroupMultipleProps,
  ToolbarToggleItemProps,
};



================================================
FILE: packages/react/tooltip/README.md
================================================
# `react-tooltip`

View docs [here](https://radix-ui.com/primitives/docs/components/tooltip).



================================================
FILE: packages/react/tooltip/CHANGELOG.md
================================================
# @radix-ui/react-tooltip

## 1.2.8

- Updated dependencies: `@radix-ui/react-presence@1.1.5`, `@radix-ui/react-slot@1.2.4`, `@radix-ui/react-popper@1.2.8`, `@radix-ui/primitive@1.1.3`, `@radix-ui/react-context@1.1.3`, `@radix-ui/react-primitive@2.1.4`, `@radix-ui/react-dismissable-layer@1.1.11`, `@radix-ui/react-portal@1.1.10`, `@radix-ui/react-visually-hidden@1.2.4`

## 1.2.7

- Replace deprecated 'ElementRef' with 'ComponentRef' (#3426)
- Updated dependencies: `@radix-ui/react-dismissable-layer@1.1.10`, `@radix-ui/react-visually-hidden@1.2.3`, `@radix-ui/react-popper@1.2.7`, `@radix-ui/react-portal@1.1.9`, `@radix-ui/react-slot@1.2.3`, `@radix-ui/react-primitive@2.1.3`

## 1.2.6

- Updated dependencies: `@radix-ui/react-slot@1.2.2`, `@radix-ui/react-primitive@2.1.2`, `@radix-ui/react-dismissable-layer@1.1.9`, `@radix-ui/react-popper@1.2.6`, `@radix-ui/react-portal@1.1.8`, `@radix-ui/react-visually-hidden@1.2.2`

## 1.2.5

- Updated dependencies: `@radix-ui/react-slot@1.2.1`, `@radix-ui/react-primitive@2.1.1`, `@radix-ui/react-dismissable-layer@1.1.8`, `@radix-ui/react-popper@1.2.5`, `@radix-ui/react-portal@1.1.7`, `@radix-ui/react-visually-hidden@1.2.1`

## 1.2.4

- Updated dependencies: `@radix-ui/react-presence@1.1.4`

## 1.2.3

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.2`

## 1.2.2

- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.1`

## 1.2.1

- Minor improvements to `useControllableState` to enhance performance, reduce surface area for bugs, and log warnings when misused (#3455)
- Updated dependencies: `@radix-ui/react-use-controllable-state@1.2.0`, `@radix-ui/react-visually-hidden@1.2.0`, `@radix-ui/react-primitive@2.1.0`, `@radix-ui/react-dismissable-layer@1.1.7`, `@radix-ui/react-popper@1.2.4`, `@radix-ui/react-portal@1.1.6`



================================================
FILE: packages/react/tooltip/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/tooltip/package.json
================================================
{
  "name": "@radix-ui/react-tooltip",
  "version": "1.2.8",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/primitive": "workspace:*",
    "@radix-ui/react-compose-refs": "workspace:*",
    "@radix-ui/react-context": "workspace:*",
    "@radix-ui/react-dismissable-layer": "workspace:*",
    "@radix-ui/react-id": "workspace:*",
    "@radix-ui/react-popper": "workspace:*",
    "@radix-ui/react-portal": "workspace:*",
    "@radix-ui/react-presence": "workspace:*",
    "@radix-ui/react-primitive": "workspace:*",
    "@radix-ui/react-slot": "workspace:*",
    "@radix-ui/react-use-controllable-state": "workspace:*",
    "@radix-ui/react-visually-hidden": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/tooltip/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/tooltip/src/index.ts
================================================
'use client';
export {
  createTooltipScope,
  //
  TooltipProvider,
  Tooltip,
  TooltipTrigger,
  TooltipPortal,
  TooltipContent,
  TooltipArrow,
  //
  Provider,
  Root,
  Trigger,
  Portal,
  Content,
  Arrow,
} from './tooltip';
export type {
  TooltipProps,
  TooltipProviderProps,
  TooltipTriggerProps,
  TooltipPortalProps,
  TooltipContentProps,
  TooltipArrowProps,
} from './tooltip';



================================================
FILE: packages/react/tooltip/src/tooltip.test.tsx
================================================
import { cleanup, render, screen, waitFor } from '@testing-library/react';
import * as Tooltip from './tooltip';
import userEvent from '@testing-library/user-event';
import { afterEach, describe, it, expect } from 'vitest';

describe('Tooltip', () => {
  afterEach(cleanup);

  it('renders tooltip trigger', () => {
    render(
      <Tooltip.Provider>
        <Tooltip.Root>
          <Tooltip.Trigger>Tooltip Trigger</Tooltip.Trigger>
          <Tooltip.Portal>
            <Tooltip.Content>
              Tooltip Content
              <Tooltip.Arrow />
            </Tooltip.Content>
          </Tooltip.Portal>
        </Tooltip.Root>
      </Tooltip.Provider>,
    );

    expect(screen.getByText('Tooltip Trigger')).toBeInTheDocument();
    expect(screen.queryByText('Tooltip Content')).not.toBeInTheDocument();
  });

  it('renders tooltip content when trigger is hovered', async () => {
    render(
      <Tooltip.Provider>
        <Tooltip.Root delayDuration={0}>
          <Tooltip.Trigger>Tooltip Trigger</Tooltip.Trigger>
          <Tooltip.Portal>
            <Tooltip.Content>
              Tooltip Content
              <Tooltip.Arrow />
            </Tooltip.Content>
          </Tooltip.Portal>
        </Tooltip.Root>
      </Tooltip.Provider>,
    );

    const trigger = screen.getByText('Tooltip Trigger');
    expect(screen.queryByText('Tooltip Content')).not.toBeInTheDocument();

    userEvent.hover(trigger);
    await waitFor(() => {
      // Get the first instance of the tooltip content because the second is
      // the visually hidden primitive.
      expect(screen.queryAllByText('Tooltip Content')[0]).toBeVisible();
    });
  });

  it('renders tooltip content is dismissed when trigger is clicked', async () => {
    render(
      <Tooltip.Provider>
        <Tooltip.Root delayDuration={0}>
          <Tooltip.Trigger>Tooltip Trigger</Tooltip.Trigger>
          <Tooltip.Portal>
            <Tooltip.Content>
              Tooltip Content
              <Tooltip.Arrow />
            </Tooltip.Content>
          </Tooltip.Portal>
        </Tooltip.Root>
      </Tooltip.Provider>,
    );

    const trigger = screen.getByText('Tooltip Trigger');
    expect(screen.queryByText('Tooltip Content')).not.toBeInTheDocument();

    userEvent.hover(trigger);
    await waitFor(() => {
      // Get the first instance of the tooltip content because the second is
      // the visually hidden primitive.
      expect(screen.queryAllByText('Tooltip Content')[0]).toBeVisible();
    });

    userEvent.click(trigger);
    await waitFor(() => {
      expect(screen.queryByText('Tooltip Content')).not.toBeInTheDocument();
    });
  });
});



================================================
FILE: packages/react/tooltip/src/tooltip.tsx
================================================
import * as React from 'react';
import { composeEventHandlers } from '@radix-ui/primitive';
import { useComposedRefs } from '@radix-ui/react-compose-refs';
import { createContextScope } from '@radix-ui/react-context';
import { DismissableLayer } from '@radix-ui/react-dismissable-layer';
import { useId } from '@radix-ui/react-id';
import * as PopperPrimitive from '@radix-ui/react-popper';
import { createPopperScope } from '@radix-ui/react-popper';
import { Portal as PortalPrimitive } from '@radix-ui/react-portal';
import { Presence } from '@radix-ui/react-presence';
import { Primitive } from '@radix-ui/react-primitive';
import { createSlottable } from '@radix-ui/react-slot';
import { useControllableState } from '@radix-ui/react-use-controllable-state';
import * as VisuallyHiddenPrimitive from '@radix-ui/react-visually-hidden';

import type { Scope } from '@radix-ui/react-context';

type ScopedProps<P = {}> = P & { __scopeTooltip?: Scope };
const [createTooltipContext, createTooltipScope] = createContextScope('Tooltip', [
  createPopperScope,
]);
const usePopperScope = createPopperScope();

/* -------------------------------------------------------------------------------------------------
 * TooltipProvider
 * -----------------------------------------------------------------------------------------------*/

const PROVIDER_NAME = 'TooltipProvider';
const DEFAULT_DELAY_DURATION = 700;
const TOOLTIP_OPEN = 'tooltip.open';

type TooltipProviderContextValue = {
  isOpenDelayedRef: React.MutableRefObject<boolean>;
  delayDuration: number;
  onOpen(): void;
  onClose(): void;
  onPointerInTransitChange(inTransit: boolean): void;
  isPointerInTransitRef: React.MutableRefObject<boolean>;
  disableHoverableContent: boolean;
};

const [TooltipProviderContextProvider, useTooltipProviderContext] =
  createTooltipContext<TooltipProviderContextValue>(PROVIDER_NAME);

interface TooltipProviderProps {
  children: React.ReactNode;
  /**
   * The duration from when the pointer enters the trigger until the tooltip gets opened.
   * @defaultValue 700
   */
  delayDuration?: number;
  /**
   * How much time a user has to enter another trigger without incurring a delay again.
   * @defaultValue 300
   */
  skipDelayDuration?: number;
  /**
   * When `true`, trying to hover the content will result in the tooltip closing as the pointer leaves the trigger.
   * @defaultValue false
   */
  disableHoverableContent?: boolean;
}

const TooltipProvider: React.FC<TooltipProviderProps> = (
  props: ScopedProps<TooltipProviderProps>,
) => {
  const {
    __scopeTooltip,
    delayDuration = DEFAULT_DELAY_DURATION,
    skipDelayDuration = 300,
    disableHoverableContent = false,
    children,
  } = props;
  const isOpenDelayedRef = React.useRef(true);
  const isPointerInTransitRef = React.useRef(false);
  const skipDelayTimerRef = React.useRef(0);

  React.useEffect(() => {
    const skipDelayTimer = skipDelayTimerRef.current;
    return () => window.clearTimeout(skipDelayTimer);
  }, []);

  return (
    <TooltipProviderContextProvider
      scope={__scopeTooltip}
      isOpenDelayedRef={isOpenDelayedRef}
      delayDuration={delayDuration}
      onOpen={React.useCallback(() => {
        window.clearTimeout(skipDelayTimerRef.current);
        isOpenDelayedRef.current = false;
      }, [])}
      onClose={React.useCallback(() => {
        window.clearTimeout(skipDelayTimerRef.current);
        skipDelayTimerRef.current = window.setTimeout(
          () => (isOpenDelayedRef.current = true),
          skipDelayDuration,
        );
      }, [skipDelayDuration])}
      isPointerInTransitRef={isPointerInTransitRef}
      onPointerInTransitChange={React.useCallback((inTransit: boolean) => {
        isPointerInTransitRef.current = inTransit;
      }, [])}
      disableHoverableContent={disableHoverableContent}
    >
      {children}
    </TooltipProviderContextProvider>
  );
};

TooltipProvider.displayName = PROVIDER_NAME;

/* -------------------------------------------------------------------------------------------------
 * Tooltip
 * -----------------------------------------------------------------------------------------------*/

const TOOLTIP_NAME = 'Tooltip';

type TooltipContextValue = {
  contentId: string;
  open: boolean;
  stateAttribute: 'closed' | 'delayed-open' | 'instant-open';
  trigger: TooltipTriggerElement | null;
  onTriggerChange(trigger: TooltipTriggerElement | null): void;
  onTriggerEnter(): void;
  onTriggerLeave(): void;
  onOpen(): void;
  onClose(): void;
  disableHoverableContent: boolean;
};

const [TooltipContextProvider, useTooltipContext] =
  createTooltipContext<TooltipContextValue>(TOOLTIP_NAME);

interface TooltipProps {
  children?: React.ReactNode;
  open?: boolean;
  defaultOpen?: boolean;
  onOpenChange?: (open: boolean) => void;
  /**
   * The duration from when the pointer enters the trigger until the tooltip gets opened. This will
   * override the prop with the same name passed to Provider.
   * @defaultValue 700
   */
  delayDuration?: number;
  /**
   * When `true`, trying to hover the content will result in the tooltip closing as the pointer leaves the trigger.
   * @defaultValue false
   */
  disableHoverableContent?: boolean;
}

const Tooltip: React.FC<TooltipProps> = (props: ScopedProps<TooltipProps>) => {
  const {
    __scopeTooltip,
    children,
    open: openProp,
    defaultOpen,
    onOpenChange,
    disableHoverableContent: disableHoverableContentProp,
    delayDuration: delayDurationProp,
  } = props;
  const providerContext = useTooltipProviderContext(TOOLTIP_NAME, props.__scopeTooltip);
  const popperScope = usePopperScope(__scopeTooltip);
  const [trigger, setTrigger] = React.useState<HTMLButtonElement | null>(null);
  const contentId = useId();
  const openTimerRef = React.useRef(0);
  const disableHoverableContent =
    disableHoverableContentProp ?? providerContext.disableHoverableContent;
  const delayDuration = delayDurationProp ?? providerContext.delayDuration;
  const wasOpenDelayedRef = React.useRef(false);
  const [open, setOpen] = useControllableState({
    prop: openProp,
    defaultProp: defaultOpen ?? false,
    onChange: (open) => {
      if (open) {
        providerContext.onOpen();

        // as `onChange` is called within a lifecycle method we
        // avoid dispatching via `dispatchDiscreteCustomEvent`.
        document.dispatchEvent(new CustomEvent(TOOLTIP_OPEN));
      } else {
        providerContext.onClose();
      }
      onOpenChange?.(open);
    },
    caller: TOOLTIP_NAME,
  });
  const stateAttribute = React.useMemo(() => {
    return open ? (wasOpenDelayedRef.current ? 'delayed-open' : 'instant-open') : 'closed';
  }, [open]);

  const handleOpen = React.useCallback(() => {
    window.clearTimeout(openTimerRef.current);
    openTimerRef.current = 0;
    wasOpenDelayedRef.current = false;
    setOpen(true);
  }, [setOpen]);

  const handleClose = React.useCallback(() => {
    window.clearTimeout(openTimerRef.current);
    openTimerRef.current = 0;
    setOpen(false);
  }, [setOpen]);

  const handleDelayedOpen = React.useCallback(() => {
    window.clearTimeout(openTimerRef.current);
    openTimerRef.current = window.setTimeout(() => {
      wasOpenDelayedRef.current = true;
      setOpen(true);
      openTimerRef.current = 0;
    }, delayDuration);
  }, [delayDuration, setOpen]);

  React.useEffect(() => {
    return () => {
      if (openTimerRef.current) {
        window.clearTimeout(openTimerRef.current);
        openTimerRef.current = 0;
      }
    };
  }, []);

  return (
    <PopperPrimitive.Root {...popperScope}>
      <TooltipContextProvider
        scope={__scopeTooltip}
        contentId={contentId}
        open={open}
        stateAttribute={stateAttribute}
        trigger={trigger}
        onTriggerChange={setTrigger}
        onTriggerEnter={React.useCallback(() => {
          if (providerContext.isOpenDelayedRef.current) handleDelayedOpen();
          else handleOpen();
        }, [providerContext.isOpenDelayedRef, handleDelayedOpen, handleOpen])}
        onTriggerLeave={React.useCallback(() => {
          if (disableHoverableContent) {
            handleClose();
          } else {
            // Clear the timer in case the pointer leaves the trigger before the tooltip is opened.
            window.clearTimeout(openTimerRef.current);
            openTimerRef.current = 0;
          }
        }, [handleClose, disableHoverableContent])}
        onOpen={handleOpen}
        onClose={handleClose}
        disableHoverableContent={disableHoverableContent}
      >
        {children}
      </TooltipContextProvider>
    </PopperPrimitive.Root>
  );
};

Tooltip.displayName = TOOLTIP_NAME;

/* -------------------------------------------------------------------------------------------------
 * TooltipTrigger
 * -----------------------------------------------------------------------------------------------*/

const TRIGGER_NAME = 'TooltipTrigger';

type TooltipTriggerElement = React.ComponentRef<typeof Primitive.button>;
type PrimitiveButtonProps = React.ComponentPropsWithoutRef<typeof Primitive.button>;
interface TooltipTriggerProps extends PrimitiveButtonProps {}

const TooltipTrigger = React.forwardRef<TooltipTriggerElement, TooltipTriggerProps>(
  (props: ScopedProps<TooltipTriggerProps>, forwardedRef) => {
    const { __scopeTooltip, ...triggerProps } = props;
    const context = useTooltipContext(TRIGGER_NAME, __scopeTooltip);
    const providerContext = useTooltipProviderContext(TRIGGER_NAME, __scopeTooltip);
    const popperScope = usePopperScope(__scopeTooltip);
    const ref = React.useRef<TooltipTriggerElement>(null);
    const composedRefs = useComposedRefs(forwardedRef, ref, context.onTriggerChange);
    const isPointerDownRef = React.useRef(false);
    const hasPointerMoveOpenedRef = React.useRef(false);
    const handlePointerUp = React.useCallback(() => (isPointerDownRef.current = false), []);

    React.useEffect(() => {
      return () => document.removeEventListener('pointerup', handlePointerUp);
    }, [handlePointerUp]);

    return (
      <PopperPrimitive.Anchor asChild {...popperScope}>
        <Primitive.button
          // We purposefully avoid adding `type=button` here because tooltip triggers are also
          // commonly anchors and the anchor `type` attribute signifies MIME type.
          aria-describedby={context.open ? context.contentId : undefined}
          data-state={context.stateAttribute}
          {...triggerProps}
          ref={composedRefs}
          onPointerMove={composeEventHandlers(props.onPointerMove, (event) => {
            if (event.pointerType === 'touch') return;
            if (
              !hasPointerMoveOpenedRef.current &&
              !providerContext.isPointerInTransitRef.current
            ) {
              context.onTriggerEnter();
              hasPointerMoveOpenedRef.current = true;
            }
          })}
          onPointerLeave={composeEventHandlers(props.onPointerLeave, () => {
            context.onTriggerLeave();
            hasPointerMoveOpenedRef.current = false;
          })}
          onPointerDown={composeEventHandlers(props.onPointerDown, () => {
            if (context.open) {
              context.onClose();
            }
            isPointerDownRef.current = true;
            document.addEventListener('pointerup', handlePointerUp, { once: true });
          })}
          onFocus={composeEventHandlers(props.onFocus, () => {
            if (!isPointerDownRef.current) context.onOpen();
          })}
          onBlur={composeEventHandlers(props.onBlur, context.onClose)}
          onClick={composeEventHandlers(props.onClick, context.onClose)}
        />
      </PopperPrimitive.Anchor>
    );
  },
);

TooltipTrigger.displayName = TRIGGER_NAME;

/* -------------------------------------------------------------------------------------------------
 * TooltipPortal
 * -----------------------------------------------------------------------------------------------*/

const PORTAL_NAME = 'TooltipPortal';

type PortalContextValue = { forceMount?: true };
const [PortalProvider, usePortalContext] = createTooltipContext<PortalContextValue>(PORTAL_NAME, {
  forceMount: undefined,
});

type PortalProps = React.ComponentPropsWithoutRef<typeof PortalPrimitive>;
interface TooltipPortalProps {
  children?: React.ReactNode;
  /**
   * Specify a container element to portal the content into.
   */
  container?: PortalProps['container'];
  /**
   * Used to force mounting when more control is needed. Useful when
   * controlling animation with React animation libraries.
   */
  forceMount?: true;
}

const TooltipPortal: React.FC<TooltipPortalProps> = (props: ScopedProps<TooltipPortalProps>) => {
  const { __scopeTooltip, forceMount, children, container } = props;
  const context = useTooltipContext(PORTAL_NAME, __scopeTooltip);
  return (
    <PortalProvider scope={__scopeTooltip} forceMount={forceMount}>
      <Presence present={forceMount || context.open}>
        <PortalPrimitive asChild container={container}>
          {children}
        </PortalPrimitive>
      </Presence>
    </PortalProvider>
  );
};

TooltipPortal.displayName = PORTAL_NAME;

/* -------------------------------------------------------------------------------------------------
 * TooltipContent
 * -----------------------------------------------------------------------------------------------*/

const CONTENT_NAME = 'TooltipContent';

type TooltipContentElement = TooltipContentImplElement;
interface TooltipContentProps extends TooltipContentImplProps {
  /**
   * Used to force mounting when more control is needed. Useful when
   * controlling animation with React animation libraries.
   */
  forceMount?: true;
}

const TooltipContent = React.forwardRef<TooltipContentElement, TooltipContentProps>(
  (props: ScopedProps<TooltipContentProps>, forwardedRef) => {
    const portalContext = usePortalContext(CONTENT_NAME, props.__scopeTooltip);
    const { forceMount = portalContext.forceMount, side = 'top', ...contentProps } = props;
    const context = useTooltipContext(CONTENT_NAME, props.__scopeTooltip);

    return (
      <Presence present={forceMount || context.open}>
        {context.disableHoverableContent ? (
          <TooltipContentImpl side={side} {...contentProps} ref={forwardedRef} />
        ) : (
          <TooltipContentHoverable side={side} {...contentProps} ref={forwardedRef} />
        )}
      </Presence>
    );
  },
);

type Point = { x: number; y: number };
type Polygon = Point[];

type TooltipContentHoverableElement = TooltipContentImplElement;
interface TooltipContentHoverableProps extends TooltipContentImplProps {}

const TooltipContentHoverable = React.forwardRef<
  TooltipContentHoverableElement,
  TooltipContentHoverableProps
>((props: ScopedProps<TooltipContentHoverableProps>, forwardedRef) => {
  const context = useTooltipContext(CONTENT_NAME, props.__scopeTooltip);
  const providerContext = useTooltipProviderContext(CONTENT_NAME, props.__scopeTooltip);
  const ref = React.useRef<TooltipContentHoverableElement>(null);
  const composedRefs = useComposedRefs(forwardedRef, ref);
  const [pointerGraceArea, setPointerGraceArea] = React.useState<Polygon | null>(null);

  const { trigger, onClose } = context;
  const content = ref.current;

  const { onPointerInTransitChange } = providerContext;

  const handleRemoveGraceArea = React.useCallback(() => {
    setPointerGraceArea(null);
    onPointerInTransitChange(false);
  }, [onPointerInTransitChange]);

  const handleCreateGraceArea = React.useCallback(
    (event: PointerEvent, hoverTarget: HTMLElement) => {
      const currentTarget = event.currentTarget as HTMLElement;
      const exitPoint = { x: event.clientX, y: event.clientY };
      const exitSide = getExitSideFromRect(exitPoint, currentTarget.getBoundingClientRect());
      const paddedExitPoints = getPaddedExitPoints(exitPoint, exitSide);
      const hoverTargetPoints = getPointsFromRect(hoverTarget.getBoundingClientRect());
      const graceArea = getHull([...paddedExitPoints, ...hoverTargetPoints]);
      setPointerGraceArea(graceArea);
      onPointerInTransitChange(true);
    },
    [onPointerInTransitChange],
  );

  React.useEffect(() => {
    return () => handleRemoveGraceArea();
  }, [handleRemoveGraceArea]);

  React.useEffect(() => {
    if (trigger && content) {
      const handleTriggerLeave = (event: PointerEvent) => handleCreateGraceArea(event, content);
      const handleContentLeave = (event: PointerEvent) => handleCreateGraceArea(event, trigger);

      trigger.addEventListener('pointerleave', handleTriggerLeave);
      content.addEventListener('pointerleave', handleContentLeave);
      return () => {
        trigger.removeEventListener('pointerleave', handleTriggerLeave);
        content.removeEventListener('pointerleave', handleContentLeave);
      };
    }
  }, [trigger, content, handleCreateGraceArea, handleRemoveGraceArea]);

  React.useEffect(() => {
    if (pointerGraceArea) {
      const handleTrackPointerGrace = (event: PointerEvent) => {
        const target = event.target as HTMLElement;
        const pointerPosition = { x: event.clientX, y: event.clientY };
        const hasEnteredTarget = trigger?.contains(target) || content?.contains(target);
        const isPointerOutsideGraceArea = !isPointInPolygon(pointerPosition, pointerGraceArea);

        if (hasEnteredTarget) {
          handleRemoveGraceArea();
        } else if (isPointerOutsideGraceArea) {
          handleRemoveGraceArea();
          onClose();
        }
      };
      document.addEventListener('pointermove', handleTrackPointerGrace);
      return () => document.removeEventListener('pointermove', handleTrackPointerGrace);
    }
  }, [trigger, content, pointerGraceArea, onClose, handleRemoveGraceArea]);

  return <TooltipContentImpl {...props} ref={composedRefs} />;
});

const [VisuallyHiddenContentContextProvider, useVisuallyHiddenContentContext] =
  createTooltipContext(TOOLTIP_NAME, { isInside: false });

type TooltipContentImplElement = React.ComponentRef<typeof PopperPrimitive.Content>;
type DismissableLayerProps = React.ComponentPropsWithoutRef<typeof DismissableLayer>;
type PopperContentProps = React.ComponentPropsWithoutRef<typeof PopperPrimitive.Content>;
interface TooltipContentImplProps extends Omit<PopperContentProps, 'onPlaced'> {
  /**
   * A more descriptive label for accessibility purpose
   */
  'aria-label'?: string;

  /**
   * Event handler called when the escape key is down.
   * Can be prevented.
   */
  onEscapeKeyDown?: DismissableLayerProps['onEscapeKeyDown'];
  /**
   * Event handler called when the a `pointerdown` event happens outside of the `Tooltip`.
   * Can be prevented.
   */
  onPointerDownOutside?: DismissableLayerProps['onPointerDownOutside'];
}

const Slottable = createSlottable('TooltipContent');

const TooltipContentImpl = React.forwardRef<TooltipContentImplElement, TooltipContentImplProps>(
  (props: ScopedProps<TooltipContentImplProps>, forwardedRef) => {
    const {
      __scopeTooltip,
      children,
      'aria-label': ariaLabel,
      onEscapeKeyDown,
      onPointerDownOutside,
      ...contentProps
    } = props;
    const context = useTooltipContext(CONTENT_NAME, __scopeTooltip);
    const popperScope = usePopperScope(__scopeTooltip);
    const { onClose } = context;

    // Close this tooltip if another one opens
    React.useEffect(() => {
      document.addEventListener(TOOLTIP_OPEN, onClose);
      return () => document.removeEventListener(TOOLTIP_OPEN, onClose);
    }, [onClose]);

    // Close the tooltip if the trigger is scrolled
    React.useEffect(() => {
      if (context.trigger) {
        const handleScroll = (event: Event) => {
          const target = event.target as HTMLElement;
          if (target?.contains(context.trigger)) onClose();
        };
        window.addEventListener('scroll', handleScroll, { capture: true });
        return () => window.removeEventListener('scroll', handleScroll, { capture: true });
      }
    }, [context.trigger, onClose]);

    return (
      <DismissableLayer
        asChild
        disableOutsidePointerEvents={false}
        onEscapeKeyDown={onEscapeKeyDown}
        onPointerDownOutside={onPointerDownOutside}
        onFocusOutside={(event) => event.preventDefault()}
        onDismiss={onClose}
      >
        <PopperPrimitive.Content
          data-state={context.stateAttribute}
          {...popperScope}
          {...contentProps}
          ref={forwardedRef}
          style={{
            ...contentProps.style,
            // re-namespace exposed content custom properties
            ...{
              '--radix-tooltip-content-transform-origin': 'var(--radix-popper-transform-origin)',
              '--radix-tooltip-content-available-width': 'var(--radix-popper-available-width)',
              '--radix-tooltip-content-available-height': 'var(--radix-popper-available-height)',
              '--radix-tooltip-trigger-width': 'var(--radix-popper-anchor-width)',
              '--radix-tooltip-trigger-height': 'var(--radix-popper-anchor-height)',
            },
          }}
        >
          <Slottable>{children}</Slottable>
          <VisuallyHiddenContentContextProvider scope={__scopeTooltip} isInside={true}>
            <VisuallyHiddenPrimitive.Root id={context.contentId} role="tooltip">
              {ariaLabel || children}
            </VisuallyHiddenPrimitive.Root>
          </VisuallyHiddenContentContextProvider>
        </PopperPrimitive.Content>
      </DismissableLayer>
    );
  },
);

TooltipContent.displayName = CONTENT_NAME;

/* -------------------------------------------------------------------------------------------------
 * TooltipArrow
 * -----------------------------------------------------------------------------------------------*/

const ARROW_NAME = 'TooltipArrow';

type TooltipArrowElement = React.ComponentRef<typeof PopperPrimitive.Arrow>;
type PopperArrowProps = React.ComponentPropsWithoutRef<typeof PopperPrimitive.Arrow>;
interface TooltipArrowProps extends PopperArrowProps {}

const TooltipArrow = React.forwardRef<TooltipArrowElement, TooltipArrowProps>(
  (props: ScopedProps<TooltipArrowProps>, forwardedRef) => {
    const { __scopeTooltip, ...arrowProps } = props;
    const popperScope = usePopperScope(__scopeTooltip);
    const visuallyHiddenContentContext = useVisuallyHiddenContentContext(
      ARROW_NAME,
      __scopeTooltip,
    );
    // if the arrow is inside the `VisuallyHidden`, we don't want to render it all to
    // prevent issues in positioning the arrow due to the duplicate
    return visuallyHiddenContentContext.isInside ? null : (
      <PopperPrimitive.Arrow {...popperScope} {...arrowProps} ref={forwardedRef} />
    );
  },
);

TooltipArrow.displayName = ARROW_NAME;

/* -----------------------------------------------------------------------------------------------*/

type Side = NonNullable<TooltipContentProps['side']>;

function getExitSideFromRect(point: Point, rect: DOMRect): Side {
  const top = Math.abs(rect.top - point.y);
  const bottom = Math.abs(rect.bottom - point.y);
  const right = Math.abs(rect.right - point.x);
  const left = Math.abs(rect.left - point.x);

  switch (Math.min(top, bottom, right, left)) {
    case left:
      return 'left';
    case right:
      return 'right';
    case top:
      return 'top';
    case bottom:
      return 'bottom';
    default:
      throw new Error('unreachable');
  }
}

function getPaddedExitPoints(exitPoint: Point, exitSide: Side, padding = 5) {
  const paddedExitPoints: Point[] = [];
  switch (exitSide) {
    case 'top':
      paddedExitPoints.push(
        { x: exitPoint.x - padding, y: exitPoint.y + padding },
        { x: exitPoint.x + padding, y: exitPoint.y + padding },
      );
      break;
    case 'bottom':
      paddedExitPoints.push(
        { x: exitPoint.x - padding, y: exitPoint.y - padding },
        { x: exitPoint.x + padding, y: exitPoint.y - padding },
      );
      break;
    case 'left':
      paddedExitPoints.push(
        { x: exitPoint.x + padding, y: exitPoint.y - padding },
        { x: exitPoint.x + padding, y: exitPoint.y + padding },
      );
      break;
    case 'right':
      paddedExitPoints.push(
        { x: exitPoint.x - padding, y: exitPoint.y - padding },
        { x: exitPoint.x - padding, y: exitPoint.y + padding },
      );
      break;
  }
  return paddedExitPoints;
}

function getPointsFromRect(rect: DOMRect) {
  const { top, right, bottom, left } = rect;
  return [
    { x: left, y: top },
    { x: right, y: top },
    { x: right, y: bottom },
    { x: left, y: bottom },
  ];
}

// Determine if a point is inside of a polygon.
// Based on https://github.com/substack/point-in-polygon
function isPointInPolygon(point: Point, polygon: Polygon) {
  const { x, y } = point;
  let inside = false;
  for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
    const ii = polygon[i]!;
    const jj = polygon[j]!;
    const xi = ii.x;
    const yi = ii.y;
    const xj = jj.x;
    const yj = jj.y;

    // prettier-ignore
    const intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
    if (intersect) inside = !inside;
  }

  return inside;
}

// Returns a new array of points representing the convex hull of the given set of points.
// https://www.nayuki.io/page/convex-hull-algorithm
function getHull<P extends Point>(points: Readonly<Array<P>>): Array<P> {
  const newPoints: Array<P> = points.slice();
  newPoints.sort((a: Point, b: Point) => {
    if (a.x < b.x) return -1;
    else if (a.x > b.x) return +1;
    else if (a.y < b.y) return -1;
    else if (a.y > b.y) return +1;
    else return 0;
  });
  return getHullPresorted(newPoints);
}

// Returns the convex hull, assuming that each points[i] <= points[i + 1]. Runs in O(n) time.
function getHullPresorted<P extends Point>(points: Readonly<Array<P>>): Array<P> {
  if (points.length <= 1) return points.slice();

  const upperHull: Array<P> = [];
  for (let i = 0; i < points.length; i++) {
    const p = points[i]!;
    while (upperHull.length >= 2) {
      const q = upperHull[upperHull.length - 1]!;
      const r = upperHull[upperHull.length - 2]!;
      if ((q.x - r.x) * (p.y - r.y) >= (q.y - r.y) * (p.x - r.x)) upperHull.pop();
      else break;
    }
    upperHull.push(p);
  }
  upperHull.pop();

  const lowerHull: Array<P> = [];
  for (let i = points.length - 1; i >= 0; i--) {
    const p = points[i]!;
    while (lowerHull.length >= 2) {
      const q = lowerHull[lowerHull.length - 1]!;
      const r = lowerHull[lowerHull.length - 2]!;
      if ((q.x - r.x) * (p.y - r.y) >= (q.y - r.y) * (p.x - r.x)) lowerHull.pop();
      else break;
    }
    lowerHull.push(p);
  }
  lowerHull.pop();

  if (
    upperHull.length === 1 &&
    lowerHull.length === 1 &&
    upperHull[0]!.x === lowerHull[0]!.x &&
    upperHull[0]!.y === lowerHull[0]!.y
  ) {
    return upperHull;
  } else {
    return upperHull.concat(lowerHull);
  }
}

const Provider = TooltipProvider;
const Root = Tooltip;
const Trigger = TooltipTrigger;
const Portal = TooltipPortal;
const Content = TooltipContent;
const Arrow = TooltipArrow;

export {
  createTooltipScope,
  //
  TooltipProvider,
  Tooltip,
  TooltipTrigger,
  TooltipPortal,
  TooltipContent,
  TooltipArrow,
  //
  Provider,
  Root,
  Trigger,
  Portal,
  Content,
  Arrow,
};
export type {
  TooltipProviderProps,
  TooltipProps,
  TooltipTriggerProps,
  TooltipPortalProps,
  TooltipContentProps,
  TooltipArrowProps,
};



================================================
FILE: packages/react/use-callback-ref/README.md
================================================
# `react-use-callback-ref`

This is an internal utility, not intended for public usage.



================================================
FILE: packages/react/use-callback-ref/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/use-callback-ref/package.json
================================================
{
  "name": "@radix-ui/react-use-callback-ref",
  "version": "1.1.1",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/use-callback-ref/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/use-callback-ref/src/index.ts
================================================
export { useCallbackRef } from './use-callback-ref';



================================================
FILE: packages/react/use-callback-ref/src/use-callback-ref.tsx
================================================
import * as React from 'react';

/**
 * A custom hook that converts a callback to a ref to avoid triggering re-renders when passed as a
 * prop or avoid re-executing effects when passed as a dependency
 */
function useCallbackRef<T extends (...args: any[]) => any>(callback: T | undefined): T {
  const callbackRef = React.useRef(callback);

  React.useEffect(() => {
    callbackRef.current = callback;
  });

  // https://github.com/facebook/react/issues/19240
  return React.useMemo(() => ((...args) => callbackRef.current?.(...args)) as T, []);
}

export { useCallbackRef };



================================================
FILE: packages/react/use-controllable-state/README.md
================================================
# `react-use-controllable-state`

This is an internal utility, not intended for public usage.



================================================
FILE: packages/react/use-controllable-state/CHANGELOG.md
================================================
# @radix-ui/react-use-controllable-state

## 1.2.2

- Updated dependencies: `@radix-ui/react-use-effect-event@0.0.2`

## 1.2.1

- Updated dependencies: `@radix-ui/react-use-effect-event@0.0.1`

## 1.2.0

- Minor improvements to `useControllableState` to enhance performance, reduce surface area for bugs, and log warnings when misused (#3455)



================================================
FILE: packages/react/use-controllable-state/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/use-controllable-state/package.json
================================================
{
  "name": "@radix-ui/react-use-controllable-state",
  "version": "1.2.2",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/react-use-effect-event": "workspace:*",
    "@radix-ui/react-use-layout-effect": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/use-controllable-state/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/use-controllable-state/src/index.ts
================================================
export { useControllableState } from './use-controllable-state';
export { useControllableStateReducer } from './use-controllable-state-reducer';



================================================
FILE: packages/react/use-controllable-state/src/use-controllable-state-reducer.tsx
================================================
import * as React from 'react';
import { useEffectEvent } from '@radix-ui/react-use-effect-event';

type ChangeHandler<T> = (state: T) => void;

interface UseControllableStateParams<T> {
  prop: T | undefined;
  defaultProp: T;
  onChange: ChangeHandler<T> | undefined;
  caller: string;
}

interface AnyAction {
  type: string;
}

const SYNC_STATE = Symbol('RADIX:SYNC_STATE');

interface SyncStateAction<T> {
  type: typeof SYNC_STATE;
  state: T;
}

export function useControllableStateReducer<T, S extends {}, A extends AnyAction>(
  reducer: (prevState: S & { state: T }, action: A) => S & { state: T },
  userArgs: UseControllableStateParams<T>,
  initialState: S,
): [S & { state: T }, React.Dispatch<A>];

export function useControllableStateReducer<T, S extends {}, I, A extends AnyAction>(
  reducer: (prevState: S & { state: T }, action: A) => S & { state: T },
  userArgs: UseControllableStateParams<T>,
  initialArg: I,
  init: (i: I & { state: T }) => S,
): [S & { state: T }, React.Dispatch<A>];

export function useControllableStateReducer<T, S extends {}, A extends AnyAction>(
  reducer: (prevState: S & { state: T }, action: A) => S & { state: T },
  userArgs: UseControllableStateParams<T>,
  initialArg: any,
  init?: (i: any) => Omit<S, 'state'>,
): [S & { state: T }, React.Dispatch<A>] {
  const { prop: controlledState, defaultProp, onChange: onChangeProp, caller } = userArgs;
  const isControlled = controlledState !== undefined;

  const onChange = useEffectEvent(onChangeProp);

  // OK to disable conditionally calling hooks here because they will always run
  // consistently in the same environment. Bundlers should be able to remove the
  // code block entirely in production.
  /* eslint-disable react-hooks/rules-of-hooks */
  if (process.env.NODE_ENV !== 'production') {
    const isControlledRef = React.useRef(controlledState !== undefined);
    React.useEffect(() => {
      const wasControlled = isControlledRef.current;
      if (wasControlled !== isControlled) {
        const from = wasControlled ? 'controlled' : 'uncontrolled';
        const to = isControlled ? 'controlled' : 'uncontrolled';
        console.warn(
          `${caller} is changing from ${from} to ${to}. Components should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled value for the lifetime of the component.`,
        );
      }
      isControlledRef.current = isControlled;
    }, [isControlled, caller]);
  }
  /* eslint-enable react-hooks/rules-of-hooks */

  type InternalState = S & { state: T };
  const args: [InternalState] = [{ ...initialArg, state: defaultProp }];
  if (init) {
    // @ts-expect-error
    args.push(init);
  }

  const [internalState, dispatch] = React.useReducer(
    (state: InternalState, action: A | SyncStateAction<T>): InternalState => {
      if (action.type === SYNC_STATE) {
        return { ...state, state: action.state };
      }

      const next = reducer(state, action);
      if (isControlled && !Object.is(next.state, state.state)) {
        onChange(next.state);
      }
      return next;
    },
    ...args,
  );

  const uncontrolledState = internalState.state;
  const prevValueRef = React.useRef(uncontrolledState);
  React.useEffect(() => {
    if (prevValueRef.current !== uncontrolledState) {
      prevValueRef.current = uncontrolledState;
      if (!isControlled) {
        onChange(uncontrolledState);
      }
    }
  }, [onChange, uncontrolledState, prevValueRef, isControlled]);

  const state = React.useMemo(() => {
    const isControlled = controlledState !== undefined;
    if (isControlled) {
      return { ...internalState, state: controlledState };
    }

    return internalState;
  }, [internalState, controlledState]);

  React.useEffect(() => {
    // Sync internal state for controlled components so that reducer is called
    // with the correct state values
    if (isControlled && !Object.is(controlledState, internalState.state)) {
      dispatch({ type: SYNC_STATE, state: controlledState });
    }
  }, [controlledState, internalState.state, isControlled]);

  return [state, dispatch as React.Dispatch<A>];
}



================================================
FILE: packages/react/use-controllable-state/src/use-controllable-state.test.tsx
================================================
import * as React from 'react';
import { screen, cleanup, render, waitFor } from '@testing-library/react';
import { useControllableState } from './use-controllable-state';
import { afterEach, describe, it, expect, afterAll, vi } from 'vitest';
import userEvent from '@testing-library/user-event';

describe('useControllableState', () => {
  afterEach(cleanup);

  describe('given a controlled value', () => {
    it('should initially use the controlled value', () => {
      render(<ControlledComponent />);
      const checkbox = screen.getByRole('checkbox');
      expect(checkbox).toHaveAttribute('aria-checked', 'false');
    });

    it('should update the value when set internally', async () => {
      render(<ControlledComponent />);
      const checkbox = screen.getByRole('checkbox');
      userEvent.click(checkbox);
      await waitFor(() => {
        expect(checkbox).toHaveAttribute('aria-checked', 'true');
      });
    });

    it('should update the value when set externally', async () => {
      render(<ControlledComponent defaultChecked />);
      const checkbox = screen.getByRole('checkbox');
      const clearButton = screen.getByText('Clear value');
      userEvent.click(clearButton);
      await waitFor(() => {
        expect(checkbox).toHaveAttribute('aria-checked', 'false');
      });
    });
  });

  describe('given a default value', () => {
    it('should initially use the default value', () => {
      render(<UncontrolledComponent defaultChecked />);
      const checkbox = screen.getByRole('checkbox');
      expect(checkbox).toHaveAttribute('aria-checked', 'true');
    });

    it('should update the value', async () => {
      render(<UncontrolledComponent defaultChecked />);
      const checkbox = screen.getByRole('checkbox');
      userEvent.click(checkbox);
      await waitFor(() => {
        expect(checkbox).toHaveAttribute('aria-checked', 'false');
      });
    });
  });

  describe('switching between controlled and uncontrolled', () => {
    const consoleMock = vi.spyOn(console, 'warn').mockImplementation(() => void 0);
    afterAll(() => {
      consoleMock.mockReset();
    });

    describe('controlled to uncontrolled', () => {
      it('should warn', async () => {
        render(<UnstableComponent defaultChecked />);
        const clearButton = screen.getByText('Clear value');
        userEvent.click(clearButton);
        await waitFor(() => {
          expect(consoleMock).toHaveBeenLastCalledWith(
            'Checkbox is changing from controlled to uncontrolled. Components should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled value for the lifetime of the component.',
          );
        });
      });
    });

    describe('uncontrolled to controlled', () => {
      it('should warn', async () => {
        render(<UnstableComponent />);
        const checkbox = screen.getByRole('checkbox');
        userEvent.click(checkbox);
        await waitFor(() => {
          expect(consoleMock).toHaveBeenLastCalledWith(
            'Checkbox is changing from uncontrolled to controlled. Components should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled value for the lifetime of the component.',
          );
        });
      });
    });
  });
});

function ControlledComponent({ defaultChecked }: { defaultChecked?: boolean }) {
  const [checked, setChecked] = React.useState(defaultChecked ?? false);
  return (
    <div>
      <Checkbox checked={checked} onChange={setChecked} />
      <button type="button" onClick={() => setChecked(false)}>
        Clear value
      </button>
    </div>
  );
}

function UncontrolledComponent({ defaultChecked }: { defaultChecked?: boolean }) {
  return <Checkbox defaultChecked={defaultChecked} />;
}

function UnstableComponent({ defaultChecked }: { defaultChecked?: boolean }) {
  const [checked, setChecked] = React.useState(defaultChecked);
  return (
    <div>
      <Checkbox checked={checked} onChange={setChecked} />
      <button type="button" onClick={() => setChecked(undefined)}>
        Clear value
      </button>
    </div>
  );
}

function Checkbox(props: {
  checked?: boolean;
  defaultChecked?: boolean;
  onChange?: (value: boolean) => void;
}) {
  const [checked, setChecked] = useControllableState({
    defaultProp: props.defaultChecked ?? false,
    prop: props.checked,
    onChange: props.onChange,
    caller: 'Checkbox',
  });

  return (
    <button
      type="button"
      role="checkbox"
      aria-checked={checked}
      onKeyDown={(e) => void (e.key === 'Enter' && e.preventDefault())}
      onClick={() => setChecked((c) => !c)}
    />
  );
}



================================================
FILE: packages/react/use-controllable-state/src/use-controllable-state.tsx
================================================
import * as React from 'react';
import { useLayoutEffect } from '@radix-ui/react-use-layout-effect';

// Prevent bundlers from trying to optimize the import
const useInsertionEffect: typeof useLayoutEffect =
  (React as any)[' useInsertionEffect '.trim().toString()] || useLayoutEffect;

type ChangeHandler<T> = (state: T) => void;
type SetStateFn<T> = React.Dispatch<React.SetStateAction<T>>;

interface UseControllableStateParams<T> {
  prop?: T | undefined;
  defaultProp: T;
  onChange?: ChangeHandler<T>;
  caller?: string;
}

export function useControllableState<T>({
  prop,
  defaultProp,
  onChange = () => {},
  caller,
}: UseControllableStateParams<T>): [T, SetStateFn<T>] {
  const [uncontrolledProp, setUncontrolledProp, onChangeRef] = useUncontrolledState({
    defaultProp,
    onChange,
  });
  const isControlled = prop !== undefined;
  const value = isControlled ? prop : uncontrolledProp;

  // OK to disable conditionally calling hooks here because they will always run
  // consistently in the same environment. Bundlers should be able to remove the
  // code block entirely in production.
  /* eslint-disable react-hooks/rules-of-hooks */
  if (process.env.NODE_ENV !== 'production') {
    const isControlledRef = React.useRef(prop !== undefined);
    React.useEffect(() => {
      const wasControlled = isControlledRef.current;
      if (wasControlled !== isControlled) {
        const from = wasControlled ? 'controlled' : 'uncontrolled';
        const to = isControlled ? 'controlled' : 'uncontrolled';
        console.warn(
          `${caller} is changing from ${from} to ${to}. Components should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled value for the lifetime of the component.`,
        );
      }
      isControlledRef.current = isControlled;
    }, [isControlled, caller]);
  }
  /* eslint-enable react-hooks/rules-of-hooks */

  const setValue = React.useCallback<SetStateFn<T>>(
    (nextValue) => {
      if (isControlled) {
        const value = isFunction(nextValue) ? nextValue(prop) : nextValue;
        if (value !== prop) {
          onChangeRef.current?.(value);
        }
      } else {
        setUncontrolledProp(nextValue);
      }
    },
    [isControlled, prop, setUncontrolledProp, onChangeRef],
  );

  return [value, setValue];
}

function useUncontrolledState<T>({
  defaultProp,
  onChange,
}: Omit<UseControllableStateParams<T>, 'prop'>): [
  Value: T,
  setValue: React.Dispatch<React.SetStateAction<T>>,
  OnChangeRef: React.RefObject<ChangeHandler<T> | undefined>,
] {
  const [value, setValue] = React.useState(defaultProp);
  const prevValueRef = React.useRef(value);

  const onChangeRef = React.useRef(onChange);
  useInsertionEffect(() => {
    onChangeRef.current = onChange;
  }, [onChange]);

  React.useEffect(() => {
    if (prevValueRef.current !== value) {
      onChangeRef.current?.(value);
      prevValueRef.current = value;
    }
  }, [value, prevValueRef]);

  return [value, setValue, onChangeRef];
}

function isFunction(value: unknown): value is (...args: any[]) => any {
  return typeof value === 'function';
}



================================================
FILE: packages/react/use-effect-event/README.md
================================================
# `react-use-is-hydrated`

## Usage

This is an internal utility, not intended for public usage.



================================================
FILE: packages/react/use-effect-event/CHANGELOG.md
================================================
# @radix-ui/react-use-effect-event

## 0.0.2

- Patch additional issues with conditional React imports

## 0.0.1

- Update how potentially missing React APIs are imported to breaking webpack builds. See https://github.com/radix-ui/primitives/issues/3485.



================================================
FILE: packages/react/use-effect-event/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/use-effect-event/package.json
================================================
{
  "name": "@radix-ui/react-use-effect-event",
  "version": "0.0.2",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "src",
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "peerDependencies": {
    "@types/react": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    }
  },
  "dependencies": {
    "@radix-ui/react-use-layout-effect": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "@types/use-sync-external-store": "^0.0.6",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/use-effect-event/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/use-effect-event/src/index.ts
================================================
export { useEffectEvent } from './use-effect-event';



================================================
FILE: packages/react/use-effect-event/src/use-effect-event.tsx
================================================
/* eslint-disable react-hooks/rules-of-hooks */
import { useLayoutEffect } from '@radix-ui/react-use-layout-effect';
import * as React from 'react';

type AnyFunction = (...args: any[]) => any;

// See https://github.com/webpack/webpack/issues/14814
const useReactEffectEvent = (React as any)[' useEffectEvent '.trim().toString()];
const useReactInsertionEffect = (React as any)[' useInsertionEffect '.trim().toString()];

/**
 * Designed to approximate the behavior on `experimental_useEffectEvent` as best
 * as possible until its stable release, and back-fill it as a shim as needed.
 */
export function useEffectEvent<T extends AnyFunction>(callback?: T): T {
  if (typeof useReactEffectEvent === 'function') {
    return useReactEffectEvent(callback);
  }

  const ref = React.useRef<AnyFunction | undefined>(() => {
    throw new Error('Cannot call an event handler while rendering.');
  });
  // See https://github.com/webpack/webpack/issues/14814
  if (typeof useReactInsertionEffect === 'function') {
    useReactInsertionEffect(() => {
      ref.current = callback;
    });
  } else {
    useLayoutEffect(() => {
      ref.current = callback;
    });
  }

  // https://github.com/facebook/react/issues/19240
  return React.useMemo(() => ((...args) => ref.current?.(...args)) as T, []);
}



================================================
FILE: packages/react/use-escape-keydown/README.md
================================================
# `react-use-escape-keydown`

This is an internal utility, not intended for public usage.



================================================
FILE: packages/react/use-escape-keydown/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/use-escape-keydown/package.json
================================================
{
  "name": "@radix-ui/react-use-escape-keydown",
  "version": "1.1.1",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/react-use-callback-ref": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/use-escape-keydown/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/use-escape-keydown/src/index.ts
================================================
export { useEscapeKeydown } from './use-escape-keydown';



================================================
FILE: packages/react/use-escape-keydown/src/use-escape-keydown.tsx
================================================
import * as React from 'react';
import { useCallbackRef } from '@radix-ui/react-use-callback-ref';

/**
 * Listens for when the escape key is down
 */
function useEscapeKeydown(
  onEscapeKeyDownProp?: (event: KeyboardEvent) => void,
  ownerDocument: Document = globalThis?.document,
) {
  const onEscapeKeyDown = useCallbackRef(onEscapeKeyDownProp);

  React.useEffect(() => {
    const handleKeyDown = (event: KeyboardEvent) => {
      if (event.key === 'Escape') {
        onEscapeKeyDown(event);
      }
    };
    ownerDocument.addEventListener('keydown', handleKeyDown, { capture: true });
    return () => ownerDocument.removeEventListener('keydown', handleKeyDown, { capture: true });
  }, [onEscapeKeyDown, ownerDocument]);
}

export { useEscapeKeydown };



================================================
FILE: packages/react/use-is-hydrated/README.md
================================================
# `react-use-is-hydrated`

## Usage

This is an internal utility, not intended for public usage.



================================================
FILE: packages/react/use-is-hydrated/CHANGELOG.md
================================================
# @radix-ui/react-use-is-hydrated

## 0.1.0

- Update the dependency for `use-sync-external-store` to ensure entrypoint is valid



================================================
FILE: packages/react/use-is-hydrated/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/use-is-hydrated/package.json
================================================
{
  "name": "@radix-ui/react-use-is-hydrated",
  "version": "0.1.0",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "src",
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "use-sync-external-store": "^1.5.0"
  },
  "peerDependencies": {
    "@types/react": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    }
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "@types/use-sync-external-store": "^0.0.6",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/use-is-hydrated/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/use-is-hydrated/src/index.ts
================================================
export { useIsHydrated } from './use-is-hydrated';



================================================
FILE: packages/react/use-is-hydrated/src/use-is-hydrated.tsx
================================================
import { useSyncExternalStore } from 'use-sync-external-store/shim';

/**
 * Determines whether or not the component tree has been hydrated.
 */
export function useIsHydrated() {
  return useSyncExternalStore(
    subscribe,
    () => true,
    () => false,
  );
}

function subscribe() {
  return () => {};
}



================================================
FILE: packages/react/use-layout-effect/README.md
================================================
# `react-use-layout-effect`

This is an internal utility, not intended for public usage.



================================================
FILE: packages/react/use-layout-effect/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/use-layout-effect/package.json
================================================
{
  "name": "@radix-ui/react-use-layout-effect",
  "version": "1.1.1",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/use-layout-effect/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/use-layout-effect/src/index.ts
================================================
export { useLayoutEffect } from './use-layout-effect';



================================================
FILE: packages/react/use-layout-effect/src/use-layout-effect.tsx
================================================
import * as React from 'react';

/**
 * On the server, React emits a warning when calling `useLayoutEffect`.
 * This is because neither `useLayoutEffect` nor `useEffect` run on the server.
 * We use this safe version which suppresses the warning by replacing it with a noop on the server.
 *
 * See: https://reactjs.org/docs/hooks-reference.html#uselayouteffect
 */
const useLayoutEffect = globalThis?.document ? React.useLayoutEffect : () => {};

export { useLayoutEffect };



================================================
FILE: packages/react/use-previous/README.md
================================================
# `react-use-previous`

This is an internal utility, not intended for public usage.



================================================
FILE: packages/react/use-previous/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/use-previous/package.json
================================================
{
  "name": "@radix-ui/react-use-previous",
  "version": "1.1.1",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/use-previous/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/use-previous/src/index.ts
================================================
export { usePrevious } from './use-previous';



================================================
FILE: packages/react/use-previous/src/use-previous.tsx
================================================
import * as React from 'react';

function usePrevious<T>(value: T) {
  const ref = React.useRef({ value, previous: value });

  // We compare values before making an update to ensure that
  // a change has been made. This ensures the previous value is
  // persisted correctly between renders.
  return React.useMemo(() => {
    if (ref.current.value !== value) {
      ref.current.previous = ref.current.value;
      ref.current.value = value;
    }
    return ref.current.previous;
  }, [value]);
}

export { usePrevious };



================================================
FILE: packages/react/use-rect/README.md
================================================
# `react-use-rect`

This is an internal utility, not intended for public usage.



================================================
FILE: packages/react/use-rect/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/use-rect/package.json
================================================
{
  "name": "@radix-ui/react-use-rect",
  "version": "1.1.1",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/rect": "workspace:*"
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {
    "@types/react": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    }
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/use-rect/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/use-rect/src/index.ts
================================================
export { useRect } from './use-rect';



================================================
FILE: packages/react/use-rect/src/use-rect.tsx
================================================
import * as React from 'react';
import { observeElementRect } from '@radix-ui/rect';

import type { Measurable } from '@radix-ui/rect';

/**
 * Use this custom hook to get access to an element's rect (getBoundingClientRect)
 * and observe it along time.
 */
function useRect(measurable: Measurable | null) {
  const [rect, setRect] = React.useState<DOMRect>();
  React.useEffect(() => {
    if (measurable) {
      const unobserve = observeElementRect(measurable, setRect);
      return () => {
        setRect(undefined);
        unobserve();
      };
    }
    return;
  }, [measurable]);
  return rect;
}

export { useRect };



================================================
FILE: packages/react/use-size/README.md
================================================
# `react-use-size`

This is an internal utility, not intended for public usage.



================================================
FILE: packages/react/use-size/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/use-size/package.json
================================================
{
  "name": "@radix-ui/react-use-size",
  "version": "1.1.1",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/react-use-layout-effect": "workspace:*"
  },
  "peerDependencies": {
    "@types/react": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    }
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/use-size/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/use-size/src/index.ts
================================================
export { useSize } from './use-size';



================================================
FILE: packages/react/use-size/src/use-size.tsx
================================================
import * as React from 'react';
import { useLayoutEffect } from '@radix-ui/react-use-layout-effect';

function useSize(element: HTMLElement | null) {
  const [size, setSize] = React.useState<{ width: number; height: number } | undefined>(undefined);

  useLayoutEffect(() => {
    if (element) {
      // provide size as early as possible
      setSize({ width: element.offsetWidth, height: element.offsetHeight });

      const resizeObserver = new ResizeObserver((entries) => {
        if (!Array.isArray(entries)) {
          return;
        }

        // Since we only observe the one element, we don't need to loop over the
        // array
        if (!entries.length) {
          return;
        }

        const entry = entries[0]!;
        let width: number;
        let height: number;

        if ('borderBoxSize' in entry) {
          const borderSizeEntry = entry['borderBoxSize'];
          // iron out differences between browsers
          const borderSize = Array.isArray(borderSizeEntry) ? borderSizeEntry[0] : borderSizeEntry;
          width = borderSize['inlineSize'];
          height = borderSize['blockSize'];
        } else {
          // for browsers that don't support `borderBoxSize`
          // we calculate it ourselves to get the correct border box.
          width = element.offsetWidth;
          height = element.offsetHeight;
        }

        setSize({ width, height });
      });

      resizeObserver.observe(element, { box: 'border-box' });

      return () => resizeObserver.unobserve(element);
    } else {
      // We only want to reset to `undefined` when the element becomes `null`,
      // not if it changes to another element.
      setSize(undefined);
    }
  }, [element]);

  return size;
}

export { useSize };



================================================
FILE: packages/react/visually-hidden/README.md
================================================
# `react-visually-hidden`

View docs [here](https://radix-ui.com/primitives/docs/utilities/visually-hidden).



================================================
FILE: packages/react/visually-hidden/CHANGELOG.md
================================================
# @radix-ui/react-visually-hidden

## 1.2.4

- Updated dependencies: `@radix-ui/react-primitive@2.1.4`

## 1.2.3

- Replace deprecated 'ElementRef' with 'ComponentRef' (#3426)
- Updated dependencies: `@radix-ui/react-primitive@2.1.3`

## 1.2.2

- Updated dependencies: `@radix-ui/react-primitive@2.1.2`

## 1.2.1

- Updated dependencies: `@radix-ui/react-primitive@2.1.1`

## 1.2.0

- All form controls with internal bubble inputs now use the Radix `Primitive` component by default. This will allow us to expose these components directly so users can better control this behavior in the future.
- Updated dependencies: `@radix-ui/react-primitive@2.1.0`



================================================
FILE: packages/react/visually-hidden/eslint.config.mjs
================================================
// @ts-check
import { configs } from '@repo/eslint-config/react-package';

export default configs;



================================================
FILE: packages/react/visually-hidden/package.json
================================================
{
  "name": "@radix-ui/react-visually-hidden",
  "version": "1.2.4",
  "license": "MIT",
  "source": "./src/index.ts",
  "main": "./src/index.ts",
  "module": "./src/index.ts",
  "publishConfig": {
    "main": "./dist/index.js",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.ts",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.mts",
          "default": "./dist/index.mjs"
        },
        "require": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  },
  "files": [
    "dist",
    "README.md"
  ],
  "sideEffects": false,
  "scripts": {
    "lint": "eslint --max-warnings 0 src",
    "clean": "rm -rf dist",
    "reset": "rm -rf dist node_modules",
    "typecheck": "tsc --noEmit",
    "build": "radix-build"
  },
  "dependencies": {
    "@radix-ui/react-primitive": "workspace:*"
  },
  "peerDependencies": {
    "@types/react": "*",
    "@types/react-dom": "*",
    "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
    "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    }
  },
  "devDependencies": {
    "@repo/builder": "workspace:*",
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.2",
    "eslint": "^9.38.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "typescript": "^5.9.3"
  },
  "homepage": "https://radix-ui.com/primitives",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/radix-ui/primitives.git"
  },
  "bugs": {
    "url": "https://github.com/radix-ui/primitives/issues"
  }
}



================================================
FILE: packages/react/visually-hidden/tsconfig.json
================================================
{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["@repo/typescript-config/react-library"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}



================================================
FILE: packages/react/visually-hidden/src/index.ts
================================================
export {
  VisuallyHidden,
  //
  Root,
  //
  VISUALLY_HIDDEN_STYLES,
} from './visually-hidden';
export type { VisuallyHiddenProps } from './visually-hidden';



================================================
FILE: packages/react/visually-hidden/src/visually-hidden.tsx
================================================
import * as React from 'react';
import { Primitive } from '@radix-ui/react-primitive';

/* -------------------------------------------------------------------------------------------------
 * VisuallyHidden
 * -----------------------------------------------------------------------------------------------*/

const VISUALLY_HIDDEN_STYLES = Object.freeze({
  // See: https://github.com/twbs/bootstrap/blob/main/scss/mixins/_visually-hidden.scss
  position: 'absolute',
  border: 0,
  width: 1,
  height: 1,
  padding: 0,
  margin: -1,
  overflow: 'hidden',
  clip: 'rect(0, 0, 0, 0)',
  whiteSpace: 'nowrap',
  wordWrap: 'normal',
}) satisfies React.CSSProperties;

const NAME = 'VisuallyHidden';

type VisuallyHiddenElement = React.ComponentRef<typeof Primitive.span>;
type PrimitiveSpanProps = React.ComponentPropsWithoutRef<typeof Primitive.span>;
interface VisuallyHiddenProps extends PrimitiveSpanProps {}

const VisuallyHidden = React.forwardRef<VisuallyHiddenElement, VisuallyHiddenProps>(
  (props, forwardedRef) => {
    return (
      <Primitive.span
        {...props}
        ref={forwardedRef}
        style={{ ...VISUALLY_HIDDEN_STYLES, ...props.style }}
      />
    );
  },
);

VisuallyHidden.displayName = NAME;

/* -----------------------------------------------------------------------------------------------*/

const Root = VisuallyHidden;

export {
  VisuallyHidden,
  //
  Root,
  //
  VISUALLY_HIDDEN_STYLES,
};
export type { VisuallyHiddenProps };



================================================
FILE: patches/@changesets__apply-release-plan.patch
================================================
diff --git a/dist/changesets-apply-release-plan.cjs.js b/dist/changesets-apply-release-plan.cjs.js
index 7fbefa0dc2a851433de7d245f4b832ea3ad85a6c..7a8a0b5ae55ce3c71d0ce4f16040d468b1a28c77 100644
--- a/dist/changesets-apply-release-plan.cjs.js
+++ b/dist/changesets-apply-release-plan.cjs.js
@@ -194,6 +194,15 @@ async function getChangelogEntry(release, releases, changesets, changelogFuncs,
   });
   let relevantChangesets = changesets.filter(cs => relevantChangesetIds.has(cs.id));
   changelogLines.patch.push(changelogFuncs.getDependencyReleaseLine(relevantChangesets, dependentReleases, changelogOpts));
+
+  if (typeof changelogFuncs.getChangelogEntry === "function") {
+    return await changelogFuncs.getChangelogEntry(
+      release,
+      changelogLines,
+      changelogOpts
+    );
+  }
+
   return [`## ${release.newVersion}`, await generateChangesForVersionTypeMarkdown(changelogLines, "major"), await generateChangesForVersionTypeMarkdown(changelogLines, "minor"), await generateChangesForVersionTypeMarkdown(changelogLines, "patch")].filter(line => line).join("\n");
 }
 
diff --git a/dist/changesets-apply-release-plan.esm.js b/dist/changesets-apply-release-plan.esm.js
index d362c5ae0dc4f6ddd85307a18302f2e038033fe9..a3875d8d98535bdba36348f23772aa629ecffe3a 100644
--- a/dist/changesets-apply-release-plan.esm.js
+++ b/dist/changesets-apply-release-plan.esm.js
@@ -157,6 +157,15 @@ async function getChangelogEntry(release, releases, changesets, changelogFuncs,
   });
   let relevantChangesets = changesets.filter(cs => relevantChangesetIds.has(cs.id));
   changelogLines.patch.push(changelogFuncs.getDependencyReleaseLine(relevantChangesets, dependentReleases, changelogOpts));
+
+  if (typeof changelogFuncs.getChangelogEntry === "function") {
+    return await changelogFuncs.getChangelogEntry(
+      release,
+      changelogLines,
+      changelogOpts
+    );
+  }
+
   return [`## ${release.newVersion}`, await generateChangesForVersionTypeMarkdown(changelogLines, "major"), await generateChangesForVersionTypeMarkdown(changelogLines, "minor"), await generateChangesForVersionTypeMarkdown(changelogLines, "patch")].filter(line => line).join("\n");
 }
 



================================================
FILE: scripts/setup-tests.ts
================================================
import '@testing-library/jest-dom/vitest';
import * as axeMatchers from 'vitest-axe/matchers';
import { expect } from 'vitest';

expect.extend(axeMatchers);

global.ResizeObserver = class ResizeObserver {
  cb: any;
  constructor(cb: any) {
    this.cb = cb;
  }
  observe() {
    this.cb([{ borderBoxSize: { inlineSize: 0, blockSize: 0 } }]);
  }
  unobserve() {}
  disconnect() {}
};



================================================
FILE: types/global.d.ts
================================================
export {};

type RequestIdleCallbackHandle = any;
type RequestIdleCallbackOptions = {
  timeout: number;
};
type RequestIdleCallbackDeadline = {
  readonly didTimeout: boolean;
  timeRemaining: () => number;
};

declare module '*.module.css' {
  const classes: { [key: string]: string };
  export default classes;
}



================================================
FILE: types/index.d.ts
================================================
declare module '*.module.css' {
  const classes: { [key: string]: string };
  export default classes;
}



================================================
FILE: .changeset/README.md
================================================
# Changesets

Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
with multi-package repos, or single-package repos to help you version and publish your code. You can
find the full documentation for it [in our repository](https://github.com/changesets/changesets)

We have a quick list of common questions to get you started engaging with this project in
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)



================================================
FILE: .changeset/changelog.cjs
================================================
// https://github.com/ariakit/ariakit/blob/main/.changeset/changelog.cjs
// MIT License, Copyright (c) Diego Haz

/** @type {import("@changesets/types").ChangelogFunctions["getDependencyReleaseLine"]} */
async function getDependencyReleaseLine(_, dependenciesUpdated) {
  if (dependenciesUpdated.length === 0) return '';
  const updatedDepenenciesList = dependenciesUpdated.map(
    (dependency) => `\`${dependency.name}@${dependency.newVersion}\``,
  );
  return `- Updated dependencies: ${updatedDepenenciesList.join(', ')}`;
}

/** @type {import("@changesets/types").ChangelogFunctions["getReleaseLine"]} */
async function getReleaseLine(changeset) {
  const [firstLine, ...nextLines] = changeset.summary.split('\n').map((l) => l.trimEnd());

  if (!nextLines.length) return `- ${firstLine}`;

  return `### ${firstLine}\n${nextLines.join('\n')}`;
}

/**
 * @param {Array<Promise<string>} changelogLines
 */
async function getChangelogText(changelogLines) {
  const lines = await Promise.all(changelogLines);
  if (!lines.length) return '';

  const isOverviewLine = (l) => l.startsWith('### Overview\n');
  const isHeadingLine = (l) => l.startsWith('###');
  const isOtherLine = (l) => !l.startsWith('###');

  const headingLines = lines
    .filter(isHeadingLine)
    .sort((a, b) => {
      if (isOverviewLine(a)) return -1;
      if (isOverviewLine(b)) return 1;
      return 0;
    })
    .map((l) => l.replace('### Overview\n\n', ''));

  const otherLines = lines.filter(isOtherLine);
  if (!headingLines.length && !otherLines.length) return '';

  const other = otherLines.join('\n');
  if (!headingLines.length) return other;

  const heading = headingLines.join('\n\n');
  if (!otherLines.length) return heading;

  return `${heading}\n\n### Other updates\n\n${other}`;
}

/**
 * @param {import("@changesets/types").ModCompWithPackage} release
 * @param {Record<"major" | "minor" | "patch", Array<Promise<string>>} changelogLines
 */
async function getChangelogEntry(release, changelogLines) {
  // const date = new Date().toLocaleDateString("en-US", {
  //   month: "long",
  //   day: "numeric",
  //   year: "numeric",
  // });
  const text = await getChangelogText(Object.values(changelogLines).flat());
  return `## ${release.newVersion}\n\n${text}`;
}

module.exports = {
  getDependencyReleaseLine,
  getReleaseLine,
  getChangelogEntry,
};



================================================
FILE: .changeset/config.json
================================================
{
  "$schema": "https://unpkg.com/@changesets/config@3.1.1/schema.json",
  "changelog": "./changelog.cjs",
  "access": "public",
  "commit": false,
  "fixed": [],
  "linked": [],
  "baseBranch": "main",
  "updateInternalDependencies": "patch",
  "snapshot": {
    "useCalculatedVersion": true,
    "prereleaseTemplate": "rc.{timestamp}"
  },
  "ignore": ["@repo/ssr-testing", "@repo/storybook"]
}



================================================
FILE: .changeset/silent-turkeys-fly.md
================================================
---
'@radix-ui/react-collection': patch
---

Updated `unstable_createCollection` signature to extend `BaseItemData` internally



================================================
FILE: .changeset/ten-pumas-agree.md
================================================
---
'@radix-ui/react-direction': patch
---

Added `use client` directive to module entrypoint



================================================
FILE: .github/CODEOWNERS
================================================
# Add the following users as reviewers on new pull requests

- @lucasmotta @hadihallak @chaance



================================================
FILE: .github/CONTRIBUTING.md
================================================
# Contributing to Radix Primitives

## Code of Conduct

Radix has adopted the [Contributor Covenant](https://www.contributor-covenant.org/) as its Code of Conduct, and we expect project participants to adhere to it.

Please read [the full text](/CODE_OF_CONDUCT.md) so that you can understand what actions will and will not be tolerated.

## Heuristics

[heuristic](<https://en.wikipedia.org/wiki/Heuristic_(computer_science)>)
/ˌhjʊ(ə)ˈrɪstɪk/

> A technique designed for solving a problem more quickly when classic methods are too slow, or for finding an approximate solution when classic methods fail to find any exact solution

- Priority is the best User Experience
- Complexity should be introduced when it’s inevitable
- Code should be easy to reason about
- Code should be easy to delete
- Avoid abstracting too early
- Avoid thinking too far in the future

## Questions

If you have questions about Radix Primitives, be sure to check out the docs where we have several examples and detailed API references that may help you solve your problem. You can also share your questions on [GitHub Discussions](https://github.com/radix-ui/primitives/discussions).

## How to contribute

There are many ways to contribute to the project. Code is just one possible means of contribution.

- **Feedback.** Tell us what we're doing well or where we can improve.
- **Support.** You can answer questions on StackOverflow or [GitHub Discussions](https://github.com/radix-ui/primitives/discussions), or provide solutions for others in [open issues](https://github.com/radix-ui/primitives/issues).
- **Write.** If you come up with an interesting example, write about it. Post it to your blog and share it with us. We'd love to see what folks in the community build with Primitives!
- **Report.** Create issues with bug reports so we can make Primitives even better.

## Working on your first Pull Request?

There are a lot of great resources on creating a good pull request. We've included a few below, but don't be shy—we appreciate all contriibutions and are happy to help those who are willing to help us!

- [How to Contribute to a Project on GitHub](https://egghead.io/courses/how-to-contribute-to-an-open-source-project-on-github)

## Preparing a Pull Request

[Pull Requests](https://docs.github.com/en/free-pro-team@latest/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request) are always welcome, but before working on a large change, it is best to open an issue first to discuss it with maintainers.

A good PR is small, focuses on a single feature or improvement, and clearly communicates the problem it solves. Try not to include more than one issue in a single PR. It's much easier for us to review multiple small pull requests than one that is large and unwieldy.

1. [Fork the repository](https://docs.github.com/en/free-pro-team@latest/github/getting-started-with-github/fork-a-repo).

2. Clone the fork to your local machine and add upstream remote:

```sh
git clone https://github.com/<your username>/primitives.git
cd primitives
git remote add upstream https://github.com/radix-ui/primitives.git
```

3. Synchronize your local `main` branch with the upstream remote:

```sh
git checkout main
git pull upstream main
```

4. Make sure your Node version matches the [.nvmrc](../.nvmrc).

```
node -v
```

1. Install dependencies with [pnpm](https://pnpm.io):

```sh
pnpm install
```

6. Create a new branch related to your PR:

```sh
git checkout -b my-bug-fix
```

7. Make changes, then commit and push to your forked repository:

```sh
git push -u origin HEAD
```

8. Go to [the repository](https://github.com/radix-ui/primitives) and [make a Pull Request](https://docs.github.com/en/free-pro-team@latest/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request).

9. We will review your Pull Request and either merge it, request changes to it, or close it with an explanation.

## Working locally

The repo is managed with pnpm workspaces.

### Development

```bash
# install dependencies
pnpm install

# start Storybook and see examples in the browser
pnpm dev
```

Make your changes and check that they resolve the problem with an example in Storybook. We also suggest adding tests to support your change, and then run `pnpm test` to make sure nothing is broken.

You also need to inform Changesets that a particular package has changed for proper versioning. Run `pnpm changeset` to mark the appropriate type of change for those packages, then commit the resulting Changeset files.

Lastly, run `pnpm build` to ensure that the build runs successfully before submitting the pull request.



================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
<!--

Thank you for contributing! Please follow the steps below to help us process your PR quickly.

- 📝 Use a meaningful title for the pull request and include the name of the package modified.
- ✅ Add or edit tests to reflect the change (run `pnpm test`).
- 🔍 Add or edit Storybook examples to reflect the change (run `pnpm dev`).
- 🙏 Please review your own PR to check for anything you may have missed.

-->

### Description

<!-- Describe the change you are introducing -->



================================================
FILE: .github/ISSUE_TEMPLATE/Bug_report.md
================================================
---
name: 'Bug report'
about: 'Create a bug report'
---

## Bug report

### Current Behavior

<!-- If applicable, add screenshots/videos to help explain the problem. -->

### Expected behavior

<!-- A clear and concise description of what you expected to happen. -->

### Reproducible example

[CodeSandbox Template](https://codesandbox.io/s/2r30e)

### Suggested solution

<!-- How could we solve this bug? What changes would need to made? -->

### Additional context

<!-- Add any other context about the problem here.  -->

### Your environment

<!-- Very important for us to help you debug. Please fill this out! -->

| Software         | Name(s) | Version |
| ---------------- | ------- | ------- |
| Radix Package(s) |         |         |
| React            | n/a     |         |
| Browser          |         |         |
| Assistive tech   |         |         |
| Node             | n/a     |         |
| npm/yarn/pnpm    |         |         |
| Operating System |         |         |



================================================
FILE: .github/ISSUE_TEMPLATE/Documentation.md
================================================
---
name: 'Documentation'
about: 'Suggestions for Radix documentation'
---

## Documentation

### Relevant Radix Component(s)

<!-- Tell us which components you'd like to see improvements for. -->

### Examples from other doc sites

<!-- Please link to examples of your suggestion if applicable. -->



================================================
FILE: .github/ISSUE_TEMPLATE/Feature_request.md
================================================
---
name: 'Feature request'
about: 'Suggest an idea for a feature or a new component'
---

## Feature request

### Overview

<!-- A clear and concise description of the feature you'd like to see.  -->

### Examples in other libraries

<!-- Please link to examples of this feature implemented elsewhere if it exists.  -->

### Who does this impact? Who is this for?

<!-- Who is this for? All users? Beginners? Advanced? Yourself? Help us understand the value of this feature! -->

### Additional context

<!-- Add any other context or links about the request here. -->



================================================
FILE: .github/ISSUE_TEMPLATE/Question.md
================================================
---
name: 'Question'
about: 'For usage questions, please use Stack Overflow or use GitHub Discussions'
---

## Question

For usage questions, please use Stack Overflow or use [GitHub Discussions](https://github.com/radix-ui/primitives/discussions) instead of posting an issue. This helps us keep bugs and feature requests prioritized, and it increases the liklihood that more people see your question and can answer it more qiuckly!



================================================
FILE: .github/workflows/build.yml
================================================
name: Build

on:
  pull_request:
    branches:
      - main

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup pnpm
        uses: pnpm/action-setup@v4
        with:
          run_install: false

      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version-file: '.nvmrc'
          cache: 'pnpm'

      - name: Install dependencies
        run: pnpm install --frozen-lockfile

      - name: Lint
        run: pnpm lint

      - name: Run build
        run: pnpm build

      - name: Run tests
        run: pnpm test:ci



================================================
FILE: .github/workflows/chromatic.yml
================================================
name: 'Chromatic'

on:
  push:
    branches:
      - main
  # "You must append a colon (:) to all events, including events without configuration."
  # https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#example-using-multiple-events-with-activity-types-or-configuration
  pull_request:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  chromatic-deployment:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Setup pnpm
        uses: pnpm/action-setup@v4
        with:
          run_install: false

      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version-file: '.nvmrc'
          cache: 'pnpm'

      - name: Install dependencies
        run: pnpm install --frozen-lockfile

      - name: Publish to Chromatic
        uses: chromaui/action@v1
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          projectToken: 63f2bd83c33c
          exitOnceUploaded: true
          exitZeroOnChanges: true



================================================
FILE: .github/workflows/publish-snapshot.yml
================================================
name: 'Publish Snapshot Release'

on:
  push:
    branches:
      - main
    paths-ignore:
      # - '.github/**'
      - './package.json'
      - './changeset/**/*'
      - '/apps/**/*'
      - '/internal/**/*'
      - '/cypress/**/*'
      - '**/*.test.ts'
      - '**/*.test.tsx'

env:
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

concurrency: ${{ github.workflow }}-${{ github.ref }}

jobs:
  publish-snapshot:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup pnpm
        uses: pnpm/action-setup@v4
        with:
          run_install: false

      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version-file: '.nvmrc'
          registry-url: 'https://registry.npmjs.org'
          cache: 'pnpm'

      - name: Install dependencies
        run: pnpm install --frozen-lockfile

      - name: Build packages
        run: pnpm build

      - name: Write .npmrc
        run: echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > .npmrc

      - name: Update snapshot version
        run: pnpm run bump:next

      - name: Publish snapshot
        run: pnpm run release:next --no-git-checks



================================================
FILE: .github/workflows/publish-stable.yml
================================================
name: 'Publish Stable Release'

on:
  push:
    branches:
      - stable

env:
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

concurrency: ${{ github.workflow }}-${{ github.ref }}

jobs:
  publish-stable:
    name: Version or publish
    timeout-minutes: 15
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup pnpm
        uses: pnpm/action-setup@v4
        with:
          run_install: false

      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version-file: '.nvmrc'
          registry-url: 'https://registry.npmjs.org'
          cache: 'pnpm'

      - name: Install dependencies
        run: pnpm install --frozen-lockfile

      - name: Build packages
        run: pnpm build

      - name: Write .npmrc
        run: echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > .npmrc

      - name: Create Release Pull Request or Publish to npm
        id: changesets
        uses: changesets/action@v1
        with:
          title: New release
          commit: New release
          version: pnpm run bump:stable
          publish: pnpm run release:stable:ci
          createGithubReleases: false


