@urbicon-ui/blocks 6.1.4 → 6.1.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.
@@ -10,7 +10,8 @@
10
10
  toIso,
11
11
  stripTime,
12
12
  addDays,
13
- clampMonth
13
+ clampMonth,
14
+ daysInMonth
14
15
  } from '../../date';
15
16
  import { DateGridController } from '../../internal/date-grid';
16
17
  import type { DateGridSelection, DateGridView } from '../../internal/date-grid';
@@ -43,6 +44,7 @@
43
44
  // Selection
44
45
  selectionMode = 'single',
45
46
  value = $bindable(undefined),
47
+ defaultDate,
46
48
  defaultMonth,
47
49
  defaultYear,
48
50
  // Locale
@@ -130,8 +132,12 @@
130
132
  // --- Reference date: the single anchor the grid is built around ---
131
133
  // Priority:
132
134
  // 1. the first selected date — a populated picker opens on its selection
133
- // 2. `defaultMonth` / `defaultYear` fallback when no value
134
- // 3. today
135
+ // 2. `defaultDate` an explicit day anchor (the only one that anchors a
136
+ // week/day view on a specific week without also selecting that day)
137
+ // 3. `defaultMonth` / `defaultYear` — month/year anchor (resolves to the 1st;
138
+ // fine for month/year views, but a week/day view then opens on the 1st's
139
+ // week, which can fall mostly in the prior month — use `defaultDate` there)
140
+ // 4. today
135
141
  // Read at mount time only; the user navigates freely afterwards. Remount (e.g.
136
142
  // via DatePicker's popover open/close) to re-anchor on the current selection.
137
143
  function firstDateOf(v: CalendarProps['value']): Date | undefined {
@@ -142,16 +148,19 @@
142
148
  }
143
149
  function resolveInitialReference(
144
150
  v: CalendarProps['value'],
151
+ date: Date | undefined,
145
152
  month: number | undefined,
146
153
  year: number | undefined
147
154
  ): Date {
148
- const anchor = firstDateOf(v);
155
+ const anchor = firstDateOf(v) ?? date;
149
156
  if (anchor) return stripTime(anchor);
150
157
  const today = stripTime(new Date());
151
158
  if (month == null && year == null) return today;
152
159
  return new Date(year ?? today.getFullYear(), month ?? today.getMonth(), 1);
153
160
  }
154
- let referenceDate = $state(resolveInitialReference(value, defaultMonth, defaultYear));
161
+ let referenceDate = $state(
162
+ resolveInitialReference(value, defaultDate, defaultMonth, defaultYear)
163
+ );
155
164
 
156
165
  // The month/year derived from the single reference date.
157
166
  const displayedMonth = $derived(referenceDate.getMonth());
@@ -373,7 +382,15 @@
373
382
  const targetMonth = ((total % 12) + 12) % 12;
374
383
  const clamped = clampMonth(targetMonth, targetYear, minDate, maxDate);
375
384
  controller.navDirection = delta > 0 ? 'forward' : 'backward';
376
- referenceDate = new Date(clamped.year, clamped.month, 1);
385
+ // Preserve the day-of-month (clamped) so a later switch to week/day view
386
+ // anchors on a real in-month day, not the 1st's (possibly prior-month) week.
387
+ const day = Math.min(referenceDate.getDate(), daysInMonth(clamped.year, clamped.month));
388
+ let next = new Date(clamped.year, clamped.month, day);
389
+ // clampMonth bounds the month; clamp the day too so it never lands before
390
+ // minDate / after maxDate within that boundary month.
391
+ if (minDate && next < stripTime(minDate)) next = stripTime(minDate);
392
+ if (maxDate && next > stripTime(maxDate)) next = stripTime(maxDate);
393
+ referenceDate = next;
377
394
  onMonthChange?.(clamped.month, clamped.year);
378
395
  }
379
396
 
@@ -391,8 +408,10 @@
391
408
 
392
409
  function navigateYear(delta: number) {
393
410
  controller.navDirection = delta > 0 ? 'forward' : 'backward';
394
- referenceDate = new Date(displayedYear + delta, displayedMonth, 1);
395
- onMonthChange?.(displayedMonth, displayedYear + delta);
411
+ const targetYear = displayedYear + delta;
412
+ const day = Math.min(referenceDate.getDate(), daysInMonth(targetYear, displayedMonth));
413
+ referenceDate = new Date(targetYear, displayedMonth, day);
414
+ onMonthChange?.(displayedMonth, targetYear);
396
415
  }
397
416
 
398
417
  function goToToday() {
@@ -400,7 +419,8 @@
400
419
  }
401
420
 
402
421
  function goToMonth(month: number, year: number) {
403
- referenceDate = new Date(year, month, 1);
422
+ const day = Math.min(referenceDate.getDate(), daysInMonth(year, month));
423
+ referenceDate = new Date(year, month, day);
404
424
  }
405
425
 
406
426
  function setView(v: CalendarViewMode) {
@@ -5,10 +5,13 @@ import type { CalendarEvent, CalendarEventCategory, CalendarSelection, CalendarV
5
5
  import type { CalendarVariants } from './calendar.variants';
6
6
  export type CalendarSlotName = 'base' | 'header' | 'title' | 'nav' | 'navButton' | 'grid' | 'weekdayHeader' | 'weekday' | 'weekRow' | 'weekNumber' | 'day' | 'dayNumber' | 'dotContainer' | 'dot' | 'list' | 'dateHeader' | 'empty' | 'item' | 'colorBar' | 'eventTitle' | 'eventDescription' | 'eventHelper' | 'legend' | 'legendItem' | 'legendDot' | 'legendLabel' | 'yearGrid' | 'yearMonth' | 'yearMonthTitle' | 'yearMiniDay' | 'yearMiniDot' | 'weekGrid' | 'weekColumn' | 'weekColumnHeader' | 'weekColumnDayName' | 'weekColumnDayNumber' | 'weekEventList' | 'weekAllDayEvent' | 'multiDayBar' | 'multiDayBarContainer' | 'agendaView' | 'agendaDayGroup' | 'agendaDayHeader' | 'agendaEventList' | 'dayView' | 'dayViewHeader' | 'dayEventList' | 'timeGrid' | 'timeLabel' | 'timeSlotRow' | 'timeDayColumn' | 'timeEvent' | 'allDayArea' | 'currentTimeLine' | 'weekTimeLayout' | 'eventPopover' | 'eventPopoverItem' | 'miniCalendar' | 'miniCalendarHeader' | 'miniCalendarTitle' | 'miniCalendarNavButton' | 'miniCalendarWeekday' | 'miniCalendarDay';
7
7
  /**
8
- * @description Flexible calendar component with month, year, week, and day views,
9
- * event display, date selection, and configurable layout.
8
+ * @description Flexible calendar component with month, year, week, and day views.
9
+ * Renders timed appointments, multi-day spans and recurrence on a time grid, with
10
+ * event display, date selection and configurable layout. For a headless grid that
11
+ * buckets your own domain content (meals, shifts, bookings) per day, use `Planner`.
10
12
  *
11
13
  * @tag display
14
+ * @related Planner
12
15
  * @related DatePicker
13
16
  * @related DateRangePicker
14
17
  *
@@ -53,8 +56,17 @@ export interface CalendarProps extends Omit<CalendarVariants, 'dayState' | 'hasE
53
56
  /** Currently selected date(s). Supports bind:value. */
54
57
  value?: CalendarSelection;
55
58
  /**
56
- * Initial displayed month (0–11). Used only when `value` is unset;
57
- * when `value` is provided, the calendar opens on the value's month.
59
+ * Initial reference day the grid is anchored on, without selecting it. Use
60
+ * this to open a **week** or **day** view on a specific week — `defaultMonth`/
61
+ * `defaultYear` resolve to the 1st, whose week can fall mostly in the previous
62
+ * month. Ignored when `value` is set (the selection anchors instead); takes
63
+ * priority over `defaultMonth`/`defaultYear`. Read at mount only.
64
+ */
65
+ defaultDate?: Date;
66
+ /**
67
+ * Initial displayed month (0–11). Used only when `value` and `defaultDate`
68
+ * are unset; when `value` is provided, the calendar opens on the value's
69
+ * month. Best for month/year views — for week/day views prefer `defaultDate`.
58
70
  * Defaults to current month.
59
71
  */
60
72
  defaultMonth?: number;
@@ -12,6 +12,16 @@ import type { ChartMargin, ChartPlot, ChartSlotClasses } from '../../internal/ch
12
12
  * @related BarChart
13
13
  * @related Sankey
14
14
  * @stability beta
15
+ *
16
+ * @example
17
+ * ```svelte
18
+ * <ChartFrame height={200} ariaLabel="Weekly revenue">
19
+ * {#snippet children({ innerWidth, innerHeight })}
20
+ * <!-- map your data onto innerWidth / innerHeight, then draw SVG marks -->
21
+ * <polyline points={pts} fill="none" class="stroke-primary" stroke-width="2" />
22
+ * {/snippet}
23
+ * </ChartFrame>
24
+ * ```
15
25
  */
16
26
  export interface ChartFrameProps extends Omit<HTMLAttributes<HTMLElement>, 'children'> {
17
27
  /** Fixed SVG height in px. @default 240 */
@@ -37,6 +37,11 @@ export declare function getYearMonths(year: number): {
37
37
  month: number;
38
38
  year: number;
39
39
  }[];
40
+ /**
41
+ * Number of days in a month, leap years included. `month` is 0-based
42
+ * (0 = January). Day 0 of the next month is the last day of this one.
43
+ */
44
+ export declare function daysInMonth(year: number, month: number): number;
40
45
  /**
41
46
  * Clamp a month/year to optional min/max date boundaries.
42
47
  * Returns the (possibly adjusted) month/year plus flags for whether navigating
@@ -77,6 +77,13 @@ export function getWeekNumber(date) {
77
77
  export function getYearMonths(year) {
78
78
  return Array.from({ length: 12 }, (_, i) => ({ month: i, year }));
79
79
  }
80
+ /**
81
+ * Number of days in a month, leap years included. `month` is 0-based
82
+ * (0 = January). Day 0 of the next month is the last day of this one.
83
+ */
84
+ export function daysInMonth(year, month) {
85
+ return new Date(year, month + 1, 0).getDate();
86
+ }
80
87
  /**
81
88
  * Clamp a month/year to optional min/max date boundaries.
82
89
  * Returns the (possibly adjusted) month/year plus flags for whether navigating
@@ -14,5 +14,5 @@
14
14
  */
15
15
  export { daysBetween, isInMonth, isInRange, isSameDay, isWeekend, stripTime } from './compare';
16
16
  export { formatDate, formatDateFull, formatDateRange, formatDayTitle, formatMonthShort, formatMonthYear, formatWeekRange, formatWeekTitle, getWeekdayNames } from './format';
17
- export { clampMonth, getMonthGrid, getWeekDates, getWeekNumber, getYearMonths } from './geometry';
17
+ export { clampMonth, daysInMonth, getMonthGrid, getWeekDates, getWeekNumber, getYearMonths } from './geometry';
18
18
  export { addDays, eachDayOfRange, endOfWeek, isoToDate, startOfWeek, toIso } from './range';
@@ -14,5 +14,5 @@
14
14
  */
15
15
  export { daysBetween, isInMonth, isInRange, isSameDay, isWeekend, stripTime } from './compare';
16
16
  export { formatDate, formatDateFull, formatDateRange, formatDayTitle, formatMonthShort, formatMonthYear, formatWeekRange, formatWeekTitle, getWeekdayNames } from './format';
17
- export { clampMonth, getMonthGrid, getWeekDates, getWeekNumber, getYearMonths } from './geometry';
17
+ export { clampMonth, daysInMonth, getMonthGrid, getWeekDates, getWeekNumber, getYearMonths } from './geometry';
18
18
  export { addDays, eachDayOfRange, endOfWeek, isoToDate, startOfWeek, toIso } from './range';
@@ -337,174 +337,7 @@ declare const blocksTranslations: {
337
337
  };
338
338
  };
339
339
  };
340
- export declare const blocksI18n: import("@urbicon-ui/i18n").PackageI18n<{
341
- readonly accessibility: {
342
- readonly avatar: "Avatar";
343
- readonly clearInput: "Clear input";
344
- readonly clearSearch: "Clear search";
345
- readonly clearSelection: "Clear selection";
346
- readonly closeDialog: "Close dialog";
347
- readonly closeDrawer: "Close drawer";
348
- readonly dismiss: "Dismiss";
349
- readonly fileUpload: "File upload";
350
- readonly loading: "Loading";
351
- readonly maximum: "Maximum";
352
- readonly minimum: "Minimum";
353
- readonly pagination: "Page navigation";
354
- readonly progress: "Progress";
355
- readonly slider: "Slider";
356
- readonly toggle: "Toggle";
357
- readonly removableBadge: "Removable badge";
358
- readonly removeBadge: "Remove badge";
359
- readonly removeFile: "Remove {{name}}";
360
- };
361
- readonly button: {
362
- readonly close: "Close";
363
- readonly apply: "Apply";
364
- readonly cancel: "Cancel";
365
- readonly confirm: "Confirm";
366
- };
367
- readonly menu: {
368
- readonly placeholder: "Select an option...";
369
- };
370
- readonly common: {
371
- readonly loading: "Loading...";
372
- };
373
- readonly languages: {
374
- readonly de: "Deutsch";
375
- readonly en: "English";
376
- readonly es: "Español";
377
- readonly fr: "Français";
378
- readonly it: "Italiano";
379
- readonly nl: "Nederlands";
380
- };
381
- readonly localeSwitcher: {
382
- readonly ariaLabel: "Language selection";
383
- readonly placeholder: "Select language...";
384
- };
385
- readonly pagination: {
386
- readonly next: "Next";
387
- readonly first: "First";
388
- readonly last: "Last";
389
- readonly page: "Page";
390
- readonly previous: "Previous";
391
- };
392
- readonly calendar: {
393
- readonly recurring: "Recurring event";
394
- readonly previousMonth: "Previous month";
395
- readonly nextMonth: "Next month";
396
- readonly previousWeek: "Previous week";
397
- readonly nextWeek: "Next week";
398
- readonly previousDay: "Previous day";
399
- readonly nextDay: "Next day";
400
- readonly previousYear: "Previous year";
401
- readonly nextYear: "Next year";
402
- readonly today: "Today";
403
- readonly calendarGrid: "Calendar";
404
- readonly weekdays: "Weekdays";
405
- readonly weekNumber: "Week number";
406
- readonly events: "Events";
407
- readonly noEvents: "No events";
408
- readonly showMore: "{{count}} more";
409
- readonly legend: "Legend";
410
- readonly yearView: "Year overview";
411
- readonly weekView: "Week view";
412
- readonly dayView: "Day view";
413
- readonly monthView: "Month view";
414
- readonly viewMonth: "Month";
415
- readonly viewYear: "Year";
416
- readonly viewWeek: "Week";
417
- readonly viewDay: "Day";
418
- readonly multiDayLabel: "Day {{current}} of {{total}}";
419
- readonly agendaView: "Agenda view";
420
- readonly viewAgenda: "Agenda";
421
- readonly viewSwitcher: "View mode";
422
- };
423
- readonly planner: {
424
- readonly previousWeek: "Previous week";
425
- readonly nextWeek: "Next week";
426
- readonly previousMonth: "Previous month";
427
- readonly nextMonth: "Next month";
428
- readonly previousRange: "Previous range";
429
- readonly nextRange: "Next range";
430
- readonly today: "Today";
431
- readonly grid: "Planner";
432
- readonly weekNumber: "Week number";
433
- readonly itemCount: "{{count}} items";
434
- };
435
- readonly commandPalette: {
436
- readonly noResults: "No results found.";
437
- readonly search: "Search...";
438
- readonly hints: {
439
- readonly navigate: "Navigate";
440
- readonly select: "Select";
441
- readonly close: "Close";
442
- };
443
- };
444
- readonly compositionBar: {
445
- readonly total: "Total";
446
- readonly summary: "Composition: {{total}} ({{count}} shares) — {{parts}}";
447
- readonly share: "Share";
448
- readonly value: "Value";
449
- readonly percent: "Percent";
450
- readonly remaining: "remaining";
451
- };
452
- readonly guide: {
453
- readonly next: "Next";
454
- readonly previous: "Back";
455
- readonly skip: "Skip tour";
456
- readonly done: "Done";
457
- readonly step: "Step {{current}} of {{total}}";
458
- readonly tour: "Guided tour";
459
- readonly close: "Close";
460
- readonly openHelp: "Help";
461
- readonly backToList: "All topics";
462
- readonly info: "More information";
463
- readonly infoAbout: "More information about {{label}}";
464
- readonly dismiss: "Dismiss hint";
465
- readonly startTour: "Start the guided tour";
466
- readonly actionRequired: "Complete the highlighted action to continue";
467
- };
468
- readonly datepicker: {
469
- readonly placeholder: "Select a date...";
470
- readonly rangePlaceholder: "Select a date range...";
471
- readonly clear: "Clear selection";
472
- readonly openCalendar: "Open calendar";
473
- readonly invalidDate: "Invalid date";
474
- readonly outOfRange: "Date is outside the allowed range";
475
- readonly invalidRange: "Invalid date range";
476
- };
477
- readonly fileUpload: {
478
- readonly exists: "File already added";
479
- readonly invalidType: "File type {{type}} is not allowed";
480
- readonly tooLarge: "File exceeds {{size}} limit";
481
- readonly tooMany: "Maximum {{count}} files allowed";
482
- readonly tooSmall: "File must be at least {{size}}";
483
- };
484
- readonly sankey: {
485
- readonly summary: "Sankey diagram: {{nodes}} nodes, {{links}} links — {{flows}}";
486
- readonly source: "Source";
487
- readonly target: "Target";
488
- readonly value: "Value";
489
- };
490
- readonly slider: {
491
- readonly rangeStatus: {
492
- readonly insideRecommended: "In recommended range";
493
- readonly insideValid: "In valid range";
494
- readonly insideValidOnly: "Outside recommended range, but valid";
495
- readonly outsideValid: "Outside valid range";
496
- };
497
- };
498
- readonly themeSwitcher: {
499
- readonly lightMode: "Light mode";
500
- readonly darkMode: "Dark mode";
501
- readonly systemTheme: "System theme";
502
- };
503
- readonly time: {
504
- readonly ago: "{{value}} {{unit}} ago";
505
- readonly now: "now";
506
- };
507
- }>;
340
+ export declare const blocksI18n: import("@urbicon-ui/i18n").PackageI18n<import("@urbicon-ui/i18n").Translations>;
508
341
  /**
509
342
  * Context-scoped translation hook for the blocks package. Call during component
510
343
  * initialisation, then use the returned `t` (conventionally aliased `bt`):
@@ -517,174 +350,7 @@ export declare const blocksI18n: import("@urbicon-ui/i18n").PackageI18n<{
517
350
  * Resolves against the nearest `<I18nProvider>`'s locale (or the base locale
518
351
  * when none is mounted) and re-renders reactively on locale change.
519
352
  */
520
- export declare const useBlocksI18n: () => import("@urbicon-ui/i18n").TypedTranslationFunction<{
521
- readonly accessibility: {
522
- readonly avatar: "Avatar";
523
- readonly clearInput: "Clear input";
524
- readonly clearSearch: "Clear search";
525
- readonly clearSelection: "Clear selection";
526
- readonly closeDialog: "Close dialog";
527
- readonly closeDrawer: "Close drawer";
528
- readonly dismiss: "Dismiss";
529
- readonly fileUpload: "File upload";
530
- readonly loading: "Loading";
531
- readonly maximum: "Maximum";
532
- readonly minimum: "Minimum";
533
- readonly pagination: "Page navigation";
534
- readonly progress: "Progress";
535
- readonly slider: "Slider";
536
- readonly toggle: "Toggle";
537
- readonly removableBadge: "Removable badge";
538
- readonly removeBadge: "Remove badge";
539
- readonly removeFile: "Remove {{name}}";
540
- };
541
- readonly button: {
542
- readonly close: "Close";
543
- readonly apply: "Apply";
544
- readonly cancel: "Cancel";
545
- readonly confirm: "Confirm";
546
- };
547
- readonly menu: {
548
- readonly placeholder: "Select an option...";
549
- };
550
- readonly common: {
551
- readonly loading: "Loading...";
552
- };
553
- readonly languages: {
554
- readonly de: "Deutsch";
555
- readonly en: "English";
556
- readonly es: "Español";
557
- readonly fr: "Français";
558
- readonly it: "Italiano";
559
- readonly nl: "Nederlands";
560
- };
561
- readonly localeSwitcher: {
562
- readonly ariaLabel: "Language selection";
563
- readonly placeholder: "Select language...";
564
- };
565
- readonly pagination: {
566
- readonly next: "Next";
567
- readonly first: "First";
568
- readonly last: "Last";
569
- readonly page: "Page";
570
- readonly previous: "Previous";
571
- };
572
- readonly calendar: {
573
- readonly recurring: "Recurring event";
574
- readonly previousMonth: "Previous month";
575
- readonly nextMonth: "Next month";
576
- readonly previousWeek: "Previous week";
577
- readonly nextWeek: "Next week";
578
- readonly previousDay: "Previous day";
579
- readonly nextDay: "Next day";
580
- readonly previousYear: "Previous year";
581
- readonly nextYear: "Next year";
582
- readonly today: "Today";
583
- readonly calendarGrid: "Calendar";
584
- readonly weekdays: "Weekdays";
585
- readonly weekNumber: "Week number";
586
- readonly events: "Events";
587
- readonly noEvents: "No events";
588
- readonly showMore: "{{count}} more";
589
- readonly legend: "Legend";
590
- readonly yearView: "Year overview";
591
- readonly weekView: "Week view";
592
- readonly dayView: "Day view";
593
- readonly monthView: "Month view";
594
- readonly viewMonth: "Month";
595
- readonly viewYear: "Year";
596
- readonly viewWeek: "Week";
597
- readonly viewDay: "Day";
598
- readonly multiDayLabel: "Day {{current}} of {{total}}";
599
- readonly agendaView: "Agenda view";
600
- readonly viewAgenda: "Agenda";
601
- readonly viewSwitcher: "View mode";
602
- };
603
- readonly planner: {
604
- readonly previousWeek: "Previous week";
605
- readonly nextWeek: "Next week";
606
- readonly previousMonth: "Previous month";
607
- readonly nextMonth: "Next month";
608
- readonly previousRange: "Previous range";
609
- readonly nextRange: "Next range";
610
- readonly today: "Today";
611
- readonly grid: "Planner";
612
- readonly weekNumber: "Week number";
613
- readonly itemCount: "{{count}} items";
614
- };
615
- readonly commandPalette: {
616
- readonly noResults: "No results found.";
617
- readonly search: "Search...";
618
- readonly hints: {
619
- readonly navigate: "Navigate";
620
- readonly select: "Select";
621
- readonly close: "Close";
622
- };
623
- };
624
- readonly compositionBar: {
625
- readonly total: "Total";
626
- readonly summary: "Composition: {{total}} ({{count}} shares) — {{parts}}";
627
- readonly share: "Share";
628
- readonly value: "Value";
629
- readonly percent: "Percent";
630
- readonly remaining: "remaining";
631
- };
632
- readonly guide: {
633
- readonly next: "Next";
634
- readonly previous: "Back";
635
- readonly skip: "Skip tour";
636
- readonly done: "Done";
637
- readonly step: "Step {{current}} of {{total}}";
638
- readonly tour: "Guided tour";
639
- readonly close: "Close";
640
- readonly openHelp: "Help";
641
- readonly backToList: "All topics";
642
- readonly info: "More information";
643
- readonly infoAbout: "More information about {{label}}";
644
- readonly dismiss: "Dismiss hint";
645
- readonly startTour: "Start the guided tour";
646
- readonly actionRequired: "Complete the highlighted action to continue";
647
- };
648
- readonly datepicker: {
649
- readonly placeholder: "Select a date...";
650
- readonly rangePlaceholder: "Select a date range...";
651
- readonly clear: "Clear selection";
652
- readonly openCalendar: "Open calendar";
653
- readonly invalidDate: "Invalid date";
654
- readonly outOfRange: "Date is outside the allowed range";
655
- readonly invalidRange: "Invalid date range";
656
- };
657
- readonly fileUpload: {
658
- readonly exists: "File already added";
659
- readonly invalidType: "File type {{type}} is not allowed";
660
- readonly tooLarge: "File exceeds {{size}} limit";
661
- readonly tooMany: "Maximum {{count}} files allowed";
662
- readonly tooSmall: "File must be at least {{size}}";
663
- };
664
- readonly sankey: {
665
- readonly summary: "Sankey diagram: {{nodes}} nodes, {{links}} links — {{flows}}";
666
- readonly source: "Source";
667
- readonly target: "Target";
668
- readonly value: "Value";
669
- };
670
- readonly slider: {
671
- readonly rangeStatus: {
672
- readonly insideRecommended: "In recommended range";
673
- readonly insideValid: "In valid range";
674
- readonly insideValidOnly: "Outside recommended range, but valid";
675
- readonly outsideValid: "Outside valid range";
676
- };
677
- };
678
- readonly themeSwitcher: {
679
- readonly lightMode: "Light mode";
680
- readonly darkMode: "Dark mode";
681
- readonly systemTheme: "System theme";
682
- };
683
- readonly time: {
684
- readonly ago: "{{value}} {{unit}} ago";
685
- readonly now: "now";
686
- };
687
- }>;
353
+ export declare const useBlocksI18n: any;
688
354
  export declare const hasBlocksTranslation: (key: string) => boolean, getBlocksLocales: () => import("@urbicon-ui/i18n").Locale[];
689
355
  export type BlocksTranslationKey = keyof typeof enTranslations;
690
356
  export { blocksTranslations };
@@ -1,6 +1,4 @@
1
1
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2
- <path d="M4 4v16h16" />
3
- <path d="M7.5 14l3.5-4 3 2.5L20 6.5" />
4
- <path d="M11 10v10" />
5
- <path d="M14 12.5v7.5" />
2
+ <path d="M5 4v14.5h15" />
3
+ <path d="M8 18.5v-4l3-3.5 3 2.5 4-6V18.5z" />
6
4
  </svg>
@@ -1,8 +1,9 @@
1
1
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2
2
  <circle cx="5.5" cy="16" r="3.5" />
3
3
  <circle cx="18.5" cy="16" r="3.5" />
4
- <path d="M5.5 16l3.5-7h5.5l4 7" />
5
- <path d="M9 9l5.5 7" />
6
- <path d="M8 9h2.5" />
7
- <path d="M13.5 8.5h2.5" />
4
+ <path d="M5.5 16L8 9l1.5 7" />
5
+ <path d="M8 9h6.5l4 7" />
6
+ <path d="M9.5 16L14.5 9" />
7
+ <path d="M6.5 9h3" />
8
+ <path d="M14.5 9l2-1" />
8
9
  </svg>
@@ -1,8 +1,8 @@
1
1
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2
- <path d="M2.5 15.5v-3l2-1 2-3.5h8l2.5 3.5 2.5 1v3" />
3
- <path d="M2.5 15.5h2.5" />
4
- <path d="M10.5 15.5h6" />
5
- <path d="M6 11.5h10.5" />
6
- <circle cx="7.5" cy="15.5" r="2" />
7
- <circle cx="16" cy="15.5" r="2" />
2
+ <path d="M3 14.5l1-3.5h2.5l2-3h5l2 3h2.5l1 3.5" />
3
+ <path d="M3 15.5h2a2 2 0 0 0 4 0h4a2 2 0 0 0 4 0h2" />
4
+ <path d="M3 14.5v1" />
5
+ <path d="M19 14.5v1" />
6
+ <circle cx="7" cy="15.5" r="2" />
7
+ <circle cx="15" cy="15.5" r="2" />
8
8
  </svg>
@@ -1,8 +1,8 @@
1
1
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2
- <circle cx="8" cy="7.5" r="2.5" />
2
+ <circle cx="8" cy="7" r="2.5" />
3
3
  <path d="M8 2v1.5" />
4
- <path d="M3.5 7.5H2" />
5
- <path d="M4.5 4l1 1" />
6
- <path d="M12 4l-1 1" />
7
- <path d="M8.5 13.5A5 5 0 1 1 17 9h.5a4 4 0 0 1 0 8h-7a4 4 0 0 1-2-3.5z" />
4
+ <path d="M3 7h1.5" />
5
+ <path d="M4.5 3.5l1 1" />
6
+ <path d="M11.5 3.5l-1 1" />
7
+ <path d="M10 18h7.5a3 3 0 0 0 .3-6 4.5 4.5 0 0 0-8.5-1.3A3.2 3.2 0 0 0 10 18z" />
8
8
  </svg>
@@ -1,4 +1,4 @@
1
1
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2
- <path d="M18 19h-6a3 3 0 0 1-3-3V10" />
3
- <path d="M12 13l-3-3 3-3" />
2
+ <path d="M18 19v-6a3 3 0 0 0-3-3H5.5" />
3
+ <path d="M9.5 6L5.5 10l4 4" />
4
4
  </svg>
@@ -1,6 +1,8 @@
1
1
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2
- <path d="M4 13.5a8 8 0 0 1 16 0" />
3
- <path d="M7 13.5a5 5 0 0 1 10 0" />
4
- <path d="M10 13.5a2 2 0 0 1 4 0" />
5
- <path d="M12 11.5v6" />
2
+ <path d="M3.5 13.5a8.5 8.5 0 0 1 17 0" />
3
+ <path d="M3.5 13.5v3" />
4
+ <path d="M20.5 13.5v3" />
5
+ <path d="M6.5 13.5a5.5 5.5 0 0 1 11 0v4.5" />
6
+ <path d="M9.5 13.5a2.5 2.5 0 0 1 5 0v6" />
7
+ <path d="M8 17v1" />
6
8
  </svg>
@@ -1,5 +1,4 @@
1
1
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2
- <rect x="4" y="4.5" width="11" height="5" rx="0.5" />
3
- <path d="M8 9.5v1.5a1 1 0 0 0 1 1h1a1 1 0 0 0 1-1V9.5" />
4
- <path d="M9.5 12V14L17 21.5" />
2
+ <path d="M12.079242 3.1956944 20.280747 11.3972c0.195868 0.195868 0.195868 0.511238 0 0.707107l-2.828427 2.828427c-0.195869 0.195868-0.511238 0.195868-0.707107 0L11.249076 9.436597c0 0 0.641245-1.4193327 0.351653-2.2323806C11.299964 6.3597986 9.604511 4.999491 9.604511 4.999491l1.767624-1.8037966c0.193874-0.1978419 0.511238-0.1958685 0.707107 0z" />
3
+ <path d="M13.294631 11.482152 5.7224874 19.254447" />
5
4
  </svg>
@@ -1,6 +1,5 @@
1
1
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2
- <circle cx="9" cy="6" r="3.5" />
3
- <circle cx="16.5" cy="8" r="2.5" />
4
- <path d="M2.5 16.5l3-2 3.5 1.5h3a1.5 1.5 0 0 0 0-3H8.5" />
5
- <path d="M2.5 21l3.5-2 4 1.5 5-2 6-3" />
2
+ <circle cx="16" cy="5" r="2" />
3
+ <circle cx="16" cy="12" r="2" />
4
+ <path d="M11.16 14.91 8.03 12.55H1.88l9.42 7.51h6l3.59-2.84v-2" />
6
5
  </svg>
@@ -1,5 +1,7 @@
1
1
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2
- <path d="M5 14.5a7 7 0 0 1 14 0" />
3
- <path d="M3 14.5h18v1.5a1.5 1.5 0 0 1-1.5 1.5H4.5A1.5 1.5 0 0 1 3 16v-1.5z" />
4
- <path d="M9 14V9.5a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1V14" />
2
+ <path d="M4.5 14a7.5 7 0 0 1 15 0" />
3
+ <path d="M2.5 14h19a2 2 0 0 1-2 2H4.5a2 2 0 0 1-2-2z" />
4
+ <path d="M12 7v2.5" />
5
+ <path d="M8.5 9.5l.5-2" />
6
+ <path d="M15.5 9.5l-.5-2" />
5
7
  </svg>
@@ -1,5 +1,4 @@
1
1
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2
- <path d="M2.5 10.5L12 4l9.5 6.5V19a2 2 0 0 1-2 2h-15a2 2 0 0 1-2-2z" />
3
- <path d="M2.5 10.5L12 16l9.5-5.5" />
4
- <path d="M7.5 9V5.5a1 1 0 0 1 1-1h7a1 1 0 0 1 1 1V9" />
2
+ <path d="M3 10.5L12 4l9 6.5V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
3
+ <path d="M3 10.5l9 6 9-6" />
5
4
  </svg>
@@ -1,8 +1,9 @@
1
1
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2
- <path d="M13.5 6.5c3.6.5 6.5 3.2 6.5 6.5 0 1.7-.8 3.2-2 4.3V20h-3v-1.5h-4V20h-3v-1.7c-1.85-1.1-3-2.85-3-4.8 0-3.3 2.9-6 6.5-6z" />
3
- <path d="M5 11.5C3.4 11.3 3 9 3 9c1.7.2 2.6 1.2 2.9 2" />
4
- <path d="M11 6.7A3.5 3.5 0 0 1 14 3.5" />
5
- <path d="M10 7.5h4" />
6
- <path d="M16.5 11h.01" />
7
- <path d="M20 13.5h1.5" />
2
+ <ellipse cx="11" cy="12" rx="6.5" ry="5.5" />
3
+ <circle cx="18" cy="12.5" r="1.5" />
4
+ <path d="M15.3 7.65V5.39l-2.01 1.23" />
5
+ <path d="M11 9.15V6.39" />
6
+ <path d="M14.29 10.39h.01" />
7
+ <path d="M7.62 17.39v1.5" />
8
+ <path d="M14.62 17.39v1.5" />
8
9
  </svg>
@@ -1,8 +1,8 @@
1
1
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2
- <path d="M9 6.5L12 3l3 3.5" />
3
- <path d="M12 3.5a9 9 0 0 1 7.8 4.5" />
4
- <path d="M20 13.5l1.5-4.5-4.5-0.5" />
5
- <path d="M20.8 9a9 9 0 0 1-3.8 11.5" />
6
- <path d="M9 19l-4.5 1 1.5-4.5" />
7
- <path d="M5 20.5A9 9 0 0 1 4 8" />
2
+ <path d="M14.35 4.53L19.16 12.81" />
3
+ <path d="M19.98 9.74L19.16 12.81 16.08 11.99" />
4
+ <path d="M4.02 12.81L8.83 4.53" />
5
+ <path d="M5.74 5.35L8.83 4.53 9.65 7.6" />
6
+ <path d="M16.17 17.23L6.57 17.23" />
7
+ <path d="M8.83 14.98L6.57 17.23 8.83 19.47" />
8
8
  </svg>
@@ -1,9 +1,8 @@
1
1
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2
- <line x1="12" y1="2.5" x2="12" y2="21.5" />
3
- <path d="M3.75 7.25L20.25 16.75" />
4
- <path d="M20.25 7.25L3.75 16.75" />
5
- <path d="M9.5 5l2.5 2 2.5-2" />
6
- <path d="M9.5 19l2.5-2 2.5 2" />
7
- <path d="M5 9.5l.75 2.5L5 14.5" />
8
- <path d="M19 9.5l-.75 2.5.75 2.5" />
2
+ <g transform="rotate(0 12 12)"><path d="M12 12V3.5" /><path d="M12 6.5l-2-1.8" /><path d="M12 6.5l2-1.8" /></g>
3
+ <g transform="rotate(60 12 12)"><path d="M12 12V3.5" /><path d="M12 6.5l-2-1.8" /><path d="M12 6.5l2-1.8" /></g>
4
+ <g transform="rotate(120 12 12)"><path d="M12 12V3.5" /><path d="M12 6.5l-2-1.8" /><path d="M12 6.5l2-1.8" /></g>
5
+ <g transform="rotate(180 12 12)"><path d="M12 12V3.5" /><path d="M12 6.5l-2-1.8" /><path d="M12 6.5l2-1.8" /></g>
6
+ <g transform="rotate(240 12 12)"><path d="M12 12V3.5" /><path d="M12 6.5l-2-1.8" /><path d="M12 6.5l2-1.8" /></g>
7
+ <g transform="rotate(300 12 12)"><path d="M12 12V3.5" /><path d="M12 6.5l-2-1.8" /><path d="M12 6.5l2-1.8" /></g>
9
8
  </svg>
@@ -1,5 +1,5 @@
1
1
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2
- <path d="M5 12h14" />
3
- <path d="M16 7.5a4 4 0 0 0-4-3 4 4 0 0 0-3.5 3" />
4
- <path d="M8 16.5a4 4 0 0 0 4 3 4 4 0 0 0 3.5-3" />
2
+ <path d="M4.5 12h15" />
3
+ <path d="M16 8a4 4 0 0 0-4-3.5h-1.5A3 3 0 0 0 8 9" />
4
+ <path d="M8 16a4 4 0 0 0 4 3.5h1.5A3 3 0 0 0 16 15" />
5
5
  </svg>
@@ -1,12 +1,12 @@
1
1
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2
- <circle cx="6.5" cy="6.5" r="3" />
3
- <path d="M6.5 1.5v1.5" />
4
- <path d="M6.5 10v1.5" />
5
- <path d="M1.5 6.5h1.5" />
6
- <path d="M10 6.5h1.5" />
7
- <path d="M2.95 2.95l1.05 1.05" />
8
- <path d="M9 9l1.05 1.05" />
9
- <line x1="17" y1="12.5" x2="17" y2="22.5" />
10
- <line x1="12.5" y1="15" x2="21.5" y2="20" />
11
- <line x1="21.5" y1="15" x2="12.5" y2="20" />
2
+ <circle cx="7" cy="7" r="2.5" />
3
+ <path d="M7 3.5V1.5" />
4
+ <path d="M7 10.5v2" />
5
+ <path d="M3.5 7H1.5" />
6
+ <path d="M10.5 7h2" />
7
+ <path d="M4.3 4.3 3 3" />
8
+ <path d="M9.7 4.3 11 3" />
9
+ <path d="M16.5 11.5v9" />
10
+ <path d="M12.7 13.8 20.3 18.2" />
11
+ <path d="M20.3 13.8 12.7 18.2" />
12
12
  </svg>
@@ -1,8 +1,8 @@
1
1
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2
- <path d="M9.5 7l1.5-1.5a4.5 4.5 0 0 1 6.4 6.4L16 13.5" />
3
- <path d="M14.5 17l-1.5 1.5a4.5 4.5 0 0 1-6.4-6.4L8 10.5" />
4
- <path d="M19 4.5v2.5" />
5
- <path d="M16.5 9.5H19" />
6
- <path d="M5 19.5v-2.5" />
7
- <path d="M7.5 14.5H5" />
2
+ <path d="M13 11l2-2a4 4 0 1 0-5.5-5.5l-2 2" />
3
+ <path d="M11 13l-2 2a4 4 0 1 0 5.5 5.5l2-2" />
4
+ <path d="M16 5.5h3.5" />
5
+ <path d="M18.5 8V4.5" />
6
+ <path d="M8 18.5H4.5" />
7
+ <path d="M5.5 16v3.5" />
8
8
  </svg>
@@ -1,4 +1,3 @@
1
1
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2
- <path d="M14.5 3.5a5.5 5.5 0 0 0-4 7.5L4 17.5a2.5 2.5 0 1 0 3.5 3.5l6.5-6.5a5.5 5.5 0 0 0 7.5-4" />
3
- <path d="M17 3.5L14 6.5" />
2
+ <path d="M15 6.5a1.5 1.5 0 0 0 0 2l1 1a1.5 1.5 0 0 0 2 0l3.5-3.5a6 6 0 0 1-8 8l-6.5 6.5a2 2 0 0 1-3-3l6.5-6.5a6 6 0 0 1 8-8z" />
4
3
  </svg>
@@ -13,7 +13,7 @@
13
13
  * the source of truth (`bind:value`). Only `focusedDate`, `hoveredDate` and
14
14
  * `navDirection` are controller-owned `$state`.
15
15
  */
16
- import { addDays, clampMonth, daysBetween, endOfWeek, formatDateRange, formatDayTitle, formatMonthYear, formatWeekTitle, getMonthGrid, getWeekDates, getWeekdayNames, getWeekNumber, isInMonth, isInRange, isSameDay, isWeekend, startOfWeek, stripTime, toIso } from '../../date';
16
+ import { addDays, clampMonth, daysBetween, daysInMonth, endOfWeek, formatDateRange, formatDayTitle, formatMonthYear, formatWeekTitle, getMonthGrid, getWeekDates, getWeekdayNames, getWeekNumber, isInMonth, isInRange, isSameDay, isWeekend, startOfWeek, stripTime, toIso } from '../../date';
17
17
  export class DateGridController {
18
18
  #opts;
19
19
  /** The roving keyboard focus target (local midnight). Controller-owned. */
@@ -228,7 +228,21 @@ export class DateGridController {
228
228
  const targetYear = Math.floor(total / 12);
229
229
  const targetMonth = ((total % 12) + 12) % 12;
230
230
  const clamped = clampMonth(targetMonth, targetYear, minDate, maxDate);
231
- next = new Date(clamped.year, clamped.month, 1);
231
+ // Preserve the day-of-month (clamped to the target month's length, e.g.
232
+ // 31 Jan → 28 Feb) rather than snapping to the 1st. Month view ignores the
233
+ // day, but a week/day view sharing this reference then anchors on a real
234
+ // in-month day — anchoring on the 1st can land its week mostly in the prior
235
+ // month (1 Mar 2026 is a Sunday → its Monday-week is 23 Feb–1 Mar). Matches
236
+ // the keyboard PageUp/PageDown month step, which already clamps the day.
237
+ const day = Math.min(referenceDate.getDate(), daysInMonth(clamped.year, clamped.month));
238
+ next = new Date(clamped.year, clamped.month, day);
239
+ // clampMonth bounds the month; clamp the preserved day too so it never lands
240
+ // before minDate / after maxDate within that boundary month (a week view
241
+ // would otherwise open on an all-disabled week just outside the range).
242
+ if (minDate && next < stripTime(minDate))
243
+ next = stripTime(minDate);
244
+ if (maxDate && next > stripTime(maxDate))
245
+ next = stripTime(maxDate);
232
246
  break;
233
247
  }
234
248
  case 'week':
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@urbicon-ui/blocks",
3
- "version": "6.1.4",
3
+ "version": "6.1.6",
4
4
  "description": "Svelte 5 UI component library with Tailwind CSS 4, OKLCH design tokens and zero runtime dependencies",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -90,8 +90,8 @@
90
90
  "@sveltejs/package": "^2.5.8",
91
91
  "@sveltejs/vite-plugin-svelte": "^7.0.0",
92
92
  "@tailwindcss/vite": "^4.3.1",
93
- "@urbicon-ui/i18n": "6.1.4",
94
- "@urbicon-ui/shared-types": "6.1.4",
93
+ "@urbicon-ui/i18n": "6.1.6",
94
+ "@urbicon-ui/shared-types": "6.1.6",
95
95
  "prettier": "^3.8.4",
96
96
  "prettier-plugin-svelte": "^4.1.1",
97
97
  "prettier-plugin-tailwindcss": "^0.8.0",