@code-sherpas/pharos-react 0.19.0 → 0.20.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/dist/components/Avatar.js +138 -0
- package/dist/components/Avatar.js.map +1 -0
- package/dist/components/Avatar.module.js +15 -0
- package/dist/components/Avatar.module.js.map +1 -0
- package/dist/components/Badge.js +30 -0
- package/dist/components/Badge.js.map +1 -0
- package/dist/components/Badge.module.js +14 -0
- package/dist/components/Badge.module.js.map +1 -0
- package/dist/components/Button.d.ts.map +1 -1
- package/dist/components/Button.js +49 -0
- package/dist/components/Button.js.map +1 -0
- package/dist/components/Button.module.js +14 -0
- package/dist/components/Button.module.js.map +1 -0
- package/dist/components/Card.js +66 -0
- package/dist/components/Card.js.map +1 -0
- package/dist/components/Card.module.js +15 -0
- package/dist/components/Card.module.js.map +1 -0
- package/dist/components/Checkbox.d.ts.map +1 -1
- package/dist/components/Checkbox.js +47 -0
- package/dist/components/Checkbox.js.map +1 -0
- package/dist/components/Checkbox.module.js +11 -0
- package/dist/components/Checkbox.module.js.map +1 -0
- package/dist/components/Combobox.d.ts.map +1 -1
- package/dist/components/Combobox.js +212 -0
- package/dist/components/Combobox.js.map +1 -0
- package/dist/components/Combobox.module.js +25 -0
- package/dist/components/Combobox.module.js.map +1 -0
- package/dist/components/Dialog.d.ts.map +1 -1
- package/dist/components/Dialog.js +66 -0
- package/dist/components/Dialog.js.map +1 -0
- package/dist/components/Dialog.module.js +12 -0
- package/dist/components/Dialog.module.js.map +1 -0
- package/dist/components/DropdownMenu.d.ts.map +1 -1
- package/dist/components/DropdownMenu.js +64 -0
- package/dist/components/DropdownMenu.js.map +1 -0
- package/dist/components/DropdownMenu.module.js +12 -0
- package/dist/components/DropdownMenu.module.js.map +1 -0
- package/dist/components/IconButton.d.ts.map +1 -1
- package/dist/components/IconButton.js +53 -0
- package/dist/components/IconButton.js.map +1 -0
- package/dist/components/IconButton.module.js +14 -0
- package/dist/components/IconButton.module.js.map +1 -0
- package/dist/components/Input.js +28 -0
- package/dist/components/Input.js.map +1 -0
- package/dist/components/Input.module.js +10 -0
- package/dist/components/Input.module.js.map +1 -0
- package/dist/components/Popover.d.ts.map +1 -1
- package/dist/components/Popover.js +57 -0
- package/dist/components/Popover.js.map +1 -0
- package/dist/components/Popover.module.js +10 -0
- package/dist/components/Popover.module.js.map +1 -0
- package/dist/components/RadioGroup.d.ts.map +1 -1
- package/dist/components/RadioGroup.js +28 -0
- package/dist/components/RadioGroup.js.map +1 -0
- package/dist/components/RadioGroup.module.js +9 -0
- package/dist/components/RadioGroup.module.js.map +1 -0
- package/dist/components/Select.d.ts.map +1 -1
- package/dist/components/Select.js +130 -0
- package/dist/components/Select.js.map +1 -0
- package/dist/components/Select.module.js +19 -0
- package/dist/components/Select.module.js.map +1 -0
- package/dist/components/Separator.js +18 -0
- package/dist/components/Separator.js.map +1 -0
- package/dist/components/Separator.module.js +9 -0
- package/dist/components/Separator.module.js.map +1 -0
- package/dist/components/Sheet.d.ts.map +1 -1
- package/dist/components/Sheet.js +77 -0
- package/dist/components/Sheet.js.map +1 -0
- package/dist/components/Sheet.module.js +16 -0
- package/dist/components/Sheet.module.js.map +1 -0
- package/dist/components/Spinner.js +51 -0
- package/dist/components/Spinner.js.map +1 -0
- package/dist/components/Spinner.module.js +13 -0
- package/dist/components/Spinner.module.js.map +1 -0
- package/dist/components/Switch.d.ts.map +1 -1
- package/dist/components/Switch.js +19 -0
- package/dist/components/Switch.js.map +1 -0
- package/dist/components/Switch.module.js +8 -0
- package/dist/components/Switch.module.js.map +1 -0
- package/dist/components/Textarea.js +27 -0
- package/dist/components/Textarea.js.map +1 -0
- package/dist/components/Textarea.module.js +10 -0
- package/dist/components/Textarea.module.js.map +1 -0
- package/dist/index.js +20 -1218
- package/dist/lib/cn.js +9 -0
- package/dist/lib/cn.js.map +1 -0
- package/dist/styles.css +1 -1
- package/package.json +77 -3
- package/dist/index.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Sheet.js","names":[],"sources":["../../src/components/Sheet.tsx"],"sourcesContent":["'use client';\n\nimport type { ComponentProps, ComponentPropsWithoutRef } from 'react';\nimport { Dialog } from '@base-ui/react/dialog';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '../lib/cn';\nimport styles from './Sheet.module.css';\n\n/**\n * Modal panel that docks to a viewport edge and slides in (the shadcn\n * **Sheet** contract). Wraps Base UI's `Dialog.*`, which implements the ARIA\n * **dialog** pattern as a **modal** disclosure: `role=\"dialog\"` +\n * `aria-modal`, focus trapped inside the panel, scroll locked, Escape and\n * backdrop-click dismiss, focus returns to the trigger on close.\n *\n * Distinct from `Popover` (D16, non-modal, anchored to its trigger) and\n * `DropdownMenu` (D15, menu-button). A Sheet is for a task surface that\n * should command the screen — mobile navigation, a filters panel, a\n * create/edit form. Naming follows shadcn (`Sheet*`); the compound surface\n * collapses Base UI's `Portal` + `Backdrop` + `Popup` into a single\n * `SheetContent` with a `side` prop, mirroring the ergonomics of the other\n * Pharos overlays.\n *\n * v1 ships the parts the known consumers need (the LanguageSelector /\n * MobileDrawer): Trigger, Content, Header, Footer, Title, Description, Close.\n *\n * @example\n * <Sheet>\n * <SheetTrigger render={<Button intent=\"secondary\">Menu</Button>} />\n * <SheetContent side=\"left\">\n * <SheetHeader>\n * <SheetTitle>Navigation</SheetTitle>\n * <SheetDescription>Jump to a section.</SheetDescription>\n * </SheetHeader>\n * <nav>…</nav>\n * <SheetFooter>\n * <SheetClose render={<Button intent=\"ghost\">Close</Button>} />\n * </SheetFooter>\n * </SheetContent>\n * </Sheet>\n */\nexport type SheetProps = ComponentProps<typeof Dialog.Root>;\n\nexport function Sheet(props: SheetProps) {\n return <Dialog.Root {...props} />;\n}\n\nSheet.displayName = 'Sheet';\n\n/**\n * The element that opens the sheet. Renders a native `<button>` by default;\n * pass `render` to compose any control (`render={<Button…/>}`,\n * `render={<IconButton…/>}`).\n */\nexport type SheetTriggerProps = ComponentProps<typeof Dialog.Trigger>;\n\nexport function SheetTrigger(props: SheetTriggerProps) {\n return <Dialog.Trigger {...props} />;\n}\n\nSheetTrigger.displayName = 'SheetTrigger';\n\nconst sheetVariants = cva(styles.content, {\n variants: {\n side: {\n top: styles.sideTop,\n right: styles.sideRight,\n bottom: styles.sideBottom,\n left: styles.sideLeft,\n },\n },\n defaultVariants: {\n side: 'right',\n },\n});\n\ntype SheetVariantProps = VariantProps<typeof sheetVariants>;\n\n/**\n * The panel surface. Collapses Base UI's `Portal` + `Backdrop` + `Popup`. The\n * `side` prop docks it to one of the four viewport edges (default `right`)\n * and picks the matching slide-in transition. The backdrop and panel share\n * the `--pharos-z-index-popover` overlay layer so a Select / Popover opened\n * from inside the sheet still stacks above it (portal open order).\n */\nexport interface SheetContentProps extends ComponentProps<typeof Dialog.Popup>, SheetVariantProps {}\n\nexport function SheetContent({ side = 'right', className, children, ...rest }: SheetContentProps) {\n return (\n <Dialog.Portal>\n <Dialog.Backdrop className={styles.backdrop} />\n <Dialog.Popup\n data-pharos-slot=\"sheet-content\"\n data-pharos-side={side ?? 'right'}\n className={cn(sheetVariants({ side }), className)}\n {...rest}\n >\n {children}\n </Dialog.Popup>\n </Dialog.Portal>\n );\n}\n\nSheetContent.displayName = 'SheetContent';\n\n/** Groups the title + description at the top of the panel. */\nexport interface SheetHeaderProps extends ComponentPropsWithoutRef<'div'> {}\n\nexport function SheetHeader({ className, ...rest }: SheetHeaderProps) {\n return <div data-pharos-slot=\"sheet-header\" className={cn(styles.header, className)} {...rest} />;\n}\n\nSheetHeader.displayName = 'SheetHeader';\n\n/**\n * The panel's accessible name. Renders Base UI's `Dialog.Title`, which wires\n * `aria-labelledby` on the popup — required for the dialog to be announced.\n * Renders as an `<h2>` by default.\n */\nexport type SheetTitleProps = ComponentProps<typeof Dialog.Title>;\n\nexport function SheetTitle({ className, ...rest }: SheetTitleProps) {\n return (\n <Dialog.Title\n data-pharos-slot=\"sheet-title\"\n className={cn(styles.title, className)}\n {...rest}\n />\n );\n}\n\nSheetTitle.displayName = 'SheetTitle';\n\n/**\n * Supporting copy under the title. Renders Base UI's `Dialog.Description`,\n * which wires `aria-describedby` on the popup. Renders as a `<p>` by default.\n */\nexport type SheetDescriptionProps = ComponentProps<typeof Dialog.Description>;\n\nexport function SheetDescription({ className, ...rest }: SheetDescriptionProps) {\n return (\n <Dialog.Description\n data-pharos-slot=\"sheet-description\"\n className={cn(styles.description, className)}\n {...rest}\n />\n );\n}\n\nSheetDescription.displayName = 'SheetDescription';\n\n/** Bottom action row, pushed to the panel's end. */\nexport interface SheetFooterProps extends ComponentPropsWithoutRef<'div'> {}\n\nexport function SheetFooter({ className, ...rest }: SheetFooterProps) {\n return <div data-pharos-slot=\"sheet-footer\" className={cn(styles.footer, className)} {...rest} />;\n}\n\nSheetFooter.displayName = 'SheetFooter';\n\n/**\n * A button that closes the sheet. Renders Base UI's `Dialog.Close` (a native\n * `<button>`); compose any control via `render`.\n */\nexport type SheetCloseProps = ComponentProps<typeof Dialog.Close>;\n\nexport function SheetClose(props: SheetCloseProps) {\n return <Dialog.Close data-pharos-slot=\"sheet-close\" {...props} />;\n}\n\nSheetClose.displayName = 'SheetClose';\n\nexport { sheetVariants };\n"],"mappings":";;;;;;;AA2CA,SAAgB,EAAM,GAAmB;CACvC,OAAO,kBAAC,EAAO,MAAR,EAAa,GAAI,EAAQ,CAAA;AAClC;AAEA,EAAM,cAAc;AASpB,SAAgB,EAAa,GAA0B;CACrD,OAAO,kBAAC,EAAO,SAAR,EAAgB,GAAI,EAAQ,CAAA;AACrC;AAEA,EAAa,cAAc;AAE3B,IAAM,IAAgB,EAAI,EAAO,SAAS;CACxC,UAAU,EACR,MAAM;EACJ,KAAK,EAAO;EACZ,OAAO,EAAO;EACd,QAAQ,EAAO;EACf,MAAM,EAAO;CACf,EACF;CACA,iBAAiB,EACf,MAAM,QACR;AACF,CAAC;AAaD,SAAgB,EAAa,EAAE,UAAO,SAAS,cAAW,aAAU,GAAG,KAA2B;CAChG,OACE,kBAAC,EAAO,QAAR,EAAA,UAAA,CACE,kBAAC,EAAO,UAAR,EAAiB,WAAW,EAAO,SAAW,CAAA,GAC9C,kBAAC,EAAO,OAAR;EACE,oBAAiB;EACjB,oBAAkB,KAAQ;EAC1B,WAAW,EAAG,EAAc,EAAE,QAAK,CAAC,GAAG,CAAS;EAChD,GAAI;EAEH;CACW,CAAA,CACD,EAAA,CAAA;AAEnB;AAEA,EAAa,cAAc;AAK3B,SAAgB,EAAY,EAAE,cAAW,GAAG,KAA0B;CACpE,OAAO,kBAAC,OAAD;EAAK,oBAAiB;EAAe,WAAW,EAAG,EAAO,QAAQ,CAAS;EAAG,GAAI;CAAO,CAAA;AAClG;AAEA,EAAY,cAAc;AAS1B,SAAgB,EAAW,EAAE,cAAW,GAAG,KAAyB;CAClE,OACE,kBAAC,EAAO,OAAR;EACE,oBAAiB;EACjB,WAAW,EAAG,EAAO,OAAO,CAAS;EACrC,GAAI;CACL,CAAA;AAEL;AAEA,EAAW,cAAc;AAQzB,SAAgB,EAAiB,EAAE,cAAW,GAAG,KAA+B;CAC9E,OACE,kBAAC,EAAO,aAAR;EACE,oBAAiB;EACjB,WAAW,EAAG,EAAO,aAAa,CAAS;EAC3C,GAAI;CACL,CAAA;AAEL;AAEA,EAAiB,cAAc;AAK/B,SAAgB,EAAY,EAAE,cAAW,GAAG,KAA0B;CACpE,OAAO,kBAAC,OAAD;EAAK,oBAAiB;EAAe,WAAW,EAAG,EAAO,QAAQ,CAAS;EAAG,GAAI;CAAO,CAAA;AAClG;AAEA,EAAY,cAAc;AAQ1B,SAAgB,EAAW,GAAwB;CACjD,OAAO,kBAAC,EAAO,OAAR;EAAc,oBAAiB;EAAc,GAAI;CAAQ,CAAA;AAClE;AAEA,EAAW,cAAc"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
var e = {
|
|
2
|
+
backdrop: "_backdrop_1pbfd_21",
|
|
3
|
+
content: "_content_1pbfd_37",
|
|
4
|
+
sideRight: "_sideRight_1pbfd_60",
|
|
5
|
+
sideLeft: "_sideLeft_1pbfd_73",
|
|
6
|
+
sideTop: "_sideTop_1pbfd_86",
|
|
7
|
+
sideBottom: "_sideBottom_1pbfd_99",
|
|
8
|
+
header: "_header_1pbfd_113",
|
|
9
|
+
title: "_title_1pbfd_119",
|
|
10
|
+
description: "_description_1pbfd_127",
|
|
11
|
+
footer: "_footer_1pbfd_134"
|
|
12
|
+
};
|
|
13
|
+
//#endregion
|
|
14
|
+
export { e as default };
|
|
15
|
+
|
|
16
|
+
//# sourceMappingURL=Sheet.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Sheet.module.js","names":[],"sources":["../../src/components/Sheet.module.css"],"sourcesContent":["/* Sheet.module.css\n *\n * Per-component CSS Modules definition (Decision D9). Hashed into\n * `dist/styles.css`. Styles a modal panel that docks to a viewport edge and\n * slides in — the shadcn \"Sheet\" contract over Base UI's `Dialog` (modal:\n * focus trap, scroll lock, backdrop). Motion is driven by Base UI's\n * `data-starting-style` / `data-ending-style` state attributes.\n *\n * z-index: the backdrop and the panel share `--pharos-z-index-popover` — the\n * SAME overlay layer DropdownMenu / Popover / Select / Combobox use. Nesting\n * resolves by portal open order (DOM order), NOT by a higher modal z-index:\n * a Select or Popover opened from INSIDE the Sheet portals to <body> AFTER the\n * Sheet, so at equal z-index it paints above the panel. That is the primary\n * use case (a LanguageSelector inside a mobile drawer), so a dedicated higher\n * modal z-index would break it. See NAMING-decisions.md § Sheet. The token is\n * still consumer-overridable (fallback 1000). Defining a real z-index scale in\n * pharos-tokens is a tracked follow-up.\n */\n\n/* === Backdrop (Dialog.Backdrop) === */\n.backdrop {\n position: fixed;\n inset: 0;\n z-index: var(--pharos-z-index-popover, 1000);\n /* Scrim from the base-black token at 50% via color-mix — no hardcoded\n * rgba (NON-NEGOTIABLE rule 1). */\n background-color: color-mix(in srgb, var(--pharos-color-base-black) 50%, transparent);\n transition: opacity var(--pharos-duration-normal) var(--pharos-easing-out);\n}\n\n.backdrop[data-starting-style],\n.backdrop[data-ending-style] {\n opacity: 0;\n}\n\n/* === Panel (Dialog.Popup) === */\n.content {\n position: fixed;\n z-index: var(--pharos-z-index-popover, 1000);\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n gap: var(--pharos-spacing-4);\n padding: var(--pharos-spacing-6);\n\n background-color: var(--pharos-color-base-white);\n box-shadow: var(--pharos-shadow-xl);\n\n font-family: var(--pharos-font-family-sans);\n font-size: var(--pharos-font-size-sm);\n color: var(--pharos-color-neutral-900);\n\n outline: none;\n overflow-y: auto;\n\n transition: transform var(--pharos-duration-normal) var(--pharos-easing-out);\n}\n\n/* === Sides === */\n.sideRight {\n top: 0;\n bottom: 0;\n right: 0;\n height: 100dvh;\n width: min(24rem, 100vw);\n border-left: 1px solid var(--pharos-color-neutral-200);\n}\n.sideRight[data-starting-style],\n.sideRight[data-ending-style] {\n transform: translateX(100%);\n}\n\n.sideLeft {\n top: 0;\n bottom: 0;\n left: 0;\n height: 100dvh;\n width: min(24rem, 100vw);\n border-right: 1px solid var(--pharos-color-neutral-200);\n}\n.sideLeft[data-starting-style],\n.sideLeft[data-ending-style] {\n transform: translateX(-100%);\n}\n\n.sideTop {\n top: 0;\n left: 0;\n right: 0;\n width: 100vw;\n max-height: 100dvh;\n border-bottom: 1px solid var(--pharos-color-neutral-200);\n}\n.sideTop[data-starting-style],\n.sideTop[data-ending-style] {\n transform: translateY(-100%);\n}\n\n.sideBottom {\n bottom: 0;\n left: 0;\n right: 0;\n width: 100vw;\n max-height: 100dvh;\n border-top: 1px solid var(--pharos-color-neutral-200);\n}\n.sideBottom[data-starting-style],\n.sideBottom[data-ending-style] {\n transform: translateY(100%);\n}\n\n/* === Slots === */\n.header {\n display: flex;\n flex-direction: column;\n gap: var(--pharos-spacing-1);\n}\n\n.title {\n margin: 0;\n font-size: var(--pharos-font-size-lg);\n font-weight: var(--pharos-font-weight-semibold);\n line-height: 1.4;\n color: var(--pharos-color-neutral-900);\n}\n\n.description {\n margin: 0;\n font-size: var(--pharos-font-size-sm);\n line-height: 1.5;\n color: var(--pharos-color-neutral-600);\n}\n\n.footer {\n display: flex;\n gap: var(--pharos-spacing-2);\n justify-content: flex-end;\n margin-top: auto;\n}\n"],"mappings":""}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { cn as e } from "../lib/cn.js";
|
|
2
|
+
import t from "./Spinner.module.js";
|
|
3
|
+
import { cva as n } from "class-variance-authority";
|
|
4
|
+
import { jsx as r, jsxs as i } from "react/jsx-runtime";
|
|
5
|
+
//#region src/components/Spinner.tsx
|
|
6
|
+
var a = n(t.spinner, {
|
|
7
|
+
variants: { size: {
|
|
8
|
+
sm: t.sizeSm,
|
|
9
|
+
md: t.sizeMd,
|
|
10
|
+
lg: t.sizeLg
|
|
11
|
+
} },
|
|
12
|
+
defaultVariants: { size: "md" }
|
|
13
|
+
});
|
|
14
|
+
function o({ size: n, className: o, srLabel: s = "Loading…", children: c, ref: l, ...u }) {
|
|
15
|
+
let d = n ?? "md";
|
|
16
|
+
return /* @__PURE__ */ i("span", {
|
|
17
|
+
ref: l,
|
|
18
|
+
role: "status",
|
|
19
|
+
"data-pharos-size": d,
|
|
20
|
+
className: e(a({ size: d }), o),
|
|
21
|
+
...u,
|
|
22
|
+
children: [
|
|
23
|
+
/* @__PURE__ */ r("svg", {
|
|
24
|
+
className: t.icon,
|
|
25
|
+
viewBox: "0 0 24 24",
|
|
26
|
+
fill: "none",
|
|
27
|
+
stroke: "currentColor",
|
|
28
|
+
strokeWidth: 2.5,
|
|
29
|
+
strokeLinecap: "round",
|
|
30
|
+
"aria-hidden": "true",
|
|
31
|
+
focusable: "false",
|
|
32
|
+
children: /* @__PURE__ */ r("circle", {
|
|
33
|
+
cx: "12",
|
|
34
|
+
cy: "12",
|
|
35
|
+
r: "10",
|
|
36
|
+
strokeDasharray: "50 25"
|
|
37
|
+
})
|
|
38
|
+
}),
|
|
39
|
+
/* @__PURE__ */ r("span", {
|
|
40
|
+
className: t.srOnly,
|
|
41
|
+
children: s
|
|
42
|
+
}),
|
|
43
|
+
c
|
|
44
|
+
]
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
o.displayName = "Spinner";
|
|
48
|
+
//#endregion
|
|
49
|
+
export { o as Spinner, a as spinnerVariants };
|
|
50
|
+
|
|
51
|
+
//# sourceMappingURL=Spinner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Spinner.js","names":[],"sources":["../../src/components/Spinner.tsx"],"sourcesContent":["import type { ComponentProps } from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '../lib/cn';\nimport styles from './Spinner.module.css';\n\n/**\n * Maps the `size` axis to per-class names inside `Spinner.module.css`. Sizes\n * align with the Button / Input / Textarea grid (16 / 20 / 24 px) so a\n * Spinner sits flush inside a control of the same size — Composition cases\n * like `<Button><Spinner /></Button>` work out of the box because the\n * Spinner inherits the Button's `currentColor`.\n *\n * No `variant` / `tone` axis on purpose. State-of-the-art DSes (Radix\n * Themes, Mantine, shadcn) keep the Spinner as a single chrome that uses\n * `currentColor`; the consumer picks the colour by setting `color` on the\n * parent (or via `className`). This keeps the atom small and removes the\n * need for a tone palette mapping.\n */\nconst spinnerVariants = cva(styles.spinner, {\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 SpinnerVariantProps = VariantProps<typeof spinnerVariants>;\n\n/**\n * Props accepted by `<Spinner>`. The component renders a `<span role=\"status\">`\n * with an inline SVG that rotates via CSS keyframes (no JS, no animation\n * libraries). Screen readers announce the `srLabel` (default `\"Loading…\"`)\n * via a visually hidden `<span>` inside the status node — the same a11y\n * pattern shadcn / Radix Themes / Material UI use.\n *\n * - `size` aligns with the control grid (Button / Input / Textarea).\n * - `srLabel` is the announced text. Pass an explicit one when the loading\n * action is specific (e.g. `\"Saving template…\"`); the default suits\n * generic \"something is loading\" cases.\n * - Native `<span>` props (e.g. `style`, `aria-*`) pass through. If the\n * consumer sets `aria-label` directly, that wins over `srLabel` for\n * assistive tech (the `srLabel` `<span>` is then redundant but harmless).\n */\nexport interface SpinnerProps extends ComponentProps<'span'>, SpinnerVariantProps {\n /**\n * Visually hidden text announced by assistive tech. Pass an explicit\n * label tied to the action (e.g. `\"Submitting form…\"`) when relevant.\n *\n * @default \"Loading…\"\n */\n srLabel?: string;\n}\n\nexport function Spinner({\n size,\n className,\n srLabel = 'Loading…',\n children,\n ref,\n ...rest\n}: SpinnerProps) {\n const resolvedSize = size ?? 'md';\n return (\n <span\n ref={ref}\n role=\"status\"\n data-pharos-size={resolvedSize}\n className={cn(spinnerVariants({ size: resolvedSize }), className)}\n {...rest}\n >\n <svg\n className={styles.icon}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2.5}\n strokeLinecap=\"round\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n {/*\n * Single arc that completes ~75 % of the circle. The remaining gap\n * gives the visual rotation a clear lead/tail under the CSS spin\n * animation. Same shape Radix Themes / Mantine use; differs from\n * shadcn's lucide-Loader2 only in being inline and dependency-free.\n */}\n <circle cx=\"12\" cy=\"12\" r=\"10\" strokeDasharray=\"50 25\" />\n </svg>\n <span className={styles.srOnly}>{srLabel}</span>\n {children}\n </span>\n );\n}\n\nSpinner.displayName = 'Spinner';\n\nexport { spinnerVariants };\n"],"mappings":";;;;;AAkBA,IAAM,IAAkB,EAAI,EAAO,SAAS;CAC1C,UAAU,EACR,MAAM;EACJ,IAAI,EAAO;EACX,IAAI,EAAO;EACX,IAAI,EAAO;CACb,EACF;CACA,iBAAiB,EACf,MAAM,KACR;AACF,CAAC;AA6BD,SAAgB,EAAQ,EACtB,SACA,cACA,aAAU,YACV,aACA,QACA,GAAG,KACY;CACf,IAAM,IAAe,KAAQ;CAC7B,OACE,kBAAC,QAAD;EACO;EACL,MAAK;EACL,oBAAkB;EAClB,WAAW,EAAG,EAAgB,EAAE,MAAM,EAAa,CAAC,GAAG,CAAS;EAChE,GAAI;YALN;GAOE,kBAAC,OAAD;IACE,WAAW,EAAO;IAClB,SAAQ;IACR,MAAK;IACL,QAAO;IACP,aAAa;IACb,eAAc;IACd,eAAY;IACZ,WAAU;cAQV,kBAAC,UAAD;KAAQ,IAAG;KAAK,IAAG;KAAK,GAAE;KAAK,iBAAgB;IAAS,CAAA;GACrD,CAAA;GACL,kBAAC,QAAD;IAAM,WAAW,EAAO;cAAS;GAAc,CAAA;GAC9C;EACG;;AAEV;AAEA,EAAQ,cAAc"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
var e = {
|
|
2
|
+
spinner: "_spinner_gg970_28",
|
|
3
|
+
icon: "_icon_gg970_46",
|
|
4
|
+
"pharos-spinner-spin": "_pharos-spinner-spin_gg970_1",
|
|
5
|
+
sizeSm: "_sizeSm_gg970_69",
|
|
6
|
+
sizeMd: "_sizeMd_gg970_74",
|
|
7
|
+
sizeLg: "_sizeLg_gg970_79",
|
|
8
|
+
srOnly: "_srOnly_gg970_87"
|
|
9
|
+
};
|
|
10
|
+
//#endregion
|
|
11
|
+
export { e as default };
|
|
12
|
+
|
|
13
|
+
//# sourceMappingURL=Spinner.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Spinner.module.js","names":[],"sources":["../../src/components/Spinner.module.css"],"sourcesContent":["/* Spinner.module.css\n *\n * Per-component CSS Modules definition (Decision D9). The build emits hashed\n * class names (`Spinner_spinner__xxxx`) into `dist/styles.css`; the runtime\n * JS references them through the `styles` object imported by Spinner.tsx.\n *\n * The Spinner is intentionally minimal: a `<span role=\"status\">` that\n * inherits its colour from the parent via `currentColor`. There is no\n * `variant` / `tone` axis — the consumer chooses the colour by setting\n * `color` on the parent (or by overriding via `className`). This matches\n * the shadcn / Radix Themes / Mantine pattern.\n */\n\n@keyframes pharos-spinner-spin {\n /* Single full rotation. Authored as a uniquely-named keyframe (prefixed\n * `pharos-spinner-`) so it cannot collide with consumer keyframes. The\n * `from`/`to` form is two-line and clear; using `100%` would compile to\n * the same output. */\n from {\n transform: rotate(0deg);\n }\n\n to {\n transform: rotate(360deg);\n }\n}\n\n.spinner {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n /* `currentColor` makes the Spinner inherit the parent's text colour by\n * default, so `<Button intent=\"primary\"><Spinner /></Button>` works out\n * of the box (the Button's white text colour cascades into the SVG's\n * `stroke=\"currentColor\"`). */\n color: currentColor;\n /* Vertical alignment with surrounding inline content (e.g. text inside a\n * Button label). Without this, the spinner sits a couple of pixels low\n * because the SVG box's baseline is its bottom edge. */\n vertical-align: middle;\n /* The animation lives on the icon, not the wrapper, so a consumer that\n * targets the wrapper for layout (margin, gap-as-flex-child) does not\n * accidentally inherit the spin transform. */\n}\n\n.icon {\n width: 100%;\n height: 100%;\n animation: pharos-spinner-spin var(--pharos-duration-slow, 1s) linear infinite;\n}\n\n/* Respect the user's reduced-motion preference. The animation slows down\n * dramatically rather than disappearing; some assistive interactions\n * still need a \"this is in progress\" visual cue, so we keep movement but\n * make it gentler. Same compromise Radix Themes uses. */\n@media (prefers-reduced-motion: reduce) {\n .icon {\n animation-duration: 4s;\n }\n}\n\n/* === Sizes ===\n *\n * Heights align with the form-control grid so a Spinner sits flush inside\n * a Button / Input / Textarea of the same size. The visual diameter of the\n * SVG itself fills the wrapper (`width: 100%; height: 100%` on the icon),\n * so the wrapper size IS the spinner size. */\n\n.sizeSm {\n width: var(--pharos-spacing-4); /* 16 px */\n height: var(--pharos-spacing-4);\n}\n\n.sizeMd {\n width: var(--pharos-spacing-5); /* 20 px */\n height: var(--pharos-spacing-5);\n}\n\n.sizeLg {\n width: var(--pharos-spacing-6); /* 24 px */\n height: var(--pharos-spacing-6);\n}\n\n/* Visually-hidden utility for the screen-reader label. Identical to the\n * Tailwind `sr-only` recipe — preserved as a local utility because Pharos\n * does not ship Tailwind in `dist/` (Decision D9). */\n.srOnly {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n}\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Switch.d.ts","sourceRoot":"","sources":["../../src/components/Switch.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Switch.d.ts","sourceRoot":"","sources":["../../src/components/Switch.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAI7D;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,WAAW,WAAY,SAAQ,cAAc,CAAC,OAAO,UAAU,CAAC,IAAI,CAAC;CAAG;AAE9E,wBAAgB,MAAM,CAAC,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,EAAE,WAAW,+BAMzD;yBANe,MAAM"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn as e } from "../lib/cn.js";
|
|
3
|
+
import t from "./Switch.module.js";
|
|
4
|
+
import { jsx as n } from "react/jsx-runtime";
|
|
5
|
+
import { Switch as r } from "@base-ui/react/switch";
|
|
6
|
+
//#region src/components/Switch.tsx
|
|
7
|
+
function i({ className: i, ...a }) {
|
|
8
|
+
return /* @__PURE__ */ n(r.Root, {
|
|
9
|
+
"data-pharos-slot": "switch",
|
|
10
|
+
className: e(t.root, i),
|
|
11
|
+
...a,
|
|
12
|
+
children: /* @__PURE__ */ n(r.Thumb, { className: t.thumb })
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
i.displayName = "Switch";
|
|
16
|
+
//#endregion
|
|
17
|
+
export { i as Switch };
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=Switch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Switch.js","names":[],"sources":["../../src/components/Switch.tsx"],"sourcesContent":["'use client';\n\nimport type { ComponentProps } from 'react';\nimport { Switch as BaseSwitch } from '@base-ui/react/switch';\nimport { cn } from '../lib/cn';\nimport styles from './Switch.module.css';\n\n/**\n * A single on/off toggle control (the shadcn **Switch** contract). Wraps Base\n * UI's `Switch`, which renders a `role=\"switch\"` button plus a hidden form\n * input, and carries the ARIA state (`aria-checked`), keyboard toggle (Space)\n * and focus handling.\n *\n * Sibling to `Checkbox` (D20) in the boolean form-control family: same\n * `checked` / `onCheckedChange` / `disabled` API, same shared focus ring. The\n * difference is semantic — a Switch takes effect immediately (a setting you\n * flip), a Checkbox is a selection that is usually submitted with a form. It\n * has no third `indeterminate` state (a toggle is binary).\n *\n * Like `Input` / `Textarea` / `Checkbox` (Escuela 1, D11), the atom owns no\n * label: pair it with a `<label htmlFor>`. Error state is conveyed via\n * `aria-invalid`, not a custom prop.\n *\n * @example\n * <label htmlFor=\"notify\" className=\"flex items-center gap-2\">\n * <Switch id=\"notify\" checked={enabled} onCheckedChange={setEnabled} />\n * Enable notifications\n * </label>\n */\nexport interface SwitchProps extends ComponentProps<typeof BaseSwitch.Root> {}\n\nexport function Switch({ className, ...rest }: SwitchProps) {\n return (\n <BaseSwitch.Root data-pharos-slot=\"switch\" className={cn(styles.root, className)} {...rest}>\n <BaseSwitch.Thumb className={styles.thumb} />\n </BaseSwitch.Root>\n );\n}\n\nSwitch.displayName = 'Switch';\n"],"mappings":";;;;;;AA+BA,SAAgB,EAAO,EAAE,cAAW,GAAG,KAAqB;CAC1D,OACE,kBAAC,EAAW,MAAZ;EAAiB,oBAAiB;EAAS,WAAW,EAAG,EAAO,MAAM,CAAS;EAAG,GAAI;YACpF,kBAAC,EAAW,OAAZ,EAAkB,WAAW,EAAO,MAAQ,CAAA;CAC7B,CAAA;AAErB;AAEA,EAAO,cAAc"}
|
|
@@ -0,0 +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":""}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { cn as e } from "../lib/cn.js";
|
|
2
|
+
import t from "./Textarea.module.js";
|
|
3
|
+
import { cva as n } from "class-variance-authority";
|
|
4
|
+
import { jsx as r } from "react/jsx-runtime";
|
|
5
|
+
//#region src/components/Textarea.tsx
|
|
6
|
+
var i = n(t.textarea, {
|
|
7
|
+
variants: { size: {
|
|
8
|
+
sm: t.sizeSm,
|
|
9
|
+
md: t.sizeMd,
|
|
10
|
+
lg: t.sizeLg
|
|
11
|
+
} },
|
|
12
|
+
defaultVariants: { size: "md" }
|
|
13
|
+
});
|
|
14
|
+
function a({ size: t, className: n, ref: a, ...o }) {
|
|
15
|
+
let s = t ?? "md";
|
|
16
|
+
return /* @__PURE__ */ r("textarea", {
|
|
17
|
+
ref: a,
|
|
18
|
+
"data-pharos-size": s,
|
|
19
|
+
className: e(i({ size: s }), n),
|
|
20
|
+
...o
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
a.displayName = "Textarea";
|
|
24
|
+
//#endregion
|
|
25
|
+
export { a as Textarea, i as textareaVariants };
|
|
26
|
+
|
|
27
|
+
//# sourceMappingURL=Textarea.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Textarea.js","names":[],"sources":["../../src/components/Textarea.tsx"],"sourcesContent":["import type { ComponentProps } from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '../lib/cn';\nimport styles from './Textarea.module.css';\n\n/**\n * Maps the `size` axis to per-class names inside `Textarea.module.css`. Like\n * `Input`, `Textarea` has no `variant` axis on purpose — shadcn's primitive\n * contract is a single styled `<textarea>` and the design-system best\n * practice for form controls is one chrome with explicit error / disabled /\n * readonly states. Composition around the textarea (label, helper, error\n * message) belongs to the future `<Field>` molecule, not to this atom\n * (Escuela 1 from the field-pattern decision, 2026-04-27).\n *\n * The three sizes share the resting visual contract with `<Input size>` so\n * a textarea sits flush next to inputs of the same size in a form: identical\n * inline padding, identical resting border tone (`neutral-500`), identical\n * font-size hop at `lg`, identical focus ring. The vertical dimension is\n * `min-height` instead of a fixed `height` because textareas grow with\n * content and the user can drag them taller (`resize: vertical`).\n */\nconst textareaVariants = cva(styles.textarea, {\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 TextareaVariantProps = VariantProps<typeof textareaVariants>;\n\n/**\n * Props accepted by `<Textarea>`. Extends every native `<textarea>`\n * attribute. Unlike `<Input>`, no native attribute is shadowed — the native\n * `<textarea>` does not have a `size` attribute, so the typed Pharos size\n * axis takes the slot without collision.\n *\n * Error state is conveyed through the standard `aria-invalid` attribute,\n * not a custom `error` prop. The CSS reacts to `[aria-invalid=\"true\"]`,\n * matching shadcn / Base UI / Mantine. The actual error message is rendered\n * by the consumer next to the textarea (or by the future `<Field>` molecule).\n */\nexport interface TextareaProps extends ComponentProps<'textarea'>, TextareaVariantProps {}\n\nexport function Textarea({ size, className, ref, ...rest }: TextareaProps) {\n const resolvedSize = size ?? 'md';\n return (\n <textarea\n ref={ref}\n data-pharos-size={resolvedSize}\n className={cn(textareaVariants({ size: resolvedSize }), className)}\n {...rest}\n />\n );\n}\n\nTextarea.displayName = 'Textarea';\n\nexport { textareaVariants };\n"],"mappings":";;;;;AAqBA,IAAM,IAAmB,EAAI,EAAO,UAAU;CAC5C,UAAU,EACR,MAAM;EACJ,IAAI,EAAO;EACX,IAAI,EAAO;EACX,IAAI,EAAO;CACb,EACF;CACA,iBAAiB,EACf,MAAM,KACR;AACF,CAAC;AAiBD,SAAgB,EAAS,EAAE,SAAM,cAAW,QAAK,GAAG,KAAuB;CACzE,IAAM,IAAe,KAAQ;CAC7B,OACE,kBAAC,YAAD;EACO;EACL,oBAAkB;EAClB,WAAW,EAAG,EAAiB,EAAE,MAAM,EAAa,CAAC,GAAG,CAAS;EACjE,GAAI;CACL,CAAA;AAEL;AAEA,EAAS,cAAc"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Textarea.module.js","names":[],"sources":["../../src/components/Textarea.module.css"],"sourcesContent":["/* Textarea.module.css\n *\n * Per-component CSS Modules definition (Decision D9). The build emits hashed\n * class names (`Textarea_textarea__xxxx`) into `dist/styles.css`; the runtime\n * JS references them through the `styles` object imported by Textarea.tsx.\n *\n * Every visual value comes from a `--pharos-*` token. No hex, no Tailwind,\n * no preflight. Hover / focus-visible / invalid / disabled states are\n * authored with native CSS pseudo-classes and the `[aria-invalid=\"true\"]`\n * attribute selector — the component does not own any \"error mode\" state\n * itself; it reflects what the consumer puts on the DOM.\n *\n * The chrome (border, radius, focus ring, invalid ring, disabled opacity)\n * is identical to `Input.module.css` so the two atoms read as siblings of\n * the same form-control family. The two genuine differences are:\n * - `min-height` instead of fixed `height` (textareas grow with content).\n * - `resize: vertical` (state-of-the-art shadcn default; consumer can\n * override via `style.resize` if needed).\n */\n\n.textarea {\n /* Strip the user-agent textarea chrome. With preflight gone from the\n * consumer, this is the only line that normalizes the rendering across\n * browsers. */\n appearance: none;\n -webkit-appearance: none;\n\n /* === Box model === */\n box-sizing: border-box;\n width: 100%;\n margin: 0;\n /* `neutral-500` lands the resting border at ~5.4:1 contrast against a\n * white surface, clearing WCAG 1.4.11 (Non-text Contrast, 3:1 for UI\n * component boundaries). Same tone Input uses; the form-control family\n * shares the resting border. */\n border: 1px solid var(--pharos-color-neutral-500);\n border-radius: var(--pharos-radius-md);\n background-color: var(--pharos-color-base-white);\n color: var(--pharos-color-neutral-900);\n\n /* === Layout ===\n * `resize: vertical` matches shadcn / Mantine / Radix Themes — the user\n * can drag the bottom edge to grow the textarea but cannot stretch it\n * horizontally (which would break form layouts). Consumers can opt out\n * via `style={{ resize: 'none' }}` if needed. */\n resize: vertical;\n\n /* === Typography ===\n * `font-family` and weight are explicit so the textarea does not inherit\n * a system-ui fallback when it lives inside surfaces that haven't set the\n * Pharos sans stack. Line-height 1.5 is more legible than Input's 1.25\n * because users frequently paste multi-line content here. */\n font-family: var(--pharos-font-family-sans);\n font-size: var(--pharos-font-size-sm);\n font-weight: var(--pharos-font-weight-regular);\n line-height: 1.5;\n\n /* === Transitions === */\n transition-property: border-color, box-shadow;\n transition-duration: var(--pharos-duration-normal);\n transition-timing-function: var(--pharos-easing-out);\n}\n\n.textarea::placeholder {\n color: var(--pharos-color-neutral-500);\n opacity: 1;\n}\n\n.textarea:focus-visible {\n outline: none;\n border-color: var(--pharos-color-primary-600);\n /* Two-stop box-shadow mirrors Input + Button focus rings: an inner halo\n * in the surface color separates the ring from the textarea fill, and\n * the outer stop is the brand accent. Same tokens as Input so the\n * system has a single focus look across every form 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.textarea:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n /* Dragging the resize handle on a disabled control is jarring; mirror\n * `cursor: not-allowed` by removing the affordance entirely. */\n resize: none;\n}\n\n.textarea[aria-invalid='true'] {\n border-color: var(--pharos-color-semantic-error-fg);\n}\n\n.textarea[aria-invalid='true']:focus-visible {\n border-color: var(--pharos-color-semantic-error-fg);\n box-shadow:\n 0 0 0 2px var(--pharos-color-base-white),\n 0 0 0 4px var(--pharos-color-semantic-error-fg);\n}\n\n/* === Sizes ===\n *\n * Inline padding matches Input exactly so a textarea sits flush next to an\n * input of the same size (no horizontal jog when stacked). Vertical padding\n * is set explicitly because textareas don't have the fixed-height that lets\n * Input use vertical centring. `min-height` is sized to ~3-4 lines of body\n * text at the corresponding font-size; `resize: vertical` lets the user\n * grow it past that.\n *\n * Font-size hops to `base` (16px) at `lg` for the same reason Input does:\n * larger controls usually pair with prominent layouts where 14px feels\n * undersized. */\n\n.sizeSm {\n min-height: var(--pharos-spacing-16);\n padding: var(--pharos-spacing-2) var(--pharos-spacing-3);\n font-size: var(--pharos-font-size-sm);\n}\n\n.sizeMd {\n min-height: var(--pharos-spacing-20);\n padding: var(--pharos-spacing-2-5) var(--pharos-spacing-4);\n font-size: var(--pharos-font-size-sm);\n}\n\n.sizeLg {\n min-height: var(--pharos-spacing-24);\n padding: var(--pharos-spacing-3) var(--pharos-spacing-6);\n font-size: var(--pharos-font-size-base);\n}\n\n/* === Touch screens ===\n * iOS Safari zooms the whole page into any text field whose font is smaller\n * than 16px the moment it is focused, and apps used to stop it by forbidding\n * zoom altogether (`maximum-scale=1`), which breaks WCAG 1.4.4. On a coarse\n * pointer every size types at `base` (16px), so the page can stay zoomable. */\n@media (pointer: coarse) {\n .textarea,\n .sizeSm,\n .sizeMd {\n font-size: var(--pharos-font-size-base);\n }\n}\n"],"mappings":""}
|