glass-easel 0.1.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.
- package/README.md +40 -0
- package/dist/glass_easel.all.d.ts +1 -0
- package/dist/glass_easel.all.js +2 -0
- package/dist/glass_easel.all.js.map +1 -0
- package/dist/glass_easel.domlike.global.d.ts +1 -0
- package/dist/glass_easel.domlike.global.js +2 -0
- package/dist/glass_easel.domlike.global.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/types/src/backend/backend_protocol.d.ts +119 -0
- package/dist/types/src/backend/backend_protocol.d.ts.map +1 -0
- package/dist/types/src/backend/composed_backend_protocol.d.ts +90 -0
- package/dist/types/src/backend/composed_backend_protocol.d.ts.map +1 -0
- package/dist/types/src/backend/domlike_backend_protocol.d.ts +76 -0
- package/dist/types/src/backend/domlike_backend_protocol.d.ts.map +1 -0
- package/dist/types/src/backend/mode.d.ts +46 -0
- package/dist/types/src/backend/mode.d.ts.map +1 -0
- package/dist/types/src/backend/suggested_backend_protocol.d.ts +30 -0
- package/dist/types/src/backend/suggested_backend_protocol.d.ts.map +1 -0
- package/dist/types/src/behavior.d.ts +428 -0
- package/dist/types/src/behavior.d.ts.map +1 -0
- package/dist/types/src/class_list.d.ts +79 -0
- package/dist/types/src/class_list.d.ts.map +1 -0
- package/dist/types/src/component.d.ts +291 -0
- package/dist/types/src/component.d.ts.map +1 -0
- package/dist/types/src/component_params.d.ts +239 -0
- package/dist/types/src/component_params.d.ts.map +1 -0
- package/dist/types/src/component_space.d.ts +164 -0
- package/dist/types/src/component_space.d.ts.map +1 -0
- package/dist/types/src/data_path.d.ts +5 -0
- package/dist/types/src/data_path.d.ts.map +1 -0
- package/dist/types/src/data_proxy.d.ts +107 -0
- package/dist/types/src/data_proxy.d.ts.map +1 -0
- package/dist/types/src/data_utils.d.ts +3 -0
- package/dist/types/src/data_utils.d.ts.map +1 -0
- package/dist/types/src/element.d.ts +275 -0
- package/dist/types/src/element.d.ts.map +1 -0
- package/dist/types/src/element_iterator.d.ts +43 -0
- package/dist/types/src/element_iterator.d.ts.map +1 -0
- package/dist/types/src/event.d.ts +104 -0
- package/dist/types/src/event.d.ts.map +1 -0
- package/dist/types/src/external_shadow_tree.d.ts +20 -0
- package/dist/types/src/external_shadow_tree.d.ts.map +1 -0
- package/dist/types/src/func_arr.d.ts +39 -0
- package/dist/types/src/func_arr.d.ts.map +1 -0
- package/dist/types/src/global_options.d.ts +111 -0
- package/dist/types/src/global_options.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +43 -0
- package/dist/types/src/index.d.ts.map +1 -0
- package/dist/types/src/mutation_observer.d.ts +79 -0
- package/dist/types/src/mutation_observer.d.ts.map +1 -0
- package/dist/types/src/native_node.d.ts +8 -0
- package/dist/types/src/native_node.d.ts.map +1 -0
- package/dist/types/src/node.d.ts +49 -0
- package/dist/types/src/node.d.ts.map +1 -0
- package/dist/types/src/relation.d.ts +47 -0
- package/dist/types/src/relation.d.ts.map +1 -0
- package/dist/types/src/render.d.ts +3 -0
- package/dist/types/src/render.d.ts.map +1 -0
- package/dist/types/src/selector.d.ts +32 -0
- package/dist/types/src/selector.d.ts.map +1 -0
- package/dist/types/src/shadow_root.d.ts +136 -0
- package/dist/types/src/shadow_root.d.ts.map +1 -0
- package/dist/types/src/template_engine.d.ts +18 -0
- package/dist/types/src/template_engine.d.ts.map +1 -0
- package/dist/types/src/text_node.d.ts +32 -0
- package/dist/types/src/text_node.d.ts.map +1 -0
- package/dist/types/src/tmpl/index.d.ts +18 -0
- package/dist/types/src/tmpl/index.d.ts.map +1 -0
- package/dist/types/src/tmpl/native_rendering.d.ts +45 -0
- package/dist/types/src/tmpl/native_rendering.d.ts.map +1 -0
- package/dist/types/src/tmpl/proc_gen_wrapper.d.ts +80 -0
- package/dist/types/src/tmpl/proc_gen_wrapper.d.ts.map +1 -0
- package/dist/types/src/tmpl/proc_gen_wrapper_dom.d.ts +50 -0
- package/dist/types/src/tmpl/proc_gen_wrapper_dom.d.ts.map +1 -0
- package/dist/types/src/tmpl/range_list_diff.d.ts +19 -0
- package/dist/types/src/tmpl/range_list_diff.d.ts.map +1 -0
- package/dist/types/src/trait_behaviors.d.ts +38 -0
- package/dist/types/src/trait_behaviors.d.ts.map +1 -0
- package/dist/types/src/virtual_node.d.ts +10 -0
- package/dist/types/src/virtual_node.d.ts.map +1 -0
- package/dist/types/tests/backend/domlike.test.d.ts +2 -0
- package/dist/types/tests/backend/domlike.test.d.ts.map +1 -0
- package/dist/types/tests/base/env.d.ts +29 -0
- package/dist/types/tests/base/env.d.ts.map +1 -0
- package/dist/types/tests/base/match.d.ts +9 -0
- package/dist/types/tests/base/match.d.ts.map +1 -0
- package/dist/types/tests/core/backend.test.d.ts +2 -0
- package/dist/types/tests/core/backend.test.d.ts.map +1 -0
- package/dist/types/tests/core/behavior.test.d.ts +2 -0
- package/dist/types/tests/core/behavior.test.d.ts.map +1 -0
- package/dist/types/tests/core/component_space.test.d.ts +2 -0
- package/dist/types/tests/core/component_space.test.d.ts.map +1 -0
- package/dist/types/tests/core/data_update.test.d.ts +2 -0
- package/dist/types/tests/core/data_update.test.d.ts.map +1 -0
- package/dist/types/tests/core/misc.test.d.ts +2 -0
- package/dist/types/tests/core/misc.test.d.ts.map +1 -0
- package/dist/types/tests/core/placeholder.test.d.ts +2 -0
- package/dist/types/tests/core/placeholder.test.d.ts.map +1 -0
- package/dist/types/tests/core/slot.test.d.ts +2 -0
- package/dist/types/tests/core/slot.test.d.ts.map +1 -0
- package/dist/types/tests/core/trait_behaviors.test.d.ts +2 -0
- package/dist/types/tests/core/trait_behaviors.test.d.ts.map +1 -0
- package/dist/types/tests/tmpl/binding_map.test.d.ts +2 -0
- package/dist/types/tests/tmpl/binding_map.test.d.ts.map +1 -0
- package/dist/types/tests/tmpl/event.test.d.ts +2 -0
- package/dist/types/tests/tmpl/event.test.d.ts.map +1 -0
- package/dist/types/tests/tmpl/expression.test.d.ts +2 -0
- package/dist/types/tests/tmpl/expression.test.d.ts.map +1 -0
- package/dist/types/tests/tmpl/lvalue.test.d.ts +2 -0
- package/dist/types/tests/tmpl/lvalue.test.d.ts.map +1 -0
- package/dist/types/tests/tmpl/native_rendering.test.d.ts +2 -0
- package/dist/types/tests/tmpl/native_rendering.test.d.ts.map +1 -0
- package/dist/types/tests/tmpl/structure.test.d.ts +2 -0
- package/dist/types/tests/tmpl/structure.test.d.ts.map +1 -0
- package/dist/types/tests/types/chaining.test.d.ts +2 -0
- package/dist/types/tests/types/chaining.test.d.ts.map +1 -0
- package/dist/types/tests/types/createElement.test.d.ts +2 -0
- package/dist/types/tests/types/createElement.test.d.ts.map +1 -0
- package/dist/types/tests/types/definition.test.d.ts +2 -0
- package/dist/types/tests/types/definition.test.d.ts.map +1 -0
- package/guide/zh_CN/advanced/binding_map_update.md +32 -0
- package/guide/zh_CN/advanced/build_args.md +28 -0
- package/guide/zh_CN/advanced/component_filter.md +70 -0
- package/guide/zh_CN/advanced/component_space.md +124 -0
- package/guide/zh_CN/advanced/custom_backend.md +53 -0
- package/guide/zh_CN/advanced/error_listener.md +32 -0
- package/guide/zh_CN/advanced/external_component.md +73 -0
- package/guide/zh_CN/advanced/template_engine.md +61 -0
- package/guide/zh_CN/appendix/backend_protocol.md +501 -0
- package/guide/zh_CN/appendix/list_diff_algorithm.md +406 -0
- package/guide/zh_CN/basic/beginning.md +94 -0
- package/guide/zh_CN/basic/component.md +156 -0
- package/guide/zh_CN/basic/event.md +169 -0
- package/guide/zh_CN/basic/lifetime.md +66 -0
- package/guide/zh_CN/basic/method.md +62 -0
- package/guide/zh_CN/basic/template.md +135 -0
- package/guide/zh_CN/data_management/advanced_update.md +170 -0
- package/guide/zh_CN/data_management/data_deep_copy.md +157 -0
- package/guide/zh_CN/data_management/data_observer.md +154 -0
- package/guide/zh_CN/data_management/property_early_init.md +31 -0
- package/guide/zh_CN/data_management/pure_data_pattern.md +21 -0
- package/guide/zh_CN/index.md +93 -0
- package/guide/zh_CN/interaction/behavior.md +52 -0
- package/guide/zh_CN/interaction/component_path.md +37 -0
- package/guide/zh_CN/interaction/generic.md +73 -0
- package/guide/zh_CN/interaction/placeholder.md +40 -0
- package/guide/zh_CN/interaction/relation.md +151 -0
- package/guide/zh_CN/interaction/slot.md +137 -0
- package/guide/zh_CN/interaction/template_import.md +94 -0
- package/guide/zh_CN/interaction/trait_behavior.md +117 -0
- package/guide/zh_CN/styling/external_class.md +46 -0
- package/guide/zh_CN/styling/style_isolation.md +54 -0
- package/guide/zh_CN/styling/virtual_host.md +52 -0
- package/guide/zh_CN/tree/element_iterator.md +54 -0
- package/guide/zh_CN/tree/mutation_observer.md +52 -0
- package/guide/zh_CN/tree/node_tree.md +142 -0
- package/guide/zh_CN/tree/node_tree_modification.md +78 -0
- package/guide/zh_CN/tree/selector.md +66 -0
- package/jest.config.js +6 -0
- package/jest.dts.config.js +9 -0
- package/jest.unit.config.js +14 -0
- package/package.json +28 -0
- package/src/backend/backend_protocol.ts +313 -0
- package/src/backend/composed_backend_protocol.ts +252 -0
- package/src/backend/domlike_backend_protocol.ts +370 -0
- package/src/backend/mode.ts +51 -0
- package/src/backend/suggested_backend_protocol.ts +83 -0
- package/src/behavior.ts +1655 -0
- package/src/bootstrap_dom_dev.js +22 -0
- package/src/class_list.ts +376 -0
- package/src/component.ts +1309 -0
- package/src/component_params.ts +461 -0
- package/src/component_space.ts +547 -0
- package/src/data_path.ts +225 -0
- package/src/data_proxy.ts +670 -0
- package/src/data_utils.ts +50 -0
- package/src/element.ts +1966 -0
- package/src/element_iterator.ts +158 -0
- package/src/event.ts +401 -0
- package/src/external_shadow_tree.ts +27 -0
- package/src/func_arr.ts +198 -0
- package/src/global_options.ts +242 -0
- package/src/index.ts +187 -0
- package/src/mutation_observer.ts +252 -0
- package/src/native_node.ts +74 -0
- package/src/node.ts +174 -0
- package/src/relation.ts +380 -0
- package/src/render.ts +25 -0
- package/src/selector.ts +218 -0
- package/src/shadow_root.ts +766 -0
- package/src/template_engine.ts +45 -0
- package/src/text_node.ts +149 -0
- package/src/tmpl/index.ts +199 -0
- package/src/tmpl/native_rendering.ts +175 -0
- package/src/tmpl/proc_gen_wrapper.ts +954 -0
- package/src/tmpl/proc_gen_wrapper_dom.ts +230 -0
- package/src/tmpl/range_list_diff.ts +443 -0
- package/src/trait_behaviors.ts +51 -0
- package/src/virtual_node.ts +51 -0
- package/tests/backend/domlike.test.ts +254 -0
- package/tests/base/env.ts +78 -0
- package/tests/base/match.ts +185 -0
- package/tests/core/backend.test.ts +144 -0
- package/tests/core/behavior.test.ts +546 -0
- package/tests/core/component_space.test.ts +212 -0
- package/tests/core/data_update.test.ts +461 -0
- package/tests/core/misc.test.ts +339 -0
- package/tests/core/placeholder.test.ts +180 -0
- package/tests/core/slot.test.ts +1495 -0
- package/tests/core/trait_behaviors.test.ts +153 -0
- package/tests/legacy/README.md +3 -0
- package/tests/legacy/behavior.test.js +293 -0
- package/tests/legacy/component.test.js +1247 -0
- package/tests/legacy/data_path.test.js +149 -0
- package/tests/legacy/data_proxy.test.js +759 -0
- package/tests/legacy/element_iterator.test.js +148 -0
- package/tests/legacy/event.test.js +849 -0
- package/tests/legacy/external.test.js +510 -0
- package/tests/legacy/extra_info.test.js +109 -0
- package/tests/legacy/generics.test.js +176 -0
- package/tests/legacy/mutation_observer.test.js +210 -0
- package/tests/legacy/relation.test.js +517 -0
- package/tests/legacy/selector.test.js +263 -0
- package/tests/legacy/slot.test.js +915 -0
- package/tests/legacy/virtual.test.js +394 -0
- package/tests/tmpl/binding_map.test.ts +208 -0
- package/tests/tmpl/event.test.ts +206 -0
- package/tests/tmpl/expression.test.ts +429 -0
- package/tests/tmpl/lvalue.test.ts +160 -0
- package/tests/tmpl/native_rendering.test.ts +155 -0
- package/tests/tmpl/structure.test.ts +998 -0
- package/tests/types/chaining.test.ts +614 -0
- package/tests/types/createElement.test.ts +82 -0
- package/tests/types/definition.test.ts +442 -0
- package/tsconfig.json +11 -0
- package/webpack.config.js +270 -0
|
@@ -0,0 +1,766 @@
|
|
|
1
|
+
import * as backend from './backend/backend_protocol'
|
|
2
|
+
import {
|
|
3
|
+
VirtualNode,
|
|
4
|
+
} from './virtual_node'
|
|
5
|
+
import {
|
|
6
|
+
Component,
|
|
7
|
+
GeneralComponentDefinition,
|
|
8
|
+
GeneralComponent,
|
|
9
|
+
convertGenerics,
|
|
10
|
+
resolvePlaceholder,
|
|
11
|
+
} from './component'
|
|
12
|
+
import {
|
|
13
|
+
TextNode,
|
|
14
|
+
} from './text_node'
|
|
15
|
+
import {
|
|
16
|
+
NativeNode,
|
|
17
|
+
} from './native_node'
|
|
18
|
+
import {
|
|
19
|
+
Element,
|
|
20
|
+
} from './element'
|
|
21
|
+
import {
|
|
22
|
+
Node,
|
|
23
|
+
} from './node'
|
|
24
|
+
import {
|
|
25
|
+
ComponentDefinitionWithPlaceholder,
|
|
26
|
+
} from './behavior'
|
|
27
|
+
import {
|
|
28
|
+
BM,
|
|
29
|
+
BackendMode,
|
|
30
|
+
} from './backend/mode'
|
|
31
|
+
import {
|
|
32
|
+
DeepCopyStrategy,
|
|
33
|
+
getDeepCopyStrategy,
|
|
34
|
+
} from './data_proxy'
|
|
35
|
+
import {
|
|
36
|
+
deepCopy,
|
|
37
|
+
simpleDeepCopy,
|
|
38
|
+
} from './data_utils'
|
|
39
|
+
|
|
40
|
+
const enum SlotMode {
|
|
41
|
+
Single,
|
|
42
|
+
Multiple,
|
|
43
|
+
Dynamic,
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
type AppliedSlotMeta = {
|
|
47
|
+
slotName: string,
|
|
48
|
+
updatePathTree: { [key: string]: true } | undefined,
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const wrapPlaceholderCallback = (
|
|
52
|
+
f: (c: GeneralComponentDefinition) => void,
|
|
53
|
+
cwp: ComponentDefinitionWithPlaceholder,
|
|
54
|
+
) => {
|
|
55
|
+
const waiting = cwp.waiting
|
|
56
|
+
if (waiting) {
|
|
57
|
+
waiting.add(f)
|
|
58
|
+
return () => {
|
|
59
|
+
waiting.remove(f)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return undefined
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export class ShadowRoot extends VirtualNode {
|
|
66
|
+
private _$host: GeneralComponent
|
|
67
|
+
/** @internal */
|
|
68
|
+
_$backendShadowRoot: backend.ShadowRootContext | null
|
|
69
|
+
private _$idMap: { [id: string]: Element } | null
|
|
70
|
+
private _$slotCacheDirty: boolean
|
|
71
|
+
private _$appliedSlotCacheDirty: boolean
|
|
72
|
+
private _$singleSlot?: Element | null
|
|
73
|
+
private _$appliedSingleSlot?: Element | null
|
|
74
|
+
private _$slots?: { [name: string]: Element }
|
|
75
|
+
private _$appliedSlots?: { [name: string]: Element }
|
|
76
|
+
private _$dynamicSlotSet?: Set<Element>
|
|
77
|
+
private _$appliedDynamicSlots?: Map<Element, AppliedSlotMeta>
|
|
78
|
+
private _$requiredSlotValueNames?: string[]
|
|
79
|
+
private _$propertyPassingDeepCopy?: DeepCopyStrategy
|
|
80
|
+
private _$insertDynamicSlotHandler?: (
|
|
81
|
+
slot: Element,
|
|
82
|
+
name: string,
|
|
83
|
+
slotValues: { [name: string]: unknown },
|
|
84
|
+
) => void
|
|
85
|
+
private _$removeDynamicSlotHandler?: (slot: Element) => void
|
|
86
|
+
private _$updateDynamicSlotHandler?: (
|
|
87
|
+
slot: Element,
|
|
88
|
+
slotValues: { [name: string]: unknown },
|
|
89
|
+
updatePathTree: { [name: string]: true },
|
|
90
|
+
) => void
|
|
91
|
+
|
|
92
|
+
constructor() {
|
|
93
|
+
throw new Error('Element cannot be constructed directly')
|
|
94
|
+
// eslint-disable-next-line no-unreachable
|
|
95
|
+
super()
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
static createShadowRoot(
|
|
99
|
+
host: GeneralComponent,
|
|
100
|
+
): ShadowRoot {
|
|
101
|
+
const node = Object.create(ShadowRoot.prototype) as ShadowRoot
|
|
102
|
+
node._$initializeVirtual('shadow', null, host._$nodeTreeContext)
|
|
103
|
+
node._$idMap = null
|
|
104
|
+
let slotMode = SlotMode.Single
|
|
105
|
+
if (host._$definition._$options.multipleSlots) slotMode = SlotMode.Multiple
|
|
106
|
+
else if (host._$definition._$options.dynamicSlots) slotMode = SlotMode.Dynamic
|
|
107
|
+
node._$slotCacheDirty = false
|
|
108
|
+
node._$appliedSlotCacheDirty = false
|
|
109
|
+
if (slotMode === SlotMode.Single) {
|
|
110
|
+
node._$singleSlot = null
|
|
111
|
+
node._$appliedSingleSlot = null
|
|
112
|
+
} else if (slotMode === SlotMode.Multiple) {
|
|
113
|
+
node._$slots = node._$appliedSlots = Object.create(null) as { [name: string]: Element }
|
|
114
|
+
} else if (slotMode === SlotMode.Dynamic) {
|
|
115
|
+
node._$dynamicSlotSet = new Set()
|
|
116
|
+
node._$appliedDynamicSlots = undefined
|
|
117
|
+
node._$requiredSlotValueNames = []
|
|
118
|
+
node._$propertyPassingDeepCopy = getDeepCopyStrategy(
|
|
119
|
+
host.getComponentOptions().propertyPassingDeepCopy,
|
|
120
|
+
)
|
|
121
|
+
node._$insertDynamicSlotHandler = undefined
|
|
122
|
+
node._$removeDynamicSlotHandler = undefined
|
|
123
|
+
node._$updateDynamicSlotHandler = undefined
|
|
124
|
+
}
|
|
125
|
+
const sr = BM.SHADOW || (BM.DYNAMIC && host.getBackendMode() === BackendMode.Shadow)
|
|
126
|
+
? (host.getBackendElement() as backend.Element | null)?.getShadowRoot() || null
|
|
127
|
+
: null
|
|
128
|
+
node._$backendShadowRoot = sr
|
|
129
|
+
const backendElement = node._$backendShadowRoot?.getRootNode() || null
|
|
130
|
+
node._$initialize(true, backendElement, node, host._$nodeTreeContext)
|
|
131
|
+
node._$host = host
|
|
132
|
+
host.shadowRoot = node
|
|
133
|
+
return node
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
getHostNode(): GeneralComponent {
|
|
137
|
+
return this._$host
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
createTextNode(text = ''): TextNode {
|
|
141
|
+
return new TextNode(text, this)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
createNativeNode(tagName: string): NativeNode {
|
|
145
|
+
return NativeNode.create(tagName, this)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
createVirtualNode(virtualName = 'virtual'): VirtualNode {
|
|
149
|
+
return VirtualNode.create(virtualName, this)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
createComponent(
|
|
153
|
+
tagName: string,
|
|
154
|
+
usingKey?: string,
|
|
155
|
+
genericTargets?: { [key: string]: string },
|
|
156
|
+
placeholderCallback?:
|
|
157
|
+
(c: GeneralComponentDefinition) => void,
|
|
158
|
+
initPropValues?: (comp: GeneralComponent) => void,
|
|
159
|
+
): GeneralComponent {
|
|
160
|
+
const host = this._$host
|
|
161
|
+
const beh = host._$behavior
|
|
162
|
+
const hostGenericImpls = host._$genericImpls
|
|
163
|
+
const space = beh.ownerSpace
|
|
164
|
+
const compName = usingKey === undefined ? tagName : usingKey
|
|
165
|
+
|
|
166
|
+
// if the target is in using list, then use the one in using list
|
|
167
|
+
const using = beh._$using[compName] || beh._$using[compName]
|
|
168
|
+
if (using) {
|
|
169
|
+
const usingTarget = using.final
|
|
170
|
+
|| (
|
|
171
|
+
using.placeholder !== null
|
|
172
|
+
&& resolvePlaceholder(using.placeholder, space, beh, hostGenericImpls)
|
|
173
|
+
)
|
|
174
|
+
const placeholderHandler = placeholderCallback
|
|
175
|
+
? wrapPlaceholderCallback(placeholderCallback, using)
|
|
176
|
+
: undefined
|
|
177
|
+
if (usingTarget) {
|
|
178
|
+
const comp = Component._$advancedCreate(
|
|
179
|
+
tagName,
|
|
180
|
+
usingTarget,
|
|
181
|
+
this,
|
|
182
|
+
null,
|
|
183
|
+
convertGenerics(usingTarget, space, host, genericTargets),
|
|
184
|
+
placeholderHandler,
|
|
185
|
+
initPropValues,
|
|
186
|
+
)
|
|
187
|
+
return comp
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// if the target is in generics list, then use the one
|
|
192
|
+
const g = hostGenericImpls && hostGenericImpls[compName]
|
|
193
|
+
if (g) {
|
|
194
|
+
const genImpl = g.final
|
|
195
|
+
|| (
|
|
196
|
+
g.placeholder !== null
|
|
197
|
+
&& resolvePlaceholder(g.placeholder, space, beh, hostGenericImpls)
|
|
198
|
+
)
|
|
199
|
+
const placeholderHandler = placeholderCallback
|
|
200
|
+
? wrapPlaceholderCallback(placeholderCallback, g)
|
|
201
|
+
: undefined
|
|
202
|
+
if (genImpl) {
|
|
203
|
+
return Component._$advancedCreate(
|
|
204
|
+
tagName,
|
|
205
|
+
genImpl,
|
|
206
|
+
this,
|
|
207
|
+
null,
|
|
208
|
+
convertGenerics(genImpl, space, host, genericTargets),
|
|
209
|
+
placeholderHandler,
|
|
210
|
+
initPropValues,
|
|
211
|
+
)
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// find in the space otherwise
|
|
216
|
+
const comp = space.getComponentByUrl(compName, '')
|
|
217
|
+
if (!comp) {
|
|
218
|
+
throw new Error(`Cannot find component "${compName}"`)
|
|
219
|
+
}
|
|
220
|
+
return Component._$advancedCreate(
|
|
221
|
+
tagName,
|
|
222
|
+
comp,
|
|
223
|
+
this,
|
|
224
|
+
null,
|
|
225
|
+
convertGenerics(comp, space, host, genericTargets),
|
|
226
|
+
undefined,
|
|
227
|
+
initPropValues,
|
|
228
|
+
)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Create a component if the given tag name is a component in the space, or a native node if not
|
|
233
|
+
*
|
|
234
|
+
* The component `using` map is not used.
|
|
235
|
+
* The tag name is not a relative path to the host component, but an absolute path.
|
|
236
|
+
*/
|
|
237
|
+
createComponentOrNativeNode(
|
|
238
|
+
tagName: string,
|
|
239
|
+
genericTargets?: { [key: string]: string },
|
|
240
|
+
initPropValues?: (comp: GeneralComponent | NativeNode) => void,
|
|
241
|
+
): GeneralComponent | NativeNode {
|
|
242
|
+
const host = this._$host
|
|
243
|
+
const beh = host._$behavior
|
|
244
|
+
const space = beh.ownerSpace
|
|
245
|
+
|
|
246
|
+
// find in the space otherwise
|
|
247
|
+
const comp = space.getComponentByUrlWithoutDefault(tagName, '')
|
|
248
|
+
if (comp) {
|
|
249
|
+
return Component._$advancedCreate(
|
|
250
|
+
tagName,
|
|
251
|
+
comp,
|
|
252
|
+
this,
|
|
253
|
+
null,
|
|
254
|
+
convertGenerics(comp, space, host, genericTargets),
|
|
255
|
+
undefined,
|
|
256
|
+
initPropValues,
|
|
257
|
+
)
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// use native node otherwise
|
|
261
|
+
const node = NativeNode.create(tagName, this)
|
|
262
|
+
initPropValues?.(node)
|
|
263
|
+
return node
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Find whether this component is placeholding or not
|
|
268
|
+
*
|
|
269
|
+
* This method will only find in the component `using` list and `generics` list.
|
|
270
|
+
* If not found, returns `undefined` .
|
|
271
|
+
* If the placeholder will be used, returns `true` ; `false` otherwise.
|
|
272
|
+
*/
|
|
273
|
+
checkComponentPlaceholder(usingKey: string): boolean | undefined {
|
|
274
|
+
const beh = this._$host._$behavior
|
|
275
|
+
let compDef: ComponentDefinitionWithPlaceholder
|
|
276
|
+
const using = beh._$using[usingKey]
|
|
277
|
+
if (using !== undefined) {
|
|
278
|
+
compDef = using
|
|
279
|
+
} else {
|
|
280
|
+
const g = this._$host._$genericImpls?.[usingKey]
|
|
281
|
+
if (g) compDef = g
|
|
282
|
+
else return undefined
|
|
283
|
+
}
|
|
284
|
+
if (compDef.final) return false
|
|
285
|
+
if (compDef.placeholder !== null) return true
|
|
286
|
+
return false
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
getElementById(id: string): Element | undefined {
|
|
290
|
+
return this._$getIdMap()[id]
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/** @internal */
|
|
294
|
+
_$markIdCacheDirty() {
|
|
295
|
+
this._$idMap = null
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/** @internal */
|
|
299
|
+
_$getIdMap(): { [id: string]: Element } {
|
|
300
|
+
if (this._$idMap) return this._$idMap
|
|
301
|
+
const idMap = Element._$generateIdMap(this)
|
|
302
|
+
this._$idMap = idMap
|
|
303
|
+
return idMap
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/** Get the slot element if the component is in single-slot mode, or `undefined` if not */
|
|
307
|
+
getSingleSlotElement(): Element | null | undefined {
|
|
308
|
+
return this._$singleSlot
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/** Get the slot element with the specified name */
|
|
312
|
+
getSlotElementFromName(name: string): Element | Element[] | null {
|
|
313
|
+
if (this._$singleSlot !== undefined) return this._$singleSlot
|
|
314
|
+
if (this._$slots) {
|
|
315
|
+
return this._$slots[name] || null
|
|
316
|
+
}
|
|
317
|
+
if (this._$dynamicSlotSet) {
|
|
318
|
+
const slots: Element[] = []
|
|
319
|
+
const iterator = this._$dynamicSlotSet.values()
|
|
320
|
+
for (let it = iterator.next(); !it.done; it = iterator.next()) {
|
|
321
|
+
const slot = it.value
|
|
322
|
+
const slotName = slot._$slotName || ''
|
|
323
|
+
if (slotName === name) slots.push(slot)
|
|
324
|
+
}
|
|
325
|
+
return slots
|
|
326
|
+
}
|
|
327
|
+
return null
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Get the slot element for the slot content
|
|
332
|
+
*
|
|
333
|
+
* The provided node must be a valid child node of the host of this shadow root.
|
|
334
|
+
* Otherwise the behavior is undefined.
|
|
335
|
+
*/
|
|
336
|
+
getContainingSlot(elem: Node | null): Element | null {
|
|
337
|
+
if (this._$singleSlot !== undefined) return this._$singleSlot
|
|
338
|
+
if (this._$dynamicSlotSet) {
|
|
339
|
+
if (!elem) return null
|
|
340
|
+
let subTreeRoot = elem
|
|
341
|
+
while (subTreeRoot.parentNode?._$inheritSlots) {
|
|
342
|
+
subTreeRoot = subTreeRoot.parentNode
|
|
343
|
+
}
|
|
344
|
+
const slotElement = subTreeRoot._$nodeSlotElement
|
|
345
|
+
if (slotElement?.ownerShadowRoot === this) {
|
|
346
|
+
return slotElement
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
if (this._$slots) {
|
|
350
|
+
let name: string
|
|
351
|
+
if (elem instanceof Element) {
|
|
352
|
+
name = elem._$nodeSlot
|
|
353
|
+
} else {
|
|
354
|
+
name = ''
|
|
355
|
+
}
|
|
356
|
+
return this._$slots[name] || null
|
|
357
|
+
}
|
|
358
|
+
return null
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Get the elements that should be composed in specified slot
|
|
363
|
+
*
|
|
364
|
+
* This method always returns a new array (or null if the specified slot is invalid).
|
|
365
|
+
* It is convinient but less performant.
|
|
366
|
+
* For better performance, consider using `forEachNodeInSpecifiedSlot` .
|
|
367
|
+
*/
|
|
368
|
+
getSlotContentArray(slot: Element): Node[] | null {
|
|
369
|
+
if (slot._$slotName === null) return null
|
|
370
|
+
const ret: Node[] = []
|
|
371
|
+
this.forEachNodeInSpecifiedSlot(slot, (node) => {
|
|
372
|
+
ret.push(node)
|
|
373
|
+
})
|
|
374
|
+
return ret
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Iterate slots
|
|
379
|
+
*/
|
|
380
|
+
forEachSlot(f: (slot: Element) => boolean | void) {
|
|
381
|
+
if (this._$singleSlot) {
|
|
382
|
+
f(this._$singleSlot)
|
|
383
|
+
} else if (this._$slots) {
|
|
384
|
+
const slots = Object.values(this._$slots)
|
|
385
|
+
for (let i = 0; i < slots.length; i += 1) {
|
|
386
|
+
if (f(slots[i]!) === false) break
|
|
387
|
+
}
|
|
388
|
+
} else if (this._$dynamicSlotSet) {
|
|
389
|
+
const iterator = this._$dynamicSlotSet.values()
|
|
390
|
+
for (let next = iterator.next(); !next.done; next = iterator.next()) {
|
|
391
|
+
if (f(next.value) === false) break
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Iterate elements with their slots
|
|
398
|
+
*/
|
|
399
|
+
forEachNodeInSlot(f: (node: Node, slot: Element | undefined) => boolean | void) {
|
|
400
|
+
if (this._$singleSlot) {
|
|
401
|
+
const slot = this._$singleSlot
|
|
402
|
+
const rec = (child: Node): boolean => {
|
|
403
|
+
if (f(child, slot) === false) {
|
|
404
|
+
return false
|
|
405
|
+
}
|
|
406
|
+
if (child instanceof Element) {
|
|
407
|
+
if (child._$inheritSlots) {
|
|
408
|
+
if (child.childNodes.every(rec) === false) {
|
|
409
|
+
return false
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
return true
|
|
414
|
+
}
|
|
415
|
+
this._$host.childNodes.every(rec)
|
|
416
|
+
} else if (this._$dynamicSlotSet) {
|
|
417
|
+
const rec = (child: Node) => {
|
|
418
|
+
if (f(child, this.getContainingSlot(child) || undefined) === false) {
|
|
419
|
+
return false
|
|
420
|
+
}
|
|
421
|
+
if (child instanceof Element && child._$inheritSlots) {
|
|
422
|
+
if (child.childNodes.every((child) => rec(child)) === false) {
|
|
423
|
+
return false
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
return true
|
|
427
|
+
}
|
|
428
|
+
this._$host.childNodes.every(rec)
|
|
429
|
+
} else if (this._$slots) {
|
|
430
|
+
const slots = this._$slots
|
|
431
|
+
const rec = (child: Node) => {
|
|
432
|
+
if (child instanceof Element) {
|
|
433
|
+
if (f(child, slots[child._$nodeSlot]) === false) {
|
|
434
|
+
return false
|
|
435
|
+
}
|
|
436
|
+
if (child._$inheritSlots) {
|
|
437
|
+
if (child.childNodes.every(rec) === false) {
|
|
438
|
+
return false
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
} else {
|
|
442
|
+
if (f(child, slots['']) === false) {
|
|
443
|
+
return false
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
return true
|
|
447
|
+
}
|
|
448
|
+
this._$host.childNodes.every(rec)
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Iterate elements in specified slot
|
|
454
|
+
*/
|
|
455
|
+
forEachNodeInSpecifiedSlot(slot: Element | string, f: (node: Node, posIndex: number) => void) {
|
|
456
|
+
if (this._$singleSlot) {
|
|
457
|
+
if (slot !== '' && this._$singleSlot !== slot) return
|
|
458
|
+
const rec = (child: Node, index: number) => {
|
|
459
|
+
f(child, index)
|
|
460
|
+
if (child instanceof Element) {
|
|
461
|
+
if (child._$inheritSlots) {
|
|
462
|
+
child.childNodes.forEach(rec)
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
this._$host.childNodes.forEach(rec)
|
|
467
|
+
} else if (this._$dynamicSlotSet) {
|
|
468
|
+
if (typeof slot === 'string') return
|
|
469
|
+
const recInheritedSlot = (child: Node, index: number) => {
|
|
470
|
+
f(child, index)
|
|
471
|
+
if (child instanceof Element && child._$inheritSlots) {
|
|
472
|
+
child.childNodes.forEach(recInheritedSlot)
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
const rec = (child: Node, index: number) => {
|
|
476
|
+
if (this.getContainingSlot(child) !== slot) return
|
|
477
|
+
f(child, index)
|
|
478
|
+
if (child instanceof Element && child._$inheritSlots) {
|
|
479
|
+
child.childNodes.forEach(recInheritedSlot)
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
this._$host.childNodes.forEach(rec)
|
|
483
|
+
} else if (this._$slots) {
|
|
484
|
+
if (typeof slot !== 'string' && this._$slots[slot._$slotName!] !== slot) return
|
|
485
|
+
const name = typeof slot === 'string' ? slot : slot._$slotName
|
|
486
|
+
const rec = (child: Node, index: number) => {
|
|
487
|
+
if (child instanceof Element) {
|
|
488
|
+
if (child._$nodeSlot === name) f(child, index)
|
|
489
|
+
if (child._$inheritSlots) {
|
|
490
|
+
child.childNodes.forEach(rec)
|
|
491
|
+
}
|
|
492
|
+
} else if (name === '') {
|
|
493
|
+
f(child, index)
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
this._$host.childNodes.forEach(rec)
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/** @internal */
|
|
501
|
+
_$markSlotCacheDirty() {
|
|
502
|
+
this._$slotCacheDirty = true
|
|
503
|
+
this._$appliedSlotCacheDirty = true
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/** @internal */
|
|
507
|
+
_$checkSlotChanges(): void {
|
|
508
|
+
if (!this._$appliedSlotCacheDirty) return
|
|
509
|
+
this._$appliedSlotCacheDirty = false
|
|
510
|
+
if (this._$slotCacheDirty) this._$updateSlotCache()
|
|
511
|
+
if (BM.SHADOW || (BM.DYNAMIC && this.getBackendMode() === BackendMode.Shadow)) return
|
|
512
|
+
|
|
513
|
+
// for dynamic slotting, invoke slot handlers
|
|
514
|
+
if (this._$dynamicSlotSet) {
|
|
515
|
+
const appliedDynamicSlots = this._$appliedDynamicSlots
|
|
516
|
+
if (!appliedDynamicSlots) return
|
|
517
|
+
const dynamicSlotSet = this._$dynamicSlotSet
|
|
518
|
+
const insertDynamicSlot = this._$insertDynamicSlotHandler
|
|
519
|
+
const removeDynamicSlot = this._$removeDynamicSlotHandler
|
|
520
|
+
const removeIter = appliedDynamicSlots.keys()
|
|
521
|
+
for (let it = removeIter.next(); !it.done; it = removeIter.next()) {
|
|
522
|
+
const slot = it.value
|
|
523
|
+
if (!dynamicSlotSet.has(slot)) {
|
|
524
|
+
removeDynamicSlot?.(slot)
|
|
525
|
+
appliedDynamicSlots.delete(slot)
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
const iter = dynamicSlotSet.values()
|
|
529
|
+
for (let it = iter.next(); !it.done; it = iter.next()) {
|
|
530
|
+
const slot = it.value
|
|
531
|
+
const slotName = slot._$slotName || ''
|
|
532
|
+
const appliedSlot = appliedDynamicSlots.get(slot)
|
|
533
|
+
if (appliedSlot !== undefined) {
|
|
534
|
+
if (appliedSlot.slotName !== slotName) {
|
|
535
|
+
removeDynamicSlot?.(slot)
|
|
536
|
+
insertDynamicSlot?.(slot, slotName, slot._$slotValues!)
|
|
537
|
+
appliedDynamicSlots.set(slot, { slotName, updatePathTree: undefined })
|
|
538
|
+
}
|
|
539
|
+
} else {
|
|
540
|
+
insertDynamicSlot?.(slot, slotName, slot._$slotValues!)
|
|
541
|
+
appliedDynamicSlots.set(slot, { slotName, updatePathTree: undefined })
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
return
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
// in single slot mode, simply check changes
|
|
548
|
+
if (this._$singleSlot !== undefined) {
|
|
549
|
+
const oldSingleSlot = this._$appliedSingleSlot
|
|
550
|
+
if (oldSingleSlot !== this._$singleSlot) {
|
|
551
|
+
this._$appliedSingleSlot = this._$singleSlot
|
|
552
|
+
Element._$insertChildReassignSlot(this, '', oldSingleSlot!, this._$singleSlot)
|
|
553
|
+
}
|
|
554
|
+
return
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
// for multiple slots, compare and find slot changes
|
|
558
|
+
const oldSlots = this._$appliedSlots!
|
|
559
|
+
const newSlots = this._$slots!
|
|
560
|
+
this._$appliedSlots = newSlots
|
|
561
|
+
const oldKeys = Object.keys(oldSlots)
|
|
562
|
+
for (let i = 0; i < oldKeys.length; i += 1) {
|
|
563
|
+
const key = oldKeys[i]!
|
|
564
|
+
const oldSlot = oldSlots[key]!
|
|
565
|
+
const newSlot = newSlots[key]
|
|
566
|
+
if (oldSlot !== newSlot) {
|
|
567
|
+
Element._$insertChildReassignSlot(this, key, oldSlot, newSlot || null)
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
const newKeys = Object.keys(newSlots)
|
|
571
|
+
for (let i = 0; i < newKeys.length; i += 1) {
|
|
572
|
+
const key = newKeys[i]!
|
|
573
|
+
const oldSlot = oldSlots[key]
|
|
574
|
+
const newSlot = newSlots[key]!
|
|
575
|
+
if (oldSlot === undefined) {
|
|
576
|
+
Element._$insertChildReassignSlot(this, key, null, newSlot || null)
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
private _$updateSlotCache() {
|
|
582
|
+
this._$slotCacheDirty = false
|
|
583
|
+
|
|
584
|
+
// in single slot mode, find the slot
|
|
585
|
+
if (this._$singleSlot !== undefined) {
|
|
586
|
+
let slot: Element | undefined
|
|
587
|
+
const rec = (child: Node): boolean => {
|
|
588
|
+
if (child instanceof Element) {
|
|
589
|
+
if (child._$slotName !== null) {
|
|
590
|
+
slot = child
|
|
591
|
+
return false
|
|
592
|
+
}
|
|
593
|
+
if (child.childNodes.every(rec) === false) {
|
|
594
|
+
return false
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
return true
|
|
598
|
+
}
|
|
599
|
+
this.childNodes.every(rec)
|
|
600
|
+
this._$singleSlot = slot || null
|
|
601
|
+
return
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// for dynamic slotting, collect the slots
|
|
605
|
+
if (this._$dynamicSlotSet) {
|
|
606
|
+
const dynamicSlotSet = new Set<Element>()
|
|
607
|
+
const rec = (child: Node): void => {
|
|
608
|
+
if (child instanceof Element) {
|
|
609
|
+
if (child._$slotName !== null) {
|
|
610
|
+
dynamicSlotSet.add(child)
|
|
611
|
+
}
|
|
612
|
+
child.childNodes.forEach(rec)
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
this.childNodes.forEach(rec)
|
|
616
|
+
this._$dynamicSlotSet = dynamicSlotSet
|
|
617
|
+
return
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
// for multiple slots, collect the slots
|
|
621
|
+
const slots = Object.create(null) as { [name: string]: Element }
|
|
622
|
+
const rec = (child: Node): void => {
|
|
623
|
+
if (child instanceof Element) {
|
|
624
|
+
if (child._$slotName !== null) {
|
|
625
|
+
if (!slots[child._$slotName]) {
|
|
626
|
+
slots[child._$slotName] = child
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
child.childNodes.forEach(rec)
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
this.childNodes.forEach(rec)
|
|
633
|
+
this._$slots = slots
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
/**
|
|
637
|
+
* Returns `true` if the component is in multiple-slot mode
|
|
638
|
+
*/
|
|
639
|
+
isMultipleSlots(): boolean {
|
|
640
|
+
return this._$slots !== undefined
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
/**
|
|
644
|
+
* Returns `true` if the component is in dynamic-slot mode
|
|
645
|
+
*/
|
|
646
|
+
isDynamicSlots(): boolean {
|
|
647
|
+
return this._$dynamicSlotSet !== undefined
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
/**
|
|
651
|
+
* Set the dynamic slot handlers
|
|
652
|
+
*
|
|
653
|
+
* The updated value should be applied with `applySlotUpdates` call.
|
|
654
|
+
* If the handlers have not been set yet,
|
|
655
|
+
* the `insertSlotHandler` will be called for each slot that has been added to the shadow tree.
|
|
656
|
+
*/
|
|
657
|
+
setDynamicSlotHandler(
|
|
658
|
+
requiredSlotValueNames: string[],
|
|
659
|
+
insertSlotHandler: (
|
|
660
|
+
slot: Element,
|
|
661
|
+
name: string,
|
|
662
|
+
slotValues: { [name: string]: unknown },
|
|
663
|
+
) => void,
|
|
664
|
+
removeSlotHandler: (slot: Element) => void,
|
|
665
|
+
updateSlotHandler: (
|
|
666
|
+
slot: Element,
|
|
667
|
+
slotValues: { [name: string]: unknown },
|
|
668
|
+
updatePathTree: { [name: string]: true },
|
|
669
|
+
) => void,
|
|
670
|
+
) {
|
|
671
|
+
this._$requiredSlotValueNames = requiredSlotValueNames
|
|
672
|
+
this._$insertDynamicSlotHandler = insertSlotHandler
|
|
673
|
+
this._$removeDynamicSlotHandler = removeSlotHandler
|
|
674
|
+
this._$updateDynamicSlotHandler = updateSlotHandler
|
|
675
|
+
if (this._$appliedDynamicSlots) {
|
|
676
|
+
const iter = this._$appliedDynamicSlots.values()
|
|
677
|
+
for (let it = iter.next(); !it.done; it = iter.next()) {
|
|
678
|
+
const slotMeta = it.value
|
|
679
|
+
if (!slotMeta.updatePathTree) {
|
|
680
|
+
slotMeta.updatePathTree = Object.create(null) as { [key: string]: true }
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
/**
|
|
687
|
+
* Use the same dynamic slot handlers with the `source`
|
|
688
|
+
*/
|
|
689
|
+
useDynamicSlotHandlerFrom(source: ShadowRoot) {
|
|
690
|
+
if (source._$insertDynamicSlotHandler) {
|
|
691
|
+
this.setDynamicSlotHandler(
|
|
692
|
+
source._$requiredSlotValueNames!.slice(),
|
|
693
|
+
source._$insertDynamicSlotHandler,
|
|
694
|
+
source._$removeDynamicSlotHandler!,
|
|
695
|
+
source._$updateDynamicSlotHandler!,
|
|
696
|
+
)
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
/**
|
|
701
|
+
* Update a slot value
|
|
702
|
+
*
|
|
703
|
+
* The updated value should be applied with `applySlotValueUpdates` call.
|
|
704
|
+
*/
|
|
705
|
+
replaceSlotValue(slot: Element, name: string, value: unknown): void {
|
|
706
|
+
const slotValues = slot._$slotValues
|
|
707
|
+
if (slotValues) {
|
|
708
|
+
const oldValue = slotValues[name]
|
|
709
|
+
let newValue = value
|
|
710
|
+
if (this._$propertyPassingDeepCopy !== DeepCopyStrategy.None) {
|
|
711
|
+
if (this._$propertyPassingDeepCopy === DeepCopyStrategy.SimpleWithRecursion) {
|
|
712
|
+
newValue = deepCopy(value, true)
|
|
713
|
+
} else {
|
|
714
|
+
newValue = simpleDeepCopy(value)
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
if (oldValue !== newValue) {
|
|
718
|
+
slotValues[name] = newValue
|
|
719
|
+
if (this._$requiredSlotValueNames!.indexOf(name) >= 0) {
|
|
720
|
+
const slotMeta = this._$appliedDynamicSlots?.get(slot)
|
|
721
|
+
if (slotMeta) {
|
|
722
|
+
if (!slotMeta.updatePathTree) {
|
|
723
|
+
slotMeta.updatePathTree = Object.create(null) as { [key: string]: true }
|
|
724
|
+
}
|
|
725
|
+
slotMeta.updatePathTree[name] = true
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
/**
|
|
733
|
+
* Apply slot value updates
|
|
734
|
+
*/
|
|
735
|
+
applySlotValueUpdates(slot: Element) {
|
|
736
|
+
const slotMeta = this._$appliedDynamicSlots?.get(slot)
|
|
737
|
+
const slotValueUpdatePathTree = slotMeta?.updatePathTree
|
|
738
|
+
if (slotValueUpdatePathTree) {
|
|
739
|
+
slotMeta.updatePathTree = undefined
|
|
740
|
+
this._$updateDynamicSlotHandler?.(slot, slot._$slotValues!, slotValueUpdatePathTree)
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
/**
|
|
745
|
+
* Apply all pending slot updates
|
|
746
|
+
*/
|
|
747
|
+
applySlotUpdates(): void {
|
|
748
|
+
if (this._$appliedDynamicSlots) {
|
|
749
|
+
// if slots has been initialized, mark all of them dirty
|
|
750
|
+
const iter = this._$appliedDynamicSlots.entries()
|
|
751
|
+
for (let it = iter.next(); !it.done; it = iter.next()) {
|
|
752
|
+
const [slot, slotMeta] = it.value
|
|
753
|
+
const slotValueUpdatePathTree = slotMeta?.updatePathTree
|
|
754
|
+
if (slotValueUpdatePathTree) {
|
|
755
|
+
slotMeta.updatePathTree = undefined
|
|
756
|
+
this._$updateDynamicSlotHandler?.(slot, slot._$slotValues!, slotValueUpdatePathTree)
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
} else {
|
|
760
|
+
// if slots is not initialized, try initialize them
|
|
761
|
+
this._$appliedDynamicSlots = new Map()
|
|
762
|
+
this._$appliedSlotCacheDirty = true
|
|
763
|
+
this._$checkSlotChanges()
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
}
|