@bagelink/vue 1.15.245 → 1.15.249

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": "@bagelink/vue",
3
3
  "type": "module",
4
- "version": "1.15.245",
4
+ "version": "1.15.249",
5
5
  "description": "Bagel core sdk packages",
6
6
  "author": {
7
7
  "name": "Bagel Studio",
@@ -229,9 +229,10 @@ const slots: SetupContext['slots'] = useSlots()
229
229
  }, computedPairClass]" :style="gradientStyle" :tabindex="disabled ? -1 : 0" @click.stop="handleClick" @keydown.enter="handleClick" @keydown.space="handleClick"
230
230
  >
231
231
  <!-- Keep label/icons mounted while loading so the button width/height don't jump.
232
- absolute-fill + flex-center (not center-xy) so it stays centered in RTL too. -->
233
- <Loading v-if="loading" class="absolute-fill flex-center pointer-events-none" size="15" color="currentColor" />
234
- <div class="bgl_btn-flex" :class="{ invisible: loading }">
232
+ Hide them hard (visibility + opacity) so the icon never shows through the spinner.
233
+ absolute-fill + flex-center (not center-xy) so the spinner stays centered in RTL too. -->
234
+ <Loading v-if="loading" class="btn-loading absolute-fill flex-center pointer-events-none" size="15" color="currentColor" />
235
+ <div class="bgl_btn-flex" :class="{ 'btn-loading-hide': loading }">
235
236
  <Icon
236
237
  v-if="icon" :icon="icon" class="transition-400" :size="iconSizeComputed"
237
238
  :mobile-size="iconMobileSize"
@@ -299,6 +300,16 @@ justify-content: center;
299
300
  height: 100%;
300
301
  }
301
302
 
303
+ /* Hide content while the spinner overlays — visibility alone can still flash
304
+ icons (esp. icon-only flat buttons); opacity + z-index keeps the spinner on top. */
305
+ .bgl_btn-flex.btn-loading-hide {
306
+ visibility: hidden;
307
+ opacity: 0;
308
+ }
309
+ .bgl_btn .btn-loading {
310
+ z-index: 1;
311
+ }
312
+
302
313
  /* Loading.ring applies a thickness offset transform that pulls the spinner off-center */
303
314
  .bgl_btn :deep(.lds-ring) {
304
315
  transform: none;
@@ -10,6 +10,10 @@ const props = defineProps<{
10
10
  error?: string
11
11
  /** Color of the entered digits. Accepts any CSS color or theme var (e.g. "primary", "var(--bgl-primary)", "#e11d48"). */
12
12
  color?: string
13
+ /** Size of each digit box (width & height). Accepts any CSS length (e.g. "2.5rem", "40px"). Default: 3rem. */
14
+ size?: string
15
+ /** Digit box size below 910px. Falls back to `size` (or 3rem) when omitted. */
16
+ mobileSize?: string
13
17
  } & BagelInputShellProps>()
14
18
 
15
19
  const emit = defineEmits(['update:modelValue', 'complete'])
@@ -23,9 +27,11 @@ const digitColor = computed(() => {
23
27
  })
24
28
 
25
29
  const shellStyle = computed(() => {
26
- const color = digitColor.value
27
- if (!color) { return baseShellStyle.value }
28
- return { ...baseShellStyle.value, '--bgl-otp-digit-color': color }
30
+ const style = { ...(baseShellStyle.value ?? {}) } as Record<string, string>
31
+ if (digitColor.value) { style['--bgl-otp-digit-color'] = digitColor.value }
32
+ if (props.size) { style['--bgl-otp-digit-size'] = props.size }
33
+ if (props.mobileSize) { style['--bgl-otp-digit-mobile-size'] = props.mobileSize }
34
+ return Object.keys(style).length > 0 ? style : undefined
29
35
  })
30
36
 
31
37
  // ── Single-input model ──────────────────────────────────────────────────────
@@ -156,7 +162,7 @@ outline: none;
156
162
  .otp-hidden-input::selection { background: transparent; }
157
163
 
158
164
  .digit-box {
159
- height: 3rem;
165
+ height: var(--bgl-otp-digit-size, 3rem);
160
166
  aspect-ratio: 1;
161
167
  flex: 0 0 auto;
162
168
  color: var(--bgl-otp-digit-color, inherit);
@@ -168,7 +174,7 @@ background: var(--bgl-gray-light);
168
174
  border-radius: 5px;
169
175
  margin: 5px;
170
176
  text-align: center;
171
- font-size: 2.4rem;
177
+ font-size: calc(var(--bgl-otp-digit-size, 3rem) * 0.8);
172
178
  font-variant-numeric: tabular-nums;
173
179
  user-select: none;
174
180
  transition: outline-color 0.2s ease, box-shadow 0.2s ease;
@@ -210,6 +216,8 @@ outline-offset: -1px;
210
216
 
211
217
  @media screen and (max-width: 910px) {
212
218
  .digit-box {
219
+ height: var(--bgl-otp-digit-mobile-size, var(--bgl-otp-digit-size, 3rem));
220
+ font-size: calc(var(--bgl-otp-digit-mobile-size, var(--bgl-otp-digit-size, 3rem)) * 0.8);
213
221
  padding: 0.25rem;
214
222
  }
215
223
  }
@@ -260,6 +260,10 @@ function handleVisible(side: ResizableSide): boolean {
260
260
  let dragSide: ResizableSide | null = null
261
261
  let dragStartX = 0
262
262
  let dragStartW = 0
263
+ /** True while the user is drag-resizing a start/end rail. Suppresses the
264
+ * grid-template-columns transition so the track tracks the pointer 1:1
265
+ * instead of lagging behind a 300ms ease. */
266
+ const isRegionDragging = ref(false)
263
267
 
264
268
  function onResizeMove(e: PointerEvent) {
265
269
  if (!dragSide) { return }
@@ -280,6 +284,8 @@ function onResizeMove(e: PointerEvent) {
280
284
  }
281
285
  function onResizeUp() {
282
286
  dragSide = null
287
+ isRegionDragging.value = false
288
+ document.body.style.cursor = ''
283
289
  document.body.style.userSelect = ''
284
290
  window.removeEventListener('pointermove', onResizeMove)
285
291
  window.removeEventListener('pointerup', onResizeUp)
@@ -288,6 +294,8 @@ function onResizeDown(side: ResizableSide, e: PointerEvent) {
288
294
  dragSide = side
289
295
  dragStartX = e.clientX
290
296
  dragStartW = parsePx(regions.value[side].size, 0)
297
+ isRegionDragging.value = true
298
+ document.body.style.cursor = 'ew-resize'
291
299
  document.body.style.userSelect = 'none'
292
300
  window.addEventListener('pointermove', onResizeMove)
293
301
  window.addEventListener('pointerup', onResizeUp)
@@ -341,7 +349,7 @@ const slotBind = computed(() => ({ isOpen, isMobile, toggleMenu, closeOnMobile }
341
349
  </script>
342
350
 
343
351
  <template>
344
- <div class="app-layout vh-100 relative" :class="{ 'app-layout--resizing': isResizing }" :style="rootVars">
352
+ <div class="app-layout vh-100 relative" :class="{ 'app-layout--resizing': isResizing || isRegionDragging }" :style="rootVars">
345
353
  <!-- top region: a full-width band above the start/end rails. Everything
346
354
  below insets by --bgl-region-top so the nav is never overlapped. -->
347
355
  <div v-if="regions.top.present" class="region-band region-band--top">
@@ -352,7 +360,7 @@ const slotBind = computed(() => ({ isOpen, isMobile, toggleMenu, closeOnMobile }
352
360
  track size (rowStyle → grid-template-columns); each rail just fills its
353
361
  track. Overlay rails (mobile drawer, floating chat) collapse their track
354
362
  to 0 and their fixed child floats above instead. -->
355
- <div class="app-row relative" :class="{ 'app-layout--resizing': isResizing }" :style="rowStyle">
363
+ <div class="app-row relative" :class="{ 'app-layout--resizing': isResizing || isRegionDragging }" :style="rowStyle">
356
364
  <!-- Mobile sidebar drawer backdrop -->
357
365
  <div v-if="startOverlayOpen" class="overlay" @click="closeOnMobile" />
358
366
 
@@ -54,10 +54,12 @@ const tabComponent = defineComponent({
54
54
  const currentTabIndex = props.tabs.findIndex(
55
55
  tab => tabValue(tab) === currentTab.value
56
56
  )
57
- if (currentTabIndex === -1) { return }
58
- const slotChildren = slots.default?.()[1]?.children
59
-
60
- return h('div', (slotChildren as VNode[])[currentTabIndex])
57
+ if (currentTabIndex === -1) return null
58
+ // Nav-only usage (no default slot / no panel children) — render nothing.
59
+ const slotChildren = slots.default?.()?.[1]?.children as VNode[] | undefined
60
+ const panel = slotChildren?.[currentTabIndex]
61
+ if (!panel) return null
62
+ return h('div', panel)
61
63
  },
62
64
  })
63
65
  </script>
@@ -29,10 +29,11 @@ const props = defineProps<{
29
29
 
30
30
  const emit = defineEmits(['update:modelValue'])
31
31
  const { currentTab } = useTabs(props.group)
32
- currentTab.value
33
- = props.modelValue || typeof props.tabs[0] === 'string'
34
- ? props.tabs[0]
35
- : props.tabs[0].value
32
+ // Prefer controlled modelValue; otherwise the first tab's string value.
33
+ // (Parentheses required — `||` binds tighter than `?:` and used to assign the
34
+ // whole tab object when modelValue was set, breaking findIndex / isActive.)
35
+ currentTab.value = props.modelValue
36
+ || (typeof props.tabs[0] === 'string' ? props.tabs[0] : props.tabs[0]?.value)
36
37
 
37
38
  const tabsWrap = ref<HTMLElement | undefined>(undefined)
38
39
  const tabEls = ref<HTMLElement[]>([])