@orz/ui 0.0.0-stage → 0.0.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/LICENSE +29 -0
- package/README.md +541 -2
- package/dist/components/avatar.d.ts +14 -0
- package/dist/components/avatar.d.ts.map +1 -0
- package/dist/components/avatar.js +23 -0
- package/dist/components/avatar.js.map +1 -0
- package/dist/components/badge.d.ts +10 -0
- package/dist/components/badge.d.ts.map +1 -0
- package/dist/components/badge.js +26 -0
- package/dist/components/badge.js.map +1 -0
- package/dist/components/button.d.ts +11 -0
- package/dist/components/button.d.ts.map +1 -0
- package/dist/components/button.js +40 -0
- package/dist/components/button.js.map +1 -0
- package/dist/components/card.d.ts +12 -0
- package/dist/components/card.d.ts.map +1 -0
- package/dist/components/card.js +25 -0
- package/dist/components/card.js.map +1 -0
- package/dist/components/color-picker.d.ts +58 -0
- package/dist/components/color-picker.d.ts.map +1 -0
- package/dist/components/color-picker.js +950 -0
- package/dist/components/color-picker.js.map +1 -0
- package/dist/components/confirm-dialog.d.ts +26 -0
- package/dist/components/confirm-dialog.d.ts.map +1 -0
- package/dist/components/confirm-dialog.js +18 -0
- package/dist/components/confirm-dialog.js.map +1 -0
- package/dist/components/dialog.d.ts +26 -0
- package/dist/components/dialog.d.ts.map +1 -0
- package/dist/components/dialog.js +149 -0
- package/dist/components/dialog.js.map +1 -0
- package/dist/components/dropdown-menu.d.ts +30 -0
- package/dist/components/dropdown-menu.d.ts.map +1 -0
- package/dist/components/dropdown-menu.js +100 -0
- package/dist/components/dropdown-menu.js.map +1 -0
- package/dist/components/filter-menu.d.ts +98 -0
- package/dist/components/filter-menu.d.ts.map +1 -0
- package/dist/components/filter-menu.js +745 -0
- package/dist/components/filter-menu.js.map +1 -0
- package/dist/components/highlighted-input.d.ts +40 -0
- package/dist/components/highlighted-input.d.ts.map +1 -0
- package/dist/components/highlighted-input.js +95 -0
- package/dist/components/highlighted-input.js.map +1 -0
- package/dist/components/hover-card.d.ts +7 -0
- package/dist/components/hover-card.d.ts.map +1 -0
- package/dist/components/hover-card.js +22 -0
- package/dist/components/hover-card.js.map +1 -0
- package/dist/components/input.d.ts +4 -0
- package/dist/components/input.d.ts.map +1 -0
- package/dist/components/input.js +7 -0
- package/dist/components/input.js.map +1 -0
- package/dist/components/label.d.ts +5 -0
- package/dist/components/label.d.ts.map +1 -0
- package/dist/components/label.js +8 -0
- package/dist/components/label.js.map +1 -0
- package/dist/components/link-chip.d.ts +67 -0
- package/dist/components/link-chip.d.ts.map +1 -0
- package/dist/components/link-chip.js +71 -0
- package/dist/components/link-chip.js.map +1 -0
- package/dist/components/load-failure.d.ts +24 -0
- package/dist/components/load-failure.d.ts.map +1 -0
- package/dist/components/load-failure.js +27 -0
- package/dist/components/load-failure.js.map +1 -0
- package/dist/components/load-more.d.ts +15 -0
- package/dist/components/load-more.d.ts.map +1 -0
- package/dist/components/load-more.js +25 -0
- package/dist/components/load-more.js.map +1 -0
- package/dist/components/media-controls.d.ts +50 -0
- package/dist/components/media-controls.d.ts.map +1 -0
- package/dist/components/media-controls.js +71 -0
- package/dist/components/media-controls.js.map +1 -0
- package/dist/components/popover.d.ts +9 -0
- package/dist/components/popover.d.ts.map +1 -0
- package/dist/components/popover.js +82 -0
- package/dist/components/popover.js.map +1 -0
- package/dist/components/query-box.d.ts +78 -0
- package/dist/components/query-box.d.ts.map +1 -0
- package/dist/components/query-box.js +332 -0
- package/dist/components/query-box.js.map +1 -0
- package/dist/components/query-highlight.d.ts +14 -0
- package/dist/components/query-highlight.d.ts.map +1 -0
- package/dist/components/query-highlight.js +132 -0
- package/dist/components/query-highlight.js.map +1 -0
- package/dist/components/select.d.ts +19 -0
- package/dist/components/select.d.ts.map +1 -0
- package/dist/components/select.js +38 -0
- package/dist/components/select.js.map +1 -0
- package/dist/components/separator.d.ts +5 -0
- package/dist/components/separator.d.ts.map +1 -0
- package/dist/components/separator.js +9 -0
- package/dist/components/separator.js.map +1 -0
- package/dist/components/sheet.d.ts +16 -0
- package/dist/components/sheet.d.ts.map +1 -0
- package/dist/components/sheet.js +41 -0
- package/dist/components/sheet.js.map +1 -0
- package/dist/components/skeleton.d.ts +3 -0
- package/dist/components/skeleton.d.ts.map +1 -0
- package/dist/components/skeleton.js +7 -0
- package/dist/components/skeleton.js.map +1 -0
- package/dist/components/slider.d.ts +8 -0
- package/dist/components/slider.d.ts.map +1 -0
- package/dist/components/slider.js +14 -0
- package/dist/components/slider.js.map +1 -0
- package/dist/components/sonner.d.ts +4 -0
- package/dist/components/sonner.d.ts.map +1 -0
- package/dist/components/sonner.js +26 -0
- package/dist/components/sonner.js.map +1 -0
- package/dist/components/switch.d.ts +5 -0
- package/dist/components/switch.d.ts.map +1 -0
- package/dist/components/switch.js +8 -0
- package/dist/components/switch.js.map +1 -0
- package/dist/components/table.d.ts +11 -0
- package/dist/components/table.d.ts.map +1 -0
- package/dist/components/table.js +28 -0
- package/dist/components/table.js.map +1 -0
- package/dist/components/tabs.d.ts +8 -0
- package/dist/components/tabs.d.ts.map +1 -0
- package/dist/components/tabs.js +18 -0
- package/dist/components/tabs.js.map +1 -0
- package/dist/components/textarea.d.ts +4 -0
- package/dist/components/textarea.d.ts.map +1 -0
- package/dist/components/textarea.js +7 -0
- package/dist/components/textarea.js.map +1 -0
- package/dist/components/theme-editor/draft.d.ts +235 -0
- package/dist/components/theme-editor/draft.d.ts.map +1 -0
- package/dist/components/theme-editor/draft.js +638 -0
- package/dist/components/theme-editor/draft.js.map +1 -0
- package/dist/components/theme-editor/export-panel.d.ts +14 -0
- package/dist/components/theme-editor/export-panel.d.ts.map +1 -0
- package/dist/components/theme-editor/export-panel.js +39 -0
- package/dist/components/theme-editor/export-panel.js.map +1 -0
- package/dist/components/theme-editor/form.d.ts +69 -0
- package/dist/components/theme-editor/form.d.ts.map +1 -0
- package/dist/components/theme-editor/form.js +350 -0
- package/dist/components/theme-editor/form.js.map +1 -0
- package/dist/components/theme-editor/import-panel.d.ts +21 -0
- package/dist/components/theme-editor/import-panel.d.ts.map +1 -0
- package/dist/components/theme-editor/import-panel.js +117 -0
- package/dist/components/theme-editor/import-panel.js.map +1 -0
- package/dist/components/theme-editor/theme-list.d.ts +23 -0
- package/dist/components/theme-editor/theme-list.d.ts.map +1 -0
- package/dist/components/theme-editor/theme-list.js +42 -0
- package/dist/components/theme-editor/theme-list.js.map +1 -0
- package/dist/components/theme-editor/token-list.d.ts +30 -0
- package/dist/components/theme-editor/token-list.d.ts.map +1 -0
- package/dist/components/theme-editor/token-list.js +124 -0
- package/dist/components/theme-editor/token-list.js.map +1 -0
- package/dist/components/theme-editor/tokens.d.ts +37 -0
- package/dist/components/theme-editor/tokens.d.ts.map +1 -0
- package/dist/components/theme-editor/tokens.js +155 -0
- package/dist/components/theme-editor/tokens.js.map +1 -0
- package/dist/components/theme-editor.d.ts +26 -0
- package/dist/components/theme-editor.d.ts.map +1 -0
- package/dist/components/theme-editor.js +467 -0
- package/dist/components/theme-editor.js.map +1 -0
- package/dist/components/theme-menu.d.ts +28 -0
- package/dist/components/theme-menu.d.ts.map +1 -0
- package/dist/components/theme-menu.js +308 -0
- package/dist/components/theme-menu.js.map +1 -0
- package/dist/components/tooltip.d.ts +11 -0
- package/dist/components/tooltip.d.ts.map +1 -0
- package/dist/components/tooltip.js +18 -0
- package/dist/components/tooltip.js.map +1 -0
- package/dist/components/unsaved-changes-dialog.d.ts +39 -0
- package/dist/components/unsaved-changes-dialog.d.ts.map +1 -0
- package/dist/components/unsaved-changes-dialog.js +46 -0
- package/dist/components/unsaved-changes-dialog.js.map +1 -0
- package/dist/hooks/scroll-insets.d.ts +89 -0
- package/dist/hooks/scroll-insets.d.ts.map +1 -0
- package/dist/hooks/scroll-insets.js +265 -0
- package/dist/hooks/scroll-insets.js.map +1 -0
- package/dist/hooks/use-element-height.d.ts +11 -0
- package/dist/hooks/use-element-height.d.ts.map +1 -0
- package/dist/hooks/use-element-height.js +33 -0
- package/dist/hooks/use-element-height.js.map +1 -0
- package/dist/hooks/use-media-query.d.ts +22 -0
- package/dist/hooks/use-media-query.d.ts.map +1 -0
- package/dist/hooks/use-media-query.js +38 -0
- package/dist/hooks/use-media-query.js.map +1 -0
- package/dist/hooks/use-overlay-scrollbars.d.ts +31 -0
- package/dist/hooks/use-overlay-scrollbars.d.ts.map +1 -0
- package/dist/hooks/use-overlay-scrollbars.js +80 -0
- package/dist/hooks/use-overlay-scrollbars.js.map +1 -0
- package/dist/hooks/use-paged-append.d.ts +7 -0
- package/dist/hooks/use-paged-append.d.ts.map +1 -0
- package/dist/hooks/use-paged-append.js +53 -0
- package/dist/hooks/use-paged-append.js.map +1 -0
- package/dist/hooks/use-query-completion.d.ts +27 -0
- package/dist/hooks/use-query-completion.d.ts.map +1 -0
- package/dist/hooks/use-query-completion.js +100 -0
- package/dist/hooks/use-query-completion.js.map +1 -0
- package/dist/hooks/use-slash-shortcut.d.ts +9 -0
- package/dist/hooks/use-slash-shortcut.d.ts.map +1 -0
- package/dist/hooks/use-slash-shortcut.js +38 -0
- package/dist/hooks/use-slash-shortcut.js.map +1 -0
- package/dist/hooks/viewport-chrome.d.ts +50 -0
- package/dist/hooks/viewport-chrome.d.ts.map +1 -0
- package/dist/hooks/viewport-chrome.js +170 -0
- package/dist/hooks/viewport-chrome.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/cell-width-table.d.ts +3 -0
- package/dist/lib/cell-width-table.d.ts.map +1 -0
- package/dist/lib/cell-width-table.js +6 -0
- package/dist/lib/cell-width-table.js.map +1 -0
- package/dist/lib/cell-width.d.ts +7 -0
- package/dist/lib/cell-width.d.ts.map +1 -0
- package/dist/lib/cell-width.js +50 -0
- package/dist/lib/cell-width.js.map +1 -0
- package/dist/lib/clipboard.d.ts +8 -0
- package/dist/lib/clipboard.d.ts.map +1 -0
- package/dist/lib/clipboard.js +19 -0
- package/dist/lib/clipboard.js.map +1 -0
- package/dist/lib/color.d.ts +40 -0
- package/dist/lib/color.d.ts.map +1 -0
- package/dist/lib/color.js +177 -0
- package/dist/lib/color.js.map +1 -0
- package/dist/lib/scroll-map.d.ts +20 -0
- package/dist/lib/scroll-map.d.ts.map +1 -0
- package/dist/lib/scroll-map.js +46 -0
- package/dist/lib/scroll-map.js.map +1 -0
- package/dist/lib/text-metrics.d.ts +33 -0
- package/dist/lib/text-metrics.d.ts.map +1 -0
- package/dist/lib/text-metrics.js +89 -0
- package/dist/lib/text-metrics.js.map +1 -0
- package/dist/lib/theme-file.d.ts +51 -0
- package/dist/lib/theme-file.d.ts.map +1 -0
- package/dist/lib/theme-file.js +511 -0
- package/dist/lib/theme-file.js.map +1 -0
- package/dist/lib/unsaved-guard.d.ts +33 -0
- package/dist/lib/unsaved-guard.d.ts.map +1 -0
- package/dist/lib/unsaved-guard.js +37 -0
- package/dist/lib/unsaved-guard.js.map +1 -0
- package/dist/lib/utils.d.ts +3 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +6 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/theme/custom.d.ts +8 -0
- package/dist/theme/custom.d.ts.map +1 -0
- package/dist/theme/custom.js +56 -0
- package/dist/theme/custom.js.map +1 -0
- package/dist/theme/index.d.ts +6 -0
- package/dist/theme/index.d.ts.map +1 -0
- package/dist/theme/index.js +5 -0
- package/dist/theme/index.js.map +1 -0
- package/dist/theme/paint-guard.d.ts +20 -0
- package/dist/theme/paint-guard.d.ts.map +1 -0
- package/dist/theme/paint-guard.js +120 -0
- package/dist/theme/paint-guard.js.map +1 -0
- package/dist/theme/picks.d.ts +22 -0
- package/dist/theme/picks.d.ts.map +1 -0
- package/dist/theme/picks.js +43 -0
- package/dist/theme/picks.js.map +1 -0
- package/dist/theme/pref.d.ts +39 -0
- package/dist/theme/pref.d.ts.map +1 -0
- package/dist/theme/pref.js +129 -0
- package/dist/theme/pref.js.map +1 -0
- package/dist/theme/provider.d.ts +41 -0
- package/dist/theme/provider.d.ts.map +1 -0
- package/dist/theme/provider.js +103 -0
- package/dist/theme/provider.js.map +1 -0
- package/dist/theme/store.d.ts +104 -0
- package/dist/theme/store.d.ts.map +1 -0
- package/dist/theme/store.js +509 -0
- package/dist/theme/store.js.map +1 -0
- package/package.json +94 -3
- package/styles.css +79 -0
- package/theme.css +186 -0
- package/vendor/shadcn-tailwind.css +664 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { type RefObject } from "react";
|
|
2
|
+
/** Page coordinates of the thing to be revealed. */
|
|
3
|
+
export type ScrollBlock = {
|
|
4
|
+
top: number;
|
|
5
|
+
height: number;
|
|
6
|
+
};
|
|
7
|
+
/** Viewport coordinates of the strip no overlay covers. */
|
|
8
|
+
export type UsableViewport = {
|
|
9
|
+
top: number;
|
|
10
|
+
height: number;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* `"auto"` centres a block that fits and tops-aligns one that does not;
|
|
14
|
+
* `"start"` demands the top edge even when the block would fit, which is what
|
|
15
|
+
* a file diff wants — its path header under the toolbar (T-190 §5).
|
|
16
|
+
*/
|
|
17
|
+
export type RevealMode = "auto" | "start";
|
|
18
|
+
/** Which `scrollIntoView` alignment reveals as much of `block` as it can. */
|
|
19
|
+
export declare function blockFor(block: ScrollBlock, usable: UsableViewport, mode?: RevealMode): ScrollLogicalPosition;
|
|
20
|
+
/**
|
|
21
|
+
* Where the page comes to rest once `scrollIntoView` has placed `block`.
|
|
22
|
+
* ↑↓ and the counter read this instead of performing the scroll, so the number
|
|
23
|
+
* on screen cannot disagree with where the arrow lands (T-61).
|
|
24
|
+
*/
|
|
25
|
+
export declare function restingScrollY(block: ScrollBlock, usable: UsableViewport, mode?: RevealMode): number;
|
|
26
|
+
/**
|
|
27
|
+
* Read back off `<html>` rather than passed down: the calls that land a target
|
|
28
|
+
* sit deep inside components that know nothing about the page's overlays, and
|
|
29
|
+
* `scroll-padding` is already the value the engine itself obeys.
|
|
30
|
+
*/
|
|
31
|
+
export declare function usableViewport(): UsableViewport;
|
|
32
|
+
/**
|
|
33
|
+
* Open every closed `<details>` between `el` and the document root.
|
|
34
|
+
*
|
|
35
|
+
* A target inside a shut fold has no box at all, so `scrollIntoView` on it
|
|
36
|
+
* does nothing and reports nothing.
|
|
37
|
+
*/
|
|
38
|
+
export declare function openEnclosingFolds(el: Element): void;
|
|
39
|
+
/**
|
|
40
|
+
* Bring `el` into the strip no overlay covers, and flash it. The one landing
|
|
41
|
+
* out of which every anchor, ↑↓ step and per-file jump is served.
|
|
42
|
+
*/
|
|
43
|
+
export declare function revealBlock(el: HTMLElement, { mode, behavior, flash: highlight, }?: {
|
|
44
|
+
mode?: RevealMode;
|
|
45
|
+
behavior?: ScrollBehavior;
|
|
46
|
+
flash?: boolean;
|
|
47
|
+
}): void;
|
|
48
|
+
/**
|
|
49
|
+
* Whether an untouched reader is being held on a particular element, as
|
|
50
|
+
* opposed to the end of the document or nothing at all. Following a new item
|
|
51
|
+
* at the end should not take the reader off a target they were sent to.
|
|
52
|
+
*/
|
|
53
|
+
export declare function isHoldingTarget(): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Hold `el` where `revealBlock` put it, re-revealing it without the flash
|
|
56
|
+
* every time `container` resizes; see `hold`.
|
|
57
|
+
*/
|
|
58
|
+
export declare function holdRevealed(el: HTMLElement, container: Element, mode?: RevealMode, behavior?: ScrollBehavior): () => void;
|
|
59
|
+
/** Go to the end of the document and stay there; see `hold`. */
|
|
60
|
+
export declare function landAtBottom(): () => void;
|
|
61
|
+
/**
|
|
62
|
+
* Keep the release of the last hold this component started, and call it on
|
|
63
|
+
* unmount: a page left without input would otherwise go on being held.
|
|
64
|
+
*/
|
|
65
|
+
export declare function useOwnHold(): (release: () => void) => void;
|
|
66
|
+
export type ScrollInsetSources = {
|
|
67
|
+
/** Overlays pinned to the viewport's top edge, a fixed app header included. */
|
|
68
|
+
top?: ReadonlyArray<RefObject<HTMLElement | null>>;
|
|
69
|
+
bottom?: ReadonlyArray<RefObject<HTMLElement | null>>;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Declare this page's overlays, so every `scrollIntoView` on it lands clear of
|
|
73
|
+
* them.
|
|
74
|
+
*
|
|
75
|
+
* `useLayoutEffect`, not `useEffect`: an anchor that scrolls from a passive
|
|
76
|
+
* effect in a child runs before any passive effect here, and a one-shot guard
|
|
77
|
+
* there never offers a second chance. Layout effects run ahead of the whole
|
|
78
|
+
* passive pass, so the insets are always in place first.
|
|
79
|
+
*
|
|
80
|
+
* The elements are measured directly rather than through `useElementHeight`,
|
|
81
|
+
* whose state holds a fallback for one commit — 56 against a real 93 on a
|
|
82
|
+
* narrow screen, exactly across the frame a hard refresh lands in.
|
|
83
|
+
*
|
|
84
|
+
* No overlay is added implicitly: a fixed header is one more ref in `top`.
|
|
85
|
+
* What an on-screen keyboard covers is counted on its own, from the visual
|
|
86
|
+
* viewport. The landing flash is `.anchor-flash` from `@orz/ui/styles.css`.
|
|
87
|
+
*/
|
|
88
|
+
export declare function useScrollInsets({ top, bottom, }: ScrollInsetSources): void;
|
|
89
|
+
//# sourceMappingURL=scroll-insets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scroll-insets.d.ts","sourceRoot":"","sources":["../../src/hooks/scroll-insets.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,SAAS,EAKf,MAAM,OAAO,CAAC;AAMf,oDAAoD;AACpD,MAAM,MAAM,WAAW,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1D,2DAA2D;AAC3D,MAAM,MAAM,cAAc,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE7D;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,OAAO,CAAC;AAK1C,6EAA6E;AAC7E,wBAAgB,QAAQ,CACtB,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,cAAc,EACtB,IAAI,GAAE,UAAmB,GACxB,qBAAqB,CAMvB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,cAAc,EACtB,IAAI,GAAE,UAAmB,GACxB,MAAM,CAGR;AAQD;;;;GAIG;AACH,wBAAgB,cAAc,IAAI,cAAc,CAK/C;AAeD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAOpD;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACzB,EAAE,EAAE,WAAW,EACf,EACE,IAAa,EACb,QAAQ,EACR,KAAK,EAAE,SAAgB,GACxB,GAAE;IACD,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC;CACZ,GACL,IAAI,CAUN;AAQD;;;;GAIG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAyCD;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,EAAE,EAAE,WAAW,EACf,SAAS,EAAE,OAAO,EAClB,IAAI,GAAE,UAAmB,EACzB,QAAQ,CAAC,EAAE,cAAc,GACxB,MAAM,IAAI,CAMZ;AAcD,gEAAgE;AAChE,wBAAgB,YAAY,IAAI,MAAM,IAAI,CAGzC;AAED;;;GAGG;AACH,wBAAgB,UAAU,IAAI,CAAC,OAAO,EAAE,MAAM,IAAI,KAAK,IAAI,CAO1D;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,+EAA+E;IAC/E,GAAG,CAAC,EAAE,aAAa,CAAC,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC,CAAC;IACnD,MAAM,CAAC,EAAE,aAAa,CAAC,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC,CAAC;CACvD,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,eAAe,CAAC,EAC9B,GAAQ,EACR,MAAW,GACZ,EAAE,kBAAkB,GAAG,IAAI,CAoF3B"}
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import { useCallback, useEffect, useLayoutEffect, useRef, } from "react";
|
|
2
|
+
import { VIEWPORT_CHROME_EVENT, visualViewportInsets, } from "./viewport-chrome.js";
|
|
3
|
+
/** Gap between an overlay's edge and whatever lands against it. */
|
|
4
|
+
const BREATHING_ROOM = 8;
|
|
5
|
+
/** Which `scrollIntoView` alignment reveals as much of `block` as it can. */
|
|
6
|
+
export function blockFor(block, usable, mode = "auto") {
|
|
7
|
+
if (mode === "start")
|
|
8
|
+
return "start";
|
|
9
|
+
// Overlays can leave nothing over — a long draft in the composer takes the
|
|
10
|
+
// strip past zero — and centring in a negative strip aims above its own top.
|
|
11
|
+
if (usable.height <= 0)
|
|
12
|
+
return "start";
|
|
13
|
+
return block.height <= usable.height ? "center" : "start";
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Where the page comes to rest once `scrollIntoView` has placed `block`.
|
|
17
|
+
* ↑↓ and the counter read this instead of performing the scroll, so the number
|
|
18
|
+
* on screen cannot disagree with where the arrow lands (T-61).
|
|
19
|
+
*/
|
|
20
|
+
export function restingScrollY(block, usable, mode = "auto") {
|
|
21
|
+
if (blockFor(block, usable, mode) === "start")
|
|
22
|
+
return block.top - usable.top;
|
|
23
|
+
return block.top + block.height / 2 - (usable.top + usable.height / 2);
|
|
24
|
+
}
|
|
25
|
+
/** `auto` and anything unparseable both mean "no overlay on that edge". */
|
|
26
|
+
function pixelsOf(value) {
|
|
27
|
+
const parsed = Number.parseFloat(value);
|
|
28
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Read back off `<html>` rather than passed down: the calls that land a target
|
|
32
|
+
* sit deep inside components that know nothing about the page's overlays, and
|
|
33
|
+
* `scroll-padding` is already the value the engine itself obeys.
|
|
34
|
+
*/
|
|
35
|
+
export function usableViewport() {
|
|
36
|
+
const style = getComputedStyle(document.documentElement);
|
|
37
|
+
const top = pixelsOf(style.scrollPaddingTop);
|
|
38
|
+
const bottom = pixelsOf(style.scrollPaddingBottom);
|
|
39
|
+
return { top, height: window.innerHeight - top - bottom };
|
|
40
|
+
}
|
|
41
|
+
/** One-shot highlight; restartable when the same target is revealed again. */
|
|
42
|
+
function flash(el) {
|
|
43
|
+
el.classList.remove("anchor-flash");
|
|
44
|
+
// Reflow so removing+adding the class restarts the animation.
|
|
45
|
+
void el.offsetWidth;
|
|
46
|
+
el.classList.add("anchor-flash");
|
|
47
|
+
el.addEventListener("animationend", () => el.classList.remove("anchor-flash"), { once: true });
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Open every closed `<details>` between `el` and the document root.
|
|
51
|
+
*
|
|
52
|
+
* A target inside a shut fold has no box at all, so `scrollIntoView` on it
|
|
53
|
+
* does nothing and reports nothing.
|
|
54
|
+
*/
|
|
55
|
+
export function openEnclosingFolds(el) {
|
|
56
|
+
for (let from = el.parentElement; from !== null;) {
|
|
57
|
+
const fold = from.closest("details:not([open])");
|
|
58
|
+
if (fold === null)
|
|
59
|
+
return;
|
|
60
|
+
fold.setAttribute("open", "");
|
|
61
|
+
from = fold.parentElement;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Bring `el` into the strip no overlay covers, and flash it. The one landing
|
|
66
|
+
* out of which every anchor, ↑↓ step and per-file jump is served.
|
|
67
|
+
*/
|
|
68
|
+
export function revealBlock(el, { mode = "auto", behavior, flash: highlight = true, } = {}) {
|
|
69
|
+
openEnclosingFolds(el);
|
|
70
|
+
const rect = el.getBoundingClientRect();
|
|
71
|
+
const block = blockFor({ top: rect.top + window.scrollY, height: rect.height }, usableViewport(), mode);
|
|
72
|
+
el.scrollIntoView({ block, behavior });
|
|
73
|
+
if (highlight)
|
|
74
|
+
flash(el);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* The page's one hold. Two at once would each put the viewport back on its
|
|
78
|
+
* own target at every resize, so a newer landing retires the older one.
|
|
79
|
+
*/
|
|
80
|
+
let held = null;
|
|
81
|
+
/**
|
|
82
|
+
* Whether an untouched reader is being held on a particular element, as
|
|
83
|
+
* opposed to the end of the document or nothing at all. Following a new item
|
|
84
|
+
* at the end should not take the reader off a target they were sent to.
|
|
85
|
+
*/
|
|
86
|
+
export function isHoldingTarget() {
|
|
87
|
+
return held !== null && !held.onEnd;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Run `place` again every time `container` resizes, until the reader's first
|
|
91
|
+
* input. Returns the release, for when the landing stops mattering first.
|
|
92
|
+
*
|
|
93
|
+
* A landing is made against the page as it stands, and the page keeps
|
|
94
|
+
* arriving after it: images, diffs, attachment lists, each pushing the target
|
|
95
|
+
* away from where it was put. After the first input, re-placing would fight
|
|
96
|
+
* the reader. There is no settle timeout: late content lands with unbounded
|
|
97
|
+
* gaps, and a timer that fires inside one re-opens the race.
|
|
98
|
+
*
|
|
99
|
+
* Dragging the scrollbar counts as input: Chromium and Firefox both deliver
|
|
100
|
+
* its `pointerdown` to `<html>`.
|
|
101
|
+
*/
|
|
102
|
+
function hold(container, place, onEnd = false) {
|
|
103
|
+
held?.release();
|
|
104
|
+
if (typeof ResizeObserver === "undefined")
|
|
105
|
+
return () => { }; // happy-dom
|
|
106
|
+
const controller = new AbortController();
|
|
107
|
+
const observer = new ResizeObserver(() => place(release));
|
|
108
|
+
const release = () => {
|
|
109
|
+
observer.disconnect();
|
|
110
|
+
controller.abort();
|
|
111
|
+
if (held?.release === release)
|
|
112
|
+
held = null;
|
|
113
|
+
};
|
|
114
|
+
observer.observe(container);
|
|
115
|
+
for (const type of ["wheel", "touchstart", "pointerdown", "keydown"]) {
|
|
116
|
+
window.addEventListener(type, release, {
|
|
117
|
+
capture: true,
|
|
118
|
+
passive: true,
|
|
119
|
+
signal: controller.signal,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
held = { release, onEnd };
|
|
123
|
+
return release;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Hold `el` where `revealBlock` put it, re-revealing it without the flash
|
|
127
|
+
* every time `container` resizes; see `hold`.
|
|
128
|
+
*/
|
|
129
|
+
export function holdRevealed(el, container, mode = "auto", behavior) {
|
|
130
|
+
return hold(container, (release) => {
|
|
131
|
+
// Gone with a route change nobody touched the page for.
|
|
132
|
+
if (!el.isConnected)
|
|
133
|
+
release();
|
|
134
|
+
else
|
|
135
|
+
revealBlock(el, { mode, behavior, flash: false });
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Bottom of the document, which sits below a sticky composer's in-flow spot.
|
|
140
|
+
*
|
|
141
|
+
* The largest offset there is, not `scrollHeight`: iOS Safari takes the
|
|
142
|
+
* overshoot literally for a frame, parking the visual viewport a whole screen
|
|
143
|
+
* past the end — one blank white frame on every landing.
|
|
144
|
+
*/
|
|
145
|
+
function scrollToEnd() {
|
|
146
|
+
const root = document.documentElement;
|
|
147
|
+
window.scrollTo(0, Math.max(0, root.scrollHeight - root.clientHeight));
|
|
148
|
+
}
|
|
149
|
+
/** Go to the end of the document and stay there; see `hold`. */
|
|
150
|
+
export function landAtBottom() {
|
|
151
|
+
scrollToEnd();
|
|
152
|
+
return hold(document.body, scrollToEnd, true);
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Keep the release of the last hold this component started, and call it on
|
|
156
|
+
* unmount: a page left without input would otherwise go on being held.
|
|
157
|
+
*/
|
|
158
|
+
export function useOwnHold() {
|
|
159
|
+
const own = useRef(() => { });
|
|
160
|
+
useEffect(() => () => own.current(), []);
|
|
161
|
+
return useCallback((release) => {
|
|
162
|
+
own.current();
|
|
163
|
+
own.current = release;
|
|
164
|
+
}, []);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Declare this page's overlays, so every `scrollIntoView` on it lands clear of
|
|
168
|
+
* them.
|
|
169
|
+
*
|
|
170
|
+
* `useLayoutEffect`, not `useEffect`: an anchor that scrolls from a passive
|
|
171
|
+
* effect in a child runs before any passive effect here, and a one-shot guard
|
|
172
|
+
* there never offers a second chance. Layout effects run ahead of the whole
|
|
173
|
+
* passive pass, so the insets are always in place first.
|
|
174
|
+
*
|
|
175
|
+
* The elements are measured directly rather than through `useElementHeight`,
|
|
176
|
+
* whose state holds a fallback for one commit — 56 against a real 93 on a
|
|
177
|
+
* narrow screen, exactly across the frame a hard refresh lands in.
|
|
178
|
+
*
|
|
179
|
+
* No overlay is added implicitly: a fixed header is one more ref in `top`.
|
|
180
|
+
* What an on-screen keyboard covers is counted on its own, from the visual
|
|
181
|
+
* viewport. The landing flash is `.anchor-flash` from `@orz/ui/styles.css`.
|
|
182
|
+
*/
|
|
183
|
+
export function useScrollInsets({ top = [], bottom = [], }) {
|
|
184
|
+
const sources = useRef({ top, bottom });
|
|
185
|
+
const remeasure = useRef(() => { });
|
|
186
|
+
useLayoutEffect(() => {
|
|
187
|
+
const root = document.documentElement;
|
|
188
|
+
const observed = new Set();
|
|
189
|
+
let observer = null;
|
|
190
|
+
const watch = (el) => {
|
|
191
|
+
if (observed.has(el))
|
|
192
|
+
return;
|
|
193
|
+
observed.add(el);
|
|
194
|
+
observer?.observe(el);
|
|
195
|
+
};
|
|
196
|
+
const measure = () => {
|
|
197
|
+
// A caret inside a sticky overlay always sits within that overlay's own
|
|
198
|
+
// inset, and Chrome's caret reveal honours scroll-padding: it scrolled
|
|
199
|
+
// the page on every typed character, the overlay riding along, so the
|
|
200
|
+
// caret was never "revealed". Nothing inside an overlay can be hidden
|
|
201
|
+
// behind it, so the one holding focus stops counting.
|
|
202
|
+
const focused = document.activeElement;
|
|
203
|
+
const extent = (el) => focused !== null && el.contains(focused)
|
|
204
|
+
? 0
|
|
205
|
+
: el.getBoundingClientRect().height;
|
|
206
|
+
let overlays = 0;
|
|
207
|
+
let bottomInset = 0;
|
|
208
|
+
for (const el of sources.current.top.map((r) => r.current)) {
|
|
209
|
+
if (el === null)
|
|
210
|
+
continue;
|
|
211
|
+
overlays += extent(el);
|
|
212
|
+
watch(el);
|
|
213
|
+
}
|
|
214
|
+
for (const el of sources.current.bottom.map((r) => r.current)) {
|
|
215
|
+
if (el === null)
|
|
216
|
+
continue;
|
|
217
|
+
bottomInset += extent(el);
|
|
218
|
+
watch(el);
|
|
219
|
+
}
|
|
220
|
+
// A keyboard covers the layout viewport's bottom and can pan its top
|
|
221
|
+
// out of view; sticky edges follow it, and so must the padding, or a
|
|
222
|
+
// reveal would centre its target behind the keyboard. A header
|
|
223
|
+
// useAutoHideHeader has slid partly away covers that much less.
|
|
224
|
+
const edges = visualViewportInsets();
|
|
225
|
+
const slid = pixelsOf(root.style.getPropertyValue("--header-hide"));
|
|
226
|
+
const topInset = BREATHING_ROOM + edges.top + Math.max(0, overlays - slid);
|
|
227
|
+
bottomInset += edges.bottom;
|
|
228
|
+
root.style.scrollPaddingTop = `${topInset}px`;
|
|
229
|
+
root.style.scrollPaddingBottom = `${bottomInset}px`;
|
|
230
|
+
};
|
|
231
|
+
observer =
|
|
232
|
+
typeof ResizeObserver === "undefined"
|
|
233
|
+
? null
|
|
234
|
+
: new ResizeObserver(measure);
|
|
235
|
+
remeasure.current = measure;
|
|
236
|
+
measure();
|
|
237
|
+
window.addEventListener("resize", measure);
|
|
238
|
+
window.addEventListener(VIEWPORT_CHROME_EVENT, measure);
|
|
239
|
+
// A keyboard opening resizes only the visual viewport, never the window.
|
|
240
|
+
const vv = window.visualViewport;
|
|
241
|
+
vv?.addEventListener("resize", measure);
|
|
242
|
+
vv?.addEventListener("scroll", measure);
|
|
243
|
+
document.addEventListener("focusin", measure);
|
|
244
|
+
document.addEventListener("focusout", measure);
|
|
245
|
+
return () => {
|
|
246
|
+
window.removeEventListener("resize", measure);
|
|
247
|
+
window.removeEventListener(VIEWPORT_CHROME_EVENT, measure);
|
|
248
|
+
vv?.removeEventListener("resize", measure);
|
|
249
|
+
vv?.removeEventListener("scroll", measure);
|
|
250
|
+
document.removeEventListener("focusin", measure);
|
|
251
|
+
document.removeEventListener("focusout", measure);
|
|
252
|
+
observer?.disconnect();
|
|
253
|
+
root.style.removeProperty("scroll-padding-top");
|
|
254
|
+
root.style.removeProperty("scroll-padding-bottom");
|
|
255
|
+
};
|
|
256
|
+
}, []);
|
|
257
|
+
// An overlay that mounts later — a composer opening, one arriving with the
|
|
258
|
+
// data it belongs to — had a null ref when the effect above ran, and nothing
|
|
259
|
+
// observes an element that does not exist yet.
|
|
260
|
+
useLayoutEffect(() => {
|
|
261
|
+
sources.current = { top, bottom };
|
|
262
|
+
remeasure.current();
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
//# sourceMappingURL=scroll-insets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scroll-insets.js","sourceRoot":"","sources":["../../src/hooks/scroll-insets.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The live height of one element, for anything that has to sit directly
|
|
3
|
+
* beneath it — a header that gains a second row on narrow screens has a
|
|
4
|
+
* height no CSS offset can name. `fallback` stands in until the first
|
|
5
|
+
* measurement, and for good when `target` finds nothing.
|
|
6
|
+
*
|
|
7
|
+
* `target` is asked once, after mount (`() => ref.current`, or a
|
|
8
|
+
* `querySelector`), so it may be a fresh closure every render.
|
|
9
|
+
*/
|
|
10
|
+
export declare function useElementHeight(target: () => Element | null, fallback: number): number;
|
|
11
|
+
//# sourceMappingURL=use-element-height.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-element-height.d.ts","sourceRoot":"","sources":["../../src/hooks/use-element-height.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,OAAO,GAAG,IAAI,EAC5B,QAAQ,EAAE,MAAM,GACf,MAAM,CAuBR"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* The live height of one element, for anything that has to sit directly
|
|
4
|
+
* beneath it — a header that gains a second row on narrow screens has a
|
|
5
|
+
* height no CSS offset can name. `fallback` stands in until the first
|
|
6
|
+
* measurement, and for good when `target` finds nothing.
|
|
7
|
+
*
|
|
8
|
+
* `target` is asked once, after mount (`() => ref.current`, or a
|
|
9
|
+
* `querySelector`), so it may be a fresh closure every render.
|
|
10
|
+
*/
|
|
11
|
+
export function useElementHeight(target, fallback) {
|
|
12
|
+
const [height, setHeight] = useState(fallback);
|
|
13
|
+
const find = useRef(target);
|
|
14
|
+
find.current = target;
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
const element = find.current();
|
|
17
|
+
if (element === null)
|
|
18
|
+
return;
|
|
19
|
+
const measure = () => setHeight(element.getBoundingClientRect().height);
|
|
20
|
+
measure();
|
|
21
|
+
window.addEventListener("resize", measure);
|
|
22
|
+
const observer = typeof ResizeObserver === "undefined"
|
|
23
|
+
? null
|
|
24
|
+
: new ResizeObserver(measure);
|
|
25
|
+
observer?.observe(element);
|
|
26
|
+
return () => {
|
|
27
|
+
window.removeEventListener("resize", measure);
|
|
28
|
+
observer?.disconnect();
|
|
29
|
+
};
|
|
30
|
+
}, []);
|
|
31
|
+
return height;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=use-element-height.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-element-height.js","sourceRoot":"","sources":["../../src/hooks/use-element-height.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEpD;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAC9B,MAA4B,EAC5B,QAAgB;IAEhB,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC/C,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IAC5B,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;IAEtB,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAC/B,IAAI,OAAO,KAAK,IAAI;YAAE,OAAO;QAC7B,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,qBAAqB,EAAE,CAAC,MAAM,CAAC,CAAC;QACxE,OAAO,EAAE,CAAC;QACV,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC3C,MAAM,QAAQ,GACZ,OAAO,cAAc,KAAK,WAAW;YACnC,CAAC,CAAC,IAAI;YACN,CAAC,CAAC,IAAI,cAAc,CAAC,OAAO,CAAC,CAAC;QAClC,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;QAC3B,OAAO,GAAG,EAAE;YACV,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YAC9C,QAAQ,EAAE,UAAU,EAAE,CAAC;QACzB,CAAC,CAAC;IACJ,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** Tailwind's `md` and `sm`. The one place these breakpoints are written outside CSS. */
|
|
2
|
+
export declare const MD_UP = "(min-width: 768px)";
|
|
3
|
+
export declare const SM_UP = "(min-width: 640px)";
|
|
4
|
+
/**
|
|
5
|
+
* A mouse-like primary pointer. Asked this way round, and about `pointer`
|
|
6
|
+
* rather than `any-pointer`, for two reasons:
|
|
7
|
+
*
|
|
8
|
+
* - the fallback below answers `true` to everything, so the query has to be
|
|
9
|
+
* the one whose `true` is the desktop branch;
|
|
10
|
+
* - `any-pointer: coarse` flips a touchscreen laptop, whose primary pointer
|
|
11
|
+
* is a mouse, onto the touch branch for good.
|
|
12
|
+
*/
|
|
13
|
+
export declare const POINTER_FINE = "(pointer: fine)";
|
|
14
|
+
/**
|
|
15
|
+
* Whether `query` matches, re-rendering when the answer changes.
|
|
16
|
+
*
|
|
17
|
+
* The snapshot is read during render rather than from an effect, so the
|
|
18
|
+
* first frame already branches the right way. An effect would paint one
|
|
19
|
+
* branch and correct it a frame later, which reads as a flash.
|
|
20
|
+
*/
|
|
21
|
+
export declare function useMediaQuery(query: string): boolean;
|
|
22
|
+
//# sourceMappingURL=use-media-query.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-media-query.d.ts","sourceRoot":"","sources":["../../src/hooks/use-media-query.ts"],"names":[],"mappings":"AAEA,yFAAyF;AACzF,eAAO,MAAM,KAAK,uBAAuB,CAAC;AAC1C,eAAO,MAAM,KAAK,uBAAuB,CAAC;AAE1C;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY,oBAAoB,CAAC;AAQ9C;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAWpD"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { useCallback, useSyncExternalStore } from "react";
|
|
2
|
+
/** Tailwind's `md` and `sm`. The one place these breakpoints are written outside CSS. */
|
|
3
|
+
export const MD_UP = "(min-width: 768px)";
|
|
4
|
+
export const SM_UP = "(min-width: 640px)";
|
|
5
|
+
/**
|
|
6
|
+
* A mouse-like primary pointer. Asked this way round, and about `pointer`
|
|
7
|
+
* rather than `any-pointer`, for two reasons:
|
|
8
|
+
*
|
|
9
|
+
* - the fallback below answers `true` to everything, so the query has to be
|
|
10
|
+
* the one whose `true` is the desktop branch;
|
|
11
|
+
* - `any-pointer: coarse` flips a touchscreen laptop, whose primary pointer
|
|
12
|
+
* is a mouse, onto the touch branch for good.
|
|
13
|
+
*/
|
|
14
|
+
export const POINTER_FINE = "(pointer: fine)";
|
|
15
|
+
/** Engines without `matchMedia` get the wide branch, the desktop one. */
|
|
16
|
+
function evaluate(query) {
|
|
17
|
+
if (typeof window.matchMedia !== "function")
|
|
18
|
+
return true;
|
|
19
|
+
return window.matchMedia(query).matches;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Whether `query` matches, re-rendering when the answer changes.
|
|
23
|
+
*
|
|
24
|
+
* The snapshot is read during render rather than from an effect, so the
|
|
25
|
+
* first frame already branches the right way. An effect would paint one
|
|
26
|
+
* branch and correct it a frame later, which reads as a flash.
|
|
27
|
+
*/
|
|
28
|
+
export function useMediaQuery(query) {
|
|
29
|
+
const subscribe = useCallback((onStoreChange) => {
|
|
30
|
+
if (typeof window.matchMedia !== "function")
|
|
31
|
+
return () => { };
|
|
32
|
+
const list = window.matchMedia(query);
|
|
33
|
+
list.addEventListener("change", onStoreChange);
|
|
34
|
+
return () => list.removeEventListener("change", onStoreChange);
|
|
35
|
+
}, [query]);
|
|
36
|
+
return useSyncExternalStore(subscribe, () => evaluate(query));
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=use-media-query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-media-query.js","sourceRoot":"","sources":["../../src/hooks/use-media-query.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAE1D,yFAAyF;AACzF,MAAM,CAAC,MAAM,KAAK,GAAG,oBAAoB,CAAC;AAC1C,MAAM,CAAC,MAAM,KAAK,GAAG,oBAAoB,CAAC;AAE1C;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,iBAAiB,CAAC;AAE9C,yEAAyE;AACzE,SAAS,QAAQ,CAAC,KAAa;IAC7B,IAAI,OAAO,MAAM,CAAC,UAAU,KAAK,UAAU;QAAE,OAAO,IAAI,CAAC;IACzD,OAAO,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC;AAC1C,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,MAAM,SAAS,GAAG,WAAW,CAC3B,CAAC,aAAyB,EAAE,EAAE;QAC5B,IAAI,OAAO,MAAM,CAAC,UAAU,KAAK,UAAU;YAAE,OAAO,GAAG,EAAE,GAAE,CAAC,CAAC;QAC7D,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QACtC,IAAI,CAAC,gBAAgB,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;QAC/C,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,mBAAmB,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;IACjE,CAAC,EACD,CAAC,KAAK,CAAC,CACR,CAAC;IACF,OAAO,oBAAoB,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AAChE,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type PartialOptions } from "overlayscrollbars";
|
|
2
|
+
/**
|
|
3
|
+
* Overlay scrollbars for a scroll container that stays exactly as it is: the
|
|
4
|
+
* element `viewport` is on keeps its own classes, its own children and its own
|
|
5
|
+
* native scrolling, and the bars are drawn in `slot`, a positioned parent
|
|
6
|
+
* wrapped directly around it. Needs the `overlayscrollbars` peer, and the
|
|
7
|
+
* consumer imports `overlayscrollbars/overlayscrollbars.css` itself.
|
|
8
|
+
*
|
|
9
|
+
* Both refs are needed. Letting the library build its own viewport moves the
|
|
10
|
+
* children into an inserted div, where the container's `flex gap` no longer
|
|
11
|
+
* reaches them; leaving out the slot leaves the bars inside the scroll
|
|
12
|
+
* container, where they scroll away with the content. A slot further out than
|
|
13
|
+
* the immediate parent draws the bar over whatever else it spans.
|
|
14
|
+
*
|
|
15
|
+
* `ready` withholds the instance until the caller's content is in the DOM.
|
|
16
|
+
* `autoHideSuspend` shows the bar once on arrival — but it only arms when the
|
|
17
|
+
* element already overflows at the moment the instance is created, and a
|
|
18
|
+
* container whose content is still in flight does not. Initializing on mount
|
|
19
|
+
* costs that one reveal outright. Until then the element scrolls natively.
|
|
20
|
+
*
|
|
21
|
+
* `options` go over the defaults above. A container that must never scroll
|
|
22
|
+
* sideways passes `{ overflow: { x: "hidden" } }`: Tailwind's
|
|
23
|
+
* `overflow-y-auto` leaves x computing to `auto`. Pass a stable object — a new
|
|
24
|
+
* identity is applied with `instance.options()`, which costs an update, though
|
|
25
|
+
* never a re-initialization.
|
|
26
|
+
*/
|
|
27
|
+
export declare function useOverlayScrollbars(ready: boolean, options?: PartialOptions): {
|
|
28
|
+
slot: import("react").RefObject<HTMLDivElement | null>;
|
|
29
|
+
viewport: import("react").RefObject<HTMLDivElement | null>;
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=use-overlay-scrollbars.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-overlay-scrollbars.d.ts","sourceRoot":"","sources":["../../src/hooks/use-overlay-scrollbars.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAqB3E;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,cAAc;;;EAuC5E"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { OverlayScrollbars } from "overlayscrollbars";
|
|
2
|
+
import { useEffect, useRef } from "react";
|
|
3
|
+
const DEFAULTS = {
|
|
4
|
+
theme: "os-theme-orz",
|
|
5
|
+
autoHide: "leave",
|
|
6
|
+
autoHideSuspend: true,
|
|
7
|
+
// `false`, the library's default, makes a track click do nothing at all —
|
|
8
|
+
// less than the native behaviour it replaces. Paging instead of jumping
|
|
9
|
+
// would cost a `ClickScrollPlugin` registration.
|
|
10
|
+
clickScroll: "instant",
|
|
11
|
+
};
|
|
12
|
+
/** One level deep, so a caller's `scrollbars` adds to the defaults rather than replacing them. */
|
|
13
|
+
function merged(options) {
|
|
14
|
+
return {
|
|
15
|
+
...options,
|
|
16
|
+
scrollbars: { ...DEFAULTS, ...options?.scrollbars },
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Overlay scrollbars for a scroll container that stays exactly as it is: the
|
|
21
|
+
* element `viewport` is on keeps its own classes, its own children and its own
|
|
22
|
+
* native scrolling, and the bars are drawn in `slot`, a positioned parent
|
|
23
|
+
* wrapped directly around it. Needs the `overlayscrollbars` peer, and the
|
|
24
|
+
* consumer imports `overlayscrollbars/overlayscrollbars.css` itself.
|
|
25
|
+
*
|
|
26
|
+
* Both refs are needed. Letting the library build its own viewport moves the
|
|
27
|
+
* children into an inserted div, where the container's `flex gap` no longer
|
|
28
|
+
* reaches them; leaving out the slot leaves the bars inside the scroll
|
|
29
|
+
* container, where they scroll away with the content. A slot further out than
|
|
30
|
+
* the immediate parent draws the bar over whatever else it spans.
|
|
31
|
+
*
|
|
32
|
+
* `ready` withholds the instance until the caller's content is in the DOM.
|
|
33
|
+
* `autoHideSuspend` shows the bar once on arrival — but it only arms when the
|
|
34
|
+
* element already overflows at the moment the instance is created, and a
|
|
35
|
+
* container whose content is still in flight does not. Initializing on mount
|
|
36
|
+
* costs that one reveal outright. Until then the element scrolls natively.
|
|
37
|
+
*
|
|
38
|
+
* `options` go over the defaults above. A container that must never scroll
|
|
39
|
+
* sideways passes `{ overflow: { x: "hidden" } }`: Tailwind's
|
|
40
|
+
* `overflow-y-auto` leaves x computing to `auto`. Pass a stable object — a new
|
|
41
|
+
* identity is applied with `instance.options()`, which costs an update, though
|
|
42
|
+
* never a re-initialization.
|
|
43
|
+
*/
|
|
44
|
+
export function useOverlayScrollbars(ready, options) {
|
|
45
|
+
const slot = useRef(null);
|
|
46
|
+
const viewport = useRef(null);
|
|
47
|
+
const instance = useRef(null);
|
|
48
|
+
const latest = useRef(options);
|
|
49
|
+
latest.current = options;
|
|
50
|
+
// What the live instance was last given, so the mount does not apply the
|
|
51
|
+
// options it was just created with a second time.
|
|
52
|
+
const applied = useRef(undefined);
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
const slotElement = slot.current;
|
|
55
|
+
const viewportElement = viewport.current;
|
|
56
|
+
if (!ready || slotElement === null || viewportElement === null)
|
|
57
|
+
return;
|
|
58
|
+
const created = OverlayScrollbars({
|
|
59
|
+
target: viewportElement,
|
|
60
|
+
elements: { viewport: viewportElement },
|
|
61
|
+
scrollbars: { slot: slotElement },
|
|
62
|
+
}, merged(latest.current));
|
|
63
|
+
instance.current = created;
|
|
64
|
+
applied.current = latest.current;
|
|
65
|
+
return () => {
|
|
66
|
+
instance.current = null;
|
|
67
|
+
created.destroy();
|
|
68
|
+
};
|
|
69
|
+
}, [ready]);
|
|
70
|
+
useEffect(() => {
|
|
71
|
+
if (instance.current === null || applied.current === options)
|
|
72
|
+
return;
|
|
73
|
+
applied.current = options;
|
|
74
|
+
// Pure, so a key the caller stopped passing falls back to its default
|
|
75
|
+
// instead of keeping the value it was last given.
|
|
76
|
+
instance.current.options(merged(options), true);
|
|
77
|
+
}, [options]);
|
|
78
|
+
return { slot, viewport };
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=use-overlay-scrollbars.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-overlay-scrollbars.js","sourceRoot":"","sources":["../../src/hooks/use-overlay-scrollbars.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAuB,MAAM,mBAAmB,CAAC;AAC3E,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAE1C,MAAM,QAAQ,GAAG;IACf,KAAK,EAAE,cAAc;IACrB,QAAQ,EAAE,OAAO;IACjB,eAAe,EAAE,IAAI;IACrB,0EAA0E;IAC1E,wEAAwE;IACxE,iDAAiD;IACjD,WAAW,EAAE,SAAS;CACyB,CAAC;AAElD,kGAAkG;AAClG,SAAS,MAAM,CAAC,OAAmC;IACjD,OAAO;QACL,GAAG,OAAO;QACV,UAAU,EAAE,EAAE,GAAG,QAAQ,EAAE,GAAG,OAAO,EAAE,UAAU,EAAE;KACpD,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAAc,EAAE,OAAwB;IAC3E,MAAM,IAAI,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IAC1C,MAAM,QAAQ,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IAC9C,MAAM,QAAQ,GAAG,MAAM,CAA2B,IAAI,CAAC,CAAC;IACxD,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IAC/B,MAAM,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,yEAAyE;IACzE,kDAAkD;IAClD,MAAM,OAAO,GAAG,MAAM,CAA6B,SAAS,CAAC,CAAC;IAE9D,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC;QACjC,MAAM,eAAe,GAAG,QAAQ,CAAC,OAAO,CAAC;QACzC,IAAI,CAAC,KAAK,IAAI,WAAW,KAAK,IAAI,IAAI,eAAe,KAAK,IAAI;YAAE,OAAO;QACvE,MAAM,OAAO,GAAG,iBAAiB,CAC/B;YACE,MAAM,EAAE,eAAe;YACvB,QAAQ,EAAE,EAAE,QAAQ,EAAE,eAAe,EAAE;YACvC,UAAU,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE;SAClC,EACD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CACvB,CAAC;QACF,QAAQ,CAAC,OAAO,GAAG,OAAO,CAAC;QAC3B,OAAO,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;QACjC,OAAO,GAAG,EAAE;YACV,QAAQ,CAAC,OAAO,GAAG,IAAI,CAAC;YACxB,OAAO,CAAC,OAAO,EAAE,CAAC;QACpB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IAEZ,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,QAAQ,CAAC,OAAO,KAAK,IAAI,IAAI,OAAO,CAAC,OAAO,KAAK,OAAO;YAAE,OAAO;QACrE,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC;QAC1B,sEAAsE;QACtE,kDAAkD;QAClD,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,CAAC;IAClD,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAEd,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;AAC5B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-paged-append.d.ts","sourceRoot":"","sources":["../../src/hooks/use-paged-append.ts"],"names":[],"mappings":"AAcA,wBAAgB,cAAc,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG;IACnD,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;CAC1C,CA0DA"}
|