diff --git a/app/components/DocsPopover.tsx b/app/components/DocsPopover.tsx index cc88802630..7f08da88da 100644 --- a/app/components/DocsPopover.tsx +++ b/app/components/DocsPopover.tsx @@ -6,8 +6,7 @@ * Copyright Oxide Computer Company */ -import { autoUpdate, offset, useFloating } from '@floating-ui/react' -import { Popover } from '@headlessui/react' +import { Popover, PopoverButton, PopoverPanel } from '@headlessui/react' import cn from 'classnames' import { OpenLink12Icon, Question12Icon } from '@oxide/design-system/icons/react' @@ -43,27 +42,15 @@ type DocsPopoverProps = { } export const DocsPopover = ({ heading, icon, summary, links }: DocsPopoverProps) => { - const { refs, floatingStyles } = useFloating({ - placement: 'bottom-end', - middleware: [offset(12)], - whileElementsMounted: autoUpdate, - // Needs to be off because it breaks the enter animation - // https://floating-ui.com/docs/usefloating#transform - transform: false, - }) return ( - + - - + @@ -78,7 +65,7 @@ export const DocsPopover = ({ heading, icon, summary, links }: DocsPopoverProps) ))} - + ) } diff --git a/app/ui/lib/Listbox.tsx b/app/ui/lib/Listbox.tsx index f61c4aadcd..2ef78f8b73 100644 --- a/app/ui/lib/Listbox.tsx +++ b/app/ui/lib/Listbox.tsx @@ -6,14 +6,12 @@ * Copyright Oxide Computer Company */ import { - autoUpdate, - flip, - FloatingPortal, - offset, - size, - useFloating, -} from '@floating-ui/react' -import { Listbox as Select } from '@headlessui/react' + Listbox as HListbox, + Label, + ListboxButton, + ListboxOption, + ListboxOptions, +} from '@headlessui/react' import cn from 'classnames' import type { ReactNode } from 'react' @@ -61,21 +59,6 @@ export const Listbox = ({ isLoading = false, ...props }: ListboxProps) => { - const { refs, floatingStyles } = useFloating({ - middleware: [ - offset(12), - flip(), - size({ - apply({ rects, elements }) { - Object.assign(elements.floating.style, { - width: `${rects.reference.width}px`, - }) - }, - }), - ], - whileElementsMounted: autoUpdate, - }) - const selectedItem = selected && items.find((i) => i.value === selected) const noItems = !isLoading && items.length === 0 const isDisabled = disabled || noItems @@ -83,7 +66,7 @@ export const Listbox = ({ return ( - ({ {label && ( - {label} + {label} {description && {description}} )} - ({ > - - - - {items.map((item) => ( - - {({ active, selected }) => ( - - {item.label} - - )} - - ))} - - + + + {items.map((item) => ( + + {({ active, selected }) => ( + // TODO: redo active styling with `data-active` somehow + + {item.label} + + )} + + ))} + > )} - + ) } diff --git a/app/ui/styles/components/menu-list.css b/app/ui/styles/components/menu-list.css index 8a9d719712..35c28f87a5 100644 --- a/app/ui/styles/components/menu-list.css +++ b/app/ui/styles/components/menu-list.css @@ -7,7 +7,7 @@ */ .ox-menu { - @apply max-h-[17.5rem] overflow-y-auto rounded border bg-raise border-secondary elevation-2; + @apply !max-h-[17.5rem] overflow-y-auto rounded border bg-raise border-secondary elevation-2; } .ox-menu-item { diff --git a/package-lock.json b/package-lock.json index 73944a37f2..94fd5795d8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "license": "MPL-2.0", "dependencies": { "@floating-ui/react": "^0.26.13", - "@headlessui/react": "^1.7.18", + "@headlessui/react": "^2.0.3", "@oxide/design-system": "^1.4.6", "@radix-ui/react-accordion": "^1.1.2", "@radix-ui/react-dialog": "^1.0.5", @@ -1281,19 +1281,21 @@ } }, "node_modules/@headlessui/react": { - "version": "1.7.18", - "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.7.18.tgz", - "integrity": "sha512-4i5DOrzwN4qSgNsL4Si61VMkUcWbcSKueUV7sFhpHzQcSShdlHENE5+QBntMSRvHt8NyoFO2AGG8si9lq+w4zQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-2.0.3.tgz", + "integrity": "sha512-Xd1h0YZgfhxZ7W1w4TvK0/TZ1c4qaX4liYVUkAXqW1HCLcXSqnMeYAUGJS/BBroBAUL9HErjyFcRpCWRQZ/0lA==", "dependencies": { - "@tanstack/react-virtual": "^3.0.0-beta.60", - "client-only": "^0.0.1" + "@floating-ui/react": "^0.26.13", + "@react-aria/focus": "^3.16.2", + "@react-aria/interactions": "^3.21.1", + "@tanstack/react-virtual": "3.5.0" }, "engines": { "node": ">=10" }, "peerDependencies": { - "react": "^16 || ^17 || ^18", - "react-dom": "^16 || ^17 || ^18" + "react": "^18", + "react-dom": "^18" } }, "node_modules/@humanwhocodes/config-array": { @@ -2086,6 +2088,22 @@ "react-dom": ">=16.8.0" } }, + "node_modules/@oxide/design-system/node_modules/@headlessui/react": { + "version": "1.7.19", + "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.7.19.tgz", + "integrity": "sha512-Ll+8q3OlMJfJbAKM/+/Y2q6PPYbryqNTXDbryx7SXLIDamkF6iQFbriYHga0dY44PvDhvvBWCx1Xj4U5+G4hOw==", + "dependencies": { + "@tanstack/react-virtual": "^3.0.0-beta.60", + "client-only": "^0.0.1" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": "^16 || ^17 || ^18", + "react-dom": "^16 || ^17 || ^18" + } + }, "node_modules/@oxide/openapi-gen-ts": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/@oxide/openapi-gen-ts/-/openapi-gen-ts-0.2.2.tgz", @@ -5197,11 +5215,11 @@ } }, "node_modules/@tanstack/react-virtual": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.0.4.tgz", - "integrity": "sha512-tiqKW/e2MJVCr7/pRUXulpkyxllaOclkHNfhKTo4pmHjJIqnhMfwIjc1Q1R0Un3PI3kQywywu/791c8z9u0qeA==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.5.0.tgz", + "integrity": "sha512-rtvo7KwuIvqK9zb0VZ5IL7fiJAEnG+0EiFZz8FUOs+2mhGqdGmjKIaT1XU7Zq0eFqL0jonLlhbayJI/J2SA/Bw==", "dependencies": { - "@tanstack/virtual-core": "3.0.0" + "@tanstack/virtual-core": "3.5.0" }, "funding": { "type": "github", @@ -5225,9 +5243,9 @@ } }, "node_modules/@tanstack/virtual-core": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.0.0.tgz", - "integrity": "sha512-SYXOBTjJb05rXa2vl55TTwO40A6wKu0R5i1qQwhJYNDIqaIGF7D0HsLw+pJAyi2OvntlEIVusx3xtbbgSUi6zg==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.5.0.tgz", + "integrity": "sha512-KnPRCkQTyqhanNC0K63GBG3wA8I+D1fQuVnAvcBF8f13akOKeQp1gSbu6f77zCxhEk727iV5oQnbHLYzHrECLg==", "funding": { "type": "github", "url": "https://github.com/sponsors/tannerlinsley" @@ -20504,12 +20522,14 @@ } }, "@headlessui/react": { - "version": "1.7.18", - "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.7.18.tgz", - "integrity": "sha512-4i5DOrzwN4qSgNsL4Si61VMkUcWbcSKueUV7sFhpHzQcSShdlHENE5+QBntMSRvHt8NyoFO2AGG8si9lq+w4zQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-2.0.3.tgz", + "integrity": "sha512-Xd1h0YZgfhxZ7W1w4TvK0/TZ1c4qaX4liYVUkAXqW1HCLcXSqnMeYAUGJS/BBroBAUL9HErjyFcRpCWRQZ/0lA==", "requires": { - "@tanstack/react-virtual": "^3.0.0-beta.60", - "client-only": "^0.0.1" + "@floating-ui/react": "^0.26.13", + "@react-aria/focus": "^3.16.2", + "@react-aria/interactions": "^3.21.1", + "@tanstack/react-virtual": "3.5.0" } }, "@humanwhocodes/config-array": { @@ -21125,6 +21145,15 @@ "@floating-ui/utils": "^0.1.1", "tabbable": "^6.0.1" } + }, + "@headlessui/react": { + "version": "1.7.19", + "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.7.19.tgz", + "integrity": "sha512-Ll+8q3OlMJfJbAKM/+/Y2q6PPYbryqNTXDbryx7SXLIDamkF6iQFbriYHga0dY44PvDhvvBWCx1Xj4U5+G4hOw==", + "requires": { + "@tanstack/react-virtual": "^3.0.0-beta.60", + "client-only": "^0.0.1" + } } } }, @@ -23146,11 +23175,11 @@ } }, "@tanstack/react-virtual": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.0.4.tgz", - "integrity": "sha512-tiqKW/e2MJVCr7/pRUXulpkyxllaOclkHNfhKTo4pmHjJIqnhMfwIjc1Q1R0Un3PI3kQywywu/791c8z9u0qeA==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.5.0.tgz", + "integrity": "sha512-rtvo7KwuIvqK9zb0VZ5IL7fiJAEnG+0EiFZz8FUOs+2mhGqdGmjKIaT1XU7Zq0eFqL0jonLlhbayJI/J2SA/Bw==", "requires": { - "@tanstack/virtual-core": "3.0.0" + "@tanstack/virtual-core": "3.5.0" } }, "@tanstack/table-core": { @@ -23159,9 +23188,9 @@ "integrity": "sha512-dCG8vQGk4js5v88/k83tTedWOwjGnIyONrKpHpfmSJB8jwFHl8GSu1sBBxbtACVAPtAQgwNxl0rw1d3RqRM1Tg==" }, "@tanstack/virtual-core": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.0.0.tgz", - "integrity": "sha512-SYXOBTjJb05rXa2vl55TTwO40A6wKu0R5i1qQwhJYNDIqaIGF7D0HsLw+pJAyi2OvntlEIVusx3xtbbgSUi6zg==" + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.5.0.tgz", + "integrity": "sha512-KnPRCkQTyqhanNC0K63GBG3wA8I+D1fQuVnAvcBF8f13akOKeQp1gSbu6f77zCxhEk727iV5oQnbHLYzHrECLg==" }, "@testing-library/dom": { "version": "10.1.0", diff --git a/package.json b/package.json index bd94e27f9a..a542aef807 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "private": true, "dependencies": { "@floating-ui/react": "^0.26.13", - "@headlessui/react": "^1.7.18", + "@headlessui/react": "^2.0.3", "@oxide/design-system": "^1.4.6", "@radix-ui/react-accordion": "^1.1.2", "@radix-ui/react-dialog": "^1.0.5", diff --git a/test/e2e/instance-create.e2e.ts b/test/e2e/instance-create.e2e.ts index d8b8ed006d..4ff6a7b5ed 100644 --- a/test/e2e/instance-create.e2e.ts +++ b/test/e2e/instance-create.e2e.ts @@ -62,6 +62,7 @@ test('can create an instance', async ({ page }) => { await expect(assignEphemeralIpCheckbox).toBeChecked() await assignEphemeralIpButton.click() await expect(page.getByRole('option', { name: 'ip-pool-1' })).toBeEnabled() + await assignEphemeralIpButton.click() // click closes the listbox so we can do more stuff // unchecking the box should disable the selector await assignEphemeralIpCheckbox.uncheck()