view-anchor 0.2.2 → 1.0.0-beta.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.
Files changed (46) hide show
  1. package/README.md +71 -87
  2. package/README.zh-CN.md +59 -64
  3. package/dist/index.d.ts +5 -7
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +2 -3
  6. package/dist/protocol-publisher.d.ts +7 -9
  7. package/dist/protocol-publisher.d.ts.map +1 -1
  8. package/dist/protocol-publisher.js +2 -8
  9. package/dist/protocol-types.d.ts +5 -8
  10. package/dist/protocol-types.d.ts.map +1 -1
  11. package/dist/protocol-types.js +3 -6
  12. package/dist/protocol.d.ts +2 -2
  13. package/dist/protocol.d.ts.map +1 -1
  14. package/dist/protocol.js +10 -2
  15. package/dist/react.d.ts +2 -15
  16. package/dist/react.d.ts.map +1 -1
  17. package/dist/react.js +43 -38
  18. package/dist/{size-advertiser.d.ts → size-anchor.d.ts} +6 -5
  19. package/dist/size-anchor.d.ts.map +1 -0
  20. package/dist/size-anchor.js +131 -0
  21. package/dist/types.d.ts +26 -32
  22. package/dist/types.d.ts.map +1 -1
  23. package/dist/view-anchor.d.ts +52 -33
  24. package/dist/view-anchor.d.ts.map +1 -1
  25. package/dist/view-anchor.js +186 -265
  26. package/docs/bidirectional-design.md +29 -34
  27. package/docs/index.html +656 -366
  28. package/docs/mechanism.md +35 -57
  29. package/docs/performance-report.md +12 -54
  30. package/docs/protocol.md +12 -3
  31. package/package.json +4 -6
  32. package/src/index.ts +5 -19
  33. package/src/protocol-publisher.ts +10 -16
  34. package/src/protocol-types.ts +5 -8
  35. package/src/protocol.ts +13 -7
  36. package/src/react.ts +51 -64
  37. package/src/size-anchor.ts +131 -0
  38. package/src/types.ts +29 -37
  39. package/src/view-anchor.ts +221 -287
  40. package/dist/measure-loop.d.ts +0 -24
  41. package/dist/measure-loop.d.ts.map +0 -1
  42. package/dist/measure-loop.js +0 -89
  43. package/dist/size-advertiser.d.ts.map +0 -1
  44. package/dist/size-advertiser.js +0 -94
  45. package/src/measure-loop.ts +0 -101
  46. package/src/size-advertiser.ts +0 -108
@@ -1,11 +1,8 @@
1
- import type { AdvertisedSize, Placement } from './types.js';
1
+ import type { SizeMeasurement, Placement } from './types.js';
2
2
  /**
3
- * Leaf module for the wire-format shapes shared by `protocol.ts` (decode/guard)
4
- * and `protocol-publisher.ts` (encode/batch). Keeping them here — rather than
5
- * in either of those two — avoids a value import cycle: `protocol.ts`
6
- * re-exports `protocol-publisher.ts`'s functions, and those functions need
7
- * `GEOMETRY_PROTOCOL_VERSION`, so neither of those two files can be the
8
- * source of it without the other importing back from it.
3
+ * Wire-format shapes shared by `protocol.ts` (decode/guard) and
4
+ * `protocol-publisher.ts` (encode/batch). Kept here to break a value
5
+ * import cycle between those two files.
9
6
  */
10
7
  /** Current wire format version for geometry messages. */
11
8
  export declare const GEOMETRY_PROTOCOL_VERSION: 1;
@@ -24,7 +21,7 @@ export interface SizeMessage extends GeometryAddress {
24
21
  v: typeof GEOMETRY_PROTOCOL_VERSION;
25
22
  kind: 'size';
26
23
  seq: number;
27
- size: AdvertisedSize;
24
+ size: SizeMeasurement;
28
25
  }
29
26
  export type GeometryMessage = PlacementMessage | SizeMessage;
30
27
  export interface GeometryBatch {
@@ -1 +1 @@
1
- {"version":3,"file":"protocol-types.d.ts","sourceRoot":"","sources":["../src/protocol-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAE3D;;;;;;;GAOG;AAEH,yDAAyD;AACzD,eAAO,MAAM,yBAAyB,EAAG,CAAU,CAAA;AAEnD,yEAAyE;AACzE,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,gBAAiB,SAAQ,eAAe;IACvD,CAAC,EAAE,OAAO,yBAAyB,CAAA;IACnC,IAAI,EAAE,WAAW,CAAA;IACjB,GAAG,EAAE,MAAM,CAAA;IACX,SAAS,EAAE,SAAS,CAAA;CACrB;AAED,MAAM,WAAW,WAAY,SAAQ,eAAe;IAClD,CAAC,EAAE,OAAO,yBAAyB,CAAA;IACnC,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,cAAc,CAAA;CACrB;AAED,MAAM,MAAM,eAAe,GAAG,gBAAgB,GAAG,WAAW,CAAA;AAE5D,MAAM,WAAW,aAAa;IAC5B,CAAC,EAAE,OAAO,yBAAyB,CAAA;IACnC,IAAI,EAAE,OAAO,CAAA;IACb,QAAQ,EAAE,SAAS,eAAe,EAAE,CAAA;CACrC;AAED,MAAM,MAAM,iBAAiB,GAAG,eAAe,GAAG,aAAa,CAAA"}
1
+ {"version":3,"file":"protocol-types.d.ts","sourceRoot":"","sources":["../src/protocol-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAE5D;;;;GAIG;AAEH,yDAAyD;AACzD,eAAO,MAAM,yBAAyB,EAAG,CAAU,CAAA;AAEnD,yEAAyE;AACzE,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,gBAAiB,SAAQ,eAAe;IACvD,CAAC,EAAE,OAAO,yBAAyB,CAAA;IACnC,IAAI,EAAE,WAAW,CAAA;IACjB,GAAG,EAAE,MAAM,CAAA;IACX,SAAS,EAAE,SAAS,CAAA;CACrB;AAED,MAAM,WAAW,WAAY,SAAQ,eAAe;IAClD,CAAC,EAAE,OAAO,yBAAyB,CAAA;IACnC,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,eAAe,CAAA;CACtB;AAED,MAAM,MAAM,eAAe,GAAG,gBAAgB,GAAG,WAAW,CAAA;AAE5D,MAAM,WAAW,aAAa;IAC5B,CAAC,EAAE,OAAO,yBAAyB,CAAA;IACnC,IAAI,EAAE,OAAO,CAAA;IACb,QAAQ,EAAE,SAAS,eAAe,EAAE,CAAA;CACrC;AAED,MAAM,MAAM,iBAAiB,GAAG,eAAe,GAAG,aAAa,CAAA"}
@@ -1,10 +1,7 @@
1
1
  /**
2
- * Leaf module for the wire-format shapes shared by `protocol.ts` (decode/guard)
3
- * and `protocol-publisher.ts` (encode/batch). Keeping them here — rather than
4
- * in either of those two — avoids a value import cycle: `protocol.ts`
5
- * re-exports `protocol-publisher.ts`'s functions, and those functions need
6
- * `GEOMETRY_PROTOCOL_VERSION`, so neither of those two files can be the
7
- * source of it without the other importing back from it.
2
+ * Wire-format shapes shared by `protocol.ts` (decode/guard) and
3
+ * `protocol-publisher.ts` (encode/batch). Kept here to break a value
4
+ * import cycle between those two files.
8
5
  */
9
6
  /** Current wire format version for geometry messages. */
10
7
  export const GEOMETRY_PROTOCOL_VERSION = 1;
@@ -14,7 +14,7 @@ export interface GeometryDecodeOptions {
14
14
  }
15
15
  /**
16
16
  * Decodes untrusted transport data without throwing. `maxMessages` is required
17
- * so each receiver, rather than this library, chooses its own batch limit.
17
+ * so each receiver chooses its own batch limit.
18
18
  */
19
19
  export declare function decodeGeometryWireValue(value: unknown, options: GeometryDecodeOptions): GeometryDecodeResult;
20
20
  export interface GeometrySequenceGuard {
@@ -31,5 +31,5 @@ export interface GeometrySequenceGuard {
31
31
  */
32
32
  export declare function createGeometrySequenceGuard(): GeometrySequenceGuard;
33
33
  export { createGeometryBatcher, createPlacementMessagePublisher, createSizeMessagePublisher, } from './protocol-publisher.js';
34
- export type { GeometryBatcher, GeometryBatcherOptions, GeometryBatchSend, GeometrySend, } from './protocol-publisher.js';
34
+ export type { GeometryBatcher, GeometryBatcherOptions, GeometryBatchSender, GeometryMessageSender, } from './protocol-publisher.js';
35
35
  //# sourceMappingURL=protocol.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AACA,OAAO,EACL,yBAAyB,EACzB,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,WAAW,EACjB,MAAM,qBAAqB,CAAA;AAE5B,OAAO,EAAE,yBAAyB,EAAE,CAAA;AACpC,YAAY,EACV,eAAe,EACf,aAAa,EACb,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,WAAW,GACZ,CAAA;AAED,MAAM,MAAM,oBAAoB,GAC5B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,iBAAiB,CAAA;CAAE,GACtC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAEhC,MAAM,WAAW,qBAAqB;IACpC,iEAAiE;IACjE,WAAW,EAAE,MAAM,CAAA;CACpB;AA6DD;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,qBAAqB,GAC7B,oBAAoB,CA0BtB;AAED,MAAM,WAAW,qBAAqB;IACpC,+EAA+E;IAC/E,MAAM,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAA;IACzC,kEAAkE;IAClE,KAAK,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC/B;AAKD;;;;;GAKG;AACH,wBAAgB,2BAA2B,IAAI,qBAAqB,CA4BnE;AAED,OAAO,EACL,qBAAqB,EACrB,+BAA+B,EAC/B,0BAA0B,GAC3B,MAAM,yBAAyB,CAAA;AAChC,YAAY,EACV,eAAe,EACf,sBAAsB,EACtB,iBAAiB,EACjB,YAAY,GACb,MAAM,yBAAyB,CAAA"}
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AACA,OAAO,EACL,yBAAyB,EACzB,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,WAAW,EACjB,MAAM,qBAAqB,CAAA;AAE5B,OAAO,EAAE,yBAAyB,EAAE,CAAA;AACpC,YAAY,EACV,eAAe,EACf,aAAa,EACb,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,WAAW,GACZ,CAAA;AAED,MAAM,MAAM,oBAAoB,GAC5B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,iBAAiB,CAAA;CAAE,GACtC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAEhC,MAAM,WAAW,qBAAqB;IACpC,iEAAiE;IACjE,WAAW,EAAE,MAAM,CAAA;CACpB;AAmED;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,qBAAqB,GAC7B,oBAAoB,CA0BtB;AAED,MAAM,WAAW,qBAAqB;IACpC,+EAA+E;IAC/E,MAAM,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAA;IACzC,kEAAkE;IAClE,KAAK,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC/B;AAKD;;;;;GAKG;AACH,wBAAgB,2BAA2B,IAAI,qBAAqB,CA4BnE;AAED,OAAO,EACL,qBAAqB,EACrB,+BAA+B,EAC/B,0BAA0B,GAC3B,MAAM,yBAAyB,CAAA;AAChC,YAAY,EACV,eAAe,EACf,sBAAsB,EACtB,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,yBAAyB,CAAA"}
package/dist/protocol.js CHANGED
@@ -1,6 +1,14 @@
1
1
  import { GEOMETRY_PROTOCOL_VERSION, } from './protocol-types.js';
2
2
  export { GEOMETRY_PROTOCOL_VERSION };
3
- const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
3
+ // Only plain objects count, as produced by JSON.parse or structured clone. A
4
+ // custom prototype cannot supply missing fields; checking the prototype once
5
+ // per object is much cheaper than an own-property check per field.
6
+ const isRecord = (value) => {
7
+ if (typeof value !== 'object' || value === null)
8
+ return false;
9
+ const proto = Object.getPrototypeOf(value);
10
+ return proto === Object.prototype || proto === null;
11
+ };
4
12
  const isSafeInteger = (value) => typeof value === 'number' && Number.isSafeInteger(value);
5
13
  const isNonNegativeSafeInteger = (value) => isSafeInteger(value) && value >= 0;
6
14
  function error(message) {
@@ -57,7 +65,7 @@ function decodeMessage(value) {
57
65
  }
58
66
  /**
59
67
  * Decodes untrusted transport data without throwing. `maxMessages` is required
60
- * so each receiver, rather than this library, chooses its own batch limit.
68
+ * so each receiver chooses its own batch limit.
61
69
  */
62
70
  export function decodeGeometryWireValue(value, options) {
63
71
  try {
package/dist/react.d.ts CHANGED
@@ -1,5 +1,4 @@
1
- import { type PlacementAnchorOptions } from './view-anchor.js';
2
- import type { Bounds, ViewAnchorOptions } from './types.js';
1
+ import type { ViewAnchorOptions } from './view-anchor.js';
3
2
  export interface UseViewAnchorOptions extends ViewAnchorOptions {
4
3
  /**
5
4
  * Values that re-apply the anchor when changed. Keep this array's length
@@ -9,18 +8,6 @@ export interface UseViewAnchorOptions extends ViewAnchorOptions {
9
8
  }
10
9
  /** Compatible with React 18's null callback and React 19's ref cleanup. */
11
10
  export type ViewAnchorRef = (el: HTMLElement | null) => void | (() => void);
12
- export interface UsePlacementAnchorOptions extends PlacementAnchorOptions {
13
- /**
14
- * Values that re-apply the anchor when changed. Keep this array's length
15
- * stable across renders.
16
- */
17
- deps?: ReadonlyArray<unknown>;
18
- }
19
- /** Callback ref for the explicit-visibility Placement API. */
20
- export type PlacementAnchorRef = ViewAnchorRef;
21
- /** Bind zero-bounds visibility to a DOM element callback ref. */
22
- export declare function useViewAnchor(options: UseViewAnchorOptions): ViewAnchorRef;
23
11
  /** Bind the explicit Placement API to a DOM element callback ref. */
24
- export declare function usePlacementAnchor(options: UsePlacementAnchorOptions): PlacementAnchorRef;
25
- export type { Bounds };
12
+ export declare function useViewAnchor(options: UseViewAnchorOptions): ViewAnchorRef;
26
13
  //# sourceMappingURL=react.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,sBAAsB,EAC5B,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,EAAE,MAAM,EAAoB,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAE7E,MAAM,WAAW,oBAAqB,SAAQ,iBAAiB;IAC7D;;;OAGG;IACH,IAAI,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,CAAA;CAC9B;AAED,2EAA2E;AAC3E,MAAM,MAAM,aAAa,GAAG,CAAC,EAAE,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,CAAA;AAE3E,MAAM,WAAW,yBAA0B,SAAQ,sBAAsB;IACvE;;;OAGG;IACH,IAAI,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,CAAA;CAC9B;AAED,8DAA8D;AAC9D,MAAM,MAAM,kBAAkB,GAAG,aAAa,CAAA;AA+H9C,iEAAiE;AACjE,wBAAgB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,aAAa,CAM1E;AAsBD,qEAAqE;AACrE,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,yBAAyB,GAAG,kBAAkB,CAazF;AAED,YAAY,EAAE,MAAM,EAAE,CAAA"}
1
+ {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AAEzD,MAAM,WAAW,oBAAqB,SAAQ,iBAAiB;IAC7D;;;OAGG;IACH,IAAI,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,CAAA;CAC9B;AAED,2EAA2E;AAC3E,MAAM,MAAM,aAAa,GAAG,CAAC,EAAE,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,CAAA;AA+J3E,qEAAqE;AACrE,wBAAgB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,aAAa,CAe1E"}
package/dist/react.js CHANGED
@@ -1,5 +1,5 @@
1
- import { useCallback, useEffect, useRef } from 'react';
2
- import { createPlacementAnchor, createViewAnchor, } from './view-anchor.js';
1
+ import { useCallback, useEffect, useInsertionEffect, useRef, version } from 'react';
2
+ import { createViewAnchor } from './view-anchor.js';
3
3
  // Callback refs own the imperative anchor because React invokes them during commit.
4
4
  // React 19 may call the cleanup returned from a ref and immediately reattach the
5
5
  // same element in development mode. Collapse is deferred by one microtask so that
@@ -8,12 +8,16 @@ function useAnchorRef(options, applied, adapter) {
8
8
  const handleRef = useRef(null);
9
9
  const elementRef = useRef(null);
10
10
  const optionsRef = useRef(options);
11
- optionsRef.current = options;
12
11
  const adapterRef = useRef(adapter);
13
- adapterRef.current = adapter;
14
12
  const appliedRef = useRef(applied);
15
13
  const currentAppliedRef = useRef(applied);
16
- currentAppliedRef.current = applied;
14
+ // Renders discarded before commit (e.g. suspended transitions) must not
15
+ // update optionsRef. Insertion effects run before callback refs in the same commit.
16
+ useInsertionEffect(() => {
17
+ optionsRef.current = options;
18
+ adapterRef.current = adapter;
19
+ currentAppliedRef.current = applied;
20
+ });
17
21
  // Options handed to the adapter on the last create/update call.
18
22
  // Tracks applied state across renders where the deps array reference changes.
19
23
  const lastAppliedOptionsRef = useRef(options);
@@ -26,7 +30,7 @@ function useAnchorRef(options, applied, adapter) {
26
30
  if (!handle)
27
31
  return;
28
32
  const adapter = adapterRef.current;
29
- const alreadyCollapsed = adapter.isCollapsed(lastAppliedOptionsRef.current);
33
+ const alreadyCollapsed = adapter.isCollapsed(handle, lastAppliedOptionsRef.current);
30
34
  try {
31
35
  if (!alreadyCollapsed)
32
36
  adapter.collapse(handle, optionsRef.current);
@@ -45,10 +49,13 @@ function useAnchorRef(options, applied, adapter) {
45
49
  collapseAndDispose();
46
50
  });
47
51
  };
52
+ // React 19 invokes the cleanup returned from a callback ref instead of calling
53
+ // ref(null). React 18 warns about the returned function and still calls ref(null).
54
+ const detachCleanup = (element) => Number.parseInt(version, 10) >= 19 ? () => deferDetach(element) : undefined;
48
55
  const ref = useCallback((element) => {
49
56
  if (element === elementRef.current) {
50
57
  cancelPendingDetach();
51
- return element ? () => deferDetach(element) : undefined;
58
+ return element ? detachCleanup(element) : undefined;
52
59
  }
53
60
  cancelPendingDetach();
54
61
  const previous = elementRef.current;
@@ -67,7 +74,7 @@ function useAnchorRef(options, applied, adapter) {
67
74
  handleRef.current = adapterRef.current.create(element, optionsRef.current);
68
75
  appliedRef.current = currentAppliedRef.current;
69
76
  lastAppliedOptionsRef.current = optionsRef.current;
70
- return () => deferDetach(element);
77
+ return detachCleanup(element);
71
78
  }
72
79
  return undefined;
73
80
  }, []);
@@ -95,49 +102,47 @@ function useAnchorRef(options, applied, adapter) {
95
102
  }, []);
96
103
  return ref;
97
104
  }
98
- const viewAdapter = {
99
- create: createViewAnchor,
100
- update(handle, options) {
101
- handle.update(options);
105
+ const hideStates = new WeakMap();
106
+ const trackHide = (options, state) => ({
107
+ ...options,
108
+ publish(placement) {
109
+ if (placement.visible)
110
+ return options.publish(placement);
111
+ state.accepted = false;
112
+ const result = options.publish(placement);
113
+ state.accepted = result !== false;
114
+ return result;
102
115
  },
103
- collapse(handle, options) {
104
- handle.update({ present: false, publish: options.publish });
105
- },
106
- isCollapsed(options) {
107
- return !options.present;
116
+ });
117
+ const viewAdapter = {
118
+ create(target, options) {
119
+ const state = { accepted: false };
120
+ const handle = createViewAnchor(target, trackHide(options, state));
121
+ hideStates.set(handle, state);
122
+ return handle;
108
123
  },
109
- };
110
- /** Bind zero-bounds visibility to a DOM element callback ref. */
111
- export function useViewAnchor(options) {
112
- return useAnchorRef(options, [options.present, options.publish, ...(options.deps ?? [])], viewAdapter);
113
- }
114
- const placementAdapter = {
115
- create: createPlacementAnchor,
116
124
  update(handle, options) {
117
- // In React, an omitted option represents "off" for that render,
118
- // rather than keeping the previous value.
119
- handle.update({
120
- ...options,
121
- guardDisplayNone: options.guardDisplayNone ?? false,
122
- followScroll: options.followScroll ?? false,
123
- followGeometry: options.followGeometry ?? false,
124
- });
125
+ // Options are forwarded as-is; the hook applies the same "omitted resets
126
+ // to default" rule as the core's update().
127
+ handle.update(trackHide(options, hideStates.get(handle)));
125
128
  },
126
129
  collapse(handle, options) {
127
- handle.update({ ...options, visible: false });
130
+ handle.update(trackHide({ ...options, visible: false }, hideStates.get(handle)));
128
131
  },
129
- isCollapsed(options) {
130
- return !options.visible;
132
+ isCollapsed(handle, options) {
133
+ return !options.visible && hideStates.get(handle).accepted;
131
134
  },
132
135
  };
133
136
  /** Bind the explicit Placement API to a DOM element callback ref. */
134
- export function usePlacementAnchor(options) {
137
+ export function useViewAnchor(options) {
135
138
  return useAnchorRef(options, [
136
139
  options.visible,
137
140
  options.publish,
138
- options.guardDisplayNone,
141
+ options.treatZeroAreaAsHidden,
139
142
  options.followScroll,
140
143
  options.followGeometry,
144
+ options.holdSelector,
145
+ options.dedupe,
141
146
  ...(options.deps ?? []),
142
- ], placementAdapter);
147
+ ], viewAdapter);
143
148
  }
@@ -1,16 +1,17 @@
1
- import type { SizeAdvertiserOptions, SizeAdvertiserHandle } from './types.js';
1
+ import type { SizeAnchorOptions, SizeAnchorHandle } from './types.js';
2
2
  /**
3
3
  * Report content size for a single axis back to the host.
4
4
  *
5
5
  * Runs in a downstream document, reads the content size from
6
6
  * `ResizeObserverEntry.borderBoxSize` without triggering reflow, and
7
- * publishes updates through an animation frame loop (`createMeasureLoop`).
7
+ * publishes at most once per animation frame, skipping unchanged extents by
8
+ * default (see the `dedupe` option).
8
9
  *
9
10
  * Measurements are rounded to integer pixels and clamped to >= 0.
10
11
  *
11
- * Note: `target` should be a shrink-to-fit wrapper on the owned axis.
12
+ * `target` must be a shrink-to-fit wrapper on the owned axis.
12
13
  * If its size is driven by the host view itself (such as `<body>` or `<html>`),
13
14
  * updates will not shrink back to content size.
14
15
  */
15
- export declare function createSizeAdvertiser(target: HTMLElement, opts: SizeAdvertiserOptions): SizeAdvertiserHandle;
16
- //# sourceMappingURL=size-advertiser.d.ts.map
16
+ export declare function createSizeAnchor(target: HTMLElement, opts: SizeAnchorOptions): SizeAnchorHandle;
17
+ //# sourceMappingURL=size-anchor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"size-anchor.d.ts","sourceRoot":"","sources":["../src/size-anchor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAOrE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,iBAAiB,GAAG,gBAAgB,CA6G/F"}
@@ -0,0 +1,131 @@
1
+ import { watchAbort } from './abort.js';
2
+ // Replaces a disposed instance's publish callback so a retained handle does
3
+ // not keep the caller's original callback (and whatever it captured) alive.
4
+ const NOOP_PUBLISH = () => false;
5
+ /**
6
+ * Report content size for a single axis back to the host.
7
+ *
8
+ * Runs in a downstream document, reads the content size from
9
+ * `ResizeObserverEntry.borderBoxSize` without triggering reflow, and
10
+ * publishes at most once per animation frame, skipping unchanged extents by
11
+ * default (see the `dedupe` option).
12
+ *
13
+ * Measurements are rounded to integer pixels and clamped to >= 0.
14
+ *
15
+ * `target` must be a shrink-to-fit wrapper on the owned axis.
16
+ * If its size is driven by the host view itself (such as `<body>` or `<html>`),
17
+ * updates will not shrink back to content size.
18
+ */
19
+ export function createSizeAnchor(target, opts) {
20
+ const axis = opts.axis;
21
+ let dedupe = opts.dedupe ?? true;
22
+ let publish = opts.publish;
23
+ let observer = null;
24
+ let rafId = null;
25
+ let disposed = false;
26
+ // Latest border-box recorded by the ResizeObserver callback.
27
+ let latestBoxSize = null;
28
+ // Last extent passed to publish; null until one is accepted.
29
+ let lastPublished = null;
30
+ let publicationRevision = 0;
31
+ const measure = () => {
32
+ if (!latestBoxSize)
33
+ return null;
34
+ const raw = axis === 'block' ? latestBoxSize.blockSize : latestBoxSize.inlineSize;
35
+ if (!Number.isFinite(raw))
36
+ return null;
37
+ return Math.max(0, Math.round(raw));
38
+ };
39
+ const publishExtent = (extent) => {
40
+ const previous = lastPublished;
41
+ const attempt = ++publicationRevision;
42
+ lastPublished = extent;
43
+ try {
44
+ const accepted = publish({ axis, extent }) !== false;
45
+ // A reentrant update() or dispose() during publish() already moved the
46
+ // baseline; do not roll back over that newer state.
47
+ if (!accepted && publicationRevision === attempt && !disposed)
48
+ lastPublished = previous;
49
+ }
50
+ catch (error) {
51
+ if (publicationRevision === attempt && !disposed)
52
+ lastPublished = previous;
53
+ throw error;
54
+ }
55
+ };
56
+ const publishFrame = () => {
57
+ rafId = null;
58
+ if (disposed)
59
+ return;
60
+ const extent = measure();
61
+ if (extent === null)
62
+ return;
63
+ if (dedupe && extent === lastPublished)
64
+ return;
65
+ publishExtent(extent);
66
+ };
67
+ const onResize = (entries) => {
68
+ // A callback queued before disconnect() can still fire once more; do not
69
+ // let it write `latestBoxSize` after dispose() has already cleared it.
70
+ if (disposed)
71
+ return;
72
+ const entry = entries[entries.length - 1];
73
+ if (entry) {
74
+ latestBoxSize = entry.borderBoxSize?.[0] ?? entry.contentBoxSize?.[0] ?? latestBoxSize;
75
+ }
76
+ if (rafId === null)
77
+ rafId = requestAnimationFrame(publishFrame);
78
+ };
79
+ // Warn if measuring body or documentElement, whose size matches the view.
80
+ const doc = target.ownerDocument;
81
+ if (target === doc.body || target === doc.documentElement) {
82
+ console.warn(`[view-anchor] size-anchor: <${target === doc.body ? 'body' : 'html'}>'s ` +
83
+ `${axis} size is the view size, not content size. The size anchor will ` +
84
+ `never shrink to content; measure a shrink-to-fit wrapper instead.`);
85
+ }
86
+ let removeAbortListener = () => { };
87
+ const dispose = () => {
88
+ if (disposed)
89
+ return;
90
+ disposed = true;
91
+ removeAbortListener();
92
+ removeAbortListener = () => { };
93
+ if (rafId !== null) {
94
+ cancelAnimationFrame(rafId);
95
+ rafId = null;
96
+ }
97
+ if (observer) {
98
+ observer.disconnect();
99
+ observer = null;
100
+ }
101
+ publish = NOOP_PUBLISH;
102
+ latestBoxSize = null;
103
+ lastPublished = null;
104
+ };
105
+ if (opts.signal?.aborted)
106
+ dispose();
107
+ else {
108
+ removeAbortListener = watchAbort(opts.signal, dispose);
109
+ observer = new ResizeObserver(onResize);
110
+ observer.observe(target);
111
+ }
112
+ return {
113
+ update(next) {
114
+ if (disposed)
115
+ return;
116
+ publish = next.publish;
117
+ dedupe = next.dedupe ?? true;
118
+ // The new callback has not accepted anything yet, so an extent the old
119
+ // callback rejected (or never saw) must not stay latched as the dedupe
120
+ // baseline — otherwise a later identical tick would be silently
121
+ // deduped against a value this callback was never actually given.
122
+ lastPublished = null;
123
+ // Re-publish the current size to the new sink immediately so it is not
124
+ // empty until the next ResizeObserver tick.
125
+ const extent = measure();
126
+ if (extent !== null)
127
+ publishExtent(extent);
128
+ },
129
+ dispose,
130
+ };
131
+ }
package/dist/types.d.ts CHANGED
@@ -27,44 +27,38 @@ export type Placement = {
27
27
  } | {
28
28
  visible: false;
29
29
  };
30
- export interface ViewAnchorOptions {
30
+ /** Which axis this size anchor reports: 'block' (height) or 'inline' (width). */
31
+ export type SizeAxis = 'block' | 'inline';
32
+ /** One measured size on the owned axis. */
33
+ export interface SizeMeasurement {
34
+ /** The axis this size anchor reports ('block' or 'inline'). */
35
+ readonly axis: SizeAxis;
31
36
  /**
32
- * Whether the native view should be attached. When false, publishes
33
- * zero bounds ({ x: 0, y: 0, width: 0, height: 0 }) so the host can detach
34
- * the view while keeping its instance alive.
37
+ * The target's border-box size on this axis in CSS pixels, rounded and
38
+ * non-negative. Falls back to the content box where no border box is reported.
35
39
  */
36
- present: boolean;
37
- /** Receives the live rect, or zero bounds when detached. */
38
- publish: Publisher<Bounds>;
39
- /** Stops this anchor when aborted. An already-aborted signal starts no work. */
40
- signal?: AbortSignal;
41
- }
42
- export interface ViewAnchorHandle {
43
- /** Apply new options and re-publish immediately. */
44
- update(opts: ViewAnchorOptions): void;
45
- /** Stop observing and clean up listeners. After disposal no further values are published. */
46
- dispose(): void;
47
- }
48
- /** Which axis this advertiser reports: 'block' (height) or 'inline' (width). */
49
- export type AdvertisedAxis = 'block' | 'inline';
50
- /** One frame of advertised size on the owned axis. */
51
- export interface AdvertisedSize {
52
- /** The axis this advertiser reports ('block' or 'inline'). */
53
- readonly axis: AdvertisedAxis;
54
- /** The content extent in CSS pixels, rounded and non-negative. */
55
40
  readonly extent: number;
56
41
  }
57
- export interface SizeAdvertiserOptions {
58
- /** The single axis this advertiser owns. Fixed for the advertiser's lifetime. */
59
- axis: AdvertisedAxis;
60
- /** Receives each advertised size. */
61
- publish: Publisher<AdvertisedSize>;
62
- /** Stops this advertiser when aborted. An already-aborted signal starts no work. */
42
+ export interface SizeAnchorOptions {
43
+ /** The single axis this size anchor owns. Fixed for its lifetime. */
44
+ axis: SizeAxis;
45
+ /** Receives each measured size. */
46
+ publish: Publisher<SizeMeasurement>;
47
+ /** Stops this size anchor when aborted. An already-aborted signal starts no work. */
63
48
  signal?: AbortSignal;
49
+ /**
50
+ * When true (the default), a measurement identical to the last published
51
+ * extent is not published again. When false, every measurement publishes,
52
+ * even an unchanged extent. Omitting it in update() resets to true.
53
+ */
54
+ dedupe?: boolean;
64
55
  }
65
- export interface SizeAdvertiserHandle {
66
- /** Swap the publish callback and re-advertise the current size immediately. */
67
- update(publish: Publisher<AdvertisedSize>): void;
56
+ export interface SizeAnchorHandle {
57
+ /**
58
+ * Apply a full set of options and re-publish the current size
59
+ * immediately. Like creation, an omitted dedupe resets to true.
60
+ */
61
+ update(opts: Omit<SizeAnchorOptions, 'signal' | 'axis'>): void;
68
62
  /** Stop observing and cancel any pending animation frame. */
69
63
  dispose(): void;
70
64
  }
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,8CAA8C;AAC9C,MAAM,WAAW,MAAM;IACrB,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf;AAED,iEAAiE;AACjE,MAAM,MAAM,aAAa,GAAG,IAAI,GAAG,OAAO,CAAA;AAE1C;;;GAGG;AACH,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,aAAa,CAAA;AAEtD;;;;;GAKG;AACH,MAAM,MAAM,SAAS,GAAG;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,KAAK,CAAA;CAAE,CAAA;AAE9E,MAAM,WAAW,iBAAiB;IAChC;;;;OAIG;IACH,OAAO,EAAE,OAAO,CAAA;IAChB,4DAA4D;IAC5D,OAAO,EAAE,SAAS,CAAC,MAAM,CAAC,CAAA;IAC1B,gFAAgF;IAChF,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,oDAAoD;IACpD,MAAM,CAAC,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAAA;IACrC,6FAA6F;IAC7F,OAAO,IAAI,IAAI,CAAA;CAChB;AAOD,gFAAgF;AAChF,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,QAAQ,CAAA;AAE/C,sDAAsD;AACtD,MAAM,WAAW,cAAc;IAC7B,8DAA8D;IAC9D,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAA;IAC7B,kEAAkE;IAClE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,WAAW,qBAAqB;IACpC,iFAAiF;IACjF,IAAI,EAAE,cAAc,CAAA;IACpB,qCAAqC;IACrC,OAAO,EAAE,SAAS,CAAC,cAAc,CAAC,CAAA;IAClC,oFAAoF;IACpF,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB;AAED,MAAM,WAAW,oBAAoB;IACnC,+EAA+E;IAC/E,MAAM,CAAC,OAAO,EAAE,SAAS,CAAC,cAAc,CAAC,GAAG,IAAI,CAAA;IAChD,6DAA6D;IAC7D,OAAO,IAAI,IAAI,CAAA;CAChB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,8CAA8C;AAC9C,MAAM,WAAW,MAAM;IACrB,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf;AAED,iEAAiE;AACjE,MAAM,MAAM,aAAa,GAAG,IAAI,GAAG,OAAO,CAAA;AAE1C;;;GAGG;AACH,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,aAAa,CAAA;AAEtD;;;;;GAKG;AACH,MAAM,MAAM,SAAS,GAAG;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,KAAK,CAAA;CAAE,CAAA;AAO9E,iFAAiF;AACjF,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAA;AAEzC,2CAA2C;AAC3C,MAAM,WAAW,eAAe;IAC9B,+DAA+D;IAC/D,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;IACvB;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,qEAAqE;IACrE,IAAI,EAAE,QAAQ,CAAA;IACd,mCAAmC;IACnC,OAAO,EAAE,SAAS,CAAC,eAAe,CAAC,CAAA;IACnC,qFAAqF;IACrF,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,iBAAiB,EAAE,QAAQ,GAAG,MAAM,CAAC,GAAG,IAAI,CAAA;IAC9D,6DAA6D;IAC7D,OAAO,IAAI,IAAI,CAAA;CAChB"}
@@ -1,62 +1,75 @@
1
- import type { Placement, Publisher, ViewAnchorOptions, ViewAnchorHandle } from './types.js';
2
- /**
3
- * Bind a native view or external surface to the geometry of `target`.
4
- *
5
- * - `present === true`: measures `target.getBoundingClientRect()` and publishes
6
- * immediately, then re-measures synchronously on ResizeObserver and window resize.
7
- * - `present === false`: publishes a zero rect ({ x: 0, y: 0, width: 0, height: 0 })
8
- * and stops observing.
9
- * - `update(opts)`: re-applies options immediately.
10
- * - `dispose()`: stops observing and prevents any further publishes.
11
- *
12
- * Synchronous publishing: measurement and publishing occur directly in the
13
- * observer tick. Applying geometry outside the DOM may already be delayed;
14
- * adding requestAnimationFrame would add another frame of visual lag during drag
15
- * operations. High-frequency updates are deduplicated against the last accepted rect.
16
- */
17
- export declare function createViewAnchor(target: HTMLElement, opts: ViewAnchorOptions): ViewAnchorHandle;
18
- export interface PlacementAnchorOptions {
1
+ import type { Placement, Publisher } from './types.js';
2
+ export declare const DEFAULT_HOLD_SELECTOR = "[role=\"separator\"]";
3
+ export interface ViewAnchorOptions {
19
4
  /**
20
5
  * Whether the native view should be visible. When true, publishes
21
- * { visible: true, bounds }; when false, publishes { visible: false }.
6
+ * { visible: true, bounds }; when false, publishes { visible: false } and
7
+ * stops observing, so a rejected hidden placement is only sent again by the
8
+ * next update().
22
9
  */
23
10
  visible: boolean;
24
11
  /** Receives each explicit Placement. */
25
12
  publish: Publisher<Placement>;
26
- /** Stops this anchor when aborted. An already-aborted signal starts no work. */
13
+ /**
14
+ * Stops this anchor when aborted. An already-aborted signal starts no work.
15
+ * Read once at creation only — update()'s type does not accept this field.
16
+ */
27
17
  signal?: AbortSignal;
28
18
  /**
29
19
  * When true, targets with zero area (such as display: none or unmounted elements)
30
20
  * publish { visible: false } instead of { visible: true, bounds: 0x0 }, and an
31
21
  * IntersectionObserver tracks display: none transitions. Default is false.
32
- * Sticky across update(): omitting it preserves the current setting.
22
+ * update() applies the same default: omitting it resets to false.
33
23
  */
34
- guardDisplayNone?: boolean;
24
+ treatZeroAreaAsHidden?: boolean;
35
25
  /**
36
26
  * When true, listens for capture-phase scroll events on window to re-measure
37
27
  * when an ancestor container scrolls. Default is false.
38
- * Sticky across update(): omitting it preserves the current setting.
28
+ * update() applies the same default: omitting it resets to false.
39
29
  */
40
30
  followScroll?: boolean;
41
31
  /**
42
32
  * When true, polls geometry per animation frame during active motion (scrolls,
43
- * splitter dragging, or pulse()) and auto-closes when steady. Zero idle overhead.
44
- * Sticky across update(): omitting it preserves the current setting.
33
+ * splitter dragging, or pulse()) and auto-closes when steady.
34
+ * update() applies the same default: omitting it resets to false.
45
35
  */
46
36
  followGeometry?: boolean;
37
+ /**
38
+ * CSS selector for the press-and-hold target that keeps followGeometry open
39
+ * for the duration of a pointer press. Only meaningful when followGeometry
40
+ * is true; the pointer listeners are mounted only while both are set. A capture-phase pointerdown whose
41
+ * target matches `closest(holdSelector)` opens frame following until release.
42
+ * Default is `[role="separator"]`. Pass null to disable. update() applies
43
+ * the same default when omitted. An invalid selector throws synchronously
44
+ * (SyntaxError) before any option is applied.
45
+ */
46
+ holdSelector?: string | null;
47
+ /**
48
+ * When true (the default), a measurement identical to the last accepted
49
+ * Placement is not published again. When false, every usable frame publishes
50
+ * even if the Placement is unchanged; the steady-frame close and the
51
+ * invalid/hidden frame caps still compare values either way. Hidden frames
52
+ * are never published by frame following regardless of this option. Omitting
53
+ * it in update() resets to true.
54
+ */
55
+ dedupe?: boolean;
47
56
  }
48
- export interface PlacementAnchorHandle {
57
+ export interface ViewAnchorHandle {
49
58
  /**
50
- * Apply new options and re-publish immediately.
51
- * guardDisplayNone, followScroll, and followGeometry are sticky: omitting a flag
52
- * preserves its current value. Pass an explicit false to disable one.
59
+ * Apply a full set of options and re-publish immediately. Omitted options
60
+ * reset to defaults: treatZeroAreaAsHidden/followScroll/followGeometry → false,
61
+ * holdSelector → `[role="separator"]` (pass null to disable), dedupe → true.
62
+ * `signal` is not accepted here — it cannot be changed after creation.
53
63
  */
54
- update(opts: PlacementAnchorOptions): void;
64
+ update(opts: Omit<ViewAnchorOptions, 'signal'>): void;
55
65
  /** Stop observing; never publish again. */
56
66
  dispose(): void;
57
67
  /**
58
- * Open the animation frame sentinel window. Auto-closes once stable
68
+ * Open a frame-following window. Auto-closes once stable
59
69
  * or after durationMs. No-op if followGeometry is false.
70
+ * durationMs is an upper bound, not a minimum: the window closes as soon as
71
+ * two frames measure the same rect, so a transition that starts slowly
72
+ * (sub-pixel movement in its first frames) may not be followed to the end.
60
73
  */
61
74
  pulse(durationMs?: number): void;
62
75
  }
@@ -66,7 +79,13 @@ export interface PlacementAnchorHandle {
66
79
  */
67
80
  export declare function measurePlacement(target: HTMLElement): Placement;
68
81
  /**
69
- * Explicit-visibility variant of createViewAnchor.
82
+ * Bind a native view or external surface to the geometry of `target`.
83
+ *
84
+ * When `visible === true`, publishes { visible: true, bounds } immediately,
85
+ * then re-measures synchronously on ResizeObserver and window resize.
86
+ * When `visible === false`, publishes { visible: false } and stops observing.
87
+ * Publishes are deduplicated against the last accepted Placement by default
88
+ * (see the `dedupe` option).
70
89
  */
71
- export declare function createPlacementAnchor(target: HTMLElement, opts: PlacementAnchorOptions): PlacementAnchorHandle;
90
+ export declare function createViewAnchor(target: HTMLElement, opts: ViewAnchorOptions): ViewAnchorHandle;
72
91
  //# sourceMappingURL=view-anchor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"view-anchor.d.ts","sourceRoot":"","sources":["../src/view-anchor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAU,SAAS,EAAE,SAAS,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAmBnG;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,iBAAiB,GAAG,gBAAgB,CAgH/F;AAID,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,OAAO,EAAE,OAAO,CAAA;IAChB,wCAAwC;IACxC,OAAO,EAAE,SAAS,CAAC,SAAS,CAAC,CAAA;IAC7B,gFAAgF;IAChF,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB;AAED,MAAM,WAAW,qBAAqB;IACpC;;;;OAIG;IACH,MAAM,CAAC,IAAI,EAAE,sBAAsB,GAAG,IAAI,CAAA;IAC1C,2CAA2C;IAC3C,OAAO,IAAI,IAAI,CAAA;IACf;;;OAGG;IACH,KAAK,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACjC;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,CAM/D;AAeD;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,WAAW,EACnB,IAAI,EAAE,sBAAsB,GAC3B,qBAAqB,CA6TvB"}
1
+ {"version":3,"file":"view-anchor.d.ts","sourceRoot":"","sources":["../src/view-anchor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAU,SAAS,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAQ9D,eAAO,MAAM,qBAAqB,yBAAuB,CAAA;AAWzD,MAAM,WAAW,iBAAiB;IAChC;;;;;OAKG;IACH,OAAO,EAAE,OAAO,CAAA;IAChB,wCAAwC;IACxC,OAAO,EAAE,SAAS,CAAC,SAAS,CAAC,CAAA;IAC7B;;;OAGG;IACH,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB;;;;;OAKG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B;;;;;OAKG;IACH,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,iBAAiB,EAAE,QAAQ,CAAC,GAAG,IAAI,CAAA;IACrD,2CAA2C;IAC3C,OAAO,IAAI,IAAI,CAAA;IACf;;;;;;OAMG;IACH,KAAK,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACjC;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,CAM/D;AAeD;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,iBAAiB,GAAG,gBAAgB,CA+V/F"}