@live-change/vue3-components 0.9.201 → 0.9.204

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.
package/README.md CHANGED
@@ -60,6 +60,33 @@ const synchronizedEvent = synchronized({
60
60
  const editable = synchronizedEvent.value
61
61
  ```
62
62
 
63
+ Przykład użycia `synchronizedList` (fragment z `rcstreamer`):
64
+
65
+ ```javascript
66
+ import { synchronizedList } from '@live-change/vue3-components'
67
+
68
+ const synchronizedAccessesList = synchronizedList({
69
+ source: accesses,
70
+ update: accessControlApi.updateSessionOrUserAndObjectOwnedAccess,
71
+ delete: accessControlApi.resetSessionOrUserAndObjectOwnedAccess,
72
+ identifiers: { object, objectType },
73
+ objectIdentifiers: ({ to, sessionOrUser, sessionOrUserType }) => ({
74
+ access: to, sessionOrUser, sessionOrUserType, object, objectType
75
+ }),
76
+ recursive: true
77
+ })
78
+
79
+ const synchronizedAccesses = synchronizedAccessesList.value
80
+ await synchronizedAccessesList.delete(synchronizedAccesses.value[0])
81
+ ```
82
+
83
+ `synchronizedList` jest przeznaczony do edycji list elementów (np. role dostępów), gdzie:
84
+
85
+ - `source` jest tablicą z `live(...)`,
86
+ - każdy element ma stabilne `id`,
87
+ - `identifiers` przekazuje kontekst wspólny dla listy,
88
+ - `objectIdentifiers` mapuje identyfikatory pojedynczego elementu pod akcje backendu.
89
+
63
90
  ### Formularze: `DefinedForm`, `CommandForm`, `FormBind`
64
91
 
65
92
  - **`DefinedForm`** – renderuje formularz na podstawie definicji (np. definicji akcji)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@live-change/vue3-components",
3
- "version": "0.9.201",
3
+ "version": "0.9.204",
4
4
  "description": "Live Change Framework - vue components",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -21,11 +21,12 @@
21
21
  },
22
22
  "homepage": "https://github.com/live-change/live-change-stack",
23
23
  "dependencies": {
24
- "@live-change/vue3-ssr": "^0.9.201",
24
+ "@live-change/vue3-ssr": "^0.9.204",
25
+ "@vueuse/core": "^12.3.0",
25
26
  "debug": "^4.3.4",
26
27
  "mitt": "3.0.1",
27
28
  "vue": "^3.5.12",
28
29
  "vue3-scroll-border": "0.1.7"
29
30
  },
30
- "gitHead": "c9d7d6987de61d4f4cfa04e583b94150ade7c7bf"
31
+ "gitHead": "6ac17ccf3c184ca4d7ef920f63827dbfd8749f96"
31
32
  }
@@ -0,0 +1,207 @@
1
+ <template>
2
+ <component :is="tag" ref="rootEl">
3
+ <div
4
+ v-if="showPlaceholder"
5
+ class="reactive-range-viewer-placeholder"
6
+ :style="{ minHeight: `${placeholderHeight}px` }"
7
+ />
8
+ <RangeViewer
9
+ v-else-if="currentBuckets"
10
+ :key="viewerKey"
11
+ v-bind="forwardedViewerProps"
12
+ :buckets="currentBuckets"
13
+ v-on="forwardedListeners"
14
+ >
15
+ <template v-for="(_, slotName) in slots" #[slotName]="slotProps">
16
+ <slot :name="slotName" v-bind="slotProps" />
17
+ </template>
18
+ </RangeViewer>
19
+ </component>
20
+ </template>
21
+
22
+ <script setup>
23
+ import { computed, onBeforeUnmount, ref, useAttrs, useSlots, watch } from 'vue'
24
+ import { useElementSize } from '@vueuse/core'
25
+ import { rangeBuckets } from '@live-change/vue3-ssr'
26
+ import RangeViewer from './RangeViewer.vue'
27
+
28
+ const props = defineProps({
29
+ pathFunction: {
30
+ type: Function,
31
+ required: true
32
+ },
33
+ sourceKey: {
34
+ default: undefined
35
+ },
36
+ preserveHeightOnReload: {
37
+ type: Boolean,
38
+ default: false
39
+ },
40
+ reloadOnPathFunctionChange: {
41
+ type: Boolean,
42
+ default: false
43
+ },
44
+ bucketSize: {
45
+ type: Number,
46
+ default: 20
47
+ },
48
+ initialPosition: {
49
+ type: String,
50
+ default: undefined
51
+ },
52
+ softClose: {
53
+ type: Boolean,
54
+ default: false
55
+ },
56
+ canLoadTop: {
57
+ type: Boolean,
58
+ default: true
59
+ },
60
+ canDropTop: {
61
+ type: Boolean,
62
+ default: false
63
+ },
64
+ canLoadBottom: {
65
+ type: Boolean,
66
+ default: true
67
+ },
68
+ canDropBottom: {
69
+ type: Boolean,
70
+ default: false
71
+ },
72
+ loadTopSensorSize: {
73
+ type: String,
74
+ default: '500px'
75
+ },
76
+ loadBottomSensorSize: {
77
+ type: String,
78
+ default: '500px'
79
+ },
80
+ dropTopSensorSize: {
81
+ type: String,
82
+ default: '5000px'
83
+ },
84
+ dropBottomSensorSize: {
85
+ type: String,
86
+ default: '5000px'
87
+ },
88
+ loadTopDelay: {
89
+ type: Number,
90
+ default: 200
91
+ },
92
+ loadBottomDelay: {
93
+ type: Number,
94
+ default: 200
95
+ },
96
+ dropTopDelay: {
97
+ type: Number,
98
+ default: 200
99
+ },
100
+ dropBottomDelay: {
101
+ type: Number,
102
+ default: 200
103
+ },
104
+ frozen: {
105
+ type: Boolean,
106
+ default: false
107
+ },
108
+ tag: {
109
+ type: String,
110
+ default: 'div'
111
+ }
112
+ })
113
+
114
+ const attrs = useAttrs()
115
+ const slots = useSlots()
116
+
117
+ const rootEl = ref(null)
118
+ const { height } = useElementSize(rootEl)
119
+
120
+ const currentBuckets = ref(null)
121
+ const showPlaceholder = ref(false)
122
+ const placeholderHeight = ref(0)
123
+ const viewerKey = ref(0)
124
+ let currentReloadToken = 0
125
+
126
+ const forwardedViewerProps = computed(() => ({
127
+ bucketSize: props.bucketSize,
128
+ initialPosition: props.initialPosition,
129
+ softClose: props.softClose,
130
+ canLoadTop: props.canLoadTop,
131
+ canDropTop: props.canDropTop,
132
+ canLoadBottom: props.canLoadBottom,
133
+ canDropBottom: props.canDropBottom,
134
+ loadTopSensorSize: props.loadTopSensorSize,
135
+ loadBottomSensorSize: props.loadBottomSensorSize,
136
+ dropTopSensorSize: props.dropTopSensorSize,
137
+ dropBottomSensorSize: props.dropBottomSensorSize,
138
+ loadTopDelay: props.loadTopDelay,
139
+ loadBottomDelay: props.loadBottomDelay,
140
+ dropTopDelay: props.dropTopDelay,
141
+ dropBottomDelay: props.dropBottomDelay,
142
+ frozen: props.frozen,
143
+ tag: props.tag
144
+ }))
145
+
146
+ const forwardedListeners = computed(() => {
147
+ const listeners = {}
148
+ for(const [key, value] of Object.entries(attrs)) {
149
+ if(key.startsWith('on')) listeners[key] = value
150
+ }
151
+ return listeners
152
+ })
153
+
154
+ async function buildBuckets() {
155
+ return await rangeBuckets(
156
+ (range, p) => props.pathFunction(range, p),
157
+ {
158
+ bucketSize: props.bucketSize,
159
+ initialPosition: props.initialPosition,
160
+ softClose: props.softClose
161
+ }
162
+ )
163
+ }
164
+
165
+ async function reloadBuckets() {
166
+ const token = ++currentReloadToken
167
+ if(props.preserveHeightOnReload) {
168
+ placeholderHeight.value = Math.max(height.value || 0, 1)
169
+ showPlaceholder.value = true
170
+ }
171
+ const newBuckets = await buildBuckets()
172
+ if(token !== currentReloadToken) {
173
+ newBuckets.dispose?.()
174
+ return
175
+ }
176
+ currentBuckets.value?.dispose?.()
177
+ currentBuckets.value = newBuckets
178
+ viewerKey.value++
179
+ showPlaceholder.value = false
180
+ }
181
+
182
+ watch(
183
+ () => props.sourceKey,
184
+ async () => {
185
+ await reloadBuckets()
186
+ },
187
+ { immediate: true }
188
+ )
189
+
190
+ watch(
191
+ () => props.pathFunction,
192
+ async () => {
193
+ if(!props.reloadOnPathFunctionChange) return
194
+ await reloadBuckets()
195
+ }
196
+ )
197
+
198
+ onBeforeUnmount(() => {
199
+ currentBuckets.value?.dispose?.()
200
+ })
201
+ </script>
202
+
203
+ <style scoped>
204
+ .reactive-range-viewer-placeholder {
205
+ width: 100%;
206
+ }
207
+ </style>
package/view/index.js CHANGED
@@ -1,12 +1,14 @@
1
1
  import ScrollLoader from "./ScrollLoader.vue"
2
2
  import VisibleArea from "./VisibleArea.vue"
3
3
  import RangeViewer from "./RangeViewer.vue"
4
+ import ReactiveRangeViewer from "./ReactiveRangeViewer.vue"
4
5
 
5
- export { ScrollLoader, VisibleArea, RangeViewer }
6
+ export { ScrollLoader, VisibleArea, RangeViewer, ReactiveRangeViewer }
6
7
 
7
8
  function registerViewComponents(app) {
8
9
  app.component("scroll-loader", ScrollLoader)
9
- app.component("visible-area", VisibleArea)
10
+ app.component("visible-area", VisibleArea)
11
+ app.component("reactive-range-viewer", ReactiveRangeViewer)
10
12
  }
11
13
 
12
14
  export { registerViewComponents }