@a-type/ui 1.1.18 → 1.1.20
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/cjs/components/card/Card.d.ts +2 -2
- package/dist/cjs/components/dialog/Dialog.js +10 -2
- package/dist/cjs/components/dialog/Dialog.js.map +1 -1
- package/dist/cjs/components/dialog/Dialog.stories.js +3 -1
- package/dist/cjs/components/dialog/Dialog.stories.js.map +1 -1
- package/dist/cjs/components/errorBoundary/ErrorBoundary.d.ts +1 -1
- package/dist/cjs/components/input/Input.d.ts +3 -0
- package/dist/cjs/components/input/Input.js +13 -2
- package/dist/cjs/components/input/Input.js.map +1 -1
- package/dist/cjs/components/layouts/PageNav.js +3 -2
- package/dist/cjs/components/layouts/PageNav.js.map +1 -1
- package/dist/cjs/components/layouts/PageNowPlaying.js +6 -1
- package/dist/cjs/components/layouts/PageNowPlaying.js.map +1 -1
- package/dist/cjs/components/layouts/layouts.stories.js +2 -1
- package/dist/cjs/components/layouts/layouts.stories.js.map +1 -1
- package/dist/cjs/components/masonry/masonry.js +5 -1
- package/dist/cjs/components/masonry/masonry.js.map +1 -1
- package/dist/cjs/components/particles/ParticleLayer.stories.js +2 -2
- package/dist/cjs/components/particles/ParticleLayer.stories.js.map +1 -1
- package/dist/cjs/components/particles/particlesState.js +5 -1
- package/dist/cjs/components/particles/particlesState.js.map +1 -1
- package/dist/cjs/components/provider/Provider.d.ts +6 -0
- package/dist/cjs/components/provider/Provider.js +14 -5
- package/dist/cjs/components/provider/Provider.js.map +1 -1
- package/dist/cjs/components/utility/HideWhileKeyboardOpen.d.ts +5 -0
- package/dist/cjs/components/utility/HideWhileKeyboardOpen.js +30 -0
- package/dist/cjs/components/utility/HideWhileKeyboardOpen.js.map +1 -0
- package/dist/cjs/hooks/useSize.d.ts +2 -1
- package/dist/cjs/hooks/useSize.js +17 -5
- package/dist/cjs/hooks/useSize.js.map +1 -1
- package/dist/cjs/hooks/useVirtualKeyboardBehavior.d.ts +1 -1
- package/dist/cjs/hooks/useVirtualKeyboardBehavior.js +1 -1
- package/dist/cjs/hooks/useVirtualKeyboardBehavior.js.map +1 -1
- package/dist/cjs/hooks/useVisualViewportOffset.d.ts +1 -0
- package/dist/cjs/hooks/useVisualViewportOffset.js +56 -6
- package/dist/cjs/hooks/useVisualViewportOffset.js.map +1 -1
- package/dist/css/main.css +1 -1
- package/dist/esm/components/card/Card.d.ts +2 -2
- package/dist/esm/components/dialog/Dialog.js +10 -2
- package/dist/esm/components/dialog/Dialog.js.map +1 -1
- package/dist/esm/components/dialog/Dialog.stories.js +3 -1
- package/dist/esm/components/dialog/Dialog.stories.js.map +1 -1
- package/dist/esm/components/errorBoundary/ErrorBoundary.d.ts +1 -1
- package/dist/esm/components/input/Input.d.ts +3 -0
- package/dist/esm/components/input/Input.js +14 -3
- package/dist/esm/components/input/Input.js.map +1 -1
- package/dist/esm/components/layouts/PageNav.js +3 -2
- package/dist/esm/components/layouts/PageNav.js.map +1 -1
- package/dist/esm/components/layouts/PageNowPlaying.js +6 -1
- package/dist/esm/components/layouts/PageNowPlaying.js.map +1 -1
- package/dist/esm/components/layouts/layouts.stories.js +2 -1
- package/dist/esm/components/layouts/layouts.stories.js.map +1 -1
- package/dist/esm/components/masonry/masonry.js +2 -1
- package/dist/esm/components/masonry/masonry.js.map +1 -1
- package/dist/esm/components/particles/ParticleLayer.stories.js +2 -2
- package/dist/esm/components/particles/ParticleLayer.stories.js.map +1 -1
- package/dist/esm/components/particles/particlesState.js +5 -1
- package/dist/esm/components/particles/particlesState.js.map +1 -1
- package/dist/esm/components/provider/Provider.d.ts +6 -0
- package/dist/esm/components/provider/Provider.js +12 -4
- package/dist/esm/components/provider/Provider.js.map +1 -1
- package/dist/esm/components/utility/HideWhileKeyboardOpen.d.ts +5 -0
- package/dist/esm/components/utility/HideWhileKeyboardOpen.js +24 -0
- package/dist/esm/components/utility/HideWhileKeyboardOpen.js.map +1 -0
- package/dist/esm/hooks/useSize.d.ts +2 -1
- package/dist/esm/hooks/useSize.js +17 -5
- package/dist/esm/hooks/useSize.js.map +1 -1
- package/dist/esm/hooks/useVirtualKeyboardBehavior.d.ts +1 -1
- package/dist/esm/hooks/useVirtualKeyboardBehavior.js +1 -1
- package/dist/esm/hooks/useVirtualKeyboardBehavior.js.map +1 -1
- package/dist/esm/hooks/useVisualViewportOffset.d.ts +1 -0
- package/dist/esm/hooks/useVisualViewportOffset.js +54 -5
- package/dist/esm/hooks/useVisualViewportOffset.js.map +1 -1
- package/package.json +1 -1
- package/src/components/dialog/Dialog.stories.tsx +6 -3
- package/src/components/dialog/Dialog.tsx +18 -3
- package/src/components/input/Input.tsx +35 -2
- package/src/components/layouts/PageNav.tsx +5 -3
- package/src/components/layouts/PageNowPlaying.tsx +7 -0
- package/src/components/layouts/layouts.stories.tsx +3 -1
- package/src/components/masonry/masonry.tsx +6 -1
- package/src/components/particles/ParticleLayer.stories.tsx +2 -4
- package/src/components/particles/particlesState.ts +5 -3
- package/src/components/provider/Provider.tsx +34 -14
- package/src/components/utility/HideWhileKeyboardOpen.tsx +26 -0
- package/src/hooks/useSize.ts +24 -3
- package/src/hooks/useVirtualKeyboardBehavior.ts +1 -3
- package/src/hooks/useVisualViewportOffset.ts +82 -12
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useVirtualKeyboardBehavior.js","sourceRoot":"","sources":["../../../src/hooks/useVirtualKeyboardBehavior.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAElC,MAAM,UAAU,0BAA0B,
|
|
1
|
+
{"version":3,"file":"useVirtualKeyboardBehavior.js","sourceRoot":"","sources":["../../../src/hooks/useVirtualKeyboardBehavior.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAElC,MAAM,UAAU,0BAA0B,CAAC,QAAgC;IAC1E,SAAS,CAAC,GAAG,EAAE;QACd,IAAI,iBAAiB,IAAI,SAAS,EAAE;YACnC,aAAa;YACb,SAAS,CAAC,eAAe,CAAC,eAAe,GAAG,QAAQ,KAAK,SAAS,CAAC;SACnE;IACF,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;AAChB,CAAC"}
|
|
@@ -1,27 +1,76 @@
|
|
|
1
1
|
// @unocss-include
|
|
2
|
-
import { useEffect } from 'react';
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
import { useStableCallback } from './useStableCallback.js';
|
|
4
|
+
import { useConfig } from '../components/provider.js';
|
|
3
5
|
/**
|
|
4
6
|
* Applies bottom offset px as a CSS custom property to the document root.
|
|
5
7
|
*/
|
|
6
8
|
export function useVisualViewportOffset(disable) {
|
|
9
|
+
useReactToViewportChanges((viewport) => {
|
|
10
|
+
document.documentElement.style.setProperty('--viewport-bottom-offset', `${window.innerHeight - viewport.height - viewport.offsetTop}px`);
|
|
11
|
+
document.documentElement.style.setProperty('--viewport-height', `${viewport.height}px`);
|
|
12
|
+
document.documentElement.style.setProperty('--viewport-width', `${viewport.width}px`);
|
|
13
|
+
document.documentElement.style.setProperty('--viewport-top-offset', `${viewport.offsetTop}px`);
|
|
14
|
+
document.documentElement.style.setProperty('--viewport-left-offset', `${viewport.offsetLeft}px`);
|
|
15
|
+
document.documentElement.style.setProperty('--keyboard-open', viewport.height < window.innerHeight ? '1' : '0');
|
|
16
|
+
}, disable);
|
|
17
|
+
}
|
|
18
|
+
export function useIsKeyboardOpen() {
|
|
19
|
+
const { virtualKeyboardBehavior } = useConfig();
|
|
20
|
+
const [isViewportConstrained, setIsViewportConstrained] = useState(false);
|
|
21
|
+
useReactToViewportChanges((viewport) => {
|
|
22
|
+
setIsViewportConstrained(viewport.height < window.innerHeight);
|
|
23
|
+
}, virtualKeyboardBehavior !== 'displace');
|
|
24
|
+
const [isKeyboardOpen, setIsKeyboardOpen] = useState(false);
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
if (!('virtualKeyboard' in navigator)) {
|
|
27
|
+
// no support
|
|
28
|
+
console.warn(`virtual keyboard behavior set to 'overlay', but virtualKeyboard API is not supported in this browser.`);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const virtualKeyboard = navigator.virtualKeyboard;
|
|
32
|
+
const update = () => {
|
|
33
|
+
setIsKeyboardOpen(virtualKeyboard.boundingRect.height > 0);
|
|
34
|
+
};
|
|
35
|
+
update();
|
|
36
|
+
virtualKeyboard.addEventListener('geometrychange', update);
|
|
37
|
+
return () => {
|
|
38
|
+
virtualKeyboard.removeEventListener('geometrychange', update);
|
|
39
|
+
};
|
|
40
|
+
}, []);
|
|
41
|
+
if (virtualKeyboardBehavior === 'displace') {
|
|
42
|
+
return isViewportConstrained;
|
|
43
|
+
}
|
|
44
|
+
return isKeyboardOpen;
|
|
45
|
+
}
|
|
46
|
+
function useReactToViewportChanges(cb, disable) {
|
|
47
|
+
const stableCb = useStableCallback(cb);
|
|
7
48
|
useEffect(() => {
|
|
8
49
|
if (disable)
|
|
9
50
|
return;
|
|
10
|
-
const viewport =
|
|
51
|
+
const viewport = window.visualViewport;
|
|
11
52
|
if (!viewport) {
|
|
12
53
|
return;
|
|
13
54
|
}
|
|
14
55
|
const update = () => {
|
|
15
|
-
|
|
16
|
-
|
|
56
|
+
stableCb(viewport);
|
|
57
|
+
};
|
|
58
|
+
let prevTimeout;
|
|
59
|
+
const debouncedUpdate = () => {
|
|
60
|
+
if (prevTimeout) {
|
|
61
|
+
clearTimeout(prevTimeout);
|
|
62
|
+
}
|
|
63
|
+
prevTimeout = window.setTimeout(update, 50);
|
|
17
64
|
};
|
|
18
65
|
update();
|
|
19
66
|
window.addEventListener('scroll', update, { passive: true });
|
|
20
67
|
viewport.addEventListener('resize', update);
|
|
68
|
+
viewport.addEventListener('scroll', debouncedUpdate, { passive: true });
|
|
21
69
|
return () => {
|
|
22
70
|
viewport.removeEventListener('resize', update);
|
|
23
71
|
window.removeEventListener('scroll', update);
|
|
72
|
+
viewport.removeEventListener('scroll', debouncedUpdate);
|
|
24
73
|
};
|
|
25
|
-
}, [disable]);
|
|
74
|
+
}, [stableCb, disable]);
|
|
26
75
|
}
|
|
27
76
|
//# sourceMappingURL=useVisualViewportOffset.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useVisualViewportOffset.js","sourceRoot":"","sources":["../../../src/hooks/useVisualViewportOffset.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,
|
|
1
|
+
{"version":3,"file":"useVisualViewportOffset.js","sourceRoot":"","sources":["../../../src/hooks/useVisualViewportOffset.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -11,6 +11,8 @@ import { ParticleLayer } from '../particles.js';
|
|
|
11
11
|
import { H1, P } from '../typography.js';
|
|
12
12
|
import { Button } from '../button.js';
|
|
13
13
|
import { useEffect, useState } from 'react';
|
|
14
|
+
import { Provider } from '../provider.js';
|
|
15
|
+
import { Input } from '../input.js';
|
|
14
16
|
|
|
15
17
|
const meta = {
|
|
16
18
|
title: 'Dialog',
|
|
@@ -124,7 +126,7 @@ export const VirtualKeyboard: Story = {
|
|
|
124
126
|
}, [keyboard]);
|
|
125
127
|
|
|
126
128
|
return (
|
|
127
|
-
<
|
|
129
|
+
<Provider virtualKeyboardBehavior="overlay">
|
|
128
130
|
<Dialog>
|
|
129
131
|
<DialogTrigger asChild>
|
|
130
132
|
<Button>Open</Button>
|
|
@@ -132,18 +134,19 @@ export const VirtualKeyboard: Story = {
|
|
|
132
134
|
<DummyContent />
|
|
133
135
|
<DialogContent>
|
|
134
136
|
<DialogTitle>Hello world</DialogTitle>
|
|
137
|
+
<Input />
|
|
135
138
|
<DialogActions>
|
|
136
139
|
<DialogClose asChild>
|
|
137
140
|
<Button>Close</Button>
|
|
138
141
|
</DialogClose>
|
|
139
142
|
<Button onClick={() => setKeyboard((v) => !v)}>
|
|
140
|
-
Toggle fake
|
|
143
|
+
Toggle fake kb
|
|
141
144
|
</Button>
|
|
142
145
|
</DialogActions>
|
|
143
146
|
</DialogContent>
|
|
144
147
|
</Dialog>
|
|
145
148
|
<div className="fixed bottom-0 h-[var(--mock-virtual-keyboard-height,0)] bg-black w-full transition-height left-0 right-0" />
|
|
146
|
-
</
|
|
149
|
+
</Provider>
|
|
147
150
|
);
|
|
148
151
|
},
|
|
149
152
|
};
|
|
@@ -19,6 +19,7 @@ import { CheckIcon, ChevronDownIcon } from '@radix-ui/react-icons';
|
|
|
19
19
|
import { selectTriggerClassName } from '../select.js';
|
|
20
20
|
import { useDrag } from '@use-gesture/react';
|
|
21
21
|
import { Button } from '../button.js';
|
|
22
|
+
import { useConfig } from '../provider.js';
|
|
22
23
|
|
|
23
24
|
const StyledOverlay = withClassName(
|
|
24
25
|
DialogPrimitive.Overlay,
|
|
@@ -35,10 +36,16 @@ const StyledContent = withClassName(
|
|
|
35
36
|
'layer-components:(left-50% top-50% translate-[-50%] w-90vw max-w-450px max-h-85vh p-6 pt-8 rounded-lg border-b-1 pt-6)',
|
|
36
37
|
'layer-components:(animate-dialog-in [&[data-state=closed]]:animate-dialog-out motion-reduce:animate-none)',
|
|
37
38
|
);
|
|
38
|
-
const
|
|
39
|
-
'layer-variants:lt-sm:(translate-0
|
|
39
|
+
const sheetClassNames = classNames(
|
|
40
|
+
'layer-variants:lt-sm:(translate-0 left-0 right-0 top-auto h-min-content rounded-tl-xl rounded-tr-xl rounded-b-0 p-6 pt-8 w-full max-w-none pb-[calc(3rem+env(safe-area-inset-bottom,0px))] border-b-0)',
|
|
40
41
|
'layer-variants:lt-sm:(animate-ease-in animate-fade-in-up [&[data-state=closed]]:animate-fade-out-down)',
|
|
41
42
|
);
|
|
43
|
+
const sheetClassNameWithOverlayKeyboard = classNames(
|
|
44
|
+
'layer-variants:lt-sm:(bottom-[calc(var(--mock-virtual-keyboard-height,env(keyboard-inset-height,0px))+var(--gesture-y,0px))] max-h-[calc(95vh-var(--mock-virtual-keyboard-height,env(keyboard-inset-height,0px)))])',
|
|
45
|
+
);
|
|
46
|
+
const sheetClassNameWithDisplaceKeyboard = classNames(
|
|
47
|
+
'layer-variants:lt-sm:(bottom-[calc(var(--viewport-bottom-offset,0px)+var(--gesture-y,0px))] max-h-[calc(0.85*var(--viewport-height,100vh))])',
|
|
48
|
+
);
|
|
42
49
|
|
|
43
50
|
export const Content = forwardRef<
|
|
44
51
|
HTMLDivElement,
|
|
@@ -107,6 +114,8 @@ export const Content = forwardRef<
|
|
|
107
114
|
|
|
108
115
|
const finalRef = useMergedRef(ref, openRef, gestureRef);
|
|
109
116
|
|
|
117
|
+
const { virtualKeyboardBehavior } = useConfig();
|
|
118
|
+
|
|
110
119
|
return (
|
|
111
120
|
<DialogPrimitive.Portal>
|
|
112
121
|
<StyledOverlay />
|
|
@@ -120,7 +129,13 @@ export const Content = forwardRef<
|
|
|
120
129
|
'max-w-600px': width === 'md',
|
|
121
130
|
'max-w-300px': width === 'sm',
|
|
122
131
|
},
|
|
123
|
-
!disableSheet &&
|
|
132
|
+
!disableSheet && sheetClassNames,
|
|
133
|
+
!disableSheet &&
|
|
134
|
+
virtualKeyboardBehavior === 'overlay' &&
|
|
135
|
+
sheetClassNameWithOverlayKeyboard,
|
|
136
|
+
!disableSheet &&
|
|
137
|
+
virtualKeyboardBehavior === 'displace' &&
|
|
138
|
+
sheetClassNameWithDisplaceKeyboard,
|
|
124
139
|
outerClassName || className,
|
|
125
140
|
)}
|
|
126
141
|
>
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import classNames from 'clsx';
|
|
2
2
|
import {
|
|
3
3
|
ComponentProps,
|
|
4
|
-
ComponentPropsWithRef,
|
|
5
4
|
FocusEvent,
|
|
6
5
|
forwardRef,
|
|
7
6
|
useCallback,
|
|
7
|
+
useEffect,
|
|
8
|
+
useState,
|
|
8
9
|
} from 'react';
|
|
9
10
|
import { Slot } from '@radix-ui/react-slot';
|
|
10
11
|
|
|
@@ -20,10 +21,23 @@ export interface InputProps extends ComponentProps<'input'> {
|
|
|
20
21
|
variant?: 'default' | 'primary';
|
|
21
22
|
autoSelect?: boolean;
|
|
22
23
|
asChild?: boolean;
|
|
24
|
+
/** Shuffle between random placeholders */
|
|
25
|
+
placeholders?: string[];
|
|
26
|
+
placeholdersIntervalMs?: number;
|
|
23
27
|
}
|
|
24
28
|
|
|
25
29
|
export const Input = forwardRef<HTMLInputElement, InputProps>(function Input(
|
|
26
|
-
{
|
|
30
|
+
{
|
|
31
|
+
className,
|
|
32
|
+
autoSelect,
|
|
33
|
+
onFocus,
|
|
34
|
+
variant: _,
|
|
35
|
+
asChild,
|
|
36
|
+
placeholders,
|
|
37
|
+
placeholder,
|
|
38
|
+
placeholdersIntervalMs = 5000,
|
|
39
|
+
...props
|
|
40
|
+
},
|
|
27
41
|
ref,
|
|
28
42
|
) {
|
|
29
43
|
const handleFocus = useCallback(
|
|
@@ -36,6 +50,24 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(function Input(
|
|
|
36
50
|
[onFocus, autoSelect],
|
|
37
51
|
);
|
|
38
52
|
|
|
53
|
+
const [randomPlaceholder, setRandomPlaceholder] = useState<
|
|
54
|
+
string | undefined
|
|
55
|
+
>(
|
|
56
|
+
placeholders
|
|
57
|
+
? placeholders[Math.floor(Math.random() * placeholders.length)]
|
|
58
|
+
: undefined,
|
|
59
|
+
);
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
if (placeholders) {
|
|
62
|
+
const interval = setInterval(() => {
|
|
63
|
+
setRandomPlaceholder(
|
|
64
|
+
placeholders[Math.floor(Math.random() * placeholders.length)],
|
|
65
|
+
);
|
|
66
|
+
}, placeholdersIntervalMs);
|
|
67
|
+
return () => clearInterval(interval);
|
|
68
|
+
}
|
|
69
|
+
}, [placeholders, placeholdersIntervalMs]);
|
|
70
|
+
|
|
39
71
|
const Component = asChild ? Slot : 'input';
|
|
40
72
|
|
|
41
73
|
return (
|
|
@@ -44,6 +76,7 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(function Input(
|
|
|
44
76
|
onFocus={handleFocus}
|
|
45
77
|
className={classNames(inputClassName, className)}
|
|
46
78
|
ref={ref}
|
|
79
|
+
placeholder={placeholder ?? randomPlaceholder}
|
|
47
80
|
/>
|
|
48
81
|
);
|
|
49
82
|
});
|
|
@@ -3,13 +3,14 @@
|
|
|
3
3
|
import classNames from 'clsx';
|
|
4
4
|
import { HTMLAttributes, useRef } from 'react';
|
|
5
5
|
import { useBoundsCssVars } from '../../hooks.js';
|
|
6
|
+
import { HideWhileKeyboardOpen } from '../utility/HideWhileKeyboardOpen.js';
|
|
6
7
|
|
|
7
8
|
export function PageNav({
|
|
8
9
|
className,
|
|
9
10
|
children,
|
|
10
11
|
...props
|
|
11
12
|
}: HTMLAttributes<HTMLDivElement>) {
|
|
12
|
-
const bodyRef = useRef(document.
|
|
13
|
+
const bodyRef = useRef(document.documentElement);
|
|
13
14
|
const ref = useBoundsCssVars<HTMLDivElement>(undefined, bodyRef, {
|
|
14
15
|
left: '--nav-left',
|
|
15
16
|
top: '--nav-top',
|
|
@@ -17,8 +18,9 @@ export function PageNav({
|
|
|
17
18
|
height: '--nav-height',
|
|
18
19
|
ready: '--nav-ready',
|
|
19
20
|
});
|
|
21
|
+
|
|
20
22
|
return (
|
|
21
|
-
<
|
|
23
|
+
<HideWhileKeyboardOpen
|
|
22
24
|
{...props}
|
|
23
25
|
className={classNames(
|
|
24
26
|
'layer-components:([grid-area:nav] relative z-nav pb-[calc(0.25rem+env(safe-area-inset-bottom,0px))])',
|
|
@@ -28,6 +30,6 @@ export function PageNav({
|
|
|
28
30
|
ref={ref}
|
|
29
31
|
>
|
|
30
32
|
{children}
|
|
31
|
-
</
|
|
33
|
+
</HideWhileKeyboardOpen>
|
|
32
34
|
);
|
|
33
35
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import classNames from 'clsx';
|
|
4
4
|
import { HTMLAttributes } from 'react';
|
|
5
|
+
import { useConfig } from '../provider.js';
|
|
5
6
|
|
|
6
7
|
export function PageNowPlaying({
|
|
7
8
|
className,
|
|
@@ -12,6 +13,8 @@ export function PageNowPlaying({
|
|
|
12
13
|
unstyled?: boolean;
|
|
13
14
|
keepAboveKeyboard?: boolean;
|
|
14
15
|
}) {
|
|
16
|
+
const { virtualKeyboardBehavior } = useConfig();
|
|
17
|
+
|
|
15
18
|
return (
|
|
16
19
|
<div
|
|
17
20
|
{...props}
|
|
@@ -26,7 +29,11 @@ export function PageNowPlaying({
|
|
|
26
29
|
? 'layer-variants:p-2'
|
|
27
30
|
: 'layer-components:(bg-wash p-2px rounded-xl border-light shadow-md min-w-32px items-center justify-center m-2 w-auto)',
|
|
28
31
|
keepAboveKeyboard &&
|
|
32
|
+
virtualKeyboardBehavior === 'overlay' &&
|
|
29
33
|
'layer-variants:lt-sm:bottom-[max(var(--mock-virtual-keyboard-height,env(keyboard-inset-height,0px),var(--nav-height,env(safe-area-inset-bottom,0px))))]',
|
|
34
|
+
keepAboveKeyboard &&
|
|
35
|
+
virtualKeyboardBehavior === 'displace' &&
|
|
36
|
+
'layer-variants:lt-sm:bottom-[max(var(--viewport-bottom-offset,0px),var(--nav-height,env(safe-area-inset-bottom,0px)))]',
|
|
30
37
|
className,
|
|
31
38
|
)}
|
|
32
39
|
/>
|
|
@@ -14,6 +14,7 @@ import { Icon } from '../icon.js';
|
|
|
14
14
|
import { PageNowPlaying } from './PageNowPlaying.js';
|
|
15
15
|
import { useEffect, useState } from 'react';
|
|
16
16
|
import { Button } from '../button.js';
|
|
17
|
+
import { Input } from '../input.js';
|
|
17
18
|
|
|
18
19
|
const meta = {
|
|
19
20
|
title: 'layouts',
|
|
@@ -99,8 +100,9 @@ export const WithVirtualKeyboard: Story = {
|
|
|
99
100
|
</div>
|
|
100
101
|
<PageNowPlaying keepAboveKeyboard>
|
|
101
102
|
<Button onClick={() => setKeyboard((v) => !v)}>
|
|
102
|
-
Toggle
|
|
103
|
+
Toggle fake kb
|
|
103
104
|
</Button>
|
|
105
|
+
<Input />
|
|
104
106
|
</PageNowPlaying>
|
|
105
107
|
</PageContent>
|
|
106
108
|
<PageNav>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { debounce } from '@a-type/utils';
|
|
2
|
+
import clsx from 'clsx';
|
|
2
3
|
import { CSSProperties, ReactNode, useEffect, useRef, useState } from 'react';
|
|
3
4
|
|
|
4
5
|
interface Layout {
|
|
@@ -240,7 +241,11 @@ export function Masonry({
|
|
|
240
241
|
}, [layout, ref]);
|
|
241
242
|
|
|
242
243
|
return (
|
|
243
|
-
<div
|
|
244
|
+
<div
|
|
245
|
+
ref={ref}
|
|
246
|
+
style={initialStyle}
|
|
247
|
+
className={clsx('layer-components:z-1', className)}
|
|
248
|
+
>
|
|
244
249
|
{children}
|
|
245
250
|
</div>
|
|
246
251
|
);
|
|
@@ -19,15 +19,13 @@ export const Default: Story = {
|
|
|
19
19
|
render() {
|
|
20
20
|
return (
|
|
21
21
|
<div className="w-full h-[100vh] relative flex flex-col items-center justify-center">
|
|
22
|
-
<
|
|
23
|
-
<DemoButton />
|
|
24
|
-
</ParticleLayer>
|
|
22
|
+
<ExplodeButton />
|
|
25
23
|
</div>
|
|
26
24
|
);
|
|
27
25
|
},
|
|
28
26
|
};
|
|
29
27
|
|
|
30
|
-
function
|
|
28
|
+
function ExplodeButton() {
|
|
31
29
|
const particles = useParticles();
|
|
32
30
|
if (!particles) throw new Error('Must be used inside ParticleLayer');
|
|
33
31
|
const burst = (ev: MouseEvent) => {
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { assert } from '@a-type/utils';
|
|
2
|
-
|
|
3
1
|
export class Particles {
|
|
4
2
|
private canvas: HTMLCanvasElement | null = null;
|
|
5
3
|
private ctx: CanvasRenderingContext2D | null = null;
|
|
@@ -96,7 +94,7 @@ export class Particles {
|
|
|
96
94
|
|
|
97
95
|
this.ctx!.clearRect(0, 0, this.canvas!.width, this.canvas!.height);
|
|
98
96
|
|
|
99
|
-
if (this.particles.length ===
|
|
97
|
+
if (this.particles.length === this.freeParticles.length) {
|
|
100
98
|
// skip drawing until we get particles again
|
|
101
99
|
this.lastDrawLatch = true;
|
|
102
100
|
} else {
|
|
@@ -121,6 +119,7 @@ export class Particles {
|
|
|
121
119
|
addParticles = (spawn: ParticleSpawn) => {
|
|
122
120
|
// wrap in RAF because initializers often use element dimensions
|
|
123
121
|
requestAnimationFrame(() => {
|
|
122
|
+
const wasLatch = this.lastDrawLatch;
|
|
124
123
|
this.lastDrawLatch = false;
|
|
125
124
|
if (this.freeParticles.length < spawn.count) {
|
|
126
125
|
this.extendPool(spawn.count - this.freeParticles.length);
|
|
@@ -141,6 +140,9 @@ export class Particles {
|
|
|
141
140
|
spawn.behavior,
|
|
142
141
|
);
|
|
143
142
|
}
|
|
143
|
+
if (wasLatch) {
|
|
144
|
+
this.resume();
|
|
145
|
+
}
|
|
144
146
|
});
|
|
145
147
|
};
|
|
146
148
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ReactNode } from 'react';
|
|
1
|
+
import { createContext, ReactNode, useContext } from 'react';
|
|
2
2
|
import { ParticleLayer } from '../particles.js';
|
|
3
3
|
import { IconSpritesheet } from '../icon.js';
|
|
4
4
|
import { Toaster, ToastPosition } from 'react-hot-toast';
|
|
@@ -23,11 +23,13 @@ export function Provider({
|
|
|
23
23
|
disableParticles,
|
|
24
24
|
toastPosition = 'top-center',
|
|
25
25
|
toastContainerClassName,
|
|
26
|
-
disableViewportOffset
|
|
27
|
-
virtualKeyboardBehavior = '
|
|
26
|
+
disableViewportOffset,
|
|
27
|
+
virtualKeyboardBehavior = 'displace',
|
|
28
28
|
}: ProviderProps) {
|
|
29
29
|
useVisualViewportOffset(disableViewportOffset);
|
|
30
|
-
|
|
30
|
+
const supportedVirtualKeyboardBehavior =
|
|
31
|
+
'virtualKeyboard' in navigator ? virtualKeyboardBehavior : 'displace';
|
|
32
|
+
useVirtualKeyboardBehavior(supportedVirtualKeyboardBehavior);
|
|
31
33
|
|
|
32
34
|
const otherStuff = (
|
|
33
35
|
<>
|
|
@@ -41,18 +43,36 @@ export function Provider({
|
|
|
41
43
|
|
|
42
44
|
if (disableParticles)
|
|
43
45
|
return (
|
|
44
|
-
<
|
|
45
|
-
{
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
<ConfigContext.Provider
|
|
47
|
+
value={{ virtualKeyboardBehavior: supportedVirtualKeyboardBehavior }}
|
|
48
|
+
>
|
|
49
|
+
<TooltipProvider>
|
|
50
|
+
{children}
|
|
51
|
+
{otherStuff}
|
|
52
|
+
</TooltipProvider>
|
|
53
|
+
</ConfigContext.Provider>
|
|
48
54
|
);
|
|
49
55
|
|
|
50
56
|
return (
|
|
51
|
-
<
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
+
<ConfigContext.Provider
|
|
58
|
+
value={{ virtualKeyboardBehavior: supportedVirtualKeyboardBehavior }}
|
|
59
|
+
>
|
|
60
|
+
<TooltipProvider>
|
|
61
|
+
<ParticleLayer>
|
|
62
|
+
{children}
|
|
63
|
+
{otherStuff}
|
|
64
|
+
</ParticleLayer>
|
|
65
|
+
</TooltipProvider>
|
|
66
|
+
</ConfigContext.Provider>
|
|
57
67
|
);
|
|
58
68
|
}
|
|
69
|
+
|
|
70
|
+
export const ConfigContext = createContext<{
|
|
71
|
+
virtualKeyboardBehavior: 'overlay' | 'displace';
|
|
72
|
+
}>({
|
|
73
|
+
virtualKeyboardBehavior: 'displace',
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
export function useConfig() {
|
|
77
|
+
return useContext(ConfigContext);
|
|
78
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Slot } from '@radix-ui/react-slot';
|
|
2
|
+
import { useIsKeyboardOpen } from '../../hooks.js';
|
|
3
|
+
import clsx from 'clsx';
|
|
4
|
+
import { forwardRef, HTMLAttributes } from 'react';
|
|
5
|
+
|
|
6
|
+
export interface HideWhileKeyboardOpenProps
|
|
7
|
+
extends HTMLAttributes<HTMLDivElement> {
|
|
8
|
+
asChild?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const HideWhileKeyboardOpen = forwardRef<
|
|
12
|
+
HTMLDivElement,
|
|
13
|
+
HideWhileKeyboardOpenProps
|
|
14
|
+
>(function HideWhileKeyboardOpen({ asChild, className, ...rest }, ref) {
|
|
15
|
+
const isKeyboardOpen = useIsKeyboardOpen();
|
|
16
|
+
|
|
17
|
+
const Comp = asChild ? Slot : 'div';
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<Comp
|
|
21
|
+
ref={ref}
|
|
22
|
+
className={clsx(isKeyboardOpen && 'layer-responsive:hidden', className)}
|
|
23
|
+
{...rest}
|
|
24
|
+
/>
|
|
25
|
+
);
|
|
26
|
+
});
|
package/src/hooks/useSize.ts
CHANGED
|
@@ -74,13 +74,17 @@ export function useBounds<E extends HTMLElement>(
|
|
|
74
74
|
top: number;
|
|
75
75
|
width: number;
|
|
76
76
|
height: number;
|
|
77
|
+
ref: RefObject<E>;
|
|
77
78
|
}) => void,
|
|
79
|
+
disconnectCallback: () => void = () => {},
|
|
78
80
|
) {
|
|
79
81
|
const ref = useRef<E>(null);
|
|
80
82
|
const cb = useStableCallback(callback);
|
|
83
|
+
const disconnectCb = useStableCallback(disconnectCallback);
|
|
81
84
|
useEffect(() => {
|
|
82
85
|
const target = ref.current;
|
|
83
86
|
if (!target) {
|
|
87
|
+
disconnectCb();
|
|
84
88
|
return () => {
|
|
85
89
|
//
|
|
86
90
|
};
|
|
@@ -89,7 +93,7 @@ export function useBounds<E extends HTMLElement>(
|
|
|
89
93
|
entries.forEach((entry) => {
|
|
90
94
|
const { left, top, width, height } =
|
|
91
95
|
entry.target.getBoundingClientRect();
|
|
92
|
-
cb({ left, top, width, height });
|
|
96
|
+
cb({ left, top, width, height, ref });
|
|
93
97
|
});
|
|
94
98
|
});
|
|
95
99
|
resizeObserver.observe(target);
|
|
@@ -97,7 +101,7 @@ export function useBounds<E extends HTMLElement>(
|
|
|
97
101
|
resizeObserver.unobserve(target);
|
|
98
102
|
resizeObserver.disconnect();
|
|
99
103
|
};
|
|
100
|
-
}, [ref, cb]);
|
|
104
|
+
}, [ref, cb, disconnectCb]);
|
|
101
105
|
return ref;
|
|
102
106
|
}
|
|
103
107
|
|
|
@@ -118,11 +122,13 @@ export function useBoundsCssVars<E extends HTMLElement>(
|
|
|
118
122
|
top,
|
|
119
123
|
width,
|
|
120
124
|
height,
|
|
125
|
+
ref,
|
|
121
126
|
}: {
|
|
122
127
|
left: number;
|
|
123
128
|
top: number;
|
|
124
129
|
width: number;
|
|
125
130
|
height: number;
|
|
131
|
+
ref: RefObject<E>;
|
|
126
132
|
}) => {
|
|
127
133
|
const usedRef = applyToRef || ref;
|
|
128
134
|
usedRef.current?.style.setProperty(
|
|
@@ -159,6 +165,21 @@ export function useBoundsCssVars<E extends HTMLElement>(
|
|
|
159
165
|
propertyNames?.width,
|
|
160
166
|
propertyNames?.height,
|
|
161
167
|
]);
|
|
162
|
-
const
|
|
168
|
+
const disconnect = () => {
|
|
169
|
+
if (applyToRef?.current) {
|
|
170
|
+
applyToRef.current.style.removeProperty(
|
|
171
|
+
propertyNames?.ready ?? '--ready',
|
|
172
|
+
);
|
|
173
|
+
applyToRef.current.style.removeProperty(propertyNames?.left ?? '--left');
|
|
174
|
+
applyToRef.current.style.removeProperty(propertyNames?.top ?? '--top');
|
|
175
|
+
applyToRef.current.style.removeProperty(
|
|
176
|
+
propertyNames?.width ?? '--width',
|
|
177
|
+
);
|
|
178
|
+
applyToRef.current.style.removeProperty(
|
|
179
|
+
propertyNames?.height ?? '--height',
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
const ref = useBounds<E>(update, disconnect);
|
|
163
184
|
return ref;
|
|
164
185
|
}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { useEffect } from 'react';
|
|
2
2
|
|
|
3
|
-
export function useVirtualKeyboardBehavior(
|
|
4
|
-
behavior: 'overlay' | 'displace' = 'overlay',
|
|
5
|
-
) {
|
|
3
|
+
export function useVirtualKeyboardBehavior(behavior: 'overlay' | 'displace') {
|
|
6
4
|
useEffect(() => {
|
|
7
5
|
if ('virtualKeyboard' in navigator) {
|
|
8
6
|
// @ts-ignore
|