@rivetjs/cdk 0.1.0-alpha.0 → 0.1.0-alpha.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/_adapters/selection.d.ts +13 -2
- package/_adapters/selection.js +39 -15
- package/button/index.jsx +5 -3
- package/collections/components.d.ts +36 -1
- package/collections/components.jsx +224 -16
- package/collections/nodes.d.ts +9 -1
- package/collections/nodes.js +26 -0
- package/collections/row-stamps.d.ts +17 -0
- package/collections/row-stamps.js +108 -0
- package/collections/server-dev.d.ts +1 -0
- package/collections/server-dev.js +2 -0
- package/collections/server-off.d.ts +1 -0
- package/collections/server-off.js +2 -0
- package/collections/server-on.d.ts +1 -0
- package/collections/server-on.jsx +10 -0
- package/drag-drop/directives/drag.d.ts +16 -0
- package/drag-drop/directives/drag.js +28 -0
- package/drag-drop/drag.jsx +6 -4
- package/drag-drop/lazy-refs.js +15 -4
- package/grid-list/behaviour.d.ts +6 -0
- package/grid-list/behaviour.js +25 -7
- package/grid-list/index.d.ts +3 -1
- package/grid-list/index.jsx +60 -24
- package/interactions/press.jsx +2 -1
- package/interactions/utils.d.ts +2 -3
- package/interactions/utils.js +8 -7
- package/listbox/behaviour.jsx +37 -14
- package/listbox/index.jsx +65 -29
- package/menu/index.jsx +38 -7
- package/package.json +4 -4
- package/portal/index.d.ts +8 -0
- package/portal/index.jsx +8 -1
- package/radio-group/index.jsx +4 -1
- package/selection/keyed.js +6 -16
- package/selection/selectable-collection.js +42 -17
- package/sidebar/index.jsx +5 -4
- package/state/menu.d.ts +3 -0
- package/state/menu.js +1 -0
- package/table/index.jsx +512 -168
- package/tree/index.jsx +26 -4
- package/utils/data-attrs.d.ts +4 -2
- package/utils/data-attrs.jsx +27 -3
- package/utils/index.d.ts +1 -15
- package/utils/index.js +5 -102
- package/utils/link-state.d.ts +6 -0
- package/utils/link-state.js +6 -0
- package/utils/links.d.ts +1 -6
- package/utils/links.jsx +2 -4
- package/utils/transitions.d.ts +15 -0
- package/utils/transitions.js +104 -0
- package/virtualizer/behaviour.d.ts +35 -4
- package/virtualizer/behaviour.js +131 -9
- package/virtualizer/collection-renderer.d.ts +62 -0
- package/virtualizer/collection-renderer.jsx +190 -0
- package/virtualizer/engine.d.ts +1 -1
- package/virtualizer/index.d.ts +1 -0
- package/virtualizer/index.jsx +1 -0
- package/virtualizer/list-layout.js +4 -2
- package/virtualizer/state.js +12 -2
- package/virtualizer/virtualizer.d.ts +8 -6
- package/virtualizer/virtualizer.jsx +4 -1
|
@@ -301,6 +301,9 @@ const memoOf = (owner) => {
|
|
|
301
301
|
};
|
|
302
302
|
/** scroll on the scrollable body: remember the position (restored when focus re-enters). */
|
|
303
303
|
export function selectableCollectionScroll(options, e) {
|
|
304
|
+
// RA: not for a virtualized collection (the virtualizer owns its scroll position).
|
|
305
|
+
if (options.isVirtualized)
|
|
306
|
+
return;
|
|
304
307
|
const r = resolve(options, e);
|
|
305
308
|
const m = memoOf(r.ref ?? options);
|
|
306
309
|
m.scrollTop = r.scrollRef?.scrollTop ?? 0;
|
|
@@ -347,7 +350,7 @@ export function selectableCollectionFocus(options, e) {
|
|
|
347
350
|
else
|
|
348
351
|
navigate(manager.firstSelectedKey ?? delegate.getFirstKey?.());
|
|
349
352
|
}
|
|
350
|
-
else if (r.scrollRef) {
|
|
353
|
+
else if (!options.isVirtualized && r.scrollRef) {
|
|
351
354
|
// Restore the scroll position to what it was before.
|
|
352
355
|
r.scrollRef.scrollTop = m.scrollTop;
|
|
353
356
|
r.scrollRef.scrollLeft = m.scrollLeft;
|
|
@@ -466,6 +469,37 @@ export function selectableCollectionAutoFocus(options) {
|
|
|
466
469
|
syncFocus(options, null);
|
|
467
470
|
return true;
|
|
468
471
|
}
|
|
472
|
+
/** useSelectableItem's focus + useSelectableCollection's scroll-into-view for the focused item element. */
|
|
473
|
+
function focusItem(r, element, didAutoFocus) {
|
|
474
|
+
if (!r.shouldUseVirtualFocus) {
|
|
475
|
+
if (element.ownerDocument.activeElement !== element)
|
|
476
|
+
focusSafely(element);
|
|
477
|
+
}
|
|
478
|
+
else
|
|
479
|
+
moveVirtualFocus(element);
|
|
480
|
+
const modality = getInteractionModality();
|
|
481
|
+
if ((modality === "keyboard" || didAutoFocus) && r.scrollRef) {
|
|
482
|
+
scrollIntoView(r.scrollRef, element);
|
|
483
|
+
// Avoid scroll in iOS VO, since it may cause overlay to close.
|
|
484
|
+
if (modality !== "virtual")
|
|
485
|
+
scrollIntoViewport(element, { containingElement: r.ref });
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
/** Virtualized collections: focus the item of `key` after the render that adds it (a microtask, then a few frames). */
|
|
489
|
+
function whenRendered(r, key, didAutoFocus) {
|
|
490
|
+
let frames = 0;
|
|
491
|
+
const attempt = () => {
|
|
492
|
+
const manager = r.manager;
|
|
493
|
+
if (untrack(() => manager.focusedKey) !== key || !untrack(() => manager.isFocused) || !r.ref)
|
|
494
|
+
return;
|
|
495
|
+
const element = getItemElement(r.ref, key);
|
|
496
|
+
if (element)
|
|
497
|
+
focusItem(r, element, didAutoFocus);
|
|
498
|
+
else if (frames++ < 3)
|
|
499
|
+
requestAnimationFrame(attempt);
|
|
500
|
+
};
|
|
501
|
+
queueMicrotask(attempt);
|
|
502
|
+
}
|
|
469
503
|
/**
|
|
470
504
|
* react-aria's post-render effects, run after a handler changed state: move DOM (or virtual) focus
|
|
471
505
|
* to the focused item, scroll it into view (keyboard modality / after auto focus), and focus the
|
|
@@ -480,22 +514,13 @@ export function syncFocus(options, previousKey, event) {
|
|
|
480
514
|
const changed = focusedKey !== previousKey;
|
|
481
515
|
if (isFocused && focusedKey != null && (changed || m.didAutoFocus) && r.ref) {
|
|
482
516
|
const element = getItemElement(r.ref, focusedKey);
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
moveVirtualFocus(element);
|
|
491
|
-
const modality = getInteractionModality();
|
|
492
|
-
if ((modality === "keyboard" || m.didAutoFocus) && r.scrollRef) {
|
|
493
|
-
scrollIntoView(r.scrollRef, element);
|
|
494
|
-
// Avoid scroll in iOS VO, since it may cause overlay to close.
|
|
495
|
-
if (modality !== "virtual")
|
|
496
|
-
scrollIntoViewport(element, { containingElement: r.ref });
|
|
497
|
-
}
|
|
498
|
-
}
|
|
517
|
+
const didAutoFocus = m.didAutoFocus;
|
|
518
|
+
if (element)
|
|
519
|
+
focusItem(r, element, didAutoFocus);
|
|
520
|
+
// Virtualized: the item renders once the virtualizer persists the new focused key (RA: useSelectableItem's
|
|
521
|
+
// effect after that render) — focus and scroll it in when it appears.
|
|
522
|
+
else if (options.isVirtualized)
|
|
523
|
+
whenRendered(r, focusedKey, didAutoFocus);
|
|
499
524
|
}
|
|
500
525
|
// If the focused key becomes null (e.g. the last item is deleted), focus the whole collection.
|
|
501
526
|
if (!r.shouldUseVirtualFocus && isFocused && focusedKey == null && previousKey != null && r.ref)
|
package/sidebar/index.jsx
CHANGED
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
// Deviations: `data-active` / `data-show-on-hover` are `"true"` or absent (React writes `"false"` too);
|
|
37
37
|
// `SidebarMenuAction` writes `data-show-on-hover` and `SidebarMenuButton` `data-variant` (upstream: Tailwind
|
|
38
38
|
// classes) so CSS can key on them; the desktop root stays in the DOM on mobile (empty, CSS-hidden) so `SidebarInset`'s sibling selectors keep working.
|
|
39
|
-
import { createContext, provide, useContext } from "@rivetjs/reactivity";
|
|
39
|
+
import { createContext, provide, signal, useContext } from "@rivetjs/reactivity";
|
|
40
40
|
import { Show, clientEffect, clientEvent, ref as createRef } from "@rivetjs/runtime/dom";
|
|
41
41
|
import { resumableContext } from "@rivetjs/runtime/resume-format";
|
|
42
42
|
import { visuallyHidden } from "../a11y/index.js";
|
|
@@ -548,12 +548,13 @@ export function SidebarMenuBadge(props) {
|
|
|
548
548
|
/** A loading placeholder for a menu item. */
|
|
549
549
|
export function SidebarMenuSkeleton(props) {
|
|
550
550
|
const { showIcon = false, iconClass, textClass, class: cls, style, render, ref, children: _children, ...rest } = props;
|
|
551
|
-
// Random width between 50 to 90%.
|
|
552
|
-
|
|
551
|
+
// Random width between 50 to 90%. Rivet: state (upstream `useState`), so the server's pick is the page's: a resumed or
|
|
552
|
+
// adopted skeleton keeps the width the markup shows.
|
|
553
|
+
const width = signal(`${Math.floor(Math.random() * 40) + 50}%`);
|
|
553
554
|
const rp = renderProps({ class: cls, values: NONE, defaultClassName: "rv-SidebarMenuSkeleton" });
|
|
554
555
|
const parts = () => (<>
|
|
555
556
|
{showIcon ? <div class={iconClass ?? "rv-SidebarMenuSkeleton-icon"} data-sidebar="menu-skeleton-icon"/> : null}
|
|
556
|
-
<div class={textClass ?? "rv-SidebarMenuSkeleton-text"} data-sidebar="menu-skeleton-text" style={{ "--skeleton-width": width }}/>
|
|
557
|
+
<div class={textClass ?? "rv-SidebarMenuSkeleton-text"} data-sidebar="menu-skeleton-text" style={{ "--skeleton-width": width() }}/>
|
|
557
558
|
</>);
|
|
558
559
|
if (render)
|
|
559
560
|
return render({ ...rest, ref, "data-slot": "sidebar-menu-skeleton", "data-sidebar": "menu-skeleton", class: () => rp.class(), style, children: parts }, undefined);
|
package/state/menu.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { type Signal } from "@rivetjs/reactivity";
|
|
|
2
2
|
import { type FocusStrategy, type MultipleSelectionState } from "../_adapters/collections.js";
|
|
3
3
|
import type { PressEvent } from "../interactions/press.jsx";
|
|
4
4
|
import type { HoverEvent } from "../interactions/hover.jsx";
|
|
5
|
+
import type { VirtualCollection } from "../_adapters/selection.js";
|
|
5
6
|
import { type OverlayTriggerProps, type OverlayTriggerState } from "./overlays.js";
|
|
6
7
|
import { type Key, type ListProps, type ListState, type Selection, type SelectionMode } from "./list.js";
|
|
7
8
|
export type { Key, Selection, SelectionMode, FocusStrategy };
|
|
@@ -134,6 +135,8 @@ export declare function createMenuState(props: MenuProps, context?: {
|
|
|
134
135
|
submenuTrigger?: SubmenuTriggerState;
|
|
135
136
|
parentId?: string;
|
|
136
137
|
id?: string;
|
|
138
|
+
/** Rivet: a Menu inside a `CollectionVirtualizer` (its built collection + the layout delegate). */
|
|
139
|
+
virtual?: VirtualCollection;
|
|
137
140
|
}): MenuState;
|
|
138
141
|
/** Register a rendered MenuItem's callbacks / disabled flag (RAC: the collection node's props). */
|
|
139
142
|
export declare function registerMenuItem(state: MenuState, key: Key, item: MenuItemCallbacks & {
|