primer_view_components 0.43.5 → 0.44.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +20 -0
- data/app/assets/javascripts/components/primer/alpha/tree_view/tree_view.d.ts +39 -0
- data/app/assets/javascripts/components/primer/alpha/tree_view/tree_view_icon_pair_element.d.ts +15 -0
- data/app/assets/javascripts/components/primer/alpha/tree_view/tree_view_include_fragment_element.d.ts +9 -0
- data/app/assets/javascripts/components/primer/alpha/tree_view/tree_view_roving_tab_index.d.ts +3 -0
- data/app/assets/javascripts/components/primer/alpha/tree_view/tree_view_sub_tree_node_element.d.ts +42 -0
- data/app/assets/javascripts/components/primer/primer.d.ts +4 -0
- data/app/assets/javascripts/components/primer/shared_events.d.ts +15 -0
- data/app/assets/javascripts/primer_view_components.js +1 -1
- data/app/assets/javascripts/primer_view_components.js.map +1 -1
- data/app/assets/styles/primer_view_components.css +1 -1
- data/app/assets/styles/primer_view_components.css.map +1 -1
- data/app/components/primer/alpha/file_tree_view/directory_node.html.erb +5 -0
- data/app/components/primer/alpha/file_tree_view/directory_node.rb +24 -0
- data/app/components/primer/alpha/file_tree_view/file_node.html.erb +2 -0
- data/app/components/primer/alpha/file_tree_view/file_node.rb +14 -0
- data/app/components/primer/alpha/file_tree_view.rb +15 -0
- data/app/components/primer/alpha/skeleton_box.css +1 -0
- data/app/components/primer/alpha/skeleton_box.css.json +6 -0
- data/app/components/primer/alpha/skeleton_box.css.map +1 -0
- data/app/components/primer/alpha/skeleton_box.html.erb +1 -0
- data/app/components/primer/alpha/skeleton_box.pcss +30 -0
- data/app/components/primer/alpha/skeleton_box.rb +29 -0
- data/app/components/primer/alpha/tree_view/icon.html.erb +1 -0
- data/app/components/primer/alpha/tree_view/icon.rb +22 -0
- data/app/components/primer/alpha/tree_view/icon_pair.html.erb +13 -0
- data/app/components/primer/alpha/tree_view/icon_pair.rb +42 -0
- data/app/components/primer/alpha/tree_view/leading_action.html.erb +3 -0
- data/app/components/primer/alpha/tree_view/leading_action.rb +18 -0
- data/app/components/primer/alpha/tree_view/leaf_node.html.erb +18 -0
- data/app/components/primer/alpha/tree_view/leaf_node.rb +96 -0
- data/app/components/primer/alpha/tree_view/loading_failure_message.html.erb +13 -0
- data/app/components/primer/alpha/tree_view/loading_failure_message.rb +31 -0
- data/app/components/primer/alpha/tree_view/node.html.erb +32 -0
- data/app/components/primer/alpha/tree_view/node.rb +194 -0
- data/app/components/primer/alpha/tree_view/skeleton_loader.html.erb +23 -0
- data/app/components/primer/alpha/tree_view/skeleton_loader.rb +36 -0
- data/app/components/primer/alpha/tree_view/spinner_loader.html.erb +20 -0
- data/app/components/primer/alpha/tree_view/spinner_loader.rb +33 -0
- data/app/components/primer/alpha/tree_view/sub_tree.html.erb +21 -0
- data/app/components/primer/alpha/tree_view/sub_tree.rb +113 -0
- data/app/components/primer/alpha/tree_view/sub_tree_container.html.erb +3 -0
- data/app/components/primer/alpha/tree_view/sub_tree_container.rb +39 -0
- data/app/components/primer/alpha/tree_view/sub_tree_node.html.erb +49 -0
- data/app/components/primer/alpha/tree_view/sub_tree_node.rb +188 -0
- data/app/components/primer/alpha/tree_view/tree_view.d.ts +39 -0
- data/app/components/primer/alpha/tree_view/tree_view.js +363 -0
- data/app/components/primer/alpha/tree_view/tree_view.ts +396 -0
- data/app/components/primer/alpha/tree_view/tree_view_icon_pair_element.d.ts +15 -0
- data/app/components/primer/alpha/tree_view/tree_view_icon_pair_element.js +62 -0
- data/app/components/primer/alpha/tree_view/tree_view_icon_pair_element.ts +56 -0
- data/app/components/primer/alpha/tree_view/tree_view_include_fragment_element.d.ts +9 -0
- data/app/components/primer/alpha/tree_view/tree_view_include_fragment_element.js +28 -0
- data/app/components/primer/alpha/tree_view/tree_view_include_fragment_element.ts +28 -0
- data/app/components/primer/alpha/tree_view/tree_view_roving_tab_index.d.ts +3 -0
- data/app/components/primer/alpha/tree_view/tree_view_roving_tab_index.js +130 -0
- data/app/components/primer/alpha/tree_view/tree_view_roving_tab_index.ts +161 -0
- data/app/components/primer/alpha/tree_view/tree_view_sub_tree_node_element.d.ts +42 -0
- data/app/components/primer/alpha/tree_view/tree_view_sub_tree_node_element.js +418 -0
- data/app/components/primer/alpha/tree_view/tree_view_sub_tree_node_element.ts +470 -0
- data/app/components/primer/alpha/tree_view/visual.html.erb +14 -0
- data/app/components/primer/alpha/tree_view/visual.rb +27 -0
- data/app/components/primer/alpha/tree_view.css +1 -0
- data/app/components/primer/alpha/tree_view.css.json +52 -0
- data/app/components/primer/alpha/tree_view.css.map +1 -0
- data/app/components/primer/alpha/tree_view.html.erb +12 -0
- data/app/components/primer/alpha/tree_view.pcss +373 -0
- data/app/components/primer/alpha/tree_view.rb +439 -0
- data/app/components/primer/beta/breadcrumbs.css +1 -1
- data/app/components/primer/beta/breadcrumbs.css.json +0 -1
- data/app/components/primer/beta/breadcrumbs.css.map +1 -1
- data/app/components/primer/beta/breadcrumbs.pcss +2 -8
- data/app/components/primer/beta/progress_bar.css +1 -1
- data/app/components/primer/beta/progress_bar.css.map +1 -1
- data/app/components/primer/beta/progress_bar.pcss +3 -2
- data/app/components/primer/beta/relative_time.rb +3 -0
- data/app/components/primer/beta/spinner.html.erb +1 -1
- data/app/components/primer/beta/spinner.rb +2 -0
- data/app/components/primer/primer.d.ts +4 -0
- data/app/components/primer/primer.js +4 -0
- data/app/components/primer/primer.pcss +2 -0
- data/app/components/primer/primer.ts +4 -0
- data/app/components/primer/shared_events.d.ts +15 -0
- data/app/components/primer/shared_events.ts +19 -0
- data/app/controllers/primer/view_components/tree_view_items.json +293 -0
- data/app/controllers/primer/view_components/tree_view_items_controller.rb +55 -0
- data/app/forms/check_box_with_nested_form.rb +10 -10
- data/app/forms/radio_button_with_nested_form.rb +16 -16
- data/app/views/primer/view_components/tree_view_items/async_alpha.html_fragment.erb +23 -0
- data/app/views/primer/view_components/tree_view_items/index.html_fragment.erb +24 -0
- data/config/routes.rb +2 -0
- data/lib/primer/view_components/version.rb +2 -2
- data/previews/primer/alpha/file_tree_view_preview/default.html.erb +16 -0
- data/previews/primer/alpha/file_tree_view_preview/playground.html.erb +4 -0
- data/previews/primer/alpha/file_tree_view_preview.rb +69 -0
- data/previews/primer/alpha/skeleton_box_preview.rb +20 -0
- data/previews/primer/alpha/tree_view_preview/async_alpha.html.erb +12 -0
- data/previews/primer/alpha/tree_view_preview/buttons.html.erb +10 -0
- data/previews/primer/alpha/tree_view_preview/default.html.erb +24 -0
- data/previews/primer/alpha/tree_view_preview/empty.html.erb +10 -0
- data/previews/primer/alpha/tree_view_preview/form_input.html.erb +14 -0
- data/previews/primer/alpha/tree_view_preview/leaf_node_playground.html.erb +15 -0
- data/previews/primer/alpha/tree_view_preview/links.html.erb +17 -0
- data/previews/primer/alpha/tree_view_preview/loading_failure.html.erb +36 -0
- data/previews/primer/alpha/tree_view_preview/loading_skeleton.html.erb +12 -0
- data/previews/primer/alpha/tree_view_preview/loading_spinner.html.erb +12 -0
- data/previews/primer/alpha/tree_view_preview/playground.html.erb +4 -0
- data/previews/primer/alpha/tree_view_preview.rb +208 -0
- data/static/arguments.json +456 -0
- data/static/audited_at.json +17 -0
- data/static/classes.json +15 -0
- data/static/constants.json +101 -0
- data/static/info_arch.json +1410 -56
- data/static/previews.json +232 -0
- data/static/statuses.json +17 -0
- metadata +89 -8
@@ -0,0 +1,396 @@
|
|
1
|
+
import {controller, target} from '@github/catalyst'
|
2
|
+
import {TreeViewSubTreeNodeElement} from './tree_view_sub_tree_node_element'
|
3
|
+
import {useRovingTabIndex} from './tree_view_roving_tab_index'
|
4
|
+
import type {TreeViewNodeType, TreeViewCheckedValue, TreeViewNodeInfo} from '../../shared_events'
|
5
|
+
|
6
|
+
@controller
|
7
|
+
export class TreeViewElement extends HTMLElement {
|
8
|
+
@target formInputContainer: HTMLElement
|
9
|
+
@target formInputPrototype: HTMLInputElement
|
10
|
+
|
11
|
+
#abortController: AbortController
|
12
|
+
|
13
|
+
connectedCallback() {
|
14
|
+
const {signal} = (this.#abortController = new AbortController())
|
15
|
+
this.addEventListener('click', this, {signal})
|
16
|
+
this.addEventListener('focusin', this, {signal})
|
17
|
+
this.addEventListener('keydown', this, {signal})
|
18
|
+
|
19
|
+
useRovingTabIndex(this)
|
20
|
+
|
21
|
+
// catch-all for any straggler nodes that aren't available when connectedCallback runs
|
22
|
+
new MutationObserver(mutations => {
|
23
|
+
for (const mutation of mutations) {
|
24
|
+
for (const addedNode of mutation.addedNodes) {
|
25
|
+
if (!(addedNode instanceof HTMLElement)) continue
|
26
|
+
|
27
|
+
if (addedNode.querySelector('[aria-expanded=true]')) {
|
28
|
+
this.#autoExpandFrom(addedNode)
|
29
|
+
}
|
30
|
+
}
|
31
|
+
}
|
32
|
+
}).observe(this, {childList: true, subtree: true})
|
33
|
+
|
34
|
+
const updateInputsObserver = new MutationObserver(mutations => {
|
35
|
+
if (!this.formInputContainer) return
|
36
|
+
|
37
|
+
// There is another MutationObserver in TreeViewSubTreeNodeElement that manages checking/unchecking
|
38
|
+
// nodes based on the component's select strategy. These two observers can conflict and cause infinite
|
39
|
+
// looping, so we make sure something actually changed before computing inputs again.
|
40
|
+
const somethingChanged = mutations.some(m => {
|
41
|
+
if (!(m.target instanceof HTMLElement)) return false
|
42
|
+
return m.target.getAttribute('aria-checked') !== m.oldValue
|
43
|
+
})
|
44
|
+
|
45
|
+
if (!somethingChanged) return
|
46
|
+
|
47
|
+
const newInputs = []
|
48
|
+
|
49
|
+
for (const node of this.querySelectorAll('[role=treeitem][aria-checked=true]')) {
|
50
|
+
const newInput = this.formInputPrototype.cloneNode() as HTMLInputElement
|
51
|
+
newInput.removeAttribute('data-target')
|
52
|
+
newInput.removeAttribute('form')
|
53
|
+
|
54
|
+
const payload: {path: string[]; value?: string} = {
|
55
|
+
path: this.getNodePath(node),
|
56
|
+
}
|
57
|
+
|
58
|
+
const inputValue = this.getFormInputValueForNode(node)
|
59
|
+
if (inputValue) payload.value = inputValue
|
60
|
+
|
61
|
+
newInput.value = JSON.stringify(payload)
|
62
|
+
newInputs.push(newInput)
|
63
|
+
}
|
64
|
+
|
65
|
+
this.formInputContainer.replaceChildren(...newInputs)
|
66
|
+
})
|
67
|
+
|
68
|
+
updateInputsObserver.observe(this, {
|
69
|
+
childList: true,
|
70
|
+
subtree: true,
|
71
|
+
attributeFilter: ['aria-checked'],
|
72
|
+
})
|
73
|
+
|
74
|
+
// eslint-disable-next-line github/no-then -- We don't want to wait for this to resolve, just get on with it
|
75
|
+
customElements.whenDefined('tree-view-sub-tree-node').then(() => {
|
76
|
+
// depends on TreeViewSubTreeNodeElement#eachAncestorSubTreeNode, which may not be defined yet
|
77
|
+
this.#autoExpandFrom(this)
|
78
|
+
})
|
79
|
+
}
|
80
|
+
|
81
|
+
#autoExpandFrom(root: HTMLElement) {
|
82
|
+
for (const element of root.querySelectorAll('[aria-expanded=true]')) {
|
83
|
+
this.expandAncestorsForNode(element as HTMLElement)
|
84
|
+
}
|
85
|
+
}
|
86
|
+
|
87
|
+
disconnectedCallback() {
|
88
|
+
this.#abortController.abort()
|
89
|
+
}
|
90
|
+
|
91
|
+
handleEvent(event: Event) {
|
92
|
+
const node = this.#nodeForEvent(event)
|
93
|
+
|
94
|
+
if (node) {
|
95
|
+
this.#handleNodeEvent(node, event)
|
96
|
+
}
|
97
|
+
}
|
98
|
+
|
99
|
+
#eventIsActivation(event: Event): boolean {
|
100
|
+
return event.type === 'click'
|
101
|
+
}
|
102
|
+
|
103
|
+
#nodeForEvent(event: Event): Element | null {
|
104
|
+
const eventTarget = event.target as Element
|
105
|
+
const node = eventTarget.closest('[role=treeitem]')
|
106
|
+
if (!node) return null
|
107
|
+
|
108
|
+
if (eventTarget.closest('.TreeViewItemToggle')) return null
|
109
|
+
if (eventTarget.closest('.TreeViewItemLeadingAction')) return null
|
110
|
+
|
111
|
+
return node
|
112
|
+
}
|
113
|
+
|
114
|
+
#handleNodeEvent(node: Element, event: Event) {
|
115
|
+
if (this.#eventIsCheckboxToggle(event, node)) {
|
116
|
+
this.#handleCheckboxToggle(event, node)
|
117
|
+
} else if (this.#eventIsActivation(event)) {
|
118
|
+
this.#handleNodeActivated(event, node)
|
119
|
+
} else if (event.type === 'focusin') {
|
120
|
+
this.#handleNodeFocused(node)
|
121
|
+
} else if (event instanceof KeyboardEvent) {
|
122
|
+
this.#handleNodeKeyboardEvent(event, node)
|
123
|
+
}
|
124
|
+
}
|
125
|
+
|
126
|
+
#eventIsCheckboxToggle(event: Event, node: Element) {
|
127
|
+
return event.type === 'click' && this.nodeHasCheckBox(node)
|
128
|
+
}
|
129
|
+
|
130
|
+
#handleCheckboxToggle(event: Event, node: Element) {
|
131
|
+
if (this.getNodeDisabledValue(node)) {
|
132
|
+
event.preventDefault()
|
133
|
+
return
|
134
|
+
}
|
135
|
+
|
136
|
+
// only handle checking of leaf nodes, see TreeViewSubTreeNodeElement for the code that
|
137
|
+
// handles checking sub tree items.
|
138
|
+
const type = this.getNodeType(node)
|
139
|
+
if (type !== 'leaf') return
|
140
|
+
|
141
|
+
if (this.getNodeCheckedValue(node) === 'true') {
|
142
|
+
this.setNodeCheckedValue(node, 'false')
|
143
|
+
} else {
|
144
|
+
this.setNodeCheckedValue(node, 'true')
|
145
|
+
}
|
146
|
+
}
|
147
|
+
|
148
|
+
#handleNodeActivated(event: Event, node: Element) {
|
149
|
+
if (this.getNodeDisabledValue(node)) {
|
150
|
+
event.preventDefault()
|
151
|
+
return
|
152
|
+
}
|
153
|
+
|
154
|
+
// do not emit activation events for buttons and anchors, since it is assumed any activation
|
155
|
+
// behavior for these element types is user- or browser-defined
|
156
|
+
if (!(node instanceof HTMLDivElement)) return
|
157
|
+
|
158
|
+
const path = this.getNodePath(node)
|
159
|
+
|
160
|
+
const activationSuccess = this.dispatchEvent(
|
161
|
+
new CustomEvent('treeViewBeforeNodeActivated', {
|
162
|
+
bubbles: true,
|
163
|
+
cancelable: true,
|
164
|
+
detail: this.infoFromNode(node),
|
165
|
+
}),
|
166
|
+
)
|
167
|
+
|
168
|
+
if (!activationSuccess) return
|
169
|
+
|
170
|
+
// navigate or trigger button, don't toggle
|
171
|
+
if (!this.nodeHasNativeAction(node)) {
|
172
|
+
this.toggleAtPath(path)
|
173
|
+
}
|
174
|
+
|
175
|
+
this.dispatchEvent(
|
176
|
+
new CustomEvent('treeViewNodeActivated', {
|
177
|
+
bubbles: true,
|
178
|
+
detail: this.infoFromNode(node),
|
179
|
+
}),
|
180
|
+
)
|
181
|
+
}
|
182
|
+
|
183
|
+
#handleNodeFocused(node: Element) {
|
184
|
+
const previousNode = this.querySelector('[aria-selected=true]')
|
185
|
+
previousNode?.setAttribute('aria-selected', 'false')
|
186
|
+
node.setAttribute('aria-selected', 'true')
|
187
|
+
}
|
188
|
+
|
189
|
+
#handleNodeKeyboardEvent(event: KeyboardEvent, node: Element) {
|
190
|
+
if (!node || this.getNodeType(node) !== 'leaf') {
|
191
|
+
return
|
192
|
+
}
|
193
|
+
|
194
|
+
switch (event.key) {
|
195
|
+
case ' ':
|
196
|
+
case 'Enter':
|
197
|
+
if (this.getNodeDisabledValue(node)) {
|
198
|
+
event.preventDefault()
|
199
|
+
break
|
200
|
+
}
|
201
|
+
|
202
|
+
if (this.nodeHasCheckBox(node)) {
|
203
|
+
event.preventDefault()
|
204
|
+
|
205
|
+
if (this.getNodeCheckedValue(node) === 'true') {
|
206
|
+
this.setNodeCheckedValue(node, 'false')
|
207
|
+
} else {
|
208
|
+
this.setNodeCheckedValue(node, 'true')
|
209
|
+
}
|
210
|
+
} else if (node instanceof HTMLAnchorElement) {
|
211
|
+
// simulate click on space
|
212
|
+
node.click()
|
213
|
+
}
|
214
|
+
|
215
|
+
break
|
216
|
+
}
|
217
|
+
}
|
218
|
+
|
219
|
+
getFormInputValueForNode(node: Element): string | null {
|
220
|
+
return node.getAttribute('data-value')
|
221
|
+
}
|
222
|
+
|
223
|
+
getNodePath(node: Element): string[] {
|
224
|
+
const rawPath = node.getAttribute('data-path')
|
225
|
+
|
226
|
+
if (rawPath) {
|
227
|
+
return JSON.parse(rawPath)
|
228
|
+
}
|
229
|
+
|
230
|
+
return []
|
231
|
+
}
|
232
|
+
|
233
|
+
getNodeType(node: Element): TreeViewNodeType | null {
|
234
|
+
return node.getAttribute('data-node-type') as TreeViewNodeType | null
|
235
|
+
}
|
236
|
+
|
237
|
+
markCurrentAtPath(path: string[]) {
|
238
|
+
const pathStr = JSON.stringify(path)
|
239
|
+
const nodeToMark = this.querySelector(`[data-path="${CSS.escape(pathStr)}"`)
|
240
|
+
if (!nodeToMark) return
|
241
|
+
|
242
|
+
this.currentNode?.setAttribute('aria-current', 'false')
|
243
|
+
nodeToMark.setAttribute('aria-current', 'true')
|
244
|
+
}
|
245
|
+
|
246
|
+
get currentNode(): HTMLLIElement | null {
|
247
|
+
return this.querySelector('[aria-current=true]')
|
248
|
+
}
|
249
|
+
|
250
|
+
expandAtPath(path: string[]) {
|
251
|
+
const node = this.subTreeAtPath(path)
|
252
|
+
if (!node) return
|
253
|
+
|
254
|
+
node.expand()
|
255
|
+
}
|
256
|
+
|
257
|
+
collapseAtPath(path: string[]) {
|
258
|
+
const node = this.subTreeAtPath(path)
|
259
|
+
if (!node) return
|
260
|
+
|
261
|
+
node.collapse()
|
262
|
+
}
|
263
|
+
|
264
|
+
toggleAtPath(path: string[]) {
|
265
|
+
const node = this.subTreeAtPath(path)
|
266
|
+
if (!node) return
|
267
|
+
|
268
|
+
node.toggle()
|
269
|
+
}
|
270
|
+
|
271
|
+
checkAtPath(path: string[]) {
|
272
|
+
const node = this.nodeAtPath(path)
|
273
|
+
if (!node) return
|
274
|
+
|
275
|
+
this.setNodeCheckedValue(node, 'true')
|
276
|
+
}
|
277
|
+
|
278
|
+
uncheckAtPath(path: string[]) {
|
279
|
+
const node = this.nodeAtPath(path)
|
280
|
+
if (!node) return
|
281
|
+
|
282
|
+
this.setNodeCheckedValue(node, 'false')
|
283
|
+
}
|
284
|
+
|
285
|
+
toggleCheckedAtPath(path: string[]) {
|
286
|
+
const node = this.nodeAtPath(path)
|
287
|
+
if (!node) return
|
288
|
+
|
289
|
+
if (this.getNodeType(node) === 'leaf') {
|
290
|
+
if (this.getNodeCheckedValue(node) === 'true') {
|
291
|
+
this.uncheckAtPath(path)
|
292
|
+
} else {
|
293
|
+
this.checkAtPath(path)
|
294
|
+
}
|
295
|
+
}
|
296
|
+
}
|
297
|
+
|
298
|
+
checkedValueAtPath(path: string[]): TreeViewCheckedValue {
|
299
|
+
const node = this.nodeAtPath(path)
|
300
|
+
if (!node) return 'false'
|
301
|
+
|
302
|
+
return this.getNodeCheckedValue(node)
|
303
|
+
}
|
304
|
+
|
305
|
+
disabledValueAtPath(path: string[]): boolean {
|
306
|
+
const node = this.nodeAtPath(path)
|
307
|
+
if (!node) return false
|
308
|
+
|
309
|
+
return this.getNodeDisabledValue(node)
|
310
|
+
}
|
311
|
+
|
312
|
+
nodeAtPath(path: string[], selector?: string): Element | null {
|
313
|
+
const pathStr = JSON.stringify(path)
|
314
|
+
return this.querySelector(`${selector || ''}[data-path="${CSS.escape(pathStr)}"]`)
|
315
|
+
}
|
316
|
+
|
317
|
+
subTreeAtPath(path: string[]): TreeViewSubTreeNodeElement | null {
|
318
|
+
const node = this.nodeAtPath(path, '[data-node-type=sub-tree]')
|
319
|
+
if (!node) return null
|
320
|
+
|
321
|
+
return node.closest('tree-view-sub-tree-node') as TreeViewSubTreeNodeElement | null
|
322
|
+
}
|
323
|
+
|
324
|
+
leafAtPath(path: string[]): HTMLLIElement | null {
|
325
|
+
return this.nodeAtPath(path, '[data-node-type=leaf]') as HTMLLIElement | null
|
326
|
+
}
|
327
|
+
|
328
|
+
setNodeCheckedValue(node: Element, value: TreeViewCheckedValue) {
|
329
|
+
node.setAttribute('aria-checked', value.toString())
|
330
|
+
}
|
331
|
+
|
332
|
+
getNodeCheckedValue(node: Element): TreeViewCheckedValue {
|
333
|
+
return (node.getAttribute('aria-checked') || 'false') as TreeViewCheckedValue
|
334
|
+
}
|
335
|
+
|
336
|
+
getNodeDisabledValue(node: Element): boolean {
|
337
|
+
return node.getAttribute('aria-disabled') === 'true'
|
338
|
+
}
|
339
|
+
|
340
|
+
setNodeDisabledValue(node: Element, disabled: boolean) {
|
341
|
+
if (disabled) {
|
342
|
+
node.setAttribute('aria-disabled', 'true')
|
343
|
+
} else {
|
344
|
+
node.removeAttribute('aria-disabled')
|
345
|
+
}
|
346
|
+
}
|
347
|
+
|
348
|
+
nodeHasCheckBox(node: Element): boolean {
|
349
|
+
return node.querySelector('.TreeViewItemCheckbox') !== null
|
350
|
+
}
|
351
|
+
|
352
|
+
nodeHasNativeAction(node: Element): boolean {
|
353
|
+
return node instanceof HTMLAnchorElement || node instanceof HTMLButtonElement
|
354
|
+
}
|
355
|
+
|
356
|
+
expandAncestorsForNode(node: HTMLElement) {
|
357
|
+
const subTreeNode = node.closest('tree-view-sub-tree-node') as TreeViewSubTreeNodeElement
|
358
|
+
if (!subTreeNode) return
|
359
|
+
|
360
|
+
for (const ancestor of subTreeNode.eachAncestorSubTreeNode()) {
|
361
|
+
if (!ancestor.expanded) {
|
362
|
+
ancestor.expand()
|
363
|
+
}
|
364
|
+
}
|
365
|
+
}
|
366
|
+
|
367
|
+
// PRIVATE API METHOD
|
368
|
+
//
|
369
|
+
// This would normally be marked private, but it's called by TreeViewSubTreeNodes
|
370
|
+
// and thus must be public.
|
371
|
+
infoFromNode(node: Element, newCheckedValue?: TreeViewCheckedValue): TreeViewNodeInfo | null {
|
372
|
+
const type = this.getNodeType(node)
|
373
|
+
if (!type) return null
|
374
|
+
|
375
|
+
const checkedValue = this.getNodeCheckedValue(node)
|
376
|
+
|
377
|
+
return {
|
378
|
+
node,
|
379
|
+
type,
|
380
|
+
path: this.getNodePath(node),
|
381
|
+
checkedValue: newCheckedValue || checkedValue,
|
382
|
+
previousCheckedValue: checkedValue,
|
383
|
+
}
|
384
|
+
}
|
385
|
+
}
|
386
|
+
|
387
|
+
if (!window.customElements.get('tree-view')) {
|
388
|
+
window.TreeViewElement = TreeViewElement
|
389
|
+
window.customElements.define('tree-view', TreeViewElement)
|
390
|
+
}
|
391
|
+
|
392
|
+
declare global {
|
393
|
+
interface Window {
|
394
|
+
TreeViewElement: typeof TreeViewElement
|
395
|
+
}
|
396
|
+
}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
export declare class TreeViewIconPairElement extends HTMLElement {
|
2
|
+
#private;
|
3
|
+
expandedIcon: HTMLElement;
|
4
|
+
collapsedIcon: HTMLElement;
|
5
|
+
expanded: boolean;
|
6
|
+
connectedCallback(): void;
|
7
|
+
showExpanded(): void;
|
8
|
+
showCollapsed(): void;
|
9
|
+
toggle(): void;
|
10
|
+
}
|
11
|
+
declare global {
|
12
|
+
interface Window {
|
13
|
+
TreeViewIconPairElement: typeof TreeViewIconPairElement;
|
14
|
+
}
|
15
|
+
}
|
@@ -0,0 +1,62 @@
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
6
|
+
};
|
7
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
8
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
9
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
10
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
11
|
+
};
|
12
|
+
var _TreeViewIconPairElement_instances, _TreeViewIconPairElement_update;
|
13
|
+
import { controller, target } from '@github/catalyst';
|
14
|
+
import { observeMutationsUntilConditionMet } from '../../utils';
|
15
|
+
let TreeViewIconPairElement = class TreeViewIconPairElement extends HTMLElement {
|
16
|
+
constructor() {
|
17
|
+
super(...arguments);
|
18
|
+
_TreeViewIconPairElement_instances.add(this);
|
19
|
+
}
|
20
|
+
connectedCallback() {
|
21
|
+
observeMutationsUntilConditionMet(this, () => Boolean(this.collapsedIcon) && Boolean(this.expandedIcon), () => {
|
22
|
+
this.expanded = this.collapsedIcon.hidden;
|
23
|
+
});
|
24
|
+
}
|
25
|
+
showExpanded() {
|
26
|
+
this.expanded = true;
|
27
|
+
__classPrivateFieldGet(this, _TreeViewIconPairElement_instances, "m", _TreeViewIconPairElement_update).call(this);
|
28
|
+
}
|
29
|
+
showCollapsed() {
|
30
|
+
this.expanded = false;
|
31
|
+
__classPrivateFieldGet(this, _TreeViewIconPairElement_instances, "m", _TreeViewIconPairElement_update).call(this);
|
32
|
+
}
|
33
|
+
toggle() {
|
34
|
+
this.expanded = !this.expanded;
|
35
|
+
__classPrivateFieldGet(this, _TreeViewIconPairElement_instances, "m", _TreeViewIconPairElement_update).call(this);
|
36
|
+
}
|
37
|
+
};
|
38
|
+
_TreeViewIconPairElement_instances = new WeakSet();
|
39
|
+
_TreeViewIconPairElement_update = function _TreeViewIconPairElement_update() {
|
40
|
+
if (this.expanded) {
|
41
|
+
this.expandedIcon.hidden = false;
|
42
|
+
this.collapsedIcon.hidden = true;
|
43
|
+
}
|
44
|
+
else {
|
45
|
+
this.expandedIcon.hidden = true;
|
46
|
+
this.collapsedIcon.hidden = false;
|
47
|
+
}
|
48
|
+
};
|
49
|
+
__decorate([
|
50
|
+
target
|
51
|
+
], TreeViewIconPairElement.prototype, "expandedIcon", void 0);
|
52
|
+
__decorate([
|
53
|
+
target
|
54
|
+
], TreeViewIconPairElement.prototype, "collapsedIcon", void 0);
|
55
|
+
TreeViewIconPairElement = __decorate([
|
56
|
+
controller
|
57
|
+
], TreeViewIconPairElement);
|
58
|
+
export { TreeViewIconPairElement };
|
59
|
+
if (!window.customElements.get('tree-view-icon-pair')) {
|
60
|
+
window.TreeViewIconPairElement = TreeViewIconPairElement;
|
61
|
+
window.customElements.define('tree-view-icon-pair', TreeViewIconPairElement);
|
62
|
+
}
|
@@ -0,0 +1,56 @@
|
|
1
|
+
import {controller, target} from '@github/catalyst'
|
2
|
+
import {observeMutationsUntilConditionMet} from '../../utils'
|
3
|
+
|
4
|
+
@controller
|
5
|
+
export class TreeViewIconPairElement extends HTMLElement {
|
6
|
+
@target expandedIcon: HTMLElement
|
7
|
+
@target collapsedIcon: HTMLElement
|
8
|
+
|
9
|
+
expanded: boolean
|
10
|
+
|
11
|
+
connectedCallback() {
|
12
|
+
observeMutationsUntilConditionMet(
|
13
|
+
this,
|
14
|
+
() => Boolean(this.collapsedIcon) && Boolean(this.expandedIcon),
|
15
|
+
() => {
|
16
|
+
this.expanded = this.collapsedIcon.hidden
|
17
|
+
},
|
18
|
+
)
|
19
|
+
}
|
20
|
+
|
21
|
+
showExpanded() {
|
22
|
+
this.expanded = true
|
23
|
+
this.#update()
|
24
|
+
}
|
25
|
+
|
26
|
+
showCollapsed() {
|
27
|
+
this.expanded = false
|
28
|
+
this.#update()
|
29
|
+
}
|
30
|
+
|
31
|
+
toggle() {
|
32
|
+
this.expanded = !this.expanded
|
33
|
+
this.#update()
|
34
|
+
}
|
35
|
+
|
36
|
+
#update() {
|
37
|
+
if (this.expanded) {
|
38
|
+
this.expandedIcon.hidden = false
|
39
|
+
this.collapsedIcon.hidden = true
|
40
|
+
} else {
|
41
|
+
this.expandedIcon.hidden = true
|
42
|
+
this.collapsedIcon.hidden = false
|
43
|
+
}
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|
47
|
+
if (!window.customElements.get('tree-view-icon-pair')) {
|
48
|
+
window.TreeViewIconPairElement = TreeViewIconPairElement
|
49
|
+
window.customElements.define('tree-view-icon-pair', TreeViewIconPairElement)
|
50
|
+
}
|
51
|
+
|
52
|
+
declare global {
|
53
|
+
interface Window {
|
54
|
+
TreeViewIconPairElement: typeof TreeViewIconPairElement
|
55
|
+
}
|
56
|
+
}
|
@@ -0,0 +1,9 @@
|
|
1
|
+
import { IncludeFragmentElement } from '@github/include-fragment-element';
|
2
|
+
export declare class TreeViewIncludeFragmentElement extends IncludeFragmentElement {
|
3
|
+
request(): Request;
|
4
|
+
}
|
5
|
+
declare global {
|
6
|
+
interface Window {
|
7
|
+
TreeViewIncludeFragmentElement: typeof TreeViewIncludeFragmentElement;
|
8
|
+
}
|
9
|
+
}
|
@@ -0,0 +1,28 @@
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
6
|
+
};
|
7
|
+
import { controller } from '@github/catalyst';
|
8
|
+
import { IncludeFragmentElement } from '@github/include-fragment-element';
|
9
|
+
let TreeViewIncludeFragmentElement = class TreeViewIncludeFragmentElement extends IncludeFragmentElement {
|
10
|
+
request() {
|
11
|
+
const originalRequest = super.request();
|
12
|
+
const url = new URL(originalRequest.url);
|
13
|
+
url.searchParams.set('path', this.getAttribute('data-path') || '');
|
14
|
+
return new Request(url, {
|
15
|
+
method: originalRequest.method,
|
16
|
+
headers: originalRequest.headers,
|
17
|
+
credentials: originalRequest.credentials,
|
18
|
+
});
|
19
|
+
}
|
20
|
+
};
|
21
|
+
TreeViewIncludeFragmentElement = __decorate([
|
22
|
+
controller
|
23
|
+
], TreeViewIncludeFragmentElement);
|
24
|
+
export { TreeViewIncludeFragmentElement };
|
25
|
+
if (!window.customElements.get('tree-view-include-fragment')) {
|
26
|
+
window.TreeViewIncludeFragmentElement = TreeViewIncludeFragmentElement;
|
27
|
+
window.customElements.define('tree-view-include-fragment', TreeViewIncludeFragmentElement);
|
28
|
+
}
|
@@ -0,0 +1,28 @@
|
|
1
|
+
import {controller} from '@github/catalyst'
|
2
|
+
import {IncludeFragmentElement} from '@github/include-fragment-element'
|
3
|
+
|
4
|
+
@controller
|
5
|
+
export class TreeViewIncludeFragmentElement extends IncludeFragmentElement {
|
6
|
+
request(): Request {
|
7
|
+
const originalRequest = super.request()
|
8
|
+
const url = new URL(originalRequest.url)
|
9
|
+
url.searchParams.set('path', this.getAttribute('data-path') || '')
|
10
|
+
|
11
|
+
return new Request(url, {
|
12
|
+
method: originalRequest.method,
|
13
|
+
headers: originalRequest.headers,
|
14
|
+
credentials: originalRequest.credentials,
|
15
|
+
})
|
16
|
+
}
|
17
|
+
}
|
18
|
+
|
19
|
+
if (!window.customElements.get('tree-view-include-fragment')) {
|
20
|
+
window.TreeViewIncludeFragmentElement = TreeViewIncludeFragmentElement
|
21
|
+
window.customElements.define('tree-view-include-fragment', TreeViewIncludeFragmentElement)
|
22
|
+
}
|
23
|
+
|
24
|
+
declare global {
|
25
|
+
interface Window {
|
26
|
+
TreeViewIncludeFragmentElement: typeof TreeViewIncludeFragmentElement
|
27
|
+
}
|
28
|
+
}
|