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,417 @@
1
+ import { cssUnitParser } from '$packages/css-unit-parser'
2
+ import { Ladder } from '$packages/ladder'
3
+ import { TICK_ORDER } from '$packages/order'
4
+ import { resizer } from '$packages/resizer'
5
+ import { scrollEnties } from '$packages/scroll-entries'
6
+ import { StoreCallback, StoreEntry } from '$packages/store'
7
+ import { ticker } from '$packages/ticker'
8
+ import {
9
+ ElementOrSelector,
10
+ Axes3D,
11
+ Axes2D,
12
+ isBrowser,
13
+ getCumulativeOffsetLeft,
14
+ getCumulativeOffsetTop,
15
+ } from '$packages/utils'
16
+
17
+ export function decomposeCSSMatrix(matrix: WebKitCSSMatrix) {
18
+ const scaleX = Math.sqrt(
19
+ matrix.m11 * matrix.m11 + matrix.m12 * matrix.m12 + matrix.m13 * matrix.m13
20
+ )
21
+ const scaleY = Math.sqrt(
22
+ matrix.m21 * matrix.m21 + matrix.m22 * matrix.m22 + matrix.m23 * matrix.m23
23
+ )
24
+ const scaleZ = Math.sqrt(
25
+ matrix.m31 * matrix.m31 + matrix.m32 * matrix.m32 + matrix.m33 * matrix.m33
26
+ )
27
+
28
+ const rotationX = Math.atan2(matrix.m32, matrix.m33)
29
+ const rotationY = Math.atan2(
30
+ -matrix.m31,
31
+ Math.sqrt(matrix.m32 * matrix.m32 + matrix.m33 * matrix.m33)
32
+ )
33
+ const rotationZ = Math.atan2(matrix.m21, matrix.m11)
34
+
35
+ const translationX = matrix.m41
36
+ const translationY = matrix.m42
37
+ const translationZ = matrix.m43
38
+
39
+ return {
40
+ scaleX,
41
+ scaleY,
42
+ scaleZ,
43
+ rotationX,
44
+ rotationY,
45
+ rotationZ,
46
+ translationX,
47
+ translationY,
48
+ translationZ,
49
+ }
50
+ }
51
+
52
+ export interface LayoutBoxOptions {
53
+ containerElement?: ElementOrSelector
54
+ cartesian?: boolean
55
+ scrollAxis?: Axes3D | 'auto'
56
+ frontSide?: LayoutBoxFrontSide
57
+ sizeStep?: boolean
58
+ positionStep?: boolean
59
+ culling?: boolean
60
+ }
61
+
62
+ export interface LayoutBoxScrollStepCallbackReturn {
63
+ axis: Axes2D
64
+ value: number
65
+ }
66
+
67
+ export type LayoutBoxXYZ = { x: number; y: number; z: number }
68
+
69
+ export type LayoutBoxScrollStepCallback = () => LayoutBoxScrollStepCallbackReturn
70
+ export type LayoutBoxStepCallback = StoreCallback<StoreEntry<LayoutBoxXYZ>>
71
+
72
+ export type LayoutBoxFrontSide = 'left' | 'top'
73
+
74
+ export interface LayoutBoxBindedObject {
75
+ position?: LayoutBoxXYZ
76
+ scale?: LayoutBoxXYZ
77
+ rotation?: LayoutBoxXYZ
78
+ }
79
+
80
+ export class LayoutBox {
81
+ #element: HTMLElement = null!
82
+ #containerElement: HTMLElement = null!
83
+ #scrollStepSetterCallbacks: Array<LayoutBoxScrollStepCallback> = []
84
+
85
+ #scrollAxis: Axes3D | 'auto' = 'auto'
86
+ #frontSide: LayoutBoxFrontSide = 'top'
87
+
88
+ #isCartesian = false
89
+ #isSizeStep = true
90
+ #isPositionStep = true
91
+
92
+ #width = 0
93
+ #height = 0
94
+ #depth = 0
95
+
96
+ #top = 0
97
+ #left = 0
98
+ #front = 0
99
+
100
+ #x = 0
101
+ #y = 0
102
+ #z = 0
103
+
104
+ #CSSTranslation = { x: 0, y: 0, z: 0 }
105
+ #CSSRotation = { x: 0, y: 0, z: 0 }
106
+ #CSSScale = { x: 1, y: 1, z: 1 }
107
+
108
+ #rotation = new Ladder({ x: 0, y: 0, z: 0 })
109
+ #position = new Ladder({ x: 0, y: 0, z: 0 })
110
+ #scale = new Ladder({ x: 0, y: 0, z: 0 })
111
+
112
+ constructor(element: ElementOrSelector, options?: LayoutBoxOptions) {
113
+ if (isBrowser) {
114
+ this.#element = this.#getElement(element) || document.body
115
+ this.#containerElement = this.#getElement(options?.containerElement) || document.body
116
+
117
+ this.#scrollAxis = options?.scrollAxis || 'auto'
118
+ this.#frontSide = options?.frontSide || 'top'
119
+
120
+ this.#isCartesian = options?.cartesian || false
121
+ this.#isSizeStep = options?.sizeStep !== undefined ? options.sizeStep : true
122
+ this.#isPositionStep = options?.positionStep !== undefined ? options.positionStep : true
123
+
124
+ this.#scale.setStep('_size', '+', {
125
+ x: 1,
126
+ y: 1,
127
+ z: 1,
128
+ })
129
+
130
+ this.#position.setStep('_position', '+', {
131
+ x: 0,
132
+ y: 0,
133
+ z: 0,
134
+ })
135
+
136
+ this.#scale.setStep('_scale', '*', {
137
+ x: 1,
138
+ y: 1,
139
+ z: 1,
140
+ })
141
+
142
+ this.#position.setStep('_translation', '+', {
143
+ x: 0,
144
+ y: 0,
145
+ z: 0,
146
+ })
147
+
148
+ this.#rotation.setStep('_rotation', '+', {
149
+ x: 0,
150
+ y: 0,
151
+ z: 0,
152
+ })
153
+
154
+ addEventListener('DOMContentLoaded', () => {
155
+ const scrollEntries = scrollEnties.getAll(this.element)
156
+
157
+ scrollEntries.forEach((entry) => {
158
+ this.setScrollStep(() => {
159
+ return entry
160
+ })
161
+ })
162
+ })
163
+
164
+ ticker.subscribe(this.#tickListener, {
165
+ order: TICK_ORDER.LAYOUT_BOX,
166
+ culling: options?.culling ? this.element : undefined,
167
+ })
168
+
169
+ resizer.subscribe(this.#resizeListener, TICK_ORDER.LAYOUT_BOX)
170
+ }
171
+ }
172
+
173
+ public get element() {
174
+ return this.#element
175
+ }
176
+
177
+ public get containerElement() {
178
+ return this.#containerElement
179
+ }
180
+
181
+ public get position() {
182
+ return this.#position.current
183
+ }
184
+
185
+ public get rotation() {
186
+ return this.#rotation.current
187
+ }
188
+
189
+ public get scale() {
190
+ return this.#scale.current
191
+ }
192
+
193
+ public get left() {
194
+ return this.#left
195
+ }
196
+
197
+ public get top() {
198
+ return this.#top
199
+ }
200
+
201
+ public get front() {
202
+ return this.#front
203
+ }
204
+
205
+ public get width() {
206
+ return this.#width
207
+ }
208
+
209
+ public get height() {
210
+ return this.#height
211
+ }
212
+
213
+ public get depth() {
214
+ return this.#depth
215
+ }
216
+
217
+ public bindObject(object: LayoutBoxBindedObject) {
218
+ object.position && this.#position.bind(object.position)
219
+ object.rotation && this.#rotation.bind(object.rotation)
220
+ object.scale && this.#scale.bind(object.scale)
221
+ }
222
+
223
+ public unbindObject(object: LayoutBoxBindedObject) {
224
+ object.position && this.#position.unbind(object.position)
225
+ object.rotation && this.#rotation.unbind(object.rotation)
226
+ object.scale && this.#scale.unbind(object.scale)
227
+ }
228
+
229
+ public setScrollStep(callback: LayoutBoxScrollStepCallback) {
230
+ if (!this.#scrollStepSetterCallbacks.includes(callback)) {
231
+ this.#scrollStepSetterCallbacks.push(callback)
232
+ }
233
+
234
+ return () => this.deleteScrollStep(callback)
235
+ }
236
+
237
+ public deleteScrollStep(callback: LayoutBoxScrollStepCallback) {
238
+ this.#scrollStepSetterCallbacks = this.#scrollStepSetterCallbacks.filter((s) => s !== callback)
239
+ }
240
+
241
+ public destroy() {
242
+ ticker.unsubscribe(this.#tickListener)
243
+ resizer.unsubscribe(this.#resizeListener)
244
+
245
+ this.#position.close()
246
+ this.#rotation.close()
247
+ this.#scale.close()
248
+ }
249
+
250
+ public setPositionStep(...args: Parameters<Ladder['setStep']>) {
251
+ this.#position.setStep(...args)
252
+ }
253
+
254
+ public setRotationStep(...args: Parameters<Ladder['setStep']>) {
255
+ this.#rotation.setStep(...args)
256
+ }
257
+
258
+ public setScaleStep(...args: Parameters<Ladder['setStep']>) {
259
+ this.#scale.setStep(...args)
260
+ }
261
+
262
+ public deletePositionStep(...args: Parameters<Ladder['deleteStep']>) {
263
+ this.#position.deleteStep(...args)
264
+ }
265
+
266
+ public deleteRotationStep(...args: Parameters<Ladder['deleteStep']>) {
267
+ this.#rotation.deleteStep(...args)
268
+ }
269
+
270
+ public deleteScaleStep(...args: Parameters<Ladder['deleteStep']>) {
271
+ this.#scale.deleteStep(...args)
272
+ }
273
+
274
+ #recalculate() {
275
+ this.#scale.calculate()
276
+ this.#position.calculate()
277
+ this.#rotation.calculate()
278
+ }
279
+
280
+ #composeSteps() {
281
+ this.#scale.setStep('_size', '+', {
282
+ x: this.#isSizeStep ? this.#width : 1,
283
+ y: this.#isSizeStep ? this.#height : 1,
284
+ z: this.#isSizeStep ? this.#depth : 1,
285
+ })
286
+
287
+ const xPosition = this.#isPositionStep ? this.#x : 0
288
+ const yPosition = this.#isPositionStep ? this.#y : 0
289
+ const zPosition = this.#isPositionStep ? this.#z : 0
290
+
291
+ this.#position.setStep('_position', '+', {
292
+ x: xPosition,
293
+ y: yPosition,
294
+ z: zPosition,
295
+ })
296
+
297
+ this.#scale.setStep('_scale', '*', {
298
+ x: this.#CSSScale.x,
299
+ y: this.#CSSScale.y,
300
+ z: this.#CSSScale.z,
301
+ })
302
+
303
+ this.#position.setStep('_translation', '+', {
304
+ x: this.#CSSTranslation.x,
305
+ y: this.#CSSTranslation.y,
306
+ z: this.#CSSTranslation.z,
307
+ })
308
+
309
+ this.#rotation.setStep('_rotation', '+', {
310
+ x: this.#CSSRotation.x,
311
+ y: this.#CSSRotation.y,
312
+ z: this.#CSSRotation.z,
313
+ })
314
+ }
315
+
316
+ #updateDimensions() {
317
+ const computed = getComputedStyle(this.#element)
318
+
319
+ this.#width = Math.max(this.#element.clientWidth, 1)
320
+
321
+ this.#height = Math.max(this.#element.clientHeight, 1)
322
+
323
+ this.#depth = Math.max(cssUnitParser.parse(computed.getPropertyValue('--depth') || '0px'), 1)
324
+
325
+ const vl = getCumulativeOffsetLeft(this.#containerElement)
326
+ const vt = getCumulativeOffsetTop(this.#containerElement)
327
+ const vw = this.#containerElement.clientWidth
328
+ const vh = this.#containerElement.clientHeight
329
+
330
+ this.#left = getCumulativeOffsetLeft(this.#element) - vl
331
+ this.#top = getCumulativeOffsetTop(this.#element) - vt
332
+
333
+ if (this.#scrollAxis === 'z') {
334
+ const nl = this.#left / vw
335
+ const nt = this.#top / vh
336
+
337
+ this.#left = (nl - Math.floor(nl)) * vw
338
+ this.#top = (nt - Math.floor(nt)) * vh
339
+
340
+ if (this.#frontSide === 'left') {
341
+ this.#front = getCumulativeOffsetLeft(this.#element) - vl - this.#left
342
+ } else {
343
+ this.#front = getCumulativeOffsetTop(this.#element) - vt - this.#top
344
+ }
345
+ }
346
+
347
+ this.#left += this.#element.clientLeft
348
+ this.#top += this.#element.clientTop
349
+
350
+ if (this.#isCartesian) {
351
+ const viewHalfWidth = Math.round(vw / 2)
352
+ const viewHalfHeight = Math.round(vh / 2)
353
+
354
+ const thisHalfWidth = this.#width ? Math.round(this.#width / 2) : 0
355
+ const thisHalfHeight = this.#height ? Math.round(this.#height / 2) : 0
356
+
357
+ const positionX = this.#left - viewHalfWidth + thisHalfWidth
358
+ const positionY = (this.#top - viewHalfHeight + thisHalfHeight) * -1
359
+ this.#x = positionX
360
+ this.#y = positionY
361
+ } else {
362
+ this.#x = this.#left
363
+ this.#y = this.#top
364
+ }
365
+
366
+ this.#z = this.#front * -1
367
+
368
+ const cssMatrix = new WebKitCSSMatrix(computed.transform)
369
+ const decomposedMatrix = decomposeCSSMatrix(cssMatrix)
370
+
371
+ this.#CSSTranslation.x = decomposedMatrix.translationX
372
+ this.#CSSTranslation.y = decomposedMatrix.translationY
373
+ this.#CSSTranslation.z = decomposedMatrix.translationZ
374
+
375
+ this.#CSSScale.x = decomposedMatrix.scaleX
376
+ this.#CSSScale.y = decomposedMatrix.scaleY
377
+ this.#CSSScale.z = decomposedMatrix.scaleZ
378
+
379
+ this.#CSSRotation.x = decomposedMatrix.rotationX
380
+ this.#CSSRotation.y = decomposedMatrix.rotationY
381
+ this.#CSSRotation.z = decomposedMatrix.rotationZ
382
+
383
+ this.#composeSteps()
384
+ this.#recalculate()
385
+ }
386
+
387
+ #updateScrollPosition() {
388
+ for (let index = 0; index < this.#scrollStepSetterCallbacks.length; index++) {
389
+ const callbackReturn = this.#scrollStepSetterCallbacks[index]()
390
+
391
+ let axis = callbackReturn.axis as Axes3D
392
+
393
+ if (this.#scrollAxis !== 'auto') {
394
+ axis = this.#scrollAxis
395
+ }
396
+
397
+ this.#position.setStep(`_scroll_${index}`, '+', {
398
+ [axis]: callbackReturn.value * (axis === 'x' ? -1 : this.#isCartesian ? 1 : -1),
399
+ })
400
+ }
401
+ }
402
+
403
+ #getElement(element: string | HTMLElement | undefined) {
404
+ return typeof element === 'string' ? document.querySelector<HTMLElement>(element) : element
405
+ }
406
+
407
+ #resizeListener = () => {
408
+ if (isBrowser) {
409
+ this.#updateDimensions()
410
+ }
411
+ }
412
+
413
+ #tickListener = () => {
414
+ this.#updateScrollPosition()
415
+ this.#recalculate()
416
+ }
417
+ }
@@ -0,0 +1,131 @@
1
+ import { Notifier } from '$packages/notifier'
2
+ import { debounce } from '$packages/utils'
3
+
4
+ export interface LoadingProgressDetail {
5
+ loaded: number
6
+ total: number
7
+ progress: number
8
+ namespace: string
9
+ }
10
+
11
+ export interface LoadingErrorDetail {
12
+ namespace: string
13
+ url: string
14
+ }
15
+
16
+ export interface LoadingCompleteDetail {
17
+ total: number
18
+ }
19
+
20
+ export type LoadingProgressSubscriber = (detail: LoadingProgressDetail) => void
21
+ export type LoadingErrorSubscriber = (detail: LoadingErrorDetail) => void
22
+ export type LoadingCompleteSubscriber = (detail: LoadingCompleteDetail) => void
23
+
24
+ class Loading {
25
+ #counter: Map<string, { total: number; loaded: number }> = new Map()
26
+ #progressEvent = new Notifier<LoadingProgressSubscriber>()
27
+ #completeEvent = new Notifier<LoadingCompleteSubscriber>()
28
+ #errorEvent = new Notifier<LoadingErrorSubscriber>()
29
+ #isComplete = false
30
+
31
+ public get progressEvent() {
32
+ return this.#progressEvent
33
+ }
34
+
35
+ public get completeEvent() {
36
+ return this.#completeEvent
37
+ }
38
+
39
+ public get errorEvent() {
40
+ return this.#errorEvent
41
+ }
42
+
43
+ public get _counter() {
44
+ return this.#counter
45
+ }
46
+
47
+ public get isComplete() {
48
+ return this.#isComplete
49
+ }
50
+
51
+ public reset() {
52
+ this.#isComplete = false
53
+ this.#counter.clear()
54
+ }
55
+
56
+ public setTotal(namespace: string, total: number = 1) {
57
+ if (this.#isComplete) {
58
+ return
59
+ }
60
+
61
+ this.#counter.set(namespace, { loaded: 0, total: total })
62
+ }
63
+
64
+ public setLoaded(namespace: string, loaded: number = 1) {
65
+ if (this.#isComplete) {
66
+ return
67
+ }
68
+
69
+ if (this.#counter.has(namespace)) {
70
+ const ns = this.#counter.get(namespace)!
71
+
72
+ if (ns.loaded !== loaded) {
73
+ this.#counter.set(namespace, { ...ns, loaded: loaded })
74
+ this.#progressListener(namespace)
75
+ }
76
+ }
77
+ }
78
+
79
+ public setError(namespace: string, url: string) {
80
+ if (this.#isComplete) {
81
+ return
82
+ }
83
+
84
+ if (this.#counter.has(namespace)) {
85
+ const ns = this.#counter.get(namespace)!
86
+ this.#counter.set(namespace, { ...ns, total: ns.total - 1 })
87
+ this.#errorEvent.notify({
88
+ namespace,
89
+ url,
90
+ })
91
+ }
92
+ }
93
+
94
+ public getStats() {
95
+ return Array.from(this.#counter).reduce(
96
+ (p, c) => {
97
+ return { loaded: p.loaded + c[1].loaded, total: p.total + c[1].total }
98
+ },
99
+ { loaded: 0, total: 0 }
100
+ )
101
+ }
102
+
103
+ #progressListener = (namespace: string) => {
104
+ const { loaded, total } = this.getStats()
105
+
106
+ this.#progressEvent.notify({
107
+ progress: loaded / total,
108
+ loaded,
109
+ total,
110
+ namespace,
111
+ })
112
+
113
+ this.#tryComplete()
114
+ }
115
+
116
+ #tryComplete = debounce(() => {
117
+ const { loaded, total } = this.getStats()
118
+
119
+ if (loaded === total) {
120
+ this.#isComplete = true
121
+
122
+ const { total } = this.getStats()
123
+
124
+ this.#completeEvent.notify({
125
+ total,
126
+ })
127
+ }
128
+ }, 150)
129
+ }
130
+
131
+ export const loading = new Loading()
@@ -0,0 +1,8 @@
1
+ import { getCumulativeOffsetLeft } from '$packages/utils'
2
+ import { Measurer } from './Meaurer'
3
+
4
+ export class CumulativeOffsetLeft extends Measurer {
5
+ protected handleResize() {
6
+ return getCumulativeOffsetLeft(this.element)
7
+ }
8
+ }
@@ -0,0 +1,8 @@
1
+ import { getCumulativeOffsetTop } from '$packages/utils'
2
+ import { Measurer } from './Meaurer'
3
+
4
+ export class CumulativeOffsetTop extends Measurer {
5
+ protected handleResize() {
6
+ return getCumulativeOffsetTop(this.element)
7
+ }
8
+ }
@@ -0,0 +1,38 @@
1
+ import { isBrowser } from '$packages/utils'
2
+
3
+ export abstract class Measurer {
4
+ #element: HTMLElement
5
+ #resizeObserver: ResizeObserver = null!
6
+ #value = 0
7
+
8
+ constructor(element: HTMLElement) {
9
+ this.#element = element
10
+
11
+ if (isBrowser) {
12
+ this.#resizeObserver = new ResizeObserver(this.#resizeObserverCallback)
13
+ this.#resizeObserver.observe(element)
14
+ }
15
+ }
16
+
17
+ public get element() {
18
+ return this.#element
19
+ }
20
+
21
+ public value = (modifier?: (current: number) => number) => {
22
+ return modifier ? modifier(this.#value) : this.#value
23
+ }
24
+
25
+ public destroy() {
26
+ this.#resizeObserver.disconnect()
27
+ }
28
+
29
+ protected abstract handleResize(): number
30
+
31
+ #resizeObserverCallback: ResizeObserverCallback = () => {
32
+ this.#value = this.handleResize()
33
+
34
+ if (!this.#element.isConnected) {
35
+ this.destroy()
36
+ }
37
+ }
38
+ }
@@ -0,0 +1,3 @@
1
+ export { Measurer } from './Meaurer'
2
+ export { CumulativeOffsetLeft } from './CumulativeOffsetLeft'
3
+ export { CumulativeOffsetTop } from './CumulativeOffsetTop'
@@ -0,0 +1,38 @@
1
+ import { RESIZE_ORDER } from '$packages/order'
2
+ import { resizer } from '$packages/resizer'
3
+ import { Store } from '$packages/store'
4
+
5
+ export type MediaCallback = () => void
6
+
7
+ export type MediaQueries<T extends string = string> = Map<
8
+ T,
9
+ {
10
+ match: MediaCallback
11
+ unmatch?: MediaCallback
12
+ }
13
+ >
14
+
15
+ export class Media extends Store<boolean> {
16
+ #query: string
17
+
18
+ #unsubscribeFromResizer: Function
19
+
20
+ constructor(query: string) {
21
+ super(false)
22
+
23
+ this.#query = query
24
+
25
+ this.#unsubscribeFromResizer = resizer.subscribe(() => {
26
+ if (matchMedia(this.#query).matches) {
27
+ this.current = true
28
+ } else {
29
+ this.current = false
30
+ }
31
+ }, RESIZE_ORDER.MEDIA)
32
+ }
33
+
34
+ public override close() {
35
+ super.close()
36
+ this.#unsubscribeFromResizer()
37
+ }
38
+ }
@@ -0,0 +1,32 @@
1
+ import { Morph, MorphHistoryAction } from './Morph'
2
+
3
+ export class Link {
4
+ #morph: Morph
5
+ #element: HTMLAnchorElement
6
+ #pathname: string
7
+ #historyAction: MorphHistoryAction
8
+
9
+ constructor(element: HTMLAnchorElement, morph: Morph) {
10
+ this.#morph = morph
11
+ this.#element = element
12
+ this.#pathname = this.#element.getAttribute('href') || '/'
13
+ this.#historyAction =
14
+ (this.#element.getAttribute('data-history-action') as MorphHistoryAction) || 'push'
15
+
16
+ this.#element.addEventListener('click', this.#clickListener)
17
+
18
+ if (this.#pathname === location.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: MouseEvent) => {
29
+ e.preventDefault()
30
+ this.#morph.navigate(this.#pathname, this.#historyAction)
31
+ }
32
+ }