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,380 @@
1
+ import {
2
+ VirtualNode,
3
+ } from './virtual_node'
4
+ import {
5
+ Behavior,
6
+ GeneralBehavior,
7
+ } from './behavior'
8
+ import {
9
+ Component,
10
+ GeneralComponent,
11
+ } from './component'
12
+ import {
13
+ Element,
14
+ } from './element'
15
+ import {
16
+ safeCallback,
17
+ triggerWarning,
18
+ } from './func_arr'
19
+ import { TraitBehavior } from './trait_behaviors'
20
+
21
+ export const enum RelationType {
22
+ Ancestor = 0,
23
+ Descendant,
24
+ ParentNonVirtualNode,
25
+ ChildNonVirtualNode,
26
+ ParentComponent,
27
+ ChildComponent,
28
+ }
29
+
30
+ const RELATION_TYPE_COUNT = 6
31
+
32
+ export type RelationListener = (target: unknown) => void
33
+
34
+ export type RelationFailedListener = () => void
35
+
36
+ export type RelationDefinition = {
37
+ target: string
38
+ | GeneralBehavior
39
+ | TraitBehavior<{ [x: string]: unknown }, { [x: string]: unknown }>
40
+ domain: string | null
41
+ type: RelationType
42
+ linked: RelationListener | null
43
+ linkChanged: RelationListener | null
44
+ unlinked: RelationListener | null
45
+ linkFailed: RelationFailedListener | null
46
+ }
47
+
48
+ export type RelationDefinitionGroup = {
49
+ definitions: RelationDefinition[][],
50
+ keyMap: { [key: string | symbol]: [RelationType, number] },
51
+ }
52
+
53
+ export const generateRelationDefinitionGroup = (
54
+ relations?: { [key: string]: RelationDefinition },
55
+ ): RelationDefinitionGroup | null => {
56
+ if (relations === undefined) return null
57
+ const group = {
58
+ definitions: new Array(RELATION_TYPE_COUNT) as RelationDefinition[][],
59
+ keyMap: Object.create(null) as { [key: string]: [RelationType, number] },
60
+ } as RelationDefinitionGroup
61
+ const defs = group.definitions
62
+ const keyMap = group.keyMap
63
+ const keys = Object.keys(relations)
64
+ for (let i = 0; i < keys.length; i += 1) {
65
+ const key = keys[i]!
66
+ const relation = relations[key]!
67
+ const relationType = relation.type
68
+ if (defs[relationType]) {
69
+ keyMap[key] = [relationType, defs[relationType]!.length]
70
+ defs[relationType]!.push(relation)
71
+ } else {
72
+ keyMap[key] = [relationType, 0]
73
+ defs[relationType] = [relation]
74
+ }
75
+ }
76
+ return group
77
+ }
78
+
79
+ export const cloneRelationDefinitionGroup = (
80
+ group: RelationDefinitionGroup,
81
+ ): RelationDefinitionGroup => {
82
+ const newGroup = {
83
+ definitions: group.definitions.slice(),
84
+ keyMap: Object.assign(Object.create(null), group.keyMap) as
85
+ { [key: string]: [RelationType, number] },
86
+ }
87
+ return newGroup
88
+ }
89
+
90
+ export class Relation {
91
+ private _$comp: GeneralComponent
92
+ private _$group: RelationDefinitionGroup | null
93
+ private _$sharedGroup: boolean
94
+ private _$links: ({ target: GeneralComponent, def: RelationDefinition } | null)[][]
95
+
96
+ constructor(
97
+ associatedComponent: GeneralComponent,
98
+ group: RelationDefinitionGroup | null,
99
+ ) {
100
+ this._$comp = associatedComponent
101
+ const links = new Array(RELATION_TYPE_COUNT) as
102
+ ({ target: GeneralComponent, def: RelationDefinition } | null)[][]
103
+ if (group) {
104
+ for (let type = 0; type < RELATION_TYPE_COUNT; type += 1) {
105
+ const definitions = group.definitions[type]
106
+ if (definitions) {
107
+ const link = new Array(definitions.length) as
108
+ ({ target: GeneralComponent, def: RelationDefinition } | null)[]
109
+ for (let i = 0; i < definitions.length; i += 1) {
110
+ link[i] = null
111
+ }
112
+ links[type] = link
113
+ }
114
+ }
115
+ }
116
+ this._$group = group
117
+ this._$sharedGroup = true
118
+ this._$links = links
119
+ }
120
+
121
+ add(relation: RelationDefinition): symbol {
122
+ if (this._$sharedGroup) {
123
+ this._$sharedGroup = false
124
+ const group = this._$group
125
+ if (group) {
126
+ this._$group = {
127
+ definitions: group.definitions.slice(),
128
+ keyMap: Object.assign(Object.create(null), group.keyMap) as
129
+ { [key: string]: [RelationType, number] },
130
+ }
131
+ } else {
132
+ this._$group = {
133
+ definitions: new Array(RELATION_TYPE_COUNT) as RelationDefinition[][],
134
+ keyMap: Object.create(null) as { [key: string]: [RelationType, number] },
135
+ }
136
+ }
137
+ }
138
+ const key = Symbol('')
139
+ const defs = this._$group!.definitions
140
+ const keyMap = this._$group!.keyMap
141
+ const relationType = relation.type
142
+ if (defs[relationType]) {
143
+ keyMap[key] = [relationType, defs[relationType]!.length]
144
+ defs[relationType]!.push(relation)
145
+ } else {
146
+ keyMap[key] = [relationType, 0]
147
+ defs[relationType] = [relation]
148
+ }
149
+ const linksGroup = this._$links
150
+ if (linksGroup[relationType] === undefined) {
151
+ linksGroup[relationType] = [null]
152
+ } else {
153
+ linksGroup[relationType]!.push(null)
154
+ }
155
+ return key
156
+ }
157
+
158
+ triggerLinkEvent(
159
+ parentType: RelationType.ParentComponent
160
+ | RelationType.ParentNonVirtualNode
161
+ | RelationType.Ancestor,
162
+ isDetach: boolean,
163
+ ) {
164
+ const comp = this._$comp
165
+ const linksGroup = this._$links
166
+ const selfDefs = this._$group?.definitions[parentType]
167
+ if (!selfDefs) return
168
+ for (let i = 0; i < selfDefs.length; i += 1) {
169
+ const links = linksGroup[parentType]!
170
+ const oldLink = links[i]!
171
+ let newLink: { target: GeneralComponent, def: RelationDefinition } | null = null
172
+ const def = selfDefs[i]!
173
+ let parentBeheviorTest: GeneralBehavior
174
+ | TraitBehavior<{ [x: string]: unknown }, { [x: string]: unknown }>
175
+ | null
176
+ if (def.target instanceof Behavior || def.target instanceof TraitBehavior) {
177
+ parentBeheviorTest = def.target
178
+ } else {
179
+ const space = comp.getRootBehavior().ownerSpace
180
+ if (space) {
181
+ parentBeheviorTest = space._$getBehavior(def.target, def.domain) || null
182
+ } else {
183
+ parentBeheviorTest = null
184
+ }
185
+ }
186
+ if (parentBeheviorTest) {
187
+ const parentBehevior = parentBeheviorTest
188
+ if (!isDetach) {
189
+ let cur: Element = comp
190
+ for (;;) {
191
+ const next = cur.parentNode
192
+ if (!next) break
193
+ cur = next
194
+ if (cur instanceof VirtualNode) {
195
+ continue
196
+ }
197
+ if (cur instanceof Component) {
198
+ if (cur.hasBehavior(parentBehevior)) {
199
+ const parentRelation = cur._$relation
200
+ if (parentRelation) {
201
+ let rt
202
+ if (parentType === RelationType.ParentComponent) {
203
+ rt = RelationType.ChildComponent
204
+ } else if (parentType === RelationType.Ancestor) {
205
+ rt = RelationType.Descendant
206
+ } else {
207
+ rt = RelationType.ChildNonVirtualNode
208
+ }
209
+ const parentDefs = parentRelation._$group?.definitions[rt]
210
+ if (parentDefs) {
211
+ for (let j = 0; j < parentDefs.length; j += 1) {
212
+ const def = parentDefs[j]!
213
+ let requiredBehavior: GeneralBehavior
214
+ | TraitBehavior<{ [x: string]: unknown }, { [x: string]: unknown }>
215
+ | null
216
+ if (def.target instanceof Behavior || def.target instanceof TraitBehavior) {
217
+ requiredBehavior = def.target
218
+ } else {
219
+ const space = cur.getRootBehavior().ownerSpace
220
+ if (space) {
221
+ requiredBehavior = space._$getBehavior(def.target, def.domain) || null
222
+ } else {
223
+ requiredBehavior = null
224
+ }
225
+ }
226
+ if (requiredBehavior && this._$comp.hasBehavior(requiredBehavior)) {
227
+ newLink = {
228
+ target: cur as GeneralComponent,
229
+ def,
230
+ }
231
+ break
232
+ }
233
+ }
234
+ }
235
+ }
236
+ }
237
+ if (parentType === RelationType.ParentComponent) break
238
+ }
239
+ if (parentType === RelationType.ParentNonVirtualNode) break
240
+ }
241
+ }
242
+ }
243
+ links[i] = newLink
244
+ if (oldLink) {
245
+ const oldTarget = oldLink.target
246
+ const oldDef = oldLink.def
247
+ if ((!newLink || oldLink.target !== newLink.target || oldLink.def !== newLink.def)) {
248
+ if (oldDef.unlinked) {
249
+ safeCallback(
250
+ 'Relation Unlinked Callback',
251
+ oldDef.unlinked,
252
+ oldTarget.getMethodCaller(),
253
+ [comp.getMethodCaller()],
254
+ oldTarget,
255
+ )
256
+ }
257
+ if (def.unlinked) {
258
+ safeCallback(
259
+ 'Relation Unlinked Callback',
260
+ def.unlinked,
261
+ comp.getMethodCaller(),
262
+ [oldTarget.getMethodCaller()],
263
+ comp,
264
+ )
265
+ }
266
+ } else {
267
+ if (oldDef.linkChanged) {
268
+ safeCallback(
269
+ 'Relation Link Changed Callback',
270
+ oldDef.linkChanged,
271
+ oldTarget.getMethodCaller(),
272
+ [comp.getMethodCaller()],
273
+ oldTarget,
274
+ )
275
+ }
276
+ if (def.linkChanged) {
277
+ safeCallback(
278
+ 'Relation Link Changed Callback',
279
+ def.linkChanged,
280
+ comp.getMethodCaller(),
281
+ [oldTarget.getMethodCaller()],
282
+ comp,
283
+ )
284
+ }
285
+ }
286
+ }
287
+ if (newLink) {
288
+ const newTarget = newLink.target
289
+ const newDef = newLink.def
290
+ if (!oldLink || oldLink.target !== newLink.target || oldLink.def !== newLink.def) {
291
+ if (newDef.linked) {
292
+ safeCallback(
293
+ 'Relation Linked Callback',
294
+ newDef.linked,
295
+ newTarget.getMethodCaller(),
296
+ [comp.getMethodCaller()],
297
+ newTarget,
298
+ )
299
+ }
300
+ if (def.linked) {
301
+ safeCallback(
302
+ 'Relation Linked Callback',
303
+ def.linked,
304
+ comp.getMethodCaller(),
305
+ [newTarget.getMethodCaller()],
306
+ comp,
307
+ )
308
+ }
309
+ }
310
+ }
311
+ if (!isDetach && !newLink && def.linkFailed) {
312
+ safeCallback(
313
+ 'Relation Link Failed Callback',
314
+ def.linkFailed,
315
+ comp.getMethodCaller(),
316
+ [],
317
+ comp,
318
+ )
319
+ }
320
+ }
321
+ }
322
+
323
+ getLinkedTargets(key: string | symbol): GeneralComponent[] {
324
+ const typeWithIndex = this._$group?.keyMap[key]
325
+ if (!typeWithIndex) {
326
+ triggerWarning(`no relation "${String(key)}" found.`)
327
+ return []
328
+ }
329
+ const [type, index] = typeWithIndex
330
+ if (
331
+ type === RelationType.ParentComponent
332
+ || type === RelationType.ParentNonVirtualNode
333
+ || type === RelationType.Ancestor
334
+ ) {
335
+ const link = this._$links[type]?.[index]
336
+ if (link) return [link.target]
337
+ return []
338
+ }
339
+ const ret: GeneralComponent[] = []
340
+ const comp = this._$comp
341
+ const def = this._$group?.definitions[type]?.[index]
342
+ const dfs = (node: Element) => {
343
+ const children = node.childNodes
344
+ for (let i = 0; i < children.length; i += 1) {
345
+ const child = children[i]!
346
+ if (!(child instanceof Element)) continue
347
+ if (child instanceof VirtualNode) {
348
+ dfs(child)
349
+ continue
350
+ }
351
+ if (child instanceof Component) {
352
+ if (child._$relation) {
353
+ let links
354
+ if (type === RelationType.ChildComponent) {
355
+ links = child._$relation._$links[RelationType.ParentComponent]
356
+ } else if (type === RelationType.Descendant) {
357
+ links = child._$relation._$links[RelationType.Ancestor]
358
+ } else {
359
+ links = child._$relation._$links[RelationType.ParentNonVirtualNode]
360
+ }
361
+ if (links) {
362
+ for (let i = 0; i < links.length; i += 1) {
363
+ const link = links[i]!
364
+ if (link && link.target === comp && link.def === def) {
365
+ ret.push(child as GeneralComponent)
366
+ break
367
+ }
368
+ }
369
+ }
370
+ }
371
+ if (type === RelationType.Descendant) dfs(child)
372
+ } else {
373
+ if (type === RelationType.ChildComponent || type === RelationType.Descendant) dfs(child)
374
+ }
375
+ }
376
+ }
377
+ dfs(this._$comp)
378
+ return ret
379
+ }
380
+ }
package/src/render.ts ADDED
@@ -0,0 +1,25 @@
1
+ import {
2
+ safeCallback,
3
+ } from './func_arr'
4
+ import {
5
+ Element,
6
+ } from './element'
7
+ import {
8
+ GeneralBackendContext,
9
+ } from './node'
10
+
11
+ const triggerRenderOnContext = (
12
+ context: GeneralBackendContext,
13
+ cb: ((err: Error | null) => void) | null,
14
+ ) => {
15
+ context.render(() => {
16
+ if (typeof cb === 'function') {
17
+ safeCallback('render', cb, context, [null])
18
+ }
19
+ })
20
+ }
21
+
22
+ export const triggerRender = (element: Element, callback?: (err: Error | null) => void) => {
23
+ const context = element.getBackendContext()
24
+ triggerRenderOnContext(context, callback || null)
25
+ }
@@ -0,0 +1,218 @@
1
+ import {
2
+ Element,
3
+ Component,
4
+ VirtualNode,
5
+ ShadowRoot,
6
+ ComponentSpace,
7
+ } from '.'
8
+
9
+ const enum SegmentRelation {
10
+ Child,
11
+ Descendant,
12
+ CrossShadowDescendant,
13
+ }
14
+
15
+ type Segment = {
16
+ id: string
17
+ classes: string[]
18
+ relation: SegmentRelation
19
+ }
20
+
21
+ type Union = Segment[]
22
+
23
+ // eslint-disable-next-line arrow-body-style
24
+ const getOwnerSpace = (node: Element) => {
25
+ return node.ownerShadowRoot?.getHostNode().getRootBehavior().ownerSpace
26
+ }
27
+
28
+ /** A parsed selector that can be used in selector queries */
29
+ export class ParsedSelector {
30
+ unions: Union[] = []
31
+
32
+ private static _$parseSegment(str: string, relation: SegmentRelation): Segment | null {
33
+ const matches = /^(#[_a-zA-Z][-_a-zA-Z0-9:]*|)((?:\.-?[_a-zA-Z][-_a-zA-Z0-9]*)+|)$/.exec(str)
34
+ if (!matches) return null
35
+ const id = matches[1]!.slice(1)
36
+ const classes = matches[2]!.split('.')
37
+ classes.shift()
38
+ if (!id && !classes.length) return null
39
+ return {
40
+ id,
41
+ classes,
42
+ relation,
43
+ }
44
+ }
45
+
46
+ constructor(str: string) {
47
+ const union = String(str || '').split(',')
48
+ for (let i = 0; i < union.length; i += 1) {
49
+ const segments = union[i]!.split(/( |\t|>+)/g)
50
+ const parsedSegs: Segment[] = []
51
+ let relation = SegmentRelation.Descendant
52
+ let j = 0
53
+ for (; j < segments.length; j += 1) {
54
+ const seg = segments[j]
55
+ if (!seg || seg === ' ' || seg === '\t' || seg === '>>') continue
56
+ if (seg[0] === '>') {
57
+ if (relation !== SegmentRelation.Descendant) break
58
+ if (seg.length === 3) {
59
+ relation = SegmentRelation.CrossShadowDescendant
60
+ } else {
61
+ relation = SegmentRelation.Child
62
+ }
63
+ continue
64
+ }
65
+ const parsedSeg = ParsedSelector._$parseSegment(seg, relation)
66
+ relation = SegmentRelation.Descendant
67
+ if (!parsedSeg) break
68
+ parsedSegs.push(parsedSeg)
69
+ }
70
+ if (j !== segments.length) continue
71
+ if (parsedSegs.length) this.unions.push(parsedSegs)
72
+ }
73
+ }
74
+
75
+ /** Whether the selector is empty */
76
+ isEmpty(): boolean {
77
+ return this.unions.length === 0
78
+ }
79
+
80
+ private static _$testSelectorSegment(
81
+ root: Element | null,
82
+ ownerSpace: ComponentSpace,
83
+ node: Element,
84
+ segments: Segment[],
85
+ offset: number,
86
+ relation: SegmentRelation,
87
+ ): boolean {
88
+ if (node === root) return false
89
+ const segment = segments[offset]!
90
+ // test whether current node matches
91
+ let match = true
92
+ if (getOwnerSpace(node) !== ownerSpace) match = false
93
+ else if (segment.id && segment.id !== node.id) match = false
94
+ const classes = segment.classes
95
+ for (let i = 0; match && i < classes.length; i += 1) {
96
+ if (!node.classList?.contains(classes[i]!)) match = false
97
+ }
98
+ if (!match && relation === SegmentRelation.Child) return false
99
+ let nextNode: Element | null = node
100
+ if (match && offset === 0) {
101
+ // if matches the first segment, check whether root is in the same shadow tree
102
+ if (root === null) return true
103
+ for (nextNode = nextNode.parentNode; nextNode; nextNode = nextNode.parentNode) {
104
+ if (nextNode === root) return true
105
+ }
106
+ if (relation !== SegmentRelation.CrossShadowDescendant) return false
107
+ nextNode = node
108
+ match = false
109
+ }
110
+ // check whether ancestors matches
111
+ const nextRelation = match ? segment.relation : relation
112
+ do {
113
+ if (!nextNode.parentNode) {
114
+ if (nextRelation === SegmentRelation.CrossShadowDescendant) {
115
+ nextNode = nextNode instanceof ShadowRoot ? nextNode.getHostNode() : null
116
+ } else if (relation === SegmentRelation.CrossShadowDescendant) {
117
+ match = false
118
+ nextNode = nextNode instanceof ShadowRoot ? nextNode.getHostNode() : null
119
+ } else {
120
+ nextNode = null
121
+ }
122
+ } else {
123
+ nextNode = nextNode.parentNode
124
+ }
125
+ if (nextNode === root) nextNode = null
126
+ } while (nextNode instanceof VirtualNode)
127
+ if (!nextNode) return false
128
+ if (match) {
129
+ // if matches, try match ancestors
130
+ const matchRes = ParsedSelector._$testSelectorSegment(
131
+ root,
132
+ ownerSpace,
133
+ nextNode,
134
+ segments,
135
+ offset - 1,
136
+ nextRelation,
137
+ )
138
+ if (matchRes) return true
139
+ if (relation !== SegmentRelation.CrossShadowDescendant) return false
140
+ }
141
+ return ParsedSelector._$testSelectorSegment(
142
+ root,
143
+ ownerSpace,
144
+ nextNode,
145
+ segments,
146
+ offset,
147
+ relation,
148
+ )
149
+ }
150
+
151
+ /**
152
+ * Test whether the specified node matches the selector
153
+ *
154
+ * If `root` is specified, than the selector is match inside this subtree;
155
+ * otherwise it match in the whole tree.
156
+ */
157
+ testSelector(
158
+ root: Element | null,
159
+ node: Element,
160
+ ): boolean {
161
+ if (node instanceof VirtualNode) return false
162
+ const union = this.unions
163
+ let ownerSpace: ComponentSpace | undefined
164
+ if (root !== null) {
165
+ ownerSpace = getOwnerSpace(root) || getOwnerSpace(node)
166
+ } else {
167
+ ownerSpace = getOwnerSpace(node)
168
+ }
169
+ if (ownerSpace === undefined) return false
170
+ for (let i = 0; i < union.length; i += 1) {
171
+ const segments = union[i]!
172
+ const matched = ParsedSelector._$testSelectorSegment(
173
+ root,
174
+ ownerSpace,
175
+ node,
176
+ segments,
177
+ segments.length - 1,
178
+ SegmentRelation.Child,
179
+ )
180
+ if (matched) return true
181
+ }
182
+ return false
183
+ }
184
+
185
+ /** Queries an element or elements that matches this selector */
186
+ query(root: Element, findOne: boolean): Element[] | Element | null {
187
+ const ret: Element[] = []
188
+ const rec = (root: Element, node: Element, findOne: boolean): Element[] | Element | null => {
189
+ if (this.testSelector(root, node)) {
190
+ if (findOne) return node
191
+ ret.push(node)
192
+ }
193
+ if (node instanceof Component) {
194
+ const shadowRoot = node.getShadowRoot()
195
+ if (shadowRoot) {
196
+ const r = rec(root, shadowRoot, findOne)
197
+ if (r && findOne) {
198
+ return r
199
+ }
200
+ }
201
+ }
202
+ const children = node.childNodes
203
+ for (let i = 0; i < children.length; i += 1) {
204
+ const child = children[i]
205
+ if (child instanceof Element) {
206
+ const r = rec(root, child, findOne)
207
+ if (r && findOne) {
208
+ return r
209
+ }
210
+ }
211
+ }
212
+ return null
213
+ }
214
+ const r = rec(root, root, findOne)
215
+ if (findOne) return r
216
+ return ret
217
+ }
218
+ }