@bsky.app/sift 0.3.1 → 0.3.3
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/CHANGELOG.md +14 -0
- package/build/Sift.d.ts +9 -2
- package/build/Sift.d.ts.map +1 -1
- package/build/Sift.js +8 -3
- package/build/Sift.js.map +1 -1
- package/build/computeStyles.d.ts +4 -0
- package/build/computeStyles.d.ts.map +1 -1
- package/build/computeStyles.js +5 -6
- package/build/computeStyles.js.map +1 -1
- package/build/computeStyles.web.d.ts +4 -0
- package/build/computeStyles.web.d.ts.map +1 -1
- package/build/computeStyles.web.js +2 -2
- package/build/computeStyles.web.js.map +1 -1
- package/build/useSift.d.ts +1 -6
- package/build/useSift.d.ts.map +1 -1
- package/build/useSift.js +7 -2
- package/build/useSift.js.map +1 -1
- package/package.json +5 -3
- package/src/Sift.tsx +17 -3
- package/src/computeStyles.ts +7 -7
- package/src/computeStyles.web.ts +3 -2
- package/src/useSift.ts +9 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @bsky.app/sift
|
|
2
2
|
|
|
3
|
+
## 0.3.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`345c167`](https://github.com/bluesky-social/toolbox/commit/345c1673c9cf8c83def2799326e15e2ec7a901e7) Thanks [@estrattonbailey](https://github.com/estrattonbailey)! - Split outerStyle and innerStyle for sift to allow better customization"
|
|
8
|
+
|
|
9
|
+
## 0.3.2
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- [`0828d73`](https://github.com/bluesky-social/toolbox/commit/0828d73f46b1b695488e5f968222c6c18f50a53e) Thanks [@estrattonbailey](https://github.com/estrattonbailey)! - Fix android positioning using safe-area-context in lieu of Dimensions
|
|
14
|
+
|
|
15
|
+
- [`083ac3e`](https://github.com/bluesky-social/toolbox/commit/083ac3e5b15bb750522c4c29236d52075fb01291) Thanks [@estrattonbailey](https://github.com/estrattonbailey)! - Remove deprecated APIs
|
|
16
|
+
|
|
3
17
|
## 0.3.1
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
package/build/Sift.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { type UseSiftReturn } from './useSift';
|
|
|
3
3
|
export * from './useSift';
|
|
4
4
|
export declare function Sift<Item extends {
|
|
5
5
|
key: string;
|
|
6
|
-
}>({ sift, data, render,
|
|
6
|
+
}>({ sift, data, render, outerStyle, innerStyle, onSelect, onDismiss, inverted, }: {
|
|
7
7
|
sift: UseSiftReturn;
|
|
8
8
|
data: Item[];
|
|
9
9
|
render: (props: {
|
|
@@ -18,7 +18,14 @@ export declare function Sift<Item extends {
|
|
|
18
18
|
};
|
|
19
19
|
item: Item;
|
|
20
20
|
}) => React.ReactElement;
|
|
21
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Applied to a View wrapping the FlatList.
|
|
23
|
+
*/
|
|
24
|
+
outerStyle?: StyleProp<ViewStyle>;
|
|
25
|
+
/**
|
|
26
|
+
* Applied to the FlatList itself.
|
|
27
|
+
*/
|
|
28
|
+
innerStyle?: StyleProp<ViewStyle>;
|
|
22
29
|
onSelect?: (item: Item) => void;
|
|
23
30
|
onDismiss?: () => void;
|
|
24
31
|
inverted?: boolean;
|
package/build/Sift.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Sift.d.ts","sourceRoot":"","sources":["../src/Sift.tsx"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,SAAS,EACd,KAAK,SAAS,EACd,KAAK,cAAc,EAEpB,MAAM,cAAc,CAAA;AACrB,OAAO,EAAC,KAAK,aAAa,EAAC,MAAM,WAAW,CAAA;AAG5C,cAAc,WAAW,CAAA;AAIzB,wBAAgB,IAAI,CAAC,IAAI,SAAS;IAAC,GAAG,EAAE,MAAM,CAAA;CAAC,EAAE,EAC/C,IAAI,EACJ,IAAI,EACJ,MAAM,EACN,
|
|
1
|
+
{"version":3,"file":"Sift.d.ts","sourceRoot":"","sources":["../src/Sift.tsx"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,SAAS,EACd,KAAK,SAAS,EACd,KAAK,cAAc,EAEpB,MAAM,cAAc,CAAA;AACrB,OAAO,EAAC,KAAK,aAAa,EAAC,MAAM,WAAW,CAAA;AAG5C,cAAc,WAAW,CAAA;AAIzB,wBAAgB,IAAI,CAAC,IAAI,SAAS;IAAC,GAAG,EAAE,MAAM,CAAA;CAAC,EAAE,EAC/C,IAAI,EACJ,IAAI,EACJ,MAAM,EACN,UAAU,EACV,UAAU,EACV,QAAQ,EACR,SAAS,EACT,QAAQ,GACT,EAAE;IACD,IAAI,EAAE,aAAa,CAAA;IACnB,IAAI,EAAE,IAAI,EAAE,CAAA;IACZ,MAAM,EAAE,CAAC,KAAK,EAAE;QACd,KAAK,EAAE,MAAM,CAAA;QACb,OAAO,EAAE,OAAO,CAAA;QAChB,MAAM,EAAE,OAAO,CAAA;QACf,MAAM,EAAE,OAAO,CAAA;QACf,KAAK,EAAE;YACL,IAAI,EAAE,MAAM,CAAA;YACZ,eAAe,EAAE,OAAO,CAAA;YACxB,OAAO,EAAE,MAAM,IAAI,CAAA;SACpB,CAAA;QACD,IAAI,EAAE,IAAI,CAAA;KACX,KAAK,KAAK,CAAC,YAAY,CAAA;IACxB;;OAEG;IACH,UAAU,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAA;IACjC;;OAEG;IACH,UAAU,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAA;IACjC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAA;IAC/B,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,2CA2FA;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,EACvB,QAAQ,EACR,IAAI,EACJ,KAAK,EACL,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EACF,SAAS,CAAC,SAAS,CAAC,GACpB,CAAC,CAAC,KAAK,EAAE;QAAC,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAC,KAAK,SAAS,CAAC,SAAS,CAAC,CAAC,GACvE,SAAS,CAAA;CACd,2CASA"}
|
package/build/Sift.js
CHANGED
|
@@ -4,7 +4,7 @@ import { View, FlatList, Pressable, } from 'react-native';
|
|
|
4
4
|
import { useKeyboardHandling } from './useKeyboardHandling';
|
|
5
5
|
export * from './useSift';
|
|
6
6
|
const keyExtractor = (item) => item.key;
|
|
7
|
-
export function Sift({ sift, data, render,
|
|
7
|
+
export function Sift({ sift, data, render, outerStyle, innerStyle, onSelect, onDismiss, inverted, }) {
|
|
8
8
|
const [activeIndex, setActiveIndex] = useState(0);
|
|
9
9
|
const activeIndexRef = useRef(activeIndex);
|
|
10
10
|
activeIndexRef.current = activeIndex;
|
|
@@ -53,7 +53,12 @@ export function Sift({ sift, data, render, style, onSelect, onDismiss, inverted,
|
|
|
53
53
|
onDismiss,
|
|
54
54
|
});
|
|
55
55
|
const hasStyles = sift.popoverStyles.top != null;
|
|
56
|
-
return (_jsx(View, { collapsable: false, ref: sift.refs.setPopover, role: 'listbox', id: sift.id, style: [
|
|
56
|
+
return (_jsx(View, { collapsable: false, ref: sift.refs.setPopover, role: 'listbox', id: sift.id, style: [
|
|
57
|
+
{ width: '100%' },
|
|
58
|
+
outerStyle,
|
|
59
|
+
sift.popoverStyles,
|
|
60
|
+
!hasStyles && { opacity: 0 },
|
|
61
|
+
],
|
|
57
62
|
// @ts-ignore web only
|
|
58
63
|
onMouseDown: e => {
|
|
59
64
|
e.preventDefault();
|
|
@@ -68,7 +73,7 @@ export function Sift({ sift, data, render, style, onSelect, onDismiss, inverted,
|
|
|
68
73
|
onPress: () => onSelectRef.current?.(item.item),
|
|
69
74
|
},
|
|
70
75
|
item: item.item,
|
|
71
|
-
}), []), keyboardShouldPersistTaps: "handled" }) }));
|
|
76
|
+
}), []), keyboardShouldPersistTaps: "handled", style: innerStyle }) }));
|
|
72
77
|
}
|
|
73
78
|
/**
|
|
74
79
|
* A Pressable wrapper for items rendered in Sift. It applies the necessary
|
package/build/Sift.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Sift.js","sourceRoot":"","sources":["../src/Sift.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAC,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAC,MAAM,OAAO,CAAA;AAC9D,OAAO,EACL,IAAI,EACJ,QAAQ,EACR,SAAS,GAKV,MAAM,cAAc,CAAA;AAErB,OAAO,EAAC,mBAAmB,EAAC,MAAM,uBAAuB,CAAA;AAEzD,cAAc,WAAW,CAAA;AAEzB,MAAM,YAAY,GAAG,CAAC,IAAmB,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAA;AAEtD,MAAM,UAAU,IAAI,CAA6B,EAC/C,IAAI,EACJ,IAAI,EACJ,MAAM,EACN,
|
|
1
|
+
{"version":3,"file":"Sift.js","sourceRoot":"","sources":["../src/Sift.tsx"],"names":[],"mappings":"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","sourcesContent":["import {useCallback, useEffect, useRef, useState} from 'react'\nimport {\n View,\n FlatList,\n Pressable,\n type StyleProp,\n type ViewStyle,\n type PressableProps,\n type Role,\n} from 'react-native'\nimport {type UseSiftReturn} from './useSift'\nimport {useKeyboardHandling} from './useKeyboardHandling'\n\nexport * from './useSift'\n\nconst keyExtractor = (item: {key: string}) => item.key\n\nexport function Sift<Item extends {key: string}>({\n sift,\n data,\n render,\n outerStyle,\n innerStyle,\n onSelect,\n onDismiss,\n inverted,\n}: {\n sift: UseSiftReturn\n data: Item[]\n render: (props: {\n index: number\n isFirst: boolean\n isLast: boolean\n active: boolean\n props: {\n role: string\n 'aria-selected': boolean\n onPress: () => void\n }\n item: Item\n }) => React.ReactElement\n /**\n * Applied to a View wrapping the FlatList.\n */\n outerStyle?: StyleProp<ViewStyle>\n /**\n * Applied to the FlatList itself.\n */\n innerStyle?: StyleProp<ViewStyle>\n onSelect?: (item: Item) => void\n onDismiss?: () => void\n inverted?: boolean\n}) {\n const [activeIndex, setActiveIndex] = useState(0)\n const activeIndexRef = useRef(activeIndex)\n activeIndexRef.current = activeIndex\n const dataLenRef = useRef(data.length)\n dataLenRef.current = data.length\n const updateRef = useRef(sift.updatePosition)\n updateRef.current = sift.updatePosition\n const renderRef = useRef(render)\n renderRef.current = render\n const onSelectRef = useRef(onSelect)\n onSelectRef.current = onSelect\n\n useEffect(() => {\n if (activeIndexRef.current !== 0) setActiveIndex(0)\n updateRef.current()\n }, [data.length])\n\n const next = useCallback(() => {\n if (dataLenRef.current === 0) return\n setActiveIndex(i => (i + 1) % dataLenRef.current)\n }, [])\n const prev = useCallback(() => {\n if (dataLenRef.current === 0) return\n setActiveIndex(i => (i - 1 + dataLenRef.current) % dataLenRef.current)\n }, [])\n const first = useCallback(() => {\n if (dataLenRef.current === 0) return\n setActiveIndex(0)\n }, [])\n const last = useCallback(() => {\n if (dataLenRef.current === 0) return\n setActiveIndex(dataLenRef.current - 1)\n }, [])\n\n useKeyboardHandling({\n sift,\n onArrowDown: inverted ? prev : next,\n onArrowUp: inverted ? next : prev,\n onHome: inverted ? last : first,\n onEnd: inverted ? first : last,\n onSelect: () => {\n onSelect?.(data[activeIndexRef.current])\n },\n onDismiss,\n })\n\n const hasStyles = sift.popoverStyles.top != null\n\n return (\n <View\n collapsable={false}\n ref={sift.refs.setPopover}\n role={'listbox' as any}\n id={sift.id}\n style={[\n {width: '100%'},\n outerStyle,\n sift.popoverStyles,\n !hasStyles && {opacity: 0},\n ]}\n // @ts-ignore web only\n onMouseDown={e => {\n e.preventDefault()\n }}>\n <FlatList\n data={data}\n inverted={inverted}\n keyExtractor={keyExtractor}\n extraData={activeIndex}\n renderItem={useCallback(\n (item: {item: Item; index: number}) =>\n renderRef.current({\n index: item.index,\n isFirst: item.index === 0,\n isLast: item.index === data.length - 1,\n active: item.index === activeIndexRef.current,\n props: {\n role: 'option',\n 'aria-selected': item.index === activeIndexRef.current,\n onPress: () => onSelectRef.current?.(item.item),\n },\n item: item.item,\n }),\n [],\n )}\n keyboardShouldPersistTaps=\"handled\"\n style={innerStyle}\n />\n </View>\n )\n}\n\n/**\n * A Pressable wrapper for items rendered in Sift. It applies the necessary\n * accessibility props for each item.\n */\nexport function SiftItem({\n children,\n role,\n style,\n ...props\n}: Omit<PressableProps, 'role' | 'style'> & {\n role?: string\n style?:\n | StyleProp<ViewStyle>\n | ((state: {pressed: boolean; hovered: boolean}) => StyleProp<ViewStyle>)\n | undefined\n}) {\n return (\n <Pressable\n role={role as Role}\n style={style as PressableProps['style']}\n {...props}>\n {children}\n </Pressable>\n )\n}\n"]}
|
package/build/computeStyles.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"computeStyles.d.ts","sourceRoot":"","sources":["../src/computeStyles.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"computeStyles.d.ts","sourceRoot":"","sources":["../src/computeStyles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,SAAS,EAAC,MAAM,cAAc,CAAA;AACrD,OAAO,EAAC,KAAK,SAAS,EAAC,MAAM,WAAW,CAAA;AAkBxC,wBAAsB,aAAa,CACjC,EACE,MAAM,EACN,KAAK,EACL,OAAO,GACR,EAAE;IACD,MAAM,EAAE,GAAG,CAAA;IACX,KAAK,EAAE,GAAG,CAAA;IACV,OAAO,EAAE,GAAG,GAAG,IAAI,CAAA;CACpB,EACD,OAAO,EAAE;IACP,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,SAAS,CAAA;IACpB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,MAAM,CAAC,EAAE;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAC,CAAA;IACtC,MAAM,EAAE;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAC,CAAA;CACxC,GACA,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CA2D3B"}
|
package/build/computeStyles.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Platform } from 'react-native';
|
|
2
2
|
function measureInWindow(node) {
|
|
3
3
|
return new Promise(resolve => {
|
|
4
4
|
try {
|
|
@@ -25,20 +25,19 @@ export async function computeStyles({ anchor, input, popover, }, options) {
|
|
|
25
25
|
const [side, align] = options.placement.split('-');
|
|
26
26
|
const insetTop = options.insets?.top ?? 0;
|
|
27
27
|
const insetBottom = options.insets?.bottom ?? 0;
|
|
28
|
+
// android reports measurements minus insets
|
|
29
|
+
const anchorTop = Platform.OS === 'android' ? anchorRect.y + insetTop : anchorRect.y;
|
|
28
30
|
let top = 'auto';
|
|
29
31
|
let bottom = 'auto';
|
|
30
32
|
let maxHeight;
|
|
31
33
|
if (side === 'top') {
|
|
32
|
-
|
|
33
|
-
const windowHeight = Dimensions.get('window').height +
|
|
34
|
-
(Platform.OS === 'android' ? insetBottom : 0);
|
|
35
|
-
bottom = windowHeight - anchorRect.y + options.offset;
|
|
34
|
+
bottom = options.window.height - anchorTop + options.offset;
|
|
36
35
|
maxHeight = anchorRect.y - options.offset - insetTop;
|
|
37
36
|
}
|
|
38
37
|
else {
|
|
39
38
|
top = anchorRect.y + anchorRect.height + options.offset;
|
|
40
39
|
maxHeight =
|
|
41
|
-
|
|
40
|
+
options.window.height -
|
|
42
41
|
insetBottom -
|
|
43
42
|
(anchorRect.y + anchorRect.height + options.offset);
|
|
44
43
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"computeStyles.js","sourceRoot":"","sources":["../src/computeStyles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,
|
|
1
|
+
{"version":3,"file":"computeStyles.js","sourceRoot":"","sources":["../src/computeStyles.ts"],"names":[],"mappings":"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","sourcesContent":["import {Platform, type ViewStyle} from 'react-native'\nimport {type Placement} from './useSift'\n\nfunction measureInWindow(\n node: any,\n): Promise<{x: number; y: number; width: number; height: number}> {\n return new Promise(resolve => {\n try {\n node.measureInWindow(\n (x: number, y: number, width: number, height: number) => {\n resolve({x, y, width, height})\n },\n )\n } catch {\n resolve({x: 0, y: 0, width: 0, height: 0})\n }\n })\n}\n\nexport async function computeStyles(\n {\n anchor,\n input,\n popover,\n }: {\n anchor: any\n input: any\n popover: any | null\n },\n options: {\n offset: number\n placement: Placement\n dynamicWidth?: boolean\n insets?: {top: number; bottom: number}\n window: {width: number; height: number}\n },\n): Promise<ViewStyle | null> {\n const anchorRect = await measureInWindow(anchor)\n const inputRect = await measureInWindow(input)\n const popoverRect = popover ? await measureInWindow(popover) : null\n\n // If any measurement failed (view not in hierarchy yet), return null\n // so the caller keeps the previous styles.\n if (!anchorRect.width || !inputRect.width) return null\n if (popoverRect && !popoverRect.width && !popoverRect.height) return null\n\n const popoverWidth = popoverRect?.width ?? 0\n const [side, align] = options.placement.split('-') as [\n string,\n string | undefined,\n ]\n\n const insetTop = options.insets?.top ?? 0\n const insetBottom = options.insets?.bottom ?? 0\n // android reports measurements minus insets\n const anchorTop =\n Platform.OS === 'android' ? anchorRect.y + insetTop : anchorRect.y\n\n let top: number | 'auto' = 'auto'\n let bottom: number | 'auto' = 'auto'\n let maxHeight: number | undefined\n if (side === 'top') {\n bottom = options.window.height - anchorTop + options.offset\n maxHeight = anchorRect.y - options.offset - insetTop\n } else {\n top = anchorRect.y + anchorRect.height + options.offset\n maxHeight =\n options.window.height -\n insetBottom -\n (anchorRect.y + anchorRect.height + options.offset)\n }\n\n let left: number\n if (align === 'start') {\n left = anchorRect.x\n } else if (align === 'end') {\n left = anchorRect.x + anchorRect.width - popoverWidth\n } else {\n left = anchorRect.x + (anchorRect.width - popoverWidth) / 2\n }\n\n let maxWidth: number | undefined\n if (options.dynamicWidth === false) {\n left = anchorRect.x\n maxWidth = anchorRect.width\n }\n\n return {\n position: 'absolute',\n top,\n bottom,\n left,\n maxWidth,\n maxHeight,\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"computeStyles.web.d.ts","sourceRoot":"","sources":["../src/computeStyles.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,SAAS,EAAC,MAAM,cAAc,CAAA;AAC3C,OAAO,EAAC,KAAK,SAAS,EAAC,MAAM,WAAW,CAAA;AAExC,wBAAgB,aAAa,CAC3B,EACE,MAAM,EACN,KAAK,EACL,OAAO,GACR,EAAE;IACD,MAAM,EAAE,WAAW,CAAA;IACnB,KAAK,EAAE,WAAW,CAAA;IAClB,OAAO,EAAE,WAAW,GAAG,IAAI,CAAA;CAC5B,EACD,OAAO,EAAE;IACP,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,SAAS,CAAA;IACpB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,MAAM,CAAC,EAAE;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"computeStyles.web.d.ts","sourceRoot":"","sources":["../src/computeStyles.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,SAAS,EAAC,MAAM,cAAc,CAAA;AAC3C,OAAO,EAAC,KAAK,SAAS,EAAC,MAAM,WAAW,CAAA;AAExC,wBAAgB,aAAa,CAC3B,EACE,MAAM,EACN,KAAK,EACL,OAAO,GACR,EAAE;IACD,MAAM,EAAE,WAAW,CAAA;IACnB,KAAK,EAAE,WAAW,CAAA;IAClB,OAAO,EAAE,WAAW,GAAG,IAAI,CAAA;CAC5B,EACD,OAAO,EAAE;IACP,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,SAAS,CAAA;IACpB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,MAAM,CAAC,EAAE;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAC,CAAA;IACtC,MAAM,EAAE;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAC,CAAA;CACxC,GACA,SAAS,GAAG,IAAI,CAuDlB"}
|
|
@@ -16,13 +16,13 @@ export function computeStyles({ anchor, input, popover, }, options) {
|
|
|
16
16
|
let bottom = 'auto';
|
|
17
17
|
let maxHeight;
|
|
18
18
|
if (side === 'top') {
|
|
19
|
-
bottom = window.
|
|
19
|
+
bottom = options.window.height - anchorRect.top + options.offset;
|
|
20
20
|
maxHeight = anchorRect.top - options.offset - insetTop;
|
|
21
21
|
}
|
|
22
22
|
else {
|
|
23
23
|
top = anchorRect.bottom + options.offset;
|
|
24
24
|
maxHeight =
|
|
25
|
-
window.
|
|
25
|
+
options.window.height - insetBottom - anchorRect.bottom - options.offset;
|
|
26
26
|
}
|
|
27
27
|
let left;
|
|
28
28
|
if (align === 'start') {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"computeStyles.web.js","sourceRoot":"","sources":["../src/computeStyles.web.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,aAAa,CAC3B,EACE,MAAM,EACN,KAAK,EACL,OAAO,GAKR,EACD,
|
|
1
|
+
{"version":3,"file":"computeStyles.web.js","sourceRoot":"","sources":["../src/computeStyles.web.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,aAAa,CAC3B,EACE,MAAM,EACN,KAAK,EACL,OAAO,GAKR,EACD,OAMC;IAED,MAAM,UAAU,GAAG,MAAM,CAAC,qBAAqB,EAAE,CAAA;IACjD,MAAM,SAAS,GAAG,KAAK,CAAC,qBAAqB,EAAE,CAAA;IAC/C,MAAM,WAAW,GAAG,OAAO,EAAE,qBAAqB,EAAE,CAAA;IAEpD,qEAAqE;IACrE,2CAA2C;IAC3C,IAAI,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,KAAK;QAAE,OAAO,IAAI,CAAA;IACtD,IAAI,WAAW,IAAI,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC,WAAW,CAAC,MAAM;QAAE,OAAO,IAAI,CAAA;IAEzE,MAAM,YAAY,GAAG,WAAW,EAAE,KAAK,IAAI,CAAC,CAAA;IAC5C,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAGhD,CAAA;IAED,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAA;IACzC,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,CAAA;IAE/C,IAAI,GAAG,GAAoB,MAAM,CAAA;IACjC,IAAI,MAAM,GAAoB,MAAM,CAAA;IACpC,IAAI,SAA6B,CAAA;IACjC,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;QACnB,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,GAAG,UAAU,CAAC,GAAG,GAAG,OAAO,CAAC,MAAM,CAAA;QAChE,SAAS,GAAG,UAAU,CAAC,GAAG,GAAG,OAAO,CAAC,MAAM,GAAG,QAAQ,CAAA;IACxD,CAAC;SAAM,CAAC;QACN,GAAG,GAAG,UAAU,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAA;QACxC,SAAS;YACP,OAAO,CAAC,MAAM,CAAC,MAAM,GAAG,WAAW,GAAG,UAAU,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAA;IAC5E,CAAC;IAED,IAAI,IAAY,CAAA;IAChB,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;QACtB,IAAI,GAAG,UAAU,CAAC,IAAI,CAAA;IACxB,CAAC;SAAM,IAAI,KAAK,KAAK,KAAK,EAAE,CAAC;QAC3B,IAAI,GAAG,UAAU,CAAC,KAAK,GAAG,YAAY,CAAA;IACxC,CAAC;SAAM,CAAC;QACN,IAAI,GAAG,UAAU,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC,CAAA;IAChE,CAAC;IAED,IAAI,QAA4B,CAAA;IAChC,IAAI,OAAO,CAAC,YAAY,KAAK,KAAK,EAAE,CAAC;QACnC,IAAI,GAAG,UAAU,CAAC,IAAI,CAAA;QACtB,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAA;IAC7B,CAAC;IAED,OAAO;QACL,aAAa;QACb,QAAQ,EAAE,OAAO;QACjB,GAAG;QACH,MAAM;QACN,IAAI;QACJ,QAAQ;QACR,SAAS;KACV,CAAA;AACH,CAAC","sourcesContent":["import {type ViewStyle} from 'react-native'\nimport {type Placement} from './useSift'\n\nexport function computeStyles(\n {\n anchor,\n input,\n popover,\n }: {\n anchor: HTMLElement\n input: HTMLElement\n popover: HTMLElement | null\n },\n options: {\n offset: number\n placement: Placement\n dynamicWidth?: boolean\n insets?: {top: number; bottom: number}\n window: {width: number; height: number}\n },\n): ViewStyle | null {\n const anchorRect = anchor.getBoundingClientRect()\n const inputRect = input.getBoundingClientRect()\n const popoverRect = popover?.getBoundingClientRect()\n\n // If any measurement failed (view not in hierarchy yet), return null\n // so the caller keeps the previous styles.\n if (!anchorRect.width || !inputRect.width) return null\n if (popoverRect && !popoverRect.width && !popoverRect.height) return null\n\n const popoverWidth = popoverRect?.width ?? 0\n const [side, align] = options.placement.split('-') as [\n string,\n string | undefined,\n ]\n\n const insetTop = options.insets?.top ?? 0\n const insetBottom = options.insets?.bottom ?? 0\n\n let top: number | 'auto' = 'auto'\n let bottom: number | 'auto' = 'auto'\n let maxHeight: number | undefined\n if (side === 'top') {\n bottom = options.window.height - anchorRect.top + options.offset\n maxHeight = anchorRect.top - options.offset - insetTop\n } else {\n top = anchorRect.bottom + options.offset\n maxHeight =\n options.window.height - insetBottom - anchorRect.bottom - options.offset\n }\n\n let left: number\n if (align === 'start') {\n left = anchorRect.left\n } else if (align === 'end') {\n left = anchorRect.right - popoverWidth\n } else {\n left = anchorRect.left + (anchorRect.width - popoverWidth) / 2\n }\n\n let maxWidth: number | undefined\n if (options.dynamicWidth === false) {\n left = anchorRect.left\n maxWidth = anchorRect.width\n }\n\n return {\n // @ts-ignore\n position: 'fixed',\n top,\n bottom,\n left,\n maxWidth,\n maxHeight,\n }\n}\n"]}
|
package/build/useSift.d.ts
CHANGED
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
import { type ViewStyle } from 'react-native';
|
|
2
2
|
export type Placement = 'top' | 'top-start' | 'top-end' | 'bottom' | 'bottom-start' | 'bottom-end';
|
|
3
3
|
export type UseSiftReturn = ReturnType<typeof useSift>;
|
|
4
|
-
export declare function useSift({ offset: offsetValue, placement, dynamicWidth,
|
|
4
|
+
export declare function useSift({ offset: offsetValue, placement, dynamicWidth, }?: {
|
|
5
5
|
offset?: number;
|
|
6
6
|
placement?: Placement;
|
|
7
7
|
dynamicWidth?: boolean;
|
|
8
|
-
insets?: {
|
|
9
|
-
top: number;
|
|
10
|
-
bottom: number;
|
|
11
|
-
};
|
|
12
|
-
anchorRef?: React.RefObject<any>;
|
|
13
8
|
}): {
|
|
14
9
|
id: string;
|
|
15
10
|
refs: {
|
package/build/useSift.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSift.d.ts","sourceRoot":"","sources":["../src/useSift.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,KAAK,SAAS,EAAC,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"useSift.d.ts","sourceRoot":"","sources":["../src/useSift.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,KAAK,SAAS,EAAC,MAAM,cAAc,CAAA;AAS3C,MAAM,MAAM,SAAS,GACjB,KAAK,GACL,WAAW,GACX,SAAS,GACT,QAAQ,GACR,cAAc,GACd,YAAY,CAAA;AAEhB,MAAM,MAAM,aAAa,GAAG,UAAU,CAAC,OAAO,OAAO,CAAC,CAAA;AAEtD,wBAAgB,OAAO,CAAC,EACtB,MAAM,EAAE,WAAe,EACvB,SAAoB,EACpB,YAAoB,GACrB,GAAE;IACD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,YAAY,CAAC,EAAE,OAAO,CAAA;CAClB;;;2BAuDK,GAAG;0BAaH,GAAG;;;;;;;;;;oBAnB8B,GAAG;;;;;;EAiD9C"}
|
package/build/useSift.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { useCallback, useId, useRef, useState } from 'react';
|
|
2
|
+
import { useSafeAreaInsets, useSafeAreaFrame, } from 'react-native-safe-area-context';
|
|
2
3
|
import { computeStyles } from './computeStyles';
|
|
3
4
|
const DEFAULT_POPOVER_STYLES = { position: 'absolute' };
|
|
4
|
-
export function useSift({ offset: offsetValue = 0, placement = 'bottom', dynamicWidth = false,
|
|
5
|
+
export function useSift({ offset: offsetValue = 0, placement = 'bottom', dynamicWidth = false, } = {}) {
|
|
5
6
|
const id = useId();
|
|
7
|
+
const insets = useSafeAreaInsets();
|
|
8
|
+
const window = useSafeAreaFrame();
|
|
6
9
|
/*
|
|
7
10
|
* These are reactive values and need to remain in state
|
|
8
11
|
*/
|
|
@@ -15,18 +18,20 @@ export function useSift({ offset: offsetValue = 0, placement = 'bottom', dynamic
|
|
|
15
18
|
*/
|
|
16
19
|
const inputRef = useRef(null);
|
|
17
20
|
const popoverRef = useRef(null);
|
|
18
|
-
const anchorRef = useRef(
|
|
21
|
+
const anchorRef = useRef(null);
|
|
19
22
|
const options = useRef({
|
|
20
23
|
offset: offsetValue,
|
|
21
24
|
placement,
|
|
22
25
|
dynamicWidth,
|
|
23
26
|
insets,
|
|
27
|
+
window,
|
|
24
28
|
});
|
|
25
29
|
options.current = {
|
|
26
30
|
offset: offsetValue,
|
|
27
31
|
placement,
|
|
28
32
|
dynamicWidth,
|
|
29
33
|
insets,
|
|
34
|
+
window,
|
|
30
35
|
};
|
|
31
36
|
const update = useCallback(async () => {
|
|
32
37
|
if (!inputRef.current || !popoverRef.current)
|
package/build/useSift.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSift.js","sourceRoot":"","sources":["../src/useSift.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAC,MAAM,OAAO,CAAA;AAE1D,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAA;AAE7C,MAAM,sBAAsB,GAAc,EAAC,QAAQ,EAAE,UAAU,EAAC,CAAA;AAYhE,MAAM,UAAU,OAAO,CAAC,EACtB,MAAM,EAAE,WAAW,GAAG,CAAC,EACvB,SAAS,GAAG,QAAQ,EACpB,YAAY,GAAG,KAAK,
|
|
1
|
+
{"version":3,"file":"useSift.js","sourceRoot":"","sources":["../src/useSift.ts"],"names":[],"mappings":"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","sourcesContent":["import {useCallback, useId, useRef, useState} from 'react'\nimport {type ViewStyle} from 'react-native'\nimport {\n useSafeAreaInsets,\n useSafeAreaFrame,\n} from 'react-native-safe-area-context'\nimport {computeStyles} from './computeStyles'\n\nconst DEFAULT_POPOVER_STYLES: ViewStyle = {position: 'absolute'}\n\nexport type Placement =\n | 'top'\n | 'top-start'\n | 'top-end'\n | 'bottom'\n | 'bottom-start'\n | 'bottom-end'\n\nexport type UseSiftReturn = ReturnType<typeof useSift>\n\nexport function useSift({\n offset: offsetValue = 0,\n placement = 'bottom',\n dynamicWidth = false,\n}: {\n offset?: number\n placement?: Placement\n dynamicWidth?: boolean\n} = {}) {\n const id = useId()\n const insets = useSafeAreaInsets()\n const window = useSafeAreaFrame()\n\n /*\n * These are reactive values and need to remain in state\n */\n const [input, setInput] = useState<any>(null)\n const [popover, setPopover] = useState<any>(null)\n const [popoverStyles, setPopoverStyles] = useState<ViewStyle>(\n DEFAULT_POPOVER_STYLES,\n )\n\n /*\n * These are non-reactive values that we want to persist across renders\n * without causing re-renders when they change, so we store them in refs.\n */\n const inputRef = useRef<any>(null)\n const popoverRef = useRef<any>(null)\n const anchorRef = useRef<any>(null)\n const options = useRef({\n offset: offsetValue,\n placement,\n dynamicWidth,\n insets,\n window,\n })\n options.current = {\n offset: offsetValue,\n placement,\n dynamicWidth,\n insets,\n window,\n }\n\n const update = useCallback(async () => {\n if (!inputRef.current || !popoverRef.current) return\n const styles = await computeStyles(\n {\n anchor: anchorRef.current || inputRef.current,\n input: inputRef.current,\n popover: popoverRef.current,\n },\n options.current,\n )\n if (styles) setPopoverStyles(styles)\n }, [])\n\n const handleSetInput = useCallback((node: any) => {\n inputRef.current = node\n setInput(node)\n }, [])\n\n const handleSetPopover = useCallback(\n (node: any) => {\n popoverRef.current = node\n setPopover(node)\n if (node) {\n update()\n } else {\n setPopoverStyles(DEFAULT_POPOVER_STYLES)\n }\n },\n [update],\n )\n\n const handleSetAnchor = useCallback(\n (node: any) => {\n anchorRef.current = node\n if (node) update()\n },\n [update],\n )\n\n return {\n id,\n refs: {\n setPopover: handleSetPopover,\n setAnchor: handleSetAnchor,\n },\n elements: {\n input,\n popover,\n },\n isActive() {\n return !!popover\n },\n popoverStyles,\n updatePosition: update,\n targetProps: {\n ref: handleSetInput,\n role: 'combobox' as const,\n 'aria-controls': id,\n 'aria-expanded': !!popover,\n 'aria-autocomplete': 'list' as const,\n },\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bsky.app/sift",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "A little React Native library for building autocompletes.",
|
|
6
6
|
"repository": "https://github.com/bluesky-social/toolbox",
|
|
@@ -25,10 +25,12 @@
|
|
|
25
25
|
"peerDependencies": {
|
|
26
26
|
"expo": "*",
|
|
27
27
|
"react": "*",
|
|
28
|
-
"react-native": "*"
|
|
28
|
+
"react-native": "*",
|
|
29
|
+
"react-native-safe-area-context": "~5.6.0"
|
|
29
30
|
},
|
|
30
31
|
"scripts": {
|
|
31
|
-
"build": "expo-module clean && expo-module build",
|
|
32
|
+
"build": "expo-module clean && EXPO_NONINTERACTIVE=1 expo-module build",
|
|
33
|
+
"watch": "expo-module clean && expo-module build",
|
|
32
34
|
"clean": "expo-module clean",
|
|
33
35
|
"lint": "expo-module lint",
|
|
34
36
|
"test": "vitest run",
|
package/src/Sift.tsx
CHANGED
|
@@ -19,7 +19,8 @@ export function Sift<Item extends {key: string}>({
|
|
|
19
19
|
sift,
|
|
20
20
|
data,
|
|
21
21
|
render,
|
|
22
|
-
|
|
22
|
+
outerStyle,
|
|
23
|
+
innerStyle,
|
|
23
24
|
onSelect,
|
|
24
25
|
onDismiss,
|
|
25
26
|
inverted,
|
|
@@ -38,7 +39,14 @@ export function Sift<Item extends {key: string}>({
|
|
|
38
39
|
}
|
|
39
40
|
item: Item
|
|
40
41
|
}) => React.ReactElement
|
|
41
|
-
|
|
42
|
+
/**
|
|
43
|
+
* Applied to a View wrapping the FlatList.
|
|
44
|
+
*/
|
|
45
|
+
outerStyle?: StyleProp<ViewStyle>
|
|
46
|
+
/**
|
|
47
|
+
* Applied to the FlatList itself.
|
|
48
|
+
*/
|
|
49
|
+
innerStyle?: StyleProp<ViewStyle>
|
|
42
50
|
onSelect?: (item: Item) => void
|
|
43
51
|
onDismiss?: () => void
|
|
44
52
|
inverted?: boolean
|
|
@@ -97,7 +105,12 @@ export function Sift<Item extends {key: string}>({
|
|
|
97
105
|
ref={sift.refs.setPopover}
|
|
98
106
|
role={'listbox' as any}
|
|
99
107
|
id={sift.id}
|
|
100
|
-
style={[
|
|
108
|
+
style={[
|
|
109
|
+
{width: '100%'},
|
|
110
|
+
outerStyle,
|
|
111
|
+
sift.popoverStyles,
|
|
112
|
+
!hasStyles && {opacity: 0},
|
|
113
|
+
]}
|
|
101
114
|
// @ts-ignore web only
|
|
102
115
|
onMouseDown={e => {
|
|
103
116
|
e.preventDefault()
|
|
@@ -124,6 +137,7 @@ export function Sift<Item extends {key: string}>({
|
|
|
124
137
|
[],
|
|
125
138
|
)}
|
|
126
139
|
keyboardShouldPersistTaps="handled"
|
|
140
|
+
style={innerStyle}
|
|
127
141
|
/>
|
|
128
142
|
</View>
|
|
129
143
|
)
|
package/src/computeStyles.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {Platform, type ViewStyle} from 'react-native'
|
|
2
2
|
import {type Placement} from './useSift'
|
|
3
3
|
|
|
4
4
|
function measureInWindow(
|
|
@@ -32,6 +32,7 @@ export async function computeStyles(
|
|
|
32
32
|
placement: Placement
|
|
33
33
|
dynamicWidth?: boolean
|
|
34
34
|
insets?: {top: number; bottom: number}
|
|
35
|
+
window: {width: number; height: number}
|
|
35
36
|
},
|
|
36
37
|
): Promise<ViewStyle | null> {
|
|
37
38
|
const anchorRect = await measureInWindow(anchor)
|
|
@@ -51,21 +52,20 @@ export async function computeStyles(
|
|
|
51
52
|
|
|
52
53
|
const insetTop = options.insets?.top ?? 0
|
|
53
54
|
const insetBottom = options.insets?.bottom ?? 0
|
|
55
|
+
// android reports measurements minus insets
|
|
56
|
+
const anchorTop =
|
|
57
|
+
Platform.OS === 'android' ? anchorRect.y + insetTop : anchorRect.y
|
|
54
58
|
|
|
55
59
|
let top: number | 'auto' = 'auto'
|
|
56
60
|
let bottom: number | 'auto' = 'auto'
|
|
57
61
|
let maxHeight: number | undefined
|
|
58
62
|
if (side === 'top') {
|
|
59
|
-
|
|
60
|
-
const windowHeight =
|
|
61
|
-
Dimensions.get('window').height +
|
|
62
|
-
(Platform.OS === 'android' ? insetBottom : 0)
|
|
63
|
-
bottom = windowHeight - anchorRect.y + options.offset
|
|
63
|
+
bottom = options.window.height - anchorTop + options.offset
|
|
64
64
|
maxHeight = anchorRect.y - options.offset - insetTop
|
|
65
65
|
} else {
|
|
66
66
|
top = anchorRect.y + anchorRect.height + options.offset
|
|
67
67
|
maxHeight =
|
|
68
|
-
|
|
68
|
+
options.window.height -
|
|
69
69
|
insetBottom -
|
|
70
70
|
(anchorRect.y + anchorRect.height + options.offset)
|
|
71
71
|
}
|
package/src/computeStyles.web.ts
CHANGED
|
@@ -16,6 +16,7 @@ export function computeStyles(
|
|
|
16
16
|
placement: Placement
|
|
17
17
|
dynamicWidth?: boolean
|
|
18
18
|
insets?: {top: number; bottom: number}
|
|
19
|
+
window: {width: number; height: number}
|
|
19
20
|
},
|
|
20
21
|
): ViewStyle | null {
|
|
21
22
|
const anchorRect = anchor.getBoundingClientRect()
|
|
@@ -40,12 +41,12 @@ export function computeStyles(
|
|
|
40
41
|
let bottom: number | 'auto' = 'auto'
|
|
41
42
|
let maxHeight: number | undefined
|
|
42
43
|
if (side === 'top') {
|
|
43
|
-
bottom = window.
|
|
44
|
+
bottom = options.window.height - anchorRect.top + options.offset
|
|
44
45
|
maxHeight = anchorRect.top - options.offset - insetTop
|
|
45
46
|
} else {
|
|
46
47
|
top = anchorRect.bottom + options.offset
|
|
47
48
|
maxHeight =
|
|
48
|
-
window.
|
|
49
|
+
options.window.height - insetBottom - anchorRect.bottom - options.offset
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
let left: number
|
package/src/useSift.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import {useCallback, useId, useRef, useState} from 'react'
|
|
2
2
|
import {type ViewStyle} from 'react-native'
|
|
3
|
+
import {
|
|
4
|
+
useSafeAreaInsets,
|
|
5
|
+
useSafeAreaFrame,
|
|
6
|
+
} from 'react-native-safe-area-context'
|
|
3
7
|
import {computeStyles} from './computeStyles'
|
|
4
8
|
|
|
5
9
|
const DEFAULT_POPOVER_STYLES: ViewStyle = {position: 'absolute'}
|
|
@@ -18,16 +22,14 @@ export function useSift({
|
|
|
18
22
|
offset: offsetValue = 0,
|
|
19
23
|
placement = 'bottom',
|
|
20
24
|
dynamicWidth = false,
|
|
21
|
-
insets,
|
|
22
|
-
anchorRef: externalAnchorRef,
|
|
23
25
|
}: {
|
|
24
26
|
offset?: number
|
|
25
27
|
placement?: Placement
|
|
26
28
|
dynamicWidth?: boolean
|
|
27
|
-
insets?: {top: number; bottom: number}
|
|
28
|
-
anchorRef?: React.RefObject<any>
|
|
29
29
|
} = {}) {
|
|
30
30
|
const id = useId()
|
|
31
|
+
const insets = useSafeAreaInsets()
|
|
32
|
+
const window = useSafeAreaFrame()
|
|
31
33
|
|
|
32
34
|
/*
|
|
33
35
|
* These are reactive values and need to remain in state
|
|
@@ -44,18 +46,20 @@ export function useSift({
|
|
|
44
46
|
*/
|
|
45
47
|
const inputRef = useRef<any>(null)
|
|
46
48
|
const popoverRef = useRef<any>(null)
|
|
47
|
-
const anchorRef = useRef<any>(
|
|
49
|
+
const anchorRef = useRef<any>(null)
|
|
48
50
|
const options = useRef({
|
|
49
51
|
offset: offsetValue,
|
|
50
52
|
placement,
|
|
51
53
|
dynamicWidth,
|
|
52
54
|
insets,
|
|
55
|
+
window,
|
|
53
56
|
})
|
|
54
57
|
options.current = {
|
|
55
58
|
offset: offsetValue,
|
|
56
59
|
placement,
|
|
57
60
|
dynamicWidth,
|
|
58
61
|
insets,
|
|
62
|
+
window,
|
|
59
63
|
}
|
|
60
64
|
|
|
61
65
|
const update = useCallback(async () => {
|