@mixd-id/web-scaffold 0.1.240411078 → 0.1.240411080

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.240411078",
4
+ "version": "0.1.240411080",
5
5
  "scripts": {
6
6
  "dev": "vite serve",
7
7
  "build": "vite build",
@@ -101,6 +101,11 @@ export default{
101
101
  timeoutId: null,
102
102
  scrollPosition: null,
103
103
  swiping: false,
104
+
105
+ // physics state
106
+ _rafId: null,
107
+ _anim: null,
108
+ _currentX: 0,
104
109
  }
105
110
  },
106
111
 
@@ -108,10 +113,17 @@ export default{
108
113
  window.addEventListener('touchmove', this.onTouchMove, { passive: false });
109
114
  if(this.autoPlay > 0)
110
115
  this.play()
116
+
117
+ // initialize transform position
118
+ window.requestAnimationFrame(() => {
119
+ this._currentX = this._getCurrentX()
120
+ this._applyX(this._currentX)
121
+ })
111
122
  },
112
123
 
113
124
  unmounted() {
114
125
  window.removeEventListener('touchmove', this.onTouchMove, { passive: false });
126
+ this._stopRaf()
115
127
  },
116
128
 
117
129
  watch:{
@@ -136,30 +148,99 @@ export default{
136
148
  }
137
149
  },
138
150
 
139
- setPosition(noAnimation) {
140
- if(!this.$refs.inner) return
151
+ _stopRaf(){
152
+ if(this._rafId){
153
+ cancelAnimationFrame(this._rafId)
154
+ this._rafId = null
155
+ }
156
+ this._anim = null
157
+ },
141
158
 
142
- const index = this.index
143
- let left = 0
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
175
+
176
+ let left = 0
144
177
  const gapPx = parseInt(window.getComputedStyle(this.$refs.inner).getPropertyValue('column-gap'))
145
- for(let curIndex = 0 ; curIndex < this.items.length ; curIndex++){
146
- const item = this.$refs.inner.children[curIndex]
147
- if(curIndex < index)
148
- left += (item.clientWidth + (!isNaN(gapPx) ? gapPx : 0))
149
- }
178
+ for(let curIndex = 0 ; curIndex < this.items.length ; curIndex++){
179
+ const item = this.$refs.inner.children[curIndex]
180
+ if(curIndex < index)
181
+ left += (item.clientWidth + (!isNaN(gapPx) ? gapPx : 0))
182
+ }
183
+
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()
150
196
 
151
- left *= -1
197
+ const startTime = performance.now()
198
+ let x = this._getCurrentX()
199
+ let v = 0
152
200
 
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')
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)
215
+
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)
226
+ }
227
+
228
+ this._rafId = requestAnimationFrame(step)
229
+ },
230
+
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
158
240
  }
159
241
 
160
- window.requestAnimationFrame(() => {
161
- this.$el.firstElementChild.style.transform = `translate3d(${left}px, 0, 0)`
162
- })
242
+ // spring settle
243
+ this._springTo(left)
163
244
  },
164
245
 
165
246
  setIndex(index){
@@ -176,18 +257,13 @@ export default{
176
257
  index = useBack === true ? 0 : this.items.length - 1
177
258
 
178
259
  this.index = index
179
-
180
260
  this.setPosition()
181
261
  },
182
262
 
183
263
  prev(){
184
-
185
264
  let index = this.index - 1;
186
-
187
265
  if(index < 0) index = 0
188
-
189
266
  this.index = index
190
-
191
267
  this.setPosition()
192
268
  },
193
269
 
@@ -217,16 +293,20 @@ export default{
217
293
  }
218
294
  }
219
295
  else if(this._props['direction'] === 'horizontal'){
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)
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)
227
306
  }
228
307
 
229
- this.$el.firstElementChild.style.transform = `translate3d(${ix}px, 0, 0)`
308
+ this._stopRaf() // user is directly controlling
309
+ this._applyX(nextX)
230
310
  }
231
311
 
232
312
  },
@@ -268,8 +348,9 @@ export default{
268
348
 
269
349
  this.stop()
270
350
 
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
351
+ // stop any running spring and capture current position
352
+ this._stopRaf()
353
+ const ix = this._getCurrentX()
273
354
 
274
355
  this._props = {
275
356
  sx:typeof e.touches !== 'undefined' ? e.touches[0].clientX : e.clientX,
@@ -292,21 +373,9 @@ export default{
292
373
 
293
374
  <style>
294
375
 
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
-
376
+ /* keep class for backwards compat but disable the old easing; spring animation is done in JS */
308
377
  .transition-carousel{
309
- transition: all 300ms cubic-bezier(0.25, 1, 0.5, 1);
378
+ transition: none;
310
379
  }
311
380
  </style>
312
381
 
@@ -198,6 +198,28 @@
198
198
  </div>
199
199
  </div>
200
200
 
201
+ <div>
202
+ <label :class="$style.label">Base Color</label>
203
+ <div class="mt-1 flex flex-row items-center gap-4">
204
+ <ColorPicker v-model="mediaOf(viewType, 'html, .html')['--base']" item-class="w-[48px] h-[48px]"
205
+ mode="hex" :custom-color="true" value-type="rgb"
206
+ @change="generateShade('--text', mediaOf(viewType, 'html, .html')['--text'])" />
207
+
208
+ <div class="grid grid-cols-5 gap-2 text-center">
209
+ <div>
210
+ <small class="text-xs text-text-400">400</small>
211
+ <ColorPicker v-model="mediaOf(viewType, 'html, .html')['--base-400']"
212
+ mode="hex" :custom-color="true" value-type="rgb" />
213
+ </div>
214
+ <div>
215
+ <small class="text-xs text-text-400">300</small>
216
+ <ColorPicker v-model="mediaOf(viewType, 'html, .html')['--base-300']"
217
+ mode="hex" :custom-color="true" value-type="rgb" />
218
+ </div>
219
+ </div>
220
+ </div>
221
+ </div>
222
+
201
223
  </div>
202
224
 
203
225
  <div class="p-6">
@@ -126,7 +126,7 @@
126
126
  @click="$refs.ogModal.open({ ...this.page.og }, og => page.og = og)"
127
127
  v-if="page.og && Object.keys(page.og).length > 0">
128
128
  <div>
129
- <Image :src="page.og.image" class="w-[40px] aspect-square bg-text-50" />
129
+ <Image :src="page.og.image" class="wpack-[40px] aspect-square bg-text-50" />
130
130
  </div>
131
131
  <div class="flex-1 flex flex-col">
132
132
  <label class="text-sm text-ellipsis-nowrap">
@@ -176,6 +176,8 @@
176
176
  </Dropdown>
177
177
  </div>
178
178
 
179
+ <slot name="info" :page="page"></slot>
180
+
179
181
  </div>
180
182
 
181
183
  <div v-else-if="store.tabIndex === 2" class="flex-1 overflow-y-auto p-6 flex flex-col gap-6">
@@ -930,6 +932,8 @@ export default{
930
932
  }
931
933
 
932
934
  this.readyState = 1
935
+
936
+ this.$emit('load')
933
937
  })
934
938
  .catch((err) => {
935
939
  this.toast(err)
@@ -1704,7 +1708,7 @@ export default{
1704
1708
  }
1705
1709
  },
1706
1710
 
1707
- emits: [ 'close', 'unmount' ],
1711
+ emits: [ 'close', 'load', 'unmount' ],
1708
1712
 
1709
1713
  inject: [ 'alert', 'appStyle', 'confirm', 'socket', 'toast' ],
1710
1714