@bsky.app/sift 0.2.10 → 0.3.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/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # @bsky.app/sift
2
2
 
3
+ ## 0.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`878376e`](https://github.com/bluesky-social/toolbox/commit/878376ea9e87779eb8930771acf167a5cb56990f) Thanks [@estrattonbailey](https://github.com/estrattonbailey)! - Bump stable minor
8
+
9
+ ### Patch Changes
10
+
11
+ - [`acd32e2`](https://github.com/bluesky-social/toolbox/commit/acd32e28ff75d119f794ed9857d2efc16ebc0f5a) Thanks [@estrattonbailey](https://github.com/estrattonbailey)! - Fix alignment on android
12
+
13
+ ## 0.2.11
14
+
15
+ ### Patch Changes
16
+
17
+ - [`612788d`](https://github.com/bluesky-social/toolbox/commit/612788d5c256fb647a096b0dfc63f37f6e612dff) Thanks [@estrattonbailey](https://github.com/estrattonbailey)! - Allow passing in an anchorRef to useSift
18
+
3
19
  ## 0.2.10
4
20
 
5
21
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"computeStyles.d.ts","sourceRoot":"","sources":["../src/computeStyles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,SAAS,EAAC,MAAM,cAAc,CAAA;AACvD,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;CACvC,GACA,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAwD3B"}
1
+ {"version":3,"file":"computeStyles.d.ts","sourceRoot":"","sources":["../src/computeStyles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,SAAS,EAAC,MAAM,cAAc,CAAA;AACjE,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;CACvC,GACA,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CA4D3B"}
@@ -1,4 +1,4 @@
1
- import { Dimensions } from 'react-native';
1
+ import { Dimensions, Platform } from 'react-native';
2
2
  function measureInWindow(node) {
3
3
  return new Promise(resolve => {
4
4
  try {
@@ -29,7 +29,10 @@ export async function computeStyles({ anchor, input, popover, }, options) {
29
29
  let bottom = 'auto';
30
30
  let maxHeight;
31
31
  if (side === 'top') {
32
- bottom = Dimensions.get('window').height - anchorRect.y + options.offset;
32
+ // android reports window size minus insets
33
+ const windowHeight = Dimensions.get('window').height +
34
+ (Platform.OS === 'android' ? insetBottom : 0);
35
+ bottom = windowHeight - anchorRect.y + options.offset;
33
36
  maxHeight = anchorRect.y - options.offset - insetTop;
34
37
  }
35
38
  else {
@@ -1 +1 @@
1
- {"version":3,"file":"computeStyles.js","sourceRoot":"","sources":["../src/computeStyles.ts"],"names":[],"mappings":"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","sourcesContent":["import {Dimensions, 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 },\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\n let top: number | 'auto' = 'auto'\n let bottom: number | 'auto' = 'auto'\n let maxHeight: number | undefined\n if (side === 'top') {\n bottom = Dimensions.get('window').height - anchorRect.y + options.offset\n maxHeight = anchorRect.y - options.offset - insetTop\n } else {\n top = anchorRect.y + anchorRect.height + options.offset\n maxHeight =\n Dimensions.get('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
+ {"version":3,"file":"computeStyles.js","sourceRoot":"","sources":["../src/computeStyles.ts"],"names":[],"mappings":"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","sourcesContent":["import {Dimensions, 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 },\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\n let top: number | 'auto' = 'auto'\n let bottom: number | 'auto' = 'auto'\n let maxHeight: number | undefined\n if (side === 'top') {\n // android reports window size minus insets\n const windowHeight =\n Dimensions.get('window').height +\n (Platform.OS === 'android' ? insetBottom : 0)\n bottom = windowHeight - anchorRect.y + options.offset\n maxHeight = anchorRect.y - options.offset - insetTop\n } else {\n top = anchorRect.y + anchorRect.height + options.offset\n maxHeight =\n Dimensions.get('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,7 +1,7 @@
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, insets, }?: {
4
+ export declare function useSift({ offset: offsetValue, placement, dynamicWidth, insets, anchorRef: externalAnchorRef, }?: {
5
5
  offset?: number;
6
6
  placement?: Placement;
7
7
  dynamicWidth?: boolean;
@@ -9,6 +9,7 @@ export declare function useSift({ offset: offsetValue, placement, dynamicWidth,
9
9
  top: number;
10
10
  bottom: number;
11
11
  };
12
+ anchorRef?: React.RefObject<any>;
12
13
  }): {
13
14
  id: string;
14
15
  refs: {
@@ -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;AAK3C,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,EACpB,MAAM,GACP,GAAE;IACD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,MAAM,CAAC,EAAE;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAC,CAAA;CAClC;;;2BAmDK,GAAG;0BAaH,GAAG;;;;;;;;;;oBAnB8B,GAAG;;;;;;EAiD9C"}
1
+ {"version":3,"file":"useSift.d.ts","sourceRoot":"","sources":["../src/useSift.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,KAAK,SAAS,EAAC,MAAM,cAAc,CAAA;AAK3C,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,EACpB,MAAM,EACN,SAAS,EAAE,iBAAiB,GAC7B,GAAE;IACD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,MAAM,CAAC,EAAE;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAC,CAAA;IACtC,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,CAAA;CAC5B;;;2BAmDK,GAAG;0BAaH,GAAG;;;;;;;;;;oBAnB8B,GAAG;;;;;;EAiD9C"}
package/build/useSift.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { useCallback, useId, useRef, useState } from 'react';
2
2
  import { computeStyles } from './computeStyles';
3
3
  const DEFAULT_POPOVER_STYLES = { position: 'absolute' };
4
- export function useSift({ offset: offsetValue = 0, placement = 'bottom', dynamicWidth = false, insets, } = {}) {
4
+ export function useSift({ offset: offsetValue = 0, placement = 'bottom', dynamicWidth = false, insets, anchorRef: externalAnchorRef, } = {}) {
5
5
  const id = useId();
6
6
  /*
7
7
  * These are reactive values and need to remain in state
@@ -15,7 +15,7 @@ export function useSift({ offset: offsetValue = 0, placement = 'bottom', dynamic
15
15
  */
16
16
  const inputRef = useRef(null);
17
17
  const popoverRef = useRef(null);
18
- const anchorRef = useRef(null);
18
+ const anchorRef = useRef(externalAnchorRef?.current || null);
19
19
  const options = useRef({
20
20
  offset: offsetValue,
21
21
  placement,
@@ -1 +1 @@
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 {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 insets,\n}: {\n offset?: number\n placement?: Placement\n dynamicWidth?: boolean\n insets?: {top: number; bottom: number}\n} = {}) {\n const id = useId()\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 })\n options.current = {\n offset: offsetValue,\n placement,\n dynamicWidth,\n insets,\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"]}
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 {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 insets,\n anchorRef: externalAnchorRef,\n}: {\n offset?: number\n placement?: Placement\n dynamicWidth?: boolean\n insets?: {top: number; bottom: number}\n anchorRef?: React.RefObject<any>\n} = {}) {\n const id = useId()\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>(externalAnchorRef?.current || null)\n const options = useRef({\n offset: offsetValue,\n placement,\n dynamicWidth,\n insets,\n })\n options.current = {\n offset: offsetValue,\n placement,\n dynamicWidth,\n insets,\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.2.10",
3
+ "version": "0.3.0",
4
4
  "license": "MIT",
5
5
  "description": "A little React Native library for building autocompletes.",
6
6
  "repository": "https://github.com/bluesky-social/toolbox",
@@ -1,4 +1,4 @@
1
- import {Dimensions, type ViewStyle} from 'react-native'
1
+ import {Dimensions, Platform, type ViewStyle} from 'react-native'
2
2
  import {type Placement} from './useSift'
3
3
 
4
4
  function measureInWindow(
@@ -56,7 +56,11 @@ export async function computeStyles(
56
56
  let bottom: number | 'auto' = 'auto'
57
57
  let maxHeight: number | undefined
58
58
  if (side === 'top') {
59
- bottom = Dimensions.get('window').height - anchorRect.y + options.offset
59
+ // android reports window size minus insets
60
+ const windowHeight =
61
+ Dimensions.get('window').height +
62
+ (Platform.OS === 'android' ? insetBottom : 0)
63
+ bottom = windowHeight - anchorRect.y + options.offset
60
64
  maxHeight = anchorRect.y - options.offset - insetTop
61
65
  } else {
62
66
  top = anchorRect.y + anchorRect.height + options.offset
package/src/useSift.ts CHANGED
@@ -19,11 +19,13 @@ export function useSift({
19
19
  placement = 'bottom',
20
20
  dynamicWidth = false,
21
21
  insets,
22
+ anchorRef: externalAnchorRef,
22
23
  }: {
23
24
  offset?: number
24
25
  placement?: Placement
25
26
  dynamicWidth?: boolean
26
27
  insets?: {top: number; bottom: number}
28
+ anchorRef?: React.RefObject<any>
27
29
  } = {}) {
28
30
  const id = useId()
29
31
 
@@ -42,7 +44,7 @@ export function useSift({
42
44
  */
43
45
  const inputRef = useRef<any>(null)
44
46
  const popoverRef = useRef<any>(null)
45
- const anchorRef = useRef<any>(null)
47
+ const anchorRef = useRef<any>(externalAnchorRef?.current || null)
46
48
  const options = useRef({
47
49
  offset: offsetValue,
48
50
  placement,