@ag2/weave 0.13.0 → 0.14.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.
package/README.md CHANGED
@@ -4,6 +4,27 @@
4
4
 
5
5
  The AG2 Space design system. Forked from [folds](https://github.com/cinnyapp/folds) 2.6.2 (Apache-2.0); `@ag2/weave@0.1.0` is folds@2.6.2 under the new name.
6
6
 
7
+ ## Temporary sidebar collapse
8
+
9
+ Keep `PageNav` mounted and call `useRoomNavAutoCollapse` once from the room layout:
10
+
11
+ ```tsx
12
+ import { useRoomNavAutoCollapse } from "@ag2/weave";
13
+
14
+ useRoomNavAutoCollapse(commonsOpen && !isMobile, roomId);
15
+ ```
16
+
17
+ The hook collapses the sidebar before paint without writing `roomNavCollapsed`.
18
+ Closing Commons or unmounting the layout releases the request and restores the saved
19
+ preference. Manual controls still use `useRoomNavCollapsed()`; they toggle the effective
20
+ state, save the user's choice, and override requests already active. Switching tabs in
21
+ the same room preserves that choice. Closing and reopening Commons, or changing `roomId`,
22
+ starts a fresh automatic collapse. Leave the optional scope unchanged for the lifetime
23
+ of one open panel, and disable the request on mobile.
24
+
25
+ `useRoomNavCollapsed()` retains its existing tuple and animation options. The collapsed
26
+ sidebar's restore button remains the way to expand it; no room-header control is needed.
27
+
7
28
  ## Ambient orb background
8
29
 
9
30
  `OrbBackground` renders the Absorb / Calm / Aura field and is the default background
@@ -12,6 +12,12 @@ export declare type RoomNavToggleOptions = {
12
12
  animate?: boolean;
13
13
  };
14
14
  export declare function useRoomNavCollapsed(): [boolean, (options?: RoomNavToggleOptions) => void];
15
+ /** Temporarily collapse the sidebar without writing its saved preference.
16
+ * Manual toggles win until this request ends. Changing scope starts a new request
17
+ * (for example, entering another room); switching surfaces in one scope does not.
18
+ * Call once from the layout owning the request, outside the collapsible content.
19
+ */
20
+ export declare function useRoomNavAutoCollapse(active: boolean, scope?: string): void;
15
21
  declare type PageNavProps = ClientDrawerLayoutProps & css.PageNavVariants & {
16
22
  /** Decorative brand mark shown in the collapsed rail until hover or keyboard focus. */
17
23
  collapsedMark?: ReactNode;
@@ -0,0 +1,7 @@
1
+ /** One effective state shared by the sidebar and all of its manual controls. */
2
+ export declare const createRoomNavCollapseStore: (storage: () => Pick<Storage, "getItem" | "setItem">) => {
3
+ getSnapshot: () => boolean;
4
+ subscribe: (listener: () => void) => () => void;
5
+ toggle: () => void;
6
+ requestCollapse: () => () => void;
7
+ };
package/dist/index.js CHANGED
@@ -16328,39 +16328,85 @@ function beginDragOverlay(cursor) {
16328
16328
  document.body.appendChild(overlay);
16329
16329
  return () => overlay.remove();
16330
16330
  }
16331
+ const ROOM_NAV_COLLAPSED_KEY = "roomNavCollapsed";
16332
+ const createRoomNavCollapseStore = (storage) => {
16333
+ const listeners = /* @__PURE__ */ new Set();
16334
+ const requests = /* @__PURE__ */ new Map();
16335
+ let preference = false;
16336
+ let unsavedPreference = false;
16337
+ const readPreference = () => {
16338
+ if (unsavedPreference)
16339
+ return preference;
16340
+ try {
16341
+ preference = storage().getItem(ROOM_NAV_COLLAPSED_KEY) === "1";
16342
+ } catch {
16343
+ }
16344
+ return preference;
16345
+ };
16346
+ const getSnapshot = () => readPreference() || Array.from(requests.values()).some(Boolean);
16347
+ const emit = () => listeners.forEach((listener) => listener());
16348
+ return {
16349
+ getSnapshot,
16350
+ subscribe: (listener) => {
16351
+ listeners.add(listener);
16352
+ return () => {
16353
+ listeners.delete(listener);
16354
+ };
16355
+ },
16356
+ toggle: () => {
16357
+ preference = !getSnapshot();
16358
+ try {
16359
+ storage().setItem(ROOM_NAV_COLLAPSED_KEY, preference ? "1" : "0");
16360
+ unsavedPreference = false;
16361
+ } catch {
16362
+ unsavedPreference = true;
16363
+ }
16364
+ requests.forEach((_, token) => requests.set(token, false));
16365
+ emit();
16366
+ },
16367
+ requestCollapse: () => {
16368
+ const token = Symbol("auto-collapse");
16369
+ requests.set(token, true);
16370
+ emit();
16371
+ return () => {
16372
+ requests.delete(token);
16373
+ emit();
16374
+ };
16375
+ }
16376
+ };
16377
+ };
16331
16378
  const PageRoot = ({ nav, children }) => /* @__PURE__ */ jsxs(Box, { grow: "Yes", className: PageRoot$1, children: [
16332
16379
  nav,
16333
16380
  children
16334
16381
  ] });
16335
- const ROOM_NAV_COLLAPSED_KEY = "roomNavCollapsed";
16336
- const navCollapseListeners = /* @__PURE__ */ new Set();
16382
+ const navCollapseStore = createRoomNavCollapseStore(() => localStorage);
16337
16383
  let animateNavChange = false;
16338
- const readNavCollapsed = () => {
16339
- try {
16340
- return localStorage.getItem(ROOM_NAV_COLLAPSED_KEY) === "1";
16341
- } catch {
16342
- return false;
16343
- }
16344
- };
16345
16384
  function useRoomNavCollapsed() {
16346
- const [collapsed, set] = useState(readNavCollapsed);
16347
- useEffect(() => {
16348
- const cb = () => set(readNavCollapsed());
16349
- navCollapseListeners.add(cb);
16350
- return () => {
16351
- navCollapseListeners.delete(cb);
16352
- };
16385
+ const [collapsed, set] = useState(navCollapseStore.getSnapshot);
16386
+ useLayoutEffect(() => {
16387
+ const cb = () => set(navCollapseStore.getSnapshot());
16388
+ const unsubscribe = navCollapseStore.subscribe(cb);
16389
+ cb();
16390
+ return unsubscribe;
16353
16391
  }, []);
16354
16392
  const toggle = useCallback((options) => {
16355
16393
  animateNavChange = (options == null ? void 0 : options.animate) ?? false;
16356
- try {
16357
- localStorage.setItem(ROOM_NAV_COLLAPSED_KEY, readNavCollapsed() ? "0" : "1");
16358
- } catch {
16359
- }
16360
- navCollapseListeners.forEach((cb) => cb());
16394
+ navCollapseStore.toggle();
16361
16395
  }, []);
16362
16396
  return [collapsed, toggle];
16363
16397
  }
16398
+ function useRoomNavAutoCollapse(active, scope) {
16399
+ useLayoutEffect(() => {
16400
+ if (!active)
16401
+ return void 0;
16402
+ animateNavChange = false;
16403
+ const release = navCollapseStore.requestCollapse();
16404
+ return () => {
16405
+ animateNavChange = false;
16406
+ release();
16407
+ };
16408
+ }, [active, scope]);
16409
+ }
16364
16410
  const ROOM_NAV_WIDTH_KEY = "roomNavWidth";
16365
16411
  const NAV_MIN_WIDTH = 180;
16366
16412
  const NAV_MAX_WIDTH = 480;
@@ -16407,16 +16453,16 @@ const PageNav = ({ size: size2, children, collapsedMark }) => {
16407
16453
  duration = closed ? NAV_EXIT_MS : NAV_ENTER_MS;
16408
16454
  }
16409
16455
  useLayoutEffect(() => {
16410
- var _a, _b, _c, _d, _e;
16456
+ var _a, _b, _c, _d, _e, _f;
16411
16457
  const before = previousExtent.current;
16412
16458
  const wasClosed = previousClosed.current;
16413
16459
  previousExtent.current = extent;
16414
16460
  previousClosed.current = closed;
16415
16461
  if (before !== void 0 && wasClosed !== closed) {
16416
- if (closed)
16417
- (_a = showButtonRef.current) == null ? void 0 : _a.focus({ preventScroll: true });
16418
- else if (document.activeElement === showButtonRef.current) {
16419
- const target = ((_b = drawerRef.current) == null ? void 0 : _b.querySelector("[data-nav-collapse]")) ?? ((_c = drawerRef.current) == null ? void 0 : _c.querySelector("button, a"));
16462
+ if (closed && ((_a = drawerRef.current) == null ? void 0 : _a.contains(document.activeElement))) {
16463
+ (_b = showButtonRef.current) == null ? void 0 : _b.focus({ preventScroll: true });
16464
+ } else if (!closed && document.activeElement === showButtonRef.current) {
16465
+ const target = ((_c = drawerRef.current) == null ? void 0 : _c.querySelector("[data-nav-collapse]")) ?? ((_d = drawerRef.current) == null ? void 0 : _d.querySelector("button, a"));
16420
16466
  target == null ? void 0 : target.focus({ preventScroll: true });
16421
16467
  }
16422
16468
  }
@@ -16436,13 +16482,13 @@ const PageNav = ({ size: size2, children, collapsedMark }) => {
16436
16482
  }
16437
16483
  if (before === void 0 || before === extent)
16438
16484
  return;
16439
- const main = (_d = rootRef.current) == null ? void 0 : _d.nextElementSibling;
16485
+ const main = (_e = rootRef.current) == null ? void 0 : _e.nextElementSibling;
16440
16486
  if (!main)
16441
16487
  return;
16442
16488
  const matrix = getComputedStyle(main).transform;
16443
16489
  const values = matrix.match(/matrix(3d)?\((.+)\)/);
16444
16490
  const currentX = values ? Number(values[2].split(",")[values[1] ? 12 : 4]) || 0 : 0;
16445
- (_e = mainMotion.current) == null ? void 0 : _e.cleanup();
16491
+ (_f = mainMotion.current) == null ? void 0 : _f.cleanup();
16446
16492
  main.style.transition = "none";
16447
16493
  main.style.transform = `translateX(${currentX + before - extent}px)`;
16448
16494
  main.getBoundingClientRect();
@@ -18366,6 +18412,7 @@ export {
18366
18412
  useOverlayContainer,
18367
18413
  usePopOutContainer,
18368
18414
  useResizeObserver,
18415
+ useRoomNavAutoCollapse,
18369
18416
  useRoomNavCollapsed,
18370
18417
  useScreenSize,
18371
18418
  useScreenSizeContext,