• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

LouisBrunner / dnd-multi-backend / 7105543555

05 Dec 2023 07:21PM CUT coverage: 98.498%. Remained the same
7105543555

push

github

web-flow
chore(deps-dev): bump eslint-plugin-testing-library from 6.1.2 to 6.2.0 (#239)

Bumps [eslint-plugin-testing-library](https://github.com/testing-library/eslint-plugin-testing-library) from 6.1.2 to 6.2.0.
- [Release notes](https://github.com/testing-library/eslint-plugin-testing-library/releases)
- [Changelog](https://github.com/testing-library/eslint-plugin-testing-library/blob/main/.releaserc.json)
- [Commits](https://github.com/testing-library/eslint-plugin-testing-library/compare/v6.1.2...v6.2.0)

---
updated-dependencies:
- dependency-name: eslint-plugin-testing-library
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

63 of 67 branches covered (0.0%)

Branch coverage included in aggregate %.

265 of 266 relevant lines covered (99.62%)

37.11 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.24
/packages/dnd-multi-backend/src/MultiBackendImpl.ts
1
import {DragDropManager, BackendFactory, Unsubscribe} from 'dnd-core'
138✔
2
import {BackendEntry, MultiBackendSwitcher, PreviewList, Transition } from './types'
3
import { PreviewListImpl } from './PreviewListImpl'
12✔
4

5
interface EventConstructor {
6
  new(type: string, eventInitDict?: EventInit): Event;
7
}
8

9
type DnDNode = {
10
  func: ConnectFunction,
11
  args: [unknown, unknown?, unknown?],
12
  unsubscribe: Unsubscribe,
13
}
14

15
type ConnectFunction = 'connectDragSource' | 'connectDragPreview' | 'connectDropTarget'
16

17
export type MultiBackendContext = unknown
18

19
export type MultiBackendPipelineStep = {
20
  id: string,
21
  backend: BackendFactory,
22
  transition?: Transition,
23
  preview?: boolean,
24
  skipDispatchOnTransition?: boolean,
25
  options?: unknown,
26
}
27

28
export type MultiBackendPipeline = MultiBackendPipelineStep[]
29

30
export type MultiBackendOptions = {
31
  backends: MultiBackendPipeline,
32
}
33

34
export class MultiBackendImpl implements MultiBackendSwitcher {
12✔
35
  private static /*#*/isSetUp = false
12✔
36

37
  /*private*/ #current: string
111✔
38
  /*private*/ #previews: PreviewList
111✔
39
  /*private*/ #backends: Record<string, BackendEntry>
111✔
40
  /*private*/ #backendsList: BackendEntry[]
111✔
41
  /*private*/ #nodes: Record<string, DnDNode>
111✔
42

43
  constructor(manager: DragDropManager, context?: MultiBackendContext, options?: MultiBackendOptions) {
44
    if (!options || !options.backends || options.backends.length < 1) {
99✔
45
      throw new Error(
9✔
46
        `You must specify at least one Backend, if you are coming from 2.x.x (or don't understand this error)
47
        see this guide: https://github.com/louisbrunner/dnd-multi-backend/tree/master/packages/react-dnd-multi-backend#migrating-from-2xx`
48
      )
49
    }
50

51
    this.#previews = new PreviewListImpl()
90✔
52

53
    this.#backends = {}
90✔
54
    this.#backendsList = []
90✔
55
    options.backends.forEach((backend: MultiBackendPipelineStep) => {
90✔
56
      const backendRecord = this.#createBackend(manager, context, backend)
168✔
57
      this.#backends[backendRecord.id] = backendRecord
156✔
58
      this.#backendsList.push(backendRecord)
156✔
59
    })
60
    this.#current = this.#backendsList[0].id
78✔
61

62
    this.#nodes = {}
78✔
63
  }
64

65
  #createBackend = (manager: DragDropManager, context: MultiBackendContext, backend: MultiBackendPipelineStep): BackendEntry => {
99✔
66
    if (!backend.backend) {
168✔
67
      throw new Error(`You must specify a 'backend' property in your Backend entry: ${JSON.stringify(backend)}`)
3✔
68
    }
69

70
    const instance = backend.backend(manager, context, backend.options)
165✔
71

72
    let id = backend.id
165✔
73
    // Try to infer an `id` if one doesn't exist
74
    const inferName = !backend.id && instance && instance.constructor
165✔
75
    if (inferName) {
165✔
76
      id = instance.constructor.name
3✔
77
    }
78
    if (!id) {
165✔
79
      throw new Error(
6✔
80
        `You must specify an 'id' property in your Backend entry: ${JSON.stringify(backend)}
81
        see this guide: https://github.com/louisbrunner/dnd-multi-backend/tree/master/packages/react-dnd-multi-backend#migrating-from-5xx`
82
      )
83
    } else if (inferName) {
159✔
84
      console.warn( // eslint-disable-line no-console
3✔
85
        `Deprecation notice: You are using a pipeline which doesn't include backends' 'id'.
86
        This might be unsupported in the future, please specify 'id' explicitely for every backend.`
87
      )
88
    }
89
    if (this.#backends[id]) {
159✔
90
      throw new Error(
3✔
91
        `You must specify a unique 'id' property in your Backend entry:
92
        ${JSON.stringify(backend)} (conflicts with: ${JSON.stringify(this.#backends[id])})`)
93
    }
94

95
    return {
156✔
96
      id,
97
      instance,
98
      preview: backend.preview ?? false,
156✔
99
      transition: backend.transition,
100
      skipDispatchOnTransition: backend.skipDispatchOnTransition ?? false,
156✔
101
    }
102
  }
103

104
  // DnD Backend API
105
  setup = (): void => {
99✔
106
    if (typeof window === 'undefined') {
48✔
107
      return
9✔
108
    }
109

110
    if (MultiBackendImpl.isSetUp) {
39✔
111
      throw new Error('Cannot have two MultiBackends at the same time.')
3✔
112
    }
113
    MultiBackendImpl.isSetUp = true
36✔
114
    this.#addEventListeners(window)
36✔
115
    this.#backends[this.#current].instance.setup()
36✔
116
  }
117

118
  teardown = (): void => {
99✔
119
    if (typeof window === 'undefined') {
42✔
120
      return
6✔
121
    }
122

123
    MultiBackendImpl.isSetUp = false
36✔
124
    this.#removeEventListeners(window)
36✔
125
    this.#backends[this.#current].instance.teardown()
36✔
126
  }
127

128
  connectDragSource = (sourceId: unknown, node?: unknown, options?: unknown): Unsubscribe => {
99✔
129
    return this.#connectBackend('connectDragSource', sourceId, node, options)
6✔
130
  }
131

132
  connectDragPreview = (sourceId: unknown, node?: unknown, options?: unknown): Unsubscribe => {
99✔
133
    return this.#connectBackend('connectDragPreview', sourceId, node, options)
6✔
134
  }
135

136
  connectDropTarget = (sourceId: unknown, node?: unknown, options?: unknown): Unsubscribe => {
99✔
137
    return this.#connectBackend('connectDropTarget', sourceId, node, options)
6✔
138
  }
139

140
  profile = (): Record<string, number> => {
99✔
141
    return this.#backends[this.#current].instance.profile()
3✔
142
  }
143

144
  // Used by Preview component
145
  previewEnabled = (): boolean => {
99✔
146
    return this.#backends[this.#current].preview
6✔
147
  }
148

149
  previewsList = (): PreviewList => {
99✔
150
    return this.#previews
3✔
151
  }
152

153
  backendsList = (): BackendEntry[] => {
99✔
154
    return this.#backendsList
3✔
155
  }
156

157
  // Multi Backend Listeners
158
  #addEventListeners = (target: EventTarget): void => {
99✔
159
    this.#backendsList.forEach((backend) => {
36✔
160
      if (backend.transition) {
72✔
161
        target.addEventListener(backend.transition.event, this.#backendSwitcher)
36✔
162
      }
163
    })
164
  }
165

166
  #removeEventListeners = (target: EventTarget): void => {
99✔
167
    this.#backendsList.forEach((backend) => {
36✔
168
      if (backend.transition) {
72✔
169
        target.removeEventListener(backend.transition.event, this.#backendSwitcher)
36✔
170
      }
171
    })
172
  }
173

174
  // Switching logic
175
  #backendSwitcher = (event: Event): void => {
99✔
176
    const oldBackend = this.#current
39✔
177

178
    this.#backendsList.some((backend) => {
39✔
179
      if (backend.id !== this.#current && backend.transition && backend.transition.check(event)) {
78✔
180
        this.#current = backend.id
21✔
181
        return true
21✔
182
      }
183
      return false
57✔
184
    })
185

186
    if (this.#current !== oldBackend) {
39✔
187
      this.#backends[oldBackend].instance.teardown()
21✔
188
      Object.keys(this.#nodes).forEach((id) => {
21✔
189
        const node = this.#nodes[id]
9✔
190
        node.unsubscribe()
9✔
191
        node.unsubscribe = this.#callBackend(node.func, ...node.args)
9✔
192
      })
193
      this.#previews.backendChanged(this)
21✔
194

195
      const newBackend = this.#backends[this.#current]
21✔
196
      newBackend.instance.setup()
21✔
197

198
      if (newBackend.skipDispatchOnTransition) {
21✔
199
        return
3✔
200
      }
201

202
      const Class = event.constructor as EventConstructor
18✔
203
      const newEvent = new Class(event.type, event)
18✔
204
      event.target?.dispatchEvent(newEvent)
18!
205
    }
206
  }
207

208
  #callBackend = (func: ConnectFunction, sourceId: unknown, node?: unknown, options?: unknown): Unsubscribe => {
99✔
209
    return this.#backends[this.#current].instance[func](sourceId, node, options)
27✔
210
  }
211

212
  #connectBackend = (func: ConnectFunction, sourceId: unknown, node?: unknown, options?: unknown): Unsubscribe => {
99✔
213
    const nodeId = `${func}_${sourceId as number}`
18✔
214
    const unsubscribe = this.#callBackend(func, sourceId, node, options)
18✔
215
    this.#nodes[nodeId] = {
18✔
216
      func,
217
      args: [sourceId, node, options],
218
      unsubscribe,
219
    }
220

221
    return (): void => {
18✔
222
      this.#nodes[nodeId].unsubscribe()
18✔
223
      delete this.#nodes[nodeId]
18✔
224
    }
225
  }
226
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc