@mixd-id/web-scaffold 0.1.240411080 → 0.1.240411082

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mixd-id/web-scaffold",
3
3
  "private": false,
4
- "version": "0.1.240411080",
4
+ "version": "0.1.240411082",
5
5
  "scripts": {
6
6
  "dev": "vite serve",
7
7
  "build": "vite build",
@@ -37,6 +37,7 @@
37
37
  "require": "./src/utils/preset-selector.cjs",
38
38
  "import": "./src/utils/preset-selector.mjs"
39
39
  },
40
+ "./selection": "./src/utils/selection.js",
40
41
  "./hooks/*": "./src/hooks/*",
41
42
  "./preset-selector.cjs": "./src/utils/preset-selector.cjs",
42
43
  "./preset-selector.js": "./src/utils/preset-selector.js",
@@ -5,10 +5,10 @@
5
5
  :style="computedStyle">
6
6
 
7
7
  <div ref="inner" :class="computedContainerClass">
8
- <div v-for="item in items" :class="computedItemClass">
8
+ <div v-for="item in items" :class="computedItemClass">
9
9
  <slot v-if="$slots['default']" :item="item"></slot>
10
- <component v-else :is="item.type" :="item" />
11
- </div>
10
+ <component v-else :is="item.type" :="item" />
11
+ </div>
12
12
  </div>
13
13
 
14
14
  <div v-if="useNextPrev && (items ?? []).length > 1 && index < items.length - 1" :class="$style.carouselNext" @click="next(true)">
@@ -21,7 +21,7 @@
21
21
  </slot>
22
22
  </div>
23
23
 
24
- <div v-if="useNextPrev && (items ?? []).length > 1 && index > 0" :class="$style.carouselPrev" @click="prev">
24
+ <div v-if="useNextPrev && (items ?? []).length > 1 && index > 0" :class="$style.carouselPrev" @click="prev">
25
25
  <slot name="prev">
26
26
  <div class="p-3">
27
27
  <button :class="$style.btn">
@@ -50,22 +50,22 @@ import {componentMixin} from "../mixin/component";
50
50
 
51
51
  export default{
52
52
 
53
- mixins: [ componentMixin ],
53
+ mixins: [ componentMixin ],
54
54
 
55
55
  props:{
56
56
 
57
57
  items: Array,
58
58
 
59
- infinite: {
60
- type: undefined,
61
- default: false
62
- },
59
+ infinite: {
60
+ type: undefined,
61
+ default: false
62
+ },
63
63
 
64
- ratio: Array,
64
+ ratio: Array,
65
65
 
66
- autoPlay: [ Number, String ],
66
+ autoPlay: [ Number, String ],
67
67
 
68
- useLegend: [ Boolean, Number ],
68
+ useLegend: [ Boolean, Number ],
69
69
 
70
70
  useNextPrev: [ Boolean, Number ],
71
71
 
@@ -73,68 +73,56 @@ export default{
73
73
 
74
74
  emits: [ 'change' ],
75
75
 
76
- computed: {
76
+ computed: {
77
77
 
78
- computedContainerClass(){
79
- return [
80
- this.$style.inner,
81
- this.containerClass
82
- ]
83
- .filter(_ => _)
84
- .join(' ')
85
- },
78
+ computedContainerClass(){
79
+ return [
80
+ this.$style.inner,
81
+ this.containerClass
82
+ ]
83
+ .filter(_ => _)
84
+ .join(' ')
85
+ },
86
86
 
87
- computedItemClass(){
88
- return [
89
- this.$style.item,
90
- this.itemClass
91
- ]
92
- .filter(_ => _)
93
- .join(' ')
94
- }
87
+ computedItemClass(){
88
+ return [
89
+ this.$style.item,
90
+ this.itemClass
91
+ ]
92
+ .filter(_ => _)
93
+ .join(' ')
94
+ }
95
95
 
96
- },
96
+ },
97
97
 
98
98
  data(){
99
99
  return {
100
100
  index: 0,
101
- timeoutId: null,
101
+ timeoutId: null,
102
102
  scrollPosition: null,
103
103
  swiping: false,
104
-
105
- // physics state
106
- _rafId: null,
107
- _anim: null,
108
- _currentX: 0,
109
104
  }
110
105
  },
111
106
 
112
107
  mounted(){
113
108
  window.addEventListener('touchmove', this.onTouchMove, { passive: false });
114
- if(this.autoPlay > 0)
115
- this.play()
116
-
117
- // initialize transform position
118
- window.requestAnimationFrame(() => {
119
- this._currentX = this._getCurrentX()
120
- this._applyX(this._currentX)
121
- })
109
+ if(this.autoPlay > 0)
110
+ this.play()
122
111
  },
123
112
 
124
113
  unmounted() {
125
114
  window.removeEventListener('touchmove', this.onTouchMove, { passive: false });
126
- this._stopRaf()
127
115
  },
128
116
 
129
117
  watch:{
130
118
 
131
- index(to){
119
+ index(to){
132
120
  this.$emit('change', to)
133
121
  },
134
122
 
135
- items(){
136
- this.index = 0
137
- },
123
+ items(){
124
+ this.index = 0
125
+ },
138
126
 
139
127
  },
140
128
 
@@ -148,31 +136,10 @@ export default{
148
136
  }
149
137
  },
150
138
 
151
- _stopRaf(){
152
- if(this._rafId){
153
- cancelAnimationFrame(this._rafId)
154
- this._rafId = null
155
- }
156
- this._anim = null
157
- },
158
-
159
- _applyX(x){
160
- this._currentX = x
161
- if(this.$el?.firstElementChild)
162
- this.$el.firstElementChild.style.transform = `translate3d(${x}px, 0, 0)`
163
- },
164
-
165
- _getCurrentX(){
166
- const t = this.$el?.firstElementChild?.style?.transform || ''
167
- const matches = t.match(/translate3d\((.*?)(?=\,)/)
168
- return matches != null && typeof matches[1] !== 'undefined'
169
- ? parseFloat(matches[1].replace('px', ''))
170
- : 0
171
- },
172
-
173
- _getTargetXForIndex(index){
174
- if(!this.$refs.inner) return 0
139
+ setPosition(noAnimation) {
140
+ if(!this.$refs.inner) return
175
141
 
142
+ const index = this.index
176
143
  let left = 0
177
144
  const gapPx = parseInt(window.getComputedStyle(this.$refs.inner).getPropertyValue('column-gap'))
178
145
  for(let curIndex = 0 ; curIndex < this.items.length ; curIndex++){
@@ -181,68 +148,20 @@ export default{
181
148
  left += (item.clientWidth + (!isNaN(gapPx) ? gapPx : 0))
182
149
  }
183
150
 
184
- return left * -1
185
- },
186
-
187
- _rubberBand(distance, dimension, constant = 0.55){
188
- // similar to iOS rubber-banding
189
- const abs = Math.abs(distance)
190
- const result = (dimension * constant * abs) / (dimension + constant * abs)
191
- return Math.sign(distance) * result
192
- },
193
-
194
- _springTo(targetX, { stiffness = 0.09, damping = 0.78, maxDuration = 900 } = {}){
195
- this._stopRaf()
196
-
197
- const startTime = performance.now()
198
- let x = this._getCurrentX()
199
- let v = 0
200
-
201
- const step = (now) => {
202
- const dtMs = now - (this._anim?.t || now)
203
- const dt = Math.min(0.032, Math.max(0.008, dtMs / 1000))
204
- this._anim = { t: now }
205
-
206
- // spring force
207
- const F = (targetX - x) * stiffness
208
- v = (v + F) * damping
209
- x = x + v / dt
210
-
211
- // numerical safety
212
- if(!isFinite(x)) x = targetX
213
-
214
- this._applyX(x)
151
+ left *= -1
215
152
 
216
- const elapsed = now - startTime
217
- const done = (Math.abs(targetX - x) < 0.5 && Math.abs(v) < 0.1) || elapsed > maxDuration
218
-
219
- if(done){
220
- this._applyX(targetX)
221
- this._stopRaf()
222
- return
223
- }
224
-
225
- this._rafId = requestAnimationFrame(step)
153
+ if(!noAnimation){
154
+ this.$el.firstElementChild.addEventListener('transitionend', function(){
155
+ this.classList.remove('transition-carousel')
156
+ })
157
+ this.$el.firstElementChild.classList.add('transition-carousel')
226
158
  }
227
159
 
228
- this._rafId = requestAnimationFrame(step)
160
+ window.requestAnimationFrame(() => {
161
+ this.$el.firstElementChild.style.transform = `translate3d(${left}px, 0, 0)`
162
+ })
229
163
  },
230
164
 
231
- setPosition(noAnimation) {
232
- if(!this.$refs.inner) return
233
-
234
- const left = this._getTargetXForIndex(this.index)
235
-
236
- if(noAnimation){
237
- this._stopRaf()
238
- window.requestAnimationFrame(() => this._applyX(left))
239
- return
240
- }
241
-
242
- // spring settle
243
- this._springTo(left)
244
- },
245
-
246
165
  setIndex(index){
247
166
  if(index >= 0 && index < this.items.length){
248
167
  this.index = index
@@ -257,25 +176,30 @@ export default{
257
176
  index = useBack === true ? 0 : this.items.length - 1
258
177
 
259
178
  this.index = index
179
+
260
180
  this.setPosition()
261
181
  },
262
182
 
263
183
  prev(){
184
+
264
185
  let index = this.index - 1;
186
+
265
187
  if(index < 0) index = 0
188
+
266
189
  this.index = index
190
+
267
191
  this.setPosition()
268
192
  },
269
193
 
270
- play(){
194
+ play(){
271
195
  if(this.autoPlay > 0)
272
- this.timeoutId = window.setTimeout(() => { this.next(true); this.play() }, this.autoPlay)
273
- },
196
+ this.timeoutId = window.setTimeout(() => { this.next(true); this.play() }, this.autoPlay)
197
+ },
274
198
 
275
- stop(){
276
- if(this.timeoutId)
277
- window.clearTimeout(this.timeoutId)
278
- },
199
+ stop(){
200
+ if(this.timeoutId)
201
+ window.clearTimeout(this.timeoutId)
202
+ },
279
203
 
280
204
  mouseMove(e){
281
205
  const sx = typeof e.touches !== 'undefined' ? e.touches[0].clientX : e.clientX
@@ -293,20 +217,16 @@ export default{
293
217
  }
294
218
  }
295
219
  else if(this._props['direction'] === 'horizontal'){
296
- const baseX = this._props['ix']
297
- let nextX = baseX + dx
298
-
299
- const atFirst = this.index === 0
300
- const atLast = this.index === this.items.length - 1
301
- const overscrolling = (atFirst && dx > 0) || (atLast && dx < 0)
302
-
303
- if(overscrolling){
304
- const dim = this.$el?.clientWidth || 1
305
- nextX = baseX + this._rubberBand(dx, dim)
220
+ let ix
221
+ if((this.index === this.items.length - 1 && dx < 0) ||
222
+ (this.index === 0 && dx > 0)){
223
+ ix = parseInt(this._props['ix'] + (dx * .19812))
224
+ }
225
+ else{
226
+ ix = parseInt(this._props['ix'] + dx)
306
227
  }
307
228
 
308
- this._stopRaf() // user is directly controlling
309
- this._applyX(nextX)
229
+ this.$el.firstElementChild.style.transform = `translate3d(${ix}px, 0, 0)`
310
230
  }
311
231
 
312
232
  },
@@ -338,19 +258,18 @@ export default{
338
258
  window.removeEventListener('touchmove', this.mouseMove)
339
259
  window.removeEventListener('touchend', this.mouseUp)
340
260
 
341
- if(this.autoPlay > 0)
342
- this.play()
261
+ if(this.autoPlay > 0)
262
+ this.play()
343
263
  },
344
264
 
345
265
  mouseDown(e){
346
- if(!this.items || this.items.length <= 1)
347
- return
266
+ if(!this.items || this.items.length <= 1)
267
+ return
348
268
 
349
- this.stop()
269
+ this.stop()
350
270
 
351
- // stop any running spring and capture current position
352
- this._stopRaf()
353
- const ix = this._getCurrentX()
271
+ var matches = this.$el.firstElementChild.style.transform.match(/translate3d\((.*?)(?=\,)/)
272
+ var ix = matches != null && typeof matches[1] != 'undefined' ? parseInt(matches[1].replace('px', '')) : 0
354
273
 
355
274
  this._props = {
356
275
  sx:typeof e.touches !== 'undefined' ? e.touches[0].clientX : e.clientX,
@@ -373,17 +292,29 @@ export default{
373
292
 
374
293
  <style>
375
294
 
376
- /* keep class for backwards compat but disable the old easing; spring animation is done in JS */
295
+ .carousel-next,
296
+ .carousel-prev{
297
+ position: absolute;
298
+ top: 50%;
299
+ transform: translate3d(0, -50%, 0);
300
+ }
301
+ .carousel-next{
302
+ right: 10px;
303
+ }
304
+ .carousel-prev{
305
+ left: 10px;
306
+ }
307
+
377
308
  .transition-carousel{
378
- transition: none;
309
+ transition: all 300ms cubic-bezier(0.25, 1, 0.5, 1);
379
310
  }
380
311
  </style>
381
312
 
382
313
  <style module>
383
314
 
384
315
  .comp{
385
- overflow: hidden;
386
- position: relative;
316
+ overflow: hidden;
317
+ position: relative;
387
318
  @apply flex flex-col;
388
319
  }
389
320
 
@@ -392,34 +323,34 @@ export default{
392
323
  }
393
324
 
394
325
  .carouselNext{
395
- @apply absolute top-0 bottom-0 right-0 flex items-center justify-center;
326
+ @apply absolute top-0 bottom-0 right-0 flex items-center justify-center;
396
327
  }
397
328
 
398
329
  .carouselPrev{
399
- @apply absolute top-0 bottom-0 left-0 flex items-center justify-center;
330
+ @apply absolute top-0 bottom-0 left-0 flex items-center justify-center;
400
331
  }
401
332
 
402
333
  .inner{
403
- will-change: transform;
404
- @apply flex flex-row items-stretch;
334
+ will-change: transform;
335
+ @apply flex flex-row items-stretch;
405
336
  }
406
337
  .inner>*{
407
- display: inline-block;
408
- width: 100%;
409
- min-width: 100%;
410
- vertical-align: top;
338
+ display: inline-block;
339
+ width: 100%;
340
+ min-width: 100%;
341
+ vertical-align: top;
411
342
  }
412
343
 
413
344
  .legend{
414
- @apply flex justify-center gap-2 py-1;
345
+ @apply flex justify-center gap-2 py-1;
415
346
  }
416
347
  .legend .legendItem{
417
348
  }
418
349
  .legend .legendItem>*{
419
- @apply w-2 h-2 rounded-full bg-gray-100;
350
+ @apply w-2 h-2 rounded-full bg-gray-100;
420
351
  }
421
352
  .legend .legendItemActive>*{
422
- @apply bg-primary-500;
353
+ @apply bg-primary-500;
423
354
  }
424
355
 
425
356
  .btn{
@@ -107,6 +107,7 @@ export default{
107
107
  moved: false,
108
108
  isVisible: false,
109
109
  actualSrc: null,
110
+ lastSrc: null
110
111
  }
111
112
  },
112
113
 
@@ -163,6 +164,8 @@ export default{
163
164
  if(!this.isVisible) return
164
165
 
165
166
  const setSrc = (src) => {
167
+ if(this.lastSrc && src === this.lastSrc) return
168
+
166
169
  let reader
167
170
 
168
171
  if(typeof src === 'string') {
@@ -173,6 +176,7 @@ export default{
173
176
 
174
177
  this.actualSrc = src
175
178
  this.status = 2
179
+ this.lastSrc = src
176
180
  }
177
181
 
178
182
  else if(src instanceof File){
@@ -181,11 +185,13 @@ export default{
181
185
  reader.addEventListener('load', () => {
182
186
  this.status = 2
183
187
  this.actualSrc = reader.result
188
+ this.lastSrc = src
184
189
  }, false)
185
190
 
186
191
  reader.addEventListener('error', () => {
187
192
  this.status = 3
188
193
  this.actualSrc = this.defaultSrc
194
+ this.lastSrc = src
189
195
  })
190
196
 
191
197
  reader.readAsDataURL(src)