glass-easel 0.2.0 → 0.3.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 (197) hide show
  1. package/.eslintignore +4 -0
  2. package/dist/glass_easel.all.js +2 -2
  3. package/dist/glass_easel.all.js.map +1 -1
  4. package/dist/glass_easel.d.ts +2546 -0
  5. package/dist/glass_easel.domlike.global.js +2 -2
  6. package/dist/glass_easel.domlike.global.js.map +1 -1
  7. package/guide/zh_CN/appendix/backend_protocol.md +164 -74
  8. package/jest.unit.config.js +7 -4
  9. package/package.json +7 -5
  10. package/rollup.config.ts +101 -0
  11. package/src/backend/backend_protocol.ts +26 -345
  12. package/src/backend/composed_backend_protocol.ts +10 -264
  13. package/src/backend/current_window_backend_context.ts +478 -0
  14. package/src/backend/domlike_backend_protocol.ts +9 -498
  15. package/src/backend/empty_backend.ts +265 -0
  16. package/src/backend/empty_composed_backend.ts +245 -0
  17. package/src/backend/index.ts +18 -0
  18. package/src/backend/suggested_backend_protocol.ts +62 -11
  19. package/src/behavior.ts +131 -442
  20. package/src/class_list.ts +328 -222
  21. package/src/component.ts +349 -184
  22. package/src/component_params.ts +54 -25
  23. package/src/component_space.ts +36 -15
  24. package/src/data_path.ts +22 -34
  25. package/src/data_proxy.ts +334 -27
  26. package/src/devtool.ts +89 -0
  27. package/src/element.ts +667 -285
  28. package/src/element_iterator.ts +9 -4
  29. package/src/event.ts +39 -20
  30. package/src/external_shadow_tree.ts +2 -2
  31. package/src/func_arr.ts +55 -101
  32. package/src/global_options.ts +18 -42
  33. package/src/index.ts +72 -73
  34. package/src/mutation_observer.ts +10 -7
  35. package/src/native_node.ts +79 -35
  36. package/src/node.ts +23 -30
  37. package/src/relation.ts +101 -12
  38. package/src/render.ts +5 -3
  39. package/src/selector.ts +9 -7
  40. package/src/shadow_root.ts +96 -240
  41. package/src/template_engine.ts +10 -7
  42. package/src/text_node.ts +43 -19
  43. package/src/tmpl/index.ts +38 -30
  44. package/src/tmpl/native_rendering.ts +14 -21
  45. package/src/tmpl/proc_gen_wrapper.ts +189 -151
  46. package/src/tmpl/proc_gen_wrapper_dom.ts +10 -8
  47. package/src/tmpl/range_list_diff.ts +30 -9
  48. package/src/trait_behaviors.ts +1 -1
  49. package/src/type_symbol.ts +36 -0
  50. package/src/virtual_node.ts +26 -13
  51. package/src/warning.ts +119 -0
  52. package/tests/base/composed_backend.ts +143 -142
  53. package/tests/base/env.ts +76 -3
  54. package/tests/base/match.ts +24 -22
  55. package/tests/base/shadow_backend.ts +917 -0
  56. package/tests/core/backend.test.ts +53 -1
  57. package/tests/core/behavior.test.ts +1 -1
  58. package/tests/core/data_update.test.ts +135 -0
  59. package/tests/core/misc.test.ts +91 -21
  60. package/tests/core/placeholder.test.ts +66 -25
  61. package/tests/core/slot.test.ts +161 -23
  62. package/tests/legacy/component.test.js +152 -78
  63. package/tests/legacy/data_path.test.js +19 -19
  64. package/tests/legacy/data_proxy.test.js +14 -7
  65. package/tests/legacy/external.test.js +8 -8
  66. package/tests/legacy/mutation_observer.test.js +7 -5
  67. package/tests/legacy/slot.test.js +2 -3
  68. package/tests/legacy/virtual.test.js +258 -25
  69. package/tests/tmpl/binding_map.test.ts +201 -195
  70. package/tests/tmpl/event.test.ts +138 -23
  71. package/tests/tmpl/expression.test.ts +15 -15
  72. package/tests/tmpl/lvalue.test.ts +101 -0
  73. package/tests/tmpl/structure.test.ts +486 -43
  74. package/tests/types/chaining.test.ts +27 -30
  75. package/tests/types/createElement.test.ts +5 -4
  76. package/tests/types/definition.test.ts +11 -14
  77. package/tsconfig.json +1 -3
  78. package/dist/glass_easel.all.d.ts +0 -1
  79. package/dist/glass_easel.domlike.global.d.ts +0 -1
  80. package/dist/index.d.ts +0 -1
  81. package/dist/index.js +0 -1
  82. package/dist/types/src/backend/backend_protocol.d.ts +0 -141
  83. package/dist/types/src/backend/backend_protocol.d.ts.map +0 -1
  84. package/dist/types/src/backend/composed_backend_protocol.d.ts +0 -102
  85. package/dist/types/src/backend/composed_backend_protocol.d.ts.map +0 -1
  86. package/dist/types/src/backend/domlike_backend_protocol.d.ts +0 -100
  87. package/dist/types/src/backend/domlike_backend_protocol.d.ts.map +0 -1
  88. package/dist/types/src/backend/mode.d.ts +0 -65
  89. package/dist/types/src/backend/mode.d.ts.map +0 -1
  90. package/dist/types/src/backend/suggested_backend_protocol.d.ts +0 -30
  91. package/dist/types/src/backend/suggested_backend_protocol.d.ts.map +0 -1
  92. package/dist/types/src/behavior.d.ts +0 -434
  93. package/dist/types/src/behavior.d.ts.map +0 -1
  94. package/dist/types/src/class_list.d.ts +0 -83
  95. package/dist/types/src/class_list.d.ts.map +0 -1
  96. package/dist/types/src/component.d.ts +0 -325
  97. package/dist/types/src/component.d.ts.map +0 -1
  98. package/dist/types/src/component_params.d.ts +0 -236
  99. package/dist/types/src/component_params.d.ts.map +0 -1
  100. package/dist/types/src/component_space.d.ts +0 -211
  101. package/dist/types/src/component_space.d.ts.map +0 -1
  102. package/dist/types/src/data_path.d.ts +0 -5
  103. package/dist/types/src/data_path.d.ts.map +0 -1
  104. package/dist/types/src/data_proxy.d.ts +0 -107
  105. package/dist/types/src/data_proxy.d.ts.map +0 -1
  106. package/dist/types/src/data_utils.d.ts +0 -3
  107. package/dist/types/src/data_utils.d.ts.map +0 -1
  108. package/dist/types/src/element.d.ts +0 -365
  109. package/dist/types/src/element.d.ts.map +0 -1
  110. package/dist/types/src/element_iterator.d.ts +0 -43
  111. package/dist/types/src/element_iterator.d.ts.map +0 -1
  112. package/dist/types/src/event.d.ts +0 -105
  113. package/dist/types/src/event.d.ts.map +0 -1
  114. package/dist/types/src/external_shadow_tree.d.ts +0 -20
  115. package/dist/types/src/external_shadow_tree.d.ts.map +0 -1
  116. package/dist/types/src/func_arr.d.ts +0 -39
  117. package/dist/types/src/func_arr.d.ts.map +0 -1
  118. package/dist/types/src/global_options.d.ts +0 -120
  119. package/dist/types/src/global_options.d.ts.map +0 -1
  120. package/dist/types/src/index.d.ts +0 -43
  121. package/dist/types/src/index.d.ts.map +0 -1
  122. package/dist/types/src/mutation_observer.d.ts +0 -79
  123. package/dist/types/src/mutation_observer.d.ts.map +0 -1
  124. package/dist/types/src/native_node.d.ts +0 -11
  125. package/dist/types/src/native_node.d.ts.map +0 -1
  126. package/dist/types/src/node.d.ts +0 -48
  127. package/dist/types/src/node.d.ts.map +0 -1
  128. package/dist/types/src/relation.d.ts +0 -46
  129. package/dist/types/src/relation.d.ts.map +0 -1
  130. package/dist/types/src/render.d.ts +0 -3
  131. package/dist/types/src/render.d.ts.map +0 -1
  132. package/dist/types/src/selector.d.ts +0 -32
  133. package/dist/types/src/selector.d.ts.map +0 -1
  134. package/dist/types/src/shadow_root.d.ts +0 -174
  135. package/dist/types/src/shadow_root.d.ts.map +0 -1
  136. package/dist/types/src/template_engine.d.ts +0 -56
  137. package/dist/types/src/template_engine.d.ts.map +0 -1
  138. package/dist/types/src/text_node.d.ts +0 -44
  139. package/dist/types/src/text_node.d.ts.map +0 -1
  140. package/dist/types/src/tmpl/index.d.ts +0 -19
  141. package/dist/types/src/tmpl/index.d.ts.map +0 -1
  142. package/dist/types/src/tmpl/native_rendering.d.ts +0 -45
  143. package/dist/types/src/tmpl/native_rendering.d.ts.map +0 -1
  144. package/dist/types/src/tmpl/proc_gen_wrapper.d.ts +0 -89
  145. package/dist/types/src/tmpl/proc_gen_wrapper.d.ts.map +0 -1
  146. package/dist/types/src/tmpl/proc_gen_wrapper_dom.d.ts +0 -50
  147. package/dist/types/src/tmpl/proc_gen_wrapper_dom.d.ts.map +0 -1
  148. package/dist/types/src/tmpl/range_list_diff.d.ts +0 -19
  149. package/dist/types/src/tmpl/range_list_diff.d.ts.map +0 -1
  150. package/dist/types/src/trait_behaviors.d.ts +0 -38
  151. package/dist/types/src/trait_behaviors.d.ts.map +0 -1
  152. package/dist/types/src/virtual_node.d.ts +0 -10
  153. package/dist/types/src/virtual_node.d.ts.map +0 -1
  154. package/dist/types/tests/backend/domlike.test.d.ts +0 -2
  155. package/dist/types/tests/backend/domlike.test.d.ts.map +0 -1
  156. package/dist/types/tests/base/composed_backend.d.ts +0 -123
  157. package/dist/types/tests/base/composed_backend.d.ts.map +0 -1
  158. package/dist/types/tests/base/env.d.ts +0 -30
  159. package/dist/types/tests/base/env.d.ts.map +0 -1
  160. package/dist/types/tests/base/match.d.ts +0 -9
  161. package/dist/types/tests/base/match.d.ts.map +0 -1
  162. package/dist/types/tests/core/backend.test.d.ts +0 -2
  163. package/dist/types/tests/core/backend.test.d.ts.map +0 -1
  164. package/dist/types/tests/core/behavior.test.d.ts +0 -2
  165. package/dist/types/tests/core/behavior.test.d.ts.map +0 -1
  166. package/dist/types/tests/core/component_space.test.d.ts +0 -2
  167. package/dist/types/tests/core/component_space.test.d.ts.map +0 -1
  168. package/dist/types/tests/core/data_update.test.d.ts +0 -2
  169. package/dist/types/tests/core/data_update.test.d.ts.map +0 -1
  170. package/dist/types/tests/core/misc.test.d.ts +0 -2
  171. package/dist/types/tests/core/misc.test.d.ts.map +0 -1
  172. package/dist/types/tests/core/placeholder.test.d.ts +0 -2
  173. package/dist/types/tests/core/placeholder.test.d.ts.map +0 -1
  174. package/dist/types/tests/core/slot.test.d.ts +0 -2
  175. package/dist/types/tests/core/slot.test.d.ts.map +0 -1
  176. package/dist/types/tests/core/trait_behaviors.test.d.ts +0 -2
  177. package/dist/types/tests/core/trait_behaviors.test.d.ts.map +0 -1
  178. package/dist/types/tests/tmpl/binding_map.test.d.ts +0 -2
  179. package/dist/types/tests/tmpl/binding_map.test.d.ts.map +0 -1
  180. package/dist/types/tests/tmpl/event.test.d.ts +0 -2
  181. package/dist/types/tests/tmpl/event.test.d.ts.map +0 -1
  182. package/dist/types/tests/tmpl/expression.test.d.ts +0 -2
  183. package/dist/types/tests/tmpl/expression.test.d.ts.map +0 -1
  184. package/dist/types/tests/tmpl/lvalue.test.d.ts +0 -2
  185. package/dist/types/tests/tmpl/lvalue.test.d.ts.map +0 -1
  186. package/dist/types/tests/tmpl/native_rendering.test.d.ts +0 -2
  187. package/dist/types/tests/tmpl/native_rendering.test.d.ts.map +0 -1
  188. package/dist/types/tests/tmpl/structure.test.d.ts +0 -2
  189. package/dist/types/tests/tmpl/structure.test.d.ts.map +0 -1
  190. package/dist/types/tests/types/chaining.test.d.ts +0 -2
  191. package/dist/types/tests/types/chaining.test.d.ts.map +0 -1
  192. package/dist/types/tests/types/createElement.test.d.ts +0 -2
  193. package/dist/types/tests/types/createElement.test.d.ts.map +0 -1
  194. package/dist/types/tests/types/definition.test.d.ts +0 -2
  195. package/dist/types/tests/types/definition.test.d.ts.map +0 -1
  196. package/webpack.config.js +0 -275
  197. /package/src/backend/{mode.ts → shared.ts} +0 -0
package/src/selector.ts CHANGED
@@ -1,4 +1,6 @@
1
- import { Element, Component, VirtualNode, ShadowRoot, ComponentSpace } from '.'
1
+ import { type ComponentSpace } from './component_space'
2
+ import { type Element } from './element'
3
+ import { isComponent, isElement, isShadowRoot, isVirtualNode } from './type_symbol'
2
4
 
3
5
  const enum SegmentRelation {
4
6
  Child,
@@ -106,10 +108,10 @@ export class ParsedSelector {
106
108
  do {
107
109
  if (!nextNode.parentNode) {
108
110
  if (nextRelation === SegmentRelation.CrossShadowDescendant) {
109
- nextNode = nextNode instanceof ShadowRoot ? nextNode.getHostNode() : null
111
+ nextNode = isShadowRoot(nextNode) ? nextNode.getHostNode() : null
110
112
  } else if (relation === SegmentRelation.CrossShadowDescendant) {
111
113
  match = false
112
- nextNode = nextNode instanceof ShadowRoot ? nextNode.getHostNode() : null
114
+ nextNode = isShadowRoot(nextNode) ? nextNode.getHostNode() : null
113
115
  } else {
114
116
  nextNode = null
115
117
  }
@@ -117,7 +119,7 @@ export class ParsedSelector {
117
119
  nextNode = nextNode.parentNode
118
120
  }
119
121
  if (nextNode === root) nextNode = null
120
- } while (nextNode instanceof VirtualNode)
122
+ } while (isVirtualNode(nextNode))
121
123
  if (!nextNode) return false
122
124
  if (match) {
123
125
  // if matches, try match ancestors
@@ -149,7 +151,7 @@ export class ParsedSelector {
149
151
  * otherwise it match in the whole tree.
150
152
  */
151
153
  testSelector(root: Element | null, node: Element): boolean {
152
- if (node instanceof VirtualNode) return false
154
+ if (isVirtualNode(node)) return false
153
155
  const union = this.unions
154
156
  let ownerSpace: ComponentSpace | undefined
155
157
  if (root !== null) {
@@ -181,7 +183,7 @@ export class ParsedSelector {
181
183
  if (findOne) return node
182
184
  ret.push(node)
183
185
  }
184
- if (node instanceof Component) {
186
+ if (isComponent(node)) {
185
187
  const shadowRoot = node.getShadowRoot()
186
188
  if (shadowRoot) {
187
189
  const r = rec(root, shadowRoot, findOne)
@@ -193,7 +195,7 @@ export class ParsedSelector {
193
195
  const children = node.childNodes
194
196
  for (let i = 0; i < children.length; i += 1) {
195
197
  const child = children[i]
196
- if (child instanceof Element) {
198
+ if (isElement(child)) {
197
199
  const r = rec(root, child, findOne)
198
200
  if (r && findOne) {
199
201
  return r
@@ -1,20 +1,21 @@
1
- import * as backend from './backend/backend_protocol'
2
- import { VirtualNode } from './virtual_node'
1
+ import { BM, BackendMode, type backend } from './backend'
2
+ import { type ComponentDefinitionWithPlaceholder } from './behavior'
3
3
  import {
4
4
  Component,
5
- GeneralComponentDefinition,
6
- GeneralComponent,
7
5
  convertGenerics,
8
6
  resolvePlaceholder,
7
+ type GeneralComponent,
8
+ type GeneralComponentDefinition,
9
9
  } from './component'
10
- import { TextNode } from './text_node'
11
- import { NativeNode } from './native_node'
12
- import { DoubleLinkedList, Element } from './element'
13
- import { Node } from './node'
14
- import { ComponentDefinitionWithPlaceholder } from './behavior'
15
- import { BM, BackendMode } from './backend/mode'
16
10
  import { DeepCopyStrategy, getDeepCopyStrategy } from './data_proxy'
17
11
  import { deepCopy, simpleDeepCopy } from './data_utils'
12
+ import { Element, type DoubleLinkedList } from './element'
13
+ import { NativeNode } from './native_node'
14
+ import { type Node } from './node'
15
+ import { TextNode } from './text_node'
16
+ import { SHADOW_ROOT_SYMBOL, isElement, isShadowRoot } from './type_symbol'
17
+ import { VirtualNode } from './virtual_node'
18
+ import { ThirdError, triggerWarning } from './warning'
18
19
 
19
20
  export const enum SlotMode {
20
21
  Direct = 0,
@@ -27,35 +28,32 @@ type AppliedSlotMeta = {
27
28
  updatePathTree: { [key: string]: true } | undefined
28
29
  }
29
30
 
30
- const wrapPlaceholderCallback = (
31
- f: (c: GeneralComponentDefinition) => void,
32
- cwp: Exclude<ComponentDefinitionWithPlaceholder, string>,
33
- owner: GeneralComponent,
34
- ) => {
35
- const waiting = cwp.waiting
36
- if (waiting) {
37
- waiting.add(f)
38
- waiting.hintUsed(owner)
39
- return () => {
40
- waiting.remove(f)
41
- }
42
- }
43
- return undefined
44
- }
45
-
46
31
  export class ShadowRoot extends VirtualNode {
32
+ /* @internal */
33
+ [SHADOW_ROOT_SYMBOL]: true
34
+ /* @internal */
47
35
  private _$host: GeneralComponent
48
36
  /** @internal */
49
37
  _$backendShadowRoot: backend.ShadowRootContext | null
38
+ /* @internal */
50
39
  private _$slotMode: SlotMode
40
+ /* @internal */
51
41
  private _$idMap: { [id: string]: Element } | null
42
+ /* @internal */
52
43
  private _$singleSlot?: Element | null
44
+ /* @internal */
53
45
  private _$slots?: Record<string, Element>
46
+ /* @internal */
54
47
  private _$slotsList?: Record<string, DoubleLinkedList<Element>>
48
+ /* @internal */
55
49
  private _$dynamicSlotsInserted?: boolean
50
+ /* @internal */
56
51
  private _$dynamicSlots?: Map<Element, AppliedSlotMeta>
52
+ /* @internal */
57
53
  private _$requiredSlotValueNames?: string[]
54
+ /* @internal */
58
55
  private _$propertyPassingDeepCopy?: DeepCopyStrategy
56
+ /* @internal */
59
57
  private _$insertDynamicSlotHandler?: (
60
58
  slots: {
61
59
  slot: Element
@@ -63,27 +61,33 @@ export class ShadowRoot extends VirtualNode {
63
61
  slotValues: { [name: string]: unknown }
64
62
  }[],
65
63
  ) => void
64
+ /* @internal */
66
65
  private _$removeDynamicSlotHandler?: (slots: Element[]) => void
66
+ /* @internal */
67
67
  private _$updateDynamicSlotHandler?: (
68
68
  slot: Element,
69
69
  slotValues: { [name: string]: unknown },
70
70
  updatePathTree: { [name: string]: true },
71
71
  ) => void
72
72
 
73
+ /* istanbul ignore next */
73
74
  constructor() {
74
75
  throw new Error('Element cannot be constructed directly')
75
76
  // eslint-disable-next-line no-unreachable
76
- /* istanbul ignore next */
77
77
  super()
78
78
  }
79
79
 
80
+ static isShadowRoot = isShadowRoot
81
+
80
82
  static createShadowRoot(host: GeneralComponent): ShadowRoot {
81
83
  const node = Object.create(ShadowRoot.prototype) as ShadowRoot
82
- const sr =
83
- BM.SHADOW || (BM.DYNAMIC && host.getBackendMode() === BackendMode.Shadow)
84
- ? (host.getBackendElement() as backend.Element | null)?.getShadowRoot() || null
85
- : null
86
- node._$initializeVirtual('shadow', node, host._$nodeTreeContext, sr)
84
+
85
+ let be: backend.ShadowRootContext | null = null
86
+ if (BM.SHADOW || (BM.DYNAMIC && host.getBackendMode() === BackendMode.Shadow)) {
87
+ be = (host._$backendElement as backend.Element).getShadowRoot()!
88
+ }
89
+
90
+ node.is = 'shadow'
87
91
  node._$idMap = null
88
92
  let slotMode = SlotMode.Single
89
93
  const hostComponentOptions = host.getComponentOptions()
@@ -107,10 +111,11 @@ export class ShadowRoot extends VirtualNode {
107
111
  node._$removeDynamicSlotHandler = undefined
108
112
  node._$updateDynamicSlotHandler = undefined
109
113
  }
110
- node._$backendShadowRoot = sr
111
- node._$initialize(true, sr, node, host._$nodeTreeContext)
114
+ node._$backendShadowRoot = be
115
+ node._$initialize(true, be, node, host._$nodeTreeContext)
112
116
  node._$host = host
113
117
  host.shadowRoot = node
118
+ be?.associateValue(node)
114
119
  return node
115
120
  }
116
121
 
@@ -133,10 +138,10 @@ export class ShadowRoot extends VirtualNode {
133
138
  createNativeNodeWithInit(
134
139
  tagName: string,
135
140
  stylingName: string,
136
- placeholderHandler: (() => void) | undefined,
141
+ placeholderHandlerRemover: (() => void) | undefined,
137
142
  initPropValues?: (comp: NativeNode) => void,
138
143
  ): NativeNode {
139
- const ret = NativeNode.create(tagName, this, stylingName, placeholderHandler)
144
+ const ret = NativeNode.create(tagName, this, stylingName, placeholderHandlerRemover)
140
145
  initPropValues?.(ret)
141
146
  return ret
142
147
  }
@@ -160,26 +165,39 @@ export class ShadowRoot extends VirtualNode {
160
165
  const space = beh.ownerSpace
161
166
  const compName = usingKey === undefined ? tagName : usingKey
162
167
 
163
- // if the target is in using list, then use the one in using list
164
- const using = beh._$using[compName]
165
- if (typeof using === 'string') {
166
- return this.createNativeNodeWithInit(using, tagName, undefined, initPropValues)
167
- }
168
- if (using) {
168
+ const possibleComponentDefinitions = [
169
+ // if the target is in using list, then use the one in using list
170
+ beh._$using[compName],
171
+ // if the target is in generics list, then use the one
172
+ hostGenericImpls && hostGenericImpls[compName],
173
+ ]
174
+
175
+ for (let i = 0; i < possibleComponentDefinitions.length; i += 1) {
176
+ const cwp = possibleComponentDefinitions[i]
177
+ if (cwp === null || cwp === undefined) continue
178
+ if (typeof cwp === 'string') {
179
+ return this.createNativeNodeWithInit(cwp, tagName, undefined, initPropValues)
180
+ }
169
181
  let usingTarget: GeneralComponentDefinition | string | undefined
170
- if (using.final) {
171
- usingTarget = using.final
172
- } else if (using.placeholder !== null) {
173
- usingTarget = resolvePlaceholder(using.placeholder, space, using.source, hostGenericImpls)
182
+ let placeholderHandlerRemover: (() => void) | undefined
183
+ if (cwp.final) {
184
+ usingTarget = cwp.final
185
+ } else if (cwp.placeholder !== null) {
186
+ usingTarget = resolvePlaceholder(cwp.placeholder, space, cwp.source, hostGenericImpls)
187
+ const waiting = cwp.waiting
188
+ if (placeholderCallback && waiting) {
189
+ waiting.add(placeholderCallback)
190
+ waiting.hintUsed(host)
191
+ placeholderHandlerRemover = () => {
192
+ waiting.remove(placeholderCallback)
193
+ }
194
+ }
174
195
  }
175
- const placeholderHandler = placeholderCallback
176
- ? wrapPlaceholderCallback(placeholderCallback, using, host)
177
- : undefined
178
196
  if (typeof usingTarget === 'string') {
179
197
  return this.createNativeNodeWithInit(
180
198
  usingTarget,
181
199
  tagName,
182
- placeholderHandler,
200
+ placeholderHandlerRemover,
183
201
  initPropValues,
184
202
  )
185
203
  }
@@ -190,48 +208,24 @@ export class ShadowRoot extends VirtualNode {
190
208
  this,
191
209
  null,
192
210
  convertGenerics(usingTarget, beh, host, genericTargets),
193
- placeholderHandler,
194
- initPropValues,
195
- )
196
- }
197
- }
198
-
199
- // if the target is in generics list, then use the one
200
- const g = hostGenericImpls && hostGenericImpls[compName]
201
- if (typeof g === 'string') {
202
- return this.createNativeNodeWithInit(g, tagName, undefined, initPropValues)
203
- }
204
- if (g) {
205
- let genImpl: GeneralComponentDefinition | string | undefined
206
- if (g.final) {
207
- genImpl = g.final
208
- } else if (g.placeholder !== null) {
209
- genImpl = resolvePlaceholder(g.placeholder, space, g.source, hostGenericImpls)
210
- }
211
- const placeholderHandler = placeholderCallback
212
- ? wrapPlaceholderCallback(placeholderCallback, g, host)
213
- : undefined
214
- if (typeof genImpl === 'string') {
215
- return this.createNativeNodeWithInit(genImpl, tagName, placeholderHandler, initPropValues)
216
- }
217
- if (genImpl) {
218
- return Component._$advancedCreate(
219
- tagName,
220
- genImpl,
221
- this,
222
- null,
223
- convertGenerics(genImpl, beh, host, genericTargets),
224
- placeholderHandler,
211
+ placeholderHandlerRemover,
225
212
  initPropValues,
226
213
  )
227
214
  }
228
215
  }
229
216
 
230
217
  // find in the space otherwise
231
- const comp = space.getGlobalUsingComponent(compName) ?? space.getDefaultComponent()
232
- /* istanbul ignore if */
218
+ let comp = space.getGlobalUsingComponent(compName)
219
+ if (comp === null && space._$allowUnusedNativeNode && compName !== '') {
220
+ comp = compName
221
+ }
233
222
  if (!comp) {
234
- throw new Error(`Cannot find component "${compName}"`)
223
+ comp = space.getDefaultComponent()
224
+ /* istanbul ignore if */
225
+ if (!comp) {
226
+ throw new ThirdError(`Cannot find component "${compName}"`, undefined, this._$host)
227
+ }
228
+ triggerWarning(`Cannot find component "${compName}", using default component.`, this._$host)
235
229
  }
236
230
  if (typeof comp === 'string') {
237
231
  return this.createNativeNodeWithInit(comp, tagName, undefined, initPropValues)
@@ -247,6 +241,13 @@ export class ShadowRoot extends VirtualNode {
247
241
  )
248
242
  }
249
243
 
244
+ createComponentByDef(
245
+ tagName: string,
246
+ componentDef: GeneralComponentDefinition,
247
+ ): GeneralComponent {
248
+ return Component._$advancedCreate(tagName, componentDef, this, null, null, undefined)
249
+ }
250
+
250
251
  /**
251
252
  * Create a component if the given tag name is a component in the space, or a native node if not
252
253
  *
@@ -280,10 +281,13 @@ export class ShadowRoot extends VirtualNode {
280
281
  )
281
282
  }
282
283
 
283
- // use native node otherwise
284
- const node = NativeNode.create(tagName, this)
285
- initPropValues?.(node)
286
- return node
284
+ if (space._$allowUnusedNativeNode) {
285
+ // use native node otherwise
286
+ const node = NativeNode.create(tagName, this)
287
+ initPropValues?.(node)
288
+ return node
289
+ }
290
+ throw new ThirdError(`Unknown tag name ${tagName}`, '[render]', host)
287
291
  }
288
292
 
289
293
  /**
@@ -372,7 +376,7 @@ export class ShadowRoot extends VirtualNode {
372
376
  }
373
377
  if (slotMode === SlotMode.Multiple) {
374
378
  let name: string
375
- if (elem instanceof Element) {
379
+ if (isElement(elem)) {
376
380
  name = elem._$nodeSlot
377
381
  } else {
378
382
  name = ''
@@ -833,154 +837,6 @@ export class ShadowRoot extends VirtualNode {
833
837
  getSlotMode(): SlotMode {
834
838
  return this._$slotMode
835
839
  }
836
-
837
- /** @internal */
838
- static _$updateSubtreeSlotNodes(
839
- parentNode: Element,
840
- elements: Node[],
841
- shadowRoot: ShadowRoot | null,
842
- oldShadowRoot: ShadowRoot | null,
843
- posIndex: number,
844
- ):
845
- | { updateContainingSlot: () => void; removeSlotNodes: () => void; insertSlotNodes: () => void }
846
- | undefined {
847
- if (!shadowRoot && !oldShadowRoot) return undefined
848
-
849
- const slotMode = shadowRoot?.getSlotMode()
850
- const oldSlotMode = oldShadowRoot?.getSlotMode()
851
-
852
- if (
853
- (slotMode === undefined || slotMode === SlotMode.Direct) &&
854
- (oldSlotMode === undefined || oldSlotMode === SlotMode.Direct)
855
- ) {
856
- return undefined
857
- }
858
-
859
- if (
860
- (slotMode === undefined || slotMode === SlotMode.Single) &&
861
- (oldSlotMode === undefined || oldSlotMode === SlotMode.Single)
862
- ) {
863
- let removeStart = -1
864
- let removeCount = 0
865
- let insertPos = -1
866
- const slotNodesToUpdate: Node[] = []
867
- const oldContainingSlot = elements[0]!.containingSlot
868
- const containingSlot = shadowRoot?.getContainingSlot(elements[0]!)
869
-
870
- for (let i = 0; i < elements.length; i += 1) {
871
- const elem = elements[i]!
872
- // eslint-disable-next-line no-loop-func
873
- Element.forEachNodeInSlot(elem, (node) => {
874
- if (oldContainingSlot) {
875
- if (removeCount) {
876
- removeCount += 1
877
- } else {
878
- removeStart = node.slotIndex!
879
- removeCount = 1
880
- }
881
- }
882
-
883
- slotNodesToUpdate.push(node)
884
- })
885
- }
886
-
887
- if (containingSlot && slotNodesToUpdate.length) {
888
- const firstSlotNode = slotNodesToUpdate[0]!
889
- insertPos = Element._$findSlotNodeInsertPosition(containingSlot, firstSlotNode, posIndex)
890
- }
891
-
892
- return {
893
- updateContainingSlot: () => {
894
- for (let i = slotNodesToUpdate.length - 1; i >= 0; i -= 1) {
895
- const node = slotNodesToUpdate[i]!
896
- Element._$updateContainingSlot(node, containingSlot)
897
- }
898
- },
899
- removeSlotNodes: () => {
900
- if (oldShadowRoot && oldContainingSlot && removeCount) {
901
- Element._$spliceSlotNodes(oldContainingSlot, removeStart, removeCount, undefined)
902
- }
903
- },
904
- insertSlotNodes: () => {
905
- if (shadowRoot && containingSlot && slotNodesToUpdate.length) {
906
- Element._$spliceSlotNodes(containingSlot, insertPos, 0, slotNodesToUpdate)
907
- }
908
- },
909
- }
910
- }
911
- const slotNodesToInsertMap = new Map<Element, { nodes: Node[]; insertPos: number }>()
912
- const slotNodesToRemoveMap = new Map<Element, { start: number; count: number }>()
913
-
914
- const slotNodesWithContainingSlot: [Node, Element | undefined | null][] = []
915
-
916
- for (let i = 0; i < elements.length; i += 1) {
917
- const elem = elements[i]!
918
- Element.forEachNodeInSlot(elem, (node, oldContainingSlot) => {
919
- const containingSlot =
920
- slotMode !== SlotMode.Direct ? shadowRoot?.getContainingSlot(node) : undefined
921
-
922
- if (oldContainingSlot) {
923
- const slotNodesToRemove = slotNodesToRemoveMap.get(oldContainingSlot)
924
- if (slotNodesToRemove) {
925
- slotNodesToRemove.count += 1
926
- } else {
927
- slotNodesToRemoveMap.set(oldContainingSlot, { start: node.slotIndex!, count: 1 })
928
- }
929
- }
930
-
931
- if (containingSlot) {
932
- const slotNodesToInsert = slotNodesToInsertMap.get(containingSlot)
933
- if (slotNodesToInsert) {
934
- slotNodesToInsert.nodes.push(node)
935
- } else {
936
- slotNodesToInsertMap.set(containingSlot, { nodes: [node], insertPos: -1 })
937
- }
938
- }
939
-
940
- slotNodesWithContainingSlot.push([node, containingSlot])
941
- })
942
- }
943
-
944
- if (shadowRoot && slotNodesToInsertMap.size) {
945
- const iter = slotNodesToInsertMap.entries()
946
-
947
- for (let it = iter.next(); !it.done; it = iter.next()) {
948
- const [slot, { nodes: slotNodesToInsert }] = it.value
949
- const firstSlotNodeToInsert = slotNodesToInsert[0]!
950
- it.value[1].insertPos = Element._$findSlotNodeInsertPosition(
951
- slot,
952
- firstSlotNodeToInsert,
953
- posIndex,
954
- )
955
- }
956
- }
957
-
958
- return {
959
- updateContainingSlot: () => {
960
- for (let i = slotNodesWithContainingSlot.length - 1; i >= 0; i -= 1) {
961
- const [node, containingSlot] = slotNodesWithContainingSlot[i]!
962
- Element._$updateContainingSlot(node, containingSlot)
963
- }
964
- },
965
- removeSlotNodes: () => {
966
- if (oldShadowRoot && slotNodesToRemoveMap.size) {
967
- const iter = slotNodesToRemoveMap.entries()
968
- for (let it = iter.next(); !it.done; it = iter.next()) {
969
- const [slot, { start, count }] = it.value
970
- Element._$spliceSlotNodes(slot, start, count, undefined)
971
- }
972
- }
973
- },
974
- insertSlotNodes: () => {
975
- if (shadowRoot && slotNodesToInsertMap.size) {
976
- const iter = slotNodesToInsertMap.entries()
977
-
978
- for (let it = iter.next(); !it.done; it = iter.next()) {
979
- const [slot, { nodes: slotNodesToInsert, insertPos }] = it.value
980
- Element._$spliceSlotNodes(slot, insertPos, 0, slotNodesToInsert)
981
- }
982
- }
983
- },
984
- }
985
- }
986
840
  }
841
+
842
+ ShadowRoot.prototype[SHADOW_ROOT_SYMBOL] = true
@@ -1,9 +1,9 @@
1
- import { GeneralBehavior } from './behavior'
2
- import { ShadowRoot } from './shadow_root'
3
- import { DataChange, DataValue } from './data_proxy'
4
- import { NormalizedComponentOptions } from './global_options'
5
- import { ExternalShadowRoot } from './external_shadow_tree'
6
- import { GeneralComponent } from './component'
1
+ import { type GeneralBehavior } from './behavior'
2
+ import { type ShadowRoot } from './shadow_root'
3
+ import { type DataChange, type DataValue } from './data_proxy'
4
+ import { type NormalizedComponentOptions } from './global_options'
5
+ import { type ExternalShadowRoot } from './external_shadow_tree'
6
+ import { type GeneralComponent } from './component'
7
7
 
8
8
  /**
9
9
  * A template engine that handles the template part of a component
@@ -26,7 +26,10 @@ export interface Template {
26
26
  /**
27
27
  * Create a template instance for a component instance
28
28
  */
29
- createInstance(elem: GeneralComponent): TemplateInstance
29
+ createInstance(
30
+ elem: GeneralComponent,
31
+ createShadowRoot: (component: GeneralComponent) => ShadowRoot,
32
+ ): TemplateInstance
30
33
 
31
34
  /**
32
35
  * Update the content of the template (optional)
package/src/text_node.ts CHANGED
@@ -1,14 +1,25 @@
1
- import * as backend from './backend/backend_protocol'
2
- import * as composedBackend from './backend/composed_backend_protocol'
3
- import * as domlikeBackend from './backend/domlike_backend_protocol'
4
- import { ShadowRoot } from './shadow_root'
5
- import { Element } from './element'
1
+ import {
2
+ BM,
3
+ BackendMode,
4
+ type GeneralBackendElement,
5
+ type backend,
6
+ type composedBackend,
7
+ type domlikeBackend,
8
+ } from './backend'
9
+ import { type Element } from './element'
10
+ import { ENV } from './global_options'
11
+ import { performanceMeasureEnd, performanceMeasureStart } from './devtool'
6
12
  import { MutationObserverTarget } from './mutation_observer'
7
- import { GeneralBackendElement, NodeCast } from './node'
8
- import { BM, BackendMode } from './backend/mode'
13
+ import { type NodeCast } from './node'
14
+ import { type ShadowRoot } from './shadow_root'
15
+ import { TEXT_NODE_SYMBOL, isTextNode } from './type_symbol'
9
16
 
10
17
  export class TextNode implements NodeCast {
18
+ /* @internal */
19
+ [TEXT_NODE_SYMBOL]!: true
20
+ /* @internal */
11
21
  _$backendElement: GeneralBackendElement | null
22
+ /* @internal */
12
23
  private _$text: string
13
24
  ownerShadowRoot: ShadowRoot
14
25
  parentNode: Element | null
@@ -31,18 +42,21 @@ export class TextNode implements NodeCast {
31
42
 
32
43
  constructor(text: string, owner: ShadowRoot) {
33
44
  this._$text = String(text)
34
- let backendElement: GeneralBackendElement | null
35
- if (BM.DOMLIKE || (BM.DYNAMIC && owner.getBackendMode() === BackendMode.Domlike)) {
36
- backendElement = (owner._$nodeTreeContext as domlikeBackend.Context).document.createTextNode(
37
- text,
38
- )
39
- } else if (BM.SHADOW || (BM.DYNAMIC && owner.getBackendMode() === BackendMode.Shadow)) {
40
- const backend = owner._$backendShadowRoot
41
- backendElement = backend?.createTextNode(text) || null
42
- } else {
43
- const backend = owner._$nodeTreeContext as composedBackend.Context
44
- backendElement = backend.createTextNode(text)
45
+ let backendElement: GeneralBackendElement | null = null
46
+ const context = owner.getBackendContext()
47
+ if (context) {
48
+ if (ENV.DEV) performanceMeasureStart('backend.createTextNode')
49
+ if (BM.DOMLIKE || (BM.DYNAMIC && owner.getBackendMode() === BackendMode.Domlike)) {
50
+ backendElement = (context as domlikeBackend.Context).document.createTextNode(text)
51
+ } else if (BM.SHADOW || (BM.DYNAMIC && owner.getBackendMode() === BackendMode.Shadow)) {
52
+ const backend = owner._$backendShadowRoot!
53
+ backendElement = backend.createTextNode(text)
54
+ } else {
55
+ const backend = context as composedBackend.Context
56
+ backendElement = backend.createTextNode(text)
57
+ }
45
58
  }
59
+ if (ENV.DEV) performanceMeasureEnd()
46
60
  this._$backendElement = backendElement
47
61
  this.ownerShadowRoot = owner
48
62
  this.parentNode = null
@@ -50,6 +64,8 @@ export class TextNode implements NodeCast {
50
64
  this.containingSlot = undefined
51
65
  }
52
66
 
67
+ static isTextNode = isTextNode
68
+
53
69
  static create(text: string, ownerShadowRoot: ShadowRoot): TextNode {
54
70
  return new TextNode(text, ownerShadowRoot)
55
71
  }
@@ -87,7 +103,9 @@ export class TextNode implements NodeCast {
87
103
  (BM.DYNAMIC && this.ownerShadowRoot.getBackendMode() === BackendMode.Domlike)
88
104
  )
89
105
  ) {
106
+ if (ENV.DEV) performanceMeasureStart('backend.release')
90
107
  ;(this._$backendElement as backend.Element | composedBackend.Element).release()
108
+ if (ENV.DEV) performanceMeasureEnd()
91
109
  }
92
110
  this._$backendElement = null
93
111
  }
@@ -122,8 +140,11 @@ export class TextNode implements NodeCast {
122
140
  }
123
141
 
124
142
  set textContent(text: string) {
125
- this._$text = String(text)
143
+ const newText = String(text)
144
+ if (newText === this._$text) return
145
+ this._$text = newText
126
146
  if (this._$backendElement) {
147
+ if (ENV.DEV) performanceMeasureStart('backend.setText')
127
148
  if (
128
149
  BM.DOMLIKE ||
129
150
  (BM.DYNAMIC && this.ownerShadowRoot.getBackendMode() === BackendMode.Domlike)
@@ -132,6 +153,7 @@ export class TextNode implements NodeCast {
132
153
  } else {
133
154
  ;(this._$backendElement as backend.Element | composedBackend.Element).setText(this._$text)
134
155
  }
156
+ if (ENV.DEV) performanceMeasureEnd()
135
157
  }
136
158
  MutationObserverTarget.callTextObservers(this, {
137
159
  type: 'characterData',
@@ -139,3 +161,5 @@ export class TextNode implements NodeCast {
139
161
  })
140
162
  }
141
163
  }
164
+
165
+ TextNode.prototype[TEXT_NODE_SYMBOL] = true