@exponential_app/eui-react 0.11.0 → 0.13.0

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.
@@ -44,7 +44,7 @@
44
44
  "\"use client\"\n\nimport * as React from \"react\"\nimport { Separator as SeparatorPrimitive } from \"radix-ui\"\nimport { SEPARATOR_CLASSES } from \"@exponential_app/eui/web/primitives\"\n\nimport { cn } from \"./cn\"\n\nfunction Separator({\n className,\n orientation = `horizontal`,\n decorative = true,\n ...props\n}: React.ComponentProps<typeof SeparatorPrimitive.Root>) {\n return (\n <SeparatorPrimitive.Root\n data-slot=\"separator\"\n decorative={decorative}\n orientation={orientation}\n className={cn(SEPARATOR_CLASSES.root, className)}\n {...props}\n />\n )\n}\n\nexport { Separator }\n",
45
45
  "import * as React from \"react\"\nimport { SKELETON_CLASSES } from \"@exponential_app/eui/web/primitives\"\n\nimport { cn } from \"./cn\"\n\nfunction Skeleton({ className, ...props }: React.ComponentProps<`div`>) {\n return (\n <div\n data-slot=\"skeleton\"\n className={cn(SKELETON_CLASSES.root, className)}\n {...props}\n />\n )\n}\n\nexport { Skeleton }\n",
46
46
  "import type * as React from \"react\"\nimport { LoaderCircle } from \"lucide-react\"\nimport { SPINNER_CLASSES } from \"@exponential_app/eui/web/primitives\"\n\nimport { cn } from \"./cn\"\n\nfunction Spinner({\n size = 10,\n label = `Loading`,\n className,\n ...props\n}: Omit<React.ComponentProps<`svg`>, `children`> & {\n size?: number\n /** The accessible name; the glyph itself never carries words. */\n label?: string\n className?: string\n}) {\n return (\n <LoaderCircle\n data-slot=\"spinner\"\n data-testid=\"feedback-spinner\"\n aria-label={label}\n width={size}\n height={size}\n style={{ width: size, height: size }}\n className={cn(SPINNER_CLASSES.root, className)}\n {...props}\n />\n )\n}\n\nexport { Spinner }\n",
47
- "import * as React from \"react\"\nimport { Switch as SwitchPrimitive } from \"radix-ui\"\nimport { SWITCH_CLASSES } from \"@exponential_app/eui/web/primitives\"\n\nimport { cn } from \"./cn\"\n\nfunction Switch({\n className,\n size = `default`,\n ...props\n}: React.ComponentProps<typeof SwitchPrimitive.Root> & {\n size?: `sm` | `default`\n}) {\n return (\n <SwitchPrimitive.Root\n data-slot=\"switch\"\n data-size={size}\n className={cn(SWITCH_CLASSES.root, className)}\n {...props}\n >\n <SwitchPrimitive.Thumb\n data-slot=\"switch-thumb\"\n className={cn(SWITCH_CLASSES.thumb)}\n />\n </SwitchPrimitive.Root>\n )\n}\n\nexport { Switch }\n",
47
+ "import * as React from \"react\"\nimport { Switch as SwitchPrimitive } from \"radix-ui\"\nimport { SWITCH_CLASSES } from \"@exponential_app/eui/web/primitives\"\n\nimport { cn } from \"./cn\"\n\nfunction Switch({\n className,\n size = `default`,\n ...props\n}: React.ComponentProps<typeof SwitchPrimitive.Root> & {\n size?: `sm` | `compact` | `default`\n}) {\n return (\n <SwitchPrimitive.Root\n data-slot=\"switch\"\n data-size={size}\n className={cn(SWITCH_CLASSES.root, className)}\n {...props}\n >\n <SwitchPrimitive.Thumb\n data-slot=\"switch-thumb\"\n className={cn(SWITCH_CLASSES.thumb)}\n />\n </SwitchPrimitive.Root>\n )\n}\n\nexport { Switch }\n",
48
48
  "import * as React from \"react\"\nimport { TABLE_CLASSES } from \"@exponential_app/eui/web/primitives\"\n\nimport { cn } from \"./cn\"\n\nfunction Table({ className, ...props }: React.ComponentProps<`table`>) {\n return (\n <div data-slot=\"table-container\" className={TABLE_CLASSES.container}>\n <table data-slot=\"table\" className={cn(TABLE_CLASSES.root, className)} {...props} />\n </div>\n )\n}\n\nfunction TableHeader({ className, ...props }: React.ComponentProps<`thead`>) {\n return <thead data-slot=\"table-header\" className={cn(TABLE_CLASSES.header, className)} {...props} />\n}\n\nfunction TableBody({ className, ...props }: React.ComponentProps<`tbody`>) {\n return <tbody data-slot=\"table-body\" className={cn(TABLE_CLASSES.body, className)} {...props} />\n}\n\nfunction TableFooter({ className, ...props }: React.ComponentProps<`tfoot`>) {\n return <tfoot data-slot=\"table-footer\" className={cn(TABLE_CLASSES.footer, className)} {...props} />\n}\n\n/** A selected row says so with `data-state=\"selected\"` (shadcn's convention). */\nfunction TableRow({ className, ...props }: React.ComponentProps<`tr`>) {\n return <tr data-slot=\"table-row\" className={cn(TABLE_CLASSES.row, className)} {...props} />\n}\n\nfunction TableHead({ className, ...props }: React.ComponentProps<`th`>) {\n return <th data-slot=\"table-head\" className={cn(TABLE_CLASSES.head, className)} {...props} />\n}\n\nfunction TableCell({ className, ...props }: React.ComponentProps<`td`>) {\n return <td data-slot=\"table-cell\" className={cn(TABLE_CLASSES.cell, className)} {...props} />\n}\n\nfunction TableCaption({ className, ...props }: React.ComponentProps<`caption`>) {\n return <caption data-slot=\"table-caption\" className={cn(TABLE_CLASSES.caption, className)} {...props} />\n}\n\nexport { Table, TableHeader, TableBody, TableFooter, TableRow, TableHead, TableCell, TableCaption }\n",
49
49
  "import * as React from \"react\"\nimport { TEXTAREA_CLASSES } from \"@exponential_app/eui/web/primitives\"\n\nimport { cn } from \"./cn\"\n\nfunction Textarea({ className, ...props }: React.ComponentProps<`textarea`>) {\n return (\n <textarea\n data-slot=\"textarea\"\n className={cn(TEXTAREA_CLASSES.root, className)}\n {...props}\n />\n )\n}\n\nexport { Textarea }\n",
50
50
  "import * as React from \"react\"\nimport { CircleCheck, CircleX, Info, TriangleAlert, XIcon } from \"lucide-react\"\nimport {\n TOAST_CLASSES,\n TOAST_TOUCH_QUERY,\n createToastStore,\n layoutSize,\n toastPlacement,\n toastStackGeometry,\n type ToastKind,\n type ToastRecord,\n type ToastStore,\n} from \"@exponential_app/eui/web/primitives\"\n\nimport { cn } from \"./cn\"\nimport { useMediaQuery } from \"./use-media-query\"\n\n// FEED-131: THE toast without sonner: the stack of fixtures/toast-stack.json\n// (the engine in @exponential_app/eui/web/primitives/toast) painted on plain\n// elements. A region `<section>` holds the stack box `<ol>`, one `<li>` per\n// toast placed by `--offset`/`--scale`; hover (pointer) or a tap (touch)\n// expands the stack and pauses every clock. The Solid twin paints the same.\n\nconst KIND_ICONS: Record<ToastKind, React.ComponentType<React.SVGProps<SVGSVGElement>>> = {\n success: CircleCheck,\n error: CircleX,\n info: Info,\n warning: TriangleAlert,\n}\n\n/** The default store `toast` writes to and `<Toaster />` reads. */\nexport const toastStore: ToastStore = createToastStore()\n\n/** `toast(\"…\")`, `toast.success(\"…\", { description, action })`, … on the default store. */\nexport const toast = toastStore.toast\n\nexport type ToasterProps = Omit<React.ComponentProps<`section`>, `children`> & {\n store?: ToastStore\n /** The placement input (default: the `touchMaxWidth` media query). */\n touch?: boolean\n /** The close glyph's label. */\n closeLabel?: string\n}\n\nfunction useToasts(store: ToastStore): readonly ToastRecord[] {\n return React.useSyncExternalStore(store.subscribe, store.toasts, store.toasts)\n}\n\nexport function Toaster({ store = toastStore, touch, closeLabel = `Close`, className, ...props }: ToasterProps) {\n const toasts = useToasts(store)\n const touchQuery = useMediaQuery(TOAST_TOUCH_QUERY)\n const { placement, anchoredBottom } = toastPlacement(touch ?? touchQuery)\n const [expanded, setExpanded] = React.useState(false)\n const [measured, setMeasured] = React.useState<Record<string, number>>({})\n const items = React.useRef(new Map<string, HTMLLIElement>())\n const open = expanded && toasts.length > 0\n\n React.useEffect(() => {\n if (open) store.pauseAll()\n else store.resumeAll()\n }, [open, store])\n\n React.useLayoutEffect(() => {\n const next: Record<string, number> = {}\n for (const t of toasts) {\n const el = items.current.get(t.id)\n if (t.height === undefined && el) next[t.id] = layoutSize(el).height\n }\n setMeasured((prev) => (Object.keys(next).length === Object.keys(prev).length && Object.entries(next).every(([k, v]) => prev[k] === v) ? prev : next))\n }, [toasts])\n\n const geometry = toastStackGeometry(\n toasts.map((t) => t.height ?? measured[t.id] ?? 0),\n open,\n anchoredBottom\n )\n\n return (\n <section\n aria-label=\"Notifications\"\n data-slot=\"toaster\"\n data-placement={placement}\n className={cn(TOAST_CLASSES.region, TOAST_CLASSES.regionPlacement[placement], className)}\n {...props}\n >\n <ol\n data-slot=\"toast-list\"\n data-expanded={open ? `true` : `false`}\n className={cn(TOAST_CLASSES.list, TOAST_CLASSES.listPlacement[placement])}\n style={{ height: geometry.height }}\n onPointerEnter={(event) => {\n if (event.pointerType !== `touch`) setExpanded(true)\n }}\n onPointerLeave={(event) => {\n if (event.pointerType !== `touch`) setExpanded(false)\n }}\n onPointerDown={(event) => {\n if (event.pointerType === `touch`) setExpanded((was) => !was)\n }}\n >\n {toasts.map((t, i) => {\n const item = geometry.items[i]!\n const rank = toasts.length - 1 - i\n const Icon = t.kind ? KIND_ICONS[t.kind] : null\n return (\n <li\n key={t.id}\n ref={(el) => {\n if (el) items.current.set(t.id, el)\n else items.current.delete(t.id)\n }}\n role=\"status\"\n aria-live=\"polite\"\n aria-atomic=\"true\"\n data-slot=\"toast\"\n data-kind={t.kind ?? `default`}\n data-front={rank === 0 ? `true` : `false`}\n data-expanded={open ? `true` : `false`}\n data-visible={item.visible ? `true` : `false`}\n data-index={rank}\n className={cn(TOAST_CLASSES.toast, TOAST_CLASSES.toastOrigin[anchoredBottom ? `bottom` : `top`])}\n style={{ \"--offset\": `${item.offset}px`, \"--scale\": `${item.scale}`, zIndex: i + 1 } as React.CSSProperties}\n >\n {Icon && (\n <div className={TOAST_CLASSES.iconSlot}>\n <Icon data-toast-kind={t.kind} className={cn(TOAST_CLASSES.icon, TOAST_CLASSES.kindIcon[t.kind!])} />\n </div>\n )}\n <div className={TOAST_CLASSES.content}>\n <div data-slot=\"toast-title\" className={TOAST_CLASSES.title}>\n {t.title}\n </div>\n {t.description !== undefined && (\n <div data-slot=\"toast-description\" className={TOAST_CLASSES.description}>\n {t.description}\n </div>\n )}\n </div>\n {t.action && (\n <button\n type=\"button\"\n data-slot=\"toast-action\"\n className={TOAST_CLASSES.action}\n onClick={(event) => {\n t.action?.onClick?.(event.nativeEvent)\n store.dismiss(t.id)\n }}\n >\n {t.action.label}\n </button>\n )}\n <button type=\"button\" data-slot=\"toast-close\" aria-label={closeLabel} className={TOAST_CLASSES.close} onClick={() => store.dismiss(t.id)}>\n <XIcon />\n </button>\n </li>\n )\n })}\n </ol>\n </section>\n )\n}\n\nexport { createToastStore, toastStackGeometry, toastPlacement, TOAST_CONSTANTS, TOAST_KINDS, TOAST_TOUCH_QUERY } from \"@exponential_app/eui/web/primitives\"\nexport type { ToastKind, ToastOptions, ToastRecord, ToastStore, ToastAction, ToastPlacement } from \"@exponential_app/eui/web/primitives\"\n",
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
2
  import { Switch as SwitchPrimitive } from "radix-ui";
3
3
  declare function Switch({ className, size, ...props }: React.ComponentProps<typeof SwitchPrimitive.Root> & {
4
- size?: `sm` | `default`;
4
+ size?: `sm` | `compact` | `default`;
5
5
  }): import("react/jsx-runtime").JSX.Element;
6
6
  export { Switch };
@@ -1,5 +1,5 @@
1
1
  import { type CSSProperties, type ReactNode, type Ref } from "react";
2
- import type { ModeName, ResolvedTheme, ScrollAlign, ThemeIssue, ThemeSource, UiNode, SurfaceCommand } from "@exponential_app/eui";
2
+ import type { FormFactor, ModeName, ResolvedTheme, ScrollAlign, ThemeIssue, ThemeSource, UiNode, SurfaceCommand } from "@exponential_app/eui";
3
3
  import { type DataModel } from "@exponential_app/eui/web";
4
4
  import { type ReactExtension } from "./extensions.js";
5
5
  import type { HostPlugin } from "./host.js";
@@ -73,6 +73,10 @@ export interface ExponentialSurfaceProps {
73
73
  * not feed back into its own measurement). The gpui host passes 0 (=
74
74
  * unknown) today, so the default keeps web and desktop identical. */
75
75
  viewportHeight?: number;
76
+ /** VAPP-218: the HOST's form factor, what `@media (form-factor: …)`
77
+ * matches (an editor preview's phone frame, a phone). Default: derived
78
+ * from the surface width (`phone` below the theme's `$breakpoint.md`). */
79
+ formFactor?: FormFactor;
76
80
  /** An explicit id (defaults to React's `useId`); must be unique per page. */
77
81
  id?: string;
78
82
  /** Host → surface commands (focus, announce, scrollIntoView). */
@@ -108,6 +112,8 @@ export interface LayoutInputs {
108
112
  breakpoints: Record<string, number>;
109
113
  queries: readonly string[];
110
114
  viewportHeight: number | undefined;
115
+ /** Unset = derived from the width against `breakpoints.md`. */
116
+ formFactor?: FormFactor;
111
117
  hover: boolean;
112
118
  reducedMotion: boolean;
113
119
  }
@@ -122,4 +128,4 @@ export declare function surfaceLayout(box: SurfaceBox, inputs: LayoutInputs): {
122
128
  * inline `data={{ items, filter }}` with stable values costs one pass over
123
129
  * its top-level keys). */
124
130
  export declare function sameData(a: unknown, b: unknown): boolean;
125
- export declare function ExponentialSurface({ surface, root: rootProp, templates: templatesProp, data: dataProp, theme: themeProp, mode: modeSetting, density, contrast, locale, timeZone, strings: stringOverrides, readOnly, host, extensions: extensionsProp, states, measure, inlineOverlays, direction: directionProp, width, viewportHeight, id: idProp, handleRef, className, style, children, }: ExponentialSurfaceProps): import("react/jsx-runtime").JSX.Element;
131
+ export declare function ExponentialSurface({ surface, root: rootProp, templates: templatesProp, data: dataProp, theme: themeProp, mode: modeSetting, density, contrast, locale, timeZone, strings: stringOverrides, readOnly, host, extensions: extensionsProp, states, measure, inlineOverlays, direction: directionProp, width, viewportHeight, formFactor, id: idProp, handleRef, className, style, children, }: ExponentialSurfaceProps): import("react/jsx-runtime").JSX.Element;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exponential_app/eui-react",
3
- "version": "0.11.0",
3
+ "version": "0.13.0",
4
4
  "description": "Exponential UI for React: the reference renderer of the core A2UI catalog on Radix with real CSS, runtime themes, extensions, and the shadcn primitive set the Exponential app shares.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://exponential.at/ui/",
@@ -42,7 +42,7 @@
42
42
  "*.css"
43
43
  ],
44
44
  "dependencies": {
45
- "@exponential_app/eui": "^0.11.0",
45
+ "@exponential_app/eui": "^0.13.0",
46
46
  "class-variance-authority": "^0.7.1",
47
47
  "clsx": "^2.1.1",
48
48
  "lucide-react": "^0.544.0",