@flamingo-stack/openframe-frontend-core 0.0.458 → 0.0.459
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/dist/{chunk-YV2YA3QH.cjs → chunk-6XYHSDCL.cjs} +31 -31
- package/dist/{chunk-YV2YA3QH.cjs.map → chunk-6XYHSDCL.cjs.map} +1 -1
- package/dist/{chunk-VTQSB6QB.cjs → chunk-A2RF7ZG6.cjs} +5 -5
- package/dist/{chunk-VTQSB6QB.cjs.map → chunk-A2RF7ZG6.cjs.map} +1 -1
- package/dist/{chunk-KQGFKG6Y.js → chunk-AS5B343N.js} +2 -2
- package/dist/{chunk-WGJPTFRH.js → chunk-CBNHSXTR.js} +2 -2
- package/dist/{chunk-7IRPMNRL.cjs → chunk-DMU3BSPR.cjs} +59 -59
- package/dist/{chunk-7IRPMNRL.cjs.map → chunk-DMU3BSPR.cjs.map} +1 -1
- package/dist/{chunk-QL7ODLJA.js → chunk-EFGFAVOI.js} +4 -4
- package/dist/{chunk-YQBPIUZU.js → chunk-GSKLTMIY.js} +2 -2
- package/dist/{chunk-DQ3EHM6G.cjs → chunk-IG4QVZSP.cjs} +9 -9
- package/dist/{chunk-DQ3EHM6G.cjs.map → chunk-IG4QVZSP.cjs.map} +1 -1
- package/dist/{chunk-ZHQQRYMB.js → chunk-JGSBLQLE.js} +4 -4
- package/dist/{chunk-6B27O3ZB.js → chunk-JWXOZRZ6.js} +4 -4
- package/dist/{chunk-R5QYMUKN.js → chunk-KW33TBQX.js} +2 -2
- package/dist/{chunk-IDKDOQZL.js → chunk-LDVQIOS7.js} +2 -2
- package/dist/{chunk-H7ETLG65.js → chunk-MRKRE54X.js} +4 -4
- package/dist/{chunk-L676XVP4.cjs → chunk-O5E7ZWHK.cjs} +7 -7
- package/dist/{chunk-L676XVP4.cjs.map → chunk-O5E7ZWHK.cjs.map} +1 -1
- package/dist/{chunk-LDAOPWXZ.cjs → chunk-OFPHMNRL.cjs} +11 -11
- package/dist/{chunk-LDAOPWXZ.cjs.map → chunk-OFPHMNRL.cjs.map} +1 -1
- package/dist/{chunk-ZDJ4ZUQ4.cjs → chunk-OJ5ROJSS.cjs} +37 -37
- package/dist/{chunk-ZDJ4ZUQ4.cjs.map → chunk-OJ5ROJSS.cjs.map} +1 -1
- package/dist/{chunk-HWTUVLYB.js → chunk-Q74TSDZY.js} +2 -2
- package/dist/{chunk-U2YDR5DT.js → chunk-RTQ57HC5.js} +2 -2
- package/dist/{chunk-5USSSRAL.cjs → chunk-T2EBDVMZ.cjs} +26 -26
- package/dist/{chunk-5USSSRAL.cjs.map → chunk-T2EBDVMZ.cjs.map} +1 -1
- package/dist/{chunk-TNLFAJPA.js → chunk-TP5MVWQ2.js} +4721 -4901
- package/dist/chunk-TP5MVWQ2.js.map +1 -0
- package/dist/{chunk-KIIOBK7G.cjs → chunk-WVC627C7.cjs} +26 -26
- package/dist/{chunk-KIIOBK7G.cjs.map → chunk-WVC627C7.cjs.map} +1 -1
- package/dist/{chunk-XUNJILJT.cjs → chunk-X5TAAOE7.cjs} +62 -62
- package/dist/{chunk-XUNJILJT.cjs.map → chunk-X5TAAOE7.cjs.map} +1 -1
- package/dist/{chunk-FTXDIDNX.cjs → chunk-XVHNAMAL.cjs} +15 -15
- package/dist/{chunk-FTXDIDNX.cjs.map → chunk-XVHNAMAL.cjs.map} +1 -1
- package/dist/{chunk-MKLP2SOZ.cjs → chunk-YFPZLP63.cjs} +1196 -1376
- package/dist/chunk-YFPZLP63.cjs.map +1 -0
- package/dist/components/case-studies/index.cjs +8 -8
- package/dist/components/case-studies/index.js +2 -2
- package/dist/components/chart.d.ts +1 -1
- package/dist/components/chat/chat-message-list.d.ts.map +1 -1
- package/dist/components/chat/chat-sidebar.d.ts.map +1 -1
- package/dist/components/chat/chat-ticket-list.d.ts.map +1 -1
- package/dist/components/chat/guide-welcome.d.ts.map +1 -1
- package/dist/components/chat/index.cjs +2 -2
- package/dist/components/chat/index.js +1 -1
- package/dist/components/chat/mingo-chat-history.d.ts.map +1 -1
- package/dist/components/chat/mingo-welcome.d.ts.map +1 -1
- package/dist/components/contact/index.cjs +3 -3
- package/dist/components/contact/index.js +2 -2
- package/dist/components/docs/index.cjs +5 -5
- package/dist/components/docs/index.js +4 -4
- package/dist/components/embeds/index.cjs +3 -3
- package/dist/components/embeds/index.js +2 -2
- package/dist/components/faq/index.cjs +3 -3
- package/dist/components/faq/index.js +2 -2
- package/dist/components/features/index.cjs +2 -2
- package/dist/components/features/index.js +1 -1
- package/dist/components/features/notifications/notification-drawer.d.ts.map +1 -1
- package/dist/components/features/time-tracker/time-tracker-panel.d.ts.map +1 -1
- package/dist/components/help-center-pages/index.cjs +20 -20
- package/dist/components/help-center-pages/index.js +11 -11
- package/dist/components/index.cjs +129 -135
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.js +9 -15
- package/dist/components/index.js.map +1 -1
- package/dist/components/layout/page-container.d.ts.map +1 -1
- package/dist/components/navigation/app-layout-drawer.d.ts +1 -1
- package/dist/components/navigation/index.cjs +2 -2
- package/dist/components/navigation/index.js +1 -1
- package/dist/components/onboarding-guides/index.cjs +5 -5
- package/dist/components/onboarding-guides/index.js +4 -4
- package/dist/components/related-content/index.cjs +3 -3
- package/dist/components/related-content/index.js +2 -2
- package/dist/components/tickets/index.cjs +5 -5
- package/dist/components/tickets/index.js +4 -4
- package/dist/components/ui/drawer.d.ts +1 -1
- package/dist/components/ui/drawer.d.ts.map +1 -1
- package/dist/components/ui/index.cjs +2 -8
- package/dist/components/ui/index.cjs.map +1 -1
- package/dist/components/ui/index.d.ts +0 -1
- package/dist/components/ui/index.d.ts.map +1 -1
- package/dist/components/ui/index.js +1 -7
- package/dist/components/ui/modal-v2.d.ts.map +1 -1
- package/dist/components/ui/modal.d.ts.map +1 -1
- package/dist/index.cjs +2 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -7
- package/package.json +1 -3
- package/src/components/chat/chat-message-list.tsx +6 -7
- package/src/components/chat/chat-sidebar.tsx +4 -9
- package/src/components/chat/chat-ticket-list.tsx +2 -8
- package/src/components/chat/guide-welcome.tsx +4 -6
- package/src/components/chat/mingo-chat-history.tsx +4 -6
- package/src/components/chat/mingo-welcome.tsx +4 -6
- package/src/components/features/notifications/notification-drawer.tsx +4 -8
- package/src/components/features/time-tracker/time-tracker-panel.tsx +3 -11
- package/src/components/layout/page-container.tsx +5 -17
- package/src/components/ui/drawer.tsx +3 -8
- package/src/components/ui/index.ts +0 -1
- package/src/components/ui/modal-v2.tsx +2 -12
- package/src/components/ui/modal.tsx +2 -9
- package/src/styles/index.css +0 -2
- package/dist/chunk-MKLP2SOZ.cjs.map +0 -1
- package/dist/chunk-TNLFAJPA.js.map +0 -1
- package/dist/components/ui/overlay-scroll-area.d.ts +0 -59
- package/dist/components/ui/overlay-scroll-area.d.ts.map +0 -1
- package/src/components/ui/overlay-scroll-area.tsx +0 -219
- package/src/stories/OverlayScrollArea.stories.tsx +0 -52
- package/src/styles/overlay-scrollbars-theme.css +0 -19
- package/src/styles/vendor-overlayscrollbars.css +0 -673
- /package/dist/{chunk-KQGFKG6Y.js.map → chunk-AS5B343N.js.map} +0 -0
- /package/dist/{chunk-WGJPTFRH.js.map → chunk-CBNHSXTR.js.map} +0 -0
- /package/dist/{chunk-QL7ODLJA.js.map → chunk-EFGFAVOI.js.map} +0 -0
- /package/dist/{chunk-YQBPIUZU.js.map → chunk-GSKLTMIY.js.map} +0 -0
- /package/dist/{chunk-ZHQQRYMB.js.map → chunk-JGSBLQLE.js.map} +0 -0
- /package/dist/{chunk-6B27O3ZB.js.map → chunk-JWXOZRZ6.js.map} +0 -0
- /package/dist/{chunk-R5QYMUKN.js.map → chunk-KW33TBQX.js.map} +0 -0
- /package/dist/{chunk-IDKDOQZL.js.map → chunk-LDVQIOS7.js.map} +0 -0
- /package/dist/{chunk-H7ETLG65.js.map → chunk-MRKRE54X.js.map} +0 -0
- /package/dist/{chunk-HWTUVLYB.js.map → chunk-Q74TSDZY.js.map} +0 -0
- /package/dist/{chunk-U2YDR5DT.js.map → chunk-RTQ57HC5.js.map} +0 -0
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
import { type PartialOptions } from 'overlayscrollbars';
|
|
3
|
-
/** True once mounted on a device with a mouse/trackpad-grade pointer. */
|
|
4
|
-
export declare function useFinePointer(): boolean;
|
|
5
|
-
export interface OverlayScrollAreaProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
6
|
-
/** Sizing/box classes of the scroll container (`flex-1 min-h-0`, `max-h-…`,
|
|
7
|
-
* borders, background) — AND paddings. Do NOT include `overflow-*` here.
|
|
8
|
-
*
|
|
9
|
-
* PADDING BELONGS HERE, NOT ON `contentClassName`: OverlayScrollbars owns
|
|
10
|
-
* the viewport's box and writes `padding: 0` inline on it, so a padding
|
|
11
|
-
* class on the viewport is silently dropped (measured — this is why the
|
|
12
|
-
* wrapper components keep passing their consumer `className` to the host). */
|
|
13
|
-
className?: string;
|
|
14
|
-
/** Layout classes for the scrolling element itself (`flex flex-col gap-…`).
|
|
15
|
-
* Children are its direct children, so `gap`/`flex` applies exactly as it
|
|
16
|
-
* did on the old single `overflow-auto` div. Paddings do NOT work here —
|
|
17
|
-
* see `className`. */
|
|
18
|
-
contentClassName?: string;
|
|
19
|
-
/** Receives the actual scrolling element — use for scrollTop/scrollHeight
|
|
20
|
-
* logic and as IntersectionObserver root. Set from the first commit, valid
|
|
21
|
-
* on both the overlay and the native fallback path. */
|
|
22
|
-
viewportRef?: React.Ref<HTMLDivElement>;
|
|
23
|
-
/** Extra OverlayScrollbars options merged over the ODS defaults. */
|
|
24
|
-
options?: PartialOptions;
|
|
25
|
-
children?: React.ReactNode;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Replacement for an `overflow-auto` scroll container with the standardized
|
|
29
|
-
* ODS overlay scrollbar. Split the old scroller's classes: sizing goes to
|
|
30
|
-
* `className`, content layout to `contentClassName`. The inner scroller div
|
|
31
|
-
* is stable across pointer modes — refs and `onScroll` (via the standard
|
|
32
|
-
* HTML props) keep working like on the plain div it replaces.
|
|
33
|
-
*
|
|
34
|
-
* On touch devices (no fine pointer) the overlay layer is never initialized
|
|
35
|
-
* and the inner div scrolls with its native (already overlay) scrollbar.
|
|
36
|
-
*/
|
|
37
|
-
export declare function OverlayScrollArea({ className, contentClassName, viewportRef, options, children, ...props }: OverlayScrollAreaProps): React.JSX.Element;
|
|
38
|
-
export interface GlobalOverlayScrollbarsProps {
|
|
39
|
-
/** Extra OverlayScrollbars options merged over the ODS defaults. */
|
|
40
|
-
options?: PartialOptions;
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Applies the same overlay scrollbar to the PAGE scroller (`<body>`).
|
|
44
|
-
* Render once near the app root (client side). No-op on touch devices.
|
|
45
|
-
*
|
|
46
|
-
* ONLY mount this on APP-SHELL pages whose body barely scrolls — the real
|
|
47
|
-
* scrolling happens in inner `OverlayScrollArea` containers (openframe-frontend,
|
|
48
|
-
* openframe-chat). Do NOT mount it on long scroll-driven documents: the thumb is
|
|
49
|
-
* repositioned from JS on every scroll frame, so on a page whose main thread is
|
|
50
|
-
* already busy with reveal-on-scroll sections, tickers and marquees the scroll
|
|
51
|
-
* visibly stutters. Measured on multi-platform-hub; raising the update debounce
|
|
52
|
-
* (`update.debounce.mutation`/`resize`) did NOT help, which rules out the
|
|
53
|
-
* observer re-measurement and points at the per-frame cost itself — i.e. it is
|
|
54
|
-
* inherent to any JS-drawn scrollbar, not to this library. Such pages keep the
|
|
55
|
-
* native page scrollbar, styled by the ODS `scrollbar-width`/`scrollbar-color`
|
|
56
|
-
* globals; their inner containers can still use `OverlayScrollArea`.
|
|
57
|
-
*/
|
|
58
|
-
export declare function GlobalOverlayScrollbars({ options }?: GlobalOverlayScrollbarsProps): null;
|
|
59
|
-
//# sourceMappingURL=overlay-scroll-area.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"overlay-scroll-area.d.ts","sourceRoot":"","sources":["../../../src/components/ui/overlay-scroll-area.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAqB,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAA;AA+B1E,yEAAyE;AACzE,wBAAgB,cAAc,IAAI,OAAO,CAWxC;AAoBD,MAAM,WAAW,sBAAuB,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IAClF;;;;;;mFAM+E;IAC/E,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;2BAGuB;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;4DAEwD;IACxD,WAAW,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAA;IACvC,oEAAoE;IACpE,OAAO,CAAC,EAAE,cAAc,CAAA;IACxB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC3B;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,SAAS,EACT,gBAAgB,EAChB,WAAW,EACX,OAAO,EACP,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,sBAAsB,qBA8DxB;AAED,MAAM,WAAW,4BAA4B;IAC3C,oEAAoE;IACpE,OAAO,CAAC,EAAE,cAAc,CAAA;CACzB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,uBAAuB,CAAC,EAAE,OAAO,EAAE,GAAE,4BAAiC,QA2BrF"}
|
|
@@ -1,219 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import * as React from 'react'
|
|
4
|
-
import { OverlayScrollbars, type PartialOptions } from 'overlayscrollbars'
|
|
5
|
-
import { cn } from '../../utils/cn'
|
|
6
|
-
|
|
7
|
-
// =============================================================================
|
|
8
|
-
// Standardized macOS-like overlay scrollbars on every platform.
|
|
9
|
-
//
|
|
10
|
-
// OverlayScrollbars hides the native scrollbar and draws a styleable overlay
|
|
11
|
-
// one on top while keeping NATIVE scrolling (wheel, touchpad momentum,
|
|
12
|
-
// keyboard, drag-the-thumb). With `autoHide` the bar shows only while
|
|
13
|
-
// scrolling and fades out when idle — the macOS behavior, now identical on
|
|
14
|
-
// Windows/Linux and for mouse users.
|
|
15
|
-
//
|
|
16
|
-
// Touch devices keep the native scrollbars: mobile bars are already overlay
|
|
17
|
-
// and auto-hiding, so the custom layer is initialized only on fine-pointer
|
|
18
|
-
// devices (desktop / tablet with a mouse).
|
|
19
|
-
// =============================================================================
|
|
20
|
-
|
|
21
|
-
/** Overlay scrollbars are desktop-only; touch keeps native scrolling. */
|
|
22
|
-
const FINE_POINTER_QUERY = '(hover: hover) and (pointer: fine)'
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* `matchMedia` for the fine-pointer query, or `null` where it doesn't exist —
|
|
26
|
-
* jsdom (every consumer's component tests) and non-browser render paths. The
|
|
27
|
-
* whole overlay layer is progressive enhancement, so "can't detect" degrades
|
|
28
|
-
* to the native scrollbar instead of throwing.
|
|
29
|
-
*/
|
|
30
|
-
const matchFinePointer = (): MediaQueryList | null =>
|
|
31
|
-
typeof window !== 'undefined' && typeof window.matchMedia === 'function'
|
|
32
|
-
? window.matchMedia(FINE_POINTER_QUERY)
|
|
33
|
-
: null
|
|
34
|
-
|
|
35
|
-
/** True once mounted on a device with a mouse/trackpad-grade pointer. */
|
|
36
|
-
export function useFinePointer(): boolean {
|
|
37
|
-
const [fine, setFine] = React.useState(false)
|
|
38
|
-
React.useEffect(() => {
|
|
39
|
-
const mq = matchFinePointer()
|
|
40
|
-
if (!mq) return
|
|
41
|
-
setFine(mq.matches)
|
|
42
|
-
const onChange = (e: MediaQueryListEvent) => setFine(e.matches)
|
|
43
|
-
mq.addEventListener('change', onChange)
|
|
44
|
-
return () => mq.removeEventListener('change', onChange)
|
|
45
|
-
}, [])
|
|
46
|
-
return fine
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/** Shared ODS defaults: thin grey thumb, transparent track, show on scroll. */
|
|
50
|
-
const ODS_SCROLLBAR_OPTIONS: PartialOptions = {
|
|
51
|
-
scrollbars: {
|
|
52
|
-
theme: 'os-theme-ods',
|
|
53
|
-
autoHide: 'scroll',
|
|
54
|
-
autoHideDelay: 800,
|
|
55
|
-
// Keep the bar visible until the first scroll so keyboard/AT users still
|
|
56
|
-
// get the affordance on freshly opened views.
|
|
57
|
-
autoHideSuspend: true,
|
|
58
|
-
},
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const setRef = <T,>(ref: React.Ref<T> | undefined, value: T | null) => {
|
|
62
|
-
if (!ref) return
|
|
63
|
-
if (typeof ref === 'function') ref(value)
|
|
64
|
-
else (ref as React.MutableRefObject<T | null>).current = value
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export interface OverlayScrollAreaProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
68
|
-
/** Sizing/box classes of the scroll container (`flex-1 min-h-0`, `max-h-…`,
|
|
69
|
-
* borders, background) — AND paddings. Do NOT include `overflow-*` here.
|
|
70
|
-
*
|
|
71
|
-
* PADDING BELONGS HERE, NOT ON `contentClassName`: OverlayScrollbars owns
|
|
72
|
-
* the viewport's box and writes `padding: 0` inline on it, so a padding
|
|
73
|
-
* class on the viewport is silently dropped (measured — this is why the
|
|
74
|
-
* wrapper components keep passing their consumer `className` to the host). */
|
|
75
|
-
className?: string
|
|
76
|
-
/** Layout classes for the scrolling element itself (`flex flex-col gap-…`).
|
|
77
|
-
* Children are its direct children, so `gap`/`flex` applies exactly as it
|
|
78
|
-
* did on the old single `overflow-auto` div. Paddings do NOT work here —
|
|
79
|
-
* see `className`. */
|
|
80
|
-
contentClassName?: string
|
|
81
|
-
/** Receives the actual scrolling element — use for scrollTop/scrollHeight
|
|
82
|
-
* logic and as IntersectionObserver root. Set from the first commit, valid
|
|
83
|
-
* on both the overlay and the native fallback path. */
|
|
84
|
-
viewportRef?: React.Ref<HTMLDivElement>
|
|
85
|
-
/** Extra OverlayScrollbars options merged over the ODS defaults. */
|
|
86
|
-
options?: PartialOptions
|
|
87
|
-
children?: React.ReactNode
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Replacement for an `overflow-auto` scroll container with the standardized
|
|
92
|
-
* ODS overlay scrollbar. Split the old scroller's classes: sizing goes to
|
|
93
|
-
* `className`, content layout to `contentClassName`. The inner scroller div
|
|
94
|
-
* is stable across pointer modes — refs and `onScroll` (via the standard
|
|
95
|
-
* HTML props) keep working like on the plain div it replaces.
|
|
96
|
-
*
|
|
97
|
-
* On touch devices (no fine pointer) the overlay layer is never initialized
|
|
98
|
-
* and the inner div scrolls with its native (already overlay) scrollbar.
|
|
99
|
-
*/
|
|
100
|
-
export function OverlayScrollArea({
|
|
101
|
-
className,
|
|
102
|
-
contentClassName,
|
|
103
|
-
viewportRef,
|
|
104
|
-
options,
|
|
105
|
-
children,
|
|
106
|
-
...props
|
|
107
|
-
}: OverlayScrollAreaProps) {
|
|
108
|
-
const hostRef = React.useRef<HTMLDivElement>(null)
|
|
109
|
-
const scrollerRef = React.useRef<HTMLDivElement>(null)
|
|
110
|
-
|
|
111
|
-
// Serialize to keep the effect dep stable for inline `options` objects.
|
|
112
|
-
const optionsJson = JSON.stringify(options ?? null)
|
|
113
|
-
|
|
114
|
-
// Layout effect so the viewport is upgraded before consumers' own layout
|
|
115
|
-
// effects (scroll-fade hooks, observers) measure it.
|
|
116
|
-
React.useLayoutEffect(() => {
|
|
117
|
-
const host = hostRef.current
|
|
118
|
-
const viewport = scrollerRef.current
|
|
119
|
-
if (!host || !viewport) return
|
|
120
|
-
const extra = (JSON.parse(optionsJson) ?? {}) as PartialOptions
|
|
121
|
-
const mq = matchFinePointer()
|
|
122
|
-
if (!mq) return
|
|
123
|
-
let instance: ReturnType<typeof OverlayScrollbars> | null = null
|
|
124
|
-
|
|
125
|
-
const sync = () => {
|
|
126
|
-
if (mq.matches && !instance) {
|
|
127
|
-
// Our own div is passed as the viewport: children stay inside it and
|
|
128
|
-
// it remains the scrolling element; the library only suppresses its
|
|
129
|
-
// native scrollbar and appends the overlay handles to the host.
|
|
130
|
-
instance = OverlayScrollbars(
|
|
131
|
-
{ target: host, elements: { viewport } },
|
|
132
|
-
// `scrollbars` merges one level deep: a caller overriding a single
|
|
133
|
-
// key (e.g. `autoHide`) must not drop the ODS theme and the other
|
|
134
|
-
// defaults with it.
|
|
135
|
-
{
|
|
136
|
-
...ODS_SCROLLBAR_OPTIONS,
|
|
137
|
-
...extra,
|
|
138
|
-
scrollbars: { ...ODS_SCROLLBAR_OPTIONS.scrollbars, ...extra.scrollbars },
|
|
139
|
-
},
|
|
140
|
-
)
|
|
141
|
-
} else if (!mq.matches && instance) {
|
|
142
|
-
instance.destroy()
|
|
143
|
-
instance = null
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
sync()
|
|
148
|
-
mq.addEventListener('change', sync)
|
|
149
|
-
return () => {
|
|
150
|
-
mq.removeEventListener('change', sync)
|
|
151
|
-
instance?.destroy()
|
|
152
|
-
}
|
|
153
|
-
}, [optionsJson])
|
|
154
|
-
|
|
155
|
-
return (
|
|
156
|
-
<div ref={hostRef} className={cn('relative', className)}>
|
|
157
|
-
<div
|
|
158
|
-
ref={(el) => {
|
|
159
|
-
scrollerRef.current = el
|
|
160
|
-
setRef(viewportRef, el)
|
|
161
|
-
}}
|
|
162
|
-
className={cn('h-full w-full overflow-auto', contentClassName)}
|
|
163
|
-
{...props}
|
|
164
|
-
>
|
|
165
|
-
{children}
|
|
166
|
-
</div>
|
|
167
|
-
</div>
|
|
168
|
-
)
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
export interface GlobalOverlayScrollbarsProps {
|
|
172
|
-
/** Extra OverlayScrollbars options merged over the ODS defaults. */
|
|
173
|
-
options?: PartialOptions
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Applies the same overlay scrollbar to the PAGE scroller (`<body>`).
|
|
178
|
-
* Render once near the app root (client side). No-op on touch devices.
|
|
179
|
-
*
|
|
180
|
-
* ONLY mount this on APP-SHELL pages whose body barely scrolls — the real
|
|
181
|
-
* scrolling happens in inner `OverlayScrollArea` containers (openframe-frontend,
|
|
182
|
-
* openframe-chat). Do NOT mount it on long scroll-driven documents: the thumb is
|
|
183
|
-
* repositioned from JS on every scroll frame, so on a page whose main thread is
|
|
184
|
-
* already busy with reveal-on-scroll sections, tickers and marquees the scroll
|
|
185
|
-
* visibly stutters. Measured on multi-platform-hub; raising the update debounce
|
|
186
|
-
* (`update.debounce.mutation`/`resize`) did NOT help, which rules out the
|
|
187
|
-
* observer re-measurement and points at the per-frame cost itself — i.e. it is
|
|
188
|
-
* inherent to any JS-drawn scrollbar, not to this library. Such pages keep the
|
|
189
|
-
* native page scrollbar, styled by the ODS `scrollbar-width`/`scrollbar-color`
|
|
190
|
-
* globals; their inner containers can still use `OverlayScrollArea`.
|
|
191
|
-
*/
|
|
192
|
-
export function GlobalOverlayScrollbars({ options }: GlobalOverlayScrollbarsProps = {}) {
|
|
193
|
-
const fine = useFinePointer()
|
|
194
|
-
// Serialize to keep the effect dep stable for inline `options` objects.
|
|
195
|
-
const optionsJson = JSON.stringify(options ?? null)
|
|
196
|
-
|
|
197
|
-
React.useEffect(() => {
|
|
198
|
-
if (!fine) return
|
|
199
|
-
const extra = (JSON.parse(optionsJson) ?? {}) as PartialOptions
|
|
200
|
-
// Required by OverlayScrollbars for body initialization — suppresses the
|
|
201
|
-
// native scrollbars on both scroll roots before the overlay takes over.
|
|
202
|
-
document.documentElement.setAttribute('data-overlayscrollbars-initialize', '')
|
|
203
|
-
document.body.setAttribute('data-overlayscrollbars-initialize', '')
|
|
204
|
-
const instance = OverlayScrollbars(document.body, {
|
|
205
|
-
...ODS_SCROLLBAR_OPTIONS,
|
|
206
|
-
...extra,
|
|
207
|
-
// Same one-level-deep merge as OverlayScrollArea: a caller overriding a
|
|
208
|
-
// single key must not drop the ODS theme (or a tuning preset's siblings).
|
|
209
|
-
scrollbars: { ...ODS_SCROLLBAR_OPTIONS.scrollbars, ...extra.scrollbars },
|
|
210
|
-
})
|
|
211
|
-
return () => {
|
|
212
|
-
instance.destroy()
|
|
213
|
-
document.documentElement.removeAttribute('data-overlayscrollbars-initialize')
|
|
214
|
-
document.body.removeAttribute('data-overlayscrollbars-initialize')
|
|
215
|
-
}
|
|
216
|
-
}, [fine, optionsJson])
|
|
217
|
-
|
|
218
|
-
return null
|
|
219
|
-
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from '@storybook/nextjs-vite'
|
|
2
|
-
import { OverlayScrollArea } from '../components/ui/overlay-scroll-area'
|
|
3
|
-
|
|
4
|
-
// POC: standardized macOS-like overlay scrollbar (OverlayScrollbars) — the
|
|
5
|
-
// bar appears while scrolling / hovering and fades out when idle, on every
|
|
6
|
-
// platform. Native scrolling (wheel, touchpad momentum, thumb drag) is kept.
|
|
7
|
-
|
|
8
|
-
const meta: Meta<typeof OverlayScrollArea> = {
|
|
9
|
-
title: 'UI/OverlayScrollArea',
|
|
10
|
-
component: OverlayScrollArea,
|
|
11
|
-
parameters: { layout: 'centered' },
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export default meta
|
|
15
|
-
type Story = StoryObj<typeof OverlayScrollArea>
|
|
16
|
-
|
|
17
|
-
const rows = (count: number) =>
|
|
18
|
-
Array.from({ length: count }, (_, i) => (
|
|
19
|
-
<div key={i} className="border-b border-ods-border px-[var(--spacing-system-m)] py-[var(--spacing-system-s)] text-ods-text-primary">
|
|
20
|
-
Row {i + 1} — scrollable content
|
|
21
|
-
</div>
|
|
22
|
-
))
|
|
23
|
-
|
|
24
|
-
export const Vertical: Story = {
|
|
25
|
-
render: () => (
|
|
26
|
-
<OverlayScrollArea className="h-72 w-96 rounded-lg border border-ods-border bg-ods-card">
|
|
27
|
-
{rows(40)}
|
|
28
|
-
</OverlayScrollArea>
|
|
29
|
-
),
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export const Horizontal: Story = {
|
|
33
|
-
render: () => (
|
|
34
|
-
<OverlayScrollArea className="h-24 w-96 rounded-lg border border-ods-border bg-ods-card">
|
|
35
|
-
<div className="flex w-max gap-[var(--spacing-system-s)] p-[var(--spacing-system-m)]">
|
|
36
|
-
{Array.from({ length: 30 }, (_, i) => (
|
|
37
|
-
<div key={i} className="flex h-12 w-28 shrink-0 items-center justify-center rounded-md bg-ods-bg text-ods-text-secondary">
|
|
38
|
-
Chip {i + 1}
|
|
39
|
-
</div>
|
|
40
|
-
))}
|
|
41
|
-
</div>
|
|
42
|
-
</OverlayScrollArea>
|
|
43
|
-
),
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export const Both: Story = {
|
|
47
|
-
render: () => (
|
|
48
|
-
<OverlayScrollArea className="h-72 w-96 rounded-lg border border-ods-border bg-ods-card">
|
|
49
|
-
<div className="w-[800px]">{rows(40)}</div>
|
|
50
|
-
</OverlayScrollArea>
|
|
51
|
-
),
|
|
52
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/* ODS theme for OverlayScrollbars (see components/ui/overlay-scroll-area.tsx).
|
|
2
|
-
Thin grey draggable thumb on a transparent track — matches the global
|
|
3
|
-
elevator scrollbar styling, but with macOS-like auto-hide on all platforms. */
|
|
4
|
-
.os-theme-ods {
|
|
5
|
-
--os-size: 8px;
|
|
6
|
-
--os-padding-perpendicular: 2px;
|
|
7
|
-
--os-padding-axis: 2px;
|
|
8
|
-
--os-track-bg: transparent;
|
|
9
|
-
--os-track-bg-hover: transparent;
|
|
10
|
-
--os-track-bg-active: transparent;
|
|
11
|
-
--os-handle-bg: var(--ods-system-greys-grey);
|
|
12
|
-
--os-handle-bg-hover: var(--ods-system-greys-grey-hover);
|
|
13
|
-
--os-handle-bg-active: var(--ods-system-greys-grey-action);
|
|
14
|
-
--os-handle-border-radius: 4px;
|
|
15
|
-
--os-handle-perpendicular-size: 100%;
|
|
16
|
-
--os-handle-perpendicular-size-hover: 100%;
|
|
17
|
-
--os-handle-perpendicular-size-active: 100%;
|
|
18
|
-
--os-handle-min-size: 33px;
|
|
19
|
-
}
|