@salemcobalt/ui 0.2.0-rc.23 → 0.2.0-rc.25

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
@@ -33,7 +33,7 @@ Styles ship as one stylesheet inside `@layer sc`, so an app's unlayered CSS alwa
33
33
  | `Card` | `variant` outlined · elevated · filled · plain (a quiet row: no surface, a hover wash without border or shadow, selected is `accent.wash` with a 1px `accent.border`); `padding` none · sm · md · lg; `interactive`; `selected` (visual only: pair with `aria-pressed`/`aria-selected`/`aria-current`; also turns a Score inside solid); `as` or `render` to make it an `a`/`button`/`li`. |
34
34
  | `Stack`, `Inline` | `gap` from the spacing scale (`none` … `4xl`); `align`; `justify`; `as`. `Inline` wraps unless `wrap={false}`. |
35
35
  | `Kbd` | One key per `Kbd`; `Kbd.Group label="Command K"` groups a shortcut with a `+` (or `separator="space"`). |
36
- | `Dialog` | `Root` (`open`, `defaultOpen`, `onOpenChange`, `dismissible`, `onRequestClose(reason)`: Esc, backdrop and every `Close` ask instead of closing; close by setting `open`), `Trigger`, `Content` (`size` sm · md · lg, every size clamps to the viewport minus a 16px gutter; `variant="sheet"` becomes a bottom sheet below 640px with a scrolling `Body`; `variant="fullscreen"` covers the viewport, inset 16px from 900px, with a scrolling `Body`), `Title`, `Description`, `Body`, `Actions`, `Close`. Menus, selects and tooltips opened inside render above it. |
36
+ | `Dialog` | `Root` (`open`, `defaultOpen`, `onOpenChange`, `dismissible`, `onRequestClose(reason)`: Esc, backdrop and every `Close` ask instead of closing; close by setting `open`), `Trigger`, `Content` (`size` sm · md · lg, every size clamps to the viewport minus a 16px gutter; `variant="sheet"` becomes a bottom sheet below 640px with a scrolling `Body` and swipe-down-to-dismiss from its handle or header (top 64px, outside controls and `Body`; closes past 30% of its height or on a flick, otherwise springs back; the handle is a `Close` named "Dismiss"; `dismissOnSwipe={false}` where an accidental close loses work, also off when the Root is not `dismissible`); `variant="fullscreen"` covers the viewport, inset 16px from 900px, with a scrolling `Body`), `Title`, `Description`, `Body`, `Actions`, `Close`. Menus, selects and tooltips opened inside render above it. |
37
37
  | `FullScreenFlow` | A multi-step takeover on `Dialog variant="fullscreen"` (docs/adr/0006). `Root` (`open` default `true`, required `onRequestClose(reason)` for Esc and the ×, `onNext`/`onBack` for Enter and the arrow keys outside controls, `decoration`), `Header` (`title` names the dialog, `logo`, `compactTitle` below 760px, `status`, `closeLabel`; children: `Progress`), `Progress` (`chapters` `{ label, steps }[]`, `step` counted from 1, `label`; current chapter `aria-current="step"`), `Body`, `Rail` (from 1000px, `footer`) › `RailGroup` (`label`) › `RailItem` (`current`, `done`, `disabled`, `adornment`), `Viewport` (`direction` forward · back; one keyed `Step`), `Step` (`title` an `<h2>` that takes focus, `eyebrow`, `description`, `announcement` for the live region), `Footer` (`back`, `hint`, children; 44px buttons). The app owns the step state; the flow owns motion, focus and announcements. |
38
38
  | `Toolbar` | `Root` (required `aria-label`, `wrap`, `gap`), `Group` (`aria-label`, `gap`), `Separator`, `Spacer`, `Button` (`render={<IconButton … />}` or `render={<Menu.Trigger render={…} />}` so the control joins the roving focus: Tab enters, arrows move, Tab leaves), `Link` (an anchor in the same navigation; `render={<IconButton label render={<a href />} />}` for an icon link). |
39
39
  | `Banner` | `tone` info (default) · success · warning · danger · neutral; `icon` (or `false`); `action` slot; `dismissible` + `onDismiss` (`open` to control); warning and danger are `role="alert"`, the rest `role="status"`. |
@@ -53,7 +53,7 @@ Styles ship as one stylesheet inside `@layer sc`, so an app's unlayered CSS alwa
53
53
  | `SelectionBar` | Floating bulk-action bar on Toolbar, centred at the bottom of the viewport (content width up to 48rem, gutters and the safe area respected, full width between the gutters under 640px, fade and slide-up, none under reduced motion): `count` (hidden at 0), `onClear`, children are `Toolbar.Button`s, `aria-label` ("Bulk actions"), `countLabel`, `clearLabel`. Mount it at the end of the scrolling content: while open it leaves a spacer as tall as itself so the last rows scroll clear. A polite status region announces the count; focus returns to where it came from when the bar leaves. |
54
54
  | `Toast` | `Toast.Provider` (`timeout` 6000, `limit` 3) near the root, `useToast().add({ title, description, tone, action: { label, onClick }, timeout, priority })` below it; Base UI Toast: polite region, paused on hover and focus, F6 to reach it, bottom-end at `--sc-z-toast`. |
55
55
  | `PriorityNav` | Priority+ primary navigation (docs/adr/0005): required `aria-label`; `items` as `{ href, label, id?, current?, badge?, badgeLabel? }` in priority order; links that fit stay inline and the rest go into a "More" disclosure (APG disclosure navigation: a `button` with `aria-expanded`, not a menu; Esc, click outside and focus leaving close it). The `current` link is never collapsed. `moreLabel`, `moreCountLabel(n)` (announced only: "More, 3 links"), `renderLink={(props) => <Link {...props} />}` for a router. Server-renders every link on one clipped line (scrolls sideways without JS), measures widths once (again after web fonts load or when keys/string labels change) and re-renders only when the inline count changes. Takes the free space in a flex row (`flex: 1 1 0%`); in a grid use a `minmax(0, 1fr)` track. The open panel sits in the top layer (Popover API), anchored to the toggle with CSS anchor positioning (a JS fallback elsewhere) and capped to the viewport. `data-overflowing` + `onOverflowChange(boolean)` let a header make room, with `overflowHysteresis` (px) so it cannot oscillate. Under 400px wide (container query) More shows only an ellipsis. `badge` (a count, or `'dot'`; `0` shows nothing) draws an accent pill or dot after the label, decorative, with `badgeLabel` ("2 suggestions to review") appended to the link's name; while the item is collapsed, More shows the collapsed items' summed count (a dot when they only have dots) and adds their `badgeLabel`s to its name ("More, 3 links, 2 suggestions to review"). Icon-only, the badge sits on More's corner. No motion. |
56
- | `Popover` | Non-modal panel on Base UI Popover: `Root` (`open`, `defaultOpen`, `onOpenChange`, `modal` default false), `Trigger` (secondary Button, or `render={<IconButton label dot />}`), `Content` (`side`, `align`, `sideOffset`, `arrow`; Menu's surface, `--sc-z-dropdown`), `Title` (names the dialog), `Description`, `Close` (the × with no children, or wraps a Button). Esc and focus return come from Base UI. |
56
+ | `Popover` | Non-modal panel on Base UI Popover: `Root` (`open`, `defaultOpen`, `onOpenChange`, `modal` default false), `Trigger` (secondary Button, or `render={<IconButton label dot />}`), `Content` (`side`, `align`, `sideOffset`, `arrow`, `anchor` to position against another element than the Trigger, e.g. a row's action button with a controlled `Root`; portaled to `document.body`; Menu's surface, `--sc-z-dropdown`, dropping to the backdrop layer while a Dialog opened from inside it is open, so the Dialog covers it), `Title` (names the dialog), `Description`, `Close` (the × with no children, or wraps a Button). Esc and focus return come from Base UI. |
57
57
  | `BroomIcon` | Animated 24px-grid icon for "a sweep is running": `sweeping`, `size` (Icon sizes, default `lg`, or `display` 72px with a 1.75px stroke), `title`. Inline SVG; strokes stay 1.25px at any size; holds still with the dust shown under `prefers-reduced-motion`. Inside an IconButton it takes the next icon size up. |
58
58
  | `Score` | A number on a tinted tile or in a ring: required `value` (a number, or `null` for not scored yet: a muted dash on the neutral tile or in an empty ring, no tone, no arc, read as "Fit score: not scored"), `max` (100), `tone` neutral · accent (default) · success · warning · danger (no thresholds inside: map value to tone in the app), `variant` tile · ring (64px, decorative SVG, arc animates only on change, none under reduced motion), `size` sm 40 · md 48 (tile), `caption`, `label` ("Fit score"), `valueText`, `selected`. Assistive tech reads one visually hidden sentence, "Fit score 94 out of 100"; the visible number is `aria-hidden`, no `aria-label`. A tile turns solid when `selected` or inside `.sc-card[data-selected]`, `[aria-pressed="true"]` or `[aria-selected="true"]`. |
59
59
  | `ReasonList` | `ReasonList` (`ul`) + `ReasonList.Item` (`li`): required `tone` for (filled square) · against (bar) · gap (hollow circle), so the marker shape carries the meaning as well as the colour; `size` sm · md; `divider` (dashed rule above). Name it with a heading via `aria-labelledby`; `<strong>` inside picks out key words. |
package/dist/index.d.ts CHANGED
@@ -738,13 +738,21 @@ interface DialogContentProps extends Omit<Dialog$1.Popup.Props, 'className'> {
738
738
  * the Root when leaving needs a confirmation.
739
739
  */
740
740
  variant?: DialogVariant | undefined;
741
+ /**
742
+ * `sheet` only. Below 640px a downward drag on the handle or the header (the top 64px, outside controls
743
+ * and `Dialog.Body`) moves the sheet; letting go past 30% of its height, or flicking down, closes it the
744
+ * way a press on the handle does (the handle is a `Dialog.Close` named "Dismiss"). Set `false` where an
745
+ * accidental close loses work; the handle then stays as decoration only. Off whenever the Root is not
746
+ * `dismissible`. Default `true`.
747
+ */
748
+ dismissOnSwipe?: boolean | undefined;
741
749
  className?: string | undefined;
742
750
  }
743
751
  /**
744
752
  * Portal, backdrop and the popup. Focus moves inside on open and returns to the trigger on close.
745
753
  * Menus, selects and tooltips opened from inside render above it (`--sc-z-dropdown` > `--sc-z-dialog`).
746
754
  */
747
- declare function Content$2({ size, variant, className, children, ...rest }: DialogContentProps): react.JSX.Element;
755
+ declare function Content$2({ size, variant, dismissOnSwipe, className, children, ...rest }: DialogContentProps): react.JSX.Element;
748
756
  interface DialogTitleProps extends Omit<Dialog$1.Title.Props, 'className'> {
749
757
  className?: string | undefined;
750
758
  }
@@ -2729,10 +2737,16 @@ interface PopoverContentProps extends Omit<Popover$1.Popup.Props, 'className'> {
2729
2737
  sideOffset?: number | undefined;
2730
2738
  /** Draws a tip pointing at the trigger. */
2731
2739
  arrow?: boolean | undefined;
2740
+ /**
2741
+ * What to position against instead of the `Popover.Trigger`: an element, a ref to one, a virtual element or a
2742
+ * function returning either. For a popover opened from elsewhere (a menu item, a row action) with a controlled
2743
+ * `Popover.Root open`. The panel is still portaled to `document.body`.
2744
+ */
2745
+ anchor?: Popover$1.Positioner.Props['anchor'];
2732
2746
  className?: string | undefined;
2733
2747
  }
2734
2748
  /** Portal, positioner and the panel. Any content goes inside; name it with `Popover.Title`. */
2735
- declare function Content({ side, align, sideOffset, arrow, className, children, ...rest }: PopoverContentProps): react.JSX.Element;
2749
+ declare function Content({ side, align, sideOffset, arrow, anchor, className, children, ...rest }: PopoverContentProps): react.JSX.Element;
2736
2750
  interface PopoverTitleProps extends Omit<Popover$1.Title.Props, 'className'> {
2737
2751
  className?: string | undefined;
2738
2752
  }
package/dist/index.js CHANGED
@@ -167,6 +167,141 @@ var Kbd = Object.assign(KbdBase, { Group: KbdGroup });
167
167
 
168
168
  // src/components/Dialog/Dialog.tsx
169
169
  import { Dialog as BaseDialog } from "@base-ui/react/dialog";
170
+ import { createContext, useCallback, useContext } from "react";
171
+
172
+ // src/components/Dialog/sheetSwipe.ts
173
+ var SHEET_SWIPE = {
174
+ /** Height in px, from the sheet's top edge, where a drag may start: the handle and the header. */
175
+ zone: 64,
176
+ /** Movement in px before a press becomes a drag, so taps stay taps. */
177
+ slop: 6,
178
+ /** Fraction of the sheet's height past which a release dismisses. */
179
+ distance: 0.3,
180
+ /** Release speed in px/ms: this fast downward dismisses at any distance, this fast upward keeps it open. */
181
+ velocity: 0.5,
182
+ /** Only samples this recent (ms) before the release count toward its speed. */
183
+ window: 100
184
+ };
185
+ function dragIntent(dx, dy, slop = SHEET_SWIPE.slop) {
186
+ if (Math.abs(dx) < slop && Math.abs(dy) < slop) return "pending";
187
+ return dy > 0 && dy >= Math.abs(dx) ? "drag" : "cancel";
188
+ }
189
+ function releaseVelocity(samples, window2 = SHEET_SWIPE.window) {
190
+ const last = samples[samples.length - 1];
191
+ if (!last) return 0;
192
+ const first = samples.find((s) => last.t - s.t <= window2) ?? last;
193
+ const dt = last.t - first.t;
194
+ return dt > 0 ? (last.y - first.y) / dt : 0;
195
+ }
196
+ function shouldDismissSheet({ offset, height, velocity }) {
197
+ if (offset <= 0 || height <= 0) return false;
198
+ if (velocity >= SHEET_SWIPE.velocity) return true;
199
+ if (velocity <= -SHEET_SWIPE.velocity) return false;
200
+ return offset >= height * SHEET_SWIPE.distance;
201
+ }
202
+ var IGNORE = 'a,button,input,select,textarea,label,[role="button"],[contenteditable]';
203
+ function attachSheetSwipe(handle) {
204
+ const popup = handle.parentElement;
205
+ if (!popup) return () => {
206
+ };
207
+ let press = null;
208
+ let dragging = false;
209
+ let height = 0;
210
+ let samples = [];
211
+ let suppressClick = false;
212
+ const startsDrag = (e) => {
213
+ if (!e.isPrimary || e.pointerType === "mouse" && e.button !== 0) return false;
214
+ if (handle.getClientRects().length === 0) return false;
215
+ const target = e.target instanceof Element ? e.target : null;
216
+ if (!target || handle.contains(target)) return true;
217
+ if (target.closest(IGNORE) || target.closest(".sc-dialog__body")) return false;
218
+ return e.clientY - popup.getBoundingClientRect().top <= SHEET_SWIPE.zone;
219
+ };
220
+ const settle = () => {
221
+ delete popup.dataset.swiping;
222
+ popup.style.removeProperty("transform");
223
+ };
224
+ const onDown = (e) => {
225
+ if (press || !startsDrag(e)) return;
226
+ press = { id: e.pointerId, x: e.clientX, y: e.clientY };
227
+ samples = [{ t: e.timeStamp, y: e.clientY }];
228
+ };
229
+ const onMove = (e) => {
230
+ if (!press || e.pointerId !== press.id) return;
231
+ const dy = e.clientY - press.y;
232
+ if (!dragging) {
233
+ const intent = dragIntent(e.clientX - press.x, dy);
234
+ if (intent === "pending") return;
235
+ if (intent === "cancel") {
236
+ press = null;
237
+ return;
238
+ }
239
+ dragging = true;
240
+ height = popup.getBoundingClientRect().height;
241
+ popup.dataset.swiping = "";
242
+ popup.setPointerCapture?.(e.pointerId);
243
+ window.getSelection()?.removeAllRanges();
244
+ }
245
+ e.preventDefault();
246
+ samples.push({ t: e.timeStamp, y: e.clientY });
247
+ if (samples.length > 32) samples = samples.slice(-16);
248
+ popup.style.transform = `translateY(${Math.max(0, dy)}px)`;
249
+ };
250
+ const end = (e, cancelled) => {
251
+ if (!press || e.pointerId !== press.id) return;
252
+ const startY = press.y;
253
+ const wasDragging = dragging;
254
+ press = null;
255
+ dragging = false;
256
+ if (!wasDragging) return;
257
+ window.setTimeout(() => {
258
+ suppressClick = false;
259
+ }, 0);
260
+ if (cancelled) {
261
+ suppressClick = true;
262
+ settle();
263
+ return;
264
+ }
265
+ samples.push({ t: e.timeStamp, y: e.clientY });
266
+ const release = {
267
+ offset: Math.max(0, e.clientY - startY),
268
+ height,
269
+ velocity: releaseVelocity(samples)
270
+ };
271
+ if (shouldDismissSheet(release)) {
272
+ delete popup.dataset.swiping;
273
+ handle.click();
274
+ suppressClick = true;
275
+ window.requestAnimationFrame(() => {
276
+ if (popup.isConnected && popup.hasAttribute("data-open")) settle();
277
+ });
278
+ } else {
279
+ suppressClick = true;
280
+ settle();
281
+ }
282
+ };
283
+ const onUp = (e) => end(e, false);
284
+ const onCancel = (e) => end(e, true);
285
+ const onClick = (e) => {
286
+ if (!suppressClick) return;
287
+ suppressClick = false;
288
+ e.preventDefault();
289
+ e.stopPropagation();
290
+ };
291
+ popup.addEventListener("pointerdown", onDown);
292
+ popup.addEventListener("pointermove", onMove);
293
+ popup.addEventListener("pointerup", onUp);
294
+ popup.addEventListener("pointercancel", onCancel);
295
+ popup.addEventListener("click", onClick, true);
296
+ return () => {
297
+ popup.removeEventListener("pointerdown", onDown);
298
+ popup.removeEventListener("pointermove", onMove);
299
+ popup.removeEventListener("pointerup", onUp);
300
+ popup.removeEventListener("pointercancel", onCancel);
301
+ popup.removeEventListener("click", onClick, true);
302
+ settle();
303
+ };
304
+ }
170
305
 
171
306
  // src/components/Icon/Icon.tsx
172
307
  import { jsx as jsx4 } from "react/jsx-runtime";
@@ -447,6 +582,7 @@ var REQUESTABLE = /* @__PURE__ */ new Set([
447
582
  "outside-press",
448
583
  "close-press"
449
584
  ]);
585
+ var DismissibleContext = createContext(true);
450
586
  function Root({
451
587
  dismissible = true,
452
588
  onOpenChange,
@@ -473,27 +609,49 @@ function Root({
473
609
  }
474
610
  onOpenChange?.(next);
475
611
  },
476
- children
612
+ children: /* @__PURE__ */ jsx6(DismissibleContext.Provider, { value: dismissible, children })
477
613
  }
478
614
  );
479
615
  }
480
616
  var Trigger = BaseDialog.Trigger;
481
- function Content({ size = "md", variant = "dialog", className, children, ...rest }) {
617
+ function Content({
618
+ size = "md",
619
+ variant = "dialog",
620
+ dismissOnSwipe = true,
621
+ className,
622
+ children,
623
+ ...rest
624
+ }) {
625
+ const dismissible = useContext(DismissibleContext);
626
+ const isSheet = variant === "sheet";
627
+ const swipe = isSheet && dismissOnSwipe && dismissible;
482
628
  return /* @__PURE__ */ jsxs5(BaseDialog.Portal, { children: [
483
629
  /* @__PURE__ */ jsx6(BaseDialog.Backdrop, { className: "sc-dialog__backdrop" }),
484
- /* @__PURE__ */ jsx6(
630
+ /* @__PURE__ */ jsxs5(
485
631
  BaseDialog.Popup,
486
632
  {
487
633
  className: cx("sc-dialog__popup", className),
488
634
  "data-size": size,
489
635
  "data-variant": variant,
636
+ "data-swipe-dismiss": swipe ? "" : void 0,
490
637
  "aria-modal": "true",
491
638
  ...rest,
492
- children
639
+ children: [
640
+ isSheet && /* @__PURE__ */ jsx6(SheetHandle, { swipe }),
641
+ children
642
+ ]
493
643
  }
494
644
  )
495
645
  ] });
496
646
  }
647
+ function SheetHandle({ swipe }) {
648
+ const attach = useCallback(
649
+ (node) => node ? attachSheetSwipe(node) : void 0,
650
+ []
651
+ );
652
+ if (!swipe) return /* @__PURE__ */ jsx6("div", { className: "sc-dialog__handle", "aria-hidden": "true" });
653
+ return /* @__PURE__ */ jsx6(BaseDialog.Close, { ref: attach, className: "sc-dialog__handle", "aria-label": "Dismiss" });
654
+ }
497
655
  function Title({ className, ...rest }) {
498
656
  return /* @__PURE__ */ jsx6(BaseDialog.Title, { className: cx("sc-dialog__title", className), ...rest });
499
657
  }
@@ -1402,14 +1560,14 @@ function Text({
1402
1560
  // src/components/Table/Table.tsx
1403
1561
  import { Checkbox as BaseCheckbox2 } from "@base-ui/react/checkbox";
1404
1562
  import {
1405
- createContext,
1406
- useContext
1563
+ createContext as createContext2,
1564
+ useContext as useContext2
1407
1565
  } from "react";
1408
1566
  import { jsx as jsx21, jsxs as jsxs18 } from "react/jsx-runtime";
1409
- var SelectionContext = createContext(null);
1410
- var RowIdContext = createContext(void 0);
1567
+ var SelectionContext = createContext2(null);
1568
+ var RowIdContext = createContext2(void 0);
1411
1569
  function useSelection(part) {
1412
- const selection = useContext(SelectionContext);
1570
+ const selection = useContext2(SelectionContext);
1413
1571
  if (!selection) throw new Error(`${part} needs Table.Root selection={useRowSelection(ids)}`);
1414
1572
  return selection;
1415
1573
  }
@@ -1498,7 +1656,7 @@ function Row({
1498
1656
  onMouseDown,
1499
1657
  ...rest
1500
1658
  }) {
1501
- const selection = useContext(SelectionContext);
1659
+ const selection = useContext2(SelectionContext);
1502
1660
  const selectable = selection !== null && selectionId !== void 0;
1503
1661
  const isSelected = selected ?? (selectable && selection.isSelected(selectionId));
1504
1662
  const row = /* @__PURE__ */ jsx21(
@@ -1571,7 +1729,7 @@ function SelectionHeader({
1571
1729
  }
1572
1730
  function SelectionCell({ label, className, onClick, onClickCapture, ...rest }) {
1573
1731
  const selection = useSelection("Table.SelectionCell");
1574
- const id = useContext(RowIdContext);
1732
+ const id = useContext2(RowIdContext);
1575
1733
  if (id === void 0) throw new Error("Table.SelectionCell goes inside a Table.Row with selectionId");
1576
1734
  return /* @__PURE__ */ jsx21(
1577
1735
  "td",
@@ -2255,9 +2413,9 @@ function fileTypeLabel(file) {
2255
2413
  }
2256
2414
 
2257
2415
  // src/utils/useMediaQuery.ts
2258
- import { useCallback, useSyncExternalStore } from "react";
2416
+ import { useCallback as useCallback2, useSyncExternalStore } from "react";
2259
2417
  function useMediaQuery(query) {
2260
- const subscribe = useCallback(
2418
+ const subscribe = useCallback2(
2261
2419
  (onChange) => {
2262
2420
  if (typeof window === "undefined" || typeof window.matchMedia !== "function") return () => {
2263
2421
  };
@@ -3111,6 +3269,7 @@ function Content3({
3111
3269
  align = "center",
3112
3270
  sideOffset,
3113
3271
  arrow = false,
3272
+ anchor,
3114
3273
  className,
3115
3274
  children,
3116
3275
  ...rest
@@ -3121,6 +3280,7 @@ function Content3({
3121
3280
  side,
3122
3281
  align,
3123
3282
  sideOffset: sideOffset ?? (arrow ? 8 : 4),
3283
+ anchor,
3124
3284
  className: "sc-popover__positioner",
3125
3285
  children: /* @__PURE__ */ jsxs27(BasePopover.Popup, { className: cx("sc-popover", className), ...rest, children: [
3126
3286
  arrow ? /* @__PURE__ */ jsx32(BasePopover.Arrow, { className: "sc-popover__arrow" }) : null,
@@ -3190,9 +3350,9 @@ function BroomIcon({ sweeping = false, size = "lg", title, className, ...rest })
3190
3350
  // src/components/FullScreenFlow/FullScreenFlow.tsx
3191
3351
  import {
3192
3352
  Children as Children2,
3193
- createContext as createContext2,
3194
- useCallback as useCallback2,
3195
- useContext as useContext2,
3353
+ createContext as createContext3,
3354
+ useCallback as useCallback3,
3355
+ useContext as useContext3,
3196
3356
  useEffect as useEffect6,
3197
3357
  useId as useId5,
3198
3358
  useMemo as useMemo3,
@@ -3200,9 +3360,9 @@ import {
3200
3360
  useState as useState8
3201
3361
  } from "react";
3202
3362
  import { jsx as jsx34, jsxs as jsxs29 } from "react/jsx-runtime";
3203
- var FlowContext = createContext2({ announce: () => {
3363
+ var FlowContext = createContext3({ announce: () => {
3204
3364
  } });
3205
- var FrameContext = createContext2(void 0);
3365
+ var FrameContext = createContext3(void 0);
3206
3366
  var ENTER_IGNORES = 'textarea, button, a[href], summary, select, [contenteditable], [role="combobox"], [data-flow-keys="local"]';
3207
3367
  var ARROW_IGNORES = 'input, textarea, select, button, a[href], summary, [contenteditable], [role="radiogroup"], [role="slider"], [role="listbox"], [role="tablist"], [role="menu"], [role="grid"], [role="combobox"], [data-flow-keys="local"]';
3208
3368
  function Root7({
@@ -3217,7 +3377,7 @@ function Root7({
3217
3377
  const popupRef = useRef6(null);
3218
3378
  const [message, setMessage] = useState8("");
3219
3379
  const timer = useRef6(void 0);
3220
- const announce = useCallback2((next) => {
3380
+ const announce = useCallback3((next) => {
3221
3381
  setMessage("");
3222
3382
  clearTimeout(timer.current);
3223
3383
  timer.current = setTimeout(() => setMessage(next), 30);
@@ -3403,7 +3563,7 @@ function Viewport2({ direction = "forward", className, children, ...rest }) {
3403
3563
  } else if (state.current.element !== element) {
3404
3564
  setState((s) => ({ ...s, current: { ...s.current, element } }));
3405
3565
  }
3406
- const finishExit = useCallback2((leftKey) => {
3566
+ const finishExit = useCallback3((leftKey) => {
3407
3567
  setState((s) => s.leaving?.key === leftKey ? { ...s, leaving: null } : s);
3408
3568
  }, []);
3409
3569
  const ref = useRef6(null);
@@ -3472,8 +3632,8 @@ function Step({
3472
3632
  }) {
3473
3633
  const id = useId5();
3474
3634
  const titleRef = useRef6(null);
3475
- const phase = useContext2(FrameContext);
3476
- const { announce } = useContext2(FlowContext);
3635
+ const phase = useContext3(FrameContext);
3636
+ const { announce } = useContext3(FlowContext);
3477
3637
  const message = announcement ?? (typeof title === "string" ? title : void 0);
3478
3638
  const latest = useRef6({ message, announce });
3479
3639
  useEffect6(() => {