@urbicon-ui/blocks 6.12.0 → 6.19.1

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.
Files changed (59) hide show
  1. package/README.md +5 -5
  2. package/dist/components/AreaChart/AreaChart.svelte +7 -3
  3. package/dist/components/BarChart/BarChart.svelte +7 -3
  4. package/dist/components/Calendar/Calendar.svelte +46 -29
  5. package/dist/components/Calendar/CalendarAgendaView.svelte +1 -1
  6. package/dist/components/Calendar/CalendarDayView.svelte +19 -39
  7. package/dist/components/Calendar/CalendarDayView.svelte.d.ts +1 -3
  8. package/dist/components/Calendar/CalendarEventItem.svelte +0 -1
  9. package/dist/components/Calendar/CalendarGrid.svelte +12 -8
  10. package/dist/components/Calendar/CalendarHeader.svelte +2 -2
  11. package/dist/components/Calendar/CalendarMiniMonth.svelte +0 -2
  12. package/dist/components/Calendar/CalendarTimeEvent.svelte +1 -1
  13. package/dist/components/Calendar/CalendarTimeGrid.svelte +0 -3
  14. package/dist/components/Calendar/CalendarWeekGrid.svelte +1 -1
  15. package/dist/components/Calendar/calendar.context.d.ts +1 -0
  16. package/dist/components/Calendar/calendar.types.d.ts +2 -0
  17. package/dist/components/Calendar/calendar.variants.d.ts +0 -12
  18. package/dist/components/Calendar/calendar.variants.js +0 -4
  19. package/dist/components/Calendar/index.d.ts +6 -2
  20. package/dist/components/CompositionBar/CompositionBar.svelte +1 -1
  21. package/dist/components/CompositionBar/composition-bar.variants.d.ts +15 -16
  22. package/dist/components/CompositionBar/composition-bar.variants.js +4 -2
  23. package/dist/components/CompositionBar/index.d.ts +1 -1
  24. package/dist/components/DatePicker/DatePicker.svelte +5 -3
  25. package/dist/components/DatePicker/DateRangePicker.svelte +3 -3
  26. package/dist/components/DatePicker/datepicker.engine.d.ts +6 -6
  27. package/dist/components/DatePicker/datepicker.engine.js +13 -13
  28. package/dist/components/DonutChart/DonutChart.svelte +5 -3
  29. package/dist/components/LineChart/LineChart.svelte +7 -3
  30. package/dist/components/Planner/Planner.svelte +7 -3
  31. package/dist/components/Planner/PlannerHeader.svelte +1 -1
  32. package/dist/components/Planner/planner.types.d.ts +3 -0
  33. package/dist/date/compare.d.ts +8 -0
  34. package/dist/date/compare.js +15 -0
  35. package/dist/date/index.d.ts +1 -1
  36. package/dist/date/index.js +1 -1
  37. package/dist/i18n/index.d.ts +22 -14
  38. package/dist/internal/date-grid/date-grid.svelte.d.ts +18 -3
  39. package/dist/internal/date-grid/date-grid.svelte.js +60 -19
  40. package/dist/internal/date-grid/index.d.ts +2 -2
  41. package/dist/internal/date-grid/index.js +2 -2
  42. package/dist/mint/README.md +12 -9
  43. package/dist/mint/registry.js +12 -0
  44. package/dist/primitives/Badge/badge.variants.d.ts +0 -1
  45. package/dist/primitives/Badge/badge.variants.js +1 -2
  46. package/dist/primitives/Breadcrumb/Breadcrumb.svelte +1 -2
  47. package/dist/primitives/ButtonGroup/ButtonGroup.svelte +1 -1
  48. package/dist/primitives/Combobox/Combobox.svelte +1 -0
  49. package/dist/primitives/Menu/Menu.svelte +2 -2
  50. package/dist/primitives/Pagination/Pagination.svelte +10 -2
  51. package/dist/primitives/Pagination/PaginationItem.svelte +0 -2
  52. package/dist/primitives/Stepper/StepperStep.svelte +3 -1
  53. package/dist/translations/de.d.ts +11 -7
  54. package/dist/translations/de.js +12 -8
  55. package/dist/translations/en.d.ts +11 -7
  56. package/dist/translations/en.js +12 -8
  57. package/dist/utils/date.d.ts +5 -0
  58. package/dist/utils/date.js +34 -24
  59. package/package.json +3 -3
@@ -52,6 +52,8 @@ declare const blocksTranslations: {
52
52
  readonly last: "Last";
53
53
  readonly page: "Page";
54
54
  readonly previous: "Previous";
55
+ readonly pageInfo: "{{label}} {{current}} of {{total}}";
56
+ readonly rangeInfo: "{{start}}–{{end}} of {{total}}";
55
57
  };
56
58
  readonly calendar: {
57
59
  readonly recurring: "Recurring event";
@@ -73,8 +75,6 @@ declare const blocksTranslations: {
73
75
  readonly legend: "Legend";
74
76
  readonly yearView: "Year overview";
75
77
  readonly weekView: "Week view";
76
- readonly dayView: "Day view";
77
- readonly monthView: "Month view";
78
78
  readonly viewMonth: "Month";
79
79
  readonly viewYear: "Year";
80
80
  readonly viewWeek: "Week";
@@ -93,7 +93,6 @@ declare const blocksTranslations: {
93
93
  readonly nextRange: "Next range";
94
94
  readonly today: "Today";
95
95
  readonly grid: "Planner";
96
- readonly weekNumber: "Week number";
97
96
  readonly itemCount: "{{count}} items";
98
97
  };
99
98
  readonly commandPalette: {
@@ -145,7 +144,6 @@ declare const blocksTranslations: {
145
144
  readonly datepicker: {
146
145
  readonly placeholder: "Select a date...";
147
146
  readonly rangePlaceholder: "Select a date range...";
148
- readonly clear: "Clear selection";
149
147
  readonly openCalendar: "Open calendar";
150
148
  readonly invalidDate: "Invalid date";
151
149
  readonly outOfRange: "Date is outside the allowed range";
@@ -177,9 +175,15 @@ declare const blocksTranslations: {
177
175
  readonly darkMode: "Dark mode";
178
176
  readonly systemTheme: "System theme";
179
177
  };
180
- readonly time: {
181
- readonly ago: "{{value}} {{unit}} ago";
182
- readonly now: "now";
178
+ readonly chart: {
179
+ readonly category: "Category";
180
+ readonly series: "Series {{index}}";
181
+ readonly segment: "Segment";
182
+ readonly value: "Value";
183
+ readonly share: "Share";
184
+ };
185
+ readonly stepper: {
186
+ readonly optional: "Optional";
183
187
  };
184
188
  };
185
189
  de: {
@@ -234,6 +238,8 @@ declare const blocksTranslations: {
234
238
  readonly last: "Letzte";
235
239
  readonly page: "Seite";
236
240
  readonly previous: "Vorherige";
241
+ readonly pageInfo: "{{label}} {{current}} von {{total}}";
242
+ readonly rangeInfo: "{{start}}–{{end}} von {{total}}";
237
243
  };
238
244
  readonly calendar: {
239
245
  readonly recurring: "Wiederkehrender Termin";
@@ -255,8 +261,6 @@ declare const blocksTranslations: {
255
261
  readonly legend: "Legende";
256
262
  readonly yearView: "Jahresübersicht";
257
263
  readonly weekView: "Wochenansicht";
258
- readonly dayView: "Tagesansicht";
259
- readonly monthView: "Monatsansicht";
260
264
  readonly viewMonth: "Monat";
261
265
  readonly viewYear: "Jahr";
262
266
  readonly viewWeek: "Woche";
@@ -275,7 +279,6 @@ declare const blocksTranslations: {
275
279
  readonly nextRange: "Nächster Zeitraum";
276
280
  readonly today: "Heute";
277
281
  readonly grid: "Planer";
278
- readonly weekNumber: "Kalenderwoche";
279
282
  readonly itemCount: "{{count}} Einträge";
280
283
  };
281
284
  readonly commandPalette: {
@@ -327,7 +330,6 @@ declare const blocksTranslations: {
327
330
  readonly datepicker: {
328
331
  readonly placeholder: "Datum wählen...";
329
332
  readonly rangePlaceholder: "Zeitraum wählen...";
330
- readonly clear: "Auswahl löschen";
331
333
  readonly openCalendar: "Kalender öffnen";
332
334
  readonly invalidDate: "Ungültiges Datum";
333
335
  readonly outOfRange: "Datum liegt außerhalb des zulässigen Bereichs";
@@ -359,9 +361,15 @@ declare const blocksTranslations: {
359
361
  readonly darkMode: "Dunkler Modus";
360
362
  readonly systemTheme: "Systemdesign";
361
363
  };
362
- readonly time: {
363
- readonly ago: "vor {{value}} {{unit}}";
364
- readonly now: "jetzt";
364
+ readonly chart: {
365
+ readonly category: "Kategorie";
366
+ readonly series: "Datenreihe {{index}}";
367
+ readonly segment: "Segment";
368
+ readonly value: "Wert";
369
+ readonly share: "Anteil";
370
+ };
371
+ readonly stepper: {
372
+ readonly optional: "Optional";
365
373
  };
366
374
  };
367
375
  };
@@ -86,6 +86,12 @@ export declare class DateGridController {
86
86
  get title(): string;
87
87
  get canGoBack(): boolean;
88
88
  get canGoForward(): boolean;
89
+ /** Whether today lies within `[minDate, maxDate]` and can be navigated to. Drives
90
+ * the header Today button's disabled state (mirrors the arrow buttons gating on
91
+ * canGoBack/canGoForward). Day-granular: the button jumps to today's *day*, so a
92
+ * maxDate earlier this month still disables it once today passes the bound. Reads
93
+ * the reactive `today`, so it re-evaluates after the midnight refresh. */
94
+ get canGoToToday(): boolean;
89
95
  weekNumberFor(date: Date): number;
90
96
  isToday(date: Date): boolean;
91
97
  isWeekend(date: Date): boolean;
@@ -103,11 +109,20 @@ export declare class DateGridController {
103
109
  /** Step the view by `delta` units (months / weeks / days; range shifts by its
104
110
  * own span in weeks). Emits the next reference date and visible range. */
105
111
  navigate(delta: number): void;
106
- /** Jump to today and focus it. */
112
+ /** Jump to today and focus it. Clamped to `[minDate, maxDate]`: the header Today
113
+ * button gates itself on {@link canGoToToday} (a clamped "today" is not today, so
114
+ * it disables rather than mislead), but a programmatic call still must not seat the
115
+ * reference on an all-disabled month/week/day past the boundary. Uses `today` — the
116
+ * controller's source of truth for "today" — so it lands where `isToday` marks. */
107
117
  goToToday(): void;
108
- /** Jump the reference date to a specific date. */
118
+ /** Jump the reference date to a specific date, clamped to `[minDate, maxDate]`. */
109
119
  goTo(date: Date): void;
110
- /** Set the roving focus, navigating the view if the date left the visible window. */
120
+ /** Set the roving focus, navigating the view if the date left the visible window.
121
+ * The target is clamped to `[minDate, maxDate]` — arrow/Home/End/Page keys are not
122
+ * gated by canGoBack/canGoForward, so an unclamped focus could cross the boundary
123
+ * and drag the view onto an all-disabled window (the same escape the stepping paths
124
+ * close). Only the hard outer bounds clamp; custom `isDateDisabled` holes *inside*
125
+ * the range stay focusable, per the ARIA grid pattern. */
111
126
  setFocusedDate(date: Date): void;
112
127
  /** Move the roving focus by `deltaDays` (keyboard arrows / page keys). */
113
128
  moveFocus(deltaDays: number): void;
@@ -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, daysInMonth, endOfWeek, formatDateRange, formatDayTitle, formatMonthYear, formatWeekTitle, getMonthGrid, getWeekDates, getWeekdayNames, getWeekNumber, isInMonth, isInRange, isSameDay, isWeekend, startOfWeek, stripTime, toIso } from '../../date/index.js';
16
+ import { addDays, clampDate, clampMonth, daysBetween, daysInMonth, endOfWeek, formatDateRange, formatDayTitle, formatMonthYear, formatWeekTitle, getMonthGrid, getWeekDates, getWeekdayNames, getWeekNumber, isInMonth, isInRange, isSameDay, isWeekend, startOfWeek, stripTime, toIso } from '../../date/index.js';
17
17
  export class DateGridController {
18
18
  #opts;
19
19
  /** The roving keyboard focus target (local midnight). Controller-owned. */
@@ -27,6 +27,21 @@ export class DateGridController {
27
27
  constructor(opts) {
28
28
  this.#opts = opts;
29
29
  this.focusedDate = stripTime(opts.referenceDate);
30
+ // Dev-only: surface inverted bounds (a caller passing minDate after
31
+ // maxDate). `clampDate` resolves every date to minDate in that case, so
32
+ // navigation gating and today/disabled logic become deterministic-but-
33
+ // meaningless rather than failing. Checked once at construction — the
34
+ // realistic mistake is statically swapped props; mirrors the Select/Guide
35
+ // `import.meta.env?.DEV && console.warn` precedent (no throw: a degraded
36
+ // grid still renders, and the library never crashes on caller garbage-in).
37
+ if (import.meta.env?.DEV) {
38
+ const { minDate, maxDate } = opts;
39
+ if (minDate && maxDate && stripTime(minDate) > stripTime(maxDate)) {
40
+ console.warn(`[DateGrid] minDate (${minDate.toLocaleDateString()}) is after maxDate ` +
41
+ `(${maxDate.toLocaleDateString()}) — bounds are inverted; every date ` +
42
+ `clamps to minDate and navigation is meaningless. Swap the two.`);
43
+ }
44
+ }
30
45
  }
31
46
  // ─── Reflected inputs ────────────────────────────────────────────────────
32
47
  get view() {
@@ -112,6 +127,20 @@ export class DateGridController {
112
127
  get canGoForward() {
113
128
  return this.#navBounds.canGoForward;
114
129
  }
130
+ /** Whether today lies within `[minDate, maxDate]` and can be navigated to. Drives
131
+ * the header Today button's disabled state (mirrors the arrow buttons gating on
132
+ * canGoBack/canGoForward). Day-granular: the button jumps to today's *day*, so a
133
+ * maxDate earlier this month still disables it once today passes the bound. Reads
134
+ * the reactive `today`, so it re-evaluates after the midnight refresh. */
135
+ get canGoToToday() {
136
+ const { minDate, maxDate } = this.#opts;
137
+ const t = this.today;
138
+ if (minDate && t < stripTime(minDate))
139
+ return false;
140
+ if (maxDate && t > stripTime(maxDate))
141
+ return false;
142
+ return true;
143
+ }
115
144
  // ─── Per-day queries ─────────────────────────────────────────────────────
116
145
  weekNumberFor(date) {
117
146
  return getWeekNumber(date);
@@ -235,39 +264,51 @@ export class DateGridController {
235
264
  // month (1 Mar 2026 is a Sunday → its Monday-week is 23 Feb–1 Mar). Matches
236
265
  // the keyboard PageUp/PageDown month step, which already clamps the day.
237
266
  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);
267
+ // clampMonth bounds the month; clampDate clamps the preserved day too so it
268
+ // never lands before minDate / after maxDate within that boundary month (a
269
+ // week view would otherwise open on an all-disabled week just outside range).
270
+ next = clampDate(new Date(clamped.year, clamped.month, day), minDate, maxDate);
246
271
  break;
247
272
  }
273
+ // Week/day steps carry no month bounds of their own, so clamp the shifted
274
+ // reference to [minDate, maxDate] too — otherwise a swipe or a day-view arrow
275
+ // key (neither gated by canGoBack/canGoForward the way the header arrows are)
276
+ // could step the anchor onto an all-disabled week/day past the boundary.
248
277
  case 'week':
249
- next = addDays(referenceDate, delta * 7);
278
+ next = clampDate(addDays(referenceDate, delta * 7), minDate, maxDate);
250
279
  break;
251
280
  case 'day':
252
- next = addDays(referenceDate, delta);
281
+ next = clampDate(addDays(referenceDate, delta), minDate, maxDate);
253
282
  break;
254
283
  }
255
284
  this.#emitNavigate(next);
256
285
  }
257
- /** Jump to today and focus it. */
286
+ /** Jump to today and focus it. Clamped to `[minDate, maxDate]`: the header Today
287
+ * button gates itself on {@link canGoToToday} (a clamped "today" is not today, so
288
+ * it disables rather than mislead), but a programmatic call still must not seat the
289
+ * reference on an all-disabled month/week/day past the boundary. Uses `today` — the
290
+ * controller's source of truth for "today" — so it lands where `isToday` marks. */
258
291
  goToToday() {
259
- const now = stripTime(new Date());
292
+ const { minDate, maxDate } = this.#opts;
293
+ const now = clampDate(this.today, minDate, maxDate);
260
294
  this.focusedDate = now;
261
295
  this.#emitNavigate(now);
262
296
  }
263
- /** Jump the reference date to a specific date. */
297
+ /** Jump the reference date to a specific date, clamped to `[minDate, maxDate]`. */
264
298
  goTo(date) {
265
- this.#emitNavigate(stripTime(date));
266
- }
267
- /** Set the roving focus, navigating the view if the date left the visible window. */
299
+ const { minDate, maxDate } = this.#opts;
300
+ this.#emitNavigate(clampDate(stripTime(date), minDate, maxDate));
301
+ }
302
+ /** Set the roving focus, navigating the view if the date left the visible window.
303
+ * The target is clamped to `[minDate, maxDate]` — arrow/Home/End/Page keys are not
304
+ * gated by canGoBack/canGoForward, so an unclamped focus could cross the boundary
305
+ * and drag the view onto an all-disabled window (the same escape the stepping paths
306
+ * close). Only the hard outer bounds clamp; custom `isDateDisabled` holes *inside*
307
+ * the range stay focusable, per the ARIA grid pattern. */
268
308
  setFocusedDate(date) {
269
- const d = stripTime(date);
270
- const reference = stripTime(this.#opts.referenceDate);
309
+ const { minDate, maxDate, referenceDate } = this.#opts;
310
+ const d = clampDate(stripTime(date), minDate, maxDate);
311
+ const reference = stripTime(referenceDate);
271
312
  this.focusedDate = d;
272
313
  if (this.#needsNavigationToFocus(d)) {
273
314
  this.navDirection = d.getTime() >= reference.getTime() ? 'forward' : 'backward';
@@ -3,8 +3,8 @@
3
3
  *
4
4
  * Shared mechanics for cell-based date views: the `DateGridController` state
5
5
  * class, its context, the keyboard handler and the `DateGridScaffold` chrome.
6
- * Consumed by Calendar and Planner; see docs/DATEGRID-PLANNER-PLAN.md (D6) for
7
- * why it stays internal for now.
6
+ * Consumed by Calendar and Planner; see docs/ARCHITECTURE.md "Date & Planning
7
+ * Infrastructure" for why it stays internal for now.
8
8
  */
9
9
  export { default as DateGridScaffold } from './DateGridScaffold.svelte';
10
10
  export { getDateGridContext, setDateGridContext } from './date-grid.context.js';
@@ -3,8 +3,8 @@
3
3
  *
4
4
  * Shared mechanics for cell-based date views: the `DateGridController` state
5
5
  * class, its context, the keyboard handler and the `DateGridScaffold` chrome.
6
- * Consumed by Calendar and Planner; see docs/DATEGRID-PLANNER-PLAN.md (D6) for
7
- * why it stays internal for now.
6
+ * Consumed by Calendar and Planner; see docs/ARCHITECTURE.md "Date & Planning
7
+ * Infrastructure" for why it stays internal for now.
8
8
  */
9
9
  export { default as DateGridScaffold } from './DateGridScaffold.svelte';
10
10
  export { getDateGridContext, setDateGridContext } from './date-grid.context.js';
@@ -98,7 +98,7 @@ interface RippleConfig extends MintConfig {
98
98
  ## Presets
99
99
 
100
100
  ```typescript
101
- import { mintPresets } from '@urbicon/ui';
101
+ import { mintPresets } from '@urbicon-ui/blocks';
102
102
 
103
103
  // Verfügbare Presets
104
104
  mintPresets['cta-primary']; // Für primäre Call-to-Action Buttons
@@ -108,21 +108,24 @@ mintPresets['subtle-hover']; // Für subtile Hover-Effekte
108
108
  mintPresets['error-feedback']; // Für Fehler-Feedback
109
109
  ```
110
110
 
111
- ## Svelte Actions
111
+ ## Svelte 5 Attachments
112
112
 
113
113
  ```svelte
114
114
  <script>
115
- import { mint } from '@urbicon/ui';
115
+ import { mintRegistry } from '@urbicon-ui/blocks';
116
+
117
+ // {@attach} factory — mintRegistry.apply returns the cleanup the attachment needs
118
+ const mint = (mints) => (element) => mintRegistry.apply(element, mints);
116
119
  </script>
117
120
 
118
- <!-- Mit Action -->
119
- <div use:mint="scale">Hover mich</div>
121
+ <!-- Einzelner Mint -->
122
+ <div {@attach mint('scale')}>Hover mich</div>
120
123
 
121
124
  <!-- Mehrere Mints -->
122
- <div use:mint={['scale', 'glow']}>Multi-Effekt</div>
125
+ <div {@attach mint(['scale', 'glow'])}>Multi-Effekt</div>
123
126
 
124
127
  <!-- Mit Konfiguration -->
125
- <div use:mint={{ name: 'bounce', config: { trigger: 'click' } }}>
128
+ <div {@attach mint({ name: 'bounce', config: { trigger: 'click' } })}>
126
129
  Click mich
127
130
  </div>
128
131
  ```
@@ -130,7 +133,7 @@ mintPresets['error-feedback']; // Für Fehler-Feedback
130
133
  ## Eigene Mints registrieren
131
134
 
132
135
  ```typescript
133
- import { mintRegistry } from '@urbicon/ui';
136
+ import { mintRegistry } from '@urbicon-ui/blocks';
134
137
 
135
138
  // Einfacher Mint
136
139
  mintRegistry.register('my-mint', (config) => ({
@@ -203,7 +206,7 @@ const complexMint = [
203
206
  ### Custom Mint Bundle
204
207
 
205
208
  ```typescript
206
- import { registerPlayfulMints, registerBusinessMints } from '@urbicon/ui';
209
+ import { registerPlayfulMints, registerBusinessMints } from '@urbicon-ui/blocks';
207
210
 
208
211
  // Je nach App-Kontext
209
212
  if (appTheme === 'playful') {
@@ -1,3 +1,4 @@
1
+ import { registerDefaultMints } from './presets.js';
1
2
  class MintRegistry {
2
3
  mints = new Map();
3
4
  instances = new WeakMap();
@@ -15,6 +16,17 @@ class MintRegistry {
15
16
  }
16
17
  /** Apply mints to an element using polymorphic input */
17
18
  apply(el, mint) {
19
+ // Ensure the built-in mints (scale, glow, ripple, …) are registered before
20
+ // the first application. Components declare mint defaults — Button defaults
21
+ // to 'scale' — so a consumer that never called registerDefaultMints() would
22
+ // otherwise hit "Unknown mint: scale" on every button (and get no hover
23
+ // animation). registerDefaultMints() short-circuits on a module-level flag,
24
+ // so the recurring cost is a single boolean check.
25
+ //
26
+ // The registry ↔ presets import is cyclic but inert: both sides dereference
27
+ // the cyclic binding only at call time, never at module top level, so module
28
+ // initialisation completes cleanly regardless of load order.
29
+ registerDefaultMints();
18
30
  const mintDefinitions = this.normalizeMintProp(mint);
19
31
  const elementMints = new Map();
20
32
  const cleanupFunctions = [];
@@ -27,7 +27,6 @@ export declare const badgeVariants: (props?: import("../../utils/variants.js").T
27
27
  };
28
28
  dot: {
29
29
  base: string;
30
- content: string;
31
30
  };
32
31
  };
33
32
  size: {
@@ -56,8 +56,7 @@ export const badgeVariants = tv({
56
56
  base: 'bg-transparent border-transparent'
57
57
  },
58
58
  dot: {
59
- base: '!p-0 rounded-commit border-none',
60
- content: 'sr-only'
59
+ base: '!p-0 rounded-commit border-none'
61
60
  }
62
61
  },
63
62
  size: {
@@ -115,7 +115,7 @@
115
115
  aria-current="page">{entry.item.label}</span
116
116
  >
117
117
  {:else}
118
- <!-- eslint-disable svelte/no-navigation-without-resolve -- BreadcrumbItem.href is opaque to the library -->
118
+ <!-- BreadcrumbItem.href is opaque to the library; resolve() is the consumer's responsibility. -->
119
119
  <a
120
120
  href={entry.item.href}
121
121
  class={unstyled ? (slotClasses?.link ?? '') : styles.link({ class: slotClasses?.link })}
@@ -124,7 +124,6 @@
124
124
  >
125
125
  {entry.item.label}
126
126
  </a>
127
- <!-- eslint-enable svelte/no-navigation-without-resolve -->
128
127
  {/if}
129
128
  {#if i < entries.length - 1}
130
129
  <span
@@ -73,7 +73,7 @@
73
73
  onClick() {
74
74
  if (disabled || !buttonValue || selection === 'none') return;
75
75
 
76
- // eslint-disable-next-line svelte/prefer-svelte-reactivity -- local-only copy, not stored in state
76
+ // Local-only copy, not stored in state.
77
77
  const next = new Set(selectedValues);
78
78
 
79
79
  if (selection === 'single') {
@@ -352,6 +352,7 @@
352
352
  {#if clearable && value}
353
353
  <button
354
354
  type="button"
355
+ {disabled}
355
356
  class={unstyled ? (slotClasses?.clear ?? '') : styles.clear({ class: slotClasses?.clear })}
356
357
  onclick={clear}
357
358
  aria-label={bt('accessibility.clearSelection')}
@@ -75,7 +75,7 @@
75
75
  // `registerItem` / `unregisterItem` hooks. Used to debug + (in future)
76
76
  // power type-ahead search; the keyboard model itself walks DOM-focusable
77
77
  // descendants directly so it works in array-mode too.
78
- // eslint-disable-next-line svelte/prefer-svelte-reactivity -- internal registry, not reactive UI state
78
+ // Plain Map internal registry, not reactive UI state.
79
79
  const registryBuffer: Map<string, MenuRegistryItem> = new Map();
80
80
 
81
81
  // ── Item-shape mappers ─────────────────────────────────────────────────
@@ -148,7 +148,7 @@
148
148
  }
149
149
 
150
150
  function toggleSubMenu(id: string) {
151
- // eslint-disable-next-line svelte/prefer-svelte-reactivity -- copy + reassign keeps `openSubMenus` reactive
151
+ // Copy + reassign keeps `openSubMenus` reactive.
152
152
  const next = new Set(openSubMenus);
153
153
  if (next.has(id)) next.delete(id);
154
154
  else next.add(id);
@@ -149,10 +149,18 @@
149
149
  if (infoText) return infoText;
150
150
 
151
151
  if (layout === 'table') {
152
- return `${calculatedStartItem}–${calculatedEndItem} of ${calculatedTotalItems}`;
152
+ return bt('pagination.rangeInfo', {
153
+ start: calculatedStartItem,
154
+ end: calculatedEndItem,
155
+ total: calculatedTotalItems
156
+ });
153
157
  }
154
158
 
155
- return `${pageLabel} ${currentPage} of ${totalPages}`;
159
+ return bt('pagination.pageInfo', {
160
+ label: pageLabel,
161
+ current: currentPage,
162
+ total: totalPages
163
+ });
156
164
  });
157
165
  </script>
158
166
 
@@ -29,7 +29,6 @@
29
29
  <!-- Link-based pagination item. `href` is consumer-provided (internal or
30
30
  external) — `resolve()` only applies to statically-known SvelteKit
31
31
  routes. -->
32
- <!-- eslint-disable svelte/no-navigation-without-resolve -->
33
32
  <a
34
33
  {href}
35
34
  class="focus-visible:outline-primary/50 inline-block no-underline focus-visible:rounded-md focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 {className}"
@@ -55,7 +54,6 @@
55
54
  {/if}
56
55
  </Button>
57
56
  </a>
58
- <!-- eslint-enable svelte/no-navigation-without-resolve -->
59
57
  {:else}
60
58
  <!-- Button-based pagination item -->
61
59
  <Button
@@ -1,5 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { getBlocksConfig, resolveSlotClasses } from '../../provider';
3
+ import { useBlocksI18n } from '../..';
3
4
  import { stepperVariants, type StepperVariants } from './stepper.variants';
4
5
  import { getStepperContext } from './stepper.context';
5
6
  import { resolveIcon } from '../../icons';
@@ -28,6 +29,7 @@
28
29
  }: StepperStepProps = $props();
29
30
 
30
31
  const blocksConfig = getBlocksConfig();
32
+ const bt = useBlocksI18n();
31
33
  const unstyled = $derived(unstyledProp || blocksConfig?.unstyled || false);
32
34
 
33
35
  const ctx = getStepperContext();
@@ -130,7 +132,7 @@
130
132
  <span class={slot('description')}>{description}</span>
131
133
  {/if}
132
134
  {#if optional}
133
- <span class="{slot('description')} italic">Optional</span>
135
+ <span class="{slot('description')} italic">{bt('stepper.optional')}</span>
134
136
  {/if}
135
137
  </div>
136
138
  {/snippet}
@@ -50,6 +50,8 @@ declare const _default: {
50
50
  readonly last: "Letzte";
51
51
  readonly page: "Seite";
52
52
  readonly previous: "Vorherige";
53
+ readonly pageInfo: "{{label}} {{current}} von {{total}}";
54
+ readonly rangeInfo: "{{start}}–{{end}} von {{total}}";
53
55
  };
54
56
  readonly calendar: {
55
57
  readonly recurring: "Wiederkehrender Termin";
@@ -71,8 +73,6 @@ declare const _default: {
71
73
  readonly legend: "Legende";
72
74
  readonly yearView: "Jahresübersicht";
73
75
  readonly weekView: "Wochenansicht";
74
- readonly dayView: "Tagesansicht";
75
- readonly monthView: "Monatsansicht";
76
76
  readonly viewMonth: "Monat";
77
77
  readonly viewYear: "Jahr";
78
78
  readonly viewWeek: "Woche";
@@ -91,7 +91,6 @@ declare const _default: {
91
91
  readonly nextRange: "Nächster Zeitraum";
92
92
  readonly today: "Heute";
93
93
  readonly grid: "Planer";
94
- readonly weekNumber: "Kalenderwoche";
95
94
  readonly itemCount: "{{count}} Einträge";
96
95
  };
97
96
  readonly commandPalette: {
@@ -143,7 +142,6 @@ declare const _default: {
143
142
  readonly datepicker: {
144
143
  readonly placeholder: "Datum wählen...";
145
144
  readonly rangePlaceholder: "Zeitraum wählen...";
146
- readonly clear: "Auswahl löschen";
147
145
  readonly openCalendar: "Kalender öffnen";
148
146
  readonly invalidDate: "Ungültiges Datum";
149
147
  readonly outOfRange: "Datum liegt außerhalb des zulässigen Bereichs";
@@ -175,9 +173,15 @@ declare const _default: {
175
173
  readonly darkMode: "Dunkler Modus";
176
174
  readonly systemTheme: "Systemdesign";
177
175
  };
178
- readonly time: {
179
- readonly ago: "vor {{value}} {{unit}}";
180
- readonly now: "jetzt";
176
+ readonly chart: {
177
+ readonly category: "Kategorie";
178
+ readonly series: "Datenreihe {{index}}";
179
+ readonly segment: "Segment";
180
+ readonly value: "Wert";
181
+ readonly share: "Anteil";
182
+ };
183
+ readonly stepper: {
184
+ readonly optional: "Optional";
181
185
  };
182
186
  };
183
187
  export default _default;
@@ -49,7 +49,9 @@ export default {
49
49
  first: 'Erste',
50
50
  last: 'Letzte',
51
51
  page: 'Seite',
52
- previous: 'Vorherige'
52
+ previous: 'Vorherige',
53
+ pageInfo: '{{label}} {{current}} von {{total}}',
54
+ rangeInfo: '{{start}}–{{end}} von {{total}}'
53
55
  },
54
56
  calendar: {
55
57
  recurring: 'Wiederkehrender Termin',
@@ -71,8 +73,6 @@ export default {
71
73
  legend: 'Legende',
72
74
  yearView: 'Jahresübersicht',
73
75
  weekView: 'Wochenansicht',
74
- dayView: 'Tagesansicht',
75
- monthView: 'Monatsansicht',
76
76
  viewMonth: 'Monat',
77
77
  viewYear: 'Jahr',
78
78
  viewWeek: 'Woche',
@@ -91,7 +91,6 @@ export default {
91
91
  nextRange: 'Nächster Zeitraum',
92
92
  today: 'Heute',
93
93
  grid: 'Planer',
94
- weekNumber: 'Kalenderwoche',
95
94
  itemCount: '{{count}} Einträge'
96
95
  },
97
96
  commandPalette: {
@@ -143,7 +142,6 @@ export default {
143
142
  datepicker: {
144
143
  placeholder: 'Datum wählen...',
145
144
  rangePlaceholder: 'Zeitraum wählen...',
146
- clear: 'Auswahl löschen',
147
145
  openCalendar: 'Kalender öffnen',
148
146
  invalidDate: 'Ungültiges Datum',
149
147
  outOfRange: 'Datum liegt außerhalb des zulässigen Bereichs',
@@ -175,8 +173,14 @@ export default {
175
173
  darkMode: 'Dunkler Modus',
176
174
  systemTheme: 'Systemdesign'
177
175
  },
178
- time: {
179
- ago: 'vor {{value}} {{unit}}',
180
- now: 'jetzt'
176
+ chart: {
177
+ category: 'Kategorie',
178
+ series: 'Datenreihe {{index}}',
179
+ segment: 'Segment',
180
+ value: 'Wert',
181
+ share: 'Anteil'
182
+ },
183
+ stepper: {
184
+ optional: 'Optional'
181
185
  }
182
186
  };