aptechka 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 (115) hide show
  1. package/.prettierignore +16 -0
  2. package/.prettierrc +9 -0
  3. package/.vscode/extensions.json +4 -0
  4. package/.vscode/launch.json +11 -0
  5. package/.vscode/settings.json +18 -0
  6. package/README.md +0 -0
  7. package/index.html +32 -0
  8. package/package.json +272 -0
  9. package/public/vite.svg +1 -0
  10. package/src/packages/animation/Animated.ts +189 -0
  11. package/src/packages/animation/Damped.ts +39 -0
  12. package/src/packages/animation/Tweened.ts +51 -0
  13. package/src/packages/animation/index.ts +10 -0
  14. package/src/packages/attribute/index.ts +59 -0
  15. package/src/packages/canvas-2d/index.ts +137 -0
  16. package/src/packages/controls/Controls.ts +15 -0
  17. package/src/packages/controls/KeyboardControls.ts +63 -0
  18. package/src/packages/controls/LinearControls.ts +27 -0
  19. package/src/packages/controls/User.ts +20 -0
  20. package/src/packages/controls/WheelControls.ts +92 -0
  21. package/src/packages/controls/index.ts +5 -0
  22. package/src/packages/css-unit-parser/index.ts +32 -0
  23. package/src/packages/custom-element/index.ts +19 -0
  24. package/src/packages/device/Device.ts +113 -0
  25. package/src/packages/device/Viewport.ts +67 -0
  26. package/src/packages/device/index.ts +2 -0
  27. package/src/packages/element-constructor/ElementConstructor.ts +577 -0
  28. package/src/packages/element-constructor/htmlTags.ts +679 -0
  29. package/src/packages/element-constructor/index.ts +4 -0
  30. package/src/packages/element-constructor/specialObjects.ts +8 -0
  31. package/src/packages/element-constructor/svgTags.ts +588 -0
  32. package/src/packages/en3/attachments/En3SourceManager.ts +116 -0
  33. package/src/packages/en3/core/en3.ts +306 -0
  34. package/src/packages/en3/index.ts +52 -0
  35. package/src/packages/en3/instances/en3LazyLoader.ts +22 -0
  36. package/src/packages/en3/libs/MeshoptDecoder.js +138 -0
  37. package/src/packages/en3/loaders/en3GLTFLoader.ts +54 -0
  38. package/src/packages/en3/loaders/en3TextureLoader.ts +3 -0
  39. package/src/packages/en3/objects/En3Clip.ts +53 -0
  40. package/src/packages/en3/objects/En3ClipHelpers.ts +12 -0
  41. package/src/packages/en3/objects/En3GLTF.ts +35 -0
  42. package/src/packages/en3/objects/En3Image.ts +18 -0
  43. package/src/packages/en3/objects/En3ImageLike.ts +101 -0
  44. package/src/packages/en3/objects/En3SourceConsumer.ts +5 -0
  45. package/src/packages/en3/objects/En3Video.ts +88 -0
  46. package/src/packages/en3/test/En3HTML.ts +55 -0
  47. package/src/packages/en3/test/En3ModifiedMaterial.ts +221 -0
  48. package/src/packages/en3/test/En3Raycaster.ts +187 -0
  49. package/src/packages/en3/utils/coverTexture.ts +29 -0
  50. package/src/packages/en3/utils/dispose.ts +27 -0
  51. package/src/packages/en3/utils/traverseMaterials.ts +10 -0
  52. package/src/packages/en3/utils/traverseMeshes.ts +9 -0
  53. package/src/packages/image/index.ts +19 -0
  54. package/src/packages/intersector/index.ts +83 -0
  55. package/src/packages/ladder/index.ts +112 -0
  56. package/src/packages/layout-box/index.ts +417 -0
  57. package/src/packages/loading/index.ts +131 -0
  58. package/src/packages/measurer/CumulativeOffsetLeft.ts +8 -0
  59. package/src/packages/measurer/CumulativeOffsetTop.ts +8 -0
  60. package/src/packages/measurer/Meaurer.ts +38 -0
  61. package/src/packages/measurer/index.ts +3 -0
  62. package/src/packages/media/index.ts +38 -0
  63. package/src/packages/morph/Link.ts +32 -0
  64. package/src/packages/morph/Morph.ts +246 -0
  65. package/src/packages/morph/index.ts +10 -0
  66. package/src/packages/notifier/index.ts +41 -0
  67. package/src/packages/order/index.ts +14 -0
  68. package/src/packages/resizer/index.ts +55 -0
  69. package/src/packages/router/Link.ts +33 -0
  70. package/src/packages/router/Route.ts +152 -0
  71. package/src/packages/router/RouteElement.ts +34 -0
  72. package/src/packages/router/Router.ts +190 -0
  73. package/src/packages/router/index.ts +13 -0
  74. package/src/packages/scroll/ScrollElement.ts +618 -0
  75. package/src/packages/scroll/ScrollUserElement.ts +21 -0
  76. package/src/packages/scroll/ScrollbarElement.ts +170 -0
  77. package/src/packages/scroll/index.ts +2 -0
  78. package/src/packages/scroll-entries/index.ts +74 -0
  79. package/src/packages/source/SourceClass.ts +77 -0
  80. package/src/packages/source/SourceElement.ts +177 -0
  81. package/src/packages/source/SourceManager.ts +61 -0
  82. package/src/packages/source/SourceSet.ts +52 -0
  83. package/src/packages/source/index.ts +8 -0
  84. package/src/packages/store/Composed.ts +33 -0
  85. package/src/packages/store/Derived.ts +24 -0
  86. package/src/packages/store/DerivedArray.ts +36 -0
  87. package/src/packages/store/Resource.ts +38 -0
  88. package/src/packages/store/Store.ts +144 -0
  89. package/src/packages/store/StoreRegistry.ts +105 -0
  90. package/src/packages/store/index.ts +23 -0
  91. package/src/packages/ticker/index.ts +173 -0
  92. package/src/packages/utils/array.ts +3 -0
  93. package/src/packages/utils/attributes.ts +19 -0
  94. package/src/packages/utils/browser.ts +2 -0
  95. package/src/packages/utils/canvas.ts +46 -0
  96. package/src/packages/utils/collisions.ts +12 -0
  97. package/src/packages/utils/coordinates.ts +40 -0
  98. package/src/packages/utils/decoding.ts +11 -0
  99. package/src/packages/utils/dev.ts +5 -0
  100. package/src/packages/utils/dom.ts +48 -0
  101. package/src/packages/utils/easings.ts +69 -0
  102. package/src/packages/utils/file.ts +17 -0
  103. package/src/packages/utils/function.ts +29 -0
  104. package/src/packages/utils/index.ts +61 -0
  105. package/src/packages/utils/layout.ts +22 -0
  106. package/src/packages/utils/math.ts +74 -0
  107. package/src/packages/utils/number.ts +26 -0
  108. package/src/packages/utils/object.ts +108 -0
  109. package/src/packages/utils/string.ts +49 -0
  110. package/src/packages/utils/ts-shape.ts +25 -0
  111. package/src/packages/utils/ts-utility.ts +47 -0
  112. package/src/packages/video/index.ts +39 -0
  113. package/src/playground/index.ts +0 -0
  114. package/tsconfig.json +31 -0
  115. package/vite.config.ts +65 -0
@@ -0,0 +1,246 @@
1
+ import { Notifier } from '$packages/notifier'
2
+ import { isBrowser } from '$packages/utils'
3
+ import { Link } from './Link'
4
+
5
+ export type MorphHistoryAction = 'replace' | 'push' | 'none'
6
+
7
+ export interface MorphParameters {
8
+ base?: string
9
+ waitForHeadToLoad?: boolean
10
+ cachePages?: boolean
11
+ }
12
+
13
+ export interface MorphNavigationEntry {
14
+ pathname: string
15
+ isCached: boolean
16
+ }
17
+
18
+ export interface MorphPreprocessorEntry extends MorphNavigationEntry {
19
+ resolve: () => void
20
+ reject: () => void
21
+ }
22
+
23
+ export type MorphPreprocessor = (entry: MorphPreprocessorEntry) => void
24
+
25
+ export type MorphNavigationCallback = (entry: MorphNavigationEntry) => void
26
+
27
+ export type MorphPostprocessor = MorphNavigationCallback
28
+
29
+ export class Morph {
30
+ #base: string = null!
31
+ #waitForHeadToLoad: boolean = null!
32
+ #cachePages: boolean = null!
33
+ #morphElements: Array<HTMLElement> = null!
34
+ #links: Array<Link> = []
35
+ #domParser: DOMParser = new DOMParser()
36
+ #cache: Map<string, Document> = new Map()
37
+ #candidatePathname: string | undefined
38
+ #currentPathname: string = null!
39
+
40
+ public preprocessor?: MorphPreprocessor
41
+ public postprocessor?: MorphPostprocessor
42
+
43
+ #beforeNavigationEvent = new Notifier<MorphNavigationCallback>()
44
+ #afterNavigationEvent = new Notifier<MorphNavigationCallback>()
45
+
46
+ constructor(parameters?: MorphParameters) {
47
+ if (isBrowser) {
48
+ this.#base = parameters?.base || '/'
49
+
50
+ if (parameters?.base) {
51
+ this.#base = parameters.base
52
+
53
+ if (!parameters.base.endsWith('/')) {
54
+ this.#base += '/'
55
+ }
56
+ } else {
57
+ this.#base = '/'
58
+ }
59
+
60
+ this.#waitForHeadToLoad = parameters?.waitForHeadToLoad === false ? false : true
61
+ this.#cachePages = parameters?.cachePages === false ? false : true
62
+
63
+ this.#morphElements = this.#getMorphElements(document)
64
+
65
+ this.#currentPathname = location.pathname
66
+
67
+ this.#findLinks()
68
+
69
+ addEventListener('popstate', this.#popStateListener)
70
+ }
71
+ }
72
+
73
+ public beforeNavigationEvent(callback: MorphNavigationCallback) {
74
+ return this.#beforeNavigationEvent.subscribe(callback)
75
+ }
76
+
77
+ public afterNavigationEvent(callback: MorphNavigationCallback) {
78
+ return this.#afterNavigationEvent.subscribe(callback)
79
+ }
80
+
81
+ public async navigate(pathname: string, historyAction: MorphHistoryAction = 'push') {
82
+ pathname = this.#preparePathname(pathname)
83
+
84
+ if (this.#candidatePathname === pathname || this.#currentPathname === pathname) {
85
+ return
86
+ }
87
+
88
+ this.#candidatePathname = pathname
89
+
90
+ const isCached = this.#cache.has(pathname)
91
+
92
+ try {
93
+ let isOkToSwitch = true
94
+
95
+ if (this.preprocessor) {
96
+ try {
97
+ await new Promise<void>((resolve, reject) => {
98
+ this.preprocessor?.({ pathname, resolve, reject, isCached })
99
+ })
100
+ } catch (e: any) {
101
+ if (e) {
102
+ console.error(e)
103
+ } else {
104
+ console.log('Route change canceled')
105
+ }
106
+ isOkToSwitch = false
107
+ }
108
+ }
109
+
110
+ this.#beforeNavigationEvent.notify({
111
+ pathname,
112
+ isCached,
113
+ })
114
+
115
+ if (!isOkToSwitch || this.#candidatePathname !== pathname) {
116
+ return
117
+ }
118
+
119
+ const newDocument = await this.#fetchDocument(pathname)
120
+
121
+ if (this.#cachePages) {
122
+ this.#cache.set(pathname, newDocument)
123
+ }
124
+
125
+ if (this.#candidatePathname !== pathname) {
126
+ return
127
+ }
128
+
129
+ const currentHeadChildren = Array.from(document.head.children)
130
+ const newHeadChildren = Array.from((newDocument.head.cloneNode(true) as HTMLElement).children)
131
+
132
+ const identicalHeadChildren = this.#intersectElements(currentHeadChildren, newHeadChildren)
133
+ const removeHeadChildren = this.#excludeElements(currentHeadChildren, identicalHeadChildren)
134
+ const addHeadChildren = this.#excludeElements(newHeadChildren, identicalHeadChildren)
135
+
136
+ removeHeadChildren.forEach((child) => child.remove())
137
+ addHeadChildren.forEach((child) => document.head.appendChild(child))
138
+
139
+ const elementsWithLoad = addHeadChildren.filter(
140
+ (child) =>
141
+ child.tagName === 'STYLE' || child.tagName === 'SCRIPT' || child.tagName === 'LINK'
142
+ ) as Array<HTMLLinkElement>
143
+
144
+ if (this.#waitForHeadToLoad && elementsWithLoad.length) {
145
+ await new Promise<void>(async (res) => {
146
+ let counter = 0
147
+
148
+ for await (const element of elementsWithLoad) {
149
+ element.onload = () => {
150
+ counter++
151
+
152
+ if (counter === elementsWithLoad.length) {
153
+ res()
154
+ }
155
+ }
156
+ }
157
+ })
158
+ }
159
+
160
+ const newMorphElements = this.#getMorphElements(newDocument)
161
+
162
+ this.#morphElements.forEach((morphElement, i) => {
163
+ const newMorphElement = newMorphElements[i]
164
+ morphElement.innerHTML = newMorphElement.innerHTML
165
+ })
166
+
167
+ this.#currentPathname = pathname
168
+
169
+ if (historyAction === 'push') {
170
+ history.pushState(pathname, '', pathname + location.search)
171
+ } else if (historyAction === 'replace') {
172
+ history.replaceState(pathname, '', pathname + location.search)
173
+ }
174
+
175
+ this.#findLinks()
176
+
177
+ this.postprocessor?.({ pathname, isCached })
178
+ this.#afterNavigationEvent.notify({ pathname, isCached })
179
+ } catch (e) {
180
+ console.error(e)
181
+ }
182
+
183
+ this.#candidatePathname = undefined
184
+ }
185
+
186
+ async #fetchDocument(pathname: string) {
187
+ const cahcnedDocument = this.#cache.get(pathname)
188
+
189
+ if (cahcnedDocument) {
190
+ return cahcnedDocument
191
+ }
192
+
193
+ const fetchResult = await fetch(pathname)
194
+ const text = await fetchResult.text()
195
+ const document = this.#domParser.parseFromString(text, 'text/html')
196
+ return document
197
+ }
198
+
199
+ #preparePathname(pathname: string) {
200
+ pathname = pathname.replace(this.#base, '')
201
+
202
+ if (pathname.startsWith('/')) {
203
+ pathname = pathname.slice(1)
204
+ }
205
+
206
+ return this.#base + pathname
207
+ }
208
+
209
+ #findLinks() {
210
+ const linkElements = [...document.documentElement.querySelectorAll('a')].filter((a) =>
211
+ a.getAttribute('href')?.startsWith('/')
212
+ )
213
+
214
+ this.#links.forEach((link) => link.destroy())
215
+
216
+ this.#links = linkElements.map((element) => new Link(element, this))
217
+ }
218
+
219
+ #getMorphElements(document: Document) {
220
+ const elements = document.querySelectorAll<HTMLElement>('[data-morph]')
221
+ return elements.length ? [...elements] : [document.body]
222
+ }
223
+
224
+ #intersectElements(elements: Array<Element>, elementsToIntersect: Array<Element>) {
225
+ return elements.filter((element) =>
226
+ elementsToIntersect.find(
227
+ (elementToIntersect) => elementToIntersect.outerHTML === element.outerHTML
228
+ )
229
+ )
230
+ }
231
+
232
+ #excludeElements(elements: Array<Element>, elementsToExclude: Array<Element>) {
233
+ return elements.filter(
234
+ (element) =>
235
+ !elementsToExclude.find(
236
+ (elementToExclude) => elementToExclude.outerHTML === element.outerHTML
237
+ )
238
+ )
239
+ }
240
+
241
+ #popStateListener = (event: PopStateEvent) => {
242
+ if (event.state) {
243
+ this.navigate(event.state, 'none')
244
+ }
245
+ }
246
+ }
@@ -0,0 +1,10 @@
1
+ export {
2
+ Morph,
3
+ type MorphPostprocessor,
4
+ type MorphNavigationCallback,
5
+ type MorphPreprocessor,
6
+ type MorphPreprocessorEntry,
7
+ type MorphNavigationEntry,
8
+ type MorphParameters,
9
+ type MorphHistoryAction,
10
+ } from './Morph'
@@ -0,0 +1,41 @@
1
+ export type ProviderCallback = (...args: any[]) => void
2
+
3
+ interface NotifierSubscriber {
4
+ callback: ProviderCallback
5
+ order: number
6
+ }
7
+
8
+ export class Notifier<Callback extends ProviderCallback = ProviderCallback> {
9
+ #subscribers: Array<NotifierSubscriber> = []
10
+
11
+ public close() {
12
+ this.#subscribers = []
13
+ }
14
+
15
+ public subscribe(callback: Callback, order: number = 0) {
16
+ if (this.#subscribers.find((subscriber) => subscriber.callback === callback)) {
17
+ return () => {}
18
+ }
19
+
20
+ this.#subscribers.push({
21
+ callback,
22
+ order,
23
+ })
24
+
25
+ this.#subscribers = this.#subscribers.sort((a, b) => a.order - b.order)
26
+
27
+ return () => {
28
+ this.unsubscribe(callback)
29
+ }
30
+ }
31
+
32
+ public unsubscribe(callback: Callback) {
33
+ this.#subscribers = this.#subscribers.filter((subscriber) => subscriber.callback !== callback)
34
+ }
35
+
36
+ public notify(...parameters: Parameters<Callback>) {
37
+ for (const subscriber of this.#subscribers) {
38
+ subscriber.callback(...parameters)
39
+ }
40
+ }
41
+ }
@@ -0,0 +1,14 @@
1
+ export enum RESIZE_ORDER {
2
+ DEVICE = -100000,
3
+ MEDIA,
4
+ SOURCE_MANAGER,
5
+ SCROLL,
6
+ LAYOUT_BOX,
7
+ EN3 = 100000,
8
+ }
9
+
10
+ export enum TICK_ORDER {
11
+ SCROLL = -100000,
12
+ LAYOUT_BOX,
13
+ EN3 = 100000,
14
+ }
@@ -0,0 +1,55 @@
1
+ import { Notifier } from '$packages/notifier'
2
+ import { debounce, isBrowser } from '$packages/utils'
3
+
4
+ export type ResizerCallback = () => void
5
+
6
+ export const dispatchResizeEvent = debounce((cause?: string) => {
7
+ if (cause) {
8
+ window.dispatchEvent(
9
+ new CustomEvent('resize', {
10
+ detail: {
11
+ cause: cause,
12
+ },
13
+ })
14
+ )
15
+ } else {
16
+ window.dispatchEvent(new Event('resize'))
17
+ }
18
+ }, 0)
19
+
20
+ class Resizer extends Notifier<ResizerCallback> {
21
+ #isResizeScheduled = false
22
+
23
+ constructor() {
24
+ super()
25
+
26
+ if (isBrowser) {
27
+ addEventListener('resize', this.#resizeListener)
28
+ this.#resizeListener()
29
+ }
30
+ }
31
+
32
+ public subscribe(callback: ResizerCallback, order?: number) {
33
+ const unsub = super.subscribe(callback, order)
34
+
35
+ if (!this.#isResizeScheduled) {
36
+ callback()
37
+ }
38
+
39
+ return unsub
40
+ }
41
+
42
+ #resizeListener = () => {
43
+ if (!this.#isResizeScheduled) {
44
+ this.#isResizeScheduled = true
45
+ this.#resize()
46
+ }
47
+ }
48
+
49
+ #resize = debounce(() => {
50
+ this.notify()
51
+ this.#isResizeScheduled = false
52
+ }, 0)
53
+ }
54
+
55
+ export const resizer = new Resizer()
@@ -0,0 +1,33 @@
1
+ import { Router, RouterHistoryAction } from './Router'
2
+
3
+ export class Link {
4
+ #router: Router
5
+ #element: HTMLElement
6
+ #pathname: string
7
+ #historyAction: RouterHistoryAction
8
+
9
+ constructor(router: Router, element: HTMLElement) {
10
+ this.#router = router
11
+ this.#element = element
12
+ this.#pathname = this.#element.getAttribute('href') || '/'
13
+ this.#historyAction =
14
+ (this.#element.getAttribute('data-history-action') as RouterHistoryAction) || 'push'
15
+
16
+ this.#element.addEventListener('click', this.#clickListener)
17
+
18
+ if (location.pathname === this.#pathname) {
19
+ this.#element.classList.add('current')
20
+ }
21
+ }
22
+
23
+ public destroy() {
24
+ this.#element.removeEventListener('click', this.#clickListener)
25
+ this.#element.classList.remove('current')
26
+ }
27
+
28
+ #clickListener = (e: Event) => {
29
+ e.preventDefault()
30
+
31
+ this.#router.navigate(this.#pathname, this.#historyAction)
32
+ }
33
+ }
@@ -0,0 +1,152 @@
1
+ import { isBrowser } from '$packages/utils'
2
+ import { RouteElement, RouteParameters } from './RouteElement'
3
+
4
+ export type RouteModule = () => Promise<any>
5
+
6
+ export class Route {
7
+ #pattern: string
8
+ #module: RouteModule
9
+ #urlPattern: URLPattern
10
+ #elementConstructor: typeof RouteElement | null
11
+ #element: RouteElement | null
12
+ #isActive: boolean
13
+ #outlet: HTMLElement | ShadowRoot | null
14
+ #mutationObserver: MutationObserver = null!
15
+ #permanentHeadNodes: Array<Node> = []
16
+ #temporalHeadNodes: Array<Node> = []
17
+
18
+ constructor(pattern: string, module: RouteModule) {
19
+ this.#pattern = pattern
20
+ this.#module = module
21
+ this.#urlPattern = new URLPattern({ pathname: this.#pattern })
22
+ this.#elementConstructor = null
23
+ this.#element = null
24
+ this.#isActive = false
25
+ this.#outlet = null
26
+
27
+ if (isBrowser) {
28
+ this.#mutationObserver = new MutationObserver((mutations) => {
29
+ const mutation = mutations[0]
30
+
31
+ mutation.addedNodes.forEach((addedNode) => {
32
+ if (!this.#elementConstructor) {
33
+ this.#permanentHeadNodes.push(addedNode)
34
+ } else {
35
+ this.#temporalHeadNodes.push(addedNode)
36
+ }
37
+ })
38
+ })
39
+ }
40
+ }
41
+
42
+ public get pattern() {
43
+ return this.#pattern
44
+ }
45
+
46
+ public get urlPattern() {
47
+ return this.#urlPattern
48
+ }
49
+
50
+ public get isActive() {
51
+ return this.#isActive
52
+ }
53
+
54
+ public get element() {
55
+ return this.#element
56
+ }
57
+
58
+ public get outlet() {
59
+ return this.#outlet
60
+ }
61
+
62
+ public testPathname(pathname: string) {
63
+ return this.urlPattern.test({ pathname: pathname })
64
+ }
65
+
66
+ public async render(containerElement: HTMLElement | ShadowRoot, pathname: string) {
67
+ this.#mutationObserver.observe(document.head, { childList: true, subtree: true })
68
+
69
+ if (!this.#elementConstructor) {
70
+ const content = await this.#module()
71
+
72
+ this.#temporalHeadNodes = [...this.#permanentHeadNodes]
73
+
74
+ if (typeof content.default === 'function') {
75
+ this.#elementConstructor = content.default
76
+ customElements.define('e-' + this.#elementConstructor?.name.toLowerCase(), content.default)
77
+ }
78
+ } else {
79
+ this.#permanentHeadNodes.forEach((node) => {
80
+ document.head.appendChild(node)
81
+ })
82
+ }
83
+
84
+ await this.#waitHeadNodesLoad()
85
+
86
+ if (this.#elementConstructor) {
87
+ const v = this.#urlPattern.exec({ pathname })
88
+ const pathnameParams = v?.pathname.groups || {}
89
+ const searchParams = Object.fromEntries(new URLSearchParams(location.search))
90
+
91
+ const routeParameters: RouteParameters<any, any> = {
92
+ pathnameParams,
93
+ searchParams,
94
+ }
95
+
96
+ this.#element = new this.#elementConstructor(routeParameters)
97
+
98
+ containerElement.appendChild(this.#element)
99
+
100
+ this.#outlet =
101
+ this.#element.querySelector<HTMLElement>('[data-outlet]') ||
102
+ this.#element.shadowRoot?.querySelector<HTMLElement>('[data-outlet]') ||
103
+ this.#element.shadowRoot ||
104
+ this.#element
105
+
106
+ this.#isActive = true
107
+ }
108
+
109
+ this.#mutationObserver.disconnect()
110
+ }
111
+
112
+ public close() {
113
+ this.#mutationObserver.disconnect()
114
+ this.#element?.remove()
115
+ this.#isActive = false
116
+
117
+ this.#temporalHeadNodes.forEach((node) => document.head.removeChild(node))
118
+ this.#temporalHeadNodes = []
119
+ }
120
+
121
+ public getAnchorElements() {
122
+ let links: Array<HTMLAnchorElement> = []
123
+
124
+ if (this.#element) {
125
+ links = [...this.#element.querySelectorAll<HTMLAnchorElement>('a')]
126
+ }
127
+
128
+ if (this.#element?.shadowRoot) {
129
+ links = [...links, ...this.#element.shadowRoot.querySelectorAll<HTMLAnchorElement>('a')]
130
+ }
131
+
132
+ return links
133
+ }
134
+
135
+ async #waitHeadNodesLoad() {
136
+ const nodes = this.#permanentHeadNodes.filter((node) => {
137
+ if (node instanceof HTMLElement) {
138
+ return node.tagName === 'STYLE' || node.tagName === 'SCRIPT' || node.tagName === 'LINK'
139
+ }
140
+
141
+ return false
142
+ }) as Array<HTMLStyleElement | HTMLScriptElement | HTMLLinkElement>
143
+
144
+ for await (const node of nodes) {
145
+ await new Promise<void>((res) => {
146
+ node.onload = () => {
147
+ res()
148
+ }
149
+ })
150
+ }
151
+ }
152
+ }
@@ -0,0 +1,34 @@
1
+ import { CustomElement } from '$packages/custom-element'
2
+
3
+ export type RouteURLParams<T extends string = string> = Partial<{ [key in T]: string }>
4
+
5
+ export type RouteParameters<
6
+ PathnameParams extends string = string,
7
+ SearchParams extends string = string
8
+ > = {
9
+ pathnameParams: RouteURLParams<PathnameParams>
10
+ searchParams: RouteURLParams<SearchParams>
11
+ }
12
+
13
+ export class RouteElement<
14
+ PathnameParams extends string = string,
15
+ SearchParams extends string = string
16
+ > extends CustomElement {
17
+ #pathnameParams: RouteURLParams<PathnameParams>
18
+ #searchParams: RouteURLParams<SearchParams>
19
+
20
+ constructor(parameters: RouteParameters<PathnameParams, SearchParams>) {
21
+ super()
22
+
23
+ this.#pathnameParams = parameters.pathnameParams
24
+ this.#searchParams = parameters.searchParams
25
+ }
26
+
27
+ public get pathnameParams() {
28
+ return this.#pathnameParams
29
+ }
30
+
31
+ public get searchParams() {
32
+ return this.#searchParams
33
+ }
34
+ }