@barefootjs/xyflow 0.27.0 → 0.28.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barefootjs/xyflow",
3
- "version": "0.27.0",
3
+ "version": "0.28.1",
4
4
  "description": "Signal-based xyflow wrapper for BarefootJS",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,10 +1,20 @@
1
1
  /**
2
- * `<Flow renderNode={Fn}>` hydrates the rendered bridge as a top-level
3
- * scope outside Flow's `FlowContext.Provider`, so consumers that look up
4
- * the store via `useFlow()` get back `undefined`. As an escape hatch,
5
- * `attachFlowSubsystems` stamps the host `<div class="bf-flow">` with
6
- * `__bfFlowStore` so children can walk up the DOM and read the store
7
- * without going through the context system.
2
+ * `attachFlowSubsystems` must NOT stamp the store onto the host element.
3
+ *
4
+ * It used to, as an escape hatch for "descendants that miss `FlowContext`" —
5
+ * on the premise that `<Flow renderNode={Fn}>` hydrates its children as a
6
+ * top-level scope outside the `FlowContext.Provider`. That premise does not
7
+ * hold in the rendered DOM: the provider's context map sits on the
8
+ * `<div class="bf-flow">` host itself, which is an ancestor of every
9
+ * `.bf-flow__node`, and `useContext` walks `parentElement` — so any connected
10
+ * descendant resolves the store regardless of which scope it was hydrated as.
11
+ * The one shape that genuinely failed was a child initialising while its row
12
+ * was still detached, fixed at the root in the runtime (#2431).
13
+ *
14
+ * Nothing ever read the property, so it was a write-only global whose comment
15
+ * asserted a live product defect that did not exist — and that misreading fed
16
+ * a wrong priority call. This test pins the removal so it cannot come back
17
+ * without a reader to justify it.
8
18
  */
9
19
  import { beforeAll, describe, expect, test } from 'bun:test'
10
20
  import { GlobalRegistrator } from '@happy-dom/global-registrator'
@@ -13,8 +23,8 @@ beforeAll(() => {
13
23
  if (!GlobalRegistrator.isRegistered) GlobalRegistrator.register()
14
24
  })
15
25
 
16
- describe('attachFlowSubsystems exposes the store on the host element', () => {
17
- test('sets `__bfFlowStore` on the element it attaches to', async () => {
26
+ describe('attachFlowSubsystems keeps no second store-lookup path', () => {
27
+ test('does not stamp `__bfFlowStore` on the host element', async () => {
18
28
  // Lazy import so happy-dom globals are in place before xyflow loads.
19
29
  const { attachFlowSubsystems } = await import('../flow-subsystems')
20
30
  const { createFlowStore } = await import('../store')
@@ -28,6 +38,12 @@ describe('attachFlowSubsystems exposes the store on the host element', () => {
28
38
  // biome-ignore lint/suspicious/noExplicitAny: minimal props for unit test
29
39
  attachFlowSubsystems(el, store as any, {} as any)
30
40
 
31
- expect((el as HTMLElement & { __bfFlowStore?: unknown }).__bfFlowStore).toBe(store)
41
+ // Presence, not value: a `toBeUndefined()` read would also pass if the
42
+ // attach stamped the property and assigned `undefined` to it, which is
43
+ // still an expando on a public DOM element.
44
+ expect(Object.hasOwn(el, '__bfFlowStore')).toBe(false)
45
+ // The attach itself still has to have happened — otherwise this test
46
+ // would pass against a no-op `attachFlowSubsystems`.
47
+ expect(store.domNode()).toBe(el)
32
48
  })
33
49
  })
@@ -88,14 +88,18 @@ export function attachFlowSubsystems<
88
88
  el.style.overflow = 'hidden'
89
89
 
90
90
  store.setDomNode(el)
91
- // Expose the store on the host `<div class="bf-flow">` element so
92
- // descendants that miss `FlowContext` e.g. children passed through
93
- // `<Flow renderNode={Fn}>` whose returned JSX is hydrated as a
94
- // top-level scope outside of Flow's `FlowContext.Provider` can
95
- // still locate the store via `el.closest('.bf-flow').__bfFlowStore`.
96
- // Always-set, even on hot remount, so callers can rely on a single
97
- // canonical reference.
98
- ;(el as HTMLElement & { __bfFlowStore?: typeof store }).__bfFlowStore = store
91
+ // No `__bfFlowStore` escape hatch here. This used to stamp the store on
92
+ // the host element for "descendants that miss `FlowContext`", on the
93
+ // premise that `<Flow renderNode={Fn}>` hydrates its children as a
94
+ // top-level scope outside the `FlowContext.Provider`. That premise does
95
+ // not hold in the rendered DOM: the provider's context map lives on this
96
+ // very `<div class="bf-flow">`, which is an ancestor of every
97
+ // `.bf-flow__node`, and `useContext` walks `parentElement` — so any
98
+ // CONNECTED descendant resolves the store no matter which scope it was
99
+ // hydrated as, verified in a browser. The one shape that did fail was a
100
+ // child initialising while its row was still detached, and that is fixed
101
+ // at the root in the runtime (#2431), not by a second lookup path.
102
+ // Nothing read the property, so it was a write-only global.
99
103
  store.setWidth(el.offsetWidth)
100
104
  store.setHeight(el.offsetHeight)
101
105