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.
Files changed (237) hide show
  1. package/README.md +40 -0
  2. package/dist/glass_easel.all.d.ts +1 -0
  3. package/dist/glass_easel.all.js +2 -0
  4. package/dist/glass_easel.all.js.map +1 -0
  5. package/dist/glass_easel.domlike.global.d.ts +1 -0
  6. package/dist/glass_easel.domlike.global.js +2 -0
  7. package/dist/glass_easel.domlike.global.js.map +1 -0
  8. package/dist/index.d.ts +1 -0
  9. package/dist/index.js +1 -0
  10. package/dist/types/src/backend/backend_protocol.d.ts +119 -0
  11. package/dist/types/src/backend/backend_protocol.d.ts.map +1 -0
  12. package/dist/types/src/backend/composed_backend_protocol.d.ts +90 -0
  13. package/dist/types/src/backend/composed_backend_protocol.d.ts.map +1 -0
  14. package/dist/types/src/backend/domlike_backend_protocol.d.ts +76 -0
  15. package/dist/types/src/backend/domlike_backend_protocol.d.ts.map +1 -0
  16. package/dist/types/src/backend/mode.d.ts +46 -0
  17. package/dist/types/src/backend/mode.d.ts.map +1 -0
  18. package/dist/types/src/backend/suggested_backend_protocol.d.ts +30 -0
  19. package/dist/types/src/backend/suggested_backend_protocol.d.ts.map +1 -0
  20. package/dist/types/src/behavior.d.ts +428 -0
  21. package/dist/types/src/behavior.d.ts.map +1 -0
  22. package/dist/types/src/class_list.d.ts +79 -0
  23. package/dist/types/src/class_list.d.ts.map +1 -0
  24. package/dist/types/src/component.d.ts +291 -0
  25. package/dist/types/src/component.d.ts.map +1 -0
  26. package/dist/types/src/component_params.d.ts +239 -0
  27. package/dist/types/src/component_params.d.ts.map +1 -0
  28. package/dist/types/src/component_space.d.ts +164 -0
  29. package/dist/types/src/component_space.d.ts.map +1 -0
  30. package/dist/types/src/data_path.d.ts +5 -0
  31. package/dist/types/src/data_path.d.ts.map +1 -0
  32. package/dist/types/src/data_proxy.d.ts +107 -0
  33. package/dist/types/src/data_proxy.d.ts.map +1 -0
  34. package/dist/types/src/data_utils.d.ts +3 -0
  35. package/dist/types/src/data_utils.d.ts.map +1 -0
  36. package/dist/types/src/element.d.ts +275 -0
  37. package/dist/types/src/element.d.ts.map +1 -0
  38. package/dist/types/src/element_iterator.d.ts +43 -0
  39. package/dist/types/src/element_iterator.d.ts.map +1 -0
  40. package/dist/types/src/event.d.ts +104 -0
  41. package/dist/types/src/event.d.ts.map +1 -0
  42. package/dist/types/src/external_shadow_tree.d.ts +20 -0
  43. package/dist/types/src/external_shadow_tree.d.ts.map +1 -0
  44. package/dist/types/src/func_arr.d.ts +39 -0
  45. package/dist/types/src/func_arr.d.ts.map +1 -0
  46. package/dist/types/src/global_options.d.ts +111 -0
  47. package/dist/types/src/global_options.d.ts.map +1 -0
  48. package/dist/types/src/index.d.ts +43 -0
  49. package/dist/types/src/index.d.ts.map +1 -0
  50. package/dist/types/src/mutation_observer.d.ts +79 -0
  51. package/dist/types/src/mutation_observer.d.ts.map +1 -0
  52. package/dist/types/src/native_node.d.ts +8 -0
  53. package/dist/types/src/native_node.d.ts.map +1 -0
  54. package/dist/types/src/node.d.ts +49 -0
  55. package/dist/types/src/node.d.ts.map +1 -0
  56. package/dist/types/src/relation.d.ts +47 -0
  57. package/dist/types/src/relation.d.ts.map +1 -0
  58. package/dist/types/src/render.d.ts +3 -0
  59. package/dist/types/src/render.d.ts.map +1 -0
  60. package/dist/types/src/selector.d.ts +32 -0
  61. package/dist/types/src/selector.d.ts.map +1 -0
  62. package/dist/types/src/shadow_root.d.ts +136 -0
  63. package/dist/types/src/shadow_root.d.ts.map +1 -0
  64. package/dist/types/src/template_engine.d.ts +18 -0
  65. package/dist/types/src/template_engine.d.ts.map +1 -0
  66. package/dist/types/src/text_node.d.ts +32 -0
  67. package/dist/types/src/text_node.d.ts.map +1 -0
  68. package/dist/types/src/tmpl/index.d.ts +18 -0
  69. package/dist/types/src/tmpl/index.d.ts.map +1 -0
  70. package/dist/types/src/tmpl/native_rendering.d.ts +45 -0
  71. package/dist/types/src/tmpl/native_rendering.d.ts.map +1 -0
  72. package/dist/types/src/tmpl/proc_gen_wrapper.d.ts +80 -0
  73. package/dist/types/src/tmpl/proc_gen_wrapper.d.ts.map +1 -0
  74. package/dist/types/src/tmpl/proc_gen_wrapper_dom.d.ts +50 -0
  75. package/dist/types/src/tmpl/proc_gen_wrapper_dom.d.ts.map +1 -0
  76. package/dist/types/src/tmpl/range_list_diff.d.ts +19 -0
  77. package/dist/types/src/tmpl/range_list_diff.d.ts.map +1 -0
  78. package/dist/types/src/trait_behaviors.d.ts +38 -0
  79. package/dist/types/src/trait_behaviors.d.ts.map +1 -0
  80. package/dist/types/src/virtual_node.d.ts +10 -0
  81. package/dist/types/src/virtual_node.d.ts.map +1 -0
  82. package/dist/types/tests/backend/domlike.test.d.ts +2 -0
  83. package/dist/types/tests/backend/domlike.test.d.ts.map +1 -0
  84. package/dist/types/tests/base/env.d.ts +29 -0
  85. package/dist/types/tests/base/env.d.ts.map +1 -0
  86. package/dist/types/tests/base/match.d.ts +9 -0
  87. package/dist/types/tests/base/match.d.ts.map +1 -0
  88. package/dist/types/tests/core/backend.test.d.ts +2 -0
  89. package/dist/types/tests/core/backend.test.d.ts.map +1 -0
  90. package/dist/types/tests/core/behavior.test.d.ts +2 -0
  91. package/dist/types/tests/core/behavior.test.d.ts.map +1 -0
  92. package/dist/types/tests/core/component_space.test.d.ts +2 -0
  93. package/dist/types/tests/core/component_space.test.d.ts.map +1 -0
  94. package/dist/types/tests/core/data_update.test.d.ts +2 -0
  95. package/dist/types/tests/core/data_update.test.d.ts.map +1 -0
  96. package/dist/types/tests/core/misc.test.d.ts +2 -0
  97. package/dist/types/tests/core/misc.test.d.ts.map +1 -0
  98. package/dist/types/tests/core/placeholder.test.d.ts +2 -0
  99. package/dist/types/tests/core/placeholder.test.d.ts.map +1 -0
  100. package/dist/types/tests/core/slot.test.d.ts +2 -0
  101. package/dist/types/tests/core/slot.test.d.ts.map +1 -0
  102. package/dist/types/tests/core/trait_behaviors.test.d.ts +2 -0
  103. package/dist/types/tests/core/trait_behaviors.test.d.ts.map +1 -0
  104. package/dist/types/tests/tmpl/binding_map.test.d.ts +2 -0
  105. package/dist/types/tests/tmpl/binding_map.test.d.ts.map +1 -0
  106. package/dist/types/tests/tmpl/event.test.d.ts +2 -0
  107. package/dist/types/tests/tmpl/event.test.d.ts.map +1 -0
  108. package/dist/types/tests/tmpl/expression.test.d.ts +2 -0
  109. package/dist/types/tests/tmpl/expression.test.d.ts.map +1 -0
  110. package/dist/types/tests/tmpl/lvalue.test.d.ts +2 -0
  111. package/dist/types/tests/tmpl/lvalue.test.d.ts.map +1 -0
  112. package/dist/types/tests/tmpl/native_rendering.test.d.ts +2 -0
  113. package/dist/types/tests/tmpl/native_rendering.test.d.ts.map +1 -0
  114. package/dist/types/tests/tmpl/structure.test.d.ts +2 -0
  115. package/dist/types/tests/tmpl/structure.test.d.ts.map +1 -0
  116. package/dist/types/tests/types/chaining.test.d.ts +2 -0
  117. package/dist/types/tests/types/chaining.test.d.ts.map +1 -0
  118. package/dist/types/tests/types/createElement.test.d.ts +2 -0
  119. package/dist/types/tests/types/createElement.test.d.ts.map +1 -0
  120. package/dist/types/tests/types/definition.test.d.ts +2 -0
  121. package/dist/types/tests/types/definition.test.d.ts.map +1 -0
  122. package/guide/zh_CN/advanced/binding_map_update.md +32 -0
  123. package/guide/zh_CN/advanced/build_args.md +28 -0
  124. package/guide/zh_CN/advanced/component_filter.md +70 -0
  125. package/guide/zh_CN/advanced/component_space.md +124 -0
  126. package/guide/zh_CN/advanced/custom_backend.md +53 -0
  127. package/guide/zh_CN/advanced/error_listener.md +32 -0
  128. package/guide/zh_CN/advanced/external_component.md +73 -0
  129. package/guide/zh_CN/advanced/template_engine.md +61 -0
  130. package/guide/zh_CN/appendix/backend_protocol.md +501 -0
  131. package/guide/zh_CN/appendix/list_diff_algorithm.md +406 -0
  132. package/guide/zh_CN/basic/beginning.md +94 -0
  133. package/guide/zh_CN/basic/component.md +156 -0
  134. package/guide/zh_CN/basic/event.md +169 -0
  135. package/guide/zh_CN/basic/lifetime.md +66 -0
  136. package/guide/zh_CN/basic/method.md +62 -0
  137. package/guide/zh_CN/basic/template.md +135 -0
  138. package/guide/zh_CN/data_management/advanced_update.md +170 -0
  139. package/guide/zh_CN/data_management/data_deep_copy.md +157 -0
  140. package/guide/zh_CN/data_management/data_observer.md +154 -0
  141. package/guide/zh_CN/data_management/property_early_init.md +31 -0
  142. package/guide/zh_CN/data_management/pure_data_pattern.md +21 -0
  143. package/guide/zh_CN/index.md +93 -0
  144. package/guide/zh_CN/interaction/behavior.md +52 -0
  145. package/guide/zh_CN/interaction/component_path.md +37 -0
  146. package/guide/zh_CN/interaction/generic.md +73 -0
  147. package/guide/zh_CN/interaction/placeholder.md +40 -0
  148. package/guide/zh_CN/interaction/relation.md +151 -0
  149. package/guide/zh_CN/interaction/slot.md +137 -0
  150. package/guide/zh_CN/interaction/template_import.md +94 -0
  151. package/guide/zh_CN/interaction/trait_behavior.md +117 -0
  152. package/guide/zh_CN/styling/external_class.md +46 -0
  153. package/guide/zh_CN/styling/style_isolation.md +54 -0
  154. package/guide/zh_CN/styling/virtual_host.md +52 -0
  155. package/guide/zh_CN/tree/element_iterator.md +54 -0
  156. package/guide/zh_CN/tree/mutation_observer.md +52 -0
  157. package/guide/zh_CN/tree/node_tree.md +142 -0
  158. package/guide/zh_CN/tree/node_tree_modification.md +78 -0
  159. package/guide/zh_CN/tree/selector.md +66 -0
  160. package/jest.config.js +6 -0
  161. package/jest.dts.config.js +9 -0
  162. package/jest.unit.config.js +14 -0
  163. package/package.json +28 -0
  164. package/src/backend/backend_protocol.ts +313 -0
  165. package/src/backend/composed_backend_protocol.ts +252 -0
  166. package/src/backend/domlike_backend_protocol.ts +370 -0
  167. package/src/backend/mode.ts +51 -0
  168. package/src/backend/suggested_backend_protocol.ts +83 -0
  169. package/src/behavior.ts +1655 -0
  170. package/src/bootstrap_dom_dev.js +22 -0
  171. package/src/class_list.ts +376 -0
  172. package/src/component.ts +1309 -0
  173. package/src/component_params.ts +461 -0
  174. package/src/component_space.ts +547 -0
  175. package/src/data_path.ts +225 -0
  176. package/src/data_proxy.ts +670 -0
  177. package/src/data_utils.ts +50 -0
  178. package/src/element.ts +1966 -0
  179. package/src/element_iterator.ts +158 -0
  180. package/src/event.ts +401 -0
  181. package/src/external_shadow_tree.ts +27 -0
  182. package/src/func_arr.ts +198 -0
  183. package/src/global_options.ts +242 -0
  184. package/src/index.ts +187 -0
  185. package/src/mutation_observer.ts +252 -0
  186. package/src/native_node.ts +74 -0
  187. package/src/node.ts +174 -0
  188. package/src/relation.ts +380 -0
  189. package/src/render.ts +25 -0
  190. package/src/selector.ts +218 -0
  191. package/src/shadow_root.ts +766 -0
  192. package/src/template_engine.ts +45 -0
  193. package/src/text_node.ts +149 -0
  194. package/src/tmpl/index.ts +199 -0
  195. package/src/tmpl/native_rendering.ts +175 -0
  196. package/src/tmpl/proc_gen_wrapper.ts +954 -0
  197. package/src/tmpl/proc_gen_wrapper_dom.ts +230 -0
  198. package/src/tmpl/range_list_diff.ts +443 -0
  199. package/src/trait_behaviors.ts +51 -0
  200. package/src/virtual_node.ts +51 -0
  201. package/tests/backend/domlike.test.ts +254 -0
  202. package/tests/base/env.ts +78 -0
  203. package/tests/base/match.ts +185 -0
  204. package/tests/core/backend.test.ts +144 -0
  205. package/tests/core/behavior.test.ts +546 -0
  206. package/tests/core/component_space.test.ts +212 -0
  207. package/tests/core/data_update.test.ts +461 -0
  208. package/tests/core/misc.test.ts +339 -0
  209. package/tests/core/placeholder.test.ts +180 -0
  210. package/tests/core/slot.test.ts +1495 -0
  211. package/tests/core/trait_behaviors.test.ts +153 -0
  212. package/tests/legacy/README.md +3 -0
  213. package/tests/legacy/behavior.test.js +293 -0
  214. package/tests/legacy/component.test.js +1247 -0
  215. package/tests/legacy/data_path.test.js +149 -0
  216. package/tests/legacy/data_proxy.test.js +759 -0
  217. package/tests/legacy/element_iterator.test.js +148 -0
  218. package/tests/legacy/event.test.js +849 -0
  219. package/tests/legacy/external.test.js +510 -0
  220. package/tests/legacy/extra_info.test.js +109 -0
  221. package/tests/legacy/generics.test.js +176 -0
  222. package/tests/legacy/mutation_observer.test.js +210 -0
  223. package/tests/legacy/relation.test.js +517 -0
  224. package/tests/legacy/selector.test.js +263 -0
  225. package/tests/legacy/slot.test.js +915 -0
  226. package/tests/legacy/virtual.test.js +394 -0
  227. package/tests/tmpl/binding_map.test.ts +208 -0
  228. package/tests/tmpl/event.test.ts +206 -0
  229. package/tests/tmpl/expression.test.ts +429 -0
  230. package/tests/tmpl/lvalue.test.ts +160 -0
  231. package/tests/tmpl/native_rendering.test.ts +155 -0
  232. package/tests/tmpl/structure.test.ts +998 -0
  233. package/tests/types/chaining.test.ts +614 -0
  234. package/tests/types/createElement.test.ts +82 -0
  235. package/tests/types/definition.test.ts +442 -0
  236. package/tsconfig.json +11 -0
  237. 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
+ }