@r2digisolutions/components 0.9.4 → 0.9.6

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.
@@ -112,7 +112,7 @@
112
112
  const viewTop = vv?.offsetTop ?? 0;
113
113
  const gap = 8;
114
114
  const pad = 8;
115
- const estimated = { panelW: Math.max(trigger.width, 192), panelH: 280 };
115
+ const estimated = { panelW: 208, panelH: 280 };
116
116
  const canMeasure = opts.measure !== false && !!panelEl?.matches(':popover-open');
117
117
  const panelW = Math.min(
118
118
  canMeasure && panelEl?.offsetWidth ? panelEl.offsetWidth : estimated.panelW,
@@ -139,12 +139,12 @@
139
139
  if (panelEl) {
140
140
  const s = panelEl.style;
141
141
  s.setProperty('margin', '0');
142
- s.setProperty('inset', 'auto');
142
+ s.removeProperty('inset');
143
143
  s.setProperty('top', `${Math.round(top)}px`);
144
144
  s.setProperty('left', `${Math.round(left)}px`);
145
145
  s.setProperty('right', 'auto');
146
146
  s.setProperty('bottom', 'auto');
147
- s.setProperty('width', `${Math.round(panelW)}px`);
147
+ s.setProperty('width', '13rem');
148
148
  s.setProperty('visibility', placed ? 'visible' : 'hidden');
149
149
  }
150
150
  }
@@ -246,27 +246,32 @@
246
246
  return `${h12} ${period}`;
247
247
  }
248
248
 
249
+ function scrollSelected(listEl: HTMLDivElement | null) {
250
+ const selected = listEl?.querySelector('[aria-selected="true"]') as HTMLElement | null;
251
+ if (!listEl || !selected) return;
252
+ // Don't use scrollIntoView — it also scrolls the dialog/modal ancestors.
253
+ listEl.scrollTop = selected.offsetTop - listEl.clientHeight / 2 + selected.clientHeight / 2;
254
+ }
255
+
249
256
  $effect(() => {
250
257
  if (!open) return;
251
258
  requestAnimationFrame(() => {
252
- const hEl = hourListEl?.querySelector('[aria-selected="true"]') as HTMLElement | null;
253
- const mEl = minuteListEl?.querySelector('[aria-selected="true"]') as HTMLElement | null;
254
- hEl?.scrollIntoView({ block: 'center' });
255
- mEl?.scrollIntoView({ block: 'center' });
259
+ scrollSelected(hourListEl);
260
+ scrollSelected(minuteListEl);
256
261
  });
257
262
  });
258
263
  </script>
259
264
 
260
- <div class={['w-full min-w-[12rem] max-w-[16rem]', className]}>
265
+ <div class={['w-full max-w-[16rem] min-w-[12rem]', className]}>
261
266
  {#if label}
262
- <span class="mb-1.5 block text-sm font-medium text-primary">{label}</span>
267
+ <span class="mb-1.5 text-sm font-medium text-primary block">{label}</span>
263
268
  {/if}
264
269
 
265
270
  <div
266
271
  bind:this={triggerEl}
267
272
  class={[
268
- 'flex h-10 w-full items-center overflow-hidden rounded-xl border border-border bg-surface-elevated transition-colors',
269
- open && 'border-brand-500 ring-2 ring-brand-500/20',
273
+ 'h-10 rounded-xl border-border bg-surface-elevated flex w-full items-center overflow-hidden border transition-colors',
274
+ open && 'border-brand-500 ring-brand-500/20 ring-2',
270
275
  disabled && 'opacity-60'
271
276
  ]}
272
277
  >
@@ -279,13 +284,13 @@
279
284
  aria-haspopup="dialog"
280
285
  aria-controls={panelId}
281
286
  class={[
282
- 'flex h-full min-w-0 flex-1 items-center gap-2 px-3.5 text-left text-sm',
287
+ 'min-w-0 gap-2 px-3.5 text-sm flex h-full flex-1 items-center text-left',
283
288
  'hover:bg-surface-overlay focus-visible:outline-none',
284
289
  disabled && 'cursor-not-allowed'
285
290
  ]}
286
291
  >
287
292
  <svg
288
- class="h-4 w-4 shrink-0 text-muted"
293
+ class="h-4 w-4 text-muted shrink-0"
289
294
  viewBox="0 0 24 24"
290
295
  fill="none"
291
296
  stroke="currentColor"
@@ -306,10 +311,16 @@
306
311
  <button
307
312
  type="button"
308
313
  onclick={clear}
309
- class="h-full px-3 text-muted hover:bg-surface-overlay hover:text-primary"
314
+ class="px-3 text-muted hover:bg-surface-overlay hover:text-primary h-full"
310
315
  aria-label="Clear"
311
316
  >
312
- <svg class="h-3.5 w-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
317
+ <svg
318
+ class="h-3.5 w-3.5"
319
+ viewBox="0 0 24 24"
320
+ fill="none"
321
+ stroke="currentColor"
322
+ stroke-width="2"
323
+ >
313
324
  <path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
314
325
  </svg>
315
326
  </button>
@@ -326,18 +337,18 @@
326
337
  onbeforetoggle={handleBeforeToggle}
327
338
  ontoggle={handleToggle}
328
339
  data-placed={placed ? true : undefined}
329
- class="timepicker-popover m-0 overflow-hidden rounded-2xl border border-border bg-surface-elevated shadow-xl outline-none"
340
+ class="timepicker-popover m-0 w-52 rounded-2xl border-border bg-surface-elevated shadow-xl overflow-hidden border outline-none"
330
341
  >
331
- <div class="grid grid-cols-2 divide-x divide-border">
342
+ <div class="divide-border grid grid-cols-2 divide-x">
332
343
  <div class="flex flex-col">
333
344
  <span
334
- class="border-b border-border px-3 py-2 text-center text-[11px] font-medium tracking-wide text-muted uppercase"
345
+ class="border-border px-3 py-2 font-medium tracking-wide text-muted border-b text-center text-[11px] uppercase"
335
346
  >
336
347
  Hour
337
348
  </span>
338
349
  <div
339
350
  bind:this={hourListEl}
340
- class="max-h-52 overflow-y-auto p-1.5"
351
+ class="max-h-52 p-1.5 overflow-y-auto"
341
352
  role="listbox"
342
353
  aria-label="Hours"
343
354
  >
@@ -350,8 +361,8 @@
350
361
  aria-selected={selectedH === h}
351
362
  onclick={() => pickHour(h)}
352
363
  class={[
353
- 'w-full rounded-lg px-2 py-1.5 text-sm transition-colors',
354
- 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-500/30',
364
+ 'rounded-lg px-2 py-1.5 text-sm w-full transition-colors',
365
+ 'focus-visible:ring-brand-500/30 focus-visible:ring-2 focus-visible:outline-none',
355
366
  disabledHour && 'cursor-not-allowed opacity-30',
356
367
  selectedH === h
357
368
  ? 'bg-brand-500 font-semibold text-white'
@@ -365,13 +376,13 @@
365
376
  </div>
366
377
  <div class="flex flex-col">
367
378
  <span
368
- class="border-b border-border px-3 py-2 text-center text-[11px] font-medium tracking-wide text-muted uppercase"
379
+ class="border-border px-3 py-2 font-medium tracking-wide text-muted border-b text-center text-[11px] uppercase"
369
380
  >
370
381
  Min
371
382
  </span>
372
383
  <div
373
384
  bind:this={minuteListEl}
374
- class="max-h-52 overflow-y-auto p-1.5"
385
+ class="max-h-52 p-1.5 overflow-y-auto"
375
386
  role="listbox"
376
387
  aria-label="Minutes"
377
388
  >
@@ -384,8 +395,8 @@
384
395
  aria-selected={selectedM === m}
385
396
  onclick={() => pickMinute(m)}
386
397
  class={[
387
- 'w-full rounded-lg px-2 py-1.5 text-sm transition-colors',
388
- 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-500/30',
398
+ 'rounded-lg px-2 py-1.5 text-sm w-full transition-colors',
399
+ 'focus-visible:ring-brand-500/30 focus-visible:ring-2 focus-visible:outline-none',
389
400
  disabledMin && 'cursor-not-allowed opacity-30',
390
401
  selectedM === m
391
402
  ? 'bg-brand-500 font-semibold text-white'
@@ -406,8 +417,12 @@
406
417
  .timepicker-popover {
407
418
  position: fixed;
408
419
  inset: unset;
420
+ top: auto;
421
+ right: auto;
422
+ bottom: auto;
423
+ left: auto;
409
424
  margin: 0;
410
- width: max-content;
425
+ width: 13rem;
411
426
  height: max-content;
412
427
  }
413
428
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@r2digisolutions/components",
3
- "version": "0.9.4",
3
+ "version": "0.9.6",
4
4
  "private": false,
5
5
  "description": "R2DigiSolutions Svelte 5 component library — Atomic Design, Tailwind 4, Light/Dark mode",
6
6
  "license": "MIT",