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,170 @@
1
+ import { define } from '$packages/custom-element'
2
+ import { RESIZE_ORDER } from '$packages/order'
3
+ import { resizer } from '$packages/resizer'
4
+ import { isBrowser } from '$packages/utils'
5
+ import { ScrollUserElement } from './ScrollUserElement'
6
+
7
+ @define('e-scrollbar')
8
+ export class ScrollbarElement extends ScrollUserElement {
9
+ #slotElement: HTMLSlotElement = null!
10
+ #thumbElement: HTMLElement = null!
11
+
12
+ #isHorisontal = false
13
+
14
+ #thumbSize = 0
15
+ #thumbScrollSize = 0
16
+
17
+ #position = 0
18
+
19
+ constructor() {
20
+ super()
21
+
22
+ if (isBrowser) {
23
+ const root = this.attachShadow({ mode: 'open' })
24
+
25
+ const styleElement = document.createElement('style')
26
+ styleElement.textContent = `
27
+ :host {
28
+ display: inline-block;
29
+ z-index: 1;
30
+ background-color: #efefef;
31
+ }
32
+
33
+ :host([axis="y"]) {
34
+ position: absolute;
35
+ right: 0;
36
+ top: 0;
37
+ width: 1vmin;
38
+ height: 100%;
39
+ }
40
+
41
+ :host([axis="x"]) {
42
+ position: absolute;
43
+ left: 0;
44
+ bottom: 0;
45
+ width: 100%;
46
+ height: 1vmin;
47
+ }
48
+
49
+ .default-thumb {
50
+ background-color: #181818;
51
+ border-radius: 1vmin;
52
+ touch-action: none;
53
+ }
54
+
55
+ ::slotted(*) {
56
+ touch-action: none;
57
+ }
58
+ `
59
+ root.appendChild(styleElement)
60
+
61
+ this.#slotElement = document.createElement('slot')
62
+ root.appendChild(this.#slotElement)
63
+ }
64
+ }
65
+
66
+ public get thumbElement() {
67
+ return this.#thumbElement
68
+ }
69
+
70
+ protected override connectedCallback() {
71
+ super.connectedCallback()
72
+
73
+ const slottedThumb = this.#slotElement.assignedElements()[0]
74
+
75
+ if (slottedThumb instanceof HTMLElement) {
76
+ this.#thumbElement = slottedThumb
77
+ } else {
78
+ this.#thumbElement = document.createElement('div')
79
+ this.#thumbElement.classList.add('default-thumb')
80
+ this.shadowRoot!.appendChild(this.#thumbElement)
81
+ }
82
+
83
+ this.#thumbElement.addEventListener('pointerdown', this.#grabListener)
84
+
85
+ resizer.subscribe(this.#resizeListener, RESIZE_ORDER.SCROLL + 1)
86
+
87
+ this.scrollElement.damped.subscribe(this.#scrollListener)
88
+
89
+ this.scrollElement.axisAttibute.subscribe(this.#axisListener)
90
+ }
91
+
92
+ protected disconnectedCallback() {
93
+ this.#thumbElement.removeEventListener('pointerdown', this.#grabListener)
94
+
95
+ resizer.unsubscribe(this.#resizeListener)
96
+
97
+ this.scrollElement.damped.unsubscribe(this.#scrollListener)
98
+
99
+ this.scrollElement.axisAttibute.unsubscribe(this.#axisListener)
100
+ }
101
+
102
+ #resizeListener = () => {
103
+ this.#isHorisontal = this.offsetWidth > this.offsetHeight
104
+
105
+ const barSize = this.#isHorisontal ? this.offsetWidth : this.offsetHeight
106
+
107
+ this.#thumbSize =
108
+ barSize / ((this.scrollElement.scrollSize + this.scrollElement.viewportSize) / barSize)
109
+
110
+ this.#thumbSize = Math.max(this.#thumbSize, 30)
111
+
112
+ if (this.#isHorisontal) {
113
+ this.#thumbElement.style.width = this.#thumbSize + 'px'
114
+ this.#thumbElement.style.height = '100%'
115
+ } else {
116
+ this.#thumbElement.style.width = '100%'
117
+ this.#thumbElement.style.height = this.#thumbSize + 'px'
118
+ }
119
+
120
+ this.#thumbScrollSize = barSize - this.#thumbSize
121
+
122
+ if (!this.scrollElement.scrollSize) {
123
+ this.style.display = 'none'
124
+ }
125
+ }
126
+
127
+ #scrollListener = () => {
128
+ this.#position = this.scrollElement.currentProgress * this.#thumbScrollSize
129
+
130
+ if (this.#isHorisontal) {
131
+ this.#thumbElement.style.transform = `translate3d(${this.#position}px, 0px, 0px)`
132
+ } else {
133
+ this.#thumbElement.style.transform = `translate3d(0px, ${this.#position}px, 0px)`
134
+ }
135
+ }
136
+
137
+ #axisListener = () => {
138
+ this.setAttribute('axis', this.scrollElement.axisAttibute.current)
139
+ }
140
+
141
+ #grabListener = (grabEvent: PointerEvent) => {
142
+ const move = (moveEvent: PointerEvent) => {
143
+ const moveCursor = this.#isHorisontal ? moveEvent.x : moveEvent.y
144
+
145
+ const mult = this.scrollElement.distance / this.#thumbScrollSize
146
+ const delta = (moveCursor - grabCursor) * mult
147
+
148
+ this.scrollElement.damped.set(startValue + delta)
149
+ }
150
+
151
+ const drop = () => {
152
+ removeEventListener('pointermove', move)
153
+ removeEventListener('pointerup', drop)
154
+ removeEventListener('touchend', drop)
155
+ }
156
+
157
+ addEventListener('pointermove', move)
158
+ addEventListener('pointerup', drop)
159
+ addEventListener('touchend', drop)
160
+
161
+ const startValue = this.scrollElement.damped.target
162
+ const grabCursor = this.#isHorisontal ? grabEvent.x : grabEvent.y
163
+ }
164
+ }
165
+
166
+ declare global {
167
+ interface HTMLElementTagNameMap {
168
+ 'e-scrollbar': ScrollbarElement
169
+ }
170
+ }
@@ -0,0 +1,2 @@
1
+ export { ScrollElement } from './ScrollElement'
2
+ export { ScrollbarElement } from './ScrollbarElement'
@@ -0,0 +1,74 @@
1
+ import { Axes2D } from '$packages/utils'
2
+
3
+ interface ScrollEntry {
4
+ axis: Axes2D
5
+ value: number
6
+ }
7
+
8
+ class ScrollEntries {
9
+ #elements: Set<HTMLElement> = new Set()
10
+ #entires: WeakMap<HTMLElement, ScrollEntry> = new WeakMap()
11
+
12
+ public register(element: HTMLElement) {
13
+ this.#entires.set(element, {
14
+ axis: 'y',
15
+ value: 0,
16
+ })
17
+ this.#elements.add(element)
18
+ }
19
+
20
+ public unregister(element: HTMLElement) {
21
+ this.#entires.delete(element)
22
+ this.#elements.delete(element)
23
+ }
24
+
25
+ public update(element: HTMLElement, axis: Axes2D, value: number) {
26
+ const entry = this.#entires.get(element)!
27
+ entry.axis = axis
28
+ entry.value = value
29
+ }
30
+
31
+ public hasEntry(element: HTMLElement) {
32
+ return this.#entires.has(element)
33
+ }
34
+
35
+ public getEntry(element: HTMLElement) {
36
+ return this.#entires.get(element)!
37
+ }
38
+
39
+ public getClosest(element: HTMLElement): ScrollEntry | null {
40
+ let parent = element.parentElement
41
+
42
+ while (parent && !this.hasEntry(parent)) {
43
+ parent = parent.parentElement
44
+ }
45
+
46
+ if (parent && parent !== element) {
47
+ const entry = this.getEntry(parent)
48
+
49
+ if (entry) {
50
+ return entry
51
+ } else {
52
+ return this.getClosest(parent)
53
+ }
54
+ }
55
+
56
+ return null
57
+ }
58
+
59
+ public getAll(element: HTMLElement) {
60
+ const elements = Array.from(this.#elements).filter((v) => v !== element && v.contains(element))
61
+
62
+ const entries: Array<ScrollEntry> = []
63
+
64
+ elements.forEach((element) => {
65
+ if (this.#entires.has(element)) {
66
+ entries.push(this.#entires.get(element)!)
67
+ }
68
+ })
69
+
70
+ return entries
71
+ }
72
+ }
73
+
74
+ export const scrollEnties = new ScrollEntries()
@@ -0,0 +1,77 @@
1
+ export class Source {
2
+ #url: string
3
+ #name: string
4
+ #density: number
5
+ #query: string
6
+ #queryPx: number
7
+ #queryType: 'max' | 'min'
8
+ #extension: string
9
+
10
+ constructor(url: string) {
11
+ this.#url = url
12
+
13
+ const firstQuestionIndex = url.indexOf('?')
14
+
15
+ if (firstQuestionIndex >= 0) {
16
+ url = url.slice(0, firstQuestionIndex)
17
+ }
18
+
19
+ const splitted = url.split('.')
20
+
21
+ this.#name = splitted[0]
22
+
23
+ const xpattern = /\d+x/g
24
+ const xmatch = splitted.find((s) => s.match(xpattern))
25
+ this.#density = xmatch ? parseInt(xmatch) : 1
26
+
27
+ const maxpattern = /\d+max/g
28
+ const minpattern = /\d+min/g
29
+
30
+ const maxmatch = splitted.find((s) => s.match(maxpattern))
31
+ const minmatch = splitted.find((s) => s.match(minpattern))
32
+
33
+ if (maxmatch) {
34
+ this.#queryPx = parseInt(maxmatch)
35
+ this.#queryType = 'max'
36
+ this.#query = `(max-width: ${this.#queryPx}px)`
37
+ } else if (minmatch) {
38
+ this.#queryPx = parseInt(minmatch)
39
+ this.#query = `(min-width: ${this.#queryPx}px)`
40
+ this.#queryType = 'min'
41
+ } else {
42
+ this.#queryPx = 0
43
+ this.#query = `(min-width: ${this.#queryPx}px)`
44
+ this.#queryType = 'min'
45
+ }
46
+
47
+ this.#extension = '.' + splitted[splitted.length - 1]
48
+ }
49
+
50
+ public get url() {
51
+ return this.#url
52
+ }
53
+
54
+ public get name() {
55
+ return this.#name
56
+ }
57
+
58
+ public get density() {
59
+ return this.#density
60
+ }
61
+
62
+ public get query() {
63
+ return this.#query
64
+ }
65
+
66
+ public get extension() {
67
+ return this.#extension
68
+ }
69
+
70
+ public get queryType() {
71
+ return this.#queryType
72
+ }
73
+
74
+ public get queryPx() {
75
+ return this.#queryPx
76
+ }
77
+ }
@@ -0,0 +1,177 @@
1
+ import { CustomElement } from '$packages/custom-element'
2
+ import { intersector } from '$packages/intersector'
3
+ import { loading } from '$packages/loading'
4
+ import { Notifier } from '$packages/notifier'
5
+ import type { Source } from './SourceClass'
6
+ import { SourceManager } from './SourceManager'
7
+
8
+ let id = 0
9
+
10
+ export interface SourceConsumer extends HTMLElement {
11
+ src: string | null
12
+ }
13
+
14
+ export abstract class SourceElement<T extends SourceConsumer> extends CustomElement {
15
+ #sourceManager: SourceManager = null!
16
+ #consumerElement: T = null!
17
+ #isFirstLoadHappened = false
18
+ #intersectionHappened = false
19
+ #isLazy = false
20
+ #id: string
21
+ #captureEvent = new Notifier()
22
+ #releaseEvent = new Notifier()
23
+
24
+ constructor() {
25
+ super()
26
+
27
+ this.#id = `source-consumer-${++id}`
28
+ }
29
+
30
+ public get consumerElement() {
31
+ return this.#consumerElement
32
+ }
33
+
34
+ public get captureEvent() {
35
+ return this.#captureEvent
36
+ }
37
+
38
+ public get releaseEvent() {
39
+ return this.#releaseEvent
40
+ }
41
+
42
+ protected abstract createConsumer(): T
43
+ protected abstract consumeSource(url: string | null): void
44
+
45
+ protected connectedCallback() {
46
+ const srcset = this.getAttribute('srcset')
47
+
48
+ if (!srcset) return
49
+
50
+ this.#consumerElement = this.createConsumer()
51
+
52
+ this.#consumerElement.style.cssText = `
53
+ display: block;
54
+ width: 100%;
55
+ height: 100%;
56
+ `
57
+
58
+ this.#consumerElement.classList.add('source-consumer')
59
+
60
+ Array.from(this.attributes).forEach((attr) => {
61
+ if (attr.nodeName.startsWith('e-')) {
62
+ const originalAttributeName = attr.nodeName.slice(2)
63
+ const value = attr.nodeValue || ''
64
+
65
+ this.#consumerElement.setAttribute(originalAttributeName, value)
66
+ ;(this.#consumerElement as any)[originalAttributeName] = value ? value : true
67
+ }
68
+ })
69
+
70
+ this.appendChild(this.#consumerElement)
71
+
72
+ this.#sourceManager = new SourceManager({
73
+ srcset: srcset,
74
+ })
75
+
76
+ this.#isLazy = this.hasAttribute('lazy')
77
+
78
+ this.#sourceManager.subscribe((d) => {
79
+ if (!this.#isLazy || (this.#isLazy && this.#intersectionHappened)) {
80
+ this.#loadSource(d.current)
81
+ }
82
+ })
83
+
84
+ intersector.subscribe(this, this.#intersectionListener)
85
+
86
+ this.#sourceManager.connect()
87
+ }
88
+
89
+ protected disconnectedCallback() {
90
+ intersector.unsubscribe(this.#intersectionListener)
91
+
92
+ this.#captureEvent.close()
93
+ this.#releaseEvent.close()
94
+ this.#sourceManager.close()
95
+
96
+ this.#consumerElement.onloadeddata = null
97
+ this.#consumerElement.onload = null
98
+ this.#consumerElement.onerror = null
99
+
100
+ this.#consumerElement.remove()
101
+ }
102
+
103
+ #loadSource(source: Source | undefined) {
104
+ this.#consumerElement.onloadeddata = null
105
+ this.#consumerElement.onload = null
106
+ this.#consumerElement.onerror = null
107
+
108
+ if (source) {
109
+ const isKeepSourceParameters = this.hasAttribute('keep-source-parameters')
110
+
111
+ this.classList.remove('loaded')
112
+ this.classList.add('loading')
113
+
114
+ const url = isKeepSourceParameters ? source.url : source.name + source.extension
115
+
116
+ this.consumeSource(url)
117
+
118
+ const loadListener = () => {
119
+ this.classList.remove('error')
120
+ this.classList.remove('loading')
121
+ this.classList.add('loaded')
122
+
123
+ if (!this.#isLazy && !this.#isFirstLoadHappened) {
124
+ loading.setLoaded(this.#id, 1)
125
+ }
126
+
127
+ this.#isFirstLoadHappened = true
128
+ }
129
+
130
+ const errorListener = () => {
131
+ this.classList.remove('loading')
132
+ this.classList.add('error')
133
+
134
+ if (!this.#isLazy && !this.#isFirstLoadHappened) {
135
+ loading.setError(this.#id, url)
136
+ }
137
+
138
+ this.#isFirstLoadHappened = true
139
+ }
140
+
141
+ if (!this.#isLazy && !this.#isFirstLoadHappened) {
142
+ loading.setTotal(this.#id, 1)
143
+ }
144
+
145
+ this.#consumerElement.onloadeddata = () => {
146
+ loadListener()
147
+ }
148
+ this.#consumerElement.onload = () => {
149
+ loadListener()
150
+ }
151
+ this.#consumerElement.onerror = errorListener
152
+ } else {
153
+ this.consumeSource(null)
154
+ }
155
+ }
156
+
157
+ #intersectionListener = (entry: IntersectionObserverEntry) => {
158
+ if (this.#isLazy) {
159
+ if (!this.#intersectionHappened && entry.isIntersecting) {
160
+ if (
161
+ this.#sourceManager.current &&
162
+ this.#sourceManager.current !== this.#sourceManager.previous
163
+ ) {
164
+ this.#loadSource(this.#sourceManager.current)
165
+ }
166
+
167
+ this.#intersectionHappened = true
168
+ }
169
+ }
170
+
171
+ if (entry.isIntersecting) {
172
+ this.#captureEvent.notify()
173
+ } else {
174
+ this.#releaseEvent.notify()
175
+ }
176
+ }
177
+ }
@@ -0,0 +1,61 @@
1
+ import { RESIZE_ORDER } from '$packages/order'
2
+ import { resizer } from '$packages/resizer'
3
+ import { Store } from '$packages/store'
4
+ import type { Source } from './SourceClass'
5
+ import { SourceSet, SourceSetMediaSources } from './SourceSet'
6
+
7
+ export type SourceManagerSourceSet = string | Array<string>
8
+
9
+ export interface SourceManagerParameters {
10
+ srcset: SourceManagerSourceSet
11
+ }
12
+
13
+ export class SourceManager extends Store<Source | undefined> {
14
+ #srcset: SourceSet
15
+
16
+ constructor(parameters: SourceManagerParameters) {
17
+ super(undefined)
18
+
19
+ this.#srcset = new SourceSet(parameters.srcset)
20
+ }
21
+
22
+ public override close() {
23
+ super.close()
24
+ this.disconnect()
25
+ }
26
+
27
+ public connect() {
28
+ resizer.subscribe(this.#resizeListener, RESIZE_ORDER.SOURCE_MANAGER)
29
+ }
30
+
31
+ public disconnect() {
32
+ resizer.unsubscribe(this.#resizeListener)
33
+ }
34
+
35
+ #resizeListener = () => {
36
+ let matchedSources: SourceSetMediaSources | undefined
37
+
38
+ this.#srcset.mediaBuckets.forEach((sources, query) => {
39
+ if (matchMedia(query).matches) {
40
+ matchedSources = sources
41
+ }
42
+ })
43
+
44
+ let matchedSouce: Source | undefined
45
+
46
+ let maxDensity = 0
47
+
48
+ matchedSources?.forEach((s) => {
49
+ if (s.density > maxDensity && s.density <= Math.max(devicePixelRatio, 1)) {
50
+ maxDensity = s.density
51
+ matchedSouce = s
52
+ }
53
+ })
54
+
55
+ if (matchedSources?.length && !matchedSouce) {
56
+ matchedSouce = matchedSources[0]
57
+ }
58
+
59
+ this.current = matchedSouce
60
+ }
61
+ }
@@ -0,0 +1,52 @@
1
+ import { Source } from './SourceClass'
2
+
3
+ export type SourceSetMediaSources = Array<Source>
4
+ export type SourceSetMediaBucket = Map<string, SourceSetMediaSources>
5
+
6
+ export class SourceSet {
7
+ #mediaBuckets: SourceSetMediaBucket
8
+
9
+ constructor(sourceSet: string | Array<string>) {
10
+ this.#mediaBuckets = new Map()
11
+
12
+ const mediaBuckets =
13
+ typeof sourceSet === 'string'
14
+ ? sourceSet
15
+ .trim()
16
+ .split(',')
17
+ .map((u) => u.trim())
18
+ .filter((u) => !!u)
19
+ : sourceSet
20
+
21
+ const tmp: Array<[string, Source]> = []
22
+
23
+ mediaBuckets.forEach((v) => {
24
+ const source = new Source(v)
25
+ tmp.push([source.query, source])
26
+ })
27
+
28
+ const max = tmp
29
+ .filter((v) => v[1].queryType === 'max')
30
+ .sort((a, b) => b[1].queryPx - a[1].queryPx)
31
+
32
+ const min = tmp
33
+ .filter((v) => v[1].queryType === 'min' && v[1].queryPx !== 0)
34
+ .sort((a, b) => a[1].queryPx - b[1].queryPx)
35
+
36
+ const defaultMatch = tmp.filter((t) => t[0] === '(min-width: 0px)')
37
+
38
+ const sorted = defaultMatch ? [...defaultMatch, ...max, ...min] : [...max, ...min]
39
+
40
+ sorted.forEach((v) => {
41
+ if (!this.#mediaBuckets.has(v[0])) {
42
+ this.#mediaBuckets.set(v[0], [])
43
+ }
44
+
45
+ this.#mediaBuckets.get(v[0])!.push(v[1])
46
+ })
47
+ }
48
+
49
+ public get mediaBuckets() {
50
+ return this.#mediaBuckets
51
+ }
52
+ }
@@ -0,0 +1,8 @@
1
+ export { Source } from './SourceClass'
2
+ export { SourceSet, type SourceSetMediaSources, type SourceSetMediaBucket } from './SourceSet'
3
+ export {
4
+ SourceManager,
5
+ type SourceManagerSourceSet,
6
+ type SourceManagerParameters,
7
+ } from './SourceManager'
8
+ export { SourceElement, type SourceConsumer } from './SourceElement'
@@ -0,0 +1,33 @@
1
+ import { debounce } from '$packages/utils'
2
+ import { Store, StoreOptions } from './Store'
3
+
4
+ export type ComposedCallback<ComposedType> = () => ComposedType
5
+
6
+ export class Composed<ComposedType> extends Store<ComposedType> {
7
+ #unsubscribers: Array<Function> = []
8
+
9
+ constructor(
10
+ stores: Array<Store<any>>,
11
+ callback: ComposedCallback<ComposedType>,
12
+ parameters?: StoreOptions<ComposedType>
13
+ ) {
14
+ super(null!, parameters)
15
+
16
+ const update = debounce(() => {
17
+ this.current = callback()
18
+ }, 0)
19
+
20
+ stores.forEach((store) => {
21
+ this.#unsubscribers.push(
22
+ store.subscribe(() => {
23
+ update()
24
+ })
25
+ )
26
+ })
27
+ }
28
+
29
+ public override close() {
30
+ super.close()
31
+ this.#unsubscribers.forEach((u) => u())
32
+ }
33
+ }
@@ -0,0 +1,24 @@
1
+ import { Store, StoreOptions } from './Store'
2
+
3
+ export type DerivedCallback<StoreType, DerivedType> = (value: StoreType) => DerivedType
4
+
5
+ export class Derived<DerivedType, StoreType> extends Store<DerivedType> {
6
+ #unsubscriber: Function
7
+
8
+ constructor(
9
+ store: Store<StoreType>,
10
+ callback: DerivedCallback<StoreType, DerivedType>,
11
+ parameters?: StoreOptions<DerivedType>
12
+ ) {
13
+ super(null!, parameters)
14
+
15
+ this.#unsubscriber = store.subscribe((e) => {
16
+ this.current = callback(e.current)
17
+ })
18
+ }
19
+
20
+ public override close() {
21
+ super.close()
22
+ this.#unsubscriber()
23
+ }
24
+ }