@dxtmisha/wiki 0.24.0 → 0.24.1

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.
@@ -0,0 +1,329 @@
1
+ import {Meta} from '@storybook/addon-docs/blocks'
2
+
3
+ <Meta title='@dxtmisha/functional/en/Composables/useLazyRef'/>
4
+
5
+ # Composable useLazyRef
6
+
7
+ Composable for tracking element visibility on screen using Intersection Observer API. Provides efficient lazy loading and rendering of components only when they become visible in the viewport. Perfect for optimizing performance with long lists, images, and heavy components.
8
+
9
+ ## Key Features
10
+
11
+ - **Visibility tracking** — automatic detection when element appears in viewport
12
+ - **Intersection Observer API** — uses native browser API for efficient tracking
13
+ - **Automatic cleanup** — removes observers when components unmount
14
+ - **Reactive status** — returns reactive variable with visibility state
15
+ - **Configurable margins** — supports rootMargin for content preloading
16
+ - **Multiple elements** — manages tracking of multiple elements simultaneously
17
+ - **Graceful degradation** — works without IntersectionObserver in older browsers
18
+
19
+ ## Function
20
+
21
+ ### `useLazyRef`
22
+
23
+ Creates an instance for tracking element visibility on screen.
24
+
25
+ **Parameters:** none
26
+
27
+ **Returns:** object with methods:
28
+ - `intersectionObserver: IntersectionObserver | undefined` — observer instance
29
+ - `addLazyItem: (element: Ref<HTMLElement>) => ShallowRef<boolean>` — add element for tracking
30
+ - `removeLazyItem: (element?: HTMLElement) => void` — remove element from tracking
31
+ - `disconnectLazy: () => void` — disconnect all observers
32
+
33
+ ```javascript
34
+ import { useLazyRef } from '@dxtmisha/functional'
35
+
36
+ // Create instance
37
+ const lazy = useLazyRef()
38
+
39
+ // Access methods
40
+ const isVisible = lazy.addLazyItem(elementRef)
41
+ lazy.removeLazyItem(element)
42
+ lazy.disconnectLazy()
43
+ ```
44
+
45
+ ## Basic Usage
46
+
47
+ ### `addLazyItem`
48
+
49
+ Adds element to track its visibility on screen.
50
+
51
+ **Parameters:**
52
+ - `element: Ref<HTMLElement>` — reactive reference to HTML element
53
+
54
+ **Returns:** `ShallowRef<boolean>` — reactive variable with visibility status
55
+
56
+ ```javascript
57
+ import { ref } from 'vue'
58
+ import { useLazyRef } from '@dxtmisha/functional'
59
+
60
+ const lazy = useLazyRef()
61
+ const imageRef = ref(null)
62
+
63
+ // Add element for tracking
64
+ const isVisible = lazy.addLazyItem(imageRef)
65
+
66
+ // isVisible.value === true when element is visible
67
+ // isVisible.value === false when element is not visible
68
+
69
+ // In older browsers without IntersectionObserver
70
+ // isVisible.value === true immediately (fallback)
71
+ ```
72
+
73
+ ### `removeLazyItem`
74
+
75
+ Removes element from tracking and cleans up resources.
76
+
77
+ **Parameters:**
78
+ - `element?: HTMLElement` — HTML element to remove
79
+
80
+ **Returns:** `void`
81
+
82
+ ```javascript
83
+ const element = document.getElementById('my-element')
84
+
85
+ // Remove element from tracking
86
+ lazy.removeLazyItem(element)
87
+ ```
88
+
89
+ ### `disconnectLazy`
90
+
91
+ Disconnects all observers and stops tracking all elements.
92
+
93
+ **Parameters:** none
94
+
95
+ **Returns:** `void`
96
+
97
+ ```javascript
98
+ // Complete cleanup on unmount
99
+ onBeforeUnmount(() => {
100
+ lazy.disconnectLazy()
101
+ })
102
+ ```
103
+
104
+ ## Usage in Components
105
+
106
+ ### Lazy Image Loading
107
+
108
+ ```javascript
109
+ import { ref, watch } from 'vue'
110
+ import { useLazyRef } from '@dxtmisha/functional'
111
+
112
+ export default {
113
+ setup() {
114
+ const lazy = useLazyRef()
115
+ const imageRef = ref(null)
116
+ const imageLoaded = ref(false)
117
+
118
+ const isVisible = lazy.addLazyItem(imageRef)
119
+
120
+ watch(isVisible, (visible) => {
121
+ if (visible && !imageLoaded.value) {
122
+ imageLoaded.value = true
123
+ }
124
+ })
125
+
126
+ return { imageRef, imageLoaded }
127
+ }
128
+ }
129
+
130
+ // Template:
131
+ // <div ref="imageRef">
132
+ // <img v-if="imageLoaded" src="/path/to/image.jpg" />
133
+ // <div v-else class="placeholder">Loading...</div>
134
+ // </div>
135
+ ```
136
+
137
+ ### Infinite Scroll
138
+
139
+ ```javascript
140
+ import { ref, watch } from 'vue'
141
+ import { useLazyRef } from '@dxtmisha/functional'
142
+
143
+ export default {
144
+ setup() {
145
+ const lazy = useLazyRef()
146
+ const items = ref([1, 2, 3, 4, 5])
147
+ const sentinelRef = ref(null)
148
+ const loading = ref(false)
149
+
150
+ const isSentinelVisible = lazy.addLazyItem(sentinelRef)
151
+
152
+ watch(isSentinelVisible, async (visible) => {
153
+ if (visible && !loading.value) {
154
+ loading.value = true
155
+ await new Promise(resolve => setTimeout(resolve, 1000))
156
+ items.value.push(items.value.length + 1)
157
+ loading.value = false
158
+ }
159
+ })
160
+
161
+ return { items, sentinelRef, loading }
162
+ }
163
+ }
164
+
165
+ // Template:
166
+ // <div>
167
+ // <div v-for="item in items" :key="item">Item {{ item }}</div>
168
+ // <div ref="sentinelRef" class="sentinel">
169
+ // <div v-if="loading">Loading...</div>
170
+ // </div>
171
+ // </div>
172
+ ```
173
+
174
+ ## Advanced Usage
175
+
176
+ ### Tracking Multiple Elements
177
+
178
+ ```javascript
179
+ import { ref, onBeforeUnmount } from 'vue'
180
+ import { useLazyRef } from '@dxtmisha/functional'
181
+
182
+ export default {
183
+ setup() {
184
+ const lazy = useLazyRef()
185
+ const items = ref([
186
+ { id: 1, ref: ref(null), visible: null },
187
+ { id: 2, ref: ref(null), visible: null },
188
+ { id: 3, ref: ref(null), visible: null }
189
+ ])
190
+
191
+ // Add each element for tracking
192
+ items.value.forEach(item => {
193
+ item.visible = lazy.addLazyItem(item.ref)
194
+ })
195
+
196
+ onBeforeUnmount(() => {
197
+ lazy.disconnectLazy()
198
+ })
199
+
200
+ return { items }
201
+ }
202
+ }
203
+
204
+ // Template:
205
+ // <div v-for="item in items" :key="item.id">
206
+ // <div :ref="item.ref">
207
+ // <div v-if="item.visible.value">
208
+ // Content for item {{ item.id }}
209
+ // </div>
210
+ // <div v-else class="placeholder">...</div>
211
+ // </div>
212
+ // </div>
213
+ ```
214
+
215
+ ### Conditional Element Removal
216
+
217
+ ```javascript
218
+ import { ref, watch } from 'vue'
219
+ import { useLazyRef } from '@dxtmisha/functional'
220
+
221
+ export default {
222
+ setup() {
223
+ const lazy = useLazyRef()
224
+ const elementRef = ref(null)
225
+ const showElement = ref(true)
226
+
227
+ const isVisible = lazy.addLazyItem(elementRef)
228
+
229
+ // Remove from tracking when hiding
230
+ watch(showElement, (show) => {
231
+ if (!show && elementRef.value) {
232
+ lazy.removeLazyItem(elementRef.value)
233
+ }
234
+ })
235
+
236
+ return {
237
+ elementRef,
238
+ showElement,
239
+ isVisible
240
+ }
241
+ }
242
+ }
243
+ ```
244
+
245
+ ### Preloading with rootMargin
246
+
247
+ ```javascript
248
+ // Default rootMargin: '128px 0px'
249
+ // Elements start tracking 128px before entering viewport
250
+
251
+ const lazy = useLazyRef()
252
+ const imageRef = ref(null)
253
+
254
+ // Image will start loading 128px before visibility
255
+ const isVisible = lazy.addLazyItem(imageRef)
256
+
257
+ console.log('rootMargin provides smooth preloading')
258
+ ```
259
+
260
+ ## Handling Missing IntersectionObserver
261
+
262
+ ```javascript
263
+ import { useLazyRef } from '@dxtmisha/functional'
264
+
265
+ const lazy = useLazyRef()
266
+
267
+ // Check API availability
268
+ if (lazy.intersectionObserver) {
269
+ console.log('IntersectionObserver available')
270
+ // Use lazy loading
271
+ } else {
272
+ console.log('IntersectionObserver not supported')
273
+ // isVisible will always be true (fallback)
274
+ }
275
+
276
+ const elementRef = ref(null)
277
+ const isVisible = lazy.addLazyItem(elementRef)
278
+
279
+ // In older browsers isVisible.value === true immediately
280
+ // Content loads immediately (graceful degradation)
281
+ ```
282
+
283
+ ## Performance Optimization
284
+
285
+ ### Lazy Loading in Lists
286
+
287
+ ```javascript
288
+ import { ref } from 'vue'
289
+ import { useLazyRef } from '@dxtmisha/functional'
290
+
291
+ export default {
292
+ setup() {
293
+ const lazy = useLazyRef()
294
+ const products = ref([
295
+ { id: 1, name: 'Product 1', image: '/img1.jpg' },
296
+ { id: 2, name: 'Product 2', image: '/img2.jpg' },
297
+ // ... 100 more products
298
+ ])
299
+
300
+ // Create refs for each product
301
+ const productRefs = ref(products.value.map(() => ({
302
+ element: ref(null),
303
+ visible: null
304
+ })))
305
+
306
+ // Track visibility of each product
307
+ productRefs.value.forEach(item => {
308
+ item.visible = lazy.addLazyItem(item.element)
309
+ })
310
+
311
+ return {
312
+ products,
313
+ productRefs
314
+ }
315
+ }
316
+ }
317
+
318
+ // Template:
319
+ // <div v-for="(product, index) in products" :key="product.id">
320
+ // <div :ref="productRefs[index].element">
321
+ // <template v-if="productRefs[index].visible.value">
322
+ // <img :src="product.image" :alt="product.name" />
323
+ // <h3>{{ product.name }}</h3>
324
+ // </template>
325
+ // <div v-else class="product-skeleton">Loading...</div>
326
+ // </div>
327
+ // </div>
328
+ ```
329
+
@@ -0,0 +1,159 @@
1
+ import {Meta} from '@storybook/addon-docs/blocks'
2
+
3
+ <Meta title='@dxtmisha/functional/en/Composables/useLoadingRef'/>
4
+
5
+ # Composable useLoadingRef
6
+
7
+ Composable for tracking global application loading status. Provides a reactive variable that automatically updates when loading state changes through the Loading class. Perfect for displaying global loading indicators, blocking UI during async operations, and coordinating multiple loading processes.
8
+
9
+ ## Key Features
10
+
11
+ - **Global loading status** — single place to manage loading state for entire application
12
+ - **Reactivity** — automatic updates when loading status changes
13
+ - **Loading counter** — supports multiple concurrent loading operations
14
+ - **Automatic subscription** — composable automatically subscribes to Loading events
15
+ - **Type safety** — full TypeScript support
16
+ - **Easy integration** — easily integrates with any Vue components
17
+ - **Centralized control** — all components use single source of truth
18
+
19
+ ## Function
20
+
21
+ ### `useLoadingRef`
22
+
23
+ Creates a reactive variable tracking global loading status.
24
+
25
+ **Parameters:** none
26
+
27
+ **Returns:** `ShallowRef<boolean>` — reactive variable with loading status
28
+
29
+ ```javascript
30
+ import { useLoadingRef } from '@dxtmisha/functional'
31
+
32
+ // Create reactive variable
33
+ const isLoading = useLoadingRef()
34
+
35
+ // isLoading.value === true when there are active loads
36
+ // isLoading.value === false when no loads
37
+ ```
38
+
39
+ ## Basic Usage
40
+
41
+ ### Basic Loading Tracking
42
+
43
+ ```javascript
44
+ import { useLoadingRef } from '@dxtmisha/functional'
45
+ import { Loading } from '@dxtmisha/functional'
46
+
47
+ // In component
48
+ const isLoading = useLoadingRef()
49
+
50
+ // Show loader
51
+ Loading.show()
52
+ console.log(isLoading.value) // true
53
+
54
+ // Hide loader
55
+ Loading.hide()
56
+ console.log(isLoading.value) // false
57
+ ```
58
+
59
+ ### Working with Multiple Loads
60
+
61
+ ```javascript
62
+ import { useLoadingRef, Loading } from '@dxtmisha/functional'
63
+
64
+ const isLoading = useLoadingRef()
65
+
66
+ // First loading operation
67
+ Loading.show()
68
+ console.log(isLoading.value) // true (counter = 1)
69
+
70
+ // Second loading operation
71
+ Loading.show()
72
+ console.log(isLoading.value) // true (counter = 2)
73
+
74
+ // Complete first operation
75
+ Loading.hide()
76
+ console.log(isLoading.value) // true (counter = 1)
77
+
78
+ // Complete second operation
79
+ Loading.hide()
80
+ console.log(isLoading.value) // false (counter = 0)
81
+ ```
82
+
83
+ ## Usage in Components
84
+
85
+ ### Global Loading Indicator
86
+
87
+ ```javascript
88
+ import { useLoadingRef } from '@dxtmisha/functional'
89
+
90
+ export default {
91
+ setup() {
92
+ const isLoading = useLoadingRef()
93
+
94
+ return { isLoading }
95
+ }
96
+ }
97
+
98
+ // Template:
99
+ // <div v-if="isLoading" class="global-loader">
100
+ // <div class="spinner"></div>
101
+ // <p>Loading...</p>
102
+ // </div>
103
+ ```
104
+
105
+ ### Integration with API Requests
106
+
107
+ ```javascript
108
+ import { Loading } from '@dxtmisha/functional'
109
+ import { useLoadingRef } from '@dxtmisha/functional'
110
+
111
+ export default {
112
+ setup() {
113
+ const isLoading = useLoadingRef()
114
+
115
+ const fetchUserData = async () => {
116
+ Loading.show()
117
+
118
+ try {
119
+ const response = await fetch('/api/user')
120
+ const data = await response.json()
121
+ } catch (error) {
122
+ console.error('Error:', error)
123
+ } finally {
124
+ Loading.hide()
125
+ }
126
+ }
127
+
128
+ return { isLoading, fetchUserData }
129
+ }
130
+ }
131
+
132
+ // Template:
133
+ // <button @click="fetchUserData" :disabled="isLoading">
134
+ // Load Data
135
+ // </button>
136
+ ```
137
+
138
+ ## Integration with Loading Class
139
+
140
+ Composable is tightly integrated with `Loading` class:
141
+
142
+ ```javascript
143
+ import { Loading } from '@dxtmisha/functional'
144
+ import { useLoadingRef } from '@dxtmisha/functional'
145
+
146
+ // In component A
147
+ const isLoading = useLoadingRef()
148
+
149
+ // Anywhere in application
150
+ Loading.show() // isLoading.value automatically becomes true
151
+
152
+ // In another component B
153
+ Loading.hide() // isLoading.value in component A automatically updates
154
+
155
+ // Check status
156
+ console.log(Loading.is()) // true/false
157
+
158
+ // All components with useLoadingRef() will be synchronized
159
+ ```