質問編集履歴

2

記述したファイルに誤りがあり、修正

2021/12/15 00:23

投稿

hayatoganbaru
hayatoganbaru

スコア7

test CHANGED
File without changes
test CHANGED
@@ -34,330 +34,224 @@
34
34
 
35
35
  ```
36
36
 
37
+ import { createContext, mergeRefs } from "@chakra-ui/react-utils"
38
+
39
+ import { RefCallback, useRef, useState } from "react"
40
+
41
+ import { DescendantsManager, DescendantOptions } from "./descendant"
42
+
37
- import { sortNodes, isElement, getNextIndex, getPrevIndex } from "./utils"
43
+ import { useSafeLayoutEffect, cast } from "./utils"
38
-
39
-
40
-
41
- export type DescendantOptions<T = {}> = T & {
44
+
42
-
45
+
46
+
43
- /**
47
+ /**
48
+
44
-
49
+ * @internal
50
+
45
- * If `true`, the item will be registered in all nodes map
51
+ * React hook that initializes the DescendantsManager
46
-
47
- * but omitted from enabled nodes map
52
+
48
-
49
- */
53
+ */
54
+
50
-
55
+ function useDescendants<T extends HTMLElement = HTMLElement, K = {}>() {
56
+
51
- disabled?: boolean
57
+ const descendants = useRef(new DescendantsManager<T, K>())
52
-
53
- /**
58
+
54
-
55
- * The id of the item
59
+ useSafeLayoutEffect(() => {
60
+
56
-
61
+ return () => descendants.current.destroy()
62
+
57
- */
63
+ })
58
-
64
+
59
- id?: string
65
+ return descendants.current
60
66
 
61
67
  }
62
68
 
63
69
 
64
70
 
71
+ export interface UseDescendantsReturn
72
+
73
+ extends ReturnType<typeof useDescendants> {}
74
+
75
+
76
+
77
+ /* -------------------------------------------------------------------------------------------------
78
+
79
+ * Descendants context to be used in component-land.
80
+
65
- export type Descendant<T, K> = DescendantOptions<K> & {
81
+ - Mount the `DescendantsContextProvider` at the root of the component
82
+
66
-
83
+ - Call `useDescendantsContext` anywhere you need access to the descendants information
84
+
85
+
86
+
87
+ NB: I recommend using `createDescendantContext` below
88
+
89
+ * -----------------------------------------------------------------------------------------------*/
90
+
91
+
92
+
93
+ const [
94
+
95
+ DescendantsContextProvider,
96
+
97
+ useDescendantsContext,
98
+
99
+ ] = createContext<UseDescendantsReturn>({
100
+
101
+ name: "DescendantsProvider",
102
+
103
+ errorMessage: "useDescendantsContext must be used within DescendantsProvider",
104
+
105
+ })
106
+
107
+
108
+
67
- /**
109
+ /**
110
+
68
-
111
+ * @internal
112
+
113
+ * This hook provides information a descendant such as:
114
+
69
- * DOM element of the item
115
+ * - Its index compared to other descendants
116
+
70
-
117
+ * - ref callback to register the descendant
118
+
119
+ * - Its enabled index compared to other enabled descendants
120
+
71
- */
121
+ */
122
+
72
-
123
+ function useDescendant<T extends HTMLElement = HTMLElement, K = {}>(
124
+
125
+ options?: DescendantOptions<K>,
126
+
127
+ ) {
128
+
129
+ const descendants = useDescendantsContext()
130
+
131
+ const [index, setIndex] = useState(-1)
132
+
133
+ const ref = useRef<T>(null)
134
+
135
+
136
+
137
+ useSafeLayoutEffect(() => {
138
+
139
+ return () => {
140
+
141
+ if (!ref.current) return
142
+
143
+ descendants.unregister(ref.current)
144
+
145
+ }
146
+
147
+ }, [])
148
+
149
+
150
+
151
+ useSafeLayoutEffect(() => {
152
+
153
+ if (!ref.current) return
154
+
155
+ const dataIndex = Number(ref.current.dataset.index)
156
+
157
+ if (index != dataIndex && !Number.isNaN(dataIndex)) {
158
+
159
+ setIndex(dataIndex)
160
+
161
+ }
162
+
163
+ })
164
+
165
+
166
+
167
+ const refCallback = options
168
+
169
+ ? cast<RefCallback<T>>(descendants.register(options))
170
+
171
+ : cast<RefCallback<T>>(descendants.register)
172
+
173
+
174
+
175
+ return {
176
+
177
+ descendants,
178
+
73
- node: T
179
+ index,
74
-
75
- /**
180
+
76
-
77
- * index of item in all nodes map and enabled nodes map
181
+ enabledIndex: descendants.enabledIndexOf(ref.current),
78
-
79
- */
182
+
80
-
81
- index: number
183
+ register: mergeRefs(refCallback, ref),
184
+
185
+ }
82
186
 
83
187
  }
84
188
 
85
189
 
86
190
 
87
- /**
88
-
89
- * @internal
90
-
91
- *
92
-
93
- * Class to manage descendants and their relative indices in the DOM.
94
-
95
- * It uses `node.compareDocumentPosition(...)` under the hood
96
-
97
- */
98
-
99
- export class DescendantsManager<
100
-
101
- T extends HTMLElement,
102
-
103
- K extends Record<string, any> = {}
104
-
105
- > {
106
-
107
- private descendants = new Map<T, Descendant<T, K>>()
108
-
109
-
110
-
111
- register = (nodeOrOptions: T | null | DescendantOptions<K>) => {
112
-
113
- if (nodeOrOptions == null) return
114
-
115
-
116
-
117
- if (isElement(nodeOrOptions)) {
118
-
119
- return this.registerNode(nodeOrOptions)
120
-
121
- }
122
-
123
-
124
-
125
- return (node: T | null) => {
126
-
127
- this.registerNode(node, nodeOrOptions)
128
-
129
- }
130
-
131
- }
132
-
133
-
134
-
135
- unregister = (node: T) => {
136
-
137
- this.descendants.delete(node)
138
-
139
- const sorted = sortNodes(Array.from(this.descendants.keys()))
140
-
141
- this.assignIndex(sorted)
142
-
143
- }
144
-
145
-
146
-
147
- destroy = () => {
148
-
149
- this.descendants.clear()
150
-
151
- }
152
-
153
-
154
-
155
- private assignIndex = (descendants: Node[]) => {
156
-
157
- this.descendants.forEach((descendant) => {
158
-
159
- const index = descendants.indexOf(descendant.node)
160
-
161
- descendant.index = index
162
-
163
- descendant.node.dataset.index = descendant.index.toString()
164
-
165
- })
166
-
167
- }
168
-
169
-
170
-
171
- count = () => this.descendants.size
172
-
173
-
174
-
175
- enabledCount = () => this.enabledValues().length
176
-
177
-
178
-
179
- values = () => {
180
-
181
- const values = Array.from(this.descendants.values())
182
-
183
- return values.sort((a, b) => a.index - b.index)
184
-
185
- }
186
-
187
-
188
-
189
- enabledValues = () => {
190
-
191
- return this.values().filter((descendant) => !descendant.disabled)
192
-
193
- }
194
-
195
-
196
-
197
- item = (index: number) => {
198
-
199
- if (this.count() === 0) return undefined
200
-
201
- return this.values()[index]
202
-
203
- }
204
-
205
-
206
-
207
- enabledItem = (index: number) => {
208
-
209
- if (this.enabledCount() === 0) return undefined
210
-
211
- return this.enabledValues()[index]
212
-
213
- }
214
-
215
-
216
-
217
- first = () => this.item(0)
218
-
219
-
220
-
221
- firstEnabled = () => this.enabledItem(0)
222
-
223
-
224
-
225
- last = () => this.item(this.descendants.size - 1)
226
-
227
-
228
-
229
- lastEnabled = () => {
230
-
231
- const lastIndex = this.enabledValues().length - 1
232
-
233
- return this.enabledItem(lastIndex)
234
-
235
- }
236
-
237
-
238
-
239
- indexOf = (node: T | null) => {
240
-
241
- if (!node) return -1
242
-
243
- return this.descendants.get(node)?.index ?? -1
244
-
245
- }
246
-
247
-
248
-
249
- enabledIndexOf = (node: T | null) => {
250
-
251
- if (node == null) return -1
252
-
253
- return this.enabledValues().findIndex((i) => i.node.isSameNode(node))
254
-
255
- }
256
-
257
-
258
-
259
- next = (index: number, loop = true) => {
260
-
261
- const next = getNextIndex(index, this.count(), loop)
262
-
263
- return this.item(next)
264
-
265
- }
266
-
267
-
268
-
269
- nextEnabled = (index: number, loop = true) => {
270
-
271
- const item = this.item(index)
272
-
273
- if (!item) return
274
-
275
- const enabledIndex = this.enabledIndexOf(item.node)
276
-
277
- const nextEnabledIndex = getNextIndex(
278
-
279
- enabledIndex,
280
-
281
- this.enabledCount(),
282
-
283
- loop,
284
-
285
- )
286
-
287
- return this.enabledItem(nextEnabledIndex)
288
-
289
- }
290
-
291
-
292
-
293
- prev = (index: number, loop = true) => {
294
-
295
- const prev = getPrevIndex(index, this.count() - 1, loop)
296
-
297
- return this.item(prev)
298
-
299
- }
300
-
301
-
302
-
303
- prevEnabled = (index: number, loop = true) => {
304
-
305
- const item = this.item(index)
306
-
307
- if (!item) return
308
-
309
- const enabledIndex = this.enabledIndexOf(item.node)
310
-
311
- const prevEnabledIndex = getPrevIndex(
312
-
313
- enabledIndex,
314
-
315
- this.enabledCount() - 1,
316
-
317
- loop,
318
-
319
- )
320
-
321
- return this.enabledItem(prevEnabledIndex)
322
-
323
- }
324
-
325
-
326
-
327
- private registerNode = (node: T | null, options?: DescendantOptions<K>) => {
328
-
329
- if (!node || this.descendants.has(node)) return
330
-
331
-
332
-
333
- const keys = Array.from(this.descendants.keys()).concat(node)
334
-
335
- const sorted = sortNodes(keys)
336
-
337
-
338
-
339
- if (options?.disabled) {
340
-
341
- options.disabled = !!options.disabled
342
-
343
- }
344
-
345
-
346
-
347
- const descendant = { node, index: -1, ...options }
348
-
349
-
350
-
351
- this.descendants.set(node, descendant as Descendant<T, K>)
352
-
353
-
354
-
355
- this.assignIndex(sorted)
356
-
357
- }
191
+ /* -------------------------------------------------------------------------------------------------
192
+
193
+ * Function that provides strongly typed versions of the context provider and hooks above.
194
+
195
+ To be used in component-land
196
+
197
+ * -----------------------------------------------------------------------------------------------*/
198
+
199
+
200
+
201
+ export function createDescendantContext<
202
+
203
+ T extends HTMLElement = HTMLElement,
204
+
205
+ K = {}
206
+
207
+ >() {
208
+
209
+ type ContextProviderType = React.Provider<DescendantsManager<T, K>>
210
+
211
+ const ContextProvider = cast<ContextProviderType>(DescendantsContextProvider)
212
+
213
+
214
+
215
+ const _useDescendantsContext = () =>
216
+
217
+ cast<DescendantsManager<T, K>>(useDescendantsContext())
218
+
219
+
220
+
221
+ const _useDescendant = (options?: DescendantOptions<K>) =>
222
+
223
+ useDescendant<T, K>(options)
224
+
225
+
226
+
227
+ const _useDescendants = () => useDescendants<T, K>()
228
+
229
+
230
+
231
+ return [
232
+
233
+ // context provider
234
+
235
+ ContextProvider,
236
+
237
+ // call this when you need to read from context
238
+
239
+ _useDescendantsContext,
240
+
241
+ // descendants state information, to be called and passed to `ContextProvider`
242
+
243
+ _useDescendants,
244
+
245
+ // descendant index information
246
+
247
+ _useDescendant,
248
+
249
+ ] as const
358
250
 
359
251
  }
360
252
 
361
253
 
362
254
 
255
+
256
+
363
257
  ```

1

`unregister`の記載場所と詳細

2021/12/15 00:23

投稿

hayatoganbaru
hayatoganbaru

スコア7

test CHANGED
File without changes
test CHANGED
@@ -13,3 +13,351 @@
13
13
  'unregister'なんて記述はした覚えが全くないので困っています。
14
14
 
15
15
  解決へのアプローチをお教え頂けないでしょうか?
16
+
17
+
18
+
19
+ # `unregister`の記載場所と詳細
20
+
21
+
22
+
23
+ node_modules/@chakra-ui/descendant/src/use-descendant.tsに記述があるとのことです。
24
+
25
+
26
+
27
+ 実際にそのファイルは以下のようになっております。
28
+
29
+ エラー箇所のような記述を私は見つけることができませんでした。
30
+
31
+
32
+
33
+
34
+
35
+ ```
36
+
37
+ import { sortNodes, isElement, getNextIndex, getPrevIndex } from "./utils"
38
+
39
+
40
+
41
+ export type DescendantOptions<T = {}> = T & {
42
+
43
+ /**
44
+
45
+ * If `true`, the item will be registered in all nodes map
46
+
47
+ * but omitted from enabled nodes map
48
+
49
+ */
50
+
51
+ disabled?: boolean
52
+
53
+ /**
54
+
55
+ * The id of the item
56
+
57
+ */
58
+
59
+ id?: string
60
+
61
+ }
62
+
63
+
64
+
65
+ export type Descendant<T, K> = DescendantOptions<K> & {
66
+
67
+ /**
68
+
69
+ * DOM element of the item
70
+
71
+ */
72
+
73
+ node: T
74
+
75
+ /**
76
+
77
+ * index of item in all nodes map and enabled nodes map
78
+
79
+ */
80
+
81
+ index: number
82
+
83
+ }
84
+
85
+
86
+
87
+ /**
88
+
89
+ * @internal
90
+
91
+ *
92
+
93
+ * Class to manage descendants and their relative indices in the DOM.
94
+
95
+ * It uses `node.compareDocumentPosition(...)` under the hood
96
+
97
+ */
98
+
99
+ export class DescendantsManager<
100
+
101
+ T extends HTMLElement,
102
+
103
+ K extends Record<string, any> = {}
104
+
105
+ > {
106
+
107
+ private descendants = new Map<T, Descendant<T, K>>()
108
+
109
+
110
+
111
+ register = (nodeOrOptions: T | null | DescendantOptions<K>) => {
112
+
113
+ if (nodeOrOptions == null) return
114
+
115
+
116
+
117
+ if (isElement(nodeOrOptions)) {
118
+
119
+ return this.registerNode(nodeOrOptions)
120
+
121
+ }
122
+
123
+
124
+
125
+ return (node: T | null) => {
126
+
127
+ this.registerNode(node, nodeOrOptions)
128
+
129
+ }
130
+
131
+ }
132
+
133
+
134
+
135
+ unregister = (node: T) => {
136
+
137
+ this.descendants.delete(node)
138
+
139
+ const sorted = sortNodes(Array.from(this.descendants.keys()))
140
+
141
+ this.assignIndex(sorted)
142
+
143
+ }
144
+
145
+
146
+
147
+ destroy = () => {
148
+
149
+ this.descendants.clear()
150
+
151
+ }
152
+
153
+
154
+
155
+ private assignIndex = (descendants: Node[]) => {
156
+
157
+ this.descendants.forEach((descendant) => {
158
+
159
+ const index = descendants.indexOf(descendant.node)
160
+
161
+ descendant.index = index
162
+
163
+ descendant.node.dataset.index = descendant.index.toString()
164
+
165
+ })
166
+
167
+ }
168
+
169
+
170
+
171
+ count = () => this.descendants.size
172
+
173
+
174
+
175
+ enabledCount = () => this.enabledValues().length
176
+
177
+
178
+
179
+ values = () => {
180
+
181
+ const values = Array.from(this.descendants.values())
182
+
183
+ return values.sort((a, b) => a.index - b.index)
184
+
185
+ }
186
+
187
+
188
+
189
+ enabledValues = () => {
190
+
191
+ return this.values().filter((descendant) => !descendant.disabled)
192
+
193
+ }
194
+
195
+
196
+
197
+ item = (index: number) => {
198
+
199
+ if (this.count() === 0) return undefined
200
+
201
+ return this.values()[index]
202
+
203
+ }
204
+
205
+
206
+
207
+ enabledItem = (index: number) => {
208
+
209
+ if (this.enabledCount() === 0) return undefined
210
+
211
+ return this.enabledValues()[index]
212
+
213
+ }
214
+
215
+
216
+
217
+ first = () => this.item(0)
218
+
219
+
220
+
221
+ firstEnabled = () => this.enabledItem(0)
222
+
223
+
224
+
225
+ last = () => this.item(this.descendants.size - 1)
226
+
227
+
228
+
229
+ lastEnabled = () => {
230
+
231
+ const lastIndex = this.enabledValues().length - 1
232
+
233
+ return this.enabledItem(lastIndex)
234
+
235
+ }
236
+
237
+
238
+
239
+ indexOf = (node: T | null) => {
240
+
241
+ if (!node) return -1
242
+
243
+ return this.descendants.get(node)?.index ?? -1
244
+
245
+ }
246
+
247
+
248
+
249
+ enabledIndexOf = (node: T | null) => {
250
+
251
+ if (node == null) return -1
252
+
253
+ return this.enabledValues().findIndex((i) => i.node.isSameNode(node))
254
+
255
+ }
256
+
257
+
258
+
259
+ next = (index: number, loop = true) => {
260
+
261
+ const next = getNextIndex(index, this.count(), loop)
262
+
263
+ return this.item(next)
264
+
265
+ }
266
+
267
+
268
+
269
+ nextEnabled = (index: number, loop = true) => {
270
+
271
+ const item = this.item(index)
272
+
273
+ if (!item) return
274
+
275
+ const enabledIndex = this.enabledIndexOf(item.node)
276
+
277
+ const nextEnabledIndex = getNextIndex(
278
+
279
+ enabledIndex,
280
+
281
+ this.enabledCount(),
282
+
283
+ loop,
284
+
285
+ )
286
+
287
+ return this.enabledItem(nextEnabledIndex)
288
+
289
+ }
290
+
291
+
292
+
293
+ prev = (index: number, loop = true) => {
294
+
295
+ const prev = getPrevIndex(index, this.count() - 1, loop)
296
+
297
+ return this.item(prev)
298
+
299
+ }
300
+
301
+
302
+
303
+ prevEnabled = (index: number, loop = true) => {
304
+
305
+ const item = this.item(index)
306
+
307
+ if (!item) return
308
+
309
+ const enabledIndex = this.enabledIndexOf(item.node)
310
+
311
+ const prevEnabledIndex = getPrevIndex(
312
+
313
+ enabledIndex,
314
+
315
+ this.enabledCount() - 1,
316
+
317
+ loop,
318
+
319
+ )
320
+
321
+ return this.enabledItem(prevEnabledIndex)
322
+
323
+ }
324
+
325
+
326
+
327
+ private registerNode = (node: T | null, options?: DescendantOptions<K>) => {
328
+
329
+ if (!node || this.descendants.has(node)) return
330
+
331
+
332
+
333
+ const keys = Array.from(this.descendants.keys()).concat(node)
334
+
335
+ const sorted = sortNodes(keys)
336
+
337
+
338
+
339
+ if (options?.disabled) {
340
+
341
+ options.disabled = !!options.disabled
342
+
343
+ }
344
+
345
+
346
+
347
+ const descendant = { node, index: -1, ...options }
348
+
349
+
350
+
351
+ this.descendants.set(node, descendant as Descendant<T, K>)
352
+
353
+
354
+
355
+ this.assignIndex(sorted)
356
+
357
+ }
358
+
359
+ }
360
+
361
+
362
+
363
+ ```