@urbicon-ui/blocks 6.19.0 → 6.19.2

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 (64) 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/CurrencyInput/CurrencyInput.svelte +10 -4
  25. package/dist/components/CurrencyInput/index.d.ts +13 -11
  26. package/dist/components/DatePicker/DatePicker.svelte +5 -3
  27. package/dist/components/DatePicker/DateRangePicker.svelte +3 -3
  28. package/dist/components/DatePicker/datepicker.engine.d.ts +6 -6
  29. package/dist/components/DatePicker/datepicker.engine.js +13 -13
  30. package/dist/components/DonutChart/DonutChart.svelte +5 -3
  31. package/dist/components/LineChart/LineChart.svelte +7 -3
  32. package/dist/components/Planner/Planner.svelte +7 -3
  33. package/dist/components/Planner/PlannerHeader.svelte +1 -1
  34. package/dist/components/Planner/planner.types.d.ts +3 -0
  35. package/dist/date/compare.d.ts +8 -0
  36. package/dist/date/compare.js +15 -0
  37. package/dist/date/index.d.ts +1 -1
  38. package/dist/date/index.js +1 -1
  39. package/dist/i18n/index.d.ts +24 -378
  40. package/dist/internal/date-grid/date-grid.svelte.d.ts +18 -3
  41. package/dist/internal/date-grid/date-grid.svelte.js +60 -19
  42. package/dist/internal/date-grid/index.d.ts +2 -2
  43. package/dist/internal/date-grid/index.js +2 -2
  44. package/dist/mint/README.md +12 -9
  45. package/dist/mint/registry.js +12 -0
  46. package/dist/primitives/Badge/badge.variants.d.ts +0 -1
  47. package/dist/primitives/Badge/badge.variants.js +1 -2
  48. package/dist/primitives/Breadcrumb/Breadcrumb.svelte +1 -2
  49. package/dist/primitives/ButtonGroup/ButtonGroup.svelte +1 -1
  50. package/dist/primitives/Combobox/Combobox.svelte +9 -1
  51. package/dist/primitives/Combobox/combobox.variants.d.ts +29 -0
  52. package/dist/primitives/Combobox/combobox.variants.js +22 -7
  53. package/dist/primitives/Menu/Menu.svelte +2 -2
  54. package/dist/primitives/Pagination/Pagination.svelte +10 -2
  55. package/dist/primitives/Pagination/PaginationItem.svelte +0 -2
  56. package/dist/primitives/Select/Select.svelte +0 -1
  57. package/dist/primitives/Stepper/StepperStep.svelte +3 -1
  58. package/dist/translations/de.d.ts +11 -7
  59. package/dist/translations/de.js +12 -8
  60. package/dist/translations/en.d.ts +11 -7
  61. package/dist/translations/en.js +12 -8
  62. package/dist/utils/date.d.ts +5 -0
  63. package/dist/utils/date.js +34 -24
  64. package/package.json +3 -3
@@ -406,7 +406,7 @@
406
406
  </div>
407
407
 
408
408
  <!-- Legend -->
409
- {#if showLegend && legendPlacement !== 'none'}
409
+ {#if showLegend}
410
410
  <ul
411
411
  class={unstyled ? (slotClasses?.legend ?? '') : styles.legend({ class: slotClasses?.legend })}
412
412
  >
@@ -46,7 +46,6 @@ export declare const compositionBarVariants: (props?: import("../../utils/varian
46
46
  left: {
47
47
  wrapper: string;
48
48
  };
49
- none: {};
50
49
  };
51
50
  isHovered: {
52
51
  true: {};
@@ -56,7 +55,7 @@ export declare const compositionBarVariants: (props?: import("../../utils/varian
56
55
  wrapper: (props?: ({
57
56
  orientation?: "horizontal" | "vertical" | undefined;
58
57
  size?: "sm" | "md" | "lg" | undefined;
59
- legendPlacement?: "top" | "right" | "bottom" | "left" | "none" | undefined;
58
+ legendPlacement?: "top" | "right" | "bottom" | "left" | undefined;
60
59
  isHovered?: boolean | undefined;
61
60
  } & {
62
61
  class?: string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | /*elided*/ any | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined;
@@ -65,7 +64,7 @@ export declare const compositionBarVariants: (props?: import("../../utils/varian
65
64
  barWrapper: (props?: ({
66
65
  orientation?: "horizontal" | "vertical" | undefined;
67
66
  size?: "sm" | "md" | "lg" | undefined;
68
- legendPlacement?: "top" | "right" | "bottom" | "left" | "none" | undefined;
67
+ legendPlacement?: "top" | "right" | "bottom" | "left" | undefined;
69
68
  isHovered?: boolean | undefined;
70
69
  } & {
71
70
  class?: string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | /*elided*/ any | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined;
@@ -74,7 +73,7 @@ export declare const compositionBarVariants: (props?: import("../../utils/varian
74
73
  bar: (props?: ({
75
74
  orientation?: "horizontal" | "vertical" | undefined;
76
75
  size?: "sm" | "md" | "lg" | undefined;
77
- legendPlacement?: "top" | "right" | "bottom" | "left" | "none" | undefined;
76
+ legendPlacement?: "top" | "right" | "bottom" | "left" | undefined;
78
77
  isHovered?: boolean | undefined;
79
78
  } & {
80
79
  class?: string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | /*elided*/ any | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined;
@@ -83,7 +82,7 @@ export declare const compositionBarVariants: (props?: import("../../utils/varian
83
82
  segment: (props?: ({
84
83
  orientation?: "horizontal" | "vertical" | undefined;
85
84
  size?: "sm" | "md" | "lg" | undefined;
86
- legendPlacement?: "top" | "right" | "bottom" | "left" | "none" | undefined;
85
+ legendPlacement?: "top" | "right" | "bottom" | "left" | undefined;
87
86
  isHovered?: boolean | undefined;
88
87
  } & {
89
88
  class?: string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | /*elided*/ any | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined;
@@ -92,7 +91,7 @@ export declare const compositionBarVariants: (props?: import("../../utils/varian
92
91
  segmentRest: (props?: ({
93
92
  orientation?: "horizontal" | "vertical" | undefined;
94
93
  size?: "sm" | "md" | "lg" | undefined;
95
- legendPlacement?: "top" | "right" | "bottom" | "left" | "none" | undefined;
94
+ legendPlacement?: "top" | "right" | "bottom" | "left" | undefined;
96
95
  isHovered?: boolean | undefined;
97
96
  } & {
98
97
  class?: string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | /*elided*/ any | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined;
@@ -101,7 +100,7 @@ export declare const compositionBarVariants: (props?: import("../../utils/varian
101
100
  tooltip: (props?: ({
102
101
  orientation?: "horizontal" | "vertical" | undefined;
103
102
  size?: "sm" | "md" | "lg" | undefined;
104
- legendPlacement?: "top" | "right" | "bottom" | "left" | "none" | undefined;
103
+ legendPlacement?: "top" | "right" | "bottom" | "left" | undefined;
105
104
  isHovered?: boolean | undefined;
106
105
  } & {
107
106
  class?: string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | /*elided*/ any | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined;
@@ -110,7 +109,7 @@ export declare const compositionBarVariants: (props?: import("../../utils/varian
110
109
  tooltipLabel: (props?: ({
111
110
  orientation?: "horizontal" | "vertical" | undefined;
112
111
  size?: "sm" | "md" | "lg" | undefined;
113
- legendPlacement?: "top" | "right" | "bottom" | "left" | "none" | undefined;
112
+ legendPlacement?: "top" | "right" | "bottom" | "left" | undefined;
114
113
  isHovered?: boolean | undefined;
115
114
  } & {
116
115
  class?: string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | /*elided*/ any | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined;
@@ -119,7 +118,7 @@ export declare const compositionBarVariants: (props?: import("../../utils/varian
119
118
  tooltipDetail: (props?: ({
120
119
  orientation?: "horizontal" | "vertical" | undefined;
121
120
  size?: "sm" | "md" | "lg" | undefined;
122
- legendPlacement?: "top" | "right" | "bottom" | "left" | "none" | undefined;
121
+ legendPlacement?: "top" | "right" | "bottom" | "left" | undefined;
123
122
  isHovered?: boolean | undefined;
124
123
  } & {
125
124
  class?: string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | /*elided*/ any | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined;
@@ -128,7 +127,7 @@ export declare const compositionBarVariants: (props?: import("../../utils/varian
128
127
  legend: (props?: ({
129
128
  orientation?: "horizontal" | "vertical" | undefined;
130
129
  size?: "sm" | "md" | "lg" | undefined;
131
- legendPlacement?: "top" | "right" | "bottom" | "left" | "none" | undefined;
130
+ legendPlacement?: "top" | "right" | "bottom" | "left" | undefined;
132
131
  isHovered?: boolean | undefined;
133
132
  } & {
134
133
  class?: string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | /*elided*/ any | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined;
@@ -137,7 +136,7 @@ export declare const compositionBarVariants: (props?: import("../../utils/varian
137
136
  legendItem: (props?: ({
138
137
  orientation?: "horizontal" | "vertical" | undefined;
139
138
  size?: "sm" | "md" | "lg" | undefined;
140
- legendPlacement?: "top" | "right" | "bottom" | "left" | "none" | undefined;
139
+ legendPlacement?: "top" | "right" | "bottom" | "left" | undefined;
141
140
  isHovered?: boolean | undefined;
142
141
  } & {
143
142
  class?: string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | /*elided*/ any | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined;
@@ -146,7 +145,7 @@ export declare const compositionBarVariants: (props?: import("../../utils/varian
146
145
  legendDot: (props?: ({
147
146
  orientation?: "horizontal" | "vertical" | undefined;
148
147
  size?: "sm" | "md" | "lg" | undefined;
149
- legendPlacement?: "top" | "right" | "bottom" | "left" | "none" | undefined;
148
+ legendPlacement?: "top" | "right" | "bottom" | "left" | undefined;
150
149
  isHovered?: boolean | undefined;
151
150
  } & {
152
151
  class?: string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | /*elided*/ any | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined;
@@ -155,7 +154,7 @@ export declare const compositionBarVariants: (props?: import("../../utils/varian
155
154
  legendLabel: (props?: ({
156
155
  orientation?: "horizontal" | "vertical" | undefined;
157
156
  size?: "sm" | "md" | "lg" | undefined;
158
- legendPlacement?: "top" | "right" | "bottom" | "left" | "none" | undefined;
157
+ legendPlacement?: "top" | "right" | "bottom" | "left" | undefined;
159
158
  isHovered?: boolean | undefined;
160
159
  } & {
161
160
  class?: string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | /*elided*/ any | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined;
@@ -164,7 +163,7 @@ export declare const compositionBarVariants: (props?: import("../../utils/varian
164
163
  legendValue: (props?: ({
165
164
  orientation?: "horizontal" | "vertical" | undefined;
166
165
  size?: "sm" | "md" | "lg" | undefined;
167
- legendPlacement?: "top" | "right" | "bottom" | "left" | "none" | undefined;
166
+ legendPlacement?: "top" | "right" | "bottom" | "left" | undefined;
168
167
  isHovered?: boolean | undefined;
169
168
  } & {
170
169
  class?: string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | /*elided*/ any | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined;
@@ -173,7 +172,7 @@ export declare const compositionBarVariants: (props?: import("../../utils/varian
173
172
  total: (props?: ({
174
173
  orientation?: "horizontal" | "vertical" | undefined;
175
174
  size?: "sm" | "md" | "lg" | undefined;
176
- legendPlacement?: "top" | "right" | "bottom" | "left" | "none" | undefined;
175
+ legendPlacement?: "top" | "right" | "bottom" | "left" | undefined;
177
176
  isHovered?: boolean | undefined;
178
177
  } & {
179
178
  class?: string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | /*elided*/ any | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined;
@@ -182,7 +181,7 @@ export declare const compositionBarVariants: (props?: import("../../utils/varian
182
181
  totalLabel: (props?: ({
183
182
  orientation?: "horizontal" | "vertical" | undefined;
184
183
  size?: "sm" | "md" | "lg" | undefined;
185
- legendPlacement?: "top" | "right" | "bottom" | "left" | "none" | undefined;
184
+ legendPlacement?: "top" | "right" | "bottom" | "left" | undefined;
186
185
  isHovered?: boolean | undefined;
187
186
  } & {
188
187
  class?: string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | /*elided*/ any | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined;
@@ -82,12 +82,14 @@ export const compositionBarVariants = tv({
82
82
  legendDot: 'h-3 w-3'
83
83
  }
84
84
  },
85
+ // Where the legend sits relative to the bar. Whether it renders at all is a
86
+ // separate axis — the `showLegend` prop, consistent with the other charts —
87
+ // so there is deliberately no `none` here (it duplicated `showLegend={false}`).
85
88
  legendPlacement: {
86
89
  top: { wrapper: 'flex-col-reverse' },
87
90
  right: { wrapper: 'flex-row items-start gap-4' },
88
91
  bottom: { wrapper: 'flex-col' },
89
- left: { wrapper: 'flex-row-reverse items-start gap-4' },
90
- none: {}
92
+ left: { wrapper: 'flex-row-reverse items-start gap-4' }
91
93
  },
92
94
  isHovered: {
93
95
  true: {},
@@ -65,7 +65,7 @@ export interface CompositionBarProps extends Omit<CompositionBarVariants, 'isHov
65
65
  formatPercent?: (percent: number) => string;
66
66
  /** Default intent for items without their own `intent`/`color`. @default 'primary' */
67
67
  intent?: CompositionBarIntent;
68
- /** Show the legend. @default true */
68
+ /** Show the legend. Position it with `legendPlacement`. @default true */
69
69
  showLegend?: boolean;
70
70
  /** Show percentages in legend and tooltip. @default true */
71
71
  showPercentages?: boolean;
@@ -1,10 +1,11 @@
1
1
  <script lang="ts">
2
2
  import { Input } from '../../primitives/Input';
3
+ import { useI18n } from '@urbicon-ui/i18n';
3
4
  import type { CurrencyInputProps } from './index';
4
5
 
5
6
  let {
6
7
  value = $bindable(null),
7
- locale = 'de-DE',
8
+ locale = 'auto',
8
9
  currency = 'EUR',
9
10
  symbolPosition = 'suffix',
10
11
  precision = 2,
@@ -15,9 +16,14 @@
15
16
  ...inputProps
16
17
  }: CurrencyInputProps = $props();
17
18
 
18
- const resolvedLocale = $derived(
19
- locale === 'auto' ? new Intl.NumberFormat().resolvedOptions().locale : locale
20
- );
19
+ const i18n = useI18n();
20
+
21
+ // `'auto'` (the default) follows the active `<I18nProvider>` locale — SSR-safe
22
+ // (server and client resolve the same locale) and consistent with the rest of
23
+ // the library's number formatting (CompositionBar/Sankey read `i18n.locale`
24
+ // too). Falls back to the base locale (`en`) when no provider is mounted. An
25
+ // explicit BCP 47 string overrides it.
26
+ const resolvedLocale = $derived(locale === 'auto' ? i18n.locale : locale);
21
27
 
22
28
  const decimalSeparator = $derived(
23
29
  new Intl.NumberFormat(resolvedLocale).formatToParts(1.1).find((p) => p.type === 'decimal')
@@ -24,10 +24,11 @@ export type CurrencySymbolPosition = 'prefix' | 'suffix' | 'none';
24
24
  * @tag form
25
25
  * @related Input
26
26
  *
27
- * @example Default — Euro with German locale
27
+ * @example Default — follows the active i18n locale
28
28
  * ```svelte
29
29
  * <script>
30
- * let priceCents = $state(1234_56); // 1.234,56 €
30
+ * // "1.234,56 €" under a `de` provider, "1,234.56 €" under `en` (the default)
31
+ * let priceCents = $state(1234_56);
31
32
  * </script>
32
33
  * <CurrencyInput label="Price" bind:value={priceCents} />
33
34
  * ```
@@ -68,15 +69,16 @@ export interface CurrencyInputProps extends Omit<InputProps, 'type' | 'value' |
68
69
  */
69
70
  name?: string;
70
71
  /**
71
- * BCP 47 locale used for formatting (`Intl.NumberFormat`). Controls
72
- * grouping separator (`.` vs `,`) and decimal separator. Pass `'auto'`
73
- * to defer to the runtime locale (`Intl.NumberFormat().resolvedOptions().locale`)
74
- * i.e. the user's browser language. Note that the runtime locale on the
75
- * server (Node) and in the browser typically differ, so SSR pages using
76
- * `'auto'` may briefly show a different format on initial render before
77
- * hydration. `currency` is intentionally **not** auto-detected, since it
78
- * is orthogonal to locale (a `de-CH` user may still bill in EUR).
79
- * @default 'de-DE'
72
+ * BCP 47 locale used for formatting (`Intl.NumberFormat`). Controls the
73
+ * grouping separator (`.` vs `,`) and decimal separator. Defaults to
74
+ * `'auto'`, which follows the active `<I18nProvider>` locale — SSR-safe
75
+ * (server and client resolve the same locale, no hydration flash) and
76
+ * consistent with the rest of the library's number formatting. Falls back
77
+ * to the base locale (`en`) when no provider is mounted. Pass an explicit
78
+ * BCP 47 string (e.g. `'de-DE'`, `'ja-JP'`) to override. `currency` is
79
+ * intentionally **not** auto-detected, since it is orthogonal to locale
80
+ * (a `de-CH` user may still bill in EUR).
81
+ * @default 'auto'
80
82
  */
81
83
  locale?: string;
82
84
  /**
@@ -8,7 +8,7 @@
8
8
  import CalendarIconDefault from '../../icons/CalendarIcon.svelte';
9
9
  import CloseIconDefault from '../../icons/CloseIcon.svelte';
10
10
  import { useBlocksI18n } from '../..';
11
- import { formatDate, parseDate, isDateAllowed } from './datepicker.engine';
11
+ import { formatDateInput, parseDateInput, isDateAllowed } from './datepicker.engine';
12
12
  import { coerceToDate, toDateInputValue } from '../../utils/date';
13
13
  import type { DatePickerProps } from '.';
14
14
 
@@ -65,7 +65,9 @@
65
65
  let parseError = $state<string | undefined>();
66
66
 
67
67
  const dateValue = $derived(coerceToDate(value));
68
- const formattedValue = $derived(dateValue ? formatDate(dateValue, locale, displayFormat) : '');
68
+ const formattedValue = $derived(
69
+ dateValue ? formatDateInput(dateValue, locale, displayFormat) : ''
70
+ );
69
71
 
70
72
  // Single source of truth for what the input renders. The user-typed
71
73
  // draft sticks around while the input is focused *or* a parse error
@@ -136,7 +138,7 @@
136
138
  userDraft = null;
137
139
  return;
138
140
  }
139
- const parsed = parseDate(trimmed, locale, displayFormat);
141
+ const parsed = parseDateInput(trimmed, locale, displayFormat);
140
142
  if (!parsed) {
141
143
  parseError = bt('datepicker.invalidDate');
142
144
  return;
@@ -9,7 +9,7 @@
9
9
  import CalendarIconDefault from '../../icons/CalendarIcon.svelte';
10
10
  import CloseIconDefault from '../../icons/CloseIcon.svelte';
11
11
  import { useBlocksI18n } from '../..';
12
- import { formatDateRange, parseDateRange, isDateAllowed } from './datepicker.engine';
12
+ import { formatDateRangeInput, parseDateRangeInput, isDateAllowed } from './datepicker.engine';
13
13
  import { toDateInputValue } from '../../utils/date';
14
14
  import type { DateRangePickerProps } from '.';
15
15
 
@@ -66,7 +66,7 @@
66
66
  let parseError = $state<string | undefined>();
67
67
 
68
68
  const formattedValue = $derived(
69
- value ? formatDateRange(value.start, value.end, locale, displayFormat) : ''
69
+ value ? formatDateRangeInput(value.start, value.end, locale, displayFormat) : ''
70
70
  );
71
71
 
72
72
  const inputValue = $derived(
@@ -154,7 +154,7 @@
154
154
  userDraft = null;
155
155
  return;
156
156
  }
157
- const parsed = parseDateRange(trimmed, locale, displayFormat);
157
+ const parsed = parseDateRangeInput(trimmed, locale, displayFormat);
158
158
  if (!parsed) {
159
159
  parseError = bt('datepicker.invalidRange');
160
160
  return;
@@ -14,7 +14,7 @@ export type DateFormatOptions = Intl.DateTimeFormatOptions;
14
14
  * Format a Date as a locale-aware string. Guards Invalid Date and Intl
15
15
  * errors with logging instead of silent fallback.
16
16
  */
17
- export declare function formatDate(date: Date, locale: string, options?: DateFormatOptions): string;
17
+ export declare function formatDateInput(date: Date, locale: string, options?: DateFormatOptions): string;
18
18
  /**
19
19
  * Format a date range. Deliberately concatenates the two halves with a
20
20
  * fixed " – " (U+2013, en-dash with spaces) separator instead of
@@ -22,9 +22,9 @@ export declare function formatDate(date: Date, locale: string, options?: DateFor
22
22
  * shared components (year/month) and break round-trip parsing — the
23
23
  * range "Mar 15 – 22, 2026" cannot be split back into two valid dates
24
24
  * because the first half has no year. The fixed separator keeps
25
- * `formatDateRange` and `parseDateRange` symmetric.
25
+ * `formatDateRangeInput` and `parseDateRangeInput` symmetric.
26
26
  */
27
- export declare function formatDateRange(start: Date, end: Date, locale: string, options?: DateFormatOptions): string;
27
+ export declare function formatDateRangeInput(start: Date, end: Date, locale: string, options?: DateFormatOptions): string;
28
28
  /**
29
29
  * Parse a single date from user input. Tries the locale's formatted mask
30
30
  * first (built via `Intl.DateTimeFormat#formatToParts`), then a strict
@@ -36,14 +36,14 @@ export declare function formatDateRange(start: Date, end: Date, locale: string,
36
36
  * weekday literals, or non-Gregorian calendars are NOT parseable — the
37
37
  * caller should rely on calendar-picker UX or accept ISO input only.
38
38
  */
39
- export declare function parseDate(input: string, locale: string, options?: DateFormatOptions): Date | null;
39
+ export declare function parseDateInput(input: string, locale: string, options?: DateFormatOptions): Date | null;
40
40
  /**
41
41
  * Parse a date range string like "15.03.2026 – 22.03.2026". Splits on
42
- * the locale-aware range separator and parses each half with `parseDate`.
42
+ * the locale-aware range separator and parses each half with `parseDateInput`.
43
43
  * A single date with no separator is accepted as a single-day range
44
44
  * (`{ start: d, end: d }`). Rejects inverted ranges (start after end).
45
45
  */
46
- export declare function parseDateRange(input: string, locale: string, options?: DateFormatOptions): DateRange | null;
46
+ export declare function parseDateRangeInput(input: string, locale: string, options?: DateFormatOptions): DateRange | null;
47
47
  export interface DateConstraints {
48
48
  minDate?: Date;
49
49
  maxDate?: Date;
@@ -25,9 +25,9 @@ function isSameDay(a, b) {
25
25
  * Format a Date as a locale-aware string. Guards Invalid Date and Intl
26
26
  * errors with logging instead of silent fallback.
27
27
  */
28
- export function formatDate(date, locale, options) {
28
+ export function formatDateInput(date, locale, options) {
29
29
  if (!isValid(date)) {
30
- console.warn('[DatePicker] formatDate received Invalid Date', { date, locale });
30
+ console.warn('[DatePicker] formatDateInput received Invalid Date', { date, locale });
31
31
  return '';
32
32
  }
33
33
  try {
@@ -49,16 +49,16 @@ export function formatDate(date, locale, options) {
49
49
  * shared components (year/month) and break round-trip parsing — the
50
50
  * range "Mar 15 – 22, 2026" cannot be split back into two valid dates
51
51
  * because the first half has no year. The fixed separator keeps
52
- * `formatDateRange` and `parseDateRange` symmetric.
52
+ * `formatDateRangeInput` and `parseDateRangeInput` symmetric.
53
53
  */
54
- export function formatDateRange(start, end, locale, options) {
54
+ export function formatDateRangeInput(start, end, locale, options) {
55
55
  if (!isValid(start) || !isValid(end)) {
56
- console.warn('[DatePicker] formatDateRange received Invalid Date', { start, end, locale });
56
+ console.warn('[DatePicker] formatDateRangeInput received Invalid Date', { start, end, locale });
57
57
  return '';
58
58
  }
59
59
  const fmt = options ?? defaultFormat;
60
- const s = formatDate(start, locale, fmt);
61
- const e = formatDate(end, locale, fmt);
60
+ const s = formatDateInput(start, locale, fmt);
61
+ const e = formatDateInput(end, locale, fmt);
62
62
  if (!s || !e)
63
63
  return '';
64
64
  return `${s} – ${e}`;
@@ -191,7 +191,7 @@ function parseLocaleDate(input, locale, options) {
191
191
  * weekday literals, or non-Gregorian calendars are NOT parseable — the
192
192
  * caller should rely on calendar-picker UX or accept ISO input only.
193
193
  */
194
- export function parseDate(input, locale, options) {
194
+ export function parseDateInput(input, locale, options) {
195
195
  const trimmed = input.trim();
196
196
  if (!trimmed)
197
197
  return null;
@@ -223,23 +223,23 @@ export function parseDate(input, locale, options) {
223
223
  const rangeSeparator = /\s+(?:-|\/|bis|to)\s+|\s*,\s+|\s*[–—−]\s*/i;
224
224
  /**
225
225
  * Parse a date range string like "15.03.2026 – 22.03.2026". Splits on
226
- * the locale-aware range separator and parses each half with `parseDate`.
226
+ * the locale-aware range separator and parses each half with `parseDateInput`.
227
227
  * A single date with no separator is accepted as a single-day range
228
228
  * (`{ start: d, end: d }`). Rejects inverted ranges (start after end).
229
229
  */
230
- export function parseDateRange(input, locale, options) {
230
+ export function parseDateRangeInput(input, locale, options) {
231
231
  const trimmed = input.trim();
232
232
  if (!trimmed)
233
233
  return null;
234
234
  const parts = trimmed.split(rangeSeparator);
235
235
  if (parts.length === 1) {
236
- const single = parseDate(parts[0], locale, options);
236
+ const single = parseDateInput(parts[0], locale, options);
237
237
  return single ? { start: single, end: single } : null;
238
238
  }
239
239
  if (parts.length !== 2)
240
240
  return null;
241
- const start = parseDate(parts[0], locale, options);
242
- const end = parseDate(parts[1], locale, options);
241
+ const start = parseDateInput(parts[0], locale, options);
242
+ const end = parseDateInput(parts[1], locale, options);
243
243
  if (!start || !end)
244
244
  return null;
245
245
  if (start.getTime() > end.getTime())
@@ -1,5 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { getBlocksConfig, resolveSlotClasses } from '../../provider';
3
+ import { useBlocksI18n } from '../..';
3
4
  import type { DonutChartProps } from './index';
4
5
  import { chartSlotResolver } from '../../internal/charts/variants';
5
6
  import { arcPath, seriesColor, numberFormatter } from '../../internal/charts/utils';
@@ -23,6 +24,7 @@
23
24
  }: DonutChartProps = $props();
24
25
 
25
26
  const blocksConfig = getBlocksConfig();
27
+ const bt = useBlocksI18n();
26
28
  const unstyled = $derived(unstyledProp || blocksConfig?.unstyled || false);
27
29
  const slotClasses = $derived(
28
30
  resolveSlotClasses(blocksConfig, 'DonutChart', preset, {}, slotClassesProp)
@@ -136,9 +138,9 @@
136
138
  <caption>{resolvedAriaLabel}</caption>
137
139
  <thead>
138
140
  <tr>
139
- <th scope="col">Segment</th>
140
- <th scope="col">Value</th>
141
- <th scope="col">Share</th>
141
+ <th scope="col">{bt('chart.segment')}</th>
142
+ <th scope="col">{bt('chart.value')}</th>
143
+ <th scope="col">{bt('chart.share')}</th>
142
144
  </tr>
143
145
  </thead>
144
146
  <tbody>
@@ -13,6 +13,7 @@
13
13
  } from '../../internal/charts/utils';
14
14
  import type { ChartPoint } from '../../internal/charts/utils';
15
15
  import ChartFrame from '../ChartFrame/ChartFrame.svelte';
16
+ import { useBlocksI18n } from '../..';
16
17
 
17
18
  let {
18
19
  data,
@@ -35,6 +36,7 @@
35
36
  }: LineChartProps = $props();
36
37
 
37
38
  const blocksConfig = getBlocksConfig();
39
+ const bt = useBlocksI18n();
38
40
  const unstyled = $derived(unstyledProp || blocksConfig?.unstyled || false);
39
41
  const slotClasses = $derived(
40
42
  resolveSlotClasses(blocksConfig, 'LineChart', preset, {}, slotClassesProp)
@@ -47,7 +49,9 @@
47
49
  const resolvedSeries = $derived<ChartSeries[]>(
48
50
  seriesProp && seriesProp.length > 0
49
51
  ? seriesProp
50
- : Array.from({ length: seriesCount }, (_, i) => ({ label: `Series ${i + 1}` }))
52
+ : Array.from({ length: seriesCount }, (_, i) => ({
53
+ label: bt('chart.series', { index: i + 1 })
54
+ }))
51
55
  );
52
56
 
53
57
  const fmt = $derived(formatValue ?? numberFormatter(locale));
@@ -174,9 +178,9 @@
174
178
  <caption>{resolvedAriaLabel}</caption>
175
179
  <thead>
176
180
  <tr>
177
- <th scope="col">Category</th>
181
+ <th scope="col">{bt('chart.category')}</th>
178
182
  {#each resolvedSeries as s, i (s.label + ' ' + i)}
179
- <th scope="col">{s.label || `Series ${i + 1}`}</th>
183
+ <th scope="col">{s.label || bt('chart.series', { index: i + 1 })}</th>
180
184
  {/each}
181
185
  </tr>
182
186
  </thead>
@@ -154,8 +154,8 @@
154
154
  $effect(() => {
155
155
  const _today = controller.today;
156
156
  if (typeof window === 'undefined') return;
157
- const now = new Date(); // eslint-disable-line svelte/prefer-svelte-reactivity
158
- const midnight = new Date(now); // eslint-disable-line svelte/prefer-svelte-reactivity
157
+ const now = new Date();
158
+ const midnight = new Date(now);
159
159
  midnight.setHours(24, 0, 0, 0);
160
160
  const timeout = setTimeout(() => controller.refreshToday(), midnight.getTime() - now.getTime());
161
161
  return () => clearTimeout(timeout);
@@ -220,7 +220,8 @@
220
220
  goToToday: () => controller.goToToday(),
221
221
  goTo: (date) => controller.goTo(date),
222
222
  canGoBack: controller.canGoBack,
223
- canGoForward: controller.canGoForward
223
+ canGoForward: controller.canGoForward,
224
+ canGoToToday: controller.canGoToToday
224
225
  });
225
226
 
226
227
  // --- Contexts: the controller IS the date-grid context the Scaffold reads;
@@ -249,6 +250,9 @@
249
250
  get canGoForward() {
250
251
  return controller.canGoForward;
251
252
  },
253
+ get canGoToToday() {
254
+ return controller.canGoToToday;
255
+ },
252
256
  get locale() {
253
257
  return locale;
254
258
  },
@@ -60,7 +60,7 @@
60
60
  mint="none"
61
61
  class={ctx.slot('navButton')}
62
62
  onclick={() => ctx.goToToday()}
63
- disabled={ctx.disabled}
63
+ disabled={!ctx.canGoToToday || ctx.disabled}
64
64
  aria-label={bt('planner.today')}
65
65
  >
66
66
  <CalendarDaysIcon size={16} />
@@ -77,6 +77,8 @@ export interface PlannerHeaderContext {
77
77
  canGoBack: boolean;
78
78
  /** Whether forward-navigation is within bounds. */
79
79
  canGoForward: boolean;
80
+ /** Whether today is within `[minDate, maxDate]`; gate a custom Today control on it. */
81
+ canGoToToday: boolean;
80
82
  }
81
83
  /** Every styleable slot Planner exposes through `slotClasses`. */
82
84
  export type PlannerSlotName = 'base' | 'header' | 'headerTitle' | 'nav' | 'navButton' | 'grid' | 'weekdayHeader' | 'weekday' | 'weekNumber' | 'week' | 'cell' | 'cellHeader' | 'cellWeekday' | 'cellDate' | 'cellItems' | 'empty';
@@ -93,6 +95,7 @@ export interface PlannerContext {
93
95
  readonly weekNumber: number;
94
96
  readonly canGoBack: boolean;
95
97
  readonly canGoForward: boolean;
98
+ readonly canGoToToday: boolean;
96
99
  readonly locale: string;
97
100
  readonly disabled: boolean;
98
101
  navigate(delta: number): void;
@@ -21,6 +21,14 @@ export declare function isSameDay(a: Date, b: Date): boolean;
21
21
  export declare function isWeekend(date: Date): boolean;
22
22
  /** Check whether a date falls within a range (inclusive on both ends, order-independent). */
23
23
  export declare function isInRange(date: Date, start: Date, end: Date): boolean;
24
+ /**
25
+ * Clamp a date into optional `[minDate, maxDate]` day boundaries — the
26
+ * day-level sibling of `clampMonth`. Comparison is on calendar days (time is
27
+ * stripped from both sides), so a date already inside the range is returned
28
+ * unchanged (keeping its own time-of-day) while an out-of-range date snaps to
29
+ * local midnight of the nearest boundary. Either bound may be omitted.
30
+ */
31
+ export declare function clampDate(date: Date, minDate?: Date, maxDate?: Date): Date;
24
32
  /** Check whether a date belongs to the given month and year. */
25
33
  export declare function isInMonth(date: Date, month: number, year: number): boolean;
26
34
  /**
@@ -35,6 +35,21 @@ export function isInRange(date, start, end) {
35
35
  const e = stripTime(end).getTime();
36
36
  return d >= Math.min(s, e) && d <= Math.max(s, e);
37
37
  }
38
+ /**
39
+ * Clamp a date into optional `[minDate, maxDate]` day boundaries — the
40
+ * day-level sibling of `clampMonth`. Comparison is on calendar days (time is
41
+ * stripped from both sides), so a date already inside the range is returned
42
+ * unchanged (keeping its own time-of-day) while an out-of-range date snaps to
43
+ * local midnight of the nearest boundary. Either bound may be omitted.
44
+ */
45
+ export function clampDate(date, minDate, maxDate) {
46
+ const day = stripTime(date);
47
+ if (minDate && day < stripTime(minDate))
48
+ return stripTime(minDate);
49
+ if (maxDate && day > stripTime(maxDate))
50
+ return stripTime(maxDate);
51
+ return date;
52
+ }
38
53
  /** Check whether a date belongs to the given month and year. */
39
54
  export function isInMonth(date, month, year) {
40
55
  return date.getMonth() === month && date.getFullYear() === year;
@@ -12,7 +12,7 @@
12
12
  * import { getWeekNumber, eachDayOfRange, toIso } from '@urbicon-ui/blocks/date';
13
13
  * ```
14
14
  */
15
- export { daysBetween, isInMonth, isInRange, isSameDay, isWeekend, stripTime } from './compare.js';
15
+ export { clampDate, daysBetween, isInMonth, isInRange, isSameDay, isWeekend, stripTime } from './compare.js';
16
16
  export { formatDate, formatDateFull, formatDateRange, formatDayTitle, formatMonthShort, formatMonthYear, formatWeekRange, formatWeekTitle, getWeekdayNames } from './format.js';
17
17
  export { clampMonth, daysInMonth, getMonthGrid, getWeekDates, getWeekNumber, getYearMonths } from './geometry.js';
18
18
  export { addDays, eachDayOfRange, endOfWeek, isoToDate, startOfWeek, toIso } from './range.js';
@@ -12,7 +12,7 @@
12
12
  * import { getWeekNumber, eachDayOfRange, toIso } from '@urbicon-ui/blocks/date';
13
13
  * ```
14
14
  */
15
- export { daysBetween, isInMonth, isInRange, isSameDay, isWeekend, stripTime } from './compare.js';
15
+ export { clampDate, daysBetween, isInMonth, isInRange, isSameDay, isWeekend, stripTime } from './compare.js';
16
16
  export { formatDate, formatDateFull, formatDateRange, formatDayTitle, formatMonthShort, formatMonthYear, formatWeekRange, formatWeekTitle, getWeekdayNames } from './format.js';
17
17
  export { clampMonth, daysInMonth, getMonthGrid, getWeekDates, getWeekNumber, getYearMonths } from './geometry.js';
18
18
  export { addDays, eachDayOfRange, endOfWeek, isoToDate, startOfWeek, toIso } from './range.js';