diff --git a/app/components/CapacityBar.tsx b/app/components/CapacityBar.tsx index d07497cfb4..92ef1e8b40 100644 --- a/app/components/CapacityBar.tsx +++ b/app/components/CapacityBar.tsx @@ -87,10 +87,10 @@ function Bar({ pct }: { pct: number }) { return (
-
+
) } diff --git a/app/components/CapacityBars.tsx b/app/components/CapacityBars.tsx index 3b59812bf4..15eae333b1 100644 --- a/app/components/CapacityBars.tsx +++ b/app/components/CapacityBars.tsx @@ -23,7 +23,7 @@ export const CapacityBars = ({ allocatedLabel: string }) => { return ( -
+
} title="CPU" diff --git a/app/components/DocsPopover.tsx b/app/components/DocsPopover.tsx index 17fb385b4b..185d7a9489 100644 --- a/app/components/DocsPopover.tsx +++ b/app/components/DocsPopover.tsx @@ -54,7 +54,7 @@ export const DocsPopover = ({ heading, icon, summary, links }: DocsPopoverProps)
diff --git a/app/components/ErrorPage.tsx b/app/components/ErrorPage.tsx index a655a25719..db279eda68 100644 --- a/app/components/ErrorPage.tsx +++ b/app/components/ErrorPage.tsx @@ -20,7 +20,7 @@ const GradientBackground = () => ( className="fixed top-0 right-0 bottom-0 left-0 -z-10" style={{ background: - 'radial-gradient(200% 100% at 50% 100%, var(--surface-default) 0%, #161B1D 100%)', + 'radial-gradient(200% 100% at 50% 100%, var(--surface-default) 0%, var(--surface-secondary) 100%)', }} /> ) @@ -41,10 +41,10 @@ export function ErrorPage({ children }: Props) {
-
+
-
- +
+
{children}
diff --git a/app/components/InstanceAutoRestartPopover.tsx b/app/components/InstanceAutoRestartPopover.tsx index d94c6c396d..ef4e417962 100644 --- a/app/components/InstanceAutoRestartPopover.tsx +++ b/app/components/InstanceAutoRestartPopover.tsx @@ -50,7 +50,7 @@ export const InstanceAutoRestartPopover = ({ instance }: { instance: Instance }) diff --git a/app/components/MoreActionsMenu.tsx b/app/components/MoreActionsMenu.tsx index 112be767a6..6157116d65 100644 --- a/app/components/MoreActionsMenu.tsx +++ b/app/components/MoreActionsMenu.tsx @@ -29,10 +29,7 @@ export const MoreActionsMenu = ({
{/* The [&+*]:pt-10 style is to ensure the page container isn't pushed out of screen as it uses 100vh for layout */} -
-
+
) diff --git a/app/components/RefetchIntervalPicker.tsx b/app/components/RefetchIntervalPicker.tsx index 63d253b518..451901c98d 100644 --- a/app/components/RefetchIntervalPicker.tsx +++ b/app/components/RefetchIntervalPicker.tsx @@ -52,7 +52,7 @@ export function useIntervalPicker({ enabled, isLoading, fn, className }: Props)
)}
) diff --git a/app/components/TimeSeriesChart.tsx b/app/components/TimeSeriesChart.tsx index 9f4c9d3378..5cf3dad155 100644 --- a/app/components/TimeSeriesChart.tsx +++ b/app/components/TimeSeriesChart.tsx @@ -64,9 +64,9 @@ const longDateTime = (ts: number) => format(new Date(ts), 'MMM d, yyyy HH:mm:ss const GRID_GRAY = 'var(--stroke-secondary)' const CURSOR = 'var(--chart-stroke-item)' -const GREEN_400 = 'var(--theme-accent-400)' -const GREEN_600 = 'var(--theme-accent-600)' -const GREEN_800 = 'var(--theme-accent-800)' +const GREEN_400 = 'var(--surface-accent-secondary)' +const GREEN_600 = 'var(--content-accent-tertiary)' +const GREEN_800 = 'var(--content-accent)' // TODO: figure out how to do this with TW classes instead. As far as I can tell // ticks only take direct styling @@ -92,7 +92,7 @@ function renderTooltip(props: TooltipProps, unit?: string) { } = payload[0] if (!timestamp || typeof value !== 'number') return null return ( -
+
{longDateTime(timestamp)}
@@ -315,10 +315,10 @@ const MetricsMessage = ({
@@ -344,7 +344,7 @@ const MetricsEmpty = () => ( description="There is no data for this time period." /> ) -export const ChartContainer = classed.div`flex w-full grow flex-col rounded-lg border border-default` +export const ChartContainer = classed.div`flex w-full grow flex-col rounded-lg border border-default bg-default` type ChartHeaderProps = { title: string diff --git a/app/components/TopBar.tsx b/app/components/TopBar.tsx index 675349eefa..645577552d 100644 --- a/app/components/TopBar.tsx +++ b/app/components/TopBar.tsx @@ -10,15 +10,20 @@ import { Link } from 'react-router' import { api, navToLogin, useApiMutation } from '@oxide/api' import { + DirectionRightIcon, + Monitor12Icon, + Moon12Icon, Organization16Icon, Profile16Icon, SelectArrows6Icon, Servers16Icon, Success12Icon, + Sun12Icon, } from '@oxide/design-system/icons/react' import { useCrumbs } from '~/hooks/use-crumbs' import { useCurrentUser } from '~/hooks/use-current-user' +import { setThemePreference, useThemeStore, type ThemePreference } from '~/stores/theme' import { buttonStyle } from '~/ui/lib/Button' import * as DropdownMenu from '~/ui/lib/DropdownMenu' import { Identicon } from '~/ui/lib/Identicon' @@ -50,13 +55,10 @@ export function TopBar({ systemOrSilo }: { systemOrSilo: 'system' | 'silo' }) { ) } -const bigIconBox = 'flex h-[34px] w-[34px] items-center justify-center rounded' +const bigIconBox = 'flex h-[34px] w-[34px] items-center justify-center rounded-md' const BigIdenticon = ({ name }: { name: string }) => ( - + ) const SystemIcon = () => ( @@ -136,7 +138,7 @@ function UserMenu() {
@@ -147,12 +149,77 @@ function UserMenu() { Settings + logout.mutate({})} label="Sign out" /> ) } +function ThemeSubmenu() { + const { preference } = useThemeStore() + return ( + + + + Theme + + + + + setThemePreference(v as ThemePreference)} + > + } + label="Light" + selected={preference === 'light'} + /> + } + label="Dark" + selected={preference === 'dark'} + /> + } + label="System" + selected={preference === 'system'} + /> + + + + ) +} + +function ThemeRadioItem({ + value, + icon, + label, + selected, +}: { + value: ThemePreference + icon: React.ReactNode + label: string + selected: boolean +}) { + return ( + + + {icon} + {label} + {selected && } + + + ) +} + /** * Choose between System and Silo-scoped route trees, or if the user doesn't * have access to system routes (i.e., if /v1/me has fleetViewer: false) show @@ -161,20 +228,24 @@ function UserMenu() { function SiloSystemPicker({ level }: { level: 'silo' | 'system' }) { return ( - -
+ +
{level === 'system' ? : }
-
{level === 'system' ? 'System' : 'Silo'}
+ + {level === 'system' ? 'System' : 'Silo'} + {/* aria-hidden is a tip from the Reach docs */} - +
- + diff --git a/app/forms/image-upload.tsx b/app/forms/image-upload.tsx index 8b3ec80d01..c77852af53 100644 --- a/app/forms/image-upload.tsx +++ b/app/forms/image-upload.tsx @@ -675,7 +675,7 @@ export default function ImageCreate() { label="Image uploaded successfully" className={ allDone - ? 'bg-accent-secondary *:text-accent transition-colors' + ? 'bg-accent *:text-accent transition-colors' : 'transition-colors' } /> diff --git a/app/layouts/AuthLayout.tsx b/app/layouts/AuthLayout.tsx index 98cf88fe25..4f5b1c9cdc 100644 --- a/app/layouts/AuthLayout.tsx +++ b/app/layouts/AuthLayout.tsx @@ -15,7 +15,7 @@ export default function AuthLayout() { className="relative h-screen" style={{ background: - 'radial-gradient(200% 100% at 50% 100%, var(--surface-default) 0%, #161B1D 100%)', + 'radial-gradient(200% 100% at 50% 100%, var(--surface-default) 0%, var(--surface-secondary) 100%)', }} > diff --git a/app/layouts/RootLayout.tsx b/app/layouts/RootLayout.tsx index 50d5f03d8c..4b9df6da5a 100644 --- a/app/layouts/RootLayout.tsx +++ b/app/layouts/RootLayout.tsx @@ -11,6 +11,7 @@ import { Outlet, useNavigation } from 'react-router' import { MswBanner } from '~/components/MswBanner' import { ToastStack } from '~/components/ToastStack' import { useCrumbs } from '~/hooks/use-crumbs' +import { useApplyTheme } from '~/stores/theme' /** * non top-level route: Instances / mock-project / Projects / maze-war / Oxide Console @@ -28,6 +29,7 @@ const useTitle = () => * anything to actually belong here. */ export default function RootLayout() { + useApplyTheme() const title = useTitle() useEffect(() => { document.title = title diff --git a/app/layouts/helpers.tsx b/app/layouts/helpers.tsx index 22530762b9..42244e9c29 100644 --- a/app/layouts/helpers.tsx +++ b/app/layouts/helpers.tsx @@ -22,7 +22,7 @@ export function ContentPane() { return (
diff --git a/app/pages/DeviceAuthSuccessPage.tsx b/app/pages/DeviceAuthSuccessPage.tsx index a7e3eccd80..17fdb1b249 100644 --- a/app/pages/DeviceAuthSuccessPage.tsx +++ b/app/pages/DeviceAuthSuccessPage.tsx @@ -12,7 +12,7 @@ import { Success12Icon } from '@oxide/design-system/icons/react' */ export default function DeviceAuthSuccessPage() { return ( -
+
diff --git a/app/pages/DeviceAuthVerifyPage.tsx b/app/pages/DeviceAuthVerifyPage.tsx index 601a094ab1..28903f8b47 100644 --- a/app/pages/DeviceAuthVerifyPage.tsx +++ b/app/pages/DeviceAuthVerifyPage.tsx @@ -33,7 +33,7 @@ export default function DeviceAuthVerifyPage() { return (
{ event.preventDefault() diff --git a/app/pages/LoginPage.tsx b/app/pages/LoginPage.tsx index fecc42df9c..3ca1741a73 100644 --- a/app/pages/LoginPage.tsx +++ b/app/pages/LoginPage.tsx @@ -44,7 +44,7 @@ export default function LoginPage() { <>
{silo}
diff --git a/app/pages/LoginPageSaml.tsx b/app/pages/LoginPageSaml.tsx index 897dd86e7f..6087da897d 100644 --- a/app/pages/LoginPageSaml.tsx +++ b/app/pages/LoginPageSaml.tsx @@ -24,7 +24,7 @@ export default function LoginPageSaml() { <>
{silo}
diff --git a/app/pages/project/instances/SerialConsolePage.tsx b/app/pages/project/instances/SerialConsolePage.tsx index 2a0eba1cc8..32bf55247b 100644 --- a/app/pages/project/instances/SerialConsolePage.tsx +++ b/app/pages/project/instances/SerialConsolePage.tsx @@ -139,7 +139,7 @@ export default function SerialConsolePage() {
@@ -183,7 +183,7 @@ function SerialSkeleton({ children, animate }: SkeletonProps) { {[...Array(200)].map((_e, i) => (
-
+
{children}
diff --git a/app/stores/theme.ts b/app/stores/theme.ts new file mode 100644 index 0000000000..1c71b22c25 --- /dev/null +++ b/app/stores/theme.ts @@ -0,0 +1,62 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * Copyright Oxide Computer Company + */ +import { useEffect, useSyncExternalStore } from 'react' +import { create } from 'zustand' + +export type ThemePreference = 'dark' | 'light' | 'system' + +const STORAGE_KEY = 'theme-preference' + +function getStoredPreference(): ThemePreference { + try { + const stored = localStorage.getItem(STORAGE_KEY) + if (stored === 'dark' || stored === 'light' || stored === 'system') return stored + } catch { + // localStorage unavailable + } + return 'dark' +} + +export const useThemeStore = create<{ preference: ThemePreference }>(() => ({ + preference: getStoredPreference(), +})) + +export function setThemePreference(pref: ThemePreference) { + localStorage.setItem(STORAGE_KEY, pref) + useThemeStore.setState({ preference: pref }) +} + +/** Resolve preference to actual theme, accounting for system media query */ +function resolveTheme(pref: ThemePreference, systemIsLight: boolean): 'dark' | 'light' { + if (pref === 'system') return systemIsLight ? 'light' : 'dark' + return pref +} + +function subscribeToMediaQuery(cb: () => void) { + const mql = window.matchMedia('(prefers-color-scheme: light)') + mql.addEventListener('change', cb) + return () => mql.removeEventListener('change', cb) +} + +function getSystemIsLight() { + return window.matchMedia('(prefers-color-scheme: light)').matches +} + +/** + * Hook that applies the resolved theme to the document. Renders in RootLayout + * so it runs on every page. + */ +export function useApplyTheme() { + const { preference } = useThemeStore() + const systemIsLight = useSyncExternalStore(subscribeToMediaQuery, getSystemIsLight) + const theme = resolveTheme(preference, systemIsLight) + + useEffect(() => { + document.documentElement.dataset.theme = theme + }, [theme]) +} diff --git a/app/table/cells/LinkCell.tsx b/app/table/cells/LinkCell.tsx index 106917eb87..d77a1e7352 100644 --- a/app/table/cells/LinkCell.tsx +++ b/app/table/cells/LinkCell.tsx @@ -13,7 +13,7 @@ import { classed } from '~/util/classed' const linkClass = 'link-with-underline group flex h-full w-full items-center text-sans-md' /** Pushes out the link area to the entire cell for improved clickability™ */ -const Pusher = classed.div`absolute inset-0 w-[calc(100%-2px)] right-[2px] group-hover:bg-raise` +const Pusher = classed.div`absolute inset-0 group-hover:bg-raise` /** * Because this returns a component, it should only be used in a static context diff --git a/app/table/columns/action-col.tsx b/app/table/columns/action-col.tsx index 24857d00df..acb506a875 100644 --- a/app/table/columns/action-col.tsx +++ b/app/table/columns/action-col.tsx @@ -85,7 +85,7 @@ export const RowActions = ({ id, copyIdLabel = 'Copy ID', actions }: RowActionsP {/* stopPropagation prevents clicks from toggling row select in a single select table */} e.stopPropagation()} > diff --git a/app/ui/lib/ActionMenu.tsx b/app/ui/lib/ActionMenu.tsx index 805ea0d954..cf9c989d09 100644 --- a/app/ui/lib/ActionMenu.tsx +++ b/app/ui/lib/ActionMenu.tsx @@ -117,7 +117,7 @@ export function ActionMenu(props: ActionMenuProps) { >
{items.length > 0 && ( -
+
-
+
diff --git a/app/ui/lib/BulkActionMenu.tsx b/app/ui/lib/BulkActionMenu.tsx index b5412f351c..ae4031fcf4 100644 --- a/app/ui/lib/BulkActionMenu.tsx +++ b/app/ui/lib/BulkActionMenu.tsx @@ -18,7 +18,7 @@ export interface BulkActionMenuProps { export function BulkActionMenu({ children, selectedCount }: BulkActionMenuProps) { const actionButtons = flattenChildren(children) return ( -
+
{actionButtons}
{selectedCount} selected diff --git a/app/ui/lib/Button.tsx b/app/ui/lib/Button.tsx index 206f8c036f..a0ec80ef7d 100644 --- a/app/ui/lib/Button.tsx +++ b/app/ui/lib/Button.tsx @@ -45,7 +45,7 @@ export const buttonStyle = ({ variant = 'primary', }: ButtonStyleProps = {}) => { return cn( - 'ox-button active-clicked elevation-1 rounded inline-flex items-center justify-center align-top disabled:cursor-default shrink-0', + 'ox-button active-clicked rounded-md inline-flex items-center justify-center align-top disabled:cursor-default shrink-0', `btn-${variant}`, sizeStyle[size], variant === 'danger' diff --git a/app/ui/lib/CalendarCell.tsx b/app/ui/lib/CalendarCell.tsx index d7aee306f1..3d2273035b 100644 --- a/app/ui/lib/CalendarCell.tsx +++ b/app/ui/lib/CalendarCell.tsx @@ -85,17 +85,17 @@ export function CalendarCell({ state, date }: CalendarCellProps) { isSelected && !isDisabled ? isInvalid ? 'text-error bg-error-secondary' - : 'text-accent-secondary bg-accent-secondary' + : 'text-accent-secondary bg-accent' : 'text-secondary hover:bg-tertiary', isRoundedLeft && 'rounded-l', - isRoundedRight && 'rounded-r', + isRoundedRight && 'rounded-r-md', // Hover state for non-selected cells. - !isSelected && !isDisabled ? 'rounded' : '' + !isSelected && !isDisabled ? 'rounded-md' : '' )} >
diff --git a/app/ui/lib/Checkbox.tsx b/app/ui/lib/Checkbox.tsx index cb5d028865..b50b777b0c 100644 --- a/app/ui/lib/Checkbox.tsx +++ b/app/ui/lib/Checkbox.tsx @@ -12,19 +12,17 @@ import { Checkmark12Icon } from '@oxide/design-system/icons/react' import { classed } from '~/util/classed' const Check = () => ( - + ) -const Indeterminate = classed.div`absolute w-2 h-0.5 left-1 top-[7px] bg-accent pointer-events-none` +const Indeterminate = classed.div`absolute w-2 h-0.5 left-1 top-[7px] bg-(--theme-accent-800) light:bg-(--theme-accent-600) pointer-events-none` const inputStyle = ` - appearance-none border border-default bg-default h-4 w-4 rounded-sm absolute left-0 + appearance-none border border-default bg-default h-4 w-4 rounded-sm absolute left-0 outline-none disabled:cursor-not-allowed - hover:border-hover hover:cursor-pointer - checked:bg-accent-secondary checked:border-accent-secondary - indeterminate:hover:border-accent checked:hover:border-accent - hover:indeterminate:bg-accent-secondary-hover hover:checked:bg-accent-secondary-hover - indeterminate:bg-accent-secondary indeterminate:border-accent-secondary + hover:border-raise hover:cursor-pointer + checked:bg-accent checked:border-accent-tertiary checked:hover:border-accent-secondary checked:hover:light:border-accent + indeterminate:bg-accent indeterminate:border-accent-tertiary indeterminate:hover:light:border-accent indeterminate:hover:border-accent-secondary ` export type CheckboxProps = { diff --git a/app/ui/lib/Combobox.tsx b/app/ui/lib/Combobox.tsx index 96aaa0eaf1..085842ac6e 100644 --- a/app/ui/lib/Combobox.tsx +++ b/app/ui/lib/Combobox.tsx @@ -176,10 +176,10 @@ export const Combobox = ({ )}
{filteredItems.map((item) => ( diff --git a/app/ui/lib/CopyToClipboard.tsx b/app/ui/lib/CopyToClipboard.tsx index 7330842769..a4d2934ff1 100644 --- a/app/ui/lib/CopyToClipboard.tsx +++ b/app/ui/lib/CopyToClipboard.tsx @@ -54,9 +54,9 @@ export const CopyToClipboard = ({ return (
-
+
diff --git a/app/ui/lib/DateRangePicker.tsx b/app/ui/lib/DateRangePicker.tsx index ef3bee1978..d7a328451c 100644 --- a/app/ui/lib/DateRangePicker.tsx +++ b/app/ui/lib/DateRangePicker.tsx @@ -63,7 +63,7 @@ export function DateRangePicker(props: DateRangePickerProps) { type="button" className={cn( state.isOpen && 'z-10 ring-2', - 'text-sans-md border-default hover:border-raise relative flex h-11 items-center rounded-l rounded-r border focus-within:ring-2 focus:z-10', + 'text-sans-md border-default hover:border-raise bg-default relative flex h-11 items-center rounded-l-md rounded-r-md border focus-within:ring-2 focus:z-10', state.isInvalid ? 'focus-error border-error ring-error-secondary hover:border-error' : 'border-default ring-accent-secondary' @@ -77,7 +77,7 @@ export function DateRangePicker(props: DateRangePickerProps) {
)}
-
+
diff --git a/app/ui/lib/DropdownMenu.tsx b/app/ui/lib/DropdownMenu.tsx index 4637b1855f..66dc55fa1a 100644 --- a/app/ui/lib/DropdownMenu.tsx +++ b/app/ui/lib/DropdownMenu.tsx @@ -6,13 +6,7 @@ * Copyright Oxide Computer Company */ -import { - Menu, - MenuButton, - MenuItem, - MenuItems, - type MenuItemsProps, -} from '@headlessui/react' +import { Menu } from '@base-ui/react/menu' import cn from 'classnames' import { type ReactNode, type Ref } from 'react' import { Link } from 'react-router' @@ -22,34 +16,81 @@ import { OpenLink12Icon } from '@oxide/design-system/icons/react' import { Wrap } from '../util/wrap' import { Tooltip } from './Tooltip' -export const Root = Menu +// Re-export Root with modal={false} default to prevent scroll locking +export function Root({ children, ...props }: React.ComponentProps) { + return ( + + {children} + + ) +} + +export const Trigger = Menu.Trigger -export const Trigger = MenuButton +type AnchorProp = string | { to: string; offset?: number; gap?: number } + +function parseAnchor( + anchor: AnchorProp, + gap?: number +): { + side: 'bottom' | 'top' | 'left' | 'right' + align: 'start' | 'center' | 'end' + sideOffset: number + alignOffset: number +} { + const anchorStr = typeof anchor === 'string' ? anchor : anchor.to + const parts = anchorStr.split(' ') + const side = (parts[0] ?? 'bottom') as 'bottom' | 'top' | 'left' | 'right' + const align = (parts[1] ?? 'end') as 'start' | 'center' | 'end' + const alignOffset = typeof anchor === 'object' ? (anchor.offset ?? 0) : 0 + const sideOffset = gap ?? (typeof anchor === 'object' ? (anchor.gap ?? 0) : 0) + return { side, align, sideOffset, alignOffset } +} type ContentProps = { className?: string children: ReactNode - anchor?: MenuItemsProps['anchor'] - /** Spacing in px, passed as --anchor-gap */ + anchor?: AnchorProp + /** Spacing in px between trigger and menu */ gap?: 8 } export function Content({ className, children, anchor = 'bottom end', gap }: ContentProps) { + const { side, align, sideOffset, alignOffset } = parseAnchor(anchor, gap) return ( - - {children} - + + + + {children} + + + + ) +} + +type SubContentProps = { + className?: string + children: ReactNode +} + +export function SubContent({ className, children }: SubContentProps) { + return ( + + + + {children} + + + ) } @@ -62,13 +103,14 @@ type LinkItemProps = { export function LinkItem({ className, to, children }: LinkItemProps) { // rather lazy test for external links const ext = /^https?:/.test(to) ? { rel: 'noreferrer', target: '_blank' } : undefined - // TODO: external link icon to show when it will open in a new tab return ( - - - {children} {ext ? : null} - - + + } + > + {children} {ext ? : null} + ) } @@ -78,21 +120,24 @@ type ItemProps = { onSelect: () => void /* If present, ReactNode will be displayed in a tooltip */ disabled?: React.ReactNode - ref?: Ref + ref?: Ref } -// need to forward ref because of tooltips on disabled menu buttons export const Item = ({ className, onSelect, label, disabled, ref }: ItemProps) => ( }> - - - + + {label} + ) + +export const Submenu = Menu.SubmenuRoot +export const SubmenuTrigger = Menu.SubmenuTrigger +export const RadioGroup = Menu.RadioGroup +export const RadioItem = Menu.RadioItem +export const Separator = Menu.Separator diff --git a/app/ui/lib/EmptyMessage.tsx b/app/ui/lib/EmptyMessage.tsx index c1136384e8..efd6aa8e96 100644 --- a/app/ui/lib/EmptyMessage.tsx +++ b/app/ui/lib/EmptyMessage.tsx @@ -43,7 +43,7 @@ export function EmptyMessage(props: Props) { return (
{props.icon && ( -
+
{props.icon}
)} diff --git a/app/ui/lib/FileInput.tsx b/app/ui/lib/FileInput.tsx index dc0f34db19..11b9c060c7 100644 --- a/app/ui/lib/FileInput.tsx +++ b/app/ui/lib/FileInput.tsx @@ -69,7 +69,7 @@ export function FileInput({ type="file" name="file" className={cn( - 'absolute inset-0 -z-1 w-full cursor-pointer rounded', + 'absolute inset-0 -z-1 w-full cursor-pointer rounded-md', error && 'focus-error' )} {...inputProps} @@ -81,16 +81,16 @@ export function FileInput({
diff --git a/app/ui/lib/Listbox.tsx b/app/ui/lib/Listbox.tsx index 0691124bf6..a292195a8b 100644 --- a/app/ui/lib/Listbox.tsx +++ b/app/ui/lib/Listbox.tsx @@ -104,7 +104,7 @@ export const Listbox = ({ `text-sans-md flex h-11 items-center justify-between rounded-md border`, hasError ? 'focus-error border-error-secondary hover:border-error' - : 'border-default hover:border-hover', + : 'border-default hover:border-raise', open && 'ring-accent-secondary ring-2', open && hasError && 'ring-error-secondary', isDisabled @@ -145,7 +145,7 @@ export const Listbox = ({ anchor={{ gap: 12, to: 'bottom start' }} className={cn( zIndex, - 'ox-menu pointer-events-auto overflow-y-auto outline-hidden!', + 'ox-menu shadow-menu-inset pointer-events-auto', !hideSelected ? 'w-(--button-width)' : 'min-w-24' )} // This is to prevent the `useOthersInert` call in ListboxOptions. diff --git a/app/ui/lib/Message.tsx b/app/ui/lib/Message.tsx index be3e900720..5fbdcb602b 100644 --- a/app/ui/lib/Message.tsx +++ b/app/ui/lib/Message.tsx @@ -38,10 +38,10 @@ const defaultIcon: Record = { } const color: Record = { - success: 'bg-accent-secondary border-accent/10', - error: 'bg-error-secondary border-destructive/10', - notice: 'bg-notice-secondary border-notice/10', - info: 'bg-info-secondary border-blue-800/10', + success: 'bg-accent', + error: 'bg-error', + notice: 'bg-notice', + info: 'bg-info', } const textColor: Record = { @@ -77,7 +77,7 @@ export const Message = ({ return (
- + {title} {children} diff --git a/app/ui/lib/NumberInput.tsx b/app/ui/lib/NumberInput.tsx index fa4c49417b..3792654b7d 100644 --- a/app/ui/lib/NumberInput.tsx +++ b/app/ui/lib/NumberInput.tsx @@ -37,7 +37,7 @@ export function NumberInput(props: NumberInputProps) { 'relative flex rounded-md border', props.error ? 'border-error-secondary hover:border-error' - : 'border-default hover:border-hover', + : 'border-default hover:border-raise', props.isDisabled && 'border-default!', props.className )} diff --git a/app/ui/lib/PageHeader.tsx b/app/ui/lib/PageHeader.tsx index 53886cdcee..2e72b97d7e 100644 --- a/app/ui/lib/PageHeader.tsx +++ b/app/ui/lib/PageHeader.tsx @@ -17,9 +17,9 @@ interface PageTitleProps { } export const PageTitle = ({ children: title, icon }: PageTitleProps) => { return ( -

+

{icon} - {title} + {title}

) } diff --git a/app/ui/lib/Popover.tsx b/app/ui/lib/Popover.tsx index 9387fcba74..2003cdf296 100644 --- a/app/ui/lib/Popover.tsx +++ b/app/ui/lib/Popover.tsx @@ -39,7 +39,7 @@ export function Popover(props: PopoverProps) {
{children} diff --git a/app/ui/lib/Progress.tsx b/app/ui/lib/Progress.tsx index 6d12185083..ad80e4775a 100644 --- a/app/ui/lib/Progress.tsx +++ b/app/ui/lib/Progress.tsx @@ -20,7 +20,7 @@ export type ProgressProps = { export const Progress = (props: ProgressProps) => (
diff --git a/app/ui/lib/PropertiesTable.tsx b/app/ui/lib/PropertiesTable.tsx index 0393eb8f2e..8315bff809 100644 --- a/app/ui/lib/PropertiesTable.tsx +++ b/app/ui/lib/PropertiesTable.tsx @@ -41,7 +41,7 @@ export function PropertiesTable({ aria-label="Properties table" className={cn( className, - 'properties-table border-default min-w-min basis-6/12 rounded-lg border', + 'properties-table bg-default border-default min-w-min basis-6/12 rounded-lg border', '*:border-secondary *:border-t *:pr-6 *:pl-3 [&>*:nth-child(-n+2)]:border-t-0!', 'grid grid-cols-[minmax(min-content,1fr)_3fr]', { diff --git a/app/ui/lib/Radio.tsx b/app/ui/lib/Radio.tsx index 38f4d8fedb..55b211ba61 100644 --- a/app/ui/lib/Radio.tsx +++ b/app/ui/lib/Radio.tsx @@ -24,8 +24,8 @@ export type RadioProps = Omit, 'type'> & { const fieldStyles = ` peer appearance-none absolute outline-hidden - border border-default h-4 w-4 rounded-full bg-default hover:border-hover checked:hover:border-accent - checked:bg-accent-secondary checked:border-accent-secondary disabled:bg-disabled hover:disabled:bg-disabled + border border-default h-4 w-4 rounded-full bg-default hover:border-raise checked:hover:border-accent-secondary checked:hover:light:border-accent + checked:bg-accent checked:border-accent-tertiary disabled:bg-disabled hover:disabled:bg-disabled disabled:hover:bg-transparent ` @@ -34,7 +34,7 @@ export const Radio = ({ children, className, alignTop, ...inputProps }: RadioPro {/* the dot in the middle. hide by default, use peer-checked to show if checked */} -
+
{children && {children}} @@ -42,18 +42,18 @@ export const Radio = ({ children, className, alignTop, ...inputProps }: RadioPro ) const cardLabelStyles = ` - text-sans-md border rounded-md border-default bg-default hover:border-hover + text-sans-md border rounded-md border-default bg-default hover:border-raise peer-focus:ring-2 peer-focus:ring-accent-secondary w-44 text-raise *:border-secondary *:p-3 cursor-pointer - peer-checked:bg-accent-secondary + peer-checked:bg-accent peer-checked:border-accent-secondary peer-checked:hover:border-accent peer-checked:*:border-accent peer-checked:*:border-accent-secondary peer-checked:text-accent peer-checked:[&>*_.text-default]:text-accent-secondary peer-disabled:cursor-not-allowed - peer-disabled:bg-disabled peer-disabled:peer-checked:bg-accent-secondary + peer-disabled:bg-disabled peer-disabled:peer-checked:bg-accent peer-checked:peer-disabled:hover:border-accent-secondary peer-disabled:hover:border-default peer-disabled:[&>*_.text-default]:text-disabled peer-disabled:text-disabled peer-disabled:peer-checked:text-accent-disabled peer-disabled:peer-checked:[&>*_.text-default]:text-accent-disabled ` diff --git a/app/ui/lib/ResourceMeter.tsx b/app/ui/lib/ResourceMeter.tsx index 539ff995c5..0732e934b7 100644 --- a/app/ui/lib/ResourceMeter.tsx +++ b/app/ui/lib/ResourceMeter.tsx @@ -42,7 +42,7 @@ export const ResourceMeter = ({ ? 'bg-destructive-secondary' : value > warningThreshold ? 'bg-notice-secondary' - : 'bg-accent-secondary' + : 'bg-accent' return (
diff --git a/app/ui/lib/SkipLink.tsx b/app/ui/lib/SkipLink.tsx index 66654240b4..a451aa75a3 100644 --- a/app/ui/lib/SkipLink.tsx +++ b/app/ui/lib/SkipLink.tsx @@ -13,7 +13,7 @@ const skipLinkStyles = ` uppercase text-mono-lg rounded inline-flex items-center justify-center focus:ring-2 focus:ring-accent-secondary - bg-accent-secondary border-transparent text-accent text-mono-sm + bg-accent border-transparent text-accent text-mono-sm transition-all motion-reduce:transform-none ` diff --git a/app/ui/lib/Table.tsx b/app/ui/lib/Table.tsx index 25c3ba7515..ca27e061c6 100644 --- a/app/ui/lib/Table.tsx +++ b/app/ui/lib/Table.tsx @@ -101,7 +101,7 @@ Table.Cell = ({ height = 'small', className, children, ...props }: TableCellProp >
diff --git a/app/ui/lib/Tag.tsx b/app/ui/lib/Tag.tsx index 857d548c06..8b7d4a7bc4 100644 --- a/app/ui/lib/Tag.tsx +++ b/app/ui/lib/Tag.tsx @@ -28,7 +28,7 @@ export const tagColors: Record>> = notice: 'bg-notice text-inverse', }, secondary: { - default: 'bg-accent-secondary text-accent', + default: 'bg-accent text-accent', destructive: 'bg-destructive-secondary text-destructive', notice: 'bg-notice-secondary text-notice', neutral: 'bg-secondary text-default', diff --git a/app/ui/lib/TextInput.tsx b/app/ui/lib/TextInput.tsx index a5c3fcc908..826d9dd5b5 100644 --- a/app/ui/lib/TextInput.tsx +++ b/app/ui/lib/TextInput.tsx @@ -68,7 +68,7 @@ export function TextInput({ 'flex items-center rounded-md border', error ? 'border-error-secondary hover:border-error' - : 'border-default hover:border-hover', + : 'border-default hover:border-raise', disabled && 'border-default!', className )} diff --git a/app/ui/lib/Toast.tsx b/app/ui/lib/Toast.tsx index 6d31e0d280..27c213c0b6 100644 --- a/app/ui/lib/Toast.tsx +++ b/app/ui/lib/Toast.tsx @@ -49,7 +49,7 @@ const defaultTitle: Record = { } const color: Record = { - success: 'bg-accent-secondary', + success: 'bg-accent', error: 'bg-error-secondary', info: 'bg-notice-secondary', } @@ -84,7 +84,7 @@ export const Toast = ({ return (
* { @@ -37,11 +37,7 @@ /* Active states */ .ox-tab[data-state='active'] { - @apply text-accent border-accent; -} - -.ox-tabs-list .ox-tab[data-state='active']:hover > * { - @apply bg-accent-secondary; + @apply text-accent border-accent light:border-green-800 light:text-raise; } /* Badge styles */ @@ -54,7 +50,7 @@ } .ox-tab[data-state='active'] > .ox-badge { - @apply bg-accent-secondary-hover; + @apply bg-accent; } /* Full width variants */ @@ -82,16 +78,12 @@ } .ox-side-tabs-list .ox-tab[data-state='active'] { - @apply text-accent bg-accent-secondary; + @apply text-accent bg-accent; border: none; } -.ox-side-tabs .ox-tabs-panel { - @apply mx-0 ml-4; -} - .ox-side-tabs-list .ox-tab[data-state='active']:hover { - @apply bg-accent-secondary-hover; + @apply bg-accent-hover; } .ox-side-tabs-list .ox-tab:not([data-state='active']):hover { diff --git a/app/ui/styles/components/button.css b/app/ui/styles/components/button.css index 5fc6fe2852..2ab0c0e81b 100644 --- a/app/ui/styles/components/button.css +++ b/app/ui/styles/components/button.css @@ -8,43 +8,57 @@ .ox-button { @apply relative; -} -.active-clicked:active:not(.visually-disabled) { - @apply motion-safe:translate-y-px; -} -.ox-button:after { - content: ''; - @apply absolute top-0 right-0 bottom-0 left-0 rounded-md border border-current opacity-[0.05]; -} -.btn-primary { - @apply text-accent bg-accent-secondary hover:bg-accent-secondary-hover disabled:text-accent-disabled disabled:bg-accent-secondary; -} -.btn-primary:disabled > .spinner, -.btn-primary.visually-disabled > .spinner { - @apply text-accent; -} -.btn-secondary { - @apply text-default bg-secondary hover:bg-hover disabled:text-disabled disabled:bg-secondary; -} -.btn-secondary:disabled > .spinner, -.btn-secondary.visually-disabled > .spinner { - @apply text-default; -} + &:after { + content: ''; + @apply absolute top-0 right-0 bottom-0 left-0 rounded-md border border-current/5; + } + &.btn-primary { + @apply text-accent bg-accent hover:bg-accent-hover disabled:text-accent/35 disabled:bg-accent; + } + &.btn-primary:disabled > .spinner, + &.btn-primary.visually-disabled > .spinner { + @apply text-accent; + } -.btn-danger { - @apply text-destructive bg-destructive-secondary hover:bg-destructive-secondary-hover disabled:text-destructive-disabled disabled:bg-destructive-secondary; -} -.btn-danger:disabled > .spinner, -.btn-danger.visually-disabled > .spinner { - @apply text-destructive; -} + &.btn-secondary { + @apply text-secondary bg-secondary hover:bg-hover disabled:text-secondary/35 disabled:bg-secondary; + } + &.btn-secondary:disabled > .spinner, + &.btn-secondary.visually-disabled > .spinner { + @apply text-secondary; + } -.btn-ghost { - @apply text-default border-default hover:bg-hover disabled:text-disabled border disabled:bg-transparent; -} -.btn-ghost:after { - @apply hidden; + &.btn-danger { + @apply text-destructive bg-destructive hover:bg-destructive-hover disabled:text-destructive/35 disabled:bg-destructive; + } + &.btn-danger:disabled > .spinner, + &.btn-danger.visually-disabled > .spinner { + @apply text-destructive; + } + + &.btn-ghost { + @apply text-secondary hover:bg-hover disabled:text-secondary/35 disabled:bg-transparent; + } + &.btn-ghost:after { + @apply border-current/20; + } + + &.btn-accent-ghost { + @apply text-accent border-accent-secondary hover:bg-accent-hover border; + } + + &.btn-accent-ghost:after { + @apply hidden; + } + + &.btn-accent-solid { + @apply text-inverse bg-(--theme-accent-800); + } + + &.btn-accent-solid:after { + @apply hidden; + } } /** diff --git a/app/ui/styles/components/menu-button.css b/app/ui/styles/components/menu-button.css index c7ad40e8a7..a818f2d109 100644 --- a/app/ui/styles/components/menu-button.css +++ b/app/ui/styles/components/menu-button.css @@ -8,7 +8,7 @@ .dropdown-menu-content { /* we want menu popover to be on top of top bar and pagination bar too */ - @apply bg-raise border-secondary z-(--z-top-bar-dropdown) min-w-36 rounded-md border p-0; + @apply bg-raise light:bg-default z-(--z-top-bar-dropdown) min-w-36 rounded-md p-0; & .DropdownMenuItem { @apply text-sans-md text-default border-secondary flex w-full cursor-pointer items-center border-b py-2 pr-6 pl-3 text-left select-none last:border-b-0; @@ -25,7 +25,7 @@ @apply text-destructive-disabled; } - &[data-focus] { + &[data-highlighted] { outline: none; @apply bg-tertiary; } diff --git a/app/ui/styles/components/menu-list.css b/app/ui/styles/components/menu-list.css index 8975447ee1..4745547e68 100644 --- a/app/ui/styles/components/menu-list.css +++ b/app/ui/styles/components/menu-list.css @@ -7,7 +7,7 @@ */ .ox-menu { - @apply bg-raise border-secondary elevation-2 !max-h-[17.5rem] overflow-y-auto rounded-md border; + @apply bg-raise !max-h-[17.5rem] rounded-md p-px; } .ox-menu-item { @@ -19,15 +19,15 @@ } .ox-menu-item.is-highlighted.is-selected { - @apply bg-accent-secondary-hover; + @apply bg-accent-hover; } .ox-menu-item.is-selected[data-highlighted] { - @apply bg-accent-secondary-hover; + @apply bg-accent-hover; } .ox-menu-item.is-selected { - @apply text-accent bg-accent-secondary hover:bg-accent-secondary-hover border-0; + @apply text-accent bg-accent hover:bg-accent-hover; .ox-badge { @apply text-inverse bg-accent ring-0; } @@ -36,5 +36,5 @@ /* beautiful ring */ .ox-menu-item.is-selected:after { content: ''; - @apply border-accent absolute top-0 right-0 bottom-0 left-0 block rounded-md border; + @apply ring-accent absolute inset-0 z-10 block rounded-sm ring; } diff --git a/app/ui/styles/components/mini-table.css b/app/ui/styles/components/mini-table.css index a34ec314b3..8627454313 100644 --- a/app/ui/styles/components/mini-table.css +++ b/app/ui/styles/components/mini-table.css @@ -43,12 +43,12 @@ /* first cell's div */ & td:first-child > div { - @apply ml-2 rounded-l border-l; + @apply ml-2 rounded-l-md border-l; } /* second-to-last cell's div */ & td:nth-last-child(2) > div { - @apply rounded-r border-r; + @apply rounded-r-md border-r; } /* last cell's div (the div for the delete button) */ diff --git a/app/ui/styles/components/spinner.css b/app/ui/styles/components/spinner.css index f07f28dce9..060beb4169 100644 --- a/app/ui/styles/components/spinner.css +++ b/app/ui/styles/components/spinner.css @@ -83,7 +83,7 @@ } .metrics-loading-indicator span { - @apply block h-1 w-[3px] rounded-[1px] bg-[--theme-accent-500]; + @apply block h-1 w-[3px] rounded-[1px] bg-(--theme-accent-500); animation: stretch 1.8s infinite both; } diff --git a/app/ui/styles/components/table.css b/app/ui/styles/components/table.css index 231f6ae6b0..1b2b85daf6 100644 --- a/app/ui/styles/components/table.css +++ b/app/ui/styles/components/table.css @@ -55,6 +55,17 @@ table.ox-table { @apply bg-default sticky left-0 z-10; } + /* Border between sticky first column and second column: + first column owns the right border, second column drops its left border */ + & td:first-of-type > div, + & th:first-of-type > div { + @apply border-r; + } + & td:nth-of-type(2) > div, + & th:nth-of-type(2) > div { + @apply border-l-0; + } + /* Last column is sticky if it is a more actions cell @@ -306,30 +317,42 @@ table.ox-table { Drop shadow appears if content is below a sticky cell and the table is overflowing */ +td:first-of-type, +th:first-of-type, +td:last-of-type.action-col, +th:last-of-type.action-col { + transition-property: box-shadow; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 250ms; +} + .scrolled td:first-of-type, -.scrolled th:first-of-type, +.scrolled th:first-of-type { + box-shadow: 6px 0 8px -2px oklch(0 0 0 / 0.2); +} .overflowing td:last-of-type.action-col, .overflowing th:last-of-type.action-col { - @apply elevation-2; + box-shadow: -6px 0 8px -2px oklch(0 0 0 / 0.2); +} +.light .scrolled td:first-of-type, +.light .scrolled th:first-of-type { + box-shadow: 6px 0 8px -2px oklch(0 0 0 / 0.05); +} +.light .overflowing td:last-of-type.action-col, +.light .overflowing th:last-of-type.action-col { + box-shadow: -6px 0 8px -2px oklch(0 0 0 / 0.05); } /* Stops shadow from overflowing below - -1px helps with a visual glitch when a bit - underneath shows through */ .scrolled td:first-of-type, .scrolled th:first-of-type { - clip-path: inset(0px -40px 0px -1px); + clip-path: inset(0px -40px 0px 0px); } .overflowing td:last-of-type.action-col, .overflowing th:last-of-type.action-col { - clip-path: inset(0px -1px 0px -40px); -} - -.scrolled td:first-of-type:before, -.scrolled th:first-of-type:before { - @apply border-r-secondary absolute top-0 right-0 bottom-0 border-r content-['']; + clip-path: inset(0px 0px 0px -40px); } .simplebar-scrollbar { diff --git a/app/ui/styles/components/tooltip.css b/app/ui/styles/components/tooltip.css index ebaa86e5de..ad13b7b8b9 100644 --- a/app/ui/styles/components/tooltip.css +++ b/app/ui/styles/components/tooltip.css @@ -7,7 +7,7 @@ */ .ox-tooltip { - @apply text-sans-md text-default bg-raise border-secondary elevation-2 rounded-md border p-2; + @apply text-sans-md text-default bg-raise shadow-tooltip rounded-md p-2; } .ox-tooltip-arrow { diff --git a/app/ui/styles/index.css b/app/ui/styles/index.css index 6c39b7811d..66e93a470a 100644 --- a/app/ui/styles/index.css +++ b/app/ui/styles/index.css @@ -47,6 +47,7 @@ @import '@xterm/xterm/css/xterm.css' layer(components); @source '../../../node_modules/@oxide/design-system/dist'; +@custom-variant light (&:where([data-theme=light], [data-theme=light] *)); @theme { --animate-spin-slow: spin 5s linear infinite; diff --git a/index.html b/index.html index 0e190e3691..1f7576208b 100644 --- a/index.html +++ b/index.html @@ -13,10 +13,23 @@ Oxide Console - + + + +
diff --git a/package-lock.json b/package-lock.json index 9a68ecd67d..192324395f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,9 +10,10 @@ "hasInstallScript": true, "license": "MPL-2.0", "dependencies": { + "@base-ui/react": "^1.1.0", "@floating-ui/react": "^0.26.23", "@headlessui/react": "^2.2.9", - "@oxide/design-system": "^4.1.0", + "@oxide/design-system": "^5.0.0--canary.163.21985709465.0", "@radix-ui/react-accordion": "^1.2.0", "@radix-ui/react-dialog": "^1.1.6", "@radix-ui/react-tabs": "^1.1.0", @@ -262,13 +263,10 @@ } }, "node_modules/@babel/runtime": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz", - "integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", + "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", "license": "MIT", - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, "engines": { "node": ">=6.9.0" } @@ -321,6 +319,60 @@ "node": ">=6.9.0" } }, + "node_modules/@base-ui/react": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@base-ui/react/-/react-1.1.0.tgz", + "integrity": "sha512-ikcJRNj1mOiF2HZ5jQHrXoVoHcNHdBU5ejJljcBl+VTLoYXR6FidjTN86GjO6hyshi6TZFuNvv0dEOgaOFv6Lw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.4", + "@base-ui/utils": "0.2.4", + "@floating-ui/react-dom": "^2.1.6", + "@floating-ui/utils": "^0.2.10", + "reselect": "^5.1.1", + "tabbable": "^6.4.0", + "use-sync-external-store": "^1.6.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17 || ^18 || ^19", + "react": "^17 || ^18 || ^19", + "react-dom": "^17 || ^18 || ^19" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@base-ui/utils": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@base-ui/utils/-/utils-0.2.4.tgz", + "integrity": "sha512-smZwpMhjO29v+jrZusBSc5T+IJ3vBb9cjIiBjtKcvWmRj9Z4DWGVR3efr1eHR56/bqY5a4qyY9ElkOY5ljo3ng==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.4", + "@floating-ui/utils": "^0.2.10", + "reselect": "^5.1.1", + "use-sync-external-store": "^1.6.0" + }, + "peerDependencies": { + "@types/react": "^17 || ^18 || ^19", + "react": "^17 || ^18 || ^19", + "react-dom": "^17 || ^18 || ^19" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@bundled-es-modules/cookie": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@bundled-es-modules/cookie/-/cookie-2.0.1.tgz", @@ -1565,9 +1617,9 @@ "license": "MIT" }, "node_modules/@oxide/design-system": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@oxide/design-system/-/design-system-4.1.0.tgz", - "integrity": "sha512-sFNgDf8B8Yial+3uYTfrBaQOT+2BNUlzBgubsHM88m5MMMhjNfPktGZTYy7PtGdYjzkLKSFXWYEjq248l/1MQg==", + "version": "5.0.0--canary.163.21985709465.0", + "resolved": "https://registry.npmjs.org/@oxide/design-system/-/design-system-5.0.0--canary.163.21985709465.0.tgz", + "integrity": "sha512-KGXXMmw5V1B6VQdrDB0ughO74lWd73KmyLd1KMDFd1niodPB1LVBnocCD1nK9wA1+lyed0a1eUMZGBgIRyA4fg==", "license": "MPL 2.0", "dependencies": { "@floating-ui/react": "^0.27.16", @@ -11720,12 +11772,6 @@ "node": ">=8" } }, - "node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", - "license": "MIT" - }, "node_modules/regex": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/regex/-/regex-6.0.1.tgz", @@ -11804,6 +11850,12 @@ "dev": true, "license": "MIT" }, + "node_modules/reselect": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", + "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==", + "license": "MIT" + }, "node_modules/resize-observer-polyfill": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", @@ -12406,9 +12458,9 @@ "license": "MIT" }, "node_modules/tabbable": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", - "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.4.0.tgz", + "integrity": "sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==", "license": "MIT" }, "node_modules/tagged-tag": { diff --git a/package.json b/package.json index 5df46b5fe6..6bcceeb51c 100644 --- a/package.json +++ b/package.json @@ -35,9 +35,10 @@ }, "private": true, "dependencies": { + "@base-ui/react": "^1.1.0", "@floating-ui/react": "^0.26.23", "@headlessui/react": "^2.2.9", - "@oxide/design-system": "^4.1.0", + "@oxide/design-system": "^5.0.0--canary.163.21985709465.0", "@radix-ui/react-accordion": "^1.2.0", "@radix-ui/react-dialog": "^1.1.6", "@radix-ui/react-tabs": "^1.1.0",