@code-sherpas/pharos-react 1.0.3 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -46,7 +46,7 @@ export function Demo() {
46
46
 
47
47
  ## Rules for consumers
48
48
 
49
- See [RULES.md](./RULES.md) — published with the package.
49
+ See [the rules for consumers](https://app.notion.com/p/4071751eee1081239c1efa6a8fdde525) in Notion (Programa Pharos), where Pharos keeps its documentation (decision D27).
50
50
 
51
51
  ## Storybook
52
52
 
@@ -4,13 +4,18 @@ import { VariantProps } from 'class-variance-authority';
4
4
  * Maps the `variant` axis to per-class names inside `Badge.module.css`.
5
5
  * The variant set follows shadcn/ui — `default`, `secondary`, `destructive`,
6
6
  * `outline` — extended with the semantic tones every modern DS exposes
7
- * (`success`, `warning`, `info`). Naming stays asymmetric on purpose:
7
+ * (`success`, `warning`, `info`) and the brand terracotta (`accent`,
8
+ * `accent-soft`, D25). Naming stays asymmetric on purpose:
8
9
  * `destructive` is the canonical shadcn name for "negative tone" and we
9
10
  * keep it instead of renaming it to `error`, so consumers familiar with
10
11
  * shadcn pick the right value without re-learning the API.
12
+ *
13
+ * The semantic tones are for system state only; the accent tones are for
14
+ * content identity only — a module mark, a topic tag, a category — never for
15
+ * an action, a selection or a state, which stay blue or semantic.
11
16
  */
12
17
  declare const badgeVariants: (props?: ({
13
- variant?: "secondary" | "destructive" | "default" | "outline" | "success" | "warning" | "info" | null | undefined;
18
+ variant?: "secondary" | "destructive" | "default" | "outline" | "success" | "warning" | "info" | "accent" | "accent-soft" | null | undefined;
14
19
  } & import('class-variance-authority/types').ClassProp) | undefined) => string;
15
20
  type BadgeVariantProps = VariantProps<typeof badgeVariants>;
16
21
  export interface BadgeProps extends ComponentPropsWithoutRef<'span'>, BadgeVariantProps {
@@ -1 +1 @@
1
- {"version":3,"file":"Badge.d.ts","sourceRoot":"","sources":["../../src/components/Badge.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,OAAO,CAAC;AACtD,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAIlE;;;;;;;;GAQG;AACH,QAAA,MAAM,aAAa;;8EAejB,CAAC;AAEH,KAAK,iBAAiB,GAAG,YAAY,CAAC,OAAO,aAAa,CAAC,CAAC;AAE5D,MAAM,WAAW,UAAW,SAAQ,wBAAwB,CAAC,MAAM,CAAC,EAAE,iBAAiB;CAAG;AAE1F,wBAAgB,KAAK,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,EAAE,UAAU,+BAShE;yBATe,KAAK;;;AAarB,OAAO,EAAE,aAAa,EAAE,CAAC"}
1
+ {"version":3,"file":"Badge.d.ts","sourceRoot":"","sources":["../../src/components/Badge.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,OAAO,CAAC;AACtD,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAIlE;;;;;;;;;;;;;GAaG;AACH,QAAA,MAAM,aAAa;;8EAiBjB,CAAC;AAEH,KAAK,iBAAiB,GAAG,YAAY,CAAC,OAAO,aAAa,CAAC,CAAC;AAE5D,MAAM,WAAW,UAAW,SAAQ,wBAAwB,CAAC,MAAM,CAAC,EAAE,iBAAiB;CAAG;AAE1F,wBAAgB,KAAK,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,EAAE,UAAU,+BAShE;yBATe,KAAK;;;AAarB,OAAO,EAAE,aAAa,EAAE,CAAC"}
@@ -11,7 +11,9 @@ var i = n(t.badge, {
11
11
  outline: t.outline,
12
12
  success: t.success,
13
13
  warning: t.warning,
14
- info: t.info
14
+ info: t.info,
15
+ accent: t.accent,
16
+ "accent-soft": t.accentSoft
15
17
  } },
16
18
  defaultVariants: { variant: "default" }
17
19
  });
@@ -1 +1 @@
1
- {"version":3,"file":"Badge.js","names":[],"sources":["../../src/components/Badge.tsx"],"sourcesContent":["import type { ComponentPropsWithoutRef } from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '../lib/cn';\nimport styles from './Badge.module.css';\n\n/**\n * Maps the `variant` axis to per-class names inside `Badge.module.css`.\n * The variant set follows shadcn/ui — `default`, `secondary`, `destructive`,\n * `outline` — extended with the semantic tones every modern DS exposes\n * (`success`, `warning`, `info`). Naming stays asymmetric on purpose:\n * `destructive` is the canonical shadcn name for \"negative tone\" and we\n * keep it instead of renaming it to `error`, so consumers familiar with\n * shadcn pick the right value without re-learning the API.\n */\nconst badgeVariants = cva(styles.badge, {\n variants: {\n variant: {\n default: styles.default,\n secondary: styles.secondary,\n destructive: styles.destructive,\n outline: styles.outline,\n success: styles.success,\n warning: styles.warning,\n info: styles.info,\n },\n },\n defaultVariants: {\n variant: 'default',\n },\n});\n\ntype BadgeVariantProps = VariantProps<typeof badgeVariants>;\n\nexport interface BadgeProps extends ComponentPropsWithoutRef<'span'>, BadgeVariantProps {}\n\nexport function Badge({ variant, className, ...rest }: BadgeProps) {\n const resolvedVariant = variant ?? 'default';\n return (\n <span\n data-pharos-variant={resolvedVariant}\n className={cn(badgeVariants({ variant: resolvedVariant }), className)}\n {...rest}\n />\n );\n}\n\nBadge.displayName = 'Badge';\n\nexport { badgeVariants };\n"],"mappings":";;;;;AAcA,IAAM,IAAgB,EAAI,EAAO,OAAO;CACtC,UAAU,EACR,SAAS;EACP,SAAS,EAAO;EAChB,WAAW,EAAO;EAClB,aAAa,EAAO;EACpB,SAAS,EAAO;EAChB,SAAS,EAAO;EAChB,SAAS,EAAO;EAChB,MAAM,EAAO;CACf,EACF;CACA,iBAAiB,EACf,SAAS,UACX;AACF,CAAC;AAMD,SAAgB,EAAM,EAAE,YAAS,cAAW,GAAG,KAAoB;CACjE,IAAM,IAAkB,KAAW;CACnC,OACE,kBAAC,QAAD;EACE,uBAAqB;EACrB,WAAW,EAAG,EAAc,EAAE,SAAS,EAAgB,CAAC,GAAG,CAAS;EACpE,GAAI;CACL,CAAA;AAEL;AAEA,EAAM,cAAc"}
1
+ {"version":3,"file":"Badge.js","names":[],"sources":["../../src/components/Badge.tsx"],"sourcesContent":["import type { ComponentPropsWithoutRef } from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '../lib/cn';\nimport styles from './Badge.module.css';\n\n/**\n * Maps the `variant` axis to per-class names inside `Badge.module.css`.\n * The variant set follows shadcn/ui — `default`, `secondary`, `destructive`,\n * `outline` — extended with the semantic tones every modern DS exposes\n * (`success`, `warning`, `info`) and the brand terracotta (`accent`,\n * `accent-soft`, D25). Naming stays asymmetric on purpose:\n * `destructive` is the canonical shadcn name for \"negative tone\" and we\n * keep it instead of renaming it to `error`, so consumers familiar with\n * shadcn pick the right value without re-learning the API.\n *\n * The semantic tones are for system state only; the accent tones are for\n * content identity only — a module mark, a topic tag, a category — never for\n * an action, a selection or a state, which stay blue or semantic.\n */\nconst badgeVariants = cva(styles.badge, {\n variants: {\n variant: {\n default: styles.default,\n secondary: styles.secondary,\n destructive: styles.destructive,\n outline: styles.outline,\n success: styles.success,\n warning: styles.warning,\n info: styles.info,\n accent: styles.accent,\n 'accent-soft': styles.accentSoft,\n },\n },\n defaultVariants: {\n variant: 'default',\n },\n});\n\ntype BadgeVariantProps = VariantProps<typeof badgeVariants>;\n\nexport interface BadgeProps extends ComponentPropsWithoutRef<'span'>, BadgeVariantProps {}\n\nexport function Badge({ variant, className, ...rest }: BadgeProps) {\n const resolvedVariant = variant ?? 'default';\n return (\n <span\n data-pharos-variant={resolvedVariant}\n className={cn(badgeVariants({ variant: resolvedVariant }), className)}\n {...rest}\n />\n );\n}\n\nBadge.displayName = 'Badge';\n\nexport { badgeVariants };\n"],"mappings":";;;;;AAmBA,IAAM,IAAgB,EAAI,EAAO,OAAO;CACtC,UAAU,EACR,SAAS;EACP,SAAS,EAAO;EAChB,WAAW,EAAO;EAClB,aAAa,EAAO;EACpB,SAAS,EAAO;EAChB,SAAS,EAAO;EAChB,SAAS,EAAO;EAChB,MAAM,EAAO;EACb,QAAQ,EAAO;EACf,eAAe,EAAO;CACxB,EACF;CACA,iBAAiB,EACf,SAAS,UACX;AACF,CAAC;AAMD,SAAgB,EAAM,EAAE,YAAS,cAAW,GAAG,KAAoB;CACjE,IAAM,IAAkB,KAAW;CACnC,OACE,kBAAC,QAAD;EACE,uBAAqB;EACrB,WAAW,EAAG,EAAc,EAAE,SAAS,EAAgB,CAAC,GAAG,CAAS;EACpE,GAAI;CACL,CAAA;AAEL;AAEA,EAAM,cAAc"}
@@ -1,12 +1,14 @@
1
1
  var e = {
2
- badge: "_badge_zrawy_5",
3
- default: "_default_zrawy_30",
4
- secondary: "_secondary_zrawy_35",
5
- destructive: "_destructive_zrawy_40",
6
- outline: "_outline_zrawy_45",
7
- success: "_success_zrawy_55",
8
- warning: "_warning_zrawy_60",
9
- info: "_info_zrawy_65"
2
+ badge: "_badge_5pviu_5",
3
+ default: "_default_5pviu_30",
4
+ secondary: "_secondary_5pviu_35",
5
+ destructive: "_destructive_5pviu_40",
6
+ outline: "_outline_5pviu_45",
7
+ success: "_success_5pviu_55",
8
+ warning: "_warning_5pviu_60",
9
+ info: "_info_5pviu_65",
10
+ accent: "_accent_5pviu_73",
11
+ accentSoft: "_accentSoft_5pviu_80"
10
12
  };
11
13
  //#endregion
12
14
  export { e as default };
@@ -1 +1 @@
1
- {"version":3,"file":"Badge.module.js","names":[],"sources":["../../src/components/Badge.module.css"],"sourcesContent":["/* Base layout. Same across every variant — only surface, label and border\n * change. Inline-flex so a child SVG (rendered by the consumer as plain\n * children) sits on the same baseline as the label. The font-relative SVG\n * sizing rule mirrors shadcn's `[&>svg]:size-3` utility. */\n.badge {\n display: inline-flex;\n align-items: center;\n gap: var(--pharos-spacing-1);\n padding: 0 var(--pharos-spacing-2);\n height: var(--pharos-spacing-5);\n border: 1px solid transparent;\n border-radius: var(--pharos-radius-full);\n font-family: var(--pharos-font-family-sans);\n font-size: var(--pharos-font-size-xs);\n font-weight: var(--pharos-font-weight-medium);\n line-height: 1;\n white-space: nowrap;\n width: fit-content;\n text-box-trim: trim-both;\n text-box-edge: cap alphabetic;\n}\n\n.badge > svg {\n width: 0.75em;\n height: 0.75em;\n flex: 0 0 auto;\n pointer-events: none;\n}\n\n.default {\n background: var(--pharos-color-neutral-900);\n color: var(--pharos-color-base-white);\n}\n\n.secondary {\n background: var(--pharos-color-neutral-100);\n color: var(--pharos-color-neutral-900);\n}\n\n.destructive {\n background: var(--pharos-color-semantic-error-fg);\n color: var(--pharos-color-semantic-error-on);\n}\n\n.outline {\n background: transparent;\n color: var(--pharos-color-neutral-900);\n /* `neutral-500` clears WCAG 1.4.11 (Non-text Contrast, 3:1 against the\n * surrounding surface) and matches the resting border of Input and\n * Button secondary so the system has one accessible boundary intensity\n * across primitives. See `Input.module.css` for the cross-DS rationale. */\n border-color: var(--pharos-color-neutral-500);\n}\n\n.success {\n background: var(--pharos-color-semantic-success-fg);\n color: var(--pharos-color-semantic-success-on);\n}\n\n.warning {\n background: var(--pharos-color-semantic-warning-fg);\n color: var(--pharos-color-semantic-warning-on);\n}\n\n.info {\n background: var(--pharos-color-semantic-info-fg);\n color: var(--pharos-color-semantic-info-on);\n}\n"],"mappings":""}
1
+ {"version":3,"file":"Badge.module.js","names":[],"sources":["../../src/components/Badge.module.css"],"sourcesContent":["/* Base layout. Same across every variant — only surface, label and border\n * change. Inline-flex so a child SVG (rendered by the consumer as plain\n * children) sits on the same baseline as the label. The font-relative SVG\n * sizing rule mirrors shadcn's `[&>svg]:size-3` utility. */\n.badge {\n display: inline-flex;\n align-items: center;\n gap: var(--pharos-spacing-1);\n padding: 0 var(--pharos-spacing-2);\n height: var(--pharos-spacing-5);\n border: 1px solid transparent;\n border-radius: var(--pharos-radius-full);\n font-family: var(--pharos-font-family-sans);\n font-size: var(--pharos-font-size-xs);\n font-weight: var(--pharos-font-weight-medium);\n line-height: 1;\n white-space: nowrap;\n width: fit-content;\n text-box-trim: trim-both;\n text-box-edge: cap alphabetic;\n}\n\n.badge > svg {\n width: 0.75em;\n height: 0.75em;\n flex: 0 0 auto;\n pointer-events: none;\n}\n\n.default {\n background: var(--pharos-color-neutral-900);\n color: var(--pharos-color-base-white);\n}\n\n.secondary {\n background: var(--pharos-color-neutral-100);\n color: var(--pharos-color-neutral-900);\n}\n\n.destructive {\n background: var(--pharos-color-semantic-error-fg);\n color: var(--pharos-color-semantic-error-on);\n}\n\n.outline {\n background: transparent;\n color: var(--pharos-color-neutral-900);\n /* `neutral-500` clears WCAG 1.4.11 (Non-text Contrast, 3:1 against the\n * surrounding surface) and matches the resting border of Input and\n * Button secondary so the system has one accessible boundary intensity\n * across primitives. See `Input.module.css` for the cross-DS rationale. */\n border-color: var(--pharos-color-neutral-500);\n}\n\n.success {\n background: var(--pharos-color-semantic-success-fg);\n color: var(--pharos-color-semantic-success-on);\n}\n\n.warning {\n background: var(--pharos-color-semantic-warning-fg);\n color: var(--pharos-color-semantic-warning-on);\n}\n\n.info {\n background: var(--pharos-color-semantic-info-fg);\n color: var(--pharos-color-semantic-info-on);\n}\n\n/* Brand accent (D25): content identity, never system state. Solid terracotta\n * 700, not the 600 base: white on 600 is 4.04:1 and fails AA at 12px; on 700\n * it is 5.92:1. Use it for the single mark that matters. */\n.accent {\n background: var(--pharos-color-accent-terracotta-700);\n color: var(--pharos-color-base-white);\n}\n\n/* The tint, for many tags shown together: terracotta-700 ink on the 50 tint\n * keeps AA for the 12px label. */\n.accentSoft {\n background: var(--pharos-color-accent-terracotta-50);\n color: var(--pharos-color-accent-terracotta-700);\n}\n"],"mappings":""}
@@ -15,7 +15,8 @@ import { VariantProps } from 'class-variance-authority';
15
15
  * single component with a `searchable` axis. (Free-text entry — typing a
16
16
  * value that is not in the list — is Base UI's separate `Autocomplete`
17
17
  * primitive and is deferred; every known Alexandria call-site filters a known
18
- * set.) See `NAMING-decisions.md` § Combobox.
18
+ * set.) See the Select + Combobox page of the naming decisions:
19
+ * https://app.notion.com/p/4071751eee108172bf64fdbe0fe8a94b
19
20
  *
20
21
  * Multi-select is the `multiple` axis on the root (not a separate atom),
21
22
  * matching Base UI / shadcn / React Aria. With `multiple`, selections render
@@ -1 +1 @@
1
- {"version":3,"file":"Combobox.d.ts","sourceRoot":"","sources":["../../src/components/Combobox.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Combobox.d.ts","sourceRoot":"","sources":["../../src/components/Combobox.tsx"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"Combobox.js","names":[],"sources":["../../src/components/Combobox.tsx"],"sourcesContent":["'use client';\n\nimport {\n type ComponentProps,\n type Ref,\n createContext,\n useCallback,\n useContext,\n useMemo,\n useState,\n} from 'react';\nimport { Combobox as BaseCombobox } from '@base-ui/react/combobox';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '../lib/cn';\nimport styles from './Combobox.module.css';\n\n/**\n * Single- or multi-select with a **text input that filters the options**\n * (Decision D17). Wraps Base UI's `Combobox.*` parts, which implement the\n * ARIA APG **combobox** pattern: an `<input role=\"combobox\">` with\n * `aria-expanded` / `aria-controls` pointing at a popup listbox, typeahead\n * filtering, and arrow-key navigation of the results.\n *\n * This is deliberately distinct from the `Select` atom (also D17). A Select\n * has no input — the user picks from a closed list. A Combobox is for sets\n * large enough to need filtering, or where the user expects to type. shadcn,\n * Base UI and ARIA APG separate the two; Pharos ships both rather than a\n * single component with a `searchable` axis. (Free-text entry — typing a\n * value that is not in the list — is Base UI's separate `Autocomplete`\n * primitive and is deferred; every known Alexandria call-site filters a known\n * set.) See `NAMING-decisions.md` § Combobox.\n *\n * Multi-select is the `multiple` axis on the root (not a separate atom),\n * matching Base UI / shadcn / React Aria. With `multiple`, selections render\n * as removable chips inside a `ComboboxChips` box and the popup stays open so\n * they accumulate; single-select uses a `ComboboxControl` input box and\n * closes on pick.\n *\n * Naming follows Base UI (`Combobox*`; shadcn has no canonical primitive — it\n * composes a recipe). The control chrome is split into composable parts\n * because a combobox is inherently more compositional than a select:\n * `ComboboxControl` / `ComboboxChips` own the bordered box, `ComboboxInput`\n * is the bare field, `ComboboxTrigger` the chevron. `ComboboxContent`\n * collapses `Portal` + `Positioner` + `Popup`; `ComboboxList` and\n * `ComboboxEmpty` sit inside it. The popup takes `width:\n * var(--anchor-width)` so it matches the control width exactly (long options\n * truncate) — the anchor-width affordance the picker call-sites needed.\n *\n * Per the form-control composition rule (Escuela 1, D11) the atom owns no\n * label / helper / error message; the consumer composes those and conveys\n * error via `aria-invalid`.\n *\n * @example single-select\n * <Combobox items={fruits} onValueChange={setValue}>\n * <ComboboxControl>\n * <ComboboxInput placeholder=\"Search fruit…\" />\n * <ComboboxTrigger />\n * </ComboboxControl>\n * <ComboboxContent>\n * <ComboboxEmpty>No fruit found</ComboboxEmpty>\n * <ComboboxList>\n * {(item) => (\n * <ComboboxItem key={item.value} value={item}>\n * {item.label}\n * </ComboboxItem>\n * )}\n * </ComboboxList>\n * </ComboboxContent>\n * </Combobox>\n */\nexport type ComboboxProps<\n Value,\n Multiple extends boolean | undefined = false,\n> = BaseCombobox.Root.Props<Value, Multiple>;\n\n/**\n * Lets `ComboboxChips` publish its DOM node so `ComboboxContent` can anchor\n * the floating listbox to the control box instead of the bare input.\n *\n * Why this exists: Base UI resolves the popup anchor as\n * `inputGroupElement ?? inputElement`. In single-select Pharos wraps Base UI's\n * `InputGroup` (`ComboboxControl`), so the popup anchors to the full-width\n * control. In multi-select Pharos uses `Combobox.Chips` (`ComboboxChips`) as\n * the bordered box — and `Chips` does NOT register an `inputGroupElement`, so\n * the anchor falls back to the `Input`, which floats at the end of the chip\n * row. The popup then opens narrow and shifted right. Capturing the chips box\n * here and passing it as the Positioner's `anchor` keeps the panel the full\n * control width, left-aligned, regardless of where the input sits.\n */\ninterface ComboboxAnchorContextValue {\n anchorElement: HTMLElement | null;\n setAnchorElement: (element: HTMLElement | null) => void;\n}\n\nconst ComboboxAnchorContext = createContext<ComboboxAnchorContextValue | null>(null);\n\nexport function Combobox<Value, Multiple extends boolean | undefined = false>(\n props: ComboboxProps<Value, Multiple>,\n) {\n const [anchorElement, setAnchorElement] = useState<HTMLElement | null>(null);\n const anchorContext = useMemo<ComboboxAnchorContextValue>(\n () => ({ anchorElement, setAnchorElement }),\n [anchorElement],\n );\n return (\n <ComboboxAnchorContext.Provider value={anchorContext}>\n <BaseCombobox.Root {...props} />\n </ComboboxAnchorContext.Provider>\n );\n}\n\nCombobox.displayName = 'Combobox';\n\n/** A downward chevron, inlined as an SVG (Pharos bundles no icon dependency; D4). */\nfunction ChevronDownIcon() {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" aria-hidden=\"true\">\n <path d=\"m6 9 6 6 6-6\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n );\n}\n\n/** A check mark for the selected option, inlined for the same reason. */\nfunction CheckIcon() {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" aria-hidden=\"true\">\n <path d=\"M20 6 9 17l-5-5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n );\n}\n\n/** A small ✕ for clearing / removing, inlined for the same reason. */\nfunction XIcon() {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" aria-hidden=\"true\">\n <path d=\"M18 6 6 18M6 6l12 12\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n );\n}\n\n/**\n * The bordered control box for **single-select**. Wraps Base UI's\n * `Combobox.InputGroup` and carries the Input chrome (border tone, focus\n * ring). Put a `ComboboxInput` and optionally a `ComboboxTrigger` /\n * `ComboboxClear` inside it.\n */\nexport type ComboboxControlProps = ComponentProps<typeof BaseCombobox.InputGroup>;\n\nexport function ComboboxControl({ className, ...rest }: ComboboxControlProps) {\n return (\n <BaseCombobox.InputGroup\n data-pharos-slot=\"combobox-control\"\n className={cn(styles.control, className)}\n {...rest}\n />\n );\n}\n\nComboboxControl.displayName = 'ComboboxControl';\n\n/**\n * The bordered control box for **multi-select**. Wraps Base UI's\n * `Combobox.Chips`; render `ComboboxChip`s for the current selections\n * followed by a `ComboboxInput` to keep typing. Shares the `ComboboxControl`\n * chrome.\n */\nexport type ComboboxChipsProps = ComponentProps<typeof BaseCombobox.Chips>;\n\nexport function ComboboxChips({ className, ref, ...rest }: ComboboxChipsProps) {\n const anchorContext = useContext(ComboboxAnchorContext);\n // Publish the chips box as the popup anchor (see ComboboxAnchorContext)\n // while still honouring any ref the consumer forwards.\n const setRef = useCallback(\n (element: HTMLDivElement | null) => {\n anchorContext?.setAnchorElement(element);\n if (typeof ref === 'function') {\n ref(element);\n } else if (ref) {\n (ref as { current: HTMLDivElement | null }).current = element;\n }\n },\n [anchorContext, ref],\n );\n return (\n <BaseCombobox.Chips\n data-pharos-slot=\"combobox-chips\"\n className={cn(styles.control, styles.chips, className)}\n ref={setRef as Ref<HTMLDivElement>}\n {...rest}\n />\n );\n}\n\nComboboxChips.displayName = 'ComboboxChips';\n\nconst inputVariants = cva(styles.input, {\n variants: {\n size: {\n sm: styles.inputSizeSm,\n md: styles.inputSizeMd,\n lg: styles.inputSizeLg,\n },\n },\n defaultVariants: {\n size: 'md',\n },\n});\n\ntype InputVariantProps = VariantProps<typeof inputVariants>;\n\n/**\n * The text field. Wraps Base UI's `Combobox.Input` (`role=\"combobox\"`),\n * which owns the filtering. Renders bare — the surrounding `ComboboxControl`\n * / `ComboboxChips` box owns the border. The `size` axis (sm / md / lg)\n * matches Input/Select and applies when the input is used standalone in a\n * `ComboboxControl`; inside a `ComboboxChips` box pass `inset` so it fills\n * the chip row instead of imposing its own height.\n */\nexport interface ComboboxInputProps\n extends Omit<ComponentProps<typeof BaseCombobox.Input>, 'size'>, InputVariantProps {\n /**\n * Render as a flexible filler that shares the row with chips, instead of a\n * fixed-height field. Use inside `ComboboxChips`.\n * @default false\n */\n inset?: boolean;\n}\n\nexport function ComboboxInput({ size, inset = false, className, ...rest }: ComboboxInputProps) {\n const resolvedSize = size ?? 'md';\n return (\n <BaseCombobox.Input\n data-pharos-slot=\"combobox-input\"\n data-pharos-size={resolvedSize}\n className={cn(\n inset ? cn(styles.input, styles.chipsInput) : inputVariants({ size: resolvedSize }),\n className,\n )}\n {...rest}\n />\n );\n}\n\nComboboxInput.displayName = 'ComboboxInput';\n\n/**\n * The chevron button that toggles the popup. Wraps Base UI's\n * `Combobox.Trigger`; the chevron flips when the popup is open.\n */\nexport type ComboboxTriggerProps = ComponentProps<typeof BaseCombobox.Trigger>;\n\nexport function ComboboxTrigger({ className, children, ...rest }: ComboboxTriggerProps) {\n return (\n <BaseCombobox.Trigger\n data-pharos-slot=\"combobox-trigger\"\n className={cn(styles.trigger, className)}\n {...rest}\n >\n {children ?? <ChevronDownIcon />}\n </BaseCombobox.Trigger>\n );\n}\n\nComboboxTrigger.displayName = 'ComboboxTrigger';\n\n/** A button that clears the current value(s). Wraps Base UI's `Combobox.Clear`. */\nexport type ComboboxClearProps = ComponentProps<typeof BaseCombobox.Clear>;\n\nexport function ComboboxClear({ className, children, ...rest }: ComboboxClearProps) {\n return (\n <BaseCombobox.Clear\n data-pharos-slot=\"combobox-clear\"\n className={cn(styles.clear, className)}\n {...rest}\n >\n {children ?? <XIcon />}\n </BaseCombobox.Clear>\n );\n}\n\nComboboxClear.displayName = 'ComboboxClear';\n\n/** A selected-value chip for multi-select. Wraps Base UI's `Combobox.Chip`. */\nexport type ComboboxChipProps = ComponentProps<typeof BaseCombobox.Chip>;\n\nexport function ComboboxChip({ className, ...rest }: ComboboxChipProps) {\n return (\n <BaseCombobox.Chip\n data-pharos-slot=\"combobox-chip\"\n className={cn(styles.chip, className)}\n {...rest}\n />\n );\n}\n\nComboboxChip.displayName = 'ComboboxChip';\n\n/** The ✕ that removes a chip's value. Wraps Base UI's `Combobox.ChipRemove`. */\nexport type ComboboxChipRemoveProps = ComponentProps<typeof BaseCombobox.ChipRemove>;\n\nexport function ComboboxChipRemove({\n className,\n children,\n 'aria-label': ariaLabel = 'Remove',\n ...rest\n}: ComboboxChipRemoveProps) {\n return (\n <BaseCombobox.ChipRemove\n data-pharos-slot=\"combobox-chip-remove\"\n aria-label={ariaLabel}\n className={cn(styles.chipRemove, className)}\n {...rest}\n >\n {children ?? <XIcon />}\n </BaseCombobox.ChipRemove>\n );\n}\n\nComboboxChipRemove.displayName = 'ComboboxChipRemove';\n\n/**\n * The floating listbox surface. Collapses Base UI's `Portal` + `Positioner` +\n * `Popup`. Put `ComboboxEmpty` and `ComboboxList` inside it. Defaults: opens\n * below the control, aligned to its start edge, 8px away, and matches the\n * control width (`width: var(--anchor-width)`).\n */\nexport interface ComboboxContentProps extends ComponentProps<typeof BaseCombobox.Popup> {\n /**\n * Which side of the control the listbox opens on.\n * @default 'bottom'\n */\n side?: ComponentProps<typeof BaseCombobox.Positioner>['side'];\n /**\n * Alignment of the listbox relative to the control along the chosen side.\n * @default 'start'\n */\n align?: ComponentProps<typeof BaseCombobox.Positioner>['align'];\n /**\n * Gap in pixels between the control and the listbox.\n * @default 8\n */\n sideOffset?: ComponentProps<typeof BaseCombobox.Positioner>['sideOffset'];\n /**\n * Offset in pixels along the alignment axis.\n * @default 0\n */\n alignOffset?: ComponentProps<typeof BaseCombobox.Positioner>['alignOffset'];\n}\n\nexport function ComboboxContent({\n side = 'bottom',\n align = 'start',\n sideOffset = 8,\n alignOffset = 0,\n className,\n children,\n ...rest\n}: ComboboxContentProps) {\n const anchorContext = useContext(ComboboxAnchorContext);\n // Anchor to the chips control box in multi-select (see\n // ComboboxAnchorContext); single-select leaves this undefined so Base UI\n // anchors to the `ComboboxControl` (InputGroup) as before.\n const anchor = anchorContext?.anchorElement ?? undefined;\n return (\n <BaseCombobox.Portal>\n <BaseCombobox.Positioner\n className={styles.positioner}\n anchor={anchor}\n side={side}\n align={align}\n sideOffset={sideOffset}\n alignOffset={alignOffset}\n >\n <BaseCombobox.Popup\n data-pharos-slot=\"combobox-content\"\n className={cn(styles.content, className)}\n {...rest}\n >\n {children}\n </BaseCombobox.Popup>\n </BaseCombobox.Positioner>\n </BaseCombobox.Portal>\n );\n}\n\nComboboxContent.displayName = 'ComboboxContent';\n\n/**\n * The list of results. Wraps Base UI's `Combobox.List`, which accepts either\n * static children or a render function `(item, index) => ReactNode` that maps\n * over the (already filtered) `items` passed to the root.\n */\nexport type ComboboxListProps = ComponentProps<typeof BaseCombobox.List>;\n\nexport function ComboboxList({ className, ...rest }: ComboboxListProps) {\n return <BaseCombobox.List data-pharos-slot=\"combobox-list\" className={className} {...rest} />;\n}\n\nComboboxList.displayName = 'ComboboxList';\n\n/**\n * A single result row. Folds Base UI's `Item` + the selected-state\n * `ItemIndicator` check. The `value` prop is what `onValueChange` reports.\n */\nexport interface ComboboxItemProps extends ComponentProps<typeof BaseCombobox.Item> {}\n\nexport function ComboboxItem({ className, children, ...rest }: ComboboxItemProps) {\n return (\n <BaseCombobox.Item\n data-pharos-slot=\"combobox-item\"\n className={cn(styles.item, className)}\n {...rest}\n >\n <span className={styles.itemText}>{children}</span>\n <BaseCombobox.ItemIndicator className={styles.itemIndicator}>\n <CheckIcon />\n </BaseCombobox.ItemIndicator>\n </BaseCombobox.Item>\n );\n}\n\nComboboxItem.displayName = 'ComboboxItem';\n\n/**\n * Shown in place of the list when the filter matches nothing. Wraps Base UI's\n * `Combobox.Empty`, which is only rendered when there are no results.\n */\nexport type ComboboxEmptyProps = ComponentProps<typeof BaseCombobox.Empty>;\n\nexport function ComboboxEmpty({ className, ...rest }: ComboboxEmptyProps) {\n return (\n <BaseCombobox.Empty\n data-pharos-slot=\"combobox-empty\"\n className={cn(styles.empty, className)}\n {...rest}\n />\n );\n}\n\nComboboxEmpty.displayName = 'ComboboxEmpty';\n\n/** Groups related results under an optional `ComboboxGroupLabel` (`role=\"group\"`). */\nexport type ComboboxGroupProps = ComponentProps<typeof BaseCombobox.Group>;\n\nexport function ComboboxGroup(props: ComboboxGroupProps) {\n return <BaseCombobox.Group data-pharos-slot=\"combobox-group\" {...props} />;\n}\n\nComboboxGroup.displayName = 'ComboboxGroup';\n\n/** A non-interactive heading for a `ComboboxGroup`. Wraps `Combobox.GroupLabel`. */\nexport type ComboboxGroupLabelProps = ComponentProps<typeof BaseCombobox.GroupLabel>;\n\nexport function ComboboxGroupLabel({ className, ...rest }: ComboboxGroupLabelProps) {\n return (\n <BaseCombobox.GroupLabel\n data-pharos-slot=\"combobox-group-label\"\n className={cn(styles.label, className)}\n {...rest}\n />\n );\n}\n\nComboboxGroupLabel.displayName = 'ComboboxGroupLabel';\n\n/** A thin divider between groups of results. Wraps `Combobox.Separator`. */\nexport type ComboboxSeparatorProps = ComponentProps<typeof BaseCombobox.Separator>;\n\nexport function ComboboxSeparator({ className, ...rest }: ComboboxSeparatorProps) {\n return (\n <BaseCombobox.Separator\n data-pharos-slot=\"combobox-separator\"\n className={cn(styles.separator, className)}\n {...rest}\n />\n );\n}\n\nComboboxSeparator.displayName = 'ComboboxSeparator';\n"],"mappings":"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"}
1
+ {"version":3,"file":"Combobox.js","names":[],"sources":["../../src/components/Combobox.tsx"],"sourcesContent":["'use client';\n\nimport {\n type ComponentProps,\n type Ref,\n createContext,\n useCallback,\n useContext,\n useMemo,\n useState,\n} from 'react';\nimport { Combobox as BaseCombobox } from '@base-ui/react/combobox';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '../lib/cn';\nimport styles from './Combobox.module.css';\n\n/**\n * Single- or multi-select with a **text input that filters the options**\n * (Decision D17). Wraps Base UI's `Combobox.*` parts, which implement the\n * ARIA APG **combobox** pattern: an `<input role=\"combobox\">` with\n * `aria-expanded` / `aria-controls` pointing at a popup listbox, typeahead\n * filtering, and arrow-key navigation of the results.\n *\n * This is deliberately distinct from the `Select` atom (also D17). A Select\n * has no input — the user picks from a closed list. A Combobox is for sets\n * large enough to need filtering, or where the user expects to type. shadcn,\n * Base UI and ARIA APG separate the two; Pharos ships both rather than a\n * single component with a `searchable` axis. (Free-text entry — typing a\n * value that is not in the list — is Base UI's separate `Autocomplete`\n * primitive and is deferred; every known Alexandria call-site filters a known\n * set.) See the Select + Combobox page of the naming decisions:\n * https://app.notion.com/p/4071751eee108172bf64fdbe0fe8a94b\n *\n * Multi-select is the `multiple` axis on the root (not a separate atom),\n * matching Base UI / shadcn / React Aria. With `multiple`, selections render\n * as removable chips inside a `ComboboxChips` box and the popup stays open so\n * they accumulate; single-select uses a `ComboboxControl` input box and\n * closes on pick.\n *\n * Naming follows Base UI (`Combobox*`; shadcn has no canonical primitive — it\n * composes a recipe). The control chrome is split into composable parts\n * because a combobox is inherently more compositional than a select:\n * `ComboboxControl` / `ComboboxChips` own the bordered box, `ComboboxInput`\n * is the bare field, `ComboboxTrigger` the chevron. `ComboboxContent`\n * collapses `Portal` + `Positioner` + `Popup`; `ComboboxList` and\n * `ComboboxEmpty` sit inside it. The popup takes `width:\n * var(--anchor-width)` so it matches the control width exactly (long options\n * truncate) — the anchor-width affordance the picker call-sites needed.\n *\n * Per the form-control composition rule (Escuela 1, D11) the atom owns no\n * label / helper / error message; the consumer composes those and conveys\n * error via `aria-invalid`.\n *\n * @example single-select\n * <Combobox items={fruits} onValueChange={setValue}>\n * <ComboboxControl>\n * <ComboboxInput placeholder=\"Search fruit…\" />\n * <ComboboxTrigger />\n * </ComboboxControl>\n * <ComboboxContent>\n * <ComboboxEmpty>No fruit found</ComboboxEmpty>\n * <ComboboxList>\n * {(item) => (\n * <ComboboxItem key={item.value} value={item}>\n * {item.label}\n * </ComboboxItem>\n * )}\n * </ComboboxList>\n * </ComboboxContent>\n * </Combobox>\n */\nexport type ComboboxProps<\n Value,\n Multiple extends boolean | undefined = false,\n> = BaseCombobox.Root.Props<Value, Multiple>;\n\n/**\n * Lets `ComboboxChips` publish its DOM node so `ComboboxContent` can anchor\n * the floating listbox to the control box instead of the bare input.\n *\n * Why this exists: Base UI resolves the popup anchor as\n * `inputGroupElement ?? inputElement`. In single-select Pharos wraps Base UI's\n * `InputGroup` (`ComboboxControl`), so the popup anchors to the full-width\n * control. In multi-select Pharos uses `Combobox.Chips` (`ComboboxChips`) as\n * the bordered box — and `Chips` does NOT register an `inputGroupElement`, so\n * the anchor falls back to the `Input`, which floats at the end of the chip\n * row. The popup then opens narrow and shifted right. Capturing the chips box\n * here and passing it as the Positioner's `anchor` keeps the panel the full\n * control width, left-aligned, regardless of where the input sits.\n */\ninterface ComboboxAnchorContextValue {\n anchorElement: HTMLElement | null;\n setAnchorElement: (element: HTMLElement | null) => void;\n}\n\nconst ComboboxAnchorContext = createContext<ComboboxAnchorContextValue | null>(null);\n\nexport function Combobox<Value, Multiple extends boolean | undefined = false>(\n props: ComboboxProps<Value, Multiple>,\n) {\n const [anchorElement, setAnchorElement] = useState<HTMLElement | null>(null);\n const anchorContext = useMemo<ComboboxAnchorContextValue>(\n () => ({ anchorElement, setAnchorElement }),\n [anchorElement],\n );\n return (\n <ComboboxAnchorContext.Provider value={anchorContext}>\n <BaseCombobox.Root {...props} />\n </ComboboxAnchorContext.Provider>\n );\n}\n\nCombobox.displayName = 'Combobox';\n\n/** A downward chevron, inlined as an SVG (Pharos bundles no icon dependency; D4). */\nfunction ChevronDownIcon() {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" aria-hidden=\"true\">\n <path d=\"m6 9 6 6 6-6\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n );\n}\n\n/** A check mark for the selected option, inlined for the same reason. */\nfunction CheckIcon() {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" aria-hidden=\"true\">\n <path d=\"M20 6 9 17l-5-5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n );\n}\n\n/** A small ✕ for clearing / removing, inlined for the same reason. */\nfunction XIcon() {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" aria-hidden=\"true\">\n <path d=\"M18 6 6 18M6 6l12 12\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n );\n}\n\n/**\n * The bordered control box for **single-select**. Wraps Base UI's\n * `Combobox.InputGroup` and carries the Input chrome (border tone, focus\n * ring). Put a `ComboboxInput` and optionally a `ComboboxTrigger` /\n * `ComboboxClear` inside it.\n */\nexport type ComboboxControlProps = ComponentProps<typeof BaseCombobox.InputGroup>;\n\nexport function ComboboxControl({ className, ...rest }: ComboboxControlProps) {\n return (\n <BaseCombobox.InputGroup\n data-pharos-slot=\"combobox-control\"\n className={cn(styles.control, className)}\n {...rest}\n />\n );\n}\n\nComboboxControl.displayName = 'ComboboxControl';\n\n/**\n * The bordered control box for **multi-select**. Wraps Base UI's\n * `Combobox.Chips`; render `ComboboxChip`s for the current selections\n * followed by a `ComboboxInput` to keep typing. Shares the `ComboboxControl`\n * chrome.\n */\nexport type ComboboxChipsProps = ComponentProps<typeof BaseCombobox.Chips>;\n\nexport function ComboboxChips({ className, ref, ...rest }: ComboboxChipsProps) {\n const anchorContext = useContext(ComboboxAnchorContext);\n // Publish the chips box as the popup anchor (see ComboboxAnchorContext)\n // while still honouring any ref the consumer forwards.\n const setRef = useCallback(\n (element: HTMLDivElement | null) => {\n anchorContext?.setAnchorElement(element);\n if (typeof ref === 'function') {\n ref(element);\n } else if (ref) {\n (ref as { current: HTMLDivElement | null }).current = element;\n }\n },\n [anchorContext, ref],\n );\n return (\n <BaseCombobox.Chips\n data-pharos-slot=\"combobox-chips\"\n className={cn(styles.control, styles.chips, className)}\n ref={setRef as Ref<HTMLDivElement>}\n {...rest}\n />\n );\n}\n\nComboboxChips.displayName = 'ComboboxChips';\n\nconst inputVariants = cva(styles.input, {\n variants: {\n size: {\n sm: styles.inputSizeSm,\n md: styles.inputSizeMd,\n lg: styles.inputSizeLg,\n },\n },\n defaultVariants: {\n size: 'md',\n },\n});\n\ntype InputVariantProps = VariantProps<typeof inputVariants>;\n\n/**\n * The text field. Wraps Base UI's `Combobox.Input` (`role=\"combobox\"`),\n * which owns the filtering. Renders bare — the surrounding `ComboboxControl`\n * / `ComboboxChips` box owns the border. The `size` axis (sm / md / lg)\n * matches Input/Select and applies when the input is used standalone in a\n * `ComboboxControl`; inside a `ComboboxChips` box pass `inset` so it fills\n * the chip row instead of imposing its own height.\n */\nexport interface ComboboxInputProps\n extends Omit<ComponentProps<typeof BaseCombobox.Input>, 'size'>, InputVariantProps {\n /**\n * Render as a flexible filler that shares the row with chips, instead of a\n * fixed-height field. Use inside `ComboboxChips`.\n * @default false\n */\n inset?: boolean;\n}\n\nexport function ComboboxInput({ size, inset = false, className, ...rest }: ComboboxInputProps) {\n const resolvedSize = size ?? 'md';\n return (\n <BaseCombobox.Input\n data-pharos-slot=\"combobox-input\"\n data-pharos-size={resolvedSize}\n className={cn(\n inset ? cn(styles.input, styles.chipsInput) : inputVariants({ size: resolvedSize }),\n className,\n )}\n {...rest}\n />\n );\n}\n\nComboboxInput.displayName = 'ComboboxInput';\n\n/**\n * The chevron button that toggles the popup. Wraps Base UI's\n * `Combobox.Trigger`; the chevron flips when the popup is open.\n */\nexport type ComboboxTriggerProps = ComponentProps<typeof BaseCombobox.Trigger>;\n\nexport function ComboboxTrigger({ className, children, ...rest }: ComboboxTriggerProps) {\n return (\n <BaseCombobox.Trigger\n data-pharos-slot=\"combobox-trigger\"\n className={cn(styles.trigger, className)}\n {...rest}\n >\n {children ?? <ChevronDownIcon />}\n </BaseCombobox.Trigger>\n );\n}\n\nComboboxTrigger.displayName = 'ComboboxTrigger';\n\n/** A button that clears the current value(s). Wraps Base UI's `Combobox.Clear`. */\nexport type ComboboxClearProps = ComponentProps<typeof BaseCombobox.Clear>;\n\nexport function ComboboxClear({ className, children, ...rest }: ComboboxClearProps) {\n return (\n <BaseCombobox.Clear\n data-pharos-slot=\"combobox-clear\"\n className={cn(styles.clear, className)}\n {...rest}\n >\n {children ?? <XIcon />}\n </BaseCombobox.Clear>\n );\n}\n\nComboboxClear.displayName = 'ComboboxClear';\n\n/** A selected-value chip for multi-select. Wraps Base UI's `Combobox.Chip`. */\nexport type ComboboxChipProps = ComponentProps<typeof BaseCombobox.Chip>;\n\nexport function ComboboxChip({ className, ...rest }: ComboboxChipProps) {\n return (\n <BaseCombobox.Chip\n data-pharos-slot=\"combobox-chip\"\n className={cn(styles.chip, className)}\n {...rest}\n />\n );\n}\n\nComboboxChip.displayName = 'ComboboxChip';\n\n/** The ✕ that removes a chip's value. Wraps Base UI's `Combobox.ChipRemove`. */\nexport type ComboboxChipRemoveProps = ComponentProps<typeof BaseCombobox.ChipRemove>;\n\nexport function ComboboxChipRemove({\n className,\n children,\n 'aria-label': ariaLabel = 'Remove',\n ...rest\n}: ComboboxChipRemoveProps) {\n return (\n <BaseCombobox.ChipRemove\n data-pharos-slot=\"combobox-chip-remove\"\n aria-label={ariaLabel}\n className={cn(styles.chipRemove, className)}\n {...rest}\n >\n {children ?? <XIcon />}\n </BaseCombobox.ChipRemove>\n );\n}\n\nComboboxChipRemove.displayName = 'ComboboxChipRemove';\n\n/**\n * The floating listbox surface. Collapses Base UI's `Portal` + `Positioner` +\n * `Popup`. Put `ComboboxEmpty` and `ComboboxList` inside it. Defaults: opens\n * below the control, aligned to its start edge, 8px away, and matches the\n * control width (`width: var(--anchor-width)`).\n */\nexport interface ComboboxContentProps extends ComponentProps<typeof BaseCombobox.Popup> {\n /**\n * Which side of the control the listbox opens on.\n * @default 'bottom'\n */\n side?: ComponentProps<typeof BaseCombobox.Positioner>['side'];\n /**\n * Alignment of the listbox relative to the control along the chosen side.\n * @default 'start'\n */\n align?: ComponentProps<typeof BaseCombobox.Positioner>['align'];\n /**\n * Gap in pixels between the control and the listbox.\n * @default 8\n */\n sideOffset?: ComponentProps<typeof BaseCombobox.Positioner>['sideOffset'];\n /**\n * Offset in pixels along the alignment axis.\n * @default 0\n */\n alignOffset?: ComponentProps<typeof BaseCombobox.Positioner>['alignOffset'];\n}\n\nexport function ComboboxContent({\n side = 'bottom',\n align = 'start',\n sideOffset = 8,\n alignOffset = 0,\n className,\n children,\n ...rest\n}: ComboboxContentProps) {\n const anchorContext = useContext(ComboboxAnchorContext);\n // Anchor to the chips control box in multi-select (see\n // ComboboxAnchorContext); single-select leaves this undefined so Base UI\n // anchors to the `ComboboxControl` (InputGroup) as before.\n const anchor = anchorContext?.anchorElement ?? undefined;\n return (\n <BaseCombobox.Portal>\n <BaseCombobox.Positioner\n className={styles.positioner}\n anchor={anchor}\n side={side}\n align={align}\n sideOffset={sideOffset}\n alignOffset={alignOffset}\n >\n <BaseCombobox.Popup\n data-pharos-slot=\"combobox-content\"\n className={cn(styles.content, className)}\n {...rest}\n >\n {children}\n </BaseCombobox.Popup>\n </BaseCombobox.Positioner>\n </BaseCombobox.Portal>\n );\n}\n\nComboboxContent.displayName = 'ComboboxContent';\n\n/**\n * The list of results. Wraps Base UI's `Combobox.List`, which accepts either\n * static children or a render function `(item, index) => ReactNode` that maps\n * over the (already filtered) `items` passed to the root.\n */\nexport type ComboboxListProps = ComponentProps<typeof BaseCombobox.List>;\n\nexport function ComboboxList({ className, ...rest }: ComboboxListProps) {\n return <BaseCombobox.List data-pharos-slot=\"combobox-list\" className={className} {...rest} />;\n}\n\nComboboxList.displayName = 'ComboboxList';\n\n/**\n * A single result row. Folds Base UI's `Item` + the selected-state\n * `ItemIndicator` check. The `value` prop is what `onValueChange` reports.\n */\nexport interface ComboboxItemProps extends ComponentProps<typeof BaseCombobox.Item> {}\n\nexport function ComboboxItem({ className, children, ...rest }: ComboboxItemProps) {\n return (\n <BaseCombobox.Item\n data-pharos-slot=\"combobox-item\"\n className={cn(styles.item, className)}\n {...rest}\n >\n <span className={styles.itemText}>{children}</span>\n <BaseCombobox.ItemIndicator className={styles.itemIndicator}>\n <CheckIcon />\n </BaseCombobox.ItemIndicator>\n </BaseCombobox.Item>\n );\n}\n\nComboboxItem.displayName = 'ComboboxItem';\n\n/**\n * Shown in place of the list when the filter matches nothing. Wraps Base UI's\n * `Combobox.Empty`, which is only rendered when there are no results.\n */\nexport type ComboboxEmptyProps = ComponentProps<typeof BaseCombobox.Empty>;\n\nexport function ComboboxEmpty({ className, ...rest }: ComboboxEmptyProps) {\n return (\n <BaseCombobox.Empty\n data-pharos-slot=\"combobox-empty\"\n className={cn(styles.empty, className)}\n {...rest}\n />\n );\n}\n\nComboboxEmpty.displayName = 'ComboboxEmpty';\n\n/** Groups related results under an optional `ComboboxGroupLabel` (`role=\"group\"`). */\nexport type ComboboxGroupProps = ComponentProps<typeof BaseCombobox.Group>;\n\nexport function ComboboxGroup(props: ComboboxGroupProps) {\n return <BaseCombobox.Group data-pharos-slot=\"combobox-group\" {...props} />;\n}\n\nComboboxGroup.displayName = 'ComboboxGroup';\n\n/** A non-interactive heading for a `ComboboxGroup`. Wraps `Combobox.GroupLabel`. */\nexport type ComboboxGroupLabelProps = ComponentProps<typeof BaseCombobox.GroupLabel>;\n\nexport function ComboboxGroupLabel({ className, ...rest }: ComboboxGroupLabelProps) {\n return (\n <BaseCombobox.GroupLabel\n data-pharos-slot=\"combobox-group-label\"\n className={cn(styles.label, className)}\n {...rest}\n />\n );\n}\n\nComboboxGroupLabel.displayName = 'ComboboxGroupLabel';\n\n/** A thin divider between groups of results. Wraps `Combobox.Separator`. */\nexport type ComboboxSeparatorProps = ComponentProps<typeof BaseCombobox.Separator>;\n\nexport function ComboboxSeparator({ className, ...rest }: ComboboxSeparatorProps) {\n return (\n <BaseCombobox.Separator\n data-pharos-slot=\"combobox-separator\"\n className={cn(styles.separator, className)}\n {...rest}\n />\n );\n}\n\nComboboxSeparator.displayName = 'ComboboxSeparator';\n"],"mappings":"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"}
@@ -12,7 +12,7 @@ import { Menu } from '@base-ui/react/menu';
12
12
  * disclosure/dialog contract). 7 of 8 surveyed design systems separate
13
13
  * the two for exactly this reason — putting `role="menu"` around
14
14
  * arbitrary content breaks screen-reader expectations. See
15
- * `NAMING-decisions.md` § DropdownMenu.
15
+ * the DropdownMenu page of the naming decisions: https://app.notion.com/p/4071751eee10815ab61dc5e63758da12
16
16
  *
17
17
  * Naming follows shadcn (`DropdownMenu*`, not Base UI's `Menu`). The
18
18
  * compound surface collapses Base UI's `Portal` + `Positioner` + `Popup`
@@ -1 +1 @@
1
- {"version":3,"file":"DropdownMenu.js","names":[],"sources":["../../src/components/DropdownMenu.tsx"],"sourcesContent":["'use client';\n\nimport type { ComponentProps } from 'react';\nimport { Menu } from '@base-ui/react/menu';\nimport { cn } from '../lib/cn';\nimport styles from './DropdownMenu.module.css';\n\n/**\n * Action menu anchored to a trigger (Decision D15). Wraps Base UI's\n * `Menu.*` parts, which implement the ARIA APG **menu button** pattern:\n * `role=\"menu\"` / `menuitem`, roving focus, arrow-key navigation,\n * typeahead, and Escape-to-close with focus return to the trigger.\n *\n * This is deliberately distinct from a future `Popover` atom. A\n * DropdownMenu is for **commands** (the menu-button contract); free-form\n * anchored content (forms, navigation links) belongs in a Popover (the\n * disclosure/dialog contract). 7 of 8 surveyed design systems separate\n * the two for exactly this reason — putting `role=\"menu\"` around\n * arbitrary content breaks screen-reader expectations. See\n * `NAMING-decisions.md` § DropdownMenu.\n *\n * Naming follows shadcn (`DropdownMenu*`, not Base UI's `Menu`). The\n * compound surface collapses Base UI's `Portal` + `Positioner` + `Popup`\n * into a single `DropdownMenuContent` with `side` / `align` /\n * `sideOffset` props — the same ergonomics shadcn exposes over Radix.\n *\n * v1 ships the parts the known consumers need (kebab row menus, the\n * MobileHeader user actions): Trigger, Content, Item, Separator, Label,\n * Group. `CheckboxItem`, `RadioItem`, submenus and `LinkItem` are\n * deliberately deferred — no Alexandria call-site exercises them, and the\n * compound API makes them additive without a breaking change.\n *\n * @example\n * <DropdownMenu>\n * <DropdownMenuTrigger render={<IconButton aria-label=\"Options\"><MoreIcon /></IconButton>} />\n * <DropdownMenuContent>\n * <DropdownMenuItem onClick={onRename}>Rename</DropdownMenuItem>\n * <DropdownMenuSeparator />\n * <DropdownMenuItem variant=\"destructive\" onClick={onDelete}>Delete</DropdownMenuItem>\n * </DropdownMenuContent>\n * </DropdownMenu>\n */\nexport type DropdownMenuProps = ComponentProps<typeof Menu.Root>;\n\nexport function DropdownMenu(props: DropdownMenuProps) {\n return <Menu.Root {...props} />;\n}\n\nDropdownMenu.displayName = 'DropdownMenu';\n\n/**\n * The element that opens the menu. Renders a native `<button>` by\n * default; pass `render` to compose any control while keeping the menu\n * wiring — the dominant case is the kebab `IconButton` (D13):\n * `<DropdownMenuTrigger render={<IconButton aria-label=\"Options\"><MoreIcon /></IconButton>} />`.\n */\nexport type DropdownMenuTriggerProps = ComponentProps<typeof Menu.Trigger>;\n\nexport function DropdownMenuTrigger(props: DropdownMenuTriggerProps) {\n return <Menu.Trigger {...props} />;\n}\n\nDropdownMenuTrigger.displayName = 'DropdownMenuTrigger';\n\n/**\n * The floating surface. Collapses Base UI's `Portal` + `Positioner` +\n * `Popup` so the consumer positions the menu with the three props that\n * actually matter at the call site. Defaults match the common dropdown:\n * opens below the trigger, aligned to its start edge, 8px away.\n */\nexport interface DropdownMenuContentProps extends ComponentProps<typeof Menu.Popup> {\n /**\n * Which side of the trigger the menu opens on.\n * @default 'bottom'\n */\n side?: ComponentProps<typeof Menu.Positioner>['side'];\n /**\n * Alignment of the menu relative to the trigger along the chosen side.\n * @default 'start'\n */\n align?: ComponentProps<typeof Menu.Positioner>['align'];\n /**\n * Gap in pixels between the trigger and the menu.\n * @default 8\n */\n sideOffset?: ComponentProps<typeof Menu.Positioner>['sideOffset'];\n}\n\nexport function DropdownMenuContent({\n side = 'bottom',\n align = 'start',\n sideOffset = 8,\n className,\n children,\n ...rest\n}: DropdownMenuContentProps) {\n return (\n <Menu.Portal>\n <Menu.Positioner\n className={styles.positioner}\n side={side}\n align={align}\n sideOffset={sideOffset}\n >\n <Menu.Popup\n data-pharos-slot=\"dropdown-menu-content\"\n className={cn(styles.content, className)}\n {...rest}\n >\n {children}\n </Menu.Popup>\n </Menu.Positioner>\n </Menu.Portal>\n );\n}\n\nDropdownMenuContent.displayName = 'DropdownMenuContent';\n\n/**\n * A single action row. `variant=\"destructive\"` tints the row with the\n * error foreground for delete / remove actions — the same tone the\n * destructive Button uses, and the equivalent of shadcn's destructive\n * item variant. By default a click closes the menu (`closeOnClick`);\n * pass `closeOnClick={false}` for rows that should keep it open.\n */\nexport interface DropdownMenuItemProps extends ComponentProps<typeof Menu.Item> {\n /**\n * Visual tone of the row.\n * @default 'default'\n */\n variant?: 'default' | 'destructive';\n}\n\nexport function DropdownMenuItem({\n variant = 'default',\n className,\n ...rest\n}: DropdownMenuItemProps) {\n return (\n <Menu.Item\n data-pharos-variant={variant}\n className={cn(styles.item, variant === 'destructive' && styles.itemDestructive, className)}\n {...rest}\n />\n );\n}\n\nDropdownMenuItem.displayName = 'DropdownMenuItem';\n\n/** A thin divider between groups of items. */\nexport type DropdownMenuSeparatorProps = ComponentProps<typeof Menu.Separator>;\n\nexport function DropdownMenuSeparator({ className, ...rest }: DropdownMenuSeparatorProps) {\n return (\n <Menu.Separator\n data-pharos-slot=\"dropdown-menu-separator\"\n className={cn(styles.separator, className)}\n {...rest}\n />\n );\n}\n\nDropdownMenuSeparator.displayName = 'DropdownMenuSeparator';\n\n/**\n * A non-interactive heading for a group of items. Renders Base UI's\n * `Menu.GroupLabel`, which wires `aria-labelledby` on the surrounding\n * `DropdownMenuGroup` — so use the two together when a section needs an\n * accessible name.\n */\nexport type DropdownMenuLabelProps = ComponentProps<typeof Menu.GroupLabel>;\n\nexport function DropdownMenuLabel({ className, ...rest }: DropdownMenuLabelProps) {\n return (\n <Menu.GroupLabel\n data-pharos-slot=\"dropdown-menu-label\"\n className={cn(styles.label, className)}\n {...rest}\n />\n );\n}\n\nDropdownMenuLabel.displayName = 'DropdownMenuLabel';\n\n/**\n * Groups related items under an optional `DropdownMenuLabel` for\n * accessible sectioning (`role=\"group\"`).\n */\nexport type DropdownMenuGroupProps = ComponentProps<typeof Menu.Group>;\n\nexport function DropdownMenuGroup(props: DropdownMenuGroupProps) {\n return <Menu.Group data-pharos-slot=\"dropdown-menu-group\" {...props} />;\n}\n\nDropdownMenuGroup.displayName = 'DropdownMenuGroup';\n"],"mappings":";;;;;;AA4CA,SAAgB,EAAa,GAA0B;CACrD,OAAO,kBAAC,EAAK,MAAN,EAAW,GAAI,EAAQ,CAAA;AAChC;AAEA,EAAa,cAAc;AAU3B,SAAgB,EAAoB,GAAiC;CACnE,OAAO,kBAAC,EAAK,SAAN,EAAc,GAAI,EAAQ,CAAA;AACnC;AAEA,EAAoB,cAAc;AA0BlC,SAAgB,EAAoB,EAClC,UAAO,UACP,WAAQ,SACR,gBAAa,GACb,cACA,aACA,GAAG,KACwB;CAC3B,OACE,kBAAC,EAAK,QAAN,EAAA,UACE,kBAAC,EAAK,YAAN;EACE,WAAW,EAAO;EACZ;EACC;EACK;YAEZ,kBAAC,EAAK,OAAN;GACE,oBAAiB;GACjB,WAAW,EAAG,EAAO,SAAS,CAAS;GACvC,GAAI;GAEH;EACS,CAAA;CACG,CAAA,EACN,CAAA;AAEjB;AAEA,EAAoB,cAAc;AAiBlC,SAAgB,EAAiB,EAC/B,aAAU,WACV,cACA,GAAG,KACqB;CACxB,OACE,kBAAC,EAAK,MAAN;EACE,uBAAqB;EACrB,WAAW,EAAG,EAAO,MAAM,MAAY,iBAAiB,EAAO,iBAAiB,CAAS;EACzF,GAAI;CACL,CAAA;AAEL;AAEA,EAAiB,cAAc;AAK/B,SAAgB,EAAsB,EAAE,cAAW,GAAG,KAAoC;CACxF,OACE,kBAAC,EAAK,WAAN;EACE,oBAAiB;EACjB,WAAW,EAAG,EAAO,WAAW,CAAS;EACzC,GAAI;CACL,CAAA;AAEL;AAEA,EAAsB,cAAc;AAUpC,SAAgB,EAAkB,EAAE,cAAW,GAAG,KAAgC;CAChF,OACE,kBAAC,EAAK,YAAN;EACE,oBAAiB;EACjB,WAAW,EAAG,EAAO,OAAO,CAAS;EACrC,GAAI;CACL,CAAA;AAEL;AAEA,EAAkB,cAAc;AAQhC,SAAgB,EAAkB,GAA+B;CAC/D,OAAO,kBAAC,EAAK,OAAN;EAAY,oBAAiB;EAAsB,GAAI;CAAQ,CAAA;AACxE;AAEA,EAAkB,cAAc"}
1
+ {"version":3,"file":"DropdownMenu.js","names":[],"sources":["../../src/components/DropdownMenu.tsx"],"sourcesContent":["'use client';\n\nimport type { ComponentProps } from 'react';\nimport { Menu } from '@base-ui/react/menu';\nimport { cn } from '../lib/cn';\nimport styles from './DropdownMenu.module.css';\n\n/**\n * Action menu anchored to a trigger (Decision D15). Wraps Base UI's\n * `Menu.*` parts, which implement the ARIA APG **menu button** pattern:\n * `role=\"menu\"` / `menuitem`, roving focus, arrow-key navigation,\n * typeahead, and Escape-to-close with focus return to the trigger.\n *\n * This is deliberately distinct from a future `Popover` atom. A\n * DropdownMenu is for **commands** (the menu-button contract); free-form\n * anchored content (forms, navigation links) belongs in a Popover (the\n * disclosure/dialog contract). 7 of 8 surveyed design systems separate\n * the two for exactly this reason — putting `role=\"menu\"` around\n * arbitrary content breaks screen-reader expectations. See\n * the DropdownMenu page of the naming decisions: https://app.notion.com/p/4071751eee10815ab61dc5e63758da12\n *\n * Naming follows shadcn (`DropdownMenu*`, not Base UI's `Menu`). The\n * compound surface collapses Base UI's `Portal` + `Positioner` + `Popup`\n * into a single `DropdownMenuContent` with `side` / `align` /\n * `sideOffset` props — the same ergonomics shadcn exposes over Radix.\n *\n * v1 ships the parts the known consumers need (kebab row menus, the\n * MobileHeader user actions): Trigger, Content, Item, Separator, Label,\n * Group. `CheckboxItem`, `RadioItem`, submenus and `LinkItem` are\n * deliberately deferred — no Alexandria call-site exercises them, and the\n * compound API makes them additive without a breaking change.\n *\n * @example\n * <DropdownMenu>\n * <DropdownMenuTrigger render={<IconButton aria-label=\"Options\"><MoreIcon /></IconButton>} />\n * <DropdownMenuContent>\n * <DropdownMenuItem onClick={onRename}>Rename</DropdownMenuItem>\n * <DropdownMenuSeparator />\n * <DropdownMenuItem variant=\"destructive\" onClick={onDelete}>Delete</DropdownMenuItem>\n * </DropdownMenuContent>\n * </DropdownMenu>\n */\nexport type DropdownMenuProps = ComponentProps<typeof Menu.Root>;\n\nexport function DropdownMenu(props: DropdownMenuProps) {\n return <Menu.Root {...props} />;\n}\n\nDropdownMenu.displayName = 'DropdownMenu';\n\n/**\n * The element that opens the menu. Renders a native `<button>` by\n * default; pass `render` to compose any control while keeping the menu\n * wiring — the dominant case is the kebab `IconButton` (D13):\n * `<DropdownMenuTrigger render={<IconButton aria-label=\"Options\"><MoreIcon /></IconButton>} />`.\n */\nexport type DropdownMenuTriggerProps = ComponentProps<typeof Menu.Trigger>;\n\nexport function DropdownMenuTrigger(props: DropdownMenuTriggerProps) {\n return <Menu.Trigger {...props} />;\n}\n\nDropdownMenuTrigger.displayName = 'DropdownMenuTrigger';\n\n/**\n * The floating surface. Collapses Base UI's `Portal` + `Positioner` +\n * `Popup` so the consumer positions the menu with the three props that\n * actually matter at the call site. Defaults match the common dropdown:\n * opens below the trigger, aligned to its start edge, 8px away.\n */\nexport interface DropdownMenuContentProps extends ComponentProps<typeof Menu.Popup> {\n /**\n * Which side of the trigger the menu opens on.\n * @default 'bottom'\n */\n side?: ComponentProps<typeof Menu.Positioner>['side'];\n /**\n * Alignment of the menu relative to the trigger along the chosen side.\n * @default 'start'\n */\n align?: ComponentProps<typeof Menu.Positioner>['align'];\n /**\n * Gap in pixels between the trigger and the menu.\n * @default 8\n */\n sideOffset?: ComponentProps<typeof Menu.Positioner>['sideOffset'];\n}\n\nexport function DropdownMenuContent({\n side = 'bottom',\n align = 'start',\n sideOffset = 8,\n className,\n children,\n ...rest\n}: DropdownMenuContentProps) {\n return (\n <Menu.Portal>\n <Menu.Positioner\n className={styles.positioner}\n side={side}\n align={align}\n sideOffset={sideOffset}\n >\n <Menu.Popup\n data-pharos-slot=\"dropdown-menu-content\"\n className={cn(styles.content, className)}\n {...rest}\n >\n {children}\n </Menu.Popup>\n </Menu.Positioner>\n </Menu.Portal>\n );\n}\n\nDropdownMenuContent.displayName = 'DropdownMenuContent';\n\n/**\n * A single action row. `variant=\"destructive\"` tints the row with the\n * error foreground for delete / remove actions — the same tone the\n * destructive Button uses, and the equivalent of shadcn's destructive\n * item variant. By default a click closes the menu (`closeOnClick`);\n * pass `closeOnClick={false}` for rows that should keep it open.\n */\nexport interface DropdownMenuItemProps extends ComponentProps<typeof Menu.Item> {\n /**\n * Visual tone of the row.\n * @default 'default'\n */\n variant?: 'default' | 'destructive';\n}\n\nexport function DropdownMenuItem({\n variant = 'default',\n className,\n ...rest\n}: DropdownMenuItemProps) {\n return (\n <Menu.Item\n data-pharos-variant={variant}\n className={cn(styles.item, variant === 'destructive' && styles.itemDestructive, className)}\n {...rest}\n />\n );\n}\n\nDropdownMenuItem.displayName = 'DropdownMenuItem';\n\n/** A thin divider between groups of items. */\nexport type DropdownMenuSeparatorProps = ComponentProps<typeof Menu.Separator>;\n\nexport function DropdownMenuSeparator({ className, ...rest }: DropdownMenuSeparatorProps) {\n return (\n <Menu.Separator\n data-pharos-slot=\"dropdown-menu-separator\"\n className={cn(styles.separator, className)}\n {...rest}\n />\n );\n}\n\nDropdownMenuSeparator.displayName = 'DropdownMenuSeparator';\n\n/**\n * A non-interactive heading for a group of items. Renders Base UI's\n * `Menu.GroupLabel`, which wires `aria-labelledby` on the surrounding\n * `DropdownMenuGroup` — so use the two together when a section needs an\n * accessible name.\n */\nexport type DropdownMenuLabelProps = ComponentProps<typeof Menu.GroupLabel>;\n\nexport function DropdownMenuLabel({ className, ...rest }: DropdownMenuLabelProps) {\n return (\n <Menu.GroupLabel\n data-pharos-slot=\"dropdown-menu-label\"\n className={cn(styles.label, className)}\n {...rest}\n />\n );\n}\n\nDropdownMenuLabel.displayName = 'DropdownMenuLabel';\n\n/**\n * Groups related items under an optional `DropdownMenuLabel` for\n * accessible sectioning (`role=\"group\"`).\n */\nexport type DropdownMenuGroupProps = ComponentProps<typeof Menu.Group>;\n\nexport function DropdownMenuGroup(props: DropdownMenuGroupProps) {\n return <Menu.Group data-pharos-slot=\"dropdown-menu-group\" {...props} />;\n}\n\nDropdownMenuGroup.displayName = 'DropdownMenuGroup';\n"],"mappings":";;;;;;AA4CA,SAAgB,EAAa,GAA0B;CACrD,OAAO,kBAAC,EAAK,MAAN,EAAW,GAAI,EAAQ,CAAA;AAChC;AAEA,EAAa,cAAc;AAU3B,SAAgB,EAAoB,GAAiC;CACnE,OAAO,kBAAC,EAAK,SAAN,EAAc,GAAI,EAAQ,CAAA;AACnC;AAEA,EAAoB,cAAc;AA0BlC,SAAgB,EAAoB,EAClC,UAAO,UACP,WAAQ,SACR,gBAAa,GACb,cACA,aACA,GAAG,KACwB;CAC3B,OACE,kBAAC,EAAK,QAAN,EAAA,UACE,kBAAC,EAAK,YAAN;EACE,WAAW,EAAO;EACZ;EACC;EACK;YAEZ,kBAAC,EAAK,OAAN;GACE,oBAAiB;GACjB,WAAW,EAAG,EAAO,SAAS,CAAS;GACvC,GAAI;GAEH;EACS,CAAA;CACG,CAAA,EACN,CAAA;AAEjB;AAEA,EAAoB,cAAc;AAiBlC,SAAgB,EAAiB,EAC/B,aAAU,WACV,cACA,GAAG,KACqB;CACxB,OACE,kBAAC,EAAK,MAAN;EACE,uBAAqB;EACrB,WAAW,EAAG,EAAO,MAAM,MAAY,iBAAiB,EAAO,iBAAiB,CAAS;EACzF,GAAI;CACL,CAAA;AAEL;AAEA,EAAiB,cAAc;AAK/B,SAAgB,EAAsB,EAAE,cAAW,GAAG,KAAoC;CACxF,OACE,kBAAC,EAAK,WAAN;EACE,oBAAiB;EACjB,WAAW,EAAG,EAAO,WAAW,CAAS;EACzC,GAAI;CACL,CAAA;AAEL;AAEA,EAAsB,cAAc;AAUpC,SAAgB,EAAkB,EAAE,cAAW,GAAG,KAAgC;CAChF,OACE,kBAAC,EAAK,YAAN;EACE,oBAAiB;EACjB,WAAW,EAAG,EAAO,OAAO,CAAS;EACrC,GAAI;CACL,CAAA;AAEL;AAEA,EAAkB,cAAc;AAQhC,SAAgB,EAAkB,GAA+B;CAC/D,OAAO,kBAAC,EAAK,OAAN;EAAY,oBAAiB;EAAsB,GAAI;CAAQ,CAAA;AACxE;AAEA,EAAkB,cAAc"}
@@ -15,7 +15,8 @@ import { Popover as BasePopover } from '@base-ui/react/popover';
15
15
  * systems separate the two for exactly this reason: wrapping `role="menu"`
16
16
  * around free-form content breaks screen-reader expectations. The two atoms
17
17
  * wrap different Base UI primitives (`Menu` vs `Popover`) — they do not
18
- * share machinery. See `NAMING-decisions.md` § Popover.
18
+ * share machinery. See the Popover page of the naming decisions:
19
+ * https://app.notion.com/p/4071751eee1081239536dc0517fce057
19
20
  *
20
21
  * Naming follows shadcn (`Popover*`). The compound surface collapses Base
21
22
  * UI's `Portal` + `Positioner` + `Popup` into a single `PopoverContent`
@@ -1 +1 @@
1
- {"version":3,"file":"Popover.d.ts","sourceRoot":"","sources":["../../src/components/Popover.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAIhE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,MAAM,MAAM,YAAY,GAAG,cAAc,CAAC,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC;AAEnE,wBAAgB,OAAO,CAAC,KAAK,EAAE,YAAY,+BAE1C;yBAFe,OAAO;;;AAMvB;;;;;GAKG;AACH,MAAM,MAAM,mBAAmB,GAAG,cAAc,CAAC,OAAO,WAAW,CAAC,OAAO,CAAC,CAAC;AAE7E,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,+BAExD;yBAFe,cAAc;;;AAM9B;;;;;;;;;GASG;AACH,MAAM,WAAW,mBAAoB,SAAQ,cAAc,CAAC,OAAO,WAAW,CAAC,KAAK,CAAC;IACnF;;;OAGG;IACH,IAAI,CAAC,EAAE,cAAc,CAAC,OAAO,WAAW,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;IAC7D;;;OAGG;IACH,KAAK,CAAC,EAAE,cAAc,CAAC,OAAO,WAAW,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,CAAC;IAC/D;;;OAGG;IACH,UAAU,CAAC,EAAE,cAAc,CAAC,OAAO,WAAW,CAAC,UAAU,CAAC,CAAC,YAAY,CAAC,CAAC;IACzE;;;OAGG;IACH,WAAW,CAAC,EAAE,cAAc,CAAC,OAAO,WAAW,CAAC,UAAU,CAAC,CAAC,aAAa,CAAC,CAAC;CAC5E;AAED,wBAAgB,cAAc,CAAC,EAC7B,IAAe,EACf,KAAgB,EAChB,UAAc,EACd,WAAe,EACf,SAAS,EACT,QAAQ,EACR,GAAG,IAAI,EACR,EAAE,mBAAmB,+BAoBrB;yBA5Be,cAAc;;;AAgC9B;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GAAG,cAAc,CAAC,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC;AAEzE,wBAAgB,YAAY,CAAC,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,EAAE,iBAAiB,+BAQrE;yBARe,YAAY;;;AAY5B;;;;GAIG;AACH,MAAM,MAAM,uBAAuB,GAAG,cAAc,CAAC,OAAO,WAAW,CAAC,WAAW,CAAC,CAAC;AAErF,wBAAgB,kBAAkB,CAAC,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,EAAE,uBAAuB,+BAQjF;yBARe,kBAAkB;;;AAYlC;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GAAG,cAAc,CAAC,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC;AAEzE,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,+BAEpD;yBAFe,YAAY"}
1
+ {"version":3,"file":"Popover.d.ts","sourceRoot":"","sources":["../../src/components/Popover.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAIhE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAM,MAAM,YAAY,GAAG,cAAc,CAAC,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC;AAEnE,wBAAgB,OAAO,CAAC,KAAK,EAAE,YAAY,+BAE1C;yBAFe,OAAO;;;AAMvB;;;;;GAKG;AACH,MAAM,MAAM,mBAAmB,GAAG,cAAc,CAAC,OAAO,WAAW,CAAC,OAAO,CAAC,CAAC;AAE7E,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,+BAExD;yBAFe,cAAc;;;AAM9B;;;;;;;;;GASG;AACH,MAAM,WAAW,mBAAoB,SAAQ,cAAc,CAAC,OAAO,WAAW,CAAC,KAAK,CAAC;IACnF;;;OAGG;IACH,IAAI,CAAC,EAAE,cAAc,CAAC,OAAO,WAAW,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;IAC7D;;;OAGG;IACH,KAAK,CAAC,EAAE,cAAc,CAAC,OAAO,WAAW,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,CAAC;IAC/D;;;OAGG;IACH,UAAU,CAAC,EAAE,cAAc,CAAC,OAAO,WAAW,CAAC,UAAU,CAAC,CAAC,YAAY,CAAC,CAAC;IACzE;;;OAGG;IACH,WAAW,CAAC,EAAE,cAAc,CAAC,OAAO,WAAW,CAAC,UAAU,CAAC,CAAC,aAAa,CAAC,CAAC;CAC5E;AAED,wBAAgB,cAAc,CAAC,EAC7B,IAAe,EACf,KAAgB,EAChB,UAAc,EACd,WAAe,EACf,SAAS,EACT,QAAQ,EACR,GAAG,IAAI,EACR,EAAE,mBAAmB,+BAoBrB;yBA5Be,cAAc;;;AAgC9B;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GAAG,cAAc,CAAC,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC;AAEzE,wBAAgB,YAAY,CAAC,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,EAAE,iBAAiB,+BAQrE;yBARe,YAAY;;;AAY5B;;;;GAIG;AACH,MAAM,MAAM,uBAAuB,GAAG,cAAc,CAAC,OAAO,WAAW,CAAC,WAAW,CAAC,CAAC;AAErF,wBAAgB,kBAAkB,CAAC,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,EAAE,uBAAuB,+BAQjF;yBARe,kBAAkB;;;AAYlC;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GAAG,cAAc,CAAC,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC;AAEzE,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,+BAEpD;yBAFe,YAAY"}
@@ -1 +1 @@
1
- {"version":3,"file":"Popover.js","names":[],"sources":["../../src/components/Popover.tsx"],"sourcesContent":["'use client';\n\nimport type { ComponentProps } from 'react';\nimport { Popover as BasePopover } from '@base-ui/react/popover';\nimport { cn } from '../lib/cn';\nimport styles from './Popover.module.css';\n\n/**\n * Free-form content anchored to a trigger (Decision D16). Wraps Base UI's\n * `Popover.*` parts, which implement the ARIA **dialog** pattern in a\n * **non-modal** disclosure: `role=\"dialog\"` on the popup, focus moves into\n * it on open and returns to the trigger on close, Escape and outside-click\n * dismiss it — but focus is NOT trapped and the rest of the page stays\n * interactive.\n *\n * This is deliberately distinct from the `DropdownMenu` atom (D15). A\n * DropdownMenu is for **commands** (the menu-button contract: `role=\"menu\"`\n * / `menuitem`, roving focus, typeahead); a Popover holds **arbitrary\n * content** — forms, navigation, descriptive panels. 7 of 8 surveyed design\n * systems separate the two for exactly this reason: wrapping `role=\"menu\"`\n * around free-form content breaks screen-reader expectations. The two atoms\n * wrap different Base UI primitives (`Menu` vs `Popover`) — they do not\n * share machinery. See `NAMING-decisions.md` § Popover.\n *\n * Naming follows shadcn (`Popover*`). The compound surface collapses Base\n * UI's `Portal` + `Positioner` + `Popup` into a single `PopoverContent`\n * with `side` / `align` / `sideOffset` / `alignOffset` props — the same\n * ergonomics shadcn exposes over Radix, mirroring the Pharos DropdownMenu.\n *\n * v1 ships the parts the known consumers need (the MobileHeader user panel,\n * the \"add users\" / \"add skills\" panels): Trigger, Content, Close, Title,\n * Description. `Arrow`, an `Anchor` (anchoring to an element other than the\n * trigger — the future Combobox will want it) and a modal `Backdrop` are\n * deliberately deferred; the compound API makes them additive without a\n * breaking change.\n *\n * @example\n * <Popover>\n * <PopoverTrigger render={<IconButton aria-label=\"Account\"><Avatar … /></IconButton>} />\n * <PopoverContent>\n * <PopoverTitle>Signed in as Ada</PopoverTitle>\n * <PopoverDescription>ada@example.com</PopoverDescription>\n * <button onClick={onSignOut}>Sign out</button>\n * </PopoverContent>\n * </Popover>\n */\nexport type PopoverProps = ComponentProps<typeof BasePopover.Root>;\n\nexport function Popover(props: PopoverProps) {\n return <BasePopover.Root {...props} />;\n}\n\nPopover.displayName = 'Popover';\n\n/**\n * The element that opens the popover. Renders a native `<button>` by\n * default; pass `render` to compose any control while keeping the popover\n * wiring — e.g. the MobileHeader avatar:\n * `<PopoverTrigger render={<IconButton aria-label=\"Account\">…</IconButton>} />`.\n */\nexport type PopoverTriggerProps = ComponentProps<typeof BasePopover.Trigger>;\n\nexport function PopoverTrigger(props: PopoverTriggerProps) {\n return <BasePopover.Trigger {...props} />;\n}\n\nPopoverTrigger.displayName = 'PopoverTrigger';\n\n/**\n * The floating surface. Collapses Base UI's `Portal` + `Positioner` +\n * `Popup` so the consumer positions the popover with the four props that\n * actually matter at the call site. Defaults match the common popover:\n * opens below the trigger, centred on it, 8px away.\n *\n * `align` defaults to `center` (not `start` like DropdownMenu): a menu opens\n * flush to the trigger's start edge, but a popover carries arbitrary content\n * and reads better centred — the shadcn / Radix / Base UI default.\n */\nexport interface PopoverContentProps extends ComponentProps<typeof BasePopover.Popup> {\n /**\n * Which side of the trigger the popover opens on.\n * @default 'bottom'\n */\n side?: ComponentProps<typeof BasePopover.Positioner>['side'];\n /**\n * Alignment of the popover relative to the trigger along the chosen side.\n * @default 'center'\n */\n align?: ComponentProps<typeof BasePopover.Positioner>['align'];\n /**\n * Gap in pixels between the trigger and the popover.\n * @default 8\n */\n sideOffset?: ComponentProps<typeof BasePopover.Positioner>['sideOffset'];\n /**\n * Offset in pixels along the alignment axis.\n * @default 0\n */\n alignOffset?: ComponentProps<typeof BasePopover.Positioner>['alignOffset'];\n}\n\nexport function PopoverContent({\n side = 'bottom',\n align = 'center',\n sideOffset = 8,\n alignOffset = 0,\n className,\n children,\n ...rest\n}: PopoverContentProps) {\n return (\n <BasePopover.Portal>\n <BasePopover.Positioner\n className={styles.positioner}\n side={side}\n align={align}\n sideOffset={sideOffset}\n alignOffset={alignOffset}\n >\n <BasePopover.Popup\n data-pharos-slot=\"popover-content\"\n className={cn(styles.content, className)}\n {...rest}\n >\n {children}\n </BasePopover.Popup>\n </BasePopover.Positioner>\n </BasePopover.Portal>\n );\n}\n\nPopoverContent.displayName = 'PopoverContent';\n\n/**\n * An accessible name for the popover. Renders Base UI's `Popover.Title`,\n * which wires `aria-labelledby` on the popup — the dialog labelling that\n * distinguishes a Popover from a Menu. Renders as a `<h2>` by default; pass\n * `render` to change the element.\n */\nexport type PopoverTitleProps = ComponentProps<typeof BasePopover.Title>;\n\nexport function PopoverTitle({ className, ...rest }: PopoverTitleProps) {\n return (\n <BasePopover.Title\n data-pharos-slot=\"popover-title\"\n className={cn(styles.title, className)}\n {...rest}\n />\n );\n}\n\nPopoverTitle.displayName = 'PopoverTitle';\n\n/**\n * A supporting description for the popover. Renders Base UI's\n * `Popover.Description`, which wires `aria-describedby` on the popup.\n * Renders as a `<p>` by default.\n */\nexport type PopoverDescriptionProps = ComponentProps<typeof BasePopover.Description>;\n\nexport function PopoverDescription({ className, ...rest }: PopoverDescriptionProps) {\n return (\n <BasePopover.Description\n data-pharos-slot=\"popover-description\"\n className={cn(styles.description, className)}\n {...rest}\n />\n );\n}\n\nPopoverDescription.displayName = 'PopoverDescription';\n\n/**\n * A button that closes the popover. Renders Base UI's `Popover.Close` (a\n * native `<button>`); compose any control via `render`. Unlike a menu — whose\n * items close it on selection — a popover holds content that stays open until\n * explicitly dismissed, so an in-popup close affordance is the common case.\n */\nexport type PopoverCloseProps = ComponentProps<typeof BasePopover.Close>;\n\nexport function PopoverClose(props: PopoverCloseProps) {\n return <BasePopover.Close data-pharos-slot=\"popover-close\" {...props} />;\n}\n\nPopoverClose.displayName = 'PopoverClose';\n"],"mappings":";;;;;;AAgDA,SAAgB,EAAQ,GAAqB;CAC3C,OAAO,kBAAC,EAAY,MAAb,EAAkB,GAAI,EAAQ,CAAA;AACvC;AAEA,EAAQ,cAAc;AAUtB,SAAgB,EAAe,GAA4B;CACzD,OAAO,kBAAC,EAAY,SAAb,EAAqB,GAAI,EAAQ,CAAA;AAC1C;AAEA,EAAe,cAAc;AAmC7B,SAAgB,EAAe,EAC7B,UAAO,UACP,WAAQ,UACR,gBAAa,GACb,iBAAc,GACd,cACA,aACA,GAAG,KACmB;CACtB,OACE,kBAAC,EAAY,QAAb,EAAA,UACE,kBAAC,EAAY,YAAb;EACE,WAAW,EAAO;EACZ;EACC;EACK;EACC;YAEb,kBAAC,EAAY,OAAb;GACE,oBAAiB;GACjB,WAAW,EAAG,EAAO,SAAS,CAAS;GACvC,GAAI;GAEH;EACgB,CAAA;CACG,CAAA,EACN,CAAA;AAExB;AAEA,EAAe,cAAc;AAU7B,SAAgB,EAAa,EAAE,cAAW,GAAG,KAA2B;CACtE,OACE,kBAAC,EAAY,OAAb;EACE,oBAAiB;EACjB,WAAW,EAAG,EAAO,OAAO,CAAS;EACrC,GAAI;CACL,CAAA;AAEL;AAEA,EAAa,cAAc;AAS3B,SAAgB,EAAmB,EAAE,cAAW,GAAG,KAAiC;CAClF,OACE,kBAAC,EAAY,aAAb;EACE,oBAAiB;EACjB,WAAW,EAAG,EAAO,aAAa,CAAS;EAC3C,GAAI;CACL,CAAA;AAEL;AAEA,EAAmB,cAAc;AAUjC,SAAgB,EAAa,GAA0B;CACrD,OAAO,kBAAC,EAAY,OAAb;EAAmB,oBAAiB;EAAgB,GAAI;CAAQ,CAAA;AACzE;AAEA,EAAa,cAAc"}
1
+ {"version":3,"file":"Popover.js","names":[],"sources":["../../src/components/Popover.tsx"],"sourcesContent":["'use client';\n\nimport type { ComponentProps } from 'react';\nimport { Popover as BasePopover } from '@base-ui/react/popover';\nimport { cn } from '../lib/cn';\nimport styles from './Popover.module.css';\n\n/**\n * Free-form content anchored to a trigger (Decision D16). Wraps Base UI's\n * `Popover.*` parts, which implement the ARIA **dialog** pattern in a\n * **non-modal** disclosure: `role=\"dialog\"` on the popup, focus moves into\n * it on open and returns to the trigger on close, Escape and outside-click\n * dismiss it — but focus is NOT trapped and the rest of the page stays\n * interactive.\n *\n * This is deliberately distinct from the `DropdownMenu` atom (D15). A\n * DropdownMenu is for **commands** (the menu-button contract: `role=\"menu\"`\n * / `menuitem`, roving focus, typeahead); a Popover holds **arbitrary\n * content** — forms, navigation, descriptive panels. 7 of 8 surveyed design\n * systems separate the two for exactly this reason: wrapping `role=\"menu\"`\n * around free-form content breaks screen-reader expectations. The two atoms\n * wrap different Base UI primitives (`Menu` vs `Popover`) — they do not\n * share machinery. See the Popover page of the naming decisions:\n * https://app.notion.com/p/4071751eee1081239536dc0517fce057\n *\n * Naming follows shadcn (`Popover*`). The compound surface collapses Base\n * UI's `Portal` + `Positioner` + `Popup` into a single `PopoverContent`\n * with `side` / `align` / `sideOffset` / `alignOffset` props — the same\n * ergonomics shadcn exposes over Radix, mirroring the Pharos DropdownMenu.\n *\n * v1 ships the parts the known consumers need (the MobileHeader user panel,\n * the \"add users\" / \"add skills\" panels): Trigger, Content, Close, Title,\n * Description. `Arrow`, an `Anchor` (anchoring to an element other than the\n * trigger — the future Combobox will want it) and a modal `Backdrop` are\n * deliberately deferred; the compound API makes them additive without a\n * breaking change.\n *\n * @example\n * <Popover>\n * <PopoverTrigger render={<IconButton aria-label=\"Account\"><Avatar … /></IconButton>} />\n * <PopoverContent>\n * <PopoverTitle>Signed in as Ada</PopoverTitle>\n * <PopoverDescription>ada@example.com</PopoverDescription>\n * <button onClick={onSignOut}>Sign out</button>\n * </PopoverContent>\n * </Popover>\n */\nexport type PopoverProps = ComponentProps<typeof BasePopover.Root>;\n\nexport function Popover(props: PopoverProps) {\n return <BasePopover.Root {...props} />;\n}\n\nPopover.displayName = 'Popover';\n\n/**\n * The element that opens the popover. Renders a native `<button>` by\n * default; pass `render` to compose any control while keeping the popover\n * wiring — e.g. the MobileHeader avatar:\n * `<PopoverTrigger render={<IconButton aria-label=\"Account\">…</IconButton>} />`.\n */\nexport type PopoverTriggerProps = ComponentProps<typeof BasePopover.Trigger>;\n\nexport function PopoverTrigger(props: PopoverTriggerProps) {\n return <BasePopover.Trigger {...props} />;\n}\n\nPopoverTrigger.displayName = 'PopoverTrigger';\n\n/**\n * The floating surface. Collapses Base UI's `Portal` + `Positioner` +\n * `Popup` so the consumer positions the popover with the four props that\n * actually matter at the call site. Defaults match the common popover:\n * opens below the trigger, centred on it, 8px away.\n *\n * `align` defaults to `center` (not `start` like DropdownMenu): a menu opens\n * flush to the trigger's start edge, but a popover carries arbitrary content\n * and reads better centred — the shadcn / Radix / Base UI default.\n */\nexport interface PopoverContentProps extends ComponentProps<typeof BasePopover.Popup> {\n /**\n * Which side of the trigger the popover opens on.\n * @default 'bottom'\n */\n side?: ComponentProps<typeof BasePopover.Positioner>['side'];\n /**\n * Alignment of the popover relative to the trigger along the chosen side.\n * @default 'center'\n */\n align?: ComponentProps<typeof BasePopover.Positioner>['align'];\n /**\n * Gap in pixels between the trigger and the popover.\n * @default 8\n */\n sideOffset?: ComponentProps<typeof BasePopover.Positioner>['sideOffset'];\n /**\n * Offset in pixels along the alignment axis.\n * @default 0\n */\n alignOffset?: ComponentProps<typeof BasePopover.Positioner>['alignOffset'];\n}\n\nexport function PopoverContent({\n side = 'bottom',\n align = 'center',\n sideOffset = 8,\n alignOffset = 0,\n className,\n children,\n ...rest\n}: PopoverContentProps) {\n return (\n <BasePopover.Portal>\n <BasePopover.Positioner\n className={styles.positioner}\n side={side}\n align={align}\n sideOffset={sideOffset}\n alignOffset={alignOffset}\n >\n <BasePopover.Popup\n data-pharos-slot=\"popover-content\"\n className={cn(styles.content, className)}\n {...rest}\n >\n {children}\n </BasePopover.Popup>\n </BasePopover.Positioner>\n </BasePopover.Portal>\n );\n}\n\nPopoverContent.displayName = 'PopoverContent';\n\n/**\n * An accessible name for the popover. Renders Base UI's `Popover.Title`,\n * which wires `aria-labelledby` on the popup — the dialog labelling that\n * distinguishes a Popover from a Menu. Renders as a `<h2>` by default; pass\n * `render` to change the element.\n */\nexport type PopoverTitleProps = ComponentProps<typeof BasePopover.Title>;\n\nexport function PopoverTitle({ className, ...rest }: PopoverTitleProps) {\n return (\n <BasePopover.Title\n data-pharos-slot=\"popover-title\"\n className={cn(styles.title, className)}\n {...rest}\n />\n );\n}\n\nPopoverTitle.displayName = 'PopoverTitle';\n\n/**\n * A supporting description for the popover. Renders Base UI's\n * `Popover.Description`, which wires `aria-describedby` on the popup.\n * Renders as a `<p>` by default.\n */\nexport type PopoverDescriptionProps = ComponentProps<typeof BasePopover.Description>;\n\nexport function PopoverDescription({ className, ...rest }: PopoverDescriptionProps) {\n return (\n <BasePopover.Description\n data-pharos-slot=\"popover-description\"\n className={cn(styles.description, className)}\n {...rest}\n />\n );\n}\n\nPopoverDescription.displayName = 'PopoverDescription';\n\n/**\n * A button that closes the popover. Renders Base UI's `Popover.Close` (a\n * native `<button>`); compose any control via `render`. Unlike a menu — whose\n * items close it on selection — a popover holds content that stays open until\n * explicitly dismissed, so an in-popup close affordance is the common case.\n */\nexport type PopoverCloseProps = ComponentProps<typeof BasePopover.Close>;\n\nexport function PopoverClose(props: PopoverCloseProps) {\n return <BasePopover.Close data-pharos-slot=\"popover-close\" {...props} />;\n}\n\nPopoverClose.displayName = 'PopoverClose';\n"],"mappings":";;;;;;AAiDA,SAAgB,EAAQ,GAAqB;CAC3C,OAAO,kBAAC,EAAY,MAAb,EAAkB,GAAI,EAAQ,CAAA;AACvC;AAEA,EAAQ,cAAc;AAUtB,SAAgB,EAAe,GAA4B;CACzD,OAAO,kBAAC,EAAY,SAAb,EAAqB,GAAI,EAAQ,CAAA;AAC1C;AAEA,EAAe,cAAc;AAmC7B,SAAgB,EAAe,EAC7B,UAAO,UACP,WAAQ,UACR,gBAAa,GACb,iBAAc,GACd,cACA,aACA,GAAG,KACmB;CACtB,OACE,kBAAC,EAAY,QAAb,EAAA,UACE,kBAAC,EAAY,YAAb;EACE,WAAW,EAAO;EACZ;EACC;EACK;EACC;YAEb,kBAAC,EAAY,OAAb;GACE,oBAAiB;GACjB,WAAW,EAAG,EAAO,SAAS,CAAS;GACvC,GAAI;GAEH;EACgB,CAAA;CACG,CAAA,EACN,CAAA;AAExB;AAEA,EAAe,cAAc;AAU7B,SAAgB,EAAa,EAAE,cAAW,GAAG,KAA2B;CACtE,OACE,kBAAC,EAAY,OAAb;EACE,oBAAiB;EACjB,WAAW,EAAG,EAAO,OAAO,CAAS;EACrC,GAAI;CACL,CAAA;AAEL;AAEA,EAAa,cAAc;AAS3B,SAAgB,EAAmB,EAAE,cAAW,GAAG,KAAiC;CAClF,OACE,kBAAC,EAAY,aAAb;EACE,oBAAiB;EACjB,WAAW,EAAG,EAAO,aAAa,CAAS;EAC3C,GAAI;CACL,CAAA;AAEL;AAEA,EAAmB,cAAc;AAUjC,SAAgB,EAAa,GAA0B;CACrD,OAAO,kBAAC,EAAY,OAAb;EAAmB,oBAAiB;EAAgB,GAAI;CAAQ,CAAA;AACzE;AAEA,EAAa,cAAc"}
@@ -13,7 +13,7 @@ import { VariantProps } from 'class-variance-authority';
13
13
  * that is a Combobox (the APG combobox pattern). shadcn, Base UI and ARIA APG
14
14
  * all separate the two under exactly these names, which is why Pharos ships
15
15
  * two atoms rather than one component with a `searchable` axis. See
16
- * `NAMING-decisions.md` § Select.
16
+ * the Select + Combobox page of the naming decisions: https://app.notion.com/p/4071751eee108172bf64fdbe0fe8a94b
17
17
  *
18
18
  * Multi-select is the `multiple` axis on the root (not a separate atom),
19
19
  * matching Base UI / shadcn / React Aria: pass `multiple` and `value`
@@ -1 +1 @@
1
- {"version":3,"file":"Select.js","names":[],"sources":["../../src/components/Select.tsx"],"sourcesContent":["'use client';\n\nimport type { ComponentProps } from 'react';\nimport { Select as BaseSelect } from '@base-ui/react/select';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '../lib/cn';\nimport styles from './Select.module.css';\n\n/**\n * Single- or multi-select from a **known set of options** (Decision D17).\n * Wraps Base UI's `Select.*` parts, which implement the ARIA **listbox**\n * pattern: a trigger button opens a popup with `role=\"listbox\"` whose rows\n * are `role=\"option\"`, with roving focus, typeahead and Escape-to-close.\n *\n * This is deliberately distinct from the `Combobox` atom (also D17). A\n * Select has **no text input** — the user picks from a closed list. When the\n * option set is large enough to need filtering, or the value can be typed,\n * that is a Combobox (the APG combobox pattern). shadcn, Base UI and ARIA APG\n * all separate the two under exactly these names, which is why Pharos ships\n * two atoms rather than one component with a `searchable` axis. See\n * `NAMING-decisions.md` § Select.\n *\n * Multi-select is the `multiple` axis on the root (not a separate atom),\n * matching Base UI / shadcn / React Aria: pass `multiple` and `value`\n * becomes an array. Single-select closes on pick; multi-select keeps the\n * popup open so selections accumulate — Base UI derives this from `multiple`\n * and Pharos does not override it.\n *\n * Naming follows shadcn (`Select*`). `SelectTrigger` folds Base UI's\n * `Trigger` + the chevron `Icon`; `SelectContent` collapses `Portal` +\n * `Positioner` + `Popup` + `List` with `side` / `align` / `sideOffset`\n * props; `SelectItem` folds `Item` + `ItemText` + the selected-state\n * `ItemIndicator` — the same ergonomics shadcn exposes over Radix. The popup\n * takes `width: var(--anchor-width)` so it matches the trigger width exactly\n * (long options truncate; override `width` via `className` for a wider panel).\n *\n * Following the form-control composition rule (Escuela 1, D11), the atom owns\n * no label / helper / error message — the consumer composes those, and the\n * error state is conveyed through the standard `aria-invalid` attribute on\n * the trigger (the CSS reacts to `[aria-invalid=\"true\"]`).\n *\n * **Always pass `items` (a value→label map) when the value differs from its\n * label.** Base UI's `SelectValue` resolves the trigger label from the root's\n * `items` prop, NOT from the `SelectItem` children — those are the listbox\n * label + typeahead text. This holds for interactive selection too: without\n * `items` the trigger shows the serialized raw value (the enum\n * `\"organization\"`, not `\"Organization\"`). The idiomatic, drift-free pattern\n * is a single options source that feeds both `items` and the rendered items.\n *\n * @example\n * const VISIBILITY = { private: 'Private', organization: 'Organization', public: 'Public' };\n *\n * <Select value={value} onValueChange={setValue} items={VISIBILITY}>\n * <SelectTrigger aria-label=\"Visibility\">\n * <SelectValue placeholder=\"Select visibility\" />\n * </SelectTrigger>\n * <SelectContent>\n * {Object.entries(VISIBILITY).map(([v, label]) => (\n * <SelectItem key={v} value={v}>\n * {label}\n * </SelectItem>\n * ))}\n * </SelectContent>\n * </Select>\n */\nexport type SelectProps<\n Value,\n Multiple extends boolean | undefined = false,\n> = BaseSelect.Root.Props<Value, Multiple>;\n\nexport function Select<Value, Multiple extends boolean | undefined = false>(\n props: SelectProps<Value, Multiple>,\n) {\n return <BaseSelect.Root {...props} />;\n}\n\nSelect.displayName = 'Select';\n\n/**\n * A downward chevron, inlined as an SVG so the published bundle pulls no icon\n * dependency (Pharos does not bundle `lucide-react`; D4 keeps Lucide as the\n * canonical source for the path data). Rotates 180° when the popup opens via\n * the `[data-popup-open]` selector on the wrapping `SelectIcon`.\n */\nfunction ChevronDownIcon() {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" aria-hidden=\"true\">\n <path d=\"m6 9 6 6 6-6\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n );\n}\n\n/** A check mark for the selected option, inlined for the same reason. */\nfunction CheckIcon() {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" aria-hidden=\"true\">\n <path d=\"M20 6 9 17l-5-5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n );\n}\n\nconst triggerVariants = cva(styles.trigger, {\n variants: {\n size: {\n sm: styles.sizeSm,\n md: styles.sizeMd,\n lg: styles.sizeLg,\n },\n },\n defaultVariants: {\n size: 'md',\n },\n});\n\ntype TriggerVariantProps = VariantProps<typeof triggerVariants>;\n\n/**\n * The button that opens the listbox. Shares the Input chrome (border tone,\n * focus ring, size grid) so a Select sits flush next to an Input on a form\n * row. Folds the trailing chevron, and lays children out before it — the\n * common case is a single `<SelectValue />`. The `size` axis (sm / md / lg)\n * matches the Input and Button heights.\n *\n * Give it an accessible name with `aria-label` (or wire a `<label>` /\n * `aria-labelledby`) — the trigger only shows the chosen value, not a label.\n */\nexport interface SelectTriggerProps\n extends ComponentProps<typeof BaseSelect.Trigger>, TriggerVariantProps {}\n\nexport function SelectTrigger({ size, className, children, ...rest }: SelectTriggerProps) {\n const resolvedSize = size ?? 'md';\n return (\n <BaseSelect.Trigger\n data-pharos-slot=\"select-trigger\"\n data-pharos-size={resolvedSize}\n className={cn(triggerVariants({ size: resolvedSize }), className)}\n {...rest}\n >\n {children}\n <BaseSelect.Icon className={styles.icon}>\n <ChevronDownIcon />\n </BaseSelect.Icon>\n </BaseSelect.Trigger>\n );\n}\n\nSelectTrigger.displayName = 'SelectTrigger';\n\n/**\n * Renders the selected option's label inside the trigger, or the\n * `placeholder` when nothing is selected. Wraps Base UI's `Select.Value`;\n * pass a render function as `children` to format the value yourself.\n */\nexport type SelectValueProps = ComponentProps<typeof BaseSelect.Value>;\n\nexport function SelectValue({ className, ...rest }: SelectValueProps) {\n return (\n <BaseSelect.Value\n data-pharos-slot=\"select-value\"\n className={cn(styles.value, className)}\n {...rest}\n />\n );\n}\n\nSelectValue.displayName = 'SelectValue';\n\n/**\n * The floating listbox. Collapses Base UI's `Portal` + `Positioner` +\n * `Popup` + `List` so the consumer positions it with the props that matter\n * at the call site. Defaults match the common select: opens below the\n * trigger, aligned to its start edge, 8px away, and matches the trigger width\n * (`width: var(--anchor-width)`).\n *\n * `alignItemWithTrigger` is forced to `false`. Base UI's `Select.Positioner`\n * defaults it to `true` — the native-`<select>` / macOS behaviour that floats\n * the popup *over* the trigger to put the selected item under the pointer,\n * and which silently overrides `side` / `align` / `sideOffset`\n * (`renderedSide` becomes `'none'`). Pharos anchors the listbox **below the\n * trigger** instead (D17 refinement): it is the dominant web convention\n * (shadcn `position=\"popper\"`, Ant, Mantine), it keeps the trigger box\n * visible, and — decisively — it makes `Select` consistent with `Combobox`,\n * whose Base UI primitive has no item-alignment mode and always anchors\n * adjacent. With it off, the `side` / `align` / `sideOffset` props below\n * actually take effect.\n */\nexport interface SelectContentProps extends ComponentProps<typeof BaseSelect.Popup> {\n /**\n * Which side of the trigger the listbox opens on.\n * @default 'bottom'\n */\n side?: ComponentProps<typeof BaseSelect.Positioner>['side'];\n /**\n * Alignment of the listbox relative to the trigger along the chosen side.\n * @default 'start'\n */\n align?: ComponentProps<typeof BaseSelect.Positioner>['align'];\n /**\n * Gap in pixels between the trigger and the listbox.\n * @default 8\n */\n sideOffset?: ComponentProps<typeof BaseSelect.Positioner>['sideOffset'];\n /**\n * Offset in pixels along the alignment axis.\n * @default 0\n */\n alignOffset?: ComponentProps<typeof BaseSelect.Positioner>['alignOffset'];\n}\n\nexport function SelectContent({\n side = 'bottom',\n align = 'start',\n sideOffset = 8,\n alignOffset = 0,\n className,\n children,\n ...rest\n}: SelectContentProps) {\n return (\n <BaseSelect.Portal>\n <BaseSelect.Positioner\n className={styles.positioner}\n alignItemWithTrigger={false}\n side={side}\n align={align}\n sideOffset={sideOffset}\n alignOffset={alignOffset}\n >\n <BaseSelect.Popup\n data-pharos-slot=\"select-content\"\n className={cn(styles.content, className)}\n {...rest}\n >\n <BaseSelect.List>{children}</BaseSelect.List>\n </BaseSelect.Popup>\n </BaseSelect.Positioner>\n </BaseSelect.Portal>\n );\n}\n\nSelectContent.displayName = 'SelectContent';\n\n/**\n * A single option. Folds Base UI's `Item` + `ItemText` (the label, also used\n * as the value shown in the trigger) + `ItemIndicator` (the check shown when\n * the option is selected). The `value` prop is required by Base UI and is\n * what `onValueChange` reports.\n */\nexport interface SelectItemProps extends ComponentProps<typeof BaseSelect.Item> {}\n\nexport function SelectItem({ className, children, ...rest }: SelectItemProps) {\n return (\n <BaseSelect.Item\n data-pharos-slot=\"select-item\"\n className={cn(styles.item, className)}\n {...rest}\n >\n <BaseSelect.ItemText className={styles.itemText}>{children}</BaseSelect.ItemText>\n <BaseSelect.ItemIndicator className={styles.itemIndicator}>\n <CheckIcon />\n </BaseSelect.ItemIndicator>\n </BaseSelect.Item>\n );\n}\n\nSelectItem.displayName = 'SelectItem';\n\n/**\n * Groups related options under an optional `SelectLabel` for accessible\n * sectioning (`role=\"group\"`).\n */\nexport type SelectGroupProps = ComponentProps<typeof BaseSelect.Group>;\n\nexport function SelectGroup(props: SelectGroupProps) {\n return <BaseSelect.Group data-pharos-slot=\"select-group\" {...props} />;\n}\n\nSelectGroup.displayName = 'SelectGroup';\n\n/**\n * A non-interactive heading for a `SelectGroup`. Renders Base UI's\n * `Select.GroupLabel`, which wires `aria-labelledby` on the surrounding\n * group — use the two together when a section needs an accessible name.\n */\nexport type SelectLabelProps = ComponentProps<typeof BaseSelect.GroupLabel>;\n\nexport function SelectLabel({ className, ...rest }: SelectLabelProps) {\n return (\n <BaseSelect.GroupLabel\n data-pharos-slot=\"select-label\"\n className={cn(styles.label, className)}\n {...rest}\n />\n );\n}\n\nSelectLabel.displayName = 'SelectLabel';\n\n/**\n * A thin **decorative** divider between groups of options.\n *\n * Rendered `aria-hidden` with `role=\"none\"`. Base UI's `Select.Separator`\n * re-exports the generic `Separator`, which emits `role=\"separator\"`. A\n * `separator` is **not** a permitted child of the `listbox` role (its content\n * model allows only `option` and `group`), so leaving it in the accessibility\n * tree fails axe's `aria-required-children` (critical) on a grouped Select.\n * The grouping is already conveyed semantically by `SelectGroup` (`role=\n * \"group\"`) + `SelectLabel` (`aria-labelledby`), so the divider is purely\n * visual — hiding it from the tree is the correct, drift-free fix (same as\n * Radix / shadcn, whose select separators are `aria-hidden`).\n */\nexport type SelectSeparatorProps = ComponentProps<typeof BaseSelect.Separator>;\n\nexport function SelectSeparator({ className, ...rest }: SelectSeparatorProps) {\n return (\n <BaseSelect.Separator\n data-pharos-slot=\"select-separator\"\n role=\"none\"\n aria-hidden\n className={cn(styles.separator, className)}\n {...rest}\n />\n );\n}\n\nSelectSeparator.displayName = 'SelectSeparator';\n"],"mappings":"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"}
1
+ {"version":3,"file":"Select.js","names":[],"sources":["../../src/components/Select.tsx"],"sourcesContent":["'use client';\n\nimport type { ComponentProps } from 'react';\nimport { Select as BaseSelect } from '@base-ui/react/select';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '../lib/cn';\nimport styles from './Select.module.css';\n\n/**\n * Single- or multi-select from a **known set of options** (Decision D17).\n * Wraps Base UI's `Select.*` parts, which implement the ARIA **listbox**\n * pattern: a trigger button opens a popup with `role=\"listbox\"` whose rows\n * are `role=\"option\"`, with roving focus, typeahead and Escape-to-close.\n *\n * This is deliberately distinct from the `Combobox` atom (also D17). A\n * Select has **no text input** — the user picks from a closed list. When the\n * option set is large enough to need filtering, or the value can be typed,\n * that is a Combobox (the APG combobox pattern). shadcn, Base UI and ARIA APG\n * all separate the two under exactly these names, which is why Pharos ships\n * two atoms rather than one component with a `searchable` axis. See\n * the Select + Combobox page of the naming decisions: https://app.notion.com/p/4071751eee108172bf64fdbe0fe8a94b\n *\n * Multi-select is the `multiple` axis on the root (not a separate atom),\n * matching Base UI / shadcn / React Aria: pass `multiple` and `value`\n * becomes an array. Single-select closes on pick; multi-select keeps the\n * popup open so selections accumulate — Base UI derives this from `multiple`\n * and Pharos does not override it.\n *\n * Naming follows shadcn (`Select*`). `SelectTrigger` folds Base UI's\n * `Trigger` + the chevron `Icon`; `SelectContent` collapses `Portal` +\n * `Positioner` + `Popup` + `List` with `side` / `align` / `sideOffset`\n * props; `SelectItem` folds `Item` + `ItemText` + the selected-state\n * `ItemIndicator` — the same ergonomics shadcn exposes over Radix. The popup\n * takes `width: var(--anchor-width)` so it matches the trigger width exactly\n * (long options truncate; override `width` via `className` for a wider panel).\n *\n * Following the form-control composition rule (Escuela 1, D11), the atom owns\n * no label / helper / error message — the consumer composes those, and the\n * error state is conveyed through the standard `aria-invalid` attribute on\n * the trigger (the CSS reacts to `[aria-invalid=\"true\"]`).\n *\n * **Always pass `items` (a value→label map) when the value differs from its\n * label.** Base UI's `SelectValue` resolves the trigger label from the root's\n * `items` prop, NOT from the `SelectItem` children — those are the listbox\n * label + typeahead text. This holds for interactive selection too: without\n * `items` the trigger shows the serialized raw value (the enum\n * `\"organization\"`, not `\"Organization\"`). The idiomatic, drift-free pattern\n * is a single options source that feeds both `items` and the rendered items.\n *\n * @example\n * const VISIBILITY = { private: 'Private', organization: 'Organization', public: 'Public' };\n *\n * <Select value={value} onValueChange={setValue} items={VISIBILITY}>\n * <SelectTrigger aria-label=\"Visibility\">\n * <SelectValue placeholder=\"Select visibility\" />\n * </SelectTrigger>\n * <SelectContent>\n * {Object.entries(VISIBILITY).map(([v, label]) => (\n * <SelectItem key={v} value={v}>\n * {label}\n * </SelectItem>\n * ))}\n * </SelectContent>\n * </Select>\n */\nexport type SelectProps<\n Value,\n Multiple extends boolean | undefined = false,\n> = BaseSelect.Root.Props<Value, Multiple>;\n\nexport function Select<Value, Multiple extends boolean | undefined = false>(\n props: SelectProps<Value, Multiple>,\n) {\n return <BaseSelect.Root {...props} />;\n}\n\nSelect.displayName = 'Select';\n\n/**\n * A downward chevron, inlined as an SVG so the published bundle pulls no icon\n * dependency (Pharos does not bundle `lucide-react`; D4 keeps Lucide as the\n * canonical source for the path data). Rotates 180° when the popup opens via\n * the `[data-popup-open]` selector on the wrapping `SelectIcon`.\n */\nfunction ChevronDownIcon() {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" aria-hidden=\"true\">\n <path d=\"m6 9 6 6 6-6\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n );\n}\n\n/** A check mark for the selected option, inlined for the same reason. */\nfunction CheckIcon() {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" aria-hidden=\"true\">\n <path d=\"M20 6 9 17l-5-5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n );\n}\n\nconst triggerVariants = cva(styles.trigger, {\n variants: {\n size: {\n sm: styles.sizeSm,\n md: styles.sizeMd,\n lg: styles.sizeLg,\n },\n },\n defaultVariants: {\n size: 'md',\n },\n});\n\ntype TriggerVariantProps = VariantProps<typeof triggerVariants>;\n\n/**\n * The button that opens the listbox. Shares the Input chrome (border tone,\n * focus ring, size grid) so a Select sits flush next to an Input on a form\n * row. Folds the trailing chevron, and lays children out before it — the\n * common case is a single `<SelectValue />`. The `size` axis (sm / md / lg)\n * matches the Input and Button heights.\n *\n * Give it an accessible name with `aria-label` (or wire a `<label>` /\n * `aria-labelledby`) — the trigger only shows the chosen value, not a label.\n */\nexport interface SelectTriggerProps\n extends ComponentProps<typeof BaseSelect.Trigger>, TriggerVariantProps {}\n\nexport function SelectTrigger({ size, className, children, ...rest }: SelectTriggerProps) {\n const resolvedSize = size ?? 'md';\n return (\n <BaseSelect.Trigger\n data-pharos-slot=\"select-trigger\"\n data-pharos-size={resolvedSize}\n className={cn(triggerVariants({ size: resolvedSize }), className)}\n {...rest}\n >\n {children}\n <BaseSelect.Icon className={styles.icon}>\n <ChevronDownIcon />\n </BaseSelect.Icon>\n </BaseSelect.Trigger>\n );\n}\n\nSelectTrigger.displayName = 'SelectTrigger';\n\n/**\n * Renders the selected option's label inside the trigger, or the\n * `placeholder` when nothing is selected. Wraps Base UI's `Select.Value`;\n * pass a render function as `children` to format the value yourself.\n */\nexport type SelectValueProps = ComponentProps<typeof BaseSelect.Value>;\n\nexport function SelectValue({ className, ...rest }: SelectValueProps) {\n return (\n <BaseSelect.Value\n data-pharos-slot=\"select-value\"\n className={cn(styles.value, className)}\n {...rest}\n />\n );\n}\n\nSelectValue.displayName = 'SelectValue';\n\n/**\n * The floating listbox. Collapses Base UI's `Portal` + `Positioner` +\n * `Popup` + `List` so the consumer positions it with the props that matter\n * at the call site. Defaults match the common select: opens below the\n * trigger, aligned to its start edge, 8px away, and matches the trigger width\n * (`width: var(--anchor-width)`).\n *\n * `alignItemWithTrigger` is forced to `false`. Base UI's `Select.Positioner`\n * defaults it to `true` — the native-`<select>` / macOS behaviour that floats\n * the popup *over* the trigger to put the selected item under the pointer,\n * and which silently overrides `side` / `align` / `sideOffset`\n * (`renderedSide` becomes `'none'`). Pharos anchors the listbox **below the\n * trigger** instead (D17 refinement): it is the dominant web convention\n * (shadcn `position=\"popper\"`, Ant, Mantine), it keeps the trigger box\n * visible, and — decisively — it makes `Select` consistent with `Combobox`,\n * whose Base UI primitive has no item-alignment mode and always anchors\n * adjacent. With it off, the `side` / `align` / `sideOffset` props below\n * actually take effect.\n */\nexport interface SelectContentProps extends ComponentProps<typeof BaseSelect.Popup> {\n /**\n * Which side of the trigger the listbox opens on.\n * @default 'bottom'\n */\n side?: ComponentProps<typeof BaseSelect.Positioner>['side'];\n /**\n * Alignment of the listbox relative to the trigger along the chosen side.\n * @default 'start'\n */\n align?: ComponentProps<typeof BaseSelect.Positioner>['align'];\n /**\n * Gap in pixels between the trigger and the listbox.\n * @default 8\n */\n sideOffset?: ComponentProps<typeof BaseSelect.Positioner>['sideOffset'];\n /**\n * Offset in pixels along the alignment axis.\n * @default 0\n */\n alignOffset?: ComponentProps<typeof BaseSelect.Positioner>['alignOffset'];\n}\n\nexport function SelectContent({\n side = 'bottom',\n align = 'start',\n sideOffset = 8,\n alignOffset = 0,\n className,\n children,\n ...rest\n}: SelectContentProps) {\n return (\n <BaseSelect.Portal>\n <BaseSelect.Positioner\n className={styles.positioner}\n alignItemWithTrigger={false}\n side={side}\n align={align}\n sideOffset={sideOffset}\n alignOffset={alignOffset}\n >\n <BaseSelect.Popup\n data-pharos-slot=\"select-content\"\n className={cn(styles.content, className)}\n {...rest}\n >\n <BaseSelect.List>{children}</BaseSelect.List>\n </BaseSelect.Popup>\n </BaseSelect.Positioner>\n </BaseSelect.Portal>\n );\n}\n\nSelectContent.displayName = 'SelectContent';\n\n/**\n * A single option. Folds Base UI's `Item` + `ItemText` (the label, also used\n * as the value shown in the trigger) + `ItemIndicator` (the check shown when\n * the option is selected). The `value` prop is required by Base UI and is\n * what `onValueChange` reports.\n */\nexport interface SelectItemProps extends ComponentProps<typeof BaseSelect.Item> {}\n\nexport function SelectItem({ className, children, ...rest }: SelectItemProps) {\n return (\n <BaseSelect.Item\n data-pharos-slot=\"select-item\"\n className={cn(styles.item, className)}\n {...rest}\n >\n <BaseSelect.ItemText className={styles.itemText}>{children}</BaseSelect.ItemText>\n <BaseSelect.ItemIndicator className={styles.itemIndicator}>\n <CheckIcon />\n </BaseSelect.ItemIndicator>\n </BaseSelect.Item>\n );\n}\n\nSelectItem.displayName = 'SelectItem';\n\n/**\n * Groups related options under an optional `SelectLabel` for accessible\n * sectioning (`role=\"group\"`).\n */\nexport type SelectGroupProps = ComponentProps<typeof BaseSelect.Group>;\n\nexport function SelectGroup(props: SelectGroupProps) {\n return <BaseSelect.Group data-pharos-slot=\"select-group\" {...props} />;\n}\n\nSelectGroup.displayName = 'SelectGroup';\n\n/**\n * A non-interactive heading for a `SelectGroup`. Renders Base UI's\n * `Select.GroupLabel`, which wires `aria-labelledby` on the surrounding\n * group — use the two together when a section needs an accessible name.\n */\nexport type SelectLabelProps = ComponentProps<typeof BaseSelect.GroupLabel>;\n\nexport function SelectLabel({ className, ...rest }: SelectLabelProps) {\n return (\n <BaseSelect.GroupLabel\n data-pharos-slot=\"select-label\"\n className={cn(styles.label, className)}\n {...rest}\n />\n );\n}\n\nSelectLabel.displayName = 'SelectLabel';\n\n/**\n * A thin **decorative** divider between groups of options.\n *\n * Rendered `aria-hidden` with `role=\"none\"`. Base UI's `Select.Separator`\n * re-exports the generic `Separator`, which emits `role=\"separator\"`. A\n * `separator` is **not** a permitted child of the `listbox` role (its content\n * model allows only `option` and `group`), so leaving it in the accessibility\n * tree fails axe's `aria-required-children` (critical) on a grouped Select.\n * The grouping is already conveyed semantically by `SelectGroup` (`role=\n * \"group\"`) + `SelectLabel` (`aria-labelledby`), so the divider is purely\n * visual — hiding it from the tree is the correct, drift-free fix (same as\n * Radix / shadcn, whose select separators are `aria-hidden`).\n */\nexport type SelectSeparatorProps = ComponentProps<typeof BaseSelect.Separator>;\n\nexport function SelectSeparator({ className, ...rest }: SelectSeparatorProps) {\n return (\n <BaseSelect.Separator\n data-pharos-slot=\"select-separator\"\n role=\"none\"\n aria-hidden\n className={cn(styles.separator, className)}\n {...rest}\n />\n );\n}\n\nSelectSeparator.displayName = 'SelectSeparator';\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  var e = {
2
- root: "_root_5v2er_17",
3
- thumb: "_thumb_5v2er_72"
2
+ root: "_root_1n9ji_17",
3
+ thumb: "_thumb_1n9ji_73"
4
4
  };
5
5
  //#endregion
6
6
  export { e as default };
@@ -1 +1 @@
1
- {"version":3,"file":"Switch.module.js","names":[],"sources":["../../src/components/Switch.module.css"],"sourcesContent":["/* Switch.module.css\n *\n * Per-component CSS Modules definition (Decision D9). Hashed into\n * `dist/styles.css`. Styles a single on/off toggle (the shadcn \"Switch\"\n * contract) over Base UI's `Switch`. State is driven by Base UI's\n * `data-checked` / `data-disabled` attributes.\n *\n * The atom owns no label (Escuela 1, D11): the consumer pairs it with a\n * `<label htmlFor>`. Error state is conveyed with `aria-invalid`, like Input /\n * Textarea / Checkbox. No icon dependency — the thumb is a plain `<span>`.\n *\n * Geometry is fully token-derived: a 40×24 track (spacing-10 × spacing-6) with\n * spacing-1 (4px) padding houses a 16px (spacing-4) thumb, so the thumb travels\n * exactly spacing-4 (32px inner − 16px thumb) with no hardcoded pixel value.\n */\n\n.root {\n box-sizing: border-box;\n display: inline-flex;\n align-items: center;\n flex-shrink: 0;\n width: var(--pharos-spacing-10);\n height: var(--pharos-spacing-6);\n padding: var(--pharos-spacing-1);\n\n border: none;\n border-radius: var(--pharos-radius-full);\n /* Off track. The perceivable state indicator is the thumb (white with a\n * neutral-500 hairline, ≈5.4:1) — it stays distinguishable on both the light\n * off track and the dark on track, satisfying WCAG 1.4.11. */\n background-color: var(--pharos-color-neutral-300);\n\n cursor: pointer;\n transition-property: background-color, box-shadow;\n transition-duration: var(--pharos-duration-fast);\n transition-timing-function: var(--pharos-easing-out);\n}\n\n.root:hover:not([data-disabled]):not([data-checked]) {\n background-color: var(--pharos-color-neutral-400);\n}\n\n/* On track — the neutral-900 fill, matching the Checkbox's checked look. */\n.root[data-checked] {\n background-color: var(--pharos-color-neutral-900);\n}\n\n.root[data-checked]:hover:not([data-disabled]) {\n background-color: var(--pharos-color-neutral-700);\n}\n\n/* Error state via the standard aria-invalid attribute (D11). An inset ring so\n * the track keeps its geometry (no border-driven layout shift on the thumb). */\n.root[aria-invalid='true'] {\n box-shadow: inset 0 0 0 1px var(--pharos-color-semantic-error-fg);\n}\n\n.root:focus-visible {\n outline: none;\n /* Same two-stop ring as Button / Input / Checkbox so the system has one\n * focus look. */\n box-shadow:\n 0 0 0 2px var(--pharos-color-base-white),\n 0 0 0 4px var(--pharos-color-primary-600);\n}\n\n.root[data-disabled] {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.thumb {\n box-sizing: border-box;\n width: var(--pharos-spacing-4);\n height: var(--pharos-spacing-4);\n border: 1px solid var(--pharos-color-neutral-500);\n border-radius: var(--pharos-radius-full);\n background-color: var(--pharos-color-base-white);\n\n transition-property: transform;\n transition-duration: var(--pharos-duration-fast);\n transition-timing-function: var(--pharos-easing-out);\n}\n\n/* Slide to the far edge: inner width (32px) − thumb (16px) = spacing-4. */\n.root[data-checked] .thumb {\n transform: translateX(var(--pharos-spacing-4));\n}\n"],"mappings":""}
1
+ {"version":3,"file":"Switch.module.js","names":[],"sources":["../../src/components/Switch.module.css"],"sourcesContent":["/* Switch.module.css\n *\n * Per-component CSS Modules definition (Decision D9). Hashed into\n * `dist/styles.css`. Styles a single on/off toggle (the shadcn \"Switch\"\n * contract) over Base UI's `Switch`. State is driven by Base UI's\n * `data-checked` / `data-disabled` attributes.\n *\n * The atom owns no label (Escuela 1, D11): the consumer pairs it with a\n * `<label htmlFor>`. Error state is conveyed with `aria-invalid`, like Input /\n * Textarea / Checkbox. No icon dependency — the thumb is a plain `<span>`.\n *\n * Geometry is fully token-derived: a 40×24 track (spacing-10 × spacing-6) with\n * spacing-1 (4px) padding houses a 16px (spacing-4) thumb, so the thumb travels\n * exactly spacing-4 (32px inner − 16px thumb) with no hardcoded pixel value.\n */\n\n.root {\n box-sizing: border-box;\n display: inline-flex;\n align-items: center;\n flex-shrink: 0;\n width: var(--pharos-spacing-10);\n height: var(--pharos-spacing-6);\n padding: var(--pharos-spacing-1);\n\n border: none;\n border-radius: var(--pharos-radius-full);\n /* Off track: the warm paper fill the tokens reserve for it. The perceivable\n * state indicator is the thumb (white with a neutral-500 hairline, ≈5.4:1) —\n * it stays distinguishable on both the light off track and the dark on track,\n * satisfying WCAG 1.4.11. */\n background-color: var(--pharos-color-paper-300);\n\n cursor: pointer;\n transition-property: background-color, box-shadow;\n transition-duration: var(--pharos-duration-fast);\n transition-timing-function: var(--pharos-easing-out);\n}\n\n.root:hover:not([data-disabled]):not([data-checked]) {\n background-color: var(--pharos-color-neutral-300);\n}\n\n/* On track — the neutral-900 fill, matching the Checkbox's checked look. */\n.root[data-checked] {\n background-color: var(--pharos-color-neutral-900);\n}\n\n.root[data-checked]:hover:not([data-disabled]) {\n background-color: var(--pharos-color-neutral-700);\n}\n\n/* Error state via the standard aria-invalid attribute (D11). An inset ring so\n * the track keeps its geometry (no border-driven layout shift on the thumb). */\n.root[aria-invalid='true'] {\n box-shadow: inset 0 0 0 1px var(--pharos-color-semantic-error-fg);\n}\n\n.root:focus-visible {\n outline: none;\n /* Same two-stop ring as Button / Input / Checkbox so the system has one\n * focus look. */\n box-shadow:\n 0 0 0 2px var(--pharos-color-base-white),\n 0 0 0 4px var(--pharos-color-primary-600);\n}\n\n.root[data-disabled] {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.thumb {\n box-sizing: border-box;\n width: var(--pharos-spacing-4);\n height: var(--pharos-spacing-4);\n border: 1px solid var(--pharos-color-neutral-500);\n border-radius: var(--pharos-radius-full);\n background-color: var(--pharos-color-base-white);\n\n transition-property: transform;\n transition-duration: var(--pharos-duration-fast);\n transition-timing-function: var(--pharos-easing-out);\n}\n\n/* Slide to the far edge: inner width (32px) − thumb (16px) = spacing-4. */\n.root[data-checked] .thumb {\n transform: translateX(var(--pharos-spacing-4));\n}\n"],"mappings":""}
@@ -0,0 +1,48 @@
1
+ import { ComponentProps } from 'react';
2
+ import { ToggleGroup as BaseToggleGroup } from '@base-ui/react/toggle-group';
3
+ import { Toggle as BaseToggle } from '@base-ui/react/toggle';
4
+ import { VariantProps } from 'class-variance-authority';
5
+ declare const toggleGroupVariants: (props?: ({
6
+ size?: "sm" | "md" | null | undefined;
7
+ } & import('class-variance-authority/types').ClassProp) | undefined) => string;
8
+ /**
9
+ * Two to five options shown side by side, where choosing one changes what the
10
+ * surrounding view shows at once — a list shown as List / Grid. The shadcn
11
+ * **ToggleGroup** contract (D25: the artifact's SegmentedControl under its
12
+ * canonical name), over Base UI's `ToggleGroup`: a `role="group"` of toggle
13
+ * buttons with `aria-pressed`, one tab stop and arrow keys to move between
14
+ * them; Enter or Space presses the focused one.
15
+ *
16
+ * In the default single mode one item always stays pressed: pressing the
17
+ * pressed item again is ignored, so the view always has an answer. With
18
+ * `multiple`, any number can be pressed, none included.
19
+ *
20
+ * Like the other form atoms (D11) it owns no label: name the group with
21
+ * `aria-label` or `aria-labelledby`. The value is always an array, as in
22
+ * Base UI: `value={[view]}` and `onValueChange={(v) => setView(v[0])}`.
23
+ *
24
+ * @example
25
+ * <ToggleGroup aria-label="View" value={[view]} onValueChange={(v) => setView(v[0])}>
26
+ * <ToggleGroupItem value="list">List</ToggleGroupItem>
27
+ * <ToggleGroupItem value="grid">Grid</ToggleGroupItem>
28
+ * </ToggleGroup>
29
+ */
30
+ export interface ToggleGroupProps extends ComponentProps<typeof BaseToggleGroup>, VariantProps<typeof toggleGroupVariants> {
31
+ }
32
+ export declare function ToggleGroup({ size, multiple, onValueChange, className, ...rest }: ToggleGroupProps): import("react").JSX.Element;
33
+ export declare namespace ToggleGroup {
34
+ var displayName: string;
35
+ }
36
+ /**
37
+ * One option of a `ToggleGroup`. Wraps Base UI's `Toggle` and requires a
38
+ * `value` unique within the group. Its text names it; an icon-only item needs
39
+ * an `aria-label`.
40
+ */
41
+ export interface ToggleGroupItemProps extends ComponentProps<typeof BaseToggle> {
42
+ }
43
+ export declare function ToggleGroupItem({ className, ...rest }: ToggleGroupItemProps): import("react").JSX.Element;
44
+ export declare namespace ToggleGroupItem {
45
+ var displayName: string;
46
+ }
47
+ export { toggleGroupVariants };
48
+ //# sourceMappingURL=ToggleGroup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToggleGroup.d.ts","sourceRoot":"","sources":["../../src/components/ToggleGroup.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,EAAE,WAAW,IAAI,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC7E,OAAO,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAIlE,QAAA,MAAM,mBAAmB;;8EAUvB,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,WAAW,gBACf,SAAQ,cAAc,CAAC,OAAO,eAAe,CAAC,EAAE,YAAY,CAAC,OAAO,mBAAmB,CAAC;CAAG;AAE7F,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,QAAgB,EAChB,aAAa,EACb,SAAS,EACT,GAAG,IAAI,EACR,EAAE,gBAAgB,+BAqBlB;yBA3Be,WAAW;;;AA+B3B;;;;GAIG;AACH,MAAM,WAAW,oBAAqB,SAAQ,cAAc,CAAC,OAAO,UAAU,CAAC;CAAG;AAElF,wBAAgB,eAAe,CAAC,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,EAAE,oBAAoB,+BAQ3E;yBARe,eAAe;;;AAY/B,OAAO,EAAE,mBAAmB,EAAE,CAAC"}
@@ -0,0 +1,46 @@
1
+ "use client";
2
+ import { cn as e } from "../lib/cn.js";
3
+ import t from "./ToggleGroup.module.js";
4
+ import { cva as n } from "class-variance-authority";
5
+ import { jsx as r } from "react/jsx-runtime";
6
+ import { ToggleGroup as i } from "@base-ui/react/toggle-group";
7
+ import { Toggle as a } from "@base-ui/react/toggle";
8
+ //#region src/components/ToggleGroup.tsx
9
+ var o = n(t.group, {
10
+ variants: { size: {
11
+ sm: t.sizeSm,
12
+ md: t.sizeMd
13
+ } },
14
+ defaultVariants: { size: "md" }
15
+ });
16
+ function s({ size: t, multiple: n = !1, onValueChange: a, className: s, ...c }) {
17
+ let l = t ?? "md";
18
+ return /* @__PURE__ */ r(i, {
19
+ "data-pharos-slot": "toggle-group",
20
+ "data-pharos-size": l,
21
+ multiple: n,
22
+ onValueChange: function(e, t) {
23
+ if (!n && e.length === 0) {
24
+ t.cancel();
25
+ return;
26
+ }
27
+ a?.(e, t);
28
+ },
29
+ className: e(o({ size: l }), s),
30
+ ...c,
31
+ "aria-orientation": void 0
32
+ });
33
+ }
34
+ s.displayName = "ToggleGroup";
35
+ function c({ className: n, ...i }) {
36
+ return /* @__PURE__ */ r(a, {
37
+ "data-pharos-slot": "toggle-group-item",
38
+ className: e(t.item, n),
39
+ ...i
40
+ });
41
+ }
42
+ c.displayName = "ToggleGroupItem";
43
+ //#endregion
44
+ export { s as ToggleGroup, c as ToggleGroupItem };
45
+
46
+ //# sourceMappingURL=ToggleGroup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToggleGroup.js","names":[],"sources":["../../src/components/ToggleGroup.tsx"],"sourcesContent":["'use client';\n\nimport type { ComponentProps } from 'react';\nimport { ToggleGroup as BaseToggleGroup } from '@base-ui/react/toggle-group';\nimport { Toggle as BaseToggle } from '@base-ui/react/toggle';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '../lib/cn';\nimport styles from './ToggleGroup.module.css';\n\nconst toggleGroupVariants = cva(styles.group, {\n variants: {\n size: {\n sm: styles.sizeSm,\n md: styles.sizeMd,\n },\n },\n defaultVariants: {\n size: 'md',\n },\n});\n\n/**\n * Two to five options shown side by side, where choosing one changes what the\n * surrounding view shows at once — a list shown as List / Grid. The shadcn\n * **ToggleGroup** contract (D25: the artifact's SegmentedControl under its\n * canonical name), over Base UI's `ToggleGroup`: a `role=\"group\"` of toggle\n * buttons with `aria-pressed`, one tab stop and arrow keys to move between\n * them; Enter or Space presses the focused one.\n *\n * In the default single mode one item always stays pressed: pressing the\n * pressed item again is ignored, so the view always has an answer. With\n * `multiple`, any number can be pressed, none included.\n *\n * Like the other form atoms (D11) it owns no label: name the group with\n * `aria-label` or `aria-labelledby`. The value is always an array, as in\n * Base UI: `value={[view]}` and `onValueChange={(v) => setView(v[0])}`.\n *\n * @example\n * <ToggleGroup aria-label=\"View\" value={[view]} onValueChange={(v) => setView(v[0])}>\n * <ToggleGroupItem value=\"list\">List</ToggleGroupItem>\n * <ToggleGroupItem value=\"grid\">Grid</ToggleGroupItem>\n * </ToggleGroup>\n */\nexport interface ToggleGroupProps\n extends ComponentProps<typeof BaseToggleGroup>, VariantProps<typeof toggleGroupVariants> {}\n\nexport function ToggleGroup({\n size,\n multiple = false,\n onValueChange,\n className,\n ...rest\n}: ToggleGroupProps) {\n const resolvedSize = size ?? 'md';\n return (\n <BaseToggleGroup\n data-pharos-slot=\"toggle-group\"\n data-pharos-size={resolvedSize}\n multiple={multiple}\n onValueChange={function keepOnePressed(groupValue, eventDetails) {\n if (!multiple && groupValue.length === 0) {\n eventDetails.cancel();\n return;\n }\n onValueChange?.(groupValue, eventDetails);\n }}\n className={cn(toggleGroupVariants({ size: resolvedSize }), className)}\n {...rest}\n // Base UI sets aria-orientation, which ARIA does not allow on\n // role=\"group\" (axe: aria-allowed-attr). The arrow keys work without it.\n aria-orientation={undefined}\n />\n );\n}\n\nToggleGroup.displayName = 'ToggleGroup';\n\n/**\n * One option of a `ToggleGroup`. Wraps Base UI's `Toggle` and requires a\n * `value` unique within the group. Its text names it; an icon-only item needs\n * an `aria-label`.\n */\nexport interface ToggleGroupItemProps extends ComponentProps<typeof BaseToggle> {}\n\nexport function ToggleGroupItem({ className, ...rest }: ToggleGroupItemProps) {\n return (\n <BaseToggle\n data-pharos-slot=\"toggle-group-item\"\n className={cn(styles.item, className)}\n {...rest}\n />\n );\n}\n\nToggleGroupItem.displayName = 'ToggleGroupItem';\n\nexport { toggleGroupVariants };\n"],"mappings":";;;;;;;;AASA,IAAM,IAAsB,EAAI,EAAO,OAAO;CAC5C,UAAU,EACR,MAAM;EACJ,IAAI,EAAO;EACX,IAAI,EAAO;CACb,EACF;CACA,iBAAiB,EACf,MAAM,KACR;AACF,CAAC;AA2BD,SAAgB,EAAY,EAC1B,SACA,cAAW,IACX,kBACA,cACA,GAAG,KACgB;CACnB,IAAM,IAAe,KAAQ;CAC7B,OACE,kBAAC,GAAD;EACE,oBAAiB;EACjB,oBAAkB;EACR;EACV,eAAe,SAAwB,GAAY,GAAc;GAC/D,IAAI,CAAC,KAAY,EAAW,WAAW,GAAG;IACxC,EAAa,OAAO;IACpB;GACF;GACA,IAAgB,GAAY,CAAY;EAC1C;EACA,WAAW,EAAG,EAAoB,EAAE,MAAM,EAAa,CAAC,GAAG,CAAS;EACpE,GAAI;EAGJ,oBAAkB,KAAA;CACnB,CAAA;AAEL;AAEA,EAAY,cAAc;AAS1B,SAAgB,EAAgB,EAAE,cAAW,GAAG,KAA8B;CAC5E,OACE,kBAAC,GAAD;EACE,oBAAiB;EACjB,WAAW,EAAG,EAAO,MAAM,CAAS;EACpC,GAAI;CACL,CAAA;AAEL;AAEA,EAAgB,cAAc"}
@@ -0,0 +1,10 @@
1
+ var e = {
2
+ group: "_group_zoq3z_13",
3
+ sizeSm: "_sizeSm_zoq3z_25",
4
+ sizeMd: "_sizeMd_zoq3z_29",
5
+ item: "_item_zoq3z_33"
6
+ };
7
+ //#endregion
8
+ export { e as default };
9
+
10
+ //# sourceMappingURL=ToggleGroup.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToggleGroup.module.js","names":[],"sources":["../../src/components/ToggleGroup.module.css"],"sourcesContent":["/* ToggleGroup.module.css\n *\n * Per-component CSS Modules definition (Decision D9). Hashed into\n * `dist/styles.css`. Styles the shadcn \"ToggleGroup\" contract over Base UI's\n * `ToggleGroup` + `Toggle`, with the look of the artifact's SegmentedControl\n * (D25): a warm paper rail holding pill segments, the pressed one lifted in\n * white. Item state is driven by Base UI's `data-pressed` / `data-disabled`.\n *\n * Heights sit on the control grid (32 / 40px: spacing-8 / spacing-10), with a\n * spacing-0-5 rail inset and gap.\n */\n\n.group {\n box-sizing: border-box;\n display: inline-flex;\n align-items: stretch;\n gap: var(--pharos-spacing-0-5);\n max-width: 100%;\n padding: var(--pharos-spacing-0-5);\n border-radius: var(--pharos-radius-full);\n background-color: var(--pharos-color-paper-200);\n font-family: var(--pharos-font-family-sans);\n}\n\n.sizeSm {\n height: var(--pharos-spacing-8);\n}\n\n.sizeMd {\n height: var(--pharos-spacing-10);\n}\n\n.item {\n appearance: none;\n box-sizing: border-box;\n display: inline-flex;\n flex: 1 1 auto;\n align-items: center;\n justify-content: center;\n gap: var(--pharos-spacing-1-5);\n min-width: 0;\n margin: 0;\n padding: 0 var(--pharos-spacing-3);\n\n border: 0;\n border-radius: var(--pharos-radius-full);\n background: transparent;\n /* neutral-600 on paper-200 keeps the resting labels above 4.5:1. */\n color: var(--pharos-color-neutral-600);\n font: inherit;\n font-size: var(--pharos-font-size-sm);\n font-weight: var(--pharos-font-weight-medium);\n line-height: 1;\n white-space: nowrap;\n\n cursor: pointer;\n transition-property: color, background-color, box-shadow;\n transition-duration: var(--pharos-duration-fast);\n transition-timing-function: var(--pharos-easing-out);\n}\n\n.sizeMd .item {\n padding: 0 var(--pharos-spacing-4);\n}\n\n.item > svg {\n width: 1em;\n height: 1em;\n flex: 0 0 auto;\n}\n\n.item:hover:not([data-pressed]):not([data-disabled]) {\n color: var(--pharos-color-neutral-900);\n background-color: var(--pharos-color-paper-300);\n}\n\n/* Pressed: lifted in white. The paper-300 hairline draws its edge where the\n * shadow alone would be too faint on the warm rail. */\n.item[data-pressed] {\n color: var(--pharos-color-neutral-900);\n background-color: var(--pharos-color-base-white);\n box-shadow:\n var(--pharos-shadow-sm),\n 0 0 0 1px var(--pharos-color-paper-300);\n}\n\n.item:focus-visible {\n outline: none;\n /* Same two-stop ring as every other control. */\n box-shadow:\n 0 0 0 2px var(--pharos-color-base-white),\n 0 0 0 4px var(--pharos-color-primary-600);\n}\n\n.item[data-disabled] {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .item {\n transition: none;\n }\n}\n"],"mappings":""}
package/dist/index.d.ts CHANGED
@@ -34,6 +34,8 @@ export { Switch } from './components/Switch';
34
34
  export type { SwitchProps } from './components/Switch';
35
35
  export { RadioGroup, RadioGroupItem } from './components/RadioGroup';
36
36
  export type { RadioGroupProps, RadioGroupItemProps } from './components/RadioGroup';
37
+ export { ToggleGroup, ToggleGroupItem } from './components/ToggleGroup';
38
+ export type { ToggleGroupProps, ToggleGroupItemProps } from './components/ToggleGroup';
37
39
  export { ToastProvider, Toaster, useToast } from './components/Toast';
38
40
  export type { ToastProviderProps, ToasterProps, ToasterPosition, ToastOptions, ToastVariant, UseToastReturnValue, } from './components/Toast';
39
41
  export { cn } from './lib/cn';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -17,5 +17,6 @@ import { Dialog as ge, DialogClose as _e, DialogContent as ve, DialogDescription
17
17
  import { Checkbox as we } from "./components/Checkbox.js";
18
18
  import { Switch as Te } from "./components/Switch.js";
19
19
  import { RadioGroup as Ee, RadioGroupItem as De } from "./components/RadioGroup.js";
20
- import { ToastProvider as Oe, Toaster as ke, useToast as Ae } from "./components/Toast.js";
21
- export { x as Avatar, S as AvatarFallback, C as AvatarGroup, w as AvatarImage, s as Badge, t as Button, m as Card, h as CardContent, g as CardDescription, _ as CardFooter, v as CardHeader, y as CardTitle, we as Checkbox, K as Combobox, q as ComboboxChip, J as ComboboxChipRemove, Y as ComboboxChips, X as ComboboxClear, Z as ComboboxContent, Q as ComboboxControl, $ as ComboboxEmpty, ee as ComboboxGroup, te as ComboboxGroupLabel, ne as ComboboxInput, re as ComboboxItem, ie as ComboboxList, ae as ComboboxSeparator, oe as ComboboxTrigger, ge as Dialog, _e as DialogClose, ve as DialogContent, ye as DialogDescription, be as DialogFooter, xe as DialogHeader, Se as DialogTitle, Ce as DialogTrigger, T as DropdownMenu, E as DropdownMenuContent, D as DropdownMenuGroup, O as DropdownMenuItem, k as DropdownMenuLabel, A as DropdownMenuSeparator, j as DropdownMenuTrigger, a as IconButton, l as Input, M as Popover, N as PopoverClose, P as PopoverContent, F as PopoverDescription, I as PopoverTitle, L as PopoverTrigger, Ee as RadioGroup, De as RadioGroupItem, R as Select, z as SelectContent, B as SelectGroup, V as SelectItem, H as SelectLabel, U as SelectSeparator, W as SelectTrigger, G as SelectValue, p as Separator, se as Sheet, ce as SheetClose, le as SheetContent, ue as SheetDescription, de as SheetFooter, fe as SheetHeader, pe as SheetTitle, me as SheetTrigger, r as Spinner, Te as Switch, d as Textarea, Oe as ToastProvider, ke as Toaster, c as badgeVariants, n as buttonVariants, b as cardVariants, e as cn, o as iconButtonVariants, u as inputVariants, he as sheetVariants, i as spinnerVariants, f as textareaVariants, Ae as useToast };
20
+ import { ToggleGroup as Oe, ToggleGroupItem as ke } from "./components/ToggleGroup.js";
21
+ import { ToastProvider as Ae, Toaster as je, useToast as Me } from "./components/Toast.js";
22
+ export { x as Avatar, S as AvatarFallback, C as AvatarGroup, w as AvatarImage, s as Badge, t as Button, m as Card, h as CardContent, g as CardDescription, _ as CardFooter, v as CardHeader, y as CardTitle, we as Checkbox, K as Combobox, q as ComboboxChip, J as ComboboxChipRemove, Y as ComboboxChips, X as ComboboxClear, Z as ComboboxContent, Q as ComboboxControl, $ as ComboboxEmpty, ee as ComboboxGroup, te as ComboboxGroupLabel, ne as ComboboxInput, re as ComboboxItem, ie as ComboboxList, ae as ComboboxSeparator, oe as ComboboxTrigger, ge as Dialog, _e as DialogClose, ve as DialogContent, ye as DialogDescription, be as DialogFooter, xe as DialogHeader, Se as DialogTitle, Ce as DialogTrigger, T as DropdownMenu, E as DropdownMenuContent, D as DropdownMenuGroup, O as DropdownMenuItem, k as DropdownMenuLabel, A as DropdownMenuSeparator, j as DropdownMenuTrigger, a as IconButton, l as Input, M as Popover, N as PopoverClose, P as PopoverContent, F as PopoverDescription, I as PopoverTitle, L as PopoverTrigger, Ee as RadioGroup, De as RadioGroupItem, R as Select, z as SelectContent, B as SelectGroup, V as SelectItem, H as SelectLabel, U as SelectSeparator, W as SelectTrigger, G as SelectValue, p as Separator, se as Sheet, ce as SheetClose, le as SheetContent, ue as SheetDescription, de as SheetFooter, fe as SheetHeader, pe as SheetTitle, me as SheetTrigger, r as Spinner, Te as Switch, d as Textarea, Ae as ToastProvider, je as Toaster, Oe as ToggleGroup, ke as ToggleGroupItem, c as badgeVariants, n as buttonVariants, b as cardVariants, e as cn, o as iconButtonVariants, u as inputVariants, he as sheetVariants, i as spinnerVariants, f as textareaVariants, Me as useToast };
package/dist/styles.css CHANGED
@@ -1,2 +1,2 @@
1
- ._root_1xx27_21{box-sizing:border-box;background-color:var(--pharos-color-neutral-100);color:var(--pharos-color-neutral-700);font-family:var(--pharos-font-family-sans);-webkit-user-select:none;user-select:none;--pharos-avatar-overlap:calc(var(--pharos-spacing-2) * -1);flex-shrink:0;justify-content:center;align-items:center;font-weight:500;line-height:1;display:inline-flex;position:relative;overflow:hidden}._shapeCircle_1xx27_63{border-radius:var(--pharos-radius-full)}._shapeSquare_1xx27_67{border-radius:var(--pharos-radius-md)}._sizeSm_1xx27_86{width:var(--pharos-spacing-8);height:var(--pharos-spacing-8);--pharos-avatar-overlap:calc(var(--pharos-spacing-2) * -.75);font-size:.75rem}._sizeMd_1xx27_93{width:var(--pharos-spacing-10);height:var(--pharos-spacing-10);--pharos-avatar-overlap:calc(var(--pharos-spacing-2) * -1);font-size:.875rem}._sizeLg_1xx27_100{width:var(--pharos-spacing-12);height:var(--pharos-spacing-12);--pharos-avatar-overlap:calc(var(--pharos-spacing-2) * -1.25);font-size:1rem}._image_1xx27_118{object-fit:cover;border-radius:inherit;width:100%;height:100%;display:block;position:absolute;inset:0}._fallback_1xx27_134{text-align:center;width:100%;height:100%;font:inherit;color:inherit;justify-content:center;align-items:center;display:inline-flex}._sizeSm_1xx27_86 ._fallback_1xx27_134>svg{width:var(--pharos-spacing-5);height:var(--pharos-spacing-5)}._sizeMd_1xx27_93 ._fallback_1xx27_134>svg{width:var(--pharos-spacing-6);height:var(--pharos-spacing-6)}._sizeLg_1xx27_100 ._fallback_1xx27_134>svg{width:var(--pharos-spacing-7);height:var(--pharos-spacing-7)}._group_1xx27_175{align-items:center;display:inline-flex}._group_1xx27_175>._root_1xx27_21{box-shadow:0 0 0 2px var(--pharos-avatar-group-ring,var(--pharos-color-base-white));position:relative}._group_1xx27_175>._root_1xx27_21+._root_1xx27_21{margin-left:var(--pharos-avatar-overlap)}._badge_zrawy_5{align-items:center;gap:var(--pharos-spacing-1);padding:0 var(--pharos-spacing-2);height:var(--pharos-spacing-5);border-radius:var(--pharos-radius-full);font-family:var(--pharos-font-family-sans);font-size:var(--pharos-font-size-xs);font-weight:var(--pharos-font-weight-medium);white-space:nowrap;text-box-trim:trim-both;text-box-edge:cap alphabetic;border:1px solid #0000;width:fit-content;line-height:1;display:inline-flex}._badge_zrawy_5>svg{pointer-events:none;flex:none;width:.75em;height:.75em}._default_zrawy_30{background:var(--pharos-color-neutral-900);color:var(--pharos-color-base-white)}._secondary_zrawy_35{background:var(--pharos-color-neutral-100);color:var(--pharos-color-neutral-900)}._destructive_zrawy_40{background:var(--pharos-color-semantic-error-fg);color:var(--pharos-color-semantic-error-on)}._outline_zrawy_45{color:var(--pharos-color-neutral-900);border-color:var(--pharos-color-neutral-500);background:0 0}._success_zrawy_55{background:var(--pharos-color-semantic-success-fg);color:var(--pharos-color-semantic-success-on)}._warning_zrawy_60{background:var(--pharos-color-semantic-warning-fg);color:var(--pharos-color-semantic-warning-on)}._info_zrawy_65{background:var(--pharos-color-semantic-info-fg);color:var(--pharos-color-semantic-info-on)}._button_1g7u9_18{appearance:none;box-sizing:border-box;border-radius:var(--pharos-radius-full);white-space:nowrap;text-box-trim:trim-both;text-box-edge:cap alphabetic;font-family:var(--pharos-font-family-sans);font-style:normal;font-weight:var(--pharos-font-weight-medium);font-variant:normal;font-kerning:auto;font-optical-sizing:auto;font-size-adjust:none;font-feature-settings:normal;font-variation-settings:normal;letter-spacing:normal;text-transform:none;font-stretch:100%;font-size:var(--pharos-font-size-sm);-webkit-user-select:none;user-select:none;cursor:pointer;color:inherit;transition-property:color,background-color,border-color,box-shadow;transition-duration:var(--pharos-duration-normal);transition-timing-function:var(--pharos-easing-out);background-color:#0000;border:0 solid #0000;justify-content:center;align-items:center;margin:0;padding-top:0;padding-bottom:0;line-height:1.5;text-decoration:none;display:inline-flex}._button_1g7u9_18:focus-visible{box-shadow:0 0 0 2px var(--pharos-color-base-white), 0 0 0 4px var(--button-focus-ring,var(--pharos-color-primary-600));outline:none}._button_1g7u9_18:disabled{pointer-events:none;cursor:not-allowed;opacity:.5}._button_1g7u9_18[aria-disabled=true]{cursor:not-allowed;opacity:.5}._primary_1g7u9_142{background-color:var(--pharos-color-primary-600);color:var(--pharos-color-base-white);--button-focus-ring:var(--pharos-color-primary-600)}._primary_1g7u9_142:hover:not([aria-disabled=true]){background-color:var(--pharos-color-primary-700)}._primary_1g7u9_142:active:not([aria-disabled=true]){background-color:var(--pharos-color-primary-800)}._secondary_1g7u9_156{background-color:var(--pharos-color-base-white);color:var(--pharos-color-neutral-900);border:1px solid var(--pharos-color-neutral-500);--button-focus-ring:var(--pharos-color-primary-600)}._secondary_1g7u9_156:hover:not([aria-disabled=true]){background-color:var(--pharos-color-neutral-50)}._secondary_1g7u9_156:active:not([aria-disabled=true]){background-color:var(--pharos-color-neutral-100)}._ghost_1g7u9_176{color:var(--pharos-color-neutral-900);--button-focus-ring:var(--pharos-color-primary-600);background-color:#0000}._ghost_1g7u9_176:hover:not([aria-disabled=true]){background-color:var(--pharos-color-neutral-100)}._ghost_1g7u9_176:active:not([aria-disabled=true]){background-color:var(--pharos-color-neutral-200)}._destructive_1g7u9_190{background-color:var(--pharos-color-semantic-error-fg);color:var(--pharos-color-semantic-error-on);--button-focus-ring:var(--pharos-color-semantic-error-fg)}._destructive_1g7u9_190:hover:not([aria-disabled=true]){background-color:var(--pharos-color-semantic-error-fg-hover)}._destructive_1g7u9_190:active:not([aria-disabled=true]){background-color:var(--pharos-color-semantic-error-fg-active)}._sizeSm_1g7u9_212{height:var(--pharos-spacing-8);gap:var(--pharos-spacing-1-5);padding:0 var(--pharos-spacing-3);font-size:var(--pharos-font-size-sm);line-height:1.42857}._sizeMd_1g7u9_220{height:var(--pharos-spacing-10);gap:var(--pharos-spacing-2);padding:0 var(--pharos-spacing-4);font-size:var(--pharos-font-size-sm);line-height:1.42857}._sizeLg_1g7u9_228{height:var(--pharos-spacing-12);gap:var(--pharos-spacing-2);padding:0 var(--pharos-spacing-6);font-size:var(--pharos-font-size-base);line-height:1.5}._card_yxgwa_10{background-color:var(--pharos-color-base-white);border-radius:var(--pharos-radius-2xl);gap:var(--pharos-spacing-6);font-family:var(--pharos-font-family-sans);color:var(--pharos-color-neutral-900);transition-property:border-color,box-shadow;transition-duration:var(--pharos-duration-normal);transition-timing-function:var(--pharos-easing-out);border:0 solid #0000;flex-direction:column;display:flex}._default_yxgwa_42{border:1px solid var(--pharos-color-neutral-200)}._elevated_yxgwa_46{box-shadow:var(--pharos-shadow-md);border:0 solid #0000}._outlined_yxgwa_51{border:1px solid var(--pharos-color-neutral-300)}._header_yxgwa_62{gap:var(--pharos-spacing-1-5);padding:var(--pharos-spacing-6) var(--pharos-spacing-6) 0;flex-direction:column;display:flex}._title_yxgwa_69{font-size:var(--pharos-font-size-base);font-weight:var(--pharos-font-weight-semibold);color:var(--pharos-color-neutral-900);margin:0;line-height:1.25}._description_yxgwa_77{font-size:var(--pharos-font-size-sm);font-weight:var(--pharos-font-weight-regular);color:var(--pharos-color-neutral-500);margin:0;line-height:1.5}._content_yxgwa_85{padding:0 var(--pharos-spacing-6)}._footer_yxgwa_95{align-items:center;gap:var(--pharos-spacing-3);padding:0 var(--pharos-spacing-6) var(--pharos-spacing-6);display:flex}._root_1v9tz_14{box-sizing:border-box;width:var(--pharos-spacing-5);height:var(--pharos-spacing-5);border:1px solid var(--pharos-color-neutral-500);border-radius:var(--pharos-radius-sm);background-color:var(--pharos-color-base-white);color:var(--pharos-color-base-white);cursor:pointer;transition-property:background-color,border-color,box-shadow;transition-duration:var(--pharos-duration-fast);transition-timing-function:var(--pharos-easing-out);flex-shrink:0;justify-content:center;align-items:center;padding:0;display:inline-flex}._root_1v9tz_14:hover:not([data-disabled]):not([data-checked]):not([data-indeterminate]){border-color:var(--pharos-color-neutral-700)}._root_1v9tz_14[data-checked],._root_1v9tz_14[data-indeterminate]{background-color:var(--pharos-color-neutral-900);border-color:var(--pharos-color-neutral-900)}._root_1v9tz_14[aria-invalid=true]{border-color:var(--pharos-color-semantic-error-fg)}._root_1v9tz_14:focus-visible{box-shadow:0 0 0 2px var(--pharos-color-base-white), 0 0 0 4px var(--pharos-color-primary-600);outline:none}._root_1v9tz_14[data-disabled]{cursor:not-allowed;opacity:.5}._indicator_1v9tz_65{color:var(--pharos-color-base-white);justify-content:center;align-items:center;display:inline-flex}._icon_1v9tz_72{width:var(--pharos-spacing-3);height:var(--pharos-spacing-3)}._iconIndeterminate_1v9tz_79,._indicator_1v9tz_65[data-indeterminate] ._iconCheck_1v9tz_83{display:none}._indicator_1v9tz_65[data-indeterminate] ._iconIndeterminate_1v9tz_79{display:block}._control_12m6b_5{box-sizing:border-box;align-items:center;gap:var(--pharos-spacing-2);border:1px solid var(--pharos-color-neutral-500);border-radius:var(--pharos-radius-md);background-color:var(--pharos-color-base-white);width:100%;font-family:var(--pharos-font-family-sans);transition-property:border-color,box-shadow;transition-duration:var(--pharos-duration-normal);transition-timing-function:var(--pharos-easing-out);display:flex}._control_12m6b_5:focus-within{border-color:var(--pharos-color-primary-600);box-shadow:0 0 0 2px var(--pharos-color-base-white), 0 0 0 4px var(--pharos-color-primary-600)}._control_12m6b_5[aria-invalid=true]{border-color:var(--pharos-color-semantic-error-fg)}._control_12m6b_5:has([aria-invalid=true]){border-color:var(--pharos-color-semantic-error-fg)}._control_12m6b_5[data-disabled]{opacity:.5;cursor:not-allowed}._control_12m6b_5:has(._input_12m6b_66:disabled){opacity:.5;cursor:not-allowed}._chips_12m6b_72{gap:var(--pharos-spacing-1);padding:var(--pharos-spacing-1) var(--pharos-spacing-2);flex-wrap:wrap}._input_12m6b_66{appearance:none;min-width:0;color:var(--pharos-color-neutral-900);font-family:var(--pharos-font-family-sans);font-size:var(--pharos-font-size-sm);font-weight:var(--pharos-font-weight-regular);background:0 0;border:none;outline:none;flex:auto;margin:0;line-height:1.25}._input_12m6b_66::placeholder{color:var(--pharos-color-neutral-500);opacity:1}._input_12m6b_66:disabled{cursor:not-allowed}._inputSizeSm_12m6b_110{height:var(--pharos-spacing-8);padding:0 var(--pharos-spacing-3)}._inputSizeMd_12m6b_115{height:var(--pharos-spacing-10);padding:0 var(--pharos-spacing-4)}._inputSizeLg_12m6b_120{height:var(--pharos-spacing-12);padding:0 var(--pharos-spacing-6);font-size:var(--pharos-font-size-base)}._chipsInput_12m6b_128{height:var(--pharos-spacing-7);padding:0 var(--pharos-spacing-1);flex:4rem}._trigger_12m6b_135,._clear_12m6b_136{width:var(--pharos-spacing-6);height:var(--pharos-spacing-6);color:var(--pharos-color-neutral-500);cursor:default;background:0 0;border:none;flex:none;justify-content:center;align-items:center;margin-inline-end:var(--pharos-spacing-1);padding:0;display:inline-flex}._trigger_12m6b_135 svg,._clear_12m6b_136 svg{width:1rem;height:1rem}._trigger_12m6b_135[data-popup-open] svg{transition:transform var(--pharos-duration-fast) var(--pharos-easing-out);transform:rotate(180deg)}._chip_12m6b_72{align-items:center;gap:var(--pharos-spacing-1);padding:0 var(--pharos-spacing-1) 0 var(--pharos-spacing-2);height:var(--pharos-spacing-6);border-radius:var(--pharos-radius-sm);background-color:var(--pharos-color-neutral-100);color:var(--pharos-color-neutral-900);font-size:var(--pharos-font-size-xs);display:inline-flex}._chip_12m6b_72[data-highlighted]{background-color:var(--pharos-color-neutral-200)}._chipRemove_12m6b_180{width:var(--pharos-spacing-4);height:var(--pharos-spacing-4);border-radius:var(--pharos-radius-sm);color:var(--pharos-color-neutral-500);cursor:default;background:0 0;border:none;justify-content:center;align-items:center;padding:0;display:inline-flex}._chipRemove_12m6b_180:hover{color:var(--pharos-color-neutral-900)}._trigger_12m6b_135[data-disabled],._clear_12m6b_136[data-disabled],._chipRemove_12m6b_180[data-disabled]{cursor:not-allowed}._chipRemove_12m6b_180[data-disabled]:hover{color:var(--pharos-color-neutral-500)}._chipRemove_12m6b_180 svg{width:.875rem;height:.875rem}._positioner_12m6b_227{z-index:var(--pharos-z-index-popover)}._content_12m6b_217{box-sizing:border-box;width:var(--anchor-width);max-height:var(--available-height);padding:var(--pharos-spacing-1);background-color:var(--pharos-color-base-white);border:1px solid var(--pharos-color-neutral-200);border-radius:var(--pharos-radius-md);box-shadow:var(--pharos-shadow-lg);font-family:var(--pharos-font-family-sans);font-size:var(--pharos-font-size-sm);color:var(--pharos-color-neutral-900);transform-origin:var(--transform-origin);transition-property:opacity,transform;transition-duration:var(--pharos-duration-fast);transition-timing-function:var(--pharos-easing-out);outline:none;overflow-y:auto}._content_12m6b_217[data-starting-style],._content_12m6b_217[data-ending-style]{opacity:0;transform:scale(.96)}._item_12m6b_14{align-items:flex-start;gap:var(--pharos-spacing-2);padding:var(--pharos-spacing-2) var(--pharos-spacing-3);border-radius:var(--pharos-radius-sm);color:var(--pharos-color-neutral-900);cursor:default;-webkit-user-select:none;user-select:none;scroll-margin:var(--pharos-spacing-1);outline:none;display:flex;position:relative}._item_12m6b_14[data-highlighted]{background-color:var(--pharos-color-neutral-100)}._item_12m6b_14[data-disabled]{color:var(--pharos-color-neutral-400);pointer-events:none}._itemText_12m6b_14{overflow-wrap:anywhere;white-space:normal;flex:auto;min-width:0}._itemIndicator_12m6b_298{block-size:1lh;color:var(--pharos-color-primary-600);flex:none;justify-content:center;align-items:center;display:inline-flex}._itemIndicator_12m6b_298 svg{width:1rem;height:1rem}._empty_12m6b_322{color:var(--pharos-color-neutral-500);text-align:center}._empty_12m6b_322:not(:empty){padding:var(--pharos-spacing-3)}._label_12m6b_332{padding:var(--pharos-spacing-2) var(--pharos-spacing-3) var(--pharos-spacing-1);font-size:var(--pharos-font-size-xs);font-weight:var(--pharos-font-weight-semibold);color:var(--pharos-color-neutral-600)}._separator_12m6b_339{height:1px;margin:var(--pharos-spacing-1) 0;background-color:var(--pharos-color-neutral-200)}@media (pointer:coarse){._input_12m6b_66{font-size:var(--pharos-font-size-base)}}._backdrop_1d4e6_19{z-index:var(--pharos-z-index-modal);background-color:color-mix(in srgb, var(--pharos-color-base-black) 50%, transparent);transition:opacity var(--pharos-duration-normal) var(--pharos-easing-out);position:fixed;inset:0}._backdrop_1d4e6_19[data-starting-style],._backdrop_1d4e6_19[data-ending-style]{opacity:0}._content_1d4e6_33{transform-origin:50%;z-index:var(--pharos-z-index-modal);box-sizing:border-box;width:calc(100% - 2 * var(--pharos-spacing-4));max-width:32rem;max-height:calc(100dvh - 2 * var(--pharos-spacing-6));gap:var(--pharos-spacing-4);padding:var(--pharos-spacing-6);background-color:var(--pharos-color-base-white);border-radius:var(--pharos-radius-lg);box-shadow:var(--pharos-shadow-xl);font-family:var(--pharos-font-family-sans);font-size:var(--pharos-font-size-sm);color:var(--pharos-color-neutral-900);transition-property:opacity,transform;transition-duration:var(--pharos-duration-fast);transition-timing-function:var(--pharos-easing-out);outline:none;flex-direction:column;display:flex;position:fixed;top:50%;left:50%;overflow-y:auto;transform:translate(-50%,-50%)}._content_1d4e6_33[data-starting-style],._content_1d4e6_33[data-ending-style]{opacity:0;transform:translate(-50%,-50%)scale(.96)}._header_1d4e6_76{gap:var(--pharos-spacing-1);flex-direction:column;display:flex}._title_1d4e6_82{font-size:var(--pharos-font-size-lg);font-weight:var(--pharos-font-weight-semibold);color:var(--pharos-color-neutral-900);margin:0;line-height:1.4}._description_1d4e6_90{font-size:var(--pharos-font-size-sm);color:var(--pharos-color-neutral-600);margin:0;line-height:1.5}._footer_1d4e6_97{gap:var(--pharos-spacing-2);justify-content:flex-end;margin-top:auto;display:flex}._positioner_e7uyk_9{z-index:var(--pharos-z-index-popover)}._content_e7uyk_4{box-sizing:border-box;min-width:12rem;padding:var(--pharos-spacing-1);background-color:var(--pharos-color-base-white);border:1px solid var(--pharos-color-neutral-200);border-radius:var(--pharos-radius-md);box-shadow:var(--pharos-shadow-lg);font-family:var(--pharos-font-family-sans);color:var(--pharos-color-neutral-900);transform-origin:var(--transform-origin);transition-property:opacity,transform;transition-duration:var(--pharos-duration-fast);transition-timing-function:var(--pharos-easing-out)}._content_e7uyk_4[data-starting-style],._content_e7uyk_4[data-ending-style]{opacity:0;transform:scale(.96)}._item_e7uyk_5{box-sizing:border-box;align-items:center;gap:var(--pharos-spacing-2);width:100%;padding:var(--pharos-spacing-1-5) var(--pharos-spacing-2);border-radius:var(--pharos-radius-sm);font-size:var(--pharos-font-size-sm);font-weight:var(--pharos-font-weight-medium);color:var(--pharos-color-neutral-700);cursor:default;-webkit-user-select:none;user-select:none;scroll-margin:var(--pharos-spacing-1);transition-property:background-color,color;transition-duration:var(--pharos-duration-fast);transition-timing-function:var(--pharos-easing-out);outline:none;line-height:1.25;display:flex}._item_e7uyk_5[data-highlighted]{background-color:var(--pharos-color-neutral-100);color:var(--pharos-color-neutral-900)}._item_e7uyk_5[data-disabled]{color:var(--pharos-color-neutral-500);opacity:.6;pointer-events:none}._item_e7uyk_5>svg{flex-shrink:0;width:1rem;height:1rem}._itemDestructive_e7uyk_113{color:var(--pharos-color-semantic-error-fg)}._itemDestructive_e7uyk_113[data-highlighted]{background-color:var(--pharos-color-semantic-error-bg);color:var(--pharos-color-semantic-error-fg-hover)}._separator_e7uyk_6{height:1px;margin:var(--pharos-spacing-1) calc(var(--pharos-spacing-1) * -1);background-color:var(--pharos-color-neutral-200)}._label_e7uyk_6{padding:var(--pharos-spacing-1-5) var(--pharos-spacing-2);font-size:var(--pharos-font-size-sm);font-weight:var(--pharos-font-weight-semibold);color:var(--pharos-color-neutral-500)}._button_m4r6t_14{appearance:none;box-sizing:border-box;border-radius:var(--pharos-radius-full);-webkit-user-select:none;user-select:none;cursor:pointer;color:inherit;font-family:var(--pharos-font-family-sans);transition-property:color,background-color,border-color,box-shadow;transition-duration:var(--pharos-duration-normal);transition-timing-function:var(--pharos-easing-out);background-color:#0000;border:0 solid #0000;flex-shrink:0;justify-content:center;align-items:center;margin:0;padding:0;display:inline-flex}._button_m4r6t_14:focus-visible{box-shadow:0 0 0 2px var(--pharos-color-base-white), 0 0 0 4px var(--icon-button-focus-ring,var(--pharos-color-primary-600));outline:none}._button_m4r6t_14:disabled{pointer-events:none;cursor:not-allowed;opacity:.5}._button_m4r6t_14[aria-disabled=true]{cursor:not-allowed;opacity:.5}._primary_m4r6t_89{background-color:var(--pharos-color-primary-600);color:var(--pharos-color-base-white);--icon-button-focus-ring:var(--pharos-color-primary-600)}._primary_m4r6t_89:hover:not([aria-disabled=true]){background-color:var(--pharos-color-primary-700)}._primary_m4r6t_89:active:not([aria-disabled=true]){background-color:var(--pharos-color-primary-800)}._secondary_m4r6t_103{background-color:var(--pharos-color-base-white);color:var(--pharos-color-neutral-900);border:1px solid var(--pharos-color-neutral-500);--icon-button-focus-ring:var(--pharos-color-primary-600)}._secondary_m4r6t_103:hover:not([aria-disabled=true]){background-color:var(--pharos-color-neutral-50)}._secondary_m4r6t_103:active:not([aria-disabled=true]){background-color:var(--pharos-color-neutral-100)}._ghost_m4r6t_122{color:var(--pharos-color-neutral-900);--icon-button-focus-ring:var(--pharos-color-primary-600);background-color:#0000}._ghost_m4r6t_122:hover:not([aria-disabled=true]){background-color:var(--pharos-color-neutral-100)}._ghost_m4r6t_122:active:not([aria-disabled=true]){background-color:var(--pharos-color-neutral-200)}._destructive_m4r6t_136{background-color:var(--pharos-color-semantic-error-fg);color:var(--pharos-color-semantic-error-on);--icon-button-focus-ring:var(--pharos-color-semantic-error-fg)}._destructive_m4r6t_136:hover:not([aria-disabled=true]){background-color:var(--pharos-color-semantic-error-fg-hover)}._destructive_m4r6t_136:active:not([aria-disabled=true]){background-color:var(--pharos-color-semantic-error-fg-active)}._sizeSm_m4r6t_165{width:var(--pharos-spacing-8);height:var(--pharos-spacing-8)}._sizeSm_m4r6t_165>svg{width:var(--pharos-spacing-4);height:var(--pharos-spacing-4)}._sizeMd_m4r6t_175{width:var(--pharos-spacing-10);height:var(--pharos-spacing-10)}._sizeMd_m4r6t_175>svg{width:var(--pharos-spacing-5);height:var(--pharos-spacing-5)}._sizeLg_m4r6t_185{width:var(--pharos-spacing-12);height:var(--pharos-spacing-12)}._sizeLg_m4r6t_185>svg{width:var(--pharos-spacing-6);height:var(--pharos-spacing-6)}@keyframes _pharos-spinner-spin_gg970_1{0%{transform:rotate(0)}to{transform:rotate(360deg)}}._spinner_gg970_28{color:currentColor;vertical-align:middle;justify-content:center;align-items:center;display:inline-flex}._icon_gg970_46{width:100%;height:100%;animation:_pharos-spinner-spin_gg970_1 var(--pharos-duration-slow,1s) linear infinite}@media (prefers-reduced-motion:reduce){._icon_gg970_46{animation-duration:4s}}._sizeSm_gg970_69{width:var(--pharos-spacing-4);height:var(--pharos-spacing-4)}._sizeMd_gg970_74{width:var(--pharos-spacing-5);height:var(--pharos-spacing-5)}._sizeLg_gg970_79{width:var(--pharos-spacing-6);height:var(--pharos-spacing-6)}._srOnly_gg970_87{clip:rect(0, 0, 0, 0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}._input_1ueoc_14{appearance:none;box-sizing:border-box;border:1px solid var(--pharos-color-neutral-500);border-radius:var(--pharos-radius-md);background-color:var(--pharos-color-base-white);width:100%;color:var(--pharos-color-neutral-900);font-family:var(--pharos-font-family-sans);font-size:var(--pharos-font-size-sm);font-weight:var(--pharos-font-weight-regular);transition-property:border-color,box-shadow;transition-duration:var(--pharos-duration-normal);transition-timing-function:var(--pharos-easing-out);margin:0;line-height:1.25}._input_1ueoc_14::placeholder{color:var(--pharos-color-neutral-500);opacity:1}._input_1ueoc_14:focus-visible{border-color:var(--pharos-color-primary-600);box-shadow:0 0 0 2px var(--pharos-color-base-white), 0 0 0 4px var(--pharos-color-primary-600);outline:none}._input_1ueoc_14:disabled{cursor:not-allowed;opacity:.5}._input_1ueoc_14[aria-invalid=true]{border-color:var(--pharos-color-semantic-error-fg)}._input_1ueoc_14[aria-invalid=true]:focus-visible{border-color:var(--pharos-color-semantic-error-fg);box-shadow:0 0 0 2px var(--pharos-color-base-white), 0 0 0 4px var(--pharos-color-semantic-error-fg)}._sizeSm_1ueoc_97{height:var(--pharos-spacing-8);padding:0 var(--pharos-spacing-3);font-size:var(--pharos-font-size-sm)}._sizeMd_1ueoc_103{height:var(--pharos-spacing-10);padding:0 var(--pharos-spacing-4);font-size:var(--pharos-font-size-sm)}._sizeLg_1ueoc_109{height:var(--pharos-spacing-12);padding:0 var(--pharos-spacing-6);font-size:var(--pharos-font-size-base)}@media (pointer:coarse){._input_1ueoc_14,._sizeSm_1ueoc_97,._sizeMd_1ueoc_103{font-size:var(--pharos-font-size-base)}}._positioner_l8xbr_15{z-index:var(--pharos-z-index-popover)}._content_l8xbr_4{box-sizing:border-box;max-width:20rem;padding:var(--pharos-spacing-4);background-color:var(--pharos-color-base-white);border:1px solid var(--pharos-color-neutral-200);border-radius:var(--pharos-radius-md);box-shadow:var(--pharos-shadow-lg);font-family:var(--pharos-font-family-sans);font-size:var(--pharos-font-size-sm);color:var(--pharos-color-neutral-900);transform-origin:var(--transform-origin);transition-property:opacity,transform;transition-duration:var(--pharos-duration-fast);transition-timing-function:var(--pharos-easing-out);outline:none}._content_l8xbr_4[data-starting-style],._content_l8xbr_4[data-ending-style]{opacity:0;transform:scale(.96)}._title_l8xbr_5{font-size:var(--pharos-font-size-base);font-weight:var(--pharos-font-weight-semibold);color:var(--pharos-color-neutral-900);margin:0;line-height:1.4}._description_l8xbr_5{margin:var(--pharos-spacing-1) 0 0;font-size:var(--pharos-font-size-sm);color:var(--pharos-color-neutral-600);line-height:1.5}._group_rsllu_18{gap:var(--pharos-spacing-2);flex-direction:column;display:flex}._item_rsllu_24{box-sizing:border-box;width:var(--pharos-spacing-5);height:var(--pharos-spacing-5);border:1px solid var(--pharos-color-neutral-500);border-radius:var(--pharos-radius-full);background-color:var(--pharos-color-base-white);cursor:pointer;transition-property:background-color,border-color,box-shadow;transition-duration:var(--pharos-duration-fast);transition-timing-function:var(--pharos-easing-out);flex-shrink:0;justify-content:center;align-items:center;padding:0;display:inline-flex}._item_rsllu_24:hover:not([data-disabled]):not([data-checked]){border-color:var(--pharos-color-neutral-700)}._item_rsllu_24[data-checked]{border-color:var(--pharos-color-neutral-900)}._group_rsllu_18[aria-invalid=true] ._item_rsllu_24{border-color:var(--pharos-color-semantic-error-fg)}._item_rsllu_24:focus-visible{box-shadow:0 0 0 2px var(--pharos-color-base-white), 0 0 0 4px var(--pharos-color-primary-600);outline:none}._item_rsllu_24[data-disabled]{cursor:not-allowed;opacity:.5}._indicator_rsllu_75{width:var(--pharos-spacing-2);height:var(--pharos-spacing-2);border-radius:var(--pharos-radius-full);background-color:var(--pharos-color-neutral-900);display:inline-flex}._trigger_g5qz6_35{appearance:none;box-sizing:border-box;justify-content:space-between;align-items:center;gap:var(--pharos-spacing-2);border:1px solid var(--pharos-color-neutral-500);border-radius:var(--pharos-radius-md);background-color:var(--pharos-color-base-white);width:100%;color:var(--pharos-color-neutral-900);font-family:var(--pharos-font-family-sans);font-size:var(--pharos-font-size-sm);font-weight:var(--pharos-font-weight-regular);text-align:start;cursor:default;transition-property:border-color,box-shadow;transition-duration:var(--pharos-duration-normal);transition-timing-function:var(--pharos-easing-out);margin:0;line-height:1.25;display:inline-flex}._trigger_g5qz6_35:focus-visible{border-color:var(--pharos-color-primary-600);box-shadow:0 0 0 2px var(--pharos-color-base-white), 0 0 0 4px var(--pharos-color-primary-600);outline:none}._trigger_g5qz6_35:disabled,._trigger_g5qz6_35[data-disabled]{cursor:not-allowed;opacity:.5}._trigger_g5qz6_35[aria-invalid=true]{border-color:var(--pharos-color-semantic-error-fg)}._trigger_g5qz6_35[aria-invalid=true]:focus-visible{border-color:var(--pharos-color-semantic-error-fg);box-shadow:0 0 0 2px var(--pharos-color-base-white), 0 0 0 4px var(--pharos-color-semantic-error-fg)}._sizeSm_g5qz6_92{height:var(--pharos-spacing-8);padding:0 var(--pharos-spacing-3);font-size:var(--pharos-font-size-sm)}._sizeMd_g5qz6_98{height:var(--pharos-spacing-10);padding:0 var(--pharos-spacing-4);font-size:var(--pharos-font-size-sm)}._sizeLg_g5qz6_104{height:var(--pharos-spacing-12);padding:0 var(--pharos-spacing-6);font-size:var(--pharos-font-size-base)}._value_g5qz6_113{text-overflow:ellipsis;white-space:nowrap;flex:auto;min-width:0;overflow:hidden}._value_g5qz6_113[data-placeholder]{color:var(--pharos-color-neutral-500)}._icon_g5qz6_127{color:var(--pharos-color-neutral-500);transition:transform var(--pharos-duration-fast) var(--pharos-easing-out);flex:none;justify-content:center;align-items:center;display:inline-flex}._icon_g5qz6_127 svg{width:1rem;height:1rem}._icon_g5qz6_127[data-popup-open]{transform:rotate(180deg)}._positioner_g5qz6_24{z-index:var(--pharos-z-index-popover)}._content_g5qz6_146{box-sizing:border-box;width:var(--anchor-width);max-height:var(--available-height);padding:var(--pharos-spacing-1);background-color:var(--pharos-color-base-white);border:1px solid var(--pharos-color-neutral-200);border-radius:var(--pharos-radius-md);box-shadow:var(--pharos-shadow-lg);font-family:var(--pharos-font-family-sans);font-size:var(--pharos-font-size-sm);color:var(--pharos-color-neutral-900);transform-origin:var(--transform-origin);transition-property:opacity,transform;transition-duration:var(--pharos-duration-fast);transition-timing-function:var(--pharos-easing-out);outline:none;overflow-y:auto}._content_g5qz6_146[data-starting-style],._content_g5qz6_146[data-ending-style]{opacity:0;transform:scale(.96)}._item_g5qz6_17{align-items:flex-start;gap:var(--pharos-spacing-2);padding:var(--pharos-spacing-2) var(--pharos-spacing-3);border-radius:var(--pharos-radius-sm);color:var(--pharos-color-neutral-900);cursor:default;-webkit-user-select:none;user-select:none;scroll-margin:var(--pharos-spacing-1);outline:none;display:flex;position:relative}._item_g5qz6_17[data-highlighted]{background-color:var(--pharos-color-neutral-100)}._item_g5qz6_17[data-disabled]{color:var(--pharos-color-neutral-400);pointer-events:none}._itemText_g5qz6_17{overflow-wrap:anywhere;white-space:normal;flex:auto;min-width:0}._itemIndicator_g5qz6_230{block-size:1lh;color:var(--pharos-color-primary-600);flex:none;justify-content:center;align-items:center;display:inline-flex}._itemIndicator_g5qz6_230 svg{width:1rem;height:1rem}._label_g5qz6_246{padding:var(--pharos-spacing-2) var(--pharos-spacing-3) var(--pharos-spacing-1);font-size:var(--pharos-font-size-xs);font-weight:var(--pharos-font-weight-semibold);color:var(--pharos-color-neutral-600)}._separator_g5qz6_254{height:1px;margin:var(--pharos-spacing-1) 0;background-color:var(--pharos-color-neutral-200)}._separator_da90p_13{background-color:var(--pharos-color-neutral-200);border:0;flex-shrink:0;margin:0}._horizontal_da90p_29{width:100%;height:1px}._vertical_da90p_34{width:1px;height:100%}._backdrop_1jbnh_17{z-index:var(--pharos-z-index-modal);background-color:color-mix(in srgb, var(--pharos-color-base-black) 50%, transparent);transition:opacity var(--pharos-duration-normal) var(--pharos-easing-out);position:fixed;inset:0}._backdrop_1jbnh_17[data-starting-style],._backdrop_1jbnh_17[data-ending-style]{opacity:0}._content_1jbnh_33{z-index:var(--pharos-z-index-modal);box-sizing:border-box;gap:var(--pharos-spacing-4);padding:var(--pharos-spacing-6);background-color:var(--pharos-color-base-white);box-shadow:var(--pharos-shadow-xl);font-family:var(--pharos-font-family-sans);font-size:var(--pharos-font-size-sm);color:var(--pharos-color-neutral-900);transition:transform var(--pharos-duration-normal) var(--pharos-easing-out);outline:none;flex-direction:column;display:flex;position:fixed;overflow-y:auto}._sideRight_1jbnh_56{border-left:1px solid var(--pharos-color-neutral-200);width:min(24rem,100vw);height:100dvh;top:0;bottom:0;right:0}._sideRight_1jbnh_56[data-starting-style],._sideRight_1jbnh_56[data-ending-style]{transform:translate(100%)}._sideLeft_1jbnh_69{border-right:1px solid var(--pharos-color-neutral-200);width:min(24rem,100vw);height:100dvh;top:0;bottom:0;left:0}._sideLeft_1jbnh_69[data-starting-style],._sideLeft_1jbnh_69[data-ending-style]{transform:translate(-100%)}._sideTop_1jbnh_82{border-bottom:1px solid var(--pharos-color-neutral-200);width:100vw;max-height:100dvh;top:0;left:0;right:0}._sideTop_1jbnh_82[data-starting-style],._sideTop_1jbnh_82[data-ending-style]{transform:translateY(-100%)}._sideBottom_1jbnh_95{border-top:1px solid var(--pharos-color-neutral-200);width:100vw;max-height:100dvh;bottom:0;left:0;right:0}._sideBottom_1jbnh_95[data-starting-style],._sideBottom_1jbnh_95[data-ending-style]{transform:translateY(100%)}._header_1jbnh_109{gap:var(--pharos-spacing-1);flex-direction:column;display:flex}._title_1jbnh_115{font-size:var(--pharos-font-size-lg);font-weight:var(--pharos-font-weight-semibold);color:var(--pharos-color-neutral-900);margin:0;line-height:1.4}._description_1jbnh_123{font-size:var(--pharos-font-size-sm);color:var(--pharos-color-neutral-600);margin:0;line-height:1.5}._footer_1jbnh_130{gap:var(--pharos-spacing-2);justify-content:flex-end;margin-top:auto;display:flex}._root_5v2er_17{box-sizing:border-box;width:var(--pharos-spacing-10);height:var(--pharos-spacing-6);padding:var(--pharos-spacing-1);border-radius:var(--pharos-radius-full);background-color:var(--pharos-color-neutral-300);cursor:pointer;transition-property:background-color,box-shadow;transition-duration:var(--pharos-duration-fast);transition-timing-function:var(--pharos-easing-out);border:none;flex-shrink:0;align-items:center;display:inline-flex}._root_5v2er_17:hover:not([data-disabled]):not([data-checked]){background-color:var(--pharos-color-neutral-400)}._root_5v2er_17[data-checked]{background-color:var(--pharos-color-neutral-900)}._root_5v2er_17[data-checked]:hover:not([data-disabled]){background-color:var(--pharos-color-neutral-700)}._root_5v2er_17[aria-invalid=true]{box-shadow:inset 0 0 0 1px var(--pharos-color-semantic-error-fg)}._root_5v2er_17:focus-visible{box-shadow:0 0 0 2px var(--pharos-color-base-white), 0 0 0 4px var(--pharos-color-primary-600);outline:none}._root_5v2er_17[data-disabled]{cursor:not-allowed;opacity:.5}._thumb_5v2er_72{box-sizing:border-box;width:var(--pharos-spacing-4);height:var(--pharos-spacing-4);border:1px solid var(--pharos-color-neutral-500);border-radius:var(--pharos-radius-full);background-color:var(--pharos-color-base-white);transition-property:transform;transition-duration:var(--pharos-duration-fast);transition-timing-function:var(--pharos-easing-out)}._root_5v2er_17[data-checked] ._thumb_5v2er_72{transform:translateX(var(--pharos-spacing-4))}._textarea_145hb_21{appearance:none;box-sizing:border-box;border:1px solid var(--pharos-color-neutral-500);border-radius:var(--pharos-radius-md);background-color:var(--pharos-color-base-white);width:100%;color:var(--pharos-color-neutral-900);resize:vertical;font-family:var(--pharos-font-family-sans);font-size:var(--pharos-font-size-sm);font-weight:var(--pharos-font-weight-regular);transition-property:border-color,box-shadow;transition-duration:var(--pharos-duration-normal);transition-timing-function:var(--pharos-easing-out);margin:0;line-height:1.5}._textarea_145hb_21::placeholder{color:var(--pharos-color-neutral-500);opacity:1}._textarea_145hb_21:focus-visible{border-color:var(--pharos-color-primary-600);box-shadow:0 0 0 2px var(--pharos-color-base-white), 0 0 0 4px var(--pharos-color-primary-600);outline:none}._textarea_145hb_21:disabled{cursor:not-allowed;opacity:.5;resize:none}._textarea_145hb_21[aria-invalid=true]{border-color:var(--pharos-color-semantic-error-fg)}._textarea_145hb_21[aria-invalid=true]:focus-visible{border-color:var(--pharos-color-semantic-error-fg);box-shadow:0 0 0 2px var(--pharos-color-base-white), 0 0 0 4px var(--pharos-color-semantic-error-fg)}._sizeSm_145hb_113{min-height:var(--pharos-spacing-16);padding:var(--pharos-spacing-2) var(--pharos-spacing-3);font-size:var(--pharos-font-size-sm)}._sizeMd_145hb_119{min-height:var(--pharos-spacing-20);padding:var(--pharos-spacing-2-5) var(--pharos-spacing-4);font-size:var(--pharos-font-size-sm)}._sizeLg_145hb_125{min-height:var(--pharos-spacing-24);padding:var(--pharos-spacing-3) var(--pharos-spacing-6);font-size:var(--pharos-font-size-base)}@media (pointer:coarse){._textarea_145hb_21,._sizeSm_145hb_113,._sizeMd_145hb_119{font-size:var(--pharos-font-size-base)}}._viewport_1l5b5_17{--pharos-toast-edge-gap:var(--pharos-spacing-4);z-index:var(--pharos-z-index-toast);box-sizing:border-box;inline-size:min(22.5rem, calc(100% - 2 * var(--pharos-toast-edge-gap)));gap:var(--pharos-spacing-2);pointer-events:none;outline:none;flex-direction:column;display:flex;position:fixed}._viewport_1l5b5_17[data-pharos-position^=top]{inset-block-start:var(--pharos-toast-offset,var(--pharos-toast-edge-gap))}._viewport_1l5b5_17[data-pharos-position^=bottom]{flex-direction:column-reverse;inset-block-end:var(--pharos-toast-offset,var(--pharos-toast-edge-gap))}._viewport_1l5b5_17[data-pharos-position$=start]{inset-inline-start:var(--pharos-toast-edge-gap)}._viewport_1l5b5_17[data-pharos-position$=end]{inset-inline-end:var(--pharos-toast-edge-gap)}._viewport_1l5b5_17[data-pharos-position$=center]{margin-inline:auto;inset-inline:0}._toast_1l5b5_60{--pharos-toast-enter-shift:calc(-1 * var(--pharos-spacing-4));box-sizing:border-box;pointer-events:auto;background-color:var(--pharos-color-surface-card);border:1px solid var(--pharos-color-border-subtle);border-radius:var(--pharos-radius-lg);box-shadow:var(--pharos-shadow-lg);font-family:var(--pharos-font-family-sans);font-size:var(--pharos-font-size-sm);color:var(--pharos-color-neutral-900);transform:translate(var(--toast-swipe-movement-x,0), var(--toast-swipe-movement-y,0));transition-property:opacity,transform;transition-duration:var(--pharos-duration-normal);transition-timing-function:var(--pharos-easing-out);line-height:1.43}._viewport_1l5b5_17[data-pharos-position^=bottom] ._toast_1l5b5_60{--pharos-toast-enter-shift:var(--pharos-spacing-4)}._toast_1l5b5_60[data-starting-style],._toast_1l5b5_60[data-ending-style]{opacity:0;transform:translateY(var(--pharos-toast-enter-shift))}._toast_1l5b5_60[data-ending-style][data-swipe-direction=left]{transform:translateX(calc(var(--toast-swipe-movement-x,0) - 100%))}._toast_1l5b5_60[data-ending-style][data-swipe-direction=right]{transform:translateX(calc(var(--toast-swipe-movement-x,0) + 100%))}._toast_1l5b5_60[data-limited]{opacity:0}._toast_1l5b5_60:focus-visible{box-shadow:0 0 0 2px var(--pharos-color-base-white), 0 0 0 4px var(--pharos-color-primary-600), var(--pharos-shadow-lg);outline:none}@media (prefers-reduced-motion:reduce){._toast_1l5b5_60,._toast_1l5b5_60[data-starting-style],._toast_1l5b5_60[data-ending-style]{transition-property:opacity;transform:none}}._content_1l5b5_127{align-items:flex-start;gap:var(--pharos-spacing-3);padding-block:var(--pharos-spacing-3);padding-inline:var(--pharos-spacing-4) var(--pharos-spacing-2);display:flex}._icon_1l5b5_136{inline-size:var(--pharos-spacing-5);block-size:var(--pharos-spacing-5);flex-shrink:0}._text_1l5b5_142{gap:var(--pharos-spacing-0-5);overflow-wrap:anywhere;flex-direction:column;flex:1;min-inline-size:0;display:flex}._toast_1l5b5_60[data-pharos-variant=success] ._icon_1l5b5_136{color:var(--pharos-color-semantic-success-fg)}._toast_1l5b5_60[data-pharos-variant=info] ._icon_1l5b5_136{color:var(--pharos-color-semantic-info-fg)}._toast_1l5b5_60[data-pharos-variant=destructive] ._icon_1l5b5_136{color:var(--pharos-color-semantic-error-fg)}._toast_1l5b5_60[data-pharos-variant=warning] ._icon_1l5b5_136{color:var(--pharos-color-semantic-warning-on)}._warningFill_1l5b5_169{fill:var(--pharos-color-semantic-warning-fg);stroke:var(--pharos-color-semantic-warning-fg)}._title_1l5b5_176{font-size:var(--pharos-font-size-sm);line-height:inherit;font-weight:var(--pharos-font-weight-semibold);margin:0}._description_1l5b5_183{font-size:var(--pharos-font-size-sm);line-height:inherit;color:var(--pharos-color-neutral-600);margin:0}._action_1l5b5_190{align-self:flex-start;margin-block-start:var(--pharos-spacing-2)}._close_1l5b5_197{margin-block:calc(-1 * var(--pharos-spacing-1-5)) calc(-1 * var(--pharos-spacing-1-5));flex-shrink:0}
1
+ ._root_1xx27_21{box-sizing:border-box;background-color:var(--pharos-color-neutral-100);color:var(--pharos-color-neutral-700);font-family:var(--pharos-font-family-sans);-webkit-user-select:none;user-select:none;--pharos-avatar-overlap:calc(var(--pharos-spacing-2) * -1);flex-shrink:0;justify-content:center;align-items:center;font-weight:500;line-height:1;display:inline-flex;position:relative;overflow:hidden}._shapeCircle_1xx27_63{border-radius:var(--pharos-radius-full)}._shapeSquare_1xx27_67{border-radius:var(--pharos-radius-md)}._sizeSm_1xx27_86{width:var(--pharos-spacing-8);height:var(--pharos-spacing-8);--pharos-avatar-overlap:calc(var(--pharos-spacing-2) * -.75);font-size:.75rem}._sizeMd_1xx27_93{width:var(--pharos-spacing-10);height:var(--pharos-spacing-10);--pharos-avatar-overlap:calc(var(--pharos-spacing-2) * -1);font-size:.875rem}._sizeLg_1xx27_100{width:var(--pharos-spacing-12);height:var(--pharos-spacing-12);--pharos-avatar-overlap:calc(var(--pharos-spacing-2) * -1.25);font-size:1rem}._image_1xx27_118{object-fit:cover;border-radius:inherit;width:100%;height:100%;display:block;position:absolute;inset:0}._fallback_1xx27_134{text-align:center;width:100%;height:100%;font:inherit;color:inherit;justify-content:center;align-items:center;display:inline-flex}._sizeSm_1xx27_86 ._fallback_1xx27_134>svg{width:var(--pharos-spacing-5);height:var(--pharos-spacing-5)}._sizeMd_1xx27_93 ._fallback_1xx27_134>svg{width:var(--pharos-spacing-6);height:var(--pharos-spacing-6)}._sizeLg_1xx27_100 ._fallback_1xx27_134>svg{width:var(--pharos-spacing-7);height:var(--pharos-spacing-7)}._group_1xx27_175{align-items:center;display:inline-flex}._group_1xx27_175>._root_1xx27_21{box-shadow:0 0 0 2px var(--pharos-avatar-group-ring,var(--pharos-color-base-white));position:relative}._group_1xx27_175>._root_1xx27_21+._root_1xx27_21{margin-left:var(--pharos-avatar-overlap)}._badge_5pviu_5{align-items:center;gap:var(--pharos-spacing-1);padding:0 var(--pharos-spacing-2);height:var(--pharos-spacing-5);border-radius:var(--pharos-radius-full);font-family:var(--pharos-font-family-sans);font-size:var(--pharos-font-size-xs);font-weight:var(--pharos-font-weight-medium);white-space:nowrap;text-box-trim:trim-both;text-box-edge:cap alphabetic;border:1px solid #0000;width:fit-content;line-height:1;display:inline-flex}._badge_5pviu_5>svg{pointer-events:none;flex:none;width:.75em;height:.75em}._default_5pviu_30{background:var(--pharos-color-neutral-900);color:var(--pharos-color-base-white)}._secondary_5pviu_35{background:var(--pharos-color-neutral-100);color:var(--pharos-color-neutral-900)}._destructive_5pviu_40{background:var(--pharos-color-semantic-error-fg);color:var(--pharos-color-semantic-error-on)}._outline_5pviu_45{color:var(--pharos-color-neutral-900);border-color:var(--pharos-color-neutral-500);background:0 0}._success_5pviu_55{background:var(--pharos-color-semantic-success-fg);color:var(--pharos-color-semantic-success-on)}._warning_5pviu_60{background:var(--pharos-color-semantic-warning-fg);color:var(--pharos-color-semantic-warning-on)}._info_5pviu_65{background:var(--pharos-color-semantic-info-fg);color:var(--pharos-color-semantic-info-on)}._accent_5pviu_73{background:var(--pharos-color-accent-terracotta-700);color:var(--pharos-color-base-white)}._accentSoft_5pviu_80{background:var(--pharos-color-accent-terracotta-50);color:var(--pharos-color-accent-terracotta-700)}._button_1g7u9_18{appearance:none;box-sizing:border-box;border-radius:var(--pharos-radius-full);white-space:nowrap;text-box-trim:trim-both;text-box-edge:cap alphabetic;font-family:var(--pharos-font-family-sans);font-style:normal;font-weight:var(--pharos-font-weight-medium);font-variant:normal;font-kerning:auto;font-optical-sizing:auto;font-size-adjust:none;font-feature-settings:normal;font-variation-settings:normal;letter-spacing:normal;text-transform:none;font-stretch:100%;font-size:var(--pharos-font-size-sm);-webkit-user-select:none;user-select:none;cursor:pointer;color:inherit;transition-property:color,background-color,border-color,box-shadow;transition-duration:var(--pharos-duration-normal);transition-timing-function:var(--pharos-easing-out);background-color:#0000;border:0 solid #0000;justify-content:center;align-items:center;margin:0;padding-top:0;padding-bottom:0;line-height:1.5;text-decoration:none;display:inline-flex}._button_1g7u9_18:focus-visible{box-shadow:0 0 0 2px var(--pharos-color-base-white), 0 0 0 4px var(--button-focus-ring,var(--pharos-color-primary-600));outline:none}._button_1g7u9_18:disabled{pointer-events:none;cursor:not-allowed;opacity:.5}._button_1g7u9_18[aria-disabled=true]{cursor:not-allowed;opacity:.5}._primary_1g7u9_142{background-color:var(--pharos-color-primary-600);color:var(--pharos-color-base-white);--button-focus-ring:var(--pharos-color-primary-600)}._primary_1g7u9_142:hover:not([aria-disabled=true]){background-color:var(--pharos-color-primary-700)}._primary_1g7u9_142:active:not([aria-disabled=true]){background-color:var(--pharos-color-primary-800)}._secondary_1g7u9_156{background-color:var(--pharos-color-base-white);color:var(--pharos-color-neutral-900);border:1px solid var(--pharos-color-neutral-500);--button-focus-ring:var(--pharos-color-primary-600)}._secondary_1g7u9_156:hover:not([aria-disabled=true]){background-color:var(--pharos-color-neutral-50)}._secondary_1g7u9_156:active:not([aria-disabled=true]){background-color:var(--pharos-color-neutral-100)}._ghost_1g7u9_176{color:var(--pharos-color-neutral-900);--button-focus-ring:var(--pharos-color-primary-600);background-color:#0000}._ghost_1g7u9_176:hover:not([aria-disabled=true]){background-color:var(--pharos-color-neutral-100)}._ghost_1g7u9_176:active:not([aria-disabled=true]){background-color:var(--pharos-color-neutral-200)}._destructive_1g7u9_190{background-color:var(--pharos-color-semantic-error-fg);color:var(--pharos-color-semantic-error-on);--button-focus-ring:var(--pharos-color-semantic-error-fg)}._destructive_1g7u9_190:hover:not([aria-disabled=true]){background-color:var(--pharos-color-semantic-error-fg-hover)}._destructive_1g7u9_190:active:not([aria-disabled=true]){background-color:var(--pharos-color-semantic-error-fg-active)}._sizeSm_1g7u9_212{height:var(--pharos-spacing-8);gap:var(--pharos-spacing-1-5);padding:0 var(--pharos-spacing-3);font-size:var(--pharos-font-size-sm);line-height:1.42857}._sizeMd_1g7u9_220{height:var(--pharos-spacing-10);gap:var(--pharos-spacing-2);padding:0 var(--pharos-spacing-4);font-size:var(--pharos-font-size-sm);line-height:1.42857}._sizeLg_1g7u9_228{height:var(--pharos-spacing-12);gap:var(--pharos-spacing-2);padding:0 var(--pharos-spacing-6);font-size:var(--pharos-font-size-base);line-height:1.5}._card_yxgwa_10{background-color:var(--pharos-color-base-white);border-radius:var(--pharos-radius-2xl);gap:var(--pharos-spacing-6);font-family:var(--pharos-font-family-sans);color:var(--pharos-color-neutral-900);transition-property:border-color,box-shadow;transition-duration:var(--pharos-duration-normal);transition-timing-function:var(--pharos-easing-out);border:0 solid #0000;flex-direction:column;display:flex}._default_yxgwa_42{border:1px solid var(--pharos-color-neutral-200)}._elevated_yxgwa_46{box-shadow:var(--pharos-shadow-md);border:0 solid #0000}._outlined_yxgwa_51{border:1px solid var(--pharos-color-neutral-300)}._header_yxgwa_62{gap:var(--pharos-spacing-1-5);padding:var(--pharos-spacing-6) var(--pharos-spacing-6) 0;flex-direction:column;display:flex}._title_yxgwa_69{font-size:var(--pharos-font-size-base);font-weight:var(--pharos-font-weight-semibold);color:var(--pharos-color-neutral-900);margin:0;line-height:1.25}._description_yxgwa_77{font-size:var(--pharos-font-size-sm);font-weight:var(--pharos-font-weight-regular);color:var(--pharos-color-neutral-500);margin:0;line-height:1.5}._content_yxgwa_85{padding:0 var(--pharos-spacing-6)}._footer_yxgwa_95{align-items:center;gap:var(--pharos-spacing-3);padding:0 var(--pharos-spacing-6) var(--pharos-spacing-6);display:flex}._root_1v9tz_14{box-sizing:border-box;width:var(--pharos-spacing-5);height:var(--pharos-spacing-5);border:1px solid var(--pharos-color-neutral-500);border-radius:var(--pharos-radius-sm);background-color:var(--pharos-color-base-white);color:var(--pharos-color-base-white);cursor:pointer;transition-property:background-color,border-color,box-shadow;transition-duration:var(--pharos-duration-fast);transition-timing-function:var(--pharos-easing-out);flex-shrink:0;justify-content:center;align-items:center;padding:0;display:inline-flex}._root_1v9tz_14:hover:not([data-disabled]):not([data-checked]):not([data-indeterminate]){border-color:var(--pharos-color-neutral-700)}._root_1v9tz_14[data-checked],._root_1v9tz_14[data-indeterminate]{background-color:var(--pharos-color-neutral-900);border-color:var(--pharos-color-neutral-900)}._root_1v9tz_14[aria-invalid=true]{border-color:var(--pharos-color-semantic-error-fg)}._root_1v9tz_14:focus-visible{box-shadow:0 0 0 2px var(--pharos-color-base-white), 0 0 0 4px var(--pharos-color-primary-600);outline:none}._root_1v9tz_14[data-disabled]{cursor:not-allowed;opacity:.5}._indicator_1v9tz_65{color:var(--pharos-color-base-white);justify-content:center;align-items:center;display:inline-flex}._icon_1v9tz_72{width:var(--pharos-spacing-3);height:var(--pharos-spacing-3)}._iconIndeterminate_1v9tz_79,._indicator_1v9tz_65[data-indeterminate] ._iconCheck_1v9tz_83{display:none}._indicator_1v9tz_65[data-indeterminate] ._iconIndeterminate_1v9tz_79{display:block}._control_12m6b_5{box-sizing:border-box;align-items:center;gap:var(--pharos-spacing-2);border:1px solid var(--pharos-color-neutral-500);border-radius:var(--pharos-radius-md);background-color:var(--pharos-color-base-white);width:100%;font-family:var(--pharos-font-family-sans);transition-property:border-color,box-shadow;transition-duration:var(--pharos-duration-normal);transition-timing-function:var(--pharos-easing-out);display:flex}._control_12m6b_5:focus-within{border-color:var(--pharos-color-primary-600);box-shadow:0 0 0 2px var(--pharos-color-base-white), 0 0 0 4px var(--pharos-color-primary-600)}._control_12m6b_5[aria-invalid=true]{border-color:var(--pharos-color-semantic-error-fg)}._control_12m6b_5:has([aria-invalid=true]){border-color:var(--pharos-color-semantic-error-fg)}._control_12m6b_5[data-disabled]{opacity:.5;cursor:not-allowed}._control_12m6b_5:has(._input_12m6b_66:disabled){opacity:.5;cursor:not-allowed}._chips_12m6b_72{gap:var(--pharos-spacing-1);padding:var(--pharos-spacing-1) var(--pharos-spacing-2);flex-wrap:wrap}._input_12m6b_66{appearance:none;min-width:0;color:var(--pharos-color-neutral-900);font-family:var(--pharos-font-family-sans);font-size:var(--pharos-font-size-sm);font-weight:var(--pharos-font-weight-regular);background:0 0;border:none;outline:none;flex:auto;margin:0;line-height:1.25}._input_12m6b_66::placeholder{color:var(--pharos-color-neutral-500);opacity:1}._input_12m6b_66:disabled{cursor:not-allowed}._inputSizeSm_12m6b_110{height:var(--pharos-spacing-8);padding:0 var(--pharos-spacing-3)}._inputSizeMd_12m6b_115{height:var(--pharos-spacing-10);padding:0 var(--pharos-spacing-4)}._inputSizeLg_12m6b_120{height:var(--pharos-spacing-12);padding:0 var(--pharos-spacing-6);font-size:var(--pharos-font-size-base)}._chipsInput_12m6b_128{height:var(--pharos-spacing-7);padding:0 var(--pharos-spacing-1);flex:4rem}._trigger_12m6b_135,._clear_12m6b_136{width:var(--pharos-spacing-6);height:var(--pharos-spacing-6);color:var(--pharos-color-neutral-500);cursor:default;background:0 0;border:none;flex:none;justify-content:center;align-items:center;margin-inline-end:var(--pharos-spacing-1);padding:0;display:inline-flex}._trigger_12m6b_135 svg,._clear_12m6b_136 svg{width:1rem;height:1rem}._trigger_12m6b_135[data-popup-open] svg{transition:transform var(--pharos-duration-fast) var(--pharos-easing-out);transform:rotate(180deg)}._chip_12m6b_72{align-items:center;gap:var(--pharos-spacing-1);padding:0 var(--pharos-spacing-1) 0 var(--pharos-spacing-2);height:var(--pharos-spacing-6);border-radius:var(--pharos-radius-sm);background-color:var(--pharos-color-neutral-100);color:var(--pharos-color-neutral-900);font-size:var(--pharos-font-size-xs);display:inline-flex}._chip_12m6b_72[data-highlighted]{background-color:var(--pharos-color-neutral-200)}._chipRemove_12m6b_180{width:var(--pharos-spacing-4);height:var(--pharos-spacing-4);border-radius:var(--pharos-radius-sm);color:var(--pharos-color-neutral-500);cursor:default;background:0 0;border:none;justify-content:center;align-items:center;padding:0;display:inline-flex}._chipRemove_12m6b_180:hover{color:var(--pharos-color-neutral-900)}._trigger_12m6b_135[data-disabled],._clear_12m6b_136[data-disabled],._chipRemove_12m6b_180[data-disabled]{cursor:not-allowed}._chipRemove_12m6b_180[data-disabled]:hover{color:var(--pharos-color-neutral-500)}._chipRemove_12m6b_180 svg{width:.875rem;height:.875rem}._positioner_12m6b_227{z-index:var(--pharos-z-index-popover)}._content_12m6b_217{box-sizing:border-box;width:var(--anchor-width);max-height:var(--available-height);padding:var(--pharos-spacing-1);background-color:var(--pharos-color-base-white);border:1px solid var(--pharos-color-neutral-200);border-radius:var(--pharos-radius-md);box-shadow:var(--pharos-shadow-lg);font-family:var(--pharos-font-family-sans);font-size:var(--pharos-font-size-sm);color:var(--pharos-color-neutral-900);transform-origin:var(--transform-origin);transition-property:opacity,transform;transition-duration:var(--pharos-duration-fast);transition-timing-function:var(--pharos-easing-out);outline:none;overflow-y:auto}._content_12m6b_217[data-starting-style],._content_12m6b_217[data-ending-style]{opacity:0;transform:scale(.96)}._item_12m6b_14{align-items:flex-start;gap:var(--pharos-spacing-2);padding:var(--pharos-spacing-2) var(--pharos-spacing-3);border-radius:var(--pharos-radius-sm);color:var(--pharos-color-neutral-900);cursor:default;-webkit-user-select:none;user-select:none;scroll-margin:var(--pharos-spacing-1);outline:none;display:flex;position:relative}._item_12m6b_14[data-highlighted]{background-color:var(--pharos-color-neutral-100)}._item_12m6b_14[data-disabled]{color:var(--pharos-color-neutral-400);pointer-events:none}._itemText_12m6b_14{overflow-wrap:anywhere;white-space:normal;flex:auto;min-width:0}._itemIndicator_12m6b_298{block-size:1lh;color:var(--pharos-color-primary-600);flex:none;justify-content:center;align-items:center;display:inline-flex}._itemIndicator_12m6b_298 svg{width:1rem;height:1rem}._empty_12m6b_322{color:var(--pharos-color-neutral-500);text-align:center}._empty_12m6b_322:not(:empty){padding:var(--pharos-spacing-3)}._label_12m6b_332{padding:var(--pharos-spacing-2) var(--pharos-spacing-3) var(--pharos-spacing-1);font-size:var(--pharos-font-size-xs);font-weight:var(--pharos-font-weight-semibold);color:var(--pharos-color-neutral-600)}._separator_12m6b_339{height:1px;margin:var(--pharos-spacing-1) 0;background-color:var(--pharos-color-neutral-200)}@media (pointer:coarse){._input_12m6b_66{font-size:var(--pharos-font-size-base)}}._backdrop_1d4e6_19{z-index:var(--pharos-z-index-modal);background-color:color-mix(in srgb, var(--pharos-color-base-black) 50%, transparent);transition:opacity var(--pharos-duration-normal) var(--pharos-easing-out);position:fixed;inset:0}._backdrop_1d4e6_19[data-starting-style],._backdrop_1d4e6_19[data-ending-style]{opacity:0}._content_1d4e6_33{transform-origin:50%;z-index:var(--pharos-z-index-modal);box-sizing:border-box;width:calc(100% - 2 * var(--pharos-spacing-4));max-width:32rem;max-height:calc(100dvh - 2 * var(--pharos-spacing-6));gap:var(--pharos-spacing-4);padding:var(--pharos-spacing-6);background-color:var(--pharos-color-base-white);border-radius:var(--pharos-radius-lg);box-shadow:var(--pharos-shadow-xl);font-family:var(--pharos-font-family-sans);font-size:var(--pharos-font-size-sm);color:var(--pharos-color-neutral-900);transition-property:opacity,transform;transition-duration:var(--pharos-duration-fast);transition-timing-function:var(--pharos-easing-out);outline:none;flex-direction:column;display:flex;position:fixed;top:50%;left:50%;overflow-y:auto;transform:translate(-50%,-50%)}._content_1d4e6_33[data-starting-style],._content_1d4e6_33[data-ending-style]{opacity:0;transform:translate(-50%,-50%)scale(.96)}._header_1d4e6_76{gap:var(--pharos-spacing-1);flex-direction:column;display:flex}._title_1d4e6_82{font-size:var(--pharos-font-size-lg);font-weight:var(--pharos-font-weight-semibold);color:var(--pharos-color-neutral-900);margin:0;line-height:1.4}._description_1d4e6_90{font-size:var(--pharos-font-size-sm);color:var(--pharos-color-neutral-600);margin:0;line-height:1.5}._footer_1d4e6_97{gap:var(--pharos-spacing-2);justify-content:flex-end;margin-top:auto;display:flex}._positioner_e7uyk_9{z-index:var(--pharos-z-index-popover)}._content_e7uyk_4{box-sizing:border-box;min-width:12rem;padding:var(--pharos-spacing-1);background-color:var(--pharos-color-base-white);border:1px solid var(--pharos-color-neutral-200);border-radius:var(--pharos-radius-md);box-shadow:var(--pharos-shadow-lg);font-family:var(--pharos-font-family-sans);color:var(--pharos-color-neutral-900);transform-origin:var(--transform-origin);transition-property:opacity,transform;transition-duration:var(--pharos-duration-fast);transition-timing-function:var(--pharos-easing-out)}._content_e7uyk_4[data-starting-style],._content_e7uyk_4[data-ending-style]{opacity:0;transform:scale(.96)}._item_e7uyk_5{box-sizing:border-box;align-items:center;gap:var(--pharos-spacing-2);width:100%;padding:var(--pharos-spacing-1-5) var(--pharos-spacing-2);border-radius:var(--pharos-radius-sm);font-size:var(--pharos-font-size-sm);font-weight:var(--pharos-font-weight-medium);color:var(--pharos-color-neutral-700);cursor:default;-webkit-user-select:none;user-select:none;scroll-margin:var(--pharos-spacing-1);transition-property:background-color,color;transition-duration:var(--pharos-duration-fast);transition-timing-function:var(--pharos-easing-out);outline:none;line-height:1.25;display:flex}._item_e7uyk_5[data-highlighted]{background-color:var(--pharos-color-neutral-100);color:var(--pharos-color-neutral-900)}._item_e7uyk_5[data-disabled]{color:var(--pharos-color-neutral-500);opacity:.6;pointer-events:none}._item_e7uyk_5>svg{flex-shrink:0;width:1rem;height:1rem}._itemDestructive_e7uyk_113{color:var(--pharos-color-semantic-error-fg)}._itemDestructive_e7uyk_113[data-highlighted]{background-color:var(--pharos-color-semantic-error-bg);color:var(--pharos-color-semantic-error-fg-hover)}._separator_e7uyk_6{height:1px;margin:var(--pharos-spacing-1) calc(var(--pharos-spacing-1) * -1);background-color:var(--pharos-color-neutral-200)}._label_e7uyk_6{padding:var(--pharos-spacing-1-5) var(--pharos-spacing-2);font-size:var(--pharos-font-size-sm);font-weight:var(--pharos-font-weight-semibold);color:var(--pharos-color-neutral-500)}._button_m4r6t_14{appearance:none;box-sizing:border-box;border-radius:var(--pharos-radius-full);-webkit-user-select:none;user-select:none;cursor:pointer;color:inherit;font-family:var(--pharos-font-family-sans);transition-property:color,background-color,border-color,box-shadow;transition-duration:var(--pharos-duration-normal);transition-timing-function:var(--pharos-easing-out);background-color:#0000;border:0 solid #0000;flex-shrink:0;justify-content:center;align-items:center;margin:0;padding:0;display:inline-flex}._button_m4r6t_14:focus-visible{box-shadow:0 0 0 2px var(--pharos-color-base-white), 0 0 0 4px var(--icon-button-focus-ring,var(--pharos-color-primary-600));outline:none}._button_m4r6t_14:disabled{pointer-events:none;cursor:not-allowed;opacity:.5}._button_m4r6t_14[aria-disabled=true]{cursor:not-allowed;opacity:.5}._primary_m4r6t_89{background-color:var(--pharos-color-primary-600);color:var(--pharos-color-base-white);--icon-button-focus-ring:var(--pharos-color-primary-600)}._primary_m4r6t_89:hover:not([aria-disabled=true]){background-color:var(--pharos-color-primary-700)}._primary_m4r6t_89:active:not([aria-disabled=true]){background-color:var(--pharos-color-primary-800)}._secondary_m4r6t_103{background-color:var(--pharos-color-base-white);color:var(--pharos-color-neutral-900);border:1px solid var(--pharos-color-neutral-500);--icon-button-focus-ring:var(--pharos-color-primary-600)}._secondary_m4r6t_103:hover:not([aria-disabled=true]){background-color:var(--pharos-color-neutral-50)}._secondary_m4r6t_103:active:not([aria-disabled=true]){background-color:var(--pharos-color-neutral-100)}._ghost_m4r6t_122{color:var(--pharos-color-neutral-900);--icon-button-focus-ring:var(--pharos-color-primary-600);background-color:#0000}._ghost_m4r6t_122:hover:not([aria-disabled=true]){background-color:var(--pharos-color-neutral-100)}._ghost_m4r6t_122:active:not([aria-disabled=true]){background-color:var(--pharos-color-neutral-200)}._destructive_m4r6t_136{background-color:var(--pharos-color-semantic-error-fg);color:var(--pharos-color-semantic-error-on);--icon-button-focus-ring:var(--pharos-color-semantic-error-fg)}._destructive_m4r6t_136:hover:not([aria-disabled=true]){background-color:var(--pharos-color-semantic-error-fg-hover)}._destructive_m4r6t_136:active:not([aria-disabled=true]){background-color:var(--pharos-color-semantic-error-fg-active)}._sizeSm_m4r6t_165{width:var(--pharos-spacing-8);height:var(--pharos-spacing-8)}._sizeSm_m4r6t_165>svg{width:var(--pharos-spacing-4);height:var(--pharos-spacing-4)}._sizeMd_m4r6t_175{width:var(--pharos-spacing-10);height:var(--pharos-spacing-10)}._sizeMd_m4r6t_175>svg{width:var(--pharos-spacing-5);height:var(--pharos-spacing-5)}._sizeLg_m4r6t_185{width:var(--pharos-spacing-12);height:var(--pharos-spacing-12)}._sizeLg_m4r6t_185>svg{width:var(--pharos-spacing-6);height:var(--pharos-spacing-6)}@keyframes _pharos-spinner-spin_gg970_1{0%{transform:rotate(0)}to{transform:rotate(360deg)}}._spinner_gg970_28{color:currentColor;vertical-align:middle;justify-content:center;align-items:center;display:inline-flex}._icon_gg970_46{width:100%;height:100%;animation:_pharos-spinner-spin_gg970_1 var(--pharos-duration-slow,1s) linear infinite}@media (prefers-reduced-motion:reduce){._icon_gg970_46{animation-duration:4s}}._sizeSm_gg970_69{width:var(--pharos-spacing-4);height:var(--pharos-spacing-4)}._sizeMd_gg970_74{width:var(--pharos-spacing-5);height:var(--pharos-spacing-5)}._sizeLg_gg970_79{width:var(--pharos-spacing-6);height:var(--pharos-spacing-6)}._srOnly_gg970_87{clip:rect(0, 0, 0, 0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}._input_1ueoc_14{appearance:none;box-sizing:border-box;border:1px solid var(--pharos-color-neutral-500);border-radius:var(--pharos-radius-md);background-color:var(--pharos-color-base-white);width:100%;color:var(--pharos-color-neutral-900);font-family:var(--pharos-font-family-sans);font-size:var(--pharos-font-size-sm);font-weight:var(--pharos-font-weight-regular);transition-property:border-color,box-shadow;transition-duration:var(--pharos-duration-normal);transition-timing-function:var(--pharos-easing-out);margin:0;line-height:1.25}._input_1ueoc_14::placeholder{color:var(--pharos-color-neutral-500);opacity:1}._input_1ueoc_14:focus-visible{border-color:var(--pharos-color-primary-600);box-shadow:0 0 0 2px var(--pharos-color-base-white), 0 0 0 4px var(--pharos-color-primary-600);outline:none}._input_1ueoc_14:disabled{cursor:not-allowed;opacity:.5}._input_1ueoc_14[aria-invalid=true]{border-color:var(--pharos-color-semantic-error-fg)}._input_1ueoc_14[aria-invalid=true]:focus-visible{border-color:var(--pharos-color-semantic-error-fg);box-shadow:0 0 0 2px var(--pharos-color-base-white), 0 0 0 4px var(--pharos-color-semantic-error-fg)}._sizeSm_1ueoc_97{height:var(--pharos-spacing-8);padding:0 var(--pharos-spacing-3);font-size:var(--pharos-font-size-sm)}._sizeMd_1ueoc_103{height:var(--pharos-spacing-10);padding:0 var(--pharos-spacing-4);font-size:var(--pharos-font-size-sm)}._sizeLg_1ueoc_109{height:var(--pharos-spacing-12);padding:0 var(--pharos-spacing-6);font-size:var(--pharos-font-size-base)}@media (pointer:coarse){._input_1ueoc_14,._sizeSm_1ueoc_97,._sizeMd_1ueoc_103{font-size:var(--pharos-font-size-base)}}._positioner_l8xbr_15{z-index:var(--pharos-z-index-popover)}._content_l8xbr_4{box-sizing:border-box;max-width:20rem;padding:var(--pharos-spacing-4);background-color:var(--pharos-color-base-white);border:1px solid var(--pharos-color-neutral-200);border-radius:var(--pharos-radius-md);box-shadow:var(--pharos-shadow-lg);font-family:var(--pharos-font-family-sans);font-size:var(--pharos-font-size-sm);color:var(--pharos-color-neutral-900);transform-origin:var(--transform-origin);transition-property:opacity,transform;transition-duration:var(--pharos-duration-fast);transition-timing-function:var(--pharos-easing-out);outline:none}._content_l8xbr_4[data-starting-style],._content_l8xbr_4[data-ending-style]{opacity:0;transform:scale(.96)}._title_l8xbr_5{font-size:var(--pharos-font-size-base);font-weight:var(--pharos-font-weight-semibold);color:var(--pharos-color-neutral-900);margin:0;line-height:1.4}._description_l8xbr_5{margin:var(--pharos-spacing-1) 0 0;font-size:var(--pharos-font-size-sm);color:var(--pharos-color-neutral-600);line-height:1.5}._group_rsllu_18{gap:var(--pharos-spacing-2);flex-direction:column;display:flex}._item_rsllu_24{box-sizing:border-box;width:var(--pharos-spacing-5);height:var(--pharos-spacing-5);border:1px solid var(--pharos-color-neutral-500);border-radius:var(--pharos-radius-full);background-color:var(--pharos-color-base-white);cursor:pointer;transition-property:background-color,border-color,box-shadow;transition-duration:var(--pharos-duration-fast);transition-timing-function:var(--pharos-easing-out);flex-shrink:0;justify-content:center;align-items:center;padding:0;display:inline-flex}._item_rsllu_24:hover:not([data-disabled]):not([data-checked]){border-color:var(--pharos-color-neutral-700)}._item_rsllu_24[data-checked]{border-color:var(--pharos-color-neutral-900)}._group_rsllu_18[aria-invalid=true] ._item_rsllu_24{border-color:var(--pharos-color-semantic-error-fg)}._item_rsllu_24:focus-visible{box-shadow:0 0 0 2px var(--pharos-color-base-white), 0 0 0 4px var(--pharos-color-primary-600);outline:none}._item_rsllu_24[data-disabled]{cursor:not-allowed;opacity:.5}._indicator_rsllu_75{width:var(--pharos-spacing-2);height:var(--pharos-spacing-2);border-radius:var(--pharos-radius-full);background-color:var(--pharos-color-neutral-900);display:inline-flex}._trigger_g5qz6_35{appearance:none;box-sizing:border-box;justify-content:space-between;align-items:center;gap:var(--pharos-spacing-2);border:1px solid var(--pharos-color-neutral-500);border-radius:var(--pharos-radius-md);background-color:var(--pharos-color-base-white);width:100%;color:var(--pharos-color-neutral-900);font-family:var(--pharos-font-family-sans);font-size:var(--pharos-font-size-sm);font-weight:var(--pharos-font-weight-regular);text-align:start;cursor:default;transition-property:border-color,box-shadow;transition-duration:var(--pharos-duration-normal);transition-timing-function:var(--pharos-easing-out);margin:0;line-height:1.25;display:inline-flex}._trigger_g5qz6_35:focus-visible{border-color:var(--pharos-color-primary-600);box-shadow:0 0 0 2px var(--pharos-color-base-white), 0 0 0 4px var(--pharos-color-primary-600);outline:none}._trigger_g5qz6_35:disabled,._trigger_g5qz6_35[data-disabled]{cursor:not-allowed;opacity:.5}._trigger_g5qz6_35[aria-invalid=true]{border-color:var(--pharos-color-semantic-error-fg)}._trigger_g5qz6_35[aria-invalid=true]:focus-visible{border-color:var(--pharos-color-semantic-error-fg);box-shadow:0 0 0 2px var(--pharos-color-base-white), 0 0 0 4px var(--pharos-color-semantic-error-fg)}._sizeSm_g5qz6_92{height:var(--pharos-spacing-8);padding:0 var(--pharos-spacing-3);font-size:var(--pharos-font-size-sm)}._sizeMd_g5qz6_98{height:var(--pharos-spacing-10);padding:0 var(--pharos-spacing-4);font-size:var(--pharos-font-size-sm)}._sizeLg_g5qz6_104{height:var(--pharos-spacing-12);padding:0 var(--pharos-spacing-6);font-size:var(--pharos-font-size-base)}._value_g5qz6_113{text-overflow:ellipsis;white-space:nowrap;flex:auto;min-width:0;overflow:hidden}._value_g5qz6_113[data-placeholder]{color:var(--pharos-color-neutral-500)}._icon_g5qz6_127{color:var(--pharos-color-neutral-500);transition:transform var(--pharos-duration-fast) var(--pharos-easing-out);flex:none;justify-content:center;align-items:center;display:inline-flex}._icon_g5qz6_127 svg{width:1rem;height:1rem}._icon_g5qz6_127[data-popup-open]{transform:rotate(180deg)}._positioner_g5qz6_24{z-index:var(--pharos-z-index-popover)}._content_g5qz6_146{box-sizing:border-box;width:var(--anchor-width);max-height:var(--available-height);padding:var(--pharos-spacing-1);background-color:var(--pharos-color-base-white);border:1px solid var(--pharos-color-neutral-200);border-radius:var(--pharos-radius-md);box-shadow:var(--pharos-shadow-lg);font-family:var(--pharos-font-family-sans);font-size:var(--pharos-font-size-sm);color:var(--pharos-color-neutral-900);transform-origin:var(--transform-origin);transition-property:opacity,transform;transition-duration:var(--pharos-duration-fast);transition-timing-function:var(--pharos-easing-out);outline:none;overflow-y:auto}._content_g5qz6_146[data-starting-style],._content_g5qz6_146[data-ending-style]{opacity:0;transform:scale(.96)}._item_g5qz6_17{align-items:flex-start;gap:var(--pharos-spacing-2);padding:var(--pharos-spacing-2) var(--pharos-spacing-3);border-radius:var(--pharos-radius-sm);color:var(--pharos-color-neutral-900);cursor:default;-webkit-user-select:none;user-select:none;scroll-margin:var(--pharos-spacing-1);outline:none;display:flex;position:relative}._item_g5qz6_17[data-highlighted]{background-color:var(--pharos-color-neutral-100)}._item_g5qz6_17[data-disabled]{color:var(--pharos-color-neutral-400);pointer-events:none}._itemText_g5qz6_17{overflow-wrap:anywhere;white-space:normal;flex:auto;min-width:0}._itemIndicator_g5qz6_230{block-size:1lh;color:var(--pharos-color-primary-600);flex:none;justify-content:center;align-items:center;display:inline-flex}._itemIndicator_g5qz6_230 svg{width:1rem;height:1rem}._label_g5qz6_246{padding:var(--pharos-spacing-2) var(--pharos-spacing-3) var(--pharos-spacing-1);font-size:var(--pharos-font-size-xs);font-weight:var(--pharos-font-weight-semibold);color:var(--pharos-color-neutral-600)}._separator_g5qz6_254{height:1px;margin:var(--pharos-spacing-1) 0;background-color:var(--pharos-color-neutral-200)}._separator_da90p_13{background-color:var(--pharos-color-neutral-200);border:0;flex-shrink:0;margin:0}._horizontal_da90p_29{width:100%;height:1px}._vertical_da90p_34{width:1px;height:100%}._backdrop_1jbnh_17{z-index:var(--pharos-z-index-modal);background-color:color-mix(in srgb, var(--pharos-color-base-black) 50%, transparent);transition:opacity var(--pharos-duration-normal) var(--pharos-easing-out);position:fixed;inset:0}._backdrop_1jbnh_17[data-starting-style],._backdrop_1jbnh_17[data-ending-style]{opacity:0}._content_1jbnh_33{z-index:var(--pharos-z-index-modal);box-sizing:border-box;gap:var(--pharos-spacing-4);padding:var(--pharos-spacing-6);background-color:var(--pharos-color-base-white);box-shadow:var(--pharos-shadow-xl);font-family:var(--pharos-font-family-sans);font-size:var(--pharos-font-size-sm);color:var(--pharos-color-neutral-900);transition:transform var(--pharos-duration-normal) var(--pharos-easing-out);outline:none;flex-direction:column;display:flex;position:fixed;overflow-y:auto}._sideRight_1jbnh_56{border-left:1px solid var(--pharos-color-neutral-200);width:min(24rem,100vw);height:100dvh;top:0;bottom:0;right:0}._sideRight_1jbnh_56[data-starting-style],._sideRight_1jbnh_56[data-ending-style]{transform:translate(100%)}._sideLeft_1jbnh_69{border-right:1px solid var(--pharos-color-neutral-200);width:min(24rem,100vw);height:100dvh;top:0;bottom:0;left:0}._sideLeft_1jbnh_69[data-starting-style],._sideLeft_1jbnh_69[data-ending-style]{transform:translate(-100%)}._sideTop_1jbnh_82{border-bottom:1px solid var(--pharos-color-neutral-200);width:100vw;max-height:100dvh;top:0;left:0;right:0}._sideTop_1jbnh_82[data-starting-style],._sideTop_1jbnh_82[data-ending-style]{transform:translateY(-100%)}._sideBottom_1jbnh_95{border-top:1px solid var(--pharos-color-neutral-200);width:100vw;max-height:100dvh;bottom:0;left:0;right:0}._sideBottom_1jbnh_95[data-starting-style],._sideBottom_1jbnh_95[data-ending-style]{transform:translateY(100%)}._header_1jbnh_109{gap:var(--pharos-spacing-1);flex-direction:column;display:flex}._title_1jbnh_115{font-size:var(--pharos-font-size-lg);font-weight:var(--pharos-font-weight-semibold);color:var(--pharos-color-neutral-900);margin:0;line-height:1.4}._description_1jbnh_123{font-size:var(--pharos-font-size-sm);color:var(--pharos-color-neutral-600);margin:0;line-height:1.5}._footer_1jbnh_130{gap:var(--pharos-spacing-2);justify-content:flex-end;margin-top:auto;display:flex}._root_1n9ji_17{box-sizing:border-box;width:var(--pharos-spacing-10);height:var(--pharos-spacing-6);padding:var(--pharos-spacing-1);border-radius:var(--pharos-radius-full);background-color:var(--pharos-color-paper-300);cursor:pointer;transition-property:background-color,box-shadow;transition-duration:var(--pharos-duration-fast);transition-timing-function:var(--pharos-easing-out);border:none;flex-shrink:0;align-items:center;display:inline-flex}._root_1n9ji_17:hover:not([data-disabled]):not([data-checked]){background-color:var(--pharos-color-neutral-300)}._root_1n9ji_17[data-checked]{background-color:var(--pharos-color-neutral-900)}._root_1n9ji_17[data-checked]:hover:not([data-disabled]){background-color:var(--pharos-color-neutral-700)}._root_1n9ji_17[aria-invalid=true]{box-shadow:inset 0 0 0 1px var(--pharos-color-semantic-error-fg)}._root_1n9ji_17:focus-visible{box-shadow:0 0 0 2px var(--pharos-color-base-white), 0 0 0 4px var(--pharos-color-primary-600);outline:none}._root_1n9ji_17[data-disabled]{cursor:not-allowed;opacity:.5}._thumb_1n9ji_73{box-sizing:border-box;width:var(--pharos-spacing-4);height:var(--pharos-spacing-4);border:1px solid var(--pharos-color-neutral-500);border-radius:var(--pharos-radius-full);background-color:var(--pharos-color-base-white);transition-property:transform;transition-duration:var(--pharos-duration-fast);transition-timing-function:var(--pharos-easing-out)}._root_1n9ji_17[data-checked] ._thumb_1n9ji_73{transform:translateX(var(--pharos-spacing-4))}._textarea_145hb_21{appearance:none;box-sizing:border-box;border:1px solid var(--pharos-color-neutral-500);border-radius:var(--pharos-radius-md);background-color:var(--pharos-color-base-white);width:100%;color:var(--pharos-color-neutral-900);resize:vertical;font-family:var(--pharos-font-family-sans);font-size:var(--pharos-font-size-sm);font-weight:var(--pharos-font-weight-regular);transition-property:border-color,box-shadow;transition-duration:var(--pharos-duration-normal);transition-timing-function:var(--pharos-easing-out);margin:0;line-height:1.5}._textarea_145hb_21::placeholder{color:var(--pharos-color-neutral-500);opacity:1}._textarea_145hb_21:focus-visible{border-color:var(--pharos-color-primary-600);box-shadow:0 0 0 2px var(--pharos-color-base-white), 0 0 0 4px var(--pharos-color-primary-600);outline:none}._textarea_145hb_21:disabled{cursor:not-allowed;opacity:.5;resize:none}._textarea_145hb_21[aria-invalid=true]{border-color:var(--pharos-color-semantic-error-fg)}._textarea_145hb_21[aria-invalid=true]:focus-visible{border-color:var(--pharos-color-semantic-error-fg);box-shadow:0 0 0 2px var(--pharos-color-base-white), 0 0 0 4px var(--pharos-color-semantic-error-fg)}._sizeSm_145hb_113{min-height:var(--pharos-spacing-16);padding:var(--pharos-spacing-2) var(--pharos-spacing-3);font-size:var(--pharos-font-size-sm)}._sizeMd_145hb_119{min-height:var(--pharos-spacing-20);padding:var(--pharos-spacing-2-5) var(--pharos-spacing-4);font-size:var(--pharos-font-size-sm)}._sizeLg_145hb_125{min-height:var(--pharos-spacing-24);padding:var(--pharos-spacing-3) var(--pharos-spacing-6);font-size:var(--pharos-font-size-base)}@media (pointer:coarse){._textarea_145hb_21,._sizeSm_145hb_113,._sizeMd_145hb_119{font-size:var(--pharos-font-size-base)}}._viewport_1l5b5_17{--pharos-toast-edge-gap:var(--pharos-spacing-4);z-index:var(--pharos-z-index-toast);box-sizing:border-box;inline-size:min(22.5rem, calc(100% - 2 * var(--pharos-toast-edge-gap)));gap:var(--pharos-spacing-2);pointer-events:none;outline:none;flex-direction:column;display:flex;position:fixed}._viewport_1l5b5_17[data-pharos-position^=top]{inset-block-start:var(--pharos-toast-offset,var(--pharos-toast-edge-gap))}._viewport_1l5b5_17[data-pharos-position^=bottom]{flex-direction:column-reverse;inset-block-end:var(--pharos-toast-offset,var(--pharos-toast-edge-gap))}._viewport_1l5b5_17[data-pharos-position$=start]{inset-inline-start:var(--pharos-toast-edge-gap)}._viewport_1l5b5_17[data-pharos-position$=end]{inset-inline-end:var(--pharos-toast-edge-gap)}._viewport_1l5b5_17[data-pharos-position$=center]{margin-inline:auto;inset-inline:0}._toast_1l5b5_60{--pharos-toast-enter-shift:calc(-1 * var(--pharos-spacing-4));box-sizing:border-box;pointer-events:auto;background-color:var(--pharos-color-surface-card);border:1px solid var(--pharos-color-border-subtle);border-radius:var(--pharos-radius-lg);box-shadow:var(--pharos-shadow-lg);font-family:var(--pharos-font-family-sans);font-size:var(--pharos-font-size-sm);color:var(--pharos-color-neutral-900);transform:translate(var(--toast-swipe-movement-x,0), var(--toast-swipe-movement-y,0));transition-property:opacity,transform;transition-duration:var(--pharos-duration-normal);transition-timing-function:var(--pharos-easing-out);line-height:1.43}._viewport_1l5b5_17[data-pharos-position^=bottom] ._toast_1l5b5_60{--pharos-toast-enter-shift:var(--pharos-spacing-4)}._toast_1l5b5_60[data-starting-style],._toast_1l5b5_60[data-ending-style]{opacity:0;transform:translateY(var(--pharos-toast-enter-shift))}._toast_1l5b5_60[data-ending-style][data-swipe-direction=left]{transform:translateX(calc(var(--toast-swipe-movement-x,0) - 100%))}._toast_1l5b5_60[data-ending-style][data-swipe-direction=right]{transform:translateX(calc(var(--toast-swipe-movement-x,0) + 100%))}._toast_1l5b5_60[data-limited]{opacity:0}._toast_1l5b5_60:focus-visible{box-shadow:0 0 0 2px var(--pharos-color-base-white), 0 0 0 4px var(--pharos-color-primary-600), var(--pharos-shadow-lg);outline:none}@media (prefers-reduced-motion:reduce){._toast_1l5b5_60,._toast_1l5b5_60[data-starting-style],._toast_1l5b5_60[data-ending-style]{transition-property:opacity;transform:none}}._content_1l5b5_127{align-items:flex-start;gap:var(--pharos-spacing-3);padding-block:var(--pharos-spacing-3);padding-inline:var(--pharos-spacing-4) var(--pharos-spacing-2);display:flex}._icon_1l5b5_136{inline-size:var(--pharos-spacing-5);block-size:var(--pharos-spacing-5);flex-shrink:0}._text_1l5b5_142{gap:var(--pharos-spacing-0-5);overflow-wrap:anywhere;flex-direction:column;flex:1;min-inline-size:0;display:flex}._toast_1l5b5_60[data-pharos-variant=success] ._icon_1l5b5_136{color:var(--pharos-color-semantic-success-fg)}._toast_1l5b5_60[data-pharos-variant=info] ._icon_1l5b5_136{color:var(--pharos-color-semantic-info-fg)}._toast_1l5b5_60[data-pharos-variant=destructive] ._icon_1l5b5_136{color:var(--pharos-color-semantic-error-fg)}._toast_1l5b5_60[data-pharos-variant=warning] ._icon_1l5b5_136{color:var(--pharos-color-semantic-warning-on)}._warningFill_1l5b5_169{fill:var(--pharos-color-semantic-warning-fg);stroke:var(--pharos-color-semantic-warning-fg)}._title_1l5b5_176{font-size:var(--pharos-font-size-sm);line-height:inherit;font-weight:var(--pharos-font-weight-semibold);margin:0}._description_1l5b5_183{font-size:var(--pharos-font-size-sm);line-height:inherit;color:var(--pharos-color-neutral-600);margin:0}._action_1l5b5_190{align-self:flex-start;margin-block-start:var(--pharos-spacing-2)}._close_1l5b5_197{margin-block:calc(-1 * var(--pharos-spacing-1-5)) calc(-1 * var(--pharos-spacing-1-5));flex-shrink:0}._group_zoq3z_13{box-sizing:border-box;align-items:stretch;gap:var(--pharos-spacing-0-5);max-width:100%;padding:var(--pharos-spacing-0-5);border-radius:var(--pharos-radius-full);background-color:var(--pharos-color-paper-200);font-family:var(--pharos-font-family-sans);display:inline-flex}._sizeSm_zoq3z_25{height:var(--pharos-spacing-8)}._sizeMd_zoq3z_29{height:var(--pharos-spacing-10)}._item_zoq3z_33{appearance:none;box-sizing:border-box;justify-content:center;align-items:center;gap:var(--pharos-spacing-1-5);min-width:0;padding:0 var(--pharos-spacing-3);border-radius:var(--pharos-radius-full);color:var(--pharos-color-neutral-600);font:inherit;font-size:var(--pharos-font-size-sm);font-weight:var(--pharos-font-weight-medium);white-space:nowrap;cursor:pointer;transition-property:color,background-color,box-shadow;transition-duration:var(--pharos-duration-fast);transition-timing-function:var(--pharos-easing-out);background:0 0;border:0;flex:auto;margin:0;line-height:1;display:inline-flex}._sizeMd_zoq3z_29 ._item_zoq3z_33{padding:0 var(--pharos-spacing-4)}._item_zoq3z_33>svg{flex:none;width:1em;height:1em}._item_zoq3z_33:hover:not([data-pressed]):not([data-disabled]){color:var(--pharos-color-neutral-900);background-color:var(--pharos-color-paper-300)}._item_zoq3z_33[data-pressed]{color:var(--pharos-color-neutral-900);background-color:var(--pharos-color-base-white);box-shadow:var(--pharos-shadow-sm), 0 0 0 1px var(--pharos-color-paper-300)}._item_zoq3z_33:focus-visible{box-shadow:0 0 0 2px var(--pharos-color-base-white), 0 0 0 4px var(--pharos-color-primary-600);outline:none}._item_zoq3z_33[data-disabled]{cursor:not-allowed;opacity:.5}@media (prefers-reduced-motion:reduce){._item_zoq3z_33{transition:none}}
2
2
  /*$vite$:1*/
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-sherpas/pharos-react",
3
- "version": "1.0.3",
3
+ "version": "1.1.1",
4
4
  "description": "React component library for Code Sherpas. Consumes @code-sherpas/pharos-tokens. Vite library mode + CSS Modules — no Tailwind, no CSS framework required at the consumer.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -17,8 +17,7 @@
17
17
  },
18
18
  "type": "module",
19
19
  "files": [
20
- "dist",
21
- "RULES.md"
20
+ "dist"
22
21
  ],
23
22
  "exports": {
24
23
  ".": {
@@ -101,6 +100,10 @@
101
100
  "./Toast": {
102
101
  "types": "./dist/components/Toast.d.ts",
103
102
  "import": "./dist/components/Toast.js"
103
+ },
104
+ "./ToggleGroup": {
105
+ "types": "./dist/components/ToggleGroup.d.ts",
106
+ "import": "./dist/components/ToggleGroup.js"
104
107
  }
105
108
  },
106
109
  "sideEffects": [
package/RULES.md DELETED
@@ -1,98 +0,0 @@
1
- # Rules for consumers of `@code-sherpas/pharos-react`
2
-
3
- This file ships with the package (`files` includes `RULES.md`). Every
4
- consumer — `alexandria-web-application` and any future
5
- app — must follow these rules.
6
-
7
- ## 1. Only Pharos components for UI
8
-
9
- Forbidden:
10
-
11
- - Hand-rolled `<button>` / `<input>` when `Button` / `Input` exists in
12
- `@code-sherpas/pharos-react`.
13
- - Importing primitives (`@radix-ui/*`, `@base-ui/*`, `antd`,
14
- `@heroicons/*`, `@headlessui/*`) directly. Pharos wraps what it needs.
15
- - Copy-pasting a Pharos component into the consumer and modifying it. If
16
- Pharos is missing a variant, open an issue in this repo.
17
-
18
- ## 2. Use the canonical names
19
-
20
- Pharos names follow shadcn/ui > Base UI > ARIA APG (tiebreaker: shorter
21
- name). If you are migrating Alexandria, translate the old name to the Pharos
22
- canonical one — do not alias.
23
-
24
- | Alexandria-ish | Pharos canonical |
25
- | -------------------------- | ------------------------ |
26
- | `PrimaryButton` / `CtaBtn` | `<Button variant="…" />` |
27
- | `Modal` / `Popup` | `Dialog` |
28
- | `Drawer` / `SidePanel` | `Sheet` |
29
- | `Toast` / `Notification` | `Toast` |
30
- | `Chip` / `Pill` / `Tag` | `Badge` |
31
-
32
- (Full list lives in `NAMING-decisions.md` once Phase 2 starts.)
33
-
34
- ## 3. Import the stylesheet once
35
-
36
- ```ts
37
- // in your app's root entry file
38
- import '@code-sherpas/pharos-react/styles.css';
39
- ```
40
-
41
- This loads the compiled CSS Modules output of every component (hashed class
42
- names that the React components reference at runtime). Without it,
43
- components render unstyled.
44
-
45
- **You do not need Tailwind, PostCSS, or any other CSS framework to consume
46
- pharos-react** (Decision D9). The published bundle is pure CSS — no
47
- `@layer` directives, no preflight, no global resets, no class-name
48
- collisions with your own utilities. It works the same in Next.js + Tailwind
49
- v3, Next.js + Tailwind v4, Vite + plain CSS, Astro, Remix, or any other
50
- React stack.
51
-
52
- ## 4. `pharos-tokens` is a peer dependency
53
-
54
- Consumers must install it explicitly. It is not transitively bundled to
55
- avoid duplicate CSS var declarations:
56
-
57
- ```bash
58
- pnpm add @code-sherpas/pharos-react @code-sherpas/pharos-tokens
59
- ```
60
-
61
- Version compatibility is declared via `peerDependencies` in
62
- `pharos-react/package.json`. Upgrade both together.
63
-
64
- ## 5. Respect the variants API
65
-
66
- Pharos components expose their full variant axis (size, tone, intent, etc.)
67
- via props. Forbidden:
68
-
69
- - Overriding internal class names to "fake" a variant that does not exist.
70
- - Passing `className` strings that conflict with the component's theme
71
- (e.g. `className="bg-red-500"` on a `<Button>` to make it red — use
72
- `intent="destructive"` or open an issue).
73
-
74
- `className` is allowed for layout tweaks (margins, widths), not visual
75
- identity.
76
-
77
- ## 6. Respect semver
78
-
79
- - Breaking change in this repo → major bump → consumers upgrade explicitly.
80
- - New component or variant → minor bump → consumers may adopt freely.
81
- - Bugfix, visual tweak, or internal refactor → patch → consumers get it for
82
- free.
83
-
84
- Every PR that affects the public API includes a changeset. If your PR does
85
- not, CI will fail.
86
-
87
- ## 7. Icons
88
-
89
- Pharos uses **Lucide** (decision D4). When a component needs an icon you do
90
- not pass, Pharos renders the Lucide default. If you need a custom icon,
91
- open a PR to add it under `src/icons/` — do not ship icons from the
92
- consumer that duplicate Lucide.
93
-
94
- ## 8. Extensions and forks
95
-
96
- Do not publish `@yourorg/pharos-react-extended`. If a product needs its own
97
- components, build them in the consumer under your own naming namespace and
98
- document it. If the need is general, propose it in this repo.