ng-blatui 1.34.0 → 1.35.0

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.
@@ -1,7 +1,7 @@
1
1
  import { clsx } from 'clsx';
2
2
  import { twMerge } from 'tailwind-merge';
3
3
  import * as i0 from '@angular/core';
4
- import { InjectionToken, makeEnvironmentProviders, inject, computed, input, Directive, Component, signal, model, forwardRef, PLATFORM_ID, effect, Injectable, ElementRef, ViewContainerRef, viewChild, afterNextRender, output, linkedSignal, ViewEncapsulation, Injector, DestroyRef } from '@angular/core';
4
+ import { InjectionToken, makeEnvironmentProviders, inject, computed, LOCALE_ID, input, Directive, Component, signal, model, forwardRef, PLATFORM_ID, effect, Injectable, ElementRef, ViewContainerRef, viewChild, afterNextRender, output, linkedSignal, ViewEncapsulation, Injector, DestroyRef } from '@angular/core';
5
5
  import { cva } from 'class-variance-authority';
6
6
  import { NG_VALUE_ACCESSOR } from '@angular/forms';
7
7
  export { AccordionContent, AccordionGroup, AccordionPanel, AccordionTrigger, ɵɵDeferredContent, ɵɵDeferredContentAware } from '@angular/aria/accordion';
@@ -48,6 +48,16 @@ const BUI_DEFAULT_LABELS = {
48
48
  calendarMonth: 'Month',
49
49
  calendarYear: 'Year',
50
50
  calendarNextMonth: 'Next month',
51
+ calendarWeek: 'Week',
52
+ datePickerPlaceholder: 'Pick a date',
53
+ dateRangePickerPlaceholder: 'Pick a date range',
54
+ dateRangePresetToday: 'Today',
55
+ dateRangePresetLast7Days: 'Last 7 days',
56
+ dateRangePresetLast30Days: 'Last 30 days',
57
+ dateRangePresetThisMonth: 'This month',
58
+ dateRangePresetLastMonth: 'Last month',
59
+ datetimePickerPlaceholder: 'Pick date & time',
60
+ datetimePickerTime: 'Time',
51
61
  carouselPrevious: 'Previous slide',
52
62
  carouselNext: 'Next slide',
53
63
  carouselGoToSlide: 'Go to slide',
@@ -65,8 +75,13 @@ const BUI_DEFAULT_LABELS = {
65
75
  dock: 'Dock',
66
76
  fileUploadDropzone: 'Click to upload or drag & drop',
67
77
  fileUploadRemove: 'Remove file',
78
+ ganttEmpty: 'No tasks.',
79
+ markdownEditorWrite: 'Write',
80
+ markdownEditorPreview: 'Preview',
68
81
  miniCartTrigger: 'Cart',
69
82
  miniCart: 'Shopping cart',
83
+ miniCartTitle: 'Your cart',
84
+ miniCartSubtotal: 'Subtotal',
70
85
  notificationCenter: 'Notifications',
71
86
  notificationCenterUnread: 'Unread',
72
87
  notificationCenterMarkAllRead: 'Mark all read',
@@ -76,6 +91,7 @@ const BUI_DEFAULT_LABELS = {
76
91
  phoneInputCountry: 'Country code',
77
92
  phoneInputNumber: 'Phone number',
78
93
  productCardWishlist: 'Add to wishlist',
94
+ productCardAddToCart: 'Add to cart',
79
95
  promptInputAttach: 'Attach file',
80
96
  promptInputSend: 'Send',
81
97
  quantitySelectorDecrease: 'Decrease quantity',
@@ -86,6 +102,25 @@ const BUI_DEFAULT_LABELS = {
86
102
  sonner: 'Notifications',
87
103
  sonnerDismiss: 'Dismiss notification',
88
104
  themeCustomizer: 'Theme customizer',
105
+ themeCustomizerOpen: 'Customize',
106
+ themeCustomizerClose: 'Close',
107
+ themeCustomizerTagline: 'Tune it live. Every preset is pure CSS variables.',
108
+ themeCustomizerReset: 'Reset',
109
+ themeCustomizerMode: 'Mode',
110
+ themeCustomizerBaseColor: 'Base color',
111
+ themeCustomizerAccent: 'Accent',
112
+ themeCustomizerRadius: 'Radius',
113
+ themeCustomizerInputStyle: 'Input style',
114
+ themeCustomizerBodyFont: 'Body font',
115
+ themeCustomizerHeadingFont: 'Heading font',
116
+ themeCustomizerShadow: 'Shadow',
117
+ themeCustomizerSpacing: 'Spacing',
118
+ themeCustomizerTracking: 'Tracking',
119
+ timeField: 'Time',
120
+ timeFieldHours: 'hours',
121
+ timeFieldMinutes: 'minutes',
122
+ toolCallArguments: 'Arguments',
123
+ toolCallResult: 'Result',
89
124
  treeTableToggle: 'Toggle row',
90
125
  treeTableCopy: 'Copy as tree',
91
126
  treeTableCopied: 'Copied',
@@ -126,6 +161,137 @@ function buiLabel(key, override) {
126
161
  return computed(() => override() ?? overrides?.[key] ?? BUI_DEFAULT_LABELS[key]);
127
162
  }
128
163
 
164
+ /**
165
+ * Resolve the BCP 47 locale a component formats dates in, most-specific wins:
166
+ * per-instance `locale` input → the app's `LOCALE_ID` → `'en-US'` (Angular's own default).
167
+ *
168
+ * Call from an injection context (a component field initializer):
169
+ *
170
+ * ```ts
171
+ * readonly locale = input<string>();
172
+ * protected readonly resolvedLocale = buiLocale(this.locale);
173
+ * ```
174
+ *
175
+ * The input stays a signal on purpose: apps that switch language at runtime (transloco &
176
+ * co.) need the display to reformat, which a statically-injected `LOCALE_ID` cannot do.
177
+ */
178
+ function buiLocale(override) {
179
+ const localeId = inject(LOCALE_ID);
180
+ return computed(() => {
181
+ const value = override();
182
+ return value === undefined || value === '' ? localeId : value;
183
+ });
184
+ }
185
+ /**
186
+ * The calendar system ng-blatui's date grids are built on. They are computed from JavaScript
187
+ * `Date`, so they are Gregorian, and every label that describes them is pinned to it — otherwise
188
+ * a locale whose default era is not Gregorian (`th` → Buddhist 2569, `fa` → Persian 1405) would
189
+ * name a month or year the grid is not showing.
190
+ *
191
+ * The pickers apply it as a *default* their `dateFormat` can override: pass
192
+ * `[dateFormat]="{ calendar: 'persian' }"` to display a value in another calendar system.
193
+ */
194
+ const BUI_GRID_CALENDAR = 'gregory';
195
+ /**
196
+ * CLDR's `minDays` is 1 everywhere except these regions, which follow the ISO-8601 rule.
197
+ *
198
+ * It is a table rather than a lookup because `Intl`'s own `minimalDays` cannot be trusted: V8
199
+ * dropped it, so it is absent in Chrome and Node 24 but still present in Node 22. Reading it
200
+ * would number weeks differently depending on the engine — and yield `NaN` where it is gone.
201
+ */
202
+ const ISO_WEEK_REGIONS = new Set([
203
+ 'AD',
204
+ 'AN',
205
+ 'AT',
206
+ 'AX',
207
+ 'BE',
208
+ 'BG',
209
+ 'CH',
210
+ 'CZ',
211
+ 'DE',
212
+ 'DK',
213
+ 'EE',
214
+ 'ES',
215
+ 'FI',
216
+ 'FJ',
217
+ 'FO',
218
+ 'FR',
219
+ 'GB',
220
+ 'GF',
221
+ 'GG',
222
+ 'GI',
223
+ 'GP',
224
+ 'GR',
225
+ 'HU',
226
+ 'IE',
227
+ 'IM',
228
+ 'IS',
229
+ 'IT',
230
+ 'JE',
231
+ 'LI',
232
+ 'LT',
233
+ 'LU',
234
+ 'MC',
235
+ 'MQ',
236
+ 'NL',
237
+ 'NO',
238
+ 'PL',
239
+ 'PT',
240
+ 'RE',
241
+ 'RU',
242
+ 'SE',
243
+ 'SJ',
244
+ 'SK',
245
+ 'SM',
246
+ 'VA',
247
+ ]);
248
+ /** Anglo/Western default, used when the engine has no week data for the locale. */
249
+ const FALLBACK_WEEK_INFO = { firstDay: 0, weekend: [0, 6], minimalDays: 1 };
250
+ function minimalDaysFor(locale) {
251
+ try {
252
+ const region = new Intl.Locale(locale).maximize().region;
253
+ return region !== undefined && ISO_WEEK_REGIONS.has(region) ? 4 : 1;
254
+ }
255
+ catch {
256
+ return FALLBACK_WEEK_INFO.minimalDays;
257
+ }
258
+ }
259
+ /** `Intl` counts Monday=1..Sunday=7; the calendar counts Sunday=0..Saturday=6. */
260
+ function toSundayZero(day) {
261
+ return day % 7;
262
+ }
263
+ function readWeekInfo(locale) {
264
+ // Typed as `object` so the narrowing below is a real assertion under every `lib` setting.
265
+ let resolved;
266
+ try {
267
+ resolved = new Intl.Locale(locale);
268
+ }
269
+ catch {
270
+ // An unparseable locale tag is the caller's bug, but not worth breaking a calendar over.
271
+ return FALLBACK_WEEK_INFO;
272
+ }
273
+ const source = resolved;
274
+ const info = source.getWeekInfo?.() ?? source.weekInfo;
275
+ return info === undefined
276
+ ? FALLBACK_WEEK_INFO
277
+ : {
278
+ firstDay: toSundayZero(info.firstDay),
279
+ weekend: info.weekend.map((day) => toSundayZero(day)),
280
+ minimalDays: minimalDaysFor(locale),
281
+ };
282
+ }
283
+ /**
284
+ * The locale's own week conventions, so a calendar is not silently US-shaped: `fr` starts the
285
+ * week on Monday, `ar-EG` on Saturday with a Friday/Saturday weekend, `en-US` on Sunday with a
286
+ * Saturday/Sunday weekend — the last being exactly the library's pre-locale behavior.
287
+ *
288
+ * Falls back to the US convention on engines without week data (rather than throwing), so this
289
+ * only ever adds correctness.
290
+ */
291
+ function buiWeekInfo(locale) {
292
+ return computed(() => readWeekInfo(locale()));
293
+ }
294
+
129
295
  const buttonVariants = cva("inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", {
130
296
  variants: {
131
297
  variant: {
@@ -1623,6 +1789,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
1623
1789
  args: [{ providedIn: 'root' }]
1624
1790
  }], ctorParameters: () => [] });
1625
1791
 
1792
+ /** This panel's copy has no per-instance inputs — translate it with `provideBuiLabels`. */
1793
+ const NO_OVERRIDE = signal(undefined, /* @ts-ignore */
1794
+ ...(ngDevMode ? [{ debugName: "NO_OVERRIDE" }] : /* istanbul ignore next */ []));
1626
1795
  const FONTS = [
1627
1796
  { value: 'sans', label: 'Default', family: "'Instrument Sans', sans-serif" },
1628
1797
  { value: 'inter', label: 'Inter', family: "'Inter', sans-serif" },
@@ -1646,6 +1815,22 @@ class BuiThemeCustomizer {
1646
1815
  ariaLabel = input(/* @ts-ignore */
1647
1816
  ...(ngDevMode ? [undefined, { debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
1648
1817
  ariaLabelText = buiLabel('themeCustomizer', this.ariaLabel);
1818
+ // Panel chrome. The option labels below ('Light', 'Flat', 'Compact'…) are still English:
1819
+ // 29 design-system terms deserve their own decision, not 29 more keys bolted on here.
1820
+ openText = buiLabel('themeCustomizerOpen', NO_OVERRIDE);
1821
+ closeText = buiLabel('themeCustomizerClose', NO_OVERRIDE);
1822
+ taglineText = buiLabel('themeCustomizerTagline', NO_OVERRIDE);
1823
+ resetText = buiLabel('themeCustomizerReset', NO_OVERRIDE);
1824
+ modeText = buiLabel('themeCustomizerMode', NO_OVERRIDE);
1825
+ baseColorText = buiLabel('themeCustomizerBaseColor', NO_OVERRIDE);
1826
+ accentText = buiLabel('themeCustomizerAccent', NO_OVERRIDE);
1827
+ radiusText = buiLabel('themeCustomizerRadius', NO_OVERRIDE);
1828
+ inputStyleText = buiLabel('themeCustomizerInputStyle', NO_OVERRIDE);
1829
+ bodyFontText = buiLabel('themeCustomizerBodyFont', NO_OVERRIDE);
1830
+ headingFontText = buiLabel('themeCustomizerHeadingFont', NO_OVERRIDE);
1831
+ shadowText = buiLabel('themeCustomizerShadow', NO_OVERRIDE);
1832
+ spacingText = buiLabel('themeCustomizerSpacing', NO_OVERRIDE);
1833
+ trackingText = buiLabel('themeCustomizerTracking', NO_OVERRIDE);
1649
1834
  theme = inject(ThemeStore);
1650
1835
  open = signal(false, /* @ts-ignore */
1651
1836
  ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
@@ -1736,7 +1921,7 @@ class BuiThemeCustomizer {
1736
1921
  [attr.aria-expanded]="open()"
1737
1922
  (click)="open.set(!open())"
1738
1923
  >
1739
- {{ open() ? 'Close' : 'Customize' }}
1924
+ {{ open() ? closeText() : openText() }}
1740
1925
  </button>
1741
1926
 
1742
1927
  @if (open()) {
@@ -1747,17 +1932,19 @@ class BuiThemeCustomizer {
1747
1932
  >
1748
1933
  <div class="flex items-center justify-between">
1749
1934
  <div>
1750
- <h4 class="text-sm font-semibold">Customize</h4>
1935
+ <h4 class="text-sm font-semibold">{{ openText() }}</h4>
1751
1936
  <p class="text-xs text-muted-foreground">
1752
- Tune it live. Every preset is pure CSS variables.
1937
+ {{ taglineText() }}
1753
1938
  </p>
1754
1939
  </div>
1755
- <button buiButton variant="ghost" size="sm" (click)="theme.reset()">Reset</button>
1940
+ <button buiButton variant="ghost" size="sm" (click)="theme.reset()">
1941
+ {{ resetText() }}
1942
+ </button>
1756
1943
  </div>
1757
1944
 
1758
1945
  <!-- Mode -->
1759
1946
  <div class="space-y-1.5">
1760
- <span class="text-xs font-medium">Mode</span>
1947
+ <span class="text-xs font-medium">{{ modeText() }}</span>
1761
1948
  <div class="grid grid-cols-3 gap-2">
1762
1949
  @for (m of modes; track m.value) {
1763
1950
  <button
@@ -1774,7 +1961,7 @@ class BuiThemeCustomizer {
1774
1961
 
1775
1962
  <!-- Base color -->
1776
1963
  <div class="space-y-1.5">
1777
- <span class="text-xs font-medium">Base color</span>
1964
+ <span class="text-xs font-medium">{{ baseColorText() }}</span>
1778
1965
  <div class="grid grid-cols-9 gap-2">
1779
1966
  @for (b of bases; track b.value) {
1780
1967
  <button
@@ -1792,7 +1979,7 @@ class BuiThemeCustomizer {
1792
1979
 
1793
1980
  <!-- Accent -->
1794
1981
  <div class="space-y-1.5">
1795
- <span class="text-xs font-medium">Accent</span>
1982
+ <span class="text-xs font-medium">{{ accentText() }}</span>
1796
1983
  <div class="grid grid-cols-6 gap-2">
1797
1984
  @for (a of accents; track a.value) {
1798
1985
  <button
@@ -1810,7 +1997,7 @@ class BuiThemeCustomizer {
1810
1997
 
1811
1998
  <!-- Radius -->
1812
1999
  <div class="space-y-1.5">
1813
- <span class="text-xs font-medium">Radius</span>
2000
+ <span class="text-xs font-medium">{{ radiusText() }}</span>
1814
2001
  <div class="grid grid-cols-6 gap-2">
1815
2002
  @for (r of radii; track r) {
1816
2003
  <button
@@ -1827,7 +2014,7 @@ class BuiThemeCustomizer {
1827
2014
 
1828
2015
  <!-- Input style -->
1829
2016
  <div class="space-y-1.5">
1830
- <span class="text-xs font-medium">Input style</span>
2017
+ <span class="text-xs font-medium">{{ inputStyleText() }}</span>
1831
2018
  <div class="grid grid-cols-3 gap-2">
1832
2019
  @for (i of inputStyles; track i.value) {
1833
2020
  <button
@@ -1844,7 +2031,7 @@ class BuiThemeCustomizer {
1844
2031
 
1845
2032
  <!-- Body font -->
1846
2033
  <div class="space-y-1.5">
1847
- <span class="text-xs font-medium">Body font</span>
2034
+ <span class="text-xs font-medium">{{ bodyFontText() }}</span>
1848
2035
  <div class="grid grid-cols-3 gap-2">
1849
2036
  @for (f of fonts; track f.value) {
1850
2037
  <button
@@ -1862,7 +2049,7 @@ class BuiThemeCustomizer {
1862
2049
 
1863
2050
  <!-- Heading font -->
1864
2051
  <div class="space-y-1.5">
1865
- <span class="text-xs font-medium">Heading font</span>
2052
+ <span class="text-xs font-medium">{{ headingFontText() }}</span>
1866
2053
  <div class="grid grid-cols-3 gap-2">
1867
2054
  @for (f of fonts; track f.value) {
1868
2055
  <button
@@ -1880,7 +2067,7 @@ class BuiThemeCustomizer {
1880
2067
 
1881
2068
  <!-- Shadow -->
1882
2069
  <div class="space-y-1.5">
1883
- <span class="text-xs font-medium">Shadow</span>
2070
+ <span class="text-xs font-medium">{{ shadowText() }}</span>
1884
2071
  <div class="grid grid-cols-5 gap-2">
1885
2072
  @for (s of shadows; track s.value) {
1886
2073
  <button
@@ -1898,7 +2085,7 @@ class BuiThemeCustomizer {
1898
2085
  <!-- Spacing + Tracking -->
1899
2086
  <div class="grid grid-cols-2 gap-4">
1900
2087
  <div class="space-y-1.5">
1901
- <span class="text-xs font-medium">Spacing</span>
2088
+ <span class="text-xs font-medium">{{ spacingText() }}</span>
1902
2089
  <div class="grid grid-cols-3 gap-1.5">
1903
2090
  @for (s of spacings; track s.value) {
1904
2091
  <button
@@ -1913,7 +2100,7 @@ class BuiThemeCustomizer {
1913
2100
  </div>
1914
2101
  </div>
1915
2102
  <div class="space-y-1.5">
1916
- <span class="text-xs font-medium">Tracking</span>
2103
+ <span class="text-xs font-medium">{{ trackingText() }}</span>
1917
2104
  <div class="grid grid-cols-3 gap-1.5">
1918
2105
  @for (t of trackings; track t.value) {
1919
2106
  <button
@@ -1960,7 +2147,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
1960
2147
  [attr.aria-expanded]="open()"
1961
2148
  (click)="open.set(!open())"
1962
2149
  >
1963
- {{ open() ? 'Close' : 'Customize' }}
2150
+ {{ open() ? closeText() : openText() }}
1964
2151
  </button>
1965
2152
 
1966
2153
  @if (open()) {
@@ -1971,17 +2158,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
1971
2158
  >
1972
2159
  <div class="flex items-center justify-between">
1973
2160
  <div>
1974
- <h4 class="text-sm font-semibold">Customize</h4>
2161
+ <h4 class="text-sm font-semibold">{{ openText() }}</h4>
1975
2162
  <p class="text-xs text-muted-foreground">
1976
- Tune it live. Every preset is pure CSS variables.
2163
+ {{ taglineText() }}
1977
2164
  </p>
1978
2165
  </div>
1979
- <button buiButton variant="ghost" size="sm" (click)="theme.reset()">Reset</button>
2166
+ <button buiButton variant="ghost" size="sm" (click)="theme.reset()">
2167
+ {{ resetText() }}
2168
+ </button>
1980
2169
  </div>
1981
2170
 
1982
2171
  <!-- Mode -->
1983
2172
  <div class="space-y-1.5">
1984
- <span class="text-xs font-medium">Mode</span>
2173
+ <span class="text-xs font-medium">{{ modeText() }}</span>
1985
2174
  <div class="grid grid-cols-3 gap-2">
1986
2175
  @for (m of modes; track m.value) {
1987
2176
  <button
@@ -1998,7 +2187,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
1998
2187
 
1999
2188
  <!-- Base color -->
2000
2189
  <div class="space-y-1.5">
2001
- <span class="text-xs font-medium">Base color</span>
2190
+ <span class="text-xs font-medium">{{ baseColorText() }}</span>
2002
2191
  <div class="grid grid-cols-9 gap-2">
2003
2192
  @for (b of bases; track b.value) {
2004
2193
  <button
@@ -2016,7 +2205,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
2016
2205
 
2017
2206
  <!-- Accent -->
2018
2207
  <div class="space-y-1.5">
2019
- <span class="text-xs font-medium">Accent</span>
2208
+ <span class="text-xs font-medium">{{ accentText() }}</span>
2020
2209
  <div class="grid grid-cols-6 gap-2">
2021
2210
  @for (a of accents; track a.value) {
2022
2211
  <button
@@ -2034,7 +2223,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
2034
2223
 
2035
2224
  <!-- Radius -->
2036
2225
  <div class="space-y-1.5">
2037
- <span class="text-xs font-medium">Radius</span>
2226
+ <span class="text-xs font-medium">{{ radiusText() }}</span>
2038
2227
  <div class="grid grid-cols-6 gap-2">
2039
2228
  @for (r of radii; track r) {
2040
2229
  <button
@@ -2051,7 +2240,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
2051
2240
 
2052
2241
  <!-- Input style -->
2053
2242
  <div class="space-y-1.5">
2054
- <span class="text-xs font-medium">Input style</span>
2243
+ <span class="text-xs font-medium">{{ inputStyleText() }}</span>
2055
2244
  <div class="grid grid-cols-3 gap-2">
2056
2245
  @for (i of inputStyles; track i.value) {
2057
2246
  <button
@@ -2068,7 +2257,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
2068
2257
 
2069
2258
  <!-- Body font -->
2070
2259
  <div class="space-y-1.5">
2071
- <span class="text-xs font-medium">Body font</span>
2260
+ <span class="text-xs font-medium">{{ bodyFontText() }}</span>
2072
2261
  <div class="grid grid-cols-3 gap-2">
2073
2262
  @for (f of fonts; track f.value) {
2074
2263
  <button
@@ -2086,7 +2275,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
2086
2275
 
2087
2276
  <!-- Heading font -->
2088
2277
  <div class="space-y-1.5">
2089
- <span class="text-xs font-medium">Heading font</span>
2278
+ <span class="text-xs font-medium">{{ headingFontText() }}</span>
2090
2279
  <div class="grid grid-cols-3 gap-2">
2091
2280
  @for (f of fonts; track f.value) {
2092
2281
  <button
@@ -2104,7 +2293,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
2104
2293
 
2105
2294
  <!-- Shadow -->
2106
2295
  <div class="space-y-1.5">
2107
- <span class="text-xs font-medium">Shadow</span>
2296
+ <span class="text-xs font-medium">{{ shadowText() }}</span>
2108
2297
  <div class="grid grid-cols-5 gap-2">
2109
2298
  @for (s of shadows; track s.value) {
2110
2299
  <button
@@ -2122,7 +2311,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
2122
2311
  <!-- Spacing + Tracking -->
2123
2312
  <div class="grid grid-cols-2 gap-4">
2124
2313
  <div class="space-y-1.5">
2125
- <span class="text-xs font-medium">Spacing</span>
2314
+ <span class="text-xs font-medium">{{ spacingText() }}</span>
2126
2315
  <div class="grid grid-cols-3 gap-1.5">
2127
2316
  @for (s of spacings; track s.value) {
2128
2317
  <button
@@ -2137,7 +2326,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
2137
2326
  </div>
2138
2327
  </div>
2139
2328
  <div class="space-y-1.5">
2140
- <span class="text-xs font-medium">Tracking</span>
2329
+ <span class="text-xs font-medium">{{ trackingText() }}</span>
2141
2330
  <div class="grid grid-cols-3 gap-1.5">
2142
2331
  @for (t of trackings; track t.value) {
2143
2332
  <button
@@ -7619,6 +7808,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
7619
7808
 
7620
7809
  const SIZES$1 = { sm: 'text-sm', default: 'text-base', lg: 'text-2xl' };
7621
7810
  const COMPARE_SIZES = { sm: 'text-xs', default: 'text-sm', lg: 'text-base' };
7811
+ /** Two fraction digits ("1,234.50") — matches the pre-locale rendering in `en-US`. */
7812
+ const DEFAULT_NUMBER_FORMAT$1 = {
7813
+ minimumFractionDigits: 2,
7814
+ maximumFractionDigits: 2,
7815
+ };
7622
7816
  /** A price display with optional compare-at (strikethrough) and a discount badge. */
7623
7817
  class BuiPrice {
7624
7818
  /** Current price amount to display. */
@@ -7637,6 +7831,18 @@ class BuiPrice {
7637
7831
  showDiscount = input(true, /* @ts-ignore */
7638
7832
  ...(ngDevMode ? [{ debugName: "showDiscount" }] : /* istanbul ignore next */ []));
7639
7833
  userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : /* istanbul ignore next */ {}), alias: 'class' });
7834
+ /** BCP 47 locale for number formatting. Defaults to the app's `LOCALE_ID`. */
7835
+ locale = input(/* @ts-ignore */
7836
+ ...(ngDevMode ? [undefined, { debugName: "locale" }] : /* istanbul ignore next */ []));
7837
+ /**
7838
+ * `Intl.NumberFormat` options for the amounts. Replaces the default wholesale — pass
7839
+ * `{ style: 'currency', currency: 'EUR' }` to let ICU place the symbol itself.
7840
+ */
7841
+ numberFormat = input(DEFAULT_NUMBER_FORMAT$1, /* @ts-ignore */
7842
+ ...(ngDevMode ? [{ debugName: "numberFormat" }] : /* istanbul ignore next */ []));
7843
+ resolvedLocale = buiLocale(this.locale);
7844
+ formatter = computed(() => new Intl.NumberFormat(this.resolvedLocale(), this.numberFormat()), /* @ts-ignore */
7845
+ ...(ngDevMode ? [{ debugName: "formatter" }] : /* istanbul ignore next */ []));
7640
7846
  onSale = computed(() => {
7641
7847
  const compareAt = this.compareAt();
7642
7848
  return compareAt !== null && compareAt > this.amount();
@@ -7656,11 +7862,10 @@ class BuiPrice {
7656
7862
  computedClass = computed(() => cn('inline-flex items-baseline gap-2 font-medium tabular-nums', this.userClass()), /* @ts-ignore */
7657
7863
  ...(ngDevMode ? [{ debugName: "computedClass" }] : /* istanbul ignore next */ []));
7658
7864
  format(value) {
7659
- return (this.currency() +
7660
- value.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 }));
7865
+ return this.currency() + this.formatter().format(value);
7661
7866
  }
7662
7867
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiPrice, deps: [], target: i0.ɵɵFactoryTarget.Component });
7663
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: BuiPrice, isStandalone: true, selector: "bui-price", inputs: { amount: { classPropertyName: "amount", publicName: "amount", isSignal: true, isRequired: false, transformFunction: null }, compareAt: { classPropertyName: "compareAt", publicName: "compareAt", isSignal: true, isRequired: false, transformFunction: null }, currency: { classPropertyName: "currency", publicName: "currency", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, showDiscount: { classPropertyName: "showDiscount", publicName: "showDiscount", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "data-slot": "price" }, properties: { "class": "computedClass()" } }, ngImport: i0, template: `
7868
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: BuiPrice, isStandalone: true, selector: "bui-price", inputs: { amount: { classPropertyName: "amount", publicName: "amount", isSignal: true, isRequired: false, transformFunction: null }, compareAt: { classPropertyName: "compareAt", publicName: "compareAt", isSignal: true, isRequired: false, transformFunction: null }, currency: { classPropertyName: "currency", publicName: "currency", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, showDiscount: { classPropertyName: "showDiscount", publicName: "showDiscount", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, numberFormat: { classPropertyName: "numberFormat", publicName: "numberFormat", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "data-slot": "price" }, properties: { "class": "computedClass()" } }, ngImport: i0, template: `
7664
7869
  <span [class]="currentClass()">{{ format(amount()) }}</span>
7665
7870
  @if (onSale()) {
7666
7871
  <s [class]="compareClass()"
@@ -7697,7 +7902,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
7697
7902
  }
7698
7903
  `,
7699
7904
  }]
7700
- }], propDecorators: { amount: [{ type: i0.Input, args: [{ isSignal: true, alias: "amount", required: false }] }], compareAt: [{ type: i0.Input, args: [{ isSignal: true, alias: "compareAt", required: false }] }], currency: [{ type: i0.Input, args: [{ isSignal: true, alias: "currency", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], showDiscount: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDiscount", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
7905
+ }], propDecorators: { amount: [{ type: i0.Input, args: [{ isSignal: true, alias: "amount", required: false }] }], compareAt: [{ type: i0.Input, args: [{ isSignal: true, alias: "compareAt", required: false }] }], currency: [{ type: i0.Input, args: [{ isSignal: true, alias: "currency", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], showDiscount: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDiscount", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], numberFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "numberFormat", required: false }] }] } });
7701
7906
 
7702
7907
  const DIRECTIONS = { col: 'flex-col', row: 'flex-row' };
7703
7908
  const GAPS$1 = {
@@ -9172,7 +9377,11 @@ class BuiProductCard {
9172
9377
  /** Accessible label override for the wishlist toggle button. */
9173
9378
  wishlistLabel = input(/* @ts-ignore */
9174
9379
  ...(ngDevMode ? [undefined, { debugName: "wishlistLabel" }] : /* istanbul ignore next */ []));
9380
+ /** Text of the default add-to-cart button. Falls back to `provideBuiLabels`. */
9381
+ addToCartLabel = input(/* @ts-ignore */
9382
+ ...(ngDevMode ? [undefined, { debugName: "addToCartLabel" }] : /* istanbul ignore next */ []));
9175
9383
  wishlistText = buiLabel('productCardWishlist', this.wishlistLabel);
9384
+ addToCartText = buiLabel('productCardAddToCart', this.addToCartLabel);
9176
9385
  wished = signal(false, /* @ts-ignore */
9177
9386
  ...(ngDevMode ? [{ debugName: "wished" }] : /* istanbul ignore next */ []));
9178
9387
  alt = computed(() => this.imageAlt() || this.title(), /* @ts-ignore */
@@ -9191,7 +9400,7 @@ class BuiProductCard {
9191
9400
  computedClass = computed(() => cn('group flex flex-col overflow-hidden rounded-xl border bg-card text-card-foreground shadow-sm', this.userClass()), /* @ts-ignore */
9192
9401
  ...(ngDevMode ? [{ debugName: "computedClass" }] : /* istanbul ignore next */ []));
9193
9402
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiProductCard, deps: [], target: i0.ɵɵFactoryTarget.Component });
9194
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: BuiProductCard, isStandalone: true, selector: "bui-product-card", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, href: { classPropertyName: "href", publicName: "href", isSignal: true, isRequired: false, transformFunction: null }, image: { classPropertyName: "image", publicName: "image", isSignal: true, isRequired: false, transformFunction: null }, imageAlt: { classPropertyName: "imageAlt", publicName: "imageAlt", isSignal: true, isRequired: false, transformFunction: null }, price: { classPropertyName: "price", publicName: "price", isSignal: true, isRequired: false, transformFunction: null }, compareAt: { classPropertyName: "compareAt", publicName: "compareAt", isSignal: true, isRequired: false, transformFunction: null }, currency: { classPropertyName: "currency", publicName: "currency", isSignal: true, isRequired: false, transformFunction: null }, badge: { classPropertyName: "badge", publicName: "badge", isSignal: true, isRequired: false, transformFunction: null }, category: { classPropertyName: "category", publicName: "category", isSignal: true, isRequired: false, transformFunction: null }, rating: { classPropertyName: "rating", publicName: "rating", isSignal: true, isRequired: false, transformFunction: null }, reviews: { classPropertyName: "reviews", publicName: "reviews", isSignal: true, isRequired: false, transformFunction: null }, wishlist: { classPropertyName: "wishlist", publicName: "wishlist", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, wishlistLabel: { classPropertyName: "wishlistLabel", publicName: "wishlistLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "data-slot": "product-card" }, properties: { "class": "computedClass()" } }, ngImport: i0, template: `
9403
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: BuiProductCard, isStandalone: true, selector: "bui-product-card", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, href: { classPropertyName: "href", publicName: "href", isSignal: true, isRequired: false, transformFunction: null }, image: { classPropertyName: "image", publicName: "image", isSignal: true, isRequired: false, transformFunction: null }, imageAlt: { classPropertyName: "imageAlt", publicName: "imageAlt", isSignal: true, isRequired: false, transformFunction: null }, price: { classPropertyName: "price", publicName: "price", isSignal: true, isRequired: false, transformFunction: null }, compareAt: { classPropertyName: "compareAt", publicName: "compareAt", isSignal: true, isRequired: false, transformFunction: null }, currency: { classPropertyName: "currency", publicName: "currency", isSignal: true, isRequired: false, transformFunction: null }, badge: { classPropertyName: "badge", publicName: "badge", isSignal: true, isRequired: false, transformFunction: null }, category: { classPropertyName: "category", publicName: "category", isSignal: true, isRequired: false, transformFunction: null }, rating: { classPropertyName: "rating", publicName: "rating", isSignal: true, isRequired: false, transformFunction: null }, reviews: { classPropertyName: "reviews", publicName: "reviews", isSignal: true, isRequired: false, transformFunction: null }, wishlist: { classPropertyName: "wishlist", publicName: "wishlist", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, wishlistLabel: { classPropertyName: "wishlistLabel", publicName: "wishlistLabel", isSignal: true, isRequired: false, transformFunction: null }, addToCartLabel: { classPropertyName: "addToCartLabel", publicName: "addToCartLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "data-slot": "product-card" }, properties: { "class": "computedClass()" } }, ngImport: i0, template: `
9195
9404
  <div class="relative aspect-square overflow-hidden bg-muted">
9196
9405
  <img
9197
9406
  [src]="image()"
@@ -9261,11 +9470,11 @@ class BuiProductCard {
9261
9470
  }
9262
9471
  <div class="mt-3">
9263
9472
  <ng-content>
9264
- <button buiButton class="w-full">Add to cart</button>
9473
+ <button buiButton class="w-full">{{ addToCartText() }}</button>
9265
9474
  </ng-content>
9266
9475
  </div>
9267
9476
  </div>
9268
- `, isInline: true, dependencies: [{ kind: "directive", type: BuiBadge, selector: "[buiBadge]", inputs: ["variant", "tone", "size", "class"] }, { kind: "directive", type: BuiButton, selector: "button[buiButton], a[buiButton]", inputs: ["variant", "size", "class"] }, { kind: "component", type: BuiPrice, selector: "bui-price", inputs: ["amount", "compareAt", "currency", "size", "showDiscount", "class"] }] });
9477
+ `, isInline: true, dependencies: [{ kind: "directive", type: BuiBadge, selector: "[buiBadge]", inputs: ["variant", "tone", "size", "class"] }, { kind: "directive", type: BuiButton, selector: "button[buiButton], a[buiButton]", inputs: ["variant", "size", "class"] }, { kind: "component", type: BuiPrice, selector: "bui-price", inputs: ["amount", "compareAt", "currency", "size", "showDiscount", "class", "locale", "numberFormat"] }] });
9269
9478
  }
9270
9479
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiProductCard, decorators: [{
9271
9480
  type: Component,
@@ -9343,13 +9552,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
9343
9552
  }
9344
9553
  <div class="mt-3">
9345
9554
  <ng-content>
9346
- <button buiButton class="w-full">Add to cart</button>
9555
+ <button buiButton class="w-full">{{ addToCartText() }}</button>
9347
9556
  </ng-content>
9348
9557
  </div>
9349
9558
  </div>
9350
9559
  `,
9351
9560
  }]
9352
- }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], href: [{ type: i0.Input, args: [{ isSignal: true, alias: "href", required: false }] }], image: [{ type: i0.Input, args: [{ isSignal: true, alias: "image", required: false }] }], imageAlt: [{ type: i0.Input, args: [{ isSignal: true, alias: "imageAlt", required: false }] }], price: [{ type: i0.Input, args: [{ isSignal: true, alias: "price", required: false }] }], compareAt: [{ type: i0.Input, args: [{ isSignal: true, alias: "compareAt", required: false }] }], currency: [{ type: i0.Input, args: [{ isSignal: true, alias: "currency", required: false }] }], badge: [{ type: i0.Input, args: [{ isSignal: true, alias: "badge", required: false }] }], category: [{ type: i0.Input, args: [{ isSignal: true, alias: "category", required: false }] }], rating: [{ type: i0.Input, args: [{ isSignal: true, alias: "rating", required: false }] }], reviews: [{ type: i0.Input, args: [{ isSignal: true, alias: "reviews", required: false }] }], wishlist: [{ type: i0.Input, args: [{ isSignal: true, alias: "wishlist", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], wishlistLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "wishlistLabel", required: false }] }] } });
9561
+ }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], href: [{ type: i0.Input, args: [{ isSignal: true, alias: "href", required: false }] }], image: [{ type: i0.Input, args: [{ isSignal: true, alias: "image", required: false }] }], imageAlt: [{ type: i0.Input, args: [{ isSignal: true, alias: "imageAlt", required: false }] }], price: [{ type: i0.Input, args: [{ isSignal: true, alias: "price", required: false }] }], compareAt: [{ type: i0.Input, args: [{ isSignal: true, alias: "compareAt", required: false }] }], currency: [{ type: i0.Input, args: [{ isSignal: true, alias: "currency", required: false }] }], badge: [{ type: i0.Input, args: [{ isSignal: true, alias: "badge", required: false }] }], category: [{ type: i0.Input, args: [{ isSignal: true, alias: "category", required: false }] }], rating: [{ type: i0.Input, args: [{ isSignal: true, alias: "rating", required: false }] }], reviews: [{ type: i0.Input, args: [{ isSignal: true, alias: "reviews", required: false }] }], wishlist: [{ type: i0.Input, args: [{ isSignal: true, alias: "wishlist", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], wishlistLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "wishlistLabel", required: false }] }], addToCartLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "addToCartLabel", required: false }] }] } });
9353
9562
 
9354
9563
  /**
9355
9564
  * Types and deletes a cycling list of words. The animated text is `aria-hidden`; an sr-only
@@ -10064,10 +10273,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
10064
10273
  }]
10065
10274
  }], ctorParameters: () => [], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }] } });
10066
10275
 
10276
+ /** A midday reference date; only the hour/minute matter for formatting. */
10277
+ function timeOf(hour, minute = 0) {
10278
+ return new Date(2000, 0, 1, hour, minute);
10279
+ }
10067
10280
  // eslint-disable-next-line @typescript-eslint/no-empty-function
10068
10281
  const noop$b = () => { };
10069
10282
  const SELECT_CLASS = 'h-9 rounded-md border border-input bg-background px-2 text-sm shadow-xs outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50';
10070
- /** A styled time field: a native `<input type="time">`, or hour/minute selects in `select` mode. */
10283
+ /**
10284
+ * A styled time field: a native `<input type="time">`, or hour/minute selects in `select` mode.
10285
+ * The value is always 24-hour `HH:mm`, whatever the clock shown.
10286
+ *
10287
+ * **Locale:** `select` mode follows `locale` — it renders the locale's clock (1–12 with AM/PM in
10288
+ * `en-US`, 0–23 in `fr`) and its digits. `input` mode cannot: the browser renders native time
10289
+ * inputs in *its own* UI language, and neither `lang` nor any other attribute overrides that.
10290
+ * Use `mode="select"` when the clock must follow the app's locale rather than the user's browser.
10291
+ */
10071
10292
  class BuiTimeField {
10072
10293
  /** Selected time as `HH:mm`. Two-way bindable with `[(value)]`. */
10073
10294
  value = model('', /* @ts-ignore */
@@ -10100,6 +10321,43 @@ class BuiTimeField {
10100
10321
  ariaLabel = input('', /* @ts-ignore */
10101
10322
  ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
10102
10323
  userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : /* istanbul ignore next */ {}), alias: 'class' });
10324
+ /**
10325
+ * BCP 47 locale driving `select` mode's clock and digits. Defaults to the app's `LOCALE_ID`.
10326
+ * It has no effect in `input` mode — see the class docs.
10327
+ */
10328
+ locale = input(/* @ts-ignore */
10329
+ ...(ngDevMode ? [undefined, { debugName: "locale" }] : /* istanbul ignore next */ []));
10330
+ /** Force a clock instead of the locale's own — `h12` gives 1–12 with AM/PM, `h23` gives 0–23. */
10331
+ hourCycle = input(/* @ts-ignore */
10332
+ ...(ngDevMode ? [undefined, { debugName: "hourCycle" }] : /* istanbul ignore next */ []));
10333
+ resolvedLocale = buiLocale(this.locale);
10334
+ timeText = buiLabel('timeField', signal(undefined));
10335
+ hoursText = buiLabel('timeFieldHours', signal(undefined));
10336
+ minutesText = buiLabel('timeFieldMinutes', signal(undefined));
10337
+ hoursAria = computed(() => `${this.ariaLabel() || this.timeText()} ${this.hoursText()}`, /* @ts-ignore */
10338
+ ...(ngDevMode ? [{ debugName: "hoursAria" }] : /* istanbul ignore next */ []));
10339
+ minutesAria = computed(() => `${this.ariaLabel() || this.timeText()} ${this.minutesText()}`, /* @ts-ignore */
10340
+ ...(ngDevMode ? [{ debugName: "minutesAria" }] : /* istanbul ignore next */ []));
10341
+ /** The locale's clock unless the caller pinned one. */
10342
+ resolvedHourCycle = computed(() => {
10343
+ const pinned = this.hourCycle();
10344
+ if (pinned !== undefined) {
10345
+ return pinned;
10346
+ }
10347
+ const resolved = new Intl.DateTimeFormat(this.resolvedLocale(), {
10348
+ hour: 'numeric',
10349
+ }).resolvedOptions().hourCycle;
10350
+ return resolved ?? 'h23';
10351
+ }, /* @ts-ignore */
10352
+ ...(ngDevMode ? [{ debugName: "resolvedHourCycle" }] : /* istanbul ignore next */ []));
10353
+ usesDayPeriod = computed(() => this.resolvedHourCycle() === 'h11' || this.resolvedHourCycle() === 'h12', /* @ts-ignore */
10354
+ ...(ngDevMode ? [{ debugName: "usesDayPeriod" }] : /* istanbul ignore next */ []));
10355
+ /** Two digits in the locale's own numbering system — `padStart` would mix `0` with `٠`. */
10356
+ paddedNumber = computed(() => new Intl.NumberFormat(this.resolvedLocale(), {
10357
+ minimumIntegerDigits: 2,
10358
+ useGrouping: false,
10359
+ }), /* @ts-ignore */
10360
+ ...(ngDevMode ? [{ debugName: "paddedNumber" }] : /* istanbul ignore next */ []));
10103
10361
  onChange = noop$b;
10104
10362
  onTouched = noop$b;
10105
10363
  selectClass = SELECT_CLASS;
@@ -10107,15 +10365,41 @@ class BuiTimeField {
10107
10365
  ...(ngDevMode ? [{ debugName: "hourPart" }] : /* istanbul ignore next */ []));
10108
10366
  minutePart = computed(() => (this.value().split(':', 2)[1] || '00').padStart(2, '0'), /* @ts-ignore */
10109
10367
  ...(ngDevMode ? [{ debugName: "minutePart" }] : /* istanbul ignore next */ []));
10110
- hours = computed(() => Array.from({ length: 24 }, (_, hour) => String(hour).padStart(2, '0')), /* @ts-ignore */
10368
+ hours = computed(() => {
10369
+ // The value stays 24-hour `HH` whatever the clock: it is the data, not the display.
10370
+ const hourCycle = this.resolvedHourCycle();
10371
+ const label = this.usesDayPeriod()
10372
+ ? this.dayPeriodLabel(hourCycle)
10373
+ : (hour) => this.paddedNumber().format(hour);
10374
+ return Array.from({ length: 24 }, (_, hour) => ({
10375
+ value: String(hour).padStart(2, '0'),
10376
+ label: label(hour),
10377
+ }));
10378
+ }, /* @ts-ignore */
10111
10379
  ...(ngDevMode ? [{ debugName: "hours" }] : /* istanbul ignore next */ []));
10112
10380
  minutes = computed(() => {
10113
10381
  const step = Math.max(1, this.minuteStep());
10114
- return Array.from({ length: Math.ceil(60 / step) }, (_, index) => String(index * step).padStart(2, '0'));
10382
+ const format = this.paddedNumber();
10383
+ return Array.from({ length: Math.ceil(60 / step) }, (_, index) => {
10384
+ const minute = index * step;
10385
+ return { value: String(minute).padStart(2, '0'), label: format.format(minute) };
10386
+ });
10115
10387
  }, /* @ts-ignore */
10116
10388
  ...(ngDevMode ? [{ debugName: "minutes" }] : /* istanbul ignore next */ []));
10117
10389
  computedClass = computed(() => cn('inline-block', this.userClass()), /* @ts-ignore */
10118
10390
  ...(ngDevMode ? [{ debugName: "computedClass" }] : /* istanbul ignore next */ []));
10391
+ /**
10392
+ * "1 PM" / "١ م". Built from parts rather than the plain format so the locale's own literal
10393
+ * (French renders `13 h`) never leaks into a cell that already has its own `:` separator.
10394
+ */
10395
+ dayPeriodLabel(hourCycle) {
10396
+ const format = new Intl.DateTimeFormat(this.resolvedLocale(), { hour: 'numeric', hourCycle });
10397
+ return (hour) => format
10398
+ .formatToParts(timeOf(hour))
10399
+ .filter((part) => part.type !== 'literal')
10400
+ .map((part) => part.value)
10401
+ .join(' ');
10402
+ }
10119
10403
  onInput(event) {
10120
10404
  this.value.set(event.target.value);
10121
10405
  this.onChange(this.value());
@@ -10141,7 +10425,7 @@ class BuiTimeField {
10141
10425
  this.disabled.set(isDisabled);
10142
10426
  }
10143
10427
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiTimeField, deps: [], target: i0.ɵɵFactoryTarget.Component });
10144
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: BuiTimeField, isStandalone: true, selector: "bui-time-field", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, seconds: { classPropertyName: "seconds", publicName: "seconds", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, minuteStep: { classPropertyName: "minuteStep", publicName: "minuteStep", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", disabled: "disabledChange" }, host: { attributes: { "data-slot": "time-field" }, listeners: { "focusout": "onTouched()" }, properties: { "class": "computedClass()" } }, providers: [
10428
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: BuiTimeField, isStandalone: true, selector: "bui-time-field", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, seconds: { classPropertyName: "seconds", publicName: "seconds", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, minuteStep: { classPropertyName: "minuteStep", publicName: "minuteStep", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, hourCycle: { classPropertyName: "hourCycle", publicName: "hourCycle", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", disabled: "disabledChange" }, host: { attributes: { "data-slot": "time-field" }, listeners: { "focusout": "onTouched()" }, properties: { "class": "computedClass()" } }, providers: [
10145
10429
  { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => BuiTimeField), multi: true },
10146
10430
  ], ngImport: i0, template: `
10147
10431
  @if (mode() === 'select') {
@@ -10150,11 +10434,11 @@ class BuiTimeField {
10150
10434
  [class]="selectClass"
10151
10435
  [value]="hourPart()"
10152
10436
  [disabled]="disabled()"
10153
- [attr.aria-label]="(ariaLabel() || 'Time') + ' hours'"
10437
+ [attr.aria-label]="hoursAria()"
10154
10438
  (change)="setHour($event)"
10155
10439
  >
10156
- @for (hour of hours(); track hour) {
10157
- <option [value]="hour">{{ hour }}</option>
10440
+ @for (hour of hours(); track hour.value) {
10441
+ <option [value]="hour.value">{{ hour.label }}</option>
10158
10442
  }
10159
10443
  </select>
10160
10444
  <span aria-hidden="true" class="text-muted-foreground">:</span>
@@ -10162,11 +10446,11 @@ class BuiTimeField {
10162
10446
  [class]="selectClass"
10163
10447
  [value]="minutePart()"
10164
10448
  [disabled]="disabled()"
10165
- [attr.aria-label]="(ariaLabel() || 'Time') + ' minutes'"
10449
+ [attr.aria-label]="minutesAria()"
10166
10450
  (change)="setMinute($event)"
10167
10451
  >
10168
- @for (minute of minutes(); track minute) {
10169
- <option [value]="minute">{{ minute }}</option>
10452
+ @for (minute of minutes(); track minute.value) {
10453
+ <option [value]="minute.value">{{ minute.label }}</option>
10170
10454
  }
10171
10455
  </select>
10172
10456
  </div>
@@ -10206,11 +10490,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
10206
10490
  [class]="selectClass"
10207
10491
  [value]="hourPart()"
10208
10492
  [disabled]="disabled()"
10209
- [attr.aria-label]="(ariaLabel() || 'Time') + ' hours'"
10493
+ [attr.aria-label]="hoursAria()"
10210
10494
  (change)="setHour($event)"
10211
10495
  >
10212
- @for (hour of hours(); track hour) {
10213
- <option [value]="hour">{{ hour }}</option>
10496
+ @for (hour of hours(); track hour.value) {
10497
+ <option [value]="hour.value">{{ hour.label }}</option>
10214
10498
  }
10215
10499
  </select>
10216
10500
  <span aria-hidden="true" class="text-muted-foreground">:</span>
@@ -10218,11 +10502,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
10218
10502
  [class]="selectClass"
10219
10503
  [value]="minutePart()"
10220
10504
  [disabled]="disabled()"
10221
- [attr.aria-label]="(ariaLabel() || 'Time') + ' minutes'"
10505
+ [attr.aria-label]="minutesAria()"
10222
10506
  (change)="setMinute($event)"
10223
10507
  >
10224
- @for (minute of minutes(); track minute) {
10225
- <option [value]="minute">{{ minute }}</option>
10508
+ @for (minute of minutes(); track minute.value) {
10509
+ <option [value]="minute.value">{{ minute.label }}</option>
10226
10510
  }
10227
10511
  </select>
10228
10512
  </div>
@@ -10243,7 +10527,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
10243
10527
  }
10244
10528
  `,
10245
10529
  }]
10246
- }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], seconds: [{ type: i0.Input, args: [{ isSignal: true, alias: "seconds", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], minuteStep: [{ type: i0.Input, args: [{ isSignal: true, alias: "minuteStep", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
10530
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], seconds: [{ type: i0.Input, args: [{ isSignal: true, alias: "seconds", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], minuteStep: [{ type: i0.Input, args: [{ isSignal: true, alias: "minuteStep", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], hourCycle: [{ type: i0.Input, args: [{ isSignal: true, alias: "hourCycle", required: false }] }] } });
10247
10531
 
10248
10532
  /** A group of toggle buttons (single or multiple selection). Use `button[buiToggleGroupItem]`. */
10249
10533
  class BuiToggleGroup {
@@ -11286,12 +11570,20 @@ class BuiToolCall {
11286
11570
  open = model(false, /* @ts-ignore */
11287
11571
  ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
11288
11572
  userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : /* istanbul ignore next */ {}), alias: 'class' });
11573
+ /** Heading of the arguments panel. Falls back to `provideBuiLabels`. */
11574
+ argumentsLabel = input(/* @ts-ignore */
11575
+ ...(ngDevMode ? [undefined, { debugName: "argumentsLabel" }] : /* istanbul ignore next */ []));
11576
+ /** Heading of the result panel. Falls back to `provideBuiLabels`. */
11577
+ resultLabel = input(/* @ts-ignore */
11578
+ ...(ngDevMode ? [undefined, { debugName: "resultLabel" }] : /* istanbul ignore next */ []));
11579
+ argumentsText = buiLabel('toolCallArguments', this.argumentsLabel);
11580
+ resultText = buiLabel('toolCallResult', this.resultLabel);
11289
11581
  statusClass = computed(() => STATUS[this.status()], /* @ts-ignore */
11290
11582
  ...(ngDevMode ? [{ debugName: "statusClass" }] : /* istanbul ignore next */ []));
11291
11583
  computedClass = computed(() => cn('block overflow-hidden rounded-lg border bg-card', this.userClass()), /* @ts-ignore */
11292
11584
  ...(ngDevMode ? [{ debugName: "computedClass" }] : /* istanbul ignore next */ []));
11293
11585
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiToolCall, deps: [], target: i0.ɵɵFactoryTarget.Component });
11294
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: BuiToolCall, isStandalone: true, selector: "bui-tool-call", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, status: { classPropertyName: "status", publicName: "status", isSignal: true, isRequired: false, transformFunction: null }, args: { classPropertyName: "args", publicName: "args", isSignal: true, isRequired: false, transformFunction: null }, result: { classPropertyName: "result", publicName: "result", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange" }, host: { attributes: { "data-slot": "tool-call" }, properties: { "class": "computedClass()" } }, ngImport: i0, template: `
11586
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: BuiToolCall, isStandalone: true, selector: "bui-tool-call", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, status: { classPropertyName: "status", publicName: "status", isSignal: true, isRequired: false, transformFunction: null }, args: { classPropertyName: "args", publicName: "args", isSignal: true, isRequired: false, transformFunction: null }, result: { classPropertyName: "result", publicName: "result", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, argumentsLabel: { classPropertyName: "argumentsLabel", publicName: "argumentsLabel", isSignal: true, isRequired: false, transformFunction: null }, resultLabel: { classPropertyName: "resultLabel", publicName: "resultLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange" }, host: { attributes: { "data-slot": "tool-call" }, properties: { "class": "computedClass()" } }, ngImport: i0, template: `
11295
11587
  <button
11296
11588
  type="button"
11297
11589
  class="flex w-full items-center gap-2 px-3 py-2 text-left"
@@ -11319,13 +11611,13 @@ class BuiToolCall {
11319
11611
  <div class="space-y-2 border-t border-border px-3 py-2">
11320
11612
  @if (args()) {
11321
11613
  <div>
11322
- <p class="text-xs font-medium text-muted-foreground">Arguments</p>
11614
+ <p class="text-xs font-medium text-muted-foreground">{{ argumentsText() }}</p>
11323
11615
  <pre class="mt-1 overflow-x-auto rounded bg-muted p-2 text-xs">{{ args() }}</pre>
11324
11616
  </div>
11325
11617
  }
11326
11618
  @if (result()) {
11327
11619
  <div>
11328
- <p class="text-xs font-medium text-muted-foreground">Result</p>
11620
+ <p class="text-xs font-medium text-muted-foreground">{{ resultText() }}</p>
11329
11621
  <pre class="mt-1 overflow-x-auto rounded bg-muted p-2 text-xs">{{ result() }}</pre>
11330
11622
  </div>
11331
11623
  }
@@ -11366,13 +11658,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
11366
11658
  <div class="space-y-2 border-t border-border px-3 py-2">
11367
11659
  @if (args()) {
11368
11660
  <div>
11369
- <p class="text-xs font-medium text-muted-foreground">Arguments</p>
11661
+ <p class="text-xs font-medium text-muted-foreground">{{ argumentsText() }}</p>
11370
11662
  <pre class="mt-1 overflow-x-auto rounded bg-muted p-2 text-xs">{{ args() }}</pre>
11371
11663
  </div>
11372
11664
  }
11373
11665
  @if (result()) {
11374
11666
  <div>
11375
- <p class="text-xs font-medium text-muted-foreground">Result</p>
11667
+ <p class="text-xs font-medium text-muted-foreground">{{ resultText() }}</p>
11376
11668
  <pre class="mt-1 overflow-x-auto rounded bg-muted p-2 text-xs">{{ result() }}</pre>
11377
11669
  </div>
11378
11670
  }
@@ -11380,7 +11672,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
11380
11672
  }
11381
11673
  `,
11382
11674
  }]
11383
- }], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], status: [{ type: i0.Input, args: [{ isSignal: true, alias: "status", required: false }] }], args: [{ type: i0.Input, args: [{ isSignal: true, alias: "args", required: false }] }], result: [{ type: i0.Input, args: [{ isSignal: true, alias: "result", required: false }] }], open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
11675
+ }], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], status: [{ type: i0.Input, args: [{ isSignal: true, alias: "status", required: false }] }], args: [{ type: i0.Input, args: [{ isSignal: true, alias: "args", required: false }] }], result: [{ type: i0.Input, args: [{ isSignal: true, alias: "result", required: false }] }], open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], argumentsLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "argumentsLabel", required: false }] }], resultLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "resultLabel", required: false }] }] } });
11384
11676
 
11385
11677
  /** A scrollable conversation log (`role="log"`). Use `bui-chat-message` for bubbles. */
11386
11678
  class BuiChat {
@@ -12437,7 +12729,42 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
12437
12729
 
12438
12730
  // eslint-disable-next-line @typescript-eslint/no-empty-function
12439
12731
  const noop$5 = () => { };
12440
- const WEEKDAYS = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];
12732
+ /** Pattern of the month caption ("July 2026") matches the pre-locale rendering in `en-US`. */
12733
+ const DEFAULT_MONTH_FORMAT = { month: 'long', year: 'numeric' };
12734
+ /** 2000-01-02 was a Sunday, so `+ day` lands on the weekday with index `day`. */
12735
+ function dateOfWeekday(day) {
12736
+ return new Date(2000, 0, 2 + day);
12737
+ }
12738
+ const WEEK_MS = 7 * 86_400_000;
12739
+ /** The `firstDay`-aligned week that a UTC date falls in. */
12740
+ function startOfWeek(date, firstDay) {
12741
+ const offset = (((date.getUTCDay() - firstDay) % 7) + 7) % 7;
12742
+ const start = new Date(date);
12743
+ start.setUTCDate(date.getUTCDate() - offset);
12744
+ return start;
12745
+ }
12746
+ /**
12747
+ * Week-of-year under the locale's own rule rather than a hardcoded ISO-8601.
12748
+ *
12749
+ * Week 1 is the first week holding at least `minimalDays` days of January, which is the same as
12750
+ * saying it is the week containing January `minimalDays` — that yields the ISO rule at
12751
+ * `minimalDays: 4` (week of Jan 4) and the US rule at `minimalDays: 1` (week of Jan 1).
12752
+ */
12753
+ function weekOfYear(date, firstDay, minimalDays) {
12754
+ const start = startOfWeek(date, firstDay);
12755
+ const weekOneOf = (year) => startOfWeek(new Date(Date.UTC(year, 0, minimalDays)), firstDay);
12756
+ const year = date.getUTCFullYear();
12757
+ // A late-December week can already belong to next year's week 1, and an early-January one to
12758
+ // last year's final week.
12759
+ if (start.getTime() >= weekOneOf(year + 1).getTime()) {
12760
+ return 1;
12761
+ }
12762
+ let weekOne = weekOneOf(year);
12763
+ if (start.getTime() < weekOne.getTime()) {
12764
+ weekOne = weekOneOf(year - 1);
12765
+ }
12766
+ return 1 + Math.round((start.getTime() - weekOne.getTime()) / WEEK_MS);
12767
+ }
12441
12768
  function pad$1(value) {
12442
12769
  return String(value).padStart(2, '0');
12443
12770
  }
@@ -12464,9 +12791,12 @@ class BuiCalendar {
12464
12791
  /** Number of month grids to render side by side. */
12465
12792
  months = input(1, /* @ts-ignore */
12466
12793
  ...(ngDevMode ? [{ debugName: "months" }] : /* istanbul ignore next */ []));
12467
- /** First day of the week (0 = Sunday). */
12468
- weekStart = input(0, /* @ts-ignore */
12469
- ...(ngDevMode ? [{ debugName: "weekStart" }] : /* istanbul ignore next */ []));
12794
+ /**
12795
+ * First day of the week (0 = Sunday). Defaults to the locale's own convention — Sunday in
12796
+ * `en-US`, Monday in `fr`, Saturday in `ar-EG`.
12797
+ */
12798
+ weekStart = input(/* @ts-ignore */
12799
+ ...(ngDevMode ? [undefined, { debugName: "weekStart" }] : /* istanbul ignore next */ []));
12470
12800
  /** Earliest selectable date (`yyyy-mm-dd`). */
12471
12801
  minDate = input('', /* @ts-ignore */
12472
12802
  ...(ngDevMode ? [{ debugName: "minDate" }] : /* istanbul ignore next */ []));
@@ -12476,7 +12806,7 @@ class BuiCalendar {
12476
12806
  /** Specific ISO dates (yyyy-mm-dd) to disable. */
12477
12807
  disabledDates = input([], /* @ts-ignore */
12478
12808
  ...(ngDevMode ? [{ debugName: "disabledDates" }] : /* istanbul ignore next */ []));
12479
- /** Disable Saturdays and Sundays. */
12809
+ /** Disable the locale's weekend days — Saturday/Sunday in `en-US`, Friday/Saturday in `ar-EG`. */
12480
12810
  disableWeekends = input(false, /* @ts-ignore */
12481
12811
  ...(ngDevMode ? [{ debugName: "disableWeekends" }] : /* istanbul ignore next */ []));
12482
12812
  /** Show an ISO week-number column on the left. */
@@ -12492,6 +12822,24 @@ class BuiCalendar {
12492
12822
  disabled = model(false, /* @ts-ignore */
12493
12823
  ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
12494
12824
  userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : /* istanbul ignore next */ {}), alias: 'class' });
12825
+ /** BCP 47 locale used for the month captions. Defaults to the app's `LOCALE_ID`. */
12826
+ locale = input(/* @ts-ignore */
12827
+ ...(ngDevMode ? [undefined, { debugName: "locale" }] : /* istanbul ignore next */ []));
12828
+ /**
12829
+ * `Intl.DateTimeFormat` options for the month caption. Replaces the default wholesale, so
12830
+ * `{ dateStyle: 'short' }` and `{ month: 'long' }` are both valid (they cannot be mixed).
12831
+ */
12832
+ monthFormat = input(DEFAULT_MONTH_FORMAT, /* @ts-ignore */
12833
+ ...(ngDevMode ? [{ debugName: "monthFormat" }] : /* istanbul ignore next */ []));
12834
+ /** How weekday column headers are abbreviated: each locale's own `short` form by default. */
12835
+ weekdayFormat = input('short', /* @ts-ignore */
12836
+ ...(ngDevMode ? [{ debugName: "weekdayFormat" }] : /* istanbul ignore next */ []));
12837
+ /**
12838
+ * Override the weekday column headers outright — 7 entries, **Sunday first**, regardless of
12839
+ * `weekStart`. For when a locale's `Intl` abbreviation is not what your design wants.
12840
+ */
12841
+ weekdayLabels = input(/* @ts-ignore */
12842
+ ...(ngDevMode ? [undefined, { debugName: "weekdayLabels" }] : /* istanbul ignore next */ []));
12495
12843
  /** Accessible label for the previous-month button. */
12496
12844
  previousMonthLabel = input(/* @ts-ignore */
12497
12845
  ...(ngDevMode ? [undefined, { debugName: "previousMonthLabel" }] : /* istanbul ignore next */ []));
@@ -12504,33 +12852,76 @@ class BuiCalendar {
12504
12852
  /** Accessible label for the next-month button. */
12505
12853
  nextMonthLabel = input(/* @ts-ignore */
12506
12854
  ...(ngDevMode ? [undefined, { debugName: "nextMonthLabel" }] : /* istanbul ignore next */ []));
12855
+ /** Accessible label for the week-number column. */
12856
+ weekLabel = input(/* @ts-ignore */
12857
+ ...(ngDevMode ? [undefined, { debugName: "weekLabel" }] : /* istanbul ignore next */ []));
12507
12858
  previousMonthText = buiLabel('calendarPreviousMonth', this.previousMonthLabel);
12508
12859
  monthText = buiLabel('calendarMonth', this.monthSelectLabel);
12509
12860
  yearText = buiLabel('calendarYear', this.yearLabel);
12510
12861
  nextMonthText = buiLabel('calendarNextMonth', this.nextMonthLabel);
12862
+ weekText = buiLabel('calendarWeek', this.weekLabel);
12511
12863
  onChange = noop$5;
12512
12864
  onTouched = noop$5;
12513
12865
  view = signal(new Date(new Date().getFullYear(), new Date().getMonth(), 1), /* @ts-ignore */
12514
12866
  ...(ngDevMode ? [{ debugName: "view" }] : /* istanbul ignore next */ []));
12867
+ resolvedLocale = buiLocale(this.locale);
12868
+ weekInfo = buiWeekInfo(this.resolvedLocale);
12869
+ /** The locale's first day unless the caller pinned one. */
12870
+ resolvedWeekStart = computed(() => {
12871
+ const start = this.weekStart() ?? this.weekInfo().firstDay;
12872
+ return ((start % 7) + 7) % 7;
12873
+ }, /* @ts-ignore */
12874
+ ...(ngDevMode ? [{ debugName: "resolvedWeekStart" }] : /* istanbul ignore next */ []));
12515
12875
  weekdays = computed(() => {
12516
- const start = ((this.weekStart() % 7) + 7) % 7;
12517
- return [...WEEKDAYS.slice(start), ...WEEKDAYS.slice(0, start)];
12876
+ const override = this.weekdayLabels();
12877
+ const locale = this.resolvedLocale();
12878
+ const abbreviated = new Intl.DateTimeFormat(locale, { weekday: this.weekdayFormat() });
12879
+ const full = new Intl.DateTimeFormat(locale, { weekday: 'long' });
12880
+ const start = this.resolvedWeekStart();
12881
+ return Array.from({ length: 7 }, (_, index) => {
12882
+ // `override` is Sunday-first, so it is indexed by the absolute day, not the column.
12883
+ const day = (start + index) % 7;
12884
+ const date = dateOfWeekday(day);
12885
+ return {
12886
+ day,
12887
+ label: override?.[day] ?? abbreviated.format(date),
12888
+ name: full.format(date),
12889
+ };
12890
+ });
12518
12891
  }, /* @ts-ignore */
12519
12892
  ...(ngDevMode ? [{ debugName: "weekdays" }] : /* istanbul ignore next */ []));
12520
- monthLabel = computed(() => this.view().toLocaleDateString('en-US', { month: 'long', year: 'numeric' }), /* @ts-ignore */
12893
+ monthFormatter = computed(() =>
12894
+ // Pinned, not defaulted: the caption labels the grid, so it cannot name another calendar.
12895
+ new Intl.DateTimeFormat(this.resolvedLocale(), {
12896
+ ...this.monthFormat(),
12897
+ calendar: BUI_GRID_CALENDAR,
12898
+ }), /* @ts-ignore */
12899
+ ...(ngDevMode ? [{ debugName: "monthFormatter" }] : /* istanbul ignore next */ []));
12900
+ /** Day/week/year numbers follow the locale's numbering system; never group a year as "2,026". */
12901
+ numberFormatter = computed(() => new Intl.NumberFormat(this.resolvedLocale(), { useGrouping: false }), /* @ts-ignore */
12902
+ ...(ngDevMode ? [{ debugName: "numberFormatter" }] : /* istanbul ignore next */ []));
12903
+ monthLabel = computed(() => this.monthFormatter().format(this.view()), /* @ts-ignore */
12521
12904
  ...(ngDevMode ? [{ debugName: "monthLabel" }] : /* istanbul ignore next */ []));
12522
12905
  viewMonth = computed(() => this.view().getMonth(), /* @ts-ignore */
12523
12906
  ...(ngDevMode ? [{ debugName: "viewMonth" }] : /* istanbul ignore next */ []));
12524
12907
  viewYear = computed(() => this.view().getFullYear(), /* @ts-ignore */
12525
12908
  ...(ngDevMode ? [{ debugName: "viewYear" }] : /* istanbul ignore next */ []));
12526
- monthOptions = computed(() => Array.from({ length: 12 }, (_, index) => ({
12527
- value: index,
12528
- label: new Date(2000, index, 1).toLocaleDateString('en-US', { month: 'long' }),
12529
- })), /* @ts-ignore */
12909
+ monthOptions = computed(() => {
12910
+ // Month names only — the caption's `monthFormat` may carry a year, which a picker must not.
12911
+ const names = new Intl.DateTimeFormat(this.resolvedLocale(), { month: 'long' });
12912
+ return Array.from({ length: 12 }, (_, index) => ({
12913
+ value: index,
12914
+ label: names.format(new Date(2000, index, 1)),
12915
+ }));
12916
+ }, /* @ts-ignore */
12530
12917
  ...(ngDevMode ? [{ debugName: "monthOptions" }] : /* istanbul ignore next */ []));
12531
12918
  years = computed(() => {
12532
12919
  const current = this.viewYear();
12533
- return Array.from({ length: 21 }, (_, index) => current - 10 + index);
12920
+ const format = this.numberFormatter();
12921
+ return Array.from({ length: 21 }, (_, index) => {
12922
+ const value = current - 10 + index;
12923
+ return { value, label: format.format(value) };
12924
+ });
12534
12925
  }, /* @ts-ignore */
12535
12926
  ...(ngDevMode ? [{ debugName: "years" }] : /* istanbul ignore next */ []));
12536
12927
  monthGrids = computed(() => {
@@ -12539,7 +12930,7 @@ class BuiCalendar {
12539
12930
  const base = new Date(view.getFullYear(), view.getMonth() + index, 1);
12540
12931
  return {
12541
12932
  key: `${base.getFullYear()}-${base.getMonth()}`,
12542
- label: base.toLocaleDateString('en-US', { month: 'long', year: 'numeric' }),
12933
+ label: this.monthFormatter().format(base),
12543
12934
  weeks: this.weeksFor(base),
12544
12935
  };
12545
12936
  });
@@ -12547,13 +12938,15 @@ class BuiCalendar {
12547
12938
  ...(ngDevMode ? [{ debugName: "monthGrids" }] : /* istanbul ignore next */ []));
12548
12939
  computedClass = computed(() => cn('inline-block rounded-lg bg-card p-3', this.userClass()), /* @ts-ignore */
12549
12940
  ...(ngDevMode ? [{ debugName: "computedClass" }] : /* istanbul ignore next */ []));
12941
+ /**
12942
+ * Week number for a row, under the locale's rule and aligned on the same first day as the grid
12943
+ * — a row cannot be labelled with a week it does not span.
12944
+ */
12550
12945
  weekNum(iso) {
12551
12946
  const [year, month, day] = iso.split('-').map(Number);
12552
12947
  const date = new Date(Date.UTC(year, month - 1, day));
12553
- const dayNumber = (date.getUTCDay() + 6) % 7;
12554
- date.setUTCDate(date.getUTCDate() - dayNumber + 3);
12555
- const firstThursday = new Date(Date.UTC(date.getUTCFullYear(), 0, 4));
12556
- return 1 + Math.round((date.getTime() - firstThursday.getTime()) / (7 * 24 * 3600 * 1000));
12948
+ const week = weekOfYear(date, this.resolvedWeekStart(), this.weekInfo().minimalDays);
12949
+ return this.numberFormatter().format(week);
12557
12950
  }
12558
12951
  changeMonth(delta) {
12559
12952
  const view = this.view();
@@ -12644,14 +13037,15 @@ class BuiCalendar {
12644
13037
  weeksFor(base) {
12645
13038
  const year = base.getFullYear();
12646
13039
  const month = base.getMonth();
12647
- const offset = (((new Date(year, month, 1).getDay() - this.weekStart()) % 7) + 7) % 7;
13040
+ const offset = (((new Date(year, month, 1).getDay() - this.resolvedWeekStart()) % 7) + 7) % 7;
12648
13041
  const today = isoOf$1(new Date());
13042
+ const format = this.numberFormatter();
12649
13043
  return Array.from({ length: 6 }, (_, w) => Array.from({ length: 7 }, (_, d) => {
12650
13044
  const date = new Date(year, month, 1 - offset + w * 7 + d);
12651
13045
  const iso = isoOf$1(date);
12652
13046
  return {
12653
13047
  iso,
12654
- num: date.getDate(),
13048
+ num: format.format(date.getDate()),
12655
13049
  inMonth: date.getMonth() === month,
12656
13050
  isToday: iso === today,
12657
13051
  disabled: this.isDisabled(iso, date),
@@ -12668,13 +13062,13 @@ class BuiCalendar {
12668
13062
  return true;
12669
13063
  }
12670
13064
  if (this.disableWeekends()) {
12671
- const day = date.getDay();
12672
- return day === 0 || day === 6;
13065
+ // The weekend is not Saturday/Sunday everywhere — `ar-EG` rests on Friday/Saturday.
13066
+ return this.weekInfo().weekend.includes(date.getDay());
12673
13067
  }
12674
13068
  return false;
12675
13069
  }
12676
13070
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiCalendar, deps: [], target: i0.ɵɵFactoryTarget.Component });
12677
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: BuiCalendar, isStandalone: true, selector: "bui-calendar", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, range: { classPropertyName: "range", publicName: "range", isSignal: true, isRequired: false, transformFunction: null }, values: { classPropertyName: "values", publicName: "values", isSignal: true, isRequired: false, transformFunction: null }, months: { classPropertyName: "months", publicName: "months", isSignal: true, isRequired: false, transformFunction: null }, weekStart: { classPropertyName: "weekStart", publicName: "weekStart", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: false, transformFunction: null }, disabledDates: { classPropertyName: "disabledDates", publicName: "disabledDates", isSignal: true, isRequired: false, transformFunction: null }, disableWeekends: { classPropertyName: "disableWeekends", publicName: "disableWeekends", isSignal: true, isRequired: false, transformFunction: null }, showWeekNumbers: { classPropertyName: "showWeekNumbers", publicName: "showWeekNumbers", isSignal: true, isRequired: false, transformFunction: null }, captionLayout: { classPropertyName: "captionLayout", publicName: "captionLayout", isSignal: true, isRequired: false, transformFunction: null }, hideOutsideDays: { classPropertyName: "hideOutsideDays", publicName: "hideOutsideDays", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, previousMonthLabel: { classPropertyName: "previousMonthLabel", publicName: "previousMonthLabel", isSignal: true, isRequired: false, transformFunction: null }, monthSelectLabel: { classPropertyName: "monthSelectLabel", publicName: "monthSelectLabel", isSignal: true, isRequired: false, transformFunction: null }, yearLabel: { classPropertyName: "yearLabel", publicName: "yearLabel", isSignal: true, isRequired: false, transformFunction: null }, nextMonthLabel: { classPropertyName: "nextMonthLabel", publicName: "nextMonthLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", range: "rangeChange", values: "valuesChange", disabled: "disabledChange" }, host: { attributes: { "data-slot": "calendar" }, listeners: { "focusout": "onTouched()" }, properties: { "class": "computedClass()" } }, providers: [
13071
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: BuiCalendar, isStandalone: true, selector: "bui-calendar", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, range: { classPropertyName: "range", publicName: "range", isSignal: true, isRequired: false, transformFunction: null }, values: { classPropertyName: "values", publicName: "values", isSignal: true, isRequired: false, transformFunction: null }, months: { classPropertyName: "months", publicName: "months", isSignal: true, isRequired: false, transformFunction: null }, weekStart: { classPropertyName: "weekStart", publicName: "weekStart", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: false, transformFunction: null }, disabledDates: { classPropertyName: "disabledDates", publicName: "disabledDates", isSignal: true, isRequired: false, transformFunction: null }, disableWeekends: { classPropertyName: "disableWeekends", publicName: "disableWeekends", isSignal: true, isRequired: false, transformFunction: null }, showWeekNumbers: { classPropertyName: "showWeekNumbers", publicName: "showWeekNumbers", isSignal: true, isRequired: false, transformFunction: null }, captionLayout: { classPropertyName: "captionLayout", publicName: "captionLayout", isSignal: true, isRequired: false, transformFunction: null }, hideOutsideDays: { classPropertyName: "hideOutsideDays", publicName: "hideOutsideDays", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, monthFormat: { classPropertyName: "monthFormat", publicName: "monthFormat", isSignal: true, isRequired: false, transformFunction: null }, weekdayFormat: { classPropertyName: "weekdayFormat", publicName: "weekdayFormat", isSignal: true, isRequired: false, transformFunction: null }, weekdayLabels: { classPropertyName: "weekdayLabels", publicName: "weekdayLabels", isSignal: true, isRequired: false, transformFunction: null }, previousMonthLabel: { classPropertyName: "previousMonthLabel", publicName: "previousMonthLabel", isSignal: true, isRequired: false, transformFunction: null }, monthSelectLabel: { classPropertyName: "monthSelectLabel", publicName: "monthSelectLabel", isSignal: true, isRequired: false, transformFunction: null }, yearLabel: { classPropertyName: "yearLabel", publicName: "yearLabel", isSignal: true, isRequired: false, transformFunction: null }, nextMonthLabel: { classPropertyName: "nextMonthLabel", publicName: "nextMonthLabel", isSignal: true, isRequired: false, transformFunction: null }, weekLabel: { classPropertyName: "weekLabel", publicName: "weekLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", range: "rangeChange", values: "valuesChange", disabled: "disabledChange" }, host: { attributes: { "data-slot": "calendar" }, listeners: { "focusout": "onTouched()" }, properties: { "class": "computedClass()" } }, providers: [
12678
13072
  { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => BuiCalendar), multi: true },
12679
13073
  ], ngImport: i0, template: `
12680
13074
  <div class="flex items-center justify-between pb-2">
@@ -12715,8 +13109,8 @@ class BuiCalendar {
12715
13109
  [value]="viewYear()"
12716
13110
  (change)="setYear($event)"
12717
13111
  >
12718
- @for (year of years(); track year) {
12719
- <option [value]="year">{{ year }}</option>
13112
+ @for (year of years(); track year.value) {
13113
+ <option [value]="year.value">{{ year.label }}</option>
12720
13114
  }
12721
13115
  </select>
12722
13116
  </div>
@@ -12757,11 +13151,21 @@ class BuiCalendar {
12757
13151
  <thead>
12758
13152
  <tr>
12759
13153
  @if (showWeekNumbers()) {
12760
- <th scope="col" class="size-9 text-xs font-normal text-muted-foreground">#</th>
13154
+ <th
13155
+ scope="col"
13156
+ class="h-9 min-w-9 text-xs font-normal text-muted-foreground"
13157
+ [attr.aria-label]="weekText()"
13158
+ >
13159
+ #
13160
+ </th>
12761
13161
  }
12762
- @for (weekday of weekdays(); track weekday) {
12763
- <th scope="col" class="size-9 text-xs font-normal text-muted-foreground">
12764
- {{ weekday }}
13162
+ @for (weekday of weekdays(); track weekday.day) {
13163
+ <th
13164
+ scope="col"
13165
+ class="h-9 min-w-9 px-1 text-xs font-normal text-muted-foreground"
13166
+ [attr.aria-label]="weekday.name"
13167
+ >
13168
+ {{ weekday.label }}
12765
13169
  </th>
12766
13170
  }
12767
13171
  </tr>
@@ -12849,8 +13253,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
12849
13253
  [value]="viewYear()"
12850
13254
  (change)="setYear($event)"
12851
13255
  >
12852
- @for (year of years(); track year) {
12853
- <option [value]="year">{{ year }}</option>
13256
+ @for (year of years(); track year.value) {
13257
+ <option [value]="year.value">{{ year.label }}</option>
12854
13258
  }
12855
13259
  </select>
12856
13260
  </div>
@@ -12891,11 +13295,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
12891
13295
  <thead>
12892
13296
  <tr>
12893
13297
  @if (showWeekNumbers()) {
12894
- <th scope="col" class="size-9 text-xs font-normal text-muted-foreground">#</th>
13298
+ <th
13299
+ scope="col"
13300
+ class="h-9 min-w-9 text-xs font-normal text-muted-foreground"
13301
+ [attr.aria-label]="weekText()"
13302
+ >
13303
+ #
13304
+ </th>
12895
13305
  }
12896
- @for (weekday of weekdays(); track weekday) {
12897
- <th scope="col" class="size-9 text-xs font-normal text-muted-foreground">
12898
- {{ weekday }}
13306
+ @for (weekday of weekdays(); track weekday.day) {
13307
+ <th
13308
+ scope="col"
13309
+ class="h-9 min-w-9 px-1 text-xs font-normal text-muted-foreground"
13310
+ [attr.aria-label]="weekday.name"
13311
+ >
13312
+ {{ weekday.label }}
12899
13313
  </th>
12900
13314
  }
12901
13315
  </tr>
@@ -12936,10 +13350,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
12936
13350
  </div>
12937
13351
  `,
12938
13352
  }]
12939
- }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], range: [{ type: i0.Input, args: [{ isSignal: true, alias: "range", required: false }] }, { type: i0.Output, args: ["rangeChange"] }], values: [{ type: i0.Input, args: [{ isSignal: true, alias: "values", required: false }] }, { type: i0.Output, args: ["valuesChange"] }], months: [{ type: i0.Input, args: [{ isSignal: true, alias: "months", required: false }] }], weekStart: [{ type: i0.Input, args: [{ isSignal: true, alias: "weekStart", required: false }] }], minDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "minDate", required: false }] }], maxDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxDate", required: false }] }], disabledDates: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabledDates", required: false }] }], disableWeekends: [{ type: i0.Input, args: [{ isSignal: true, alias: "disableWeekends", required: false }] }], showWeekNumbers: [{ type: i0.Input, args: [{ isSignal: true, alias: "showWeekNumbers", required: false }] }], captionLayout: [{ type: i0.Input, args: [{ isSignal: true, alias: "captionLayout", required: false }] }], hideOutsideDays: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideOutsideDays", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], previousMonthLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "previousMonthLabel", required: false }] }], monthSelectLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "monthSelectLabel", required: false }] }], yearLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "yearLabel", required: false }] }], nextMonthLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "nextMonthLabel", required: false }] }] } });
13353
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], range: [{ type: i0.Input, args: [{ isSignal: true, alias: "range", required: false }] }, { type: i0.Output, args: ["rangeChange"] }], values: [{ type: i0.Input, args: [{ isSignal: true, alias: "values", required: false }] }, { type: i0.Output, args: ["valuesChange"] }], months: [{ type: i0.Input, args: [{ isSignal: true, alias: "months", required: false }] }], weekStart: [{ type: i0.Input, args: [{ isSignal: true, alias: "weekStart", required: false }] }], minDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "minDate", required: false }] }], maxDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxDate", required: false }] }], disabledDates: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabledDates", required: false }] }], disableWeekends: [{ type: i0.Input, args: [{ isSignal: true, alias: "disableWeekends", required: false }] }], showWeekNumbers: [{ type: i0.Input, args: [{ isSignal: true, alias: "showWeekNumbers", required: false }] }], captionLayout: [{ type: i0.Input, args: [{ isSignal: true, alias: "captionLayout", required: false }] }], hideOutsideDays: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideOutsideDays", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], monthFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "monthFormat", required: false }] }], weekdayFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "weekdayFormat", required: false }] }], weekdayLabels: [{ type: i0.Input, args: [{ isSignal: true, alias: "weekdayLabels", required: false }] }], previousMonthLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "previousMonthLabel", required: false }] }], monthSelectLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "monthSelectLabel", required: false }] }], yearLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "yearLabel", required: false }] }], nextMonthLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "nextMonthLabel", required: false }] }], weekLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "weekLabel", required: false }] }] } });
12940
13354
 
12941
13355
  // eslint-disable-next-line @typescript-eslint/no-empty-function
12942
13356
  const noop$4 = () => { };
13357
+ /** Pattern of the trigger text ("Jul 16, 2026") — matches the other pickers' default. */
13358
+ const DEFAULT_DATE_FORMAT$3 = {
13359
+ month: 'short',
13360
+ day: 'numeric',
13361
+ year: 'numeric',
13362
+ };
13363
+ /** The built-in presets have no per-instance label inputs — translate them via `provideBuiLabels`. */
13364
+ const NO_LABEL_OVERRIDE = signal(undefined, /* @ts-ignore */
13365
+ ...(ngDevMode ? [{ debugName: "NO_LABEL_OVERRIDE" }] : /* istanbul ignore next */ []));
12943
13366
  const POPUP_POSITIONS$2 = [
12944
13367
  { originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4 },
12945
13368
  { originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom', offsetY: -4 },
@@ -12977,9 +13400,9 @@ class BuiDateRangePicker {
12977
13400
  /** Latest selectable date (`yyyy-mm-dd`). */
12978
13401
  maxDate = input('', /* @ts-ignore */
12979
13402
  ...(ngDevMode ? [{ debugName: "maxDate" }] : /* istanbul ignore next */ []));
12980
- /** Text shown on the trigger when nothing is selected. */
12981
- placeholder = input('Pick a date range', /* @ts-ignore */
12982
- ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
13403
+ /** Text shown on the trigger when nothing is selected. Falls back to `provideBuiLabels`. */
13404
+ placeholder = input(/* @ts-ignore */
13405
+ ...(ngDevMode ? [undefined, { debugName: "placeholder" }] : /* istanbul ignore next */ []));
12983
13406
  /** Whether the picker is disabled. Two-way bindable with `[(disabled)]`. */
12984
13407
  disabled = model(false, /* @ts-ignore */
12985
13408
  ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
@@ -12989,9 +13412,34 @@ class BuiDateRangePicker {
12989
13412
  /** Accessible name applied to the trigger. */
12990
13413
  ariaLabel = input('', { ...(ngDevMode ? { debugName: "ariaLabel" } : /* istanbul ignore next */ {}), alias: 'aria-label' });
12991
13414
  userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : /* istanbul ignore next */ {}), alias: 'class' });
13415
+ /** BCP 47 locale for the trigger text and the calendar. Defaults to the app's `LOCALE_ID`. */
13416
+ locale = input(/* @ts-ignore */
13417
+ ...(ngDevMode ? [undefined, { debugName: "locale" }] : /* istanbul ignore next */ []));
13418
+ /**
13419
+ * `Intl.DateTimeFormat` options for the trigger text. Replaces the default wholesale, so
13420
+ * `{ dateStyle: 'short' }` renders `16/07/2026` in `fr` (options cannot be mixed with it).
13421
+ */
13422
+ dateFormat = input(DEFAULT_DATE_FORMAT$3, /* @ts-ignore */
13423
+ ...(ngDevMode ? [{ debugName: "dateFormat" }] : /* istanbul ignore next */ []));
13424
+ placeholderText = buiLabel('dateRangePickerPlaceholder', this.placeholder);
13425
+ presetText = {
13426
+ today: buiLabel('dateRangePresetToday', NO_LABEL_OVERRIDE),
13427
+ last7Days: buiLabel('dateRangePresetLast7Days', NO_LABEL_OVERRIDE),
13428
+ last30Days: buiLabel('dateRangePresetLast30Days', NO_LABEL_OVERRIDE),
13429
+ thisMonth: buiLabel('dateRangePresetThisMonth', NO_LABEL_OVERRIDE),
13430
+ lastMonth: buiLabel('dateRangePresetLastMonth', NO_LABEL_OVERRIDE),
13431
+ };
12992
13432
  open = signal(false, /* @ts-ignore */
12993
13433
  ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
12994
13434
  popupPositions = POPUP_POSITIONS$2;
13435
+ resolvedLocale = buiLocale(this.locale);
13436
+ formatter = computed(() =>
13437
+ // Gregorian by default so the trigger agrees with the grid it opens; caller's options win.
13438
+ new Intl.DateTimeFormat(this.resolvedLocale(), {
13439
+ calendar: BUI_GRID_CALENDAR,
13440
+ ...this.dateFormat(),
13441
+ }), /* @ts-ignore */
13442
+ ...(ngDevMode ? [{ debugName: "formatter" }] : /* istanbul ignore next */ []));
12995
13443
  onChange = noop$4;
12996
13444
  onTouched = noop$4;
12997
13445
  hasValue = computed(() => this.value().start !== '', /* @ts-ignore */
@@ -12999,7 +13447,7 @@ class BuiDateRangePicker {
12999
13447
  display = computed(() => {
13000
13448
  const { start, end } = this.value();
13001
13449
  if (start === '') {
13002
- return this.placeholder();
13450
+ return this.placeholderText();
13003
13451
  }
13004
13452
  return end === '' ? `${this.fmt(start)} – …` : `${this.fmt(start)} – ${this.fmt(end)}`;
13005
13453
  }, /* @ts-ignore */
@@ -13036,11 +13484,7 @@ class BuiDateRangePicker {
13036
13484
  }
13037
13485
  fmt(iso) {
13038
13486
  const [year, month, day] = iso.split('-').map(Number);
13039
- return new Date(year, month - 1, day).toLocaleDateString(undefined, {
13040
- month: 'short',
13041
- day: 'numeric',
13042
- year: 'numeric',
13043
- });
13487
+ return this.formatter().format(new Date(year, month - 1, day));
13044
13488
  }
13045
13489
  defaultPresets() {
13046
13490
  const today = new Date();
@@ -13049,12 +13493,15 @@ class BuiDateRangePicker {
13049
13493
  const startOfLastMonth = new Date(today.getFullYear(), today.getMonth() - 1, 1);
13050
13494
  const endOfLastMonth = new Date(today.getFullYear(), today.getMonth(), 0);
13051
13495
  return [
13052
- { label: 'Today', range: { start: iso, end: iso } },
13053
- { label: 'Last 7 days', range: { start: isoOf(addDays(today, -6)), end: iso } },
13054
- { label: 'Last 30 days', range: { start: isoOf(addDays(today, -29)), end: iso } },
13055
- { label: 'This month', range: { start: isoOf(startOfMonth), end: iso } },
13496
+ { label: this.presetText.today(), range: { start: iso, end: iso } },
13497
+ { label: this.presetText.last7Days(), range: { start: isoOf(addDays(today, -6)), end: iso } },
13498
+ {
13499
+ label: this.presetText.last30Days(),
13500
+ range: { start: isoOf(addDays(today, -29)), end: iso },
13501
+ },
13502
+ { label: this.presetText.thisMonth(), range: { start: isoOf(startOfMonth), end: iso } },
13056
13503
  {
13057
- label: 'Last month',
13504
+ label: this.presetText.lastMonth(),
13058
13505
  range: { start: isoOf(startOfLastMonth), end: isoOf(endOfLastMonth) },
13059
13506
  },
13060
13507
  ];
@@ -13072,7 +13519,7 @@ class BuiDateRangePicker {
13072
13519
  this.disabled.set(isDisabled);
13073
13520
  }
13074
13521
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiDateRangePicker, deps: [], target: i0.ɵɵFactoryTarget.Component });
13075
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: BuiDateRangePicker, isStandalone: true, selector: "bui-date-range-picker", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, months: { classPropertyName: "months", publicName: "months", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, presets: { classPropertyName: "presets", publicName: "presets", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", disabled: "disabledChange" }, host: { attributes: { "data-slot": "date-range-picker" }, properties: { "class": "computedClass()" } }, providers: [
13522
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: BuiDateRangePicker, isStandalone: true, selector: "bui-date-range-picker", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, months: { classPropertyName: "months", publicName: "months", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, presets: { classPropertyName: "presets", publicName: "presets", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, dateFormat: { classPropertyName: "dateFormat", publicName: "dateFormat", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", disabled: "disabledChange" }, host: { attributes: { "data-slot": "date-range-picker" }, properties: { "class": "computedClass()" } }, providers: [
13076
13523
  { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => BuiDateRangePicker), multi: true },
13077
13524
  ], ngImport: i0, template: `
13078
13525
  <button
@@ -13081,7 +13528,7 @@ class BuiDateRangePicker {
13081
13528
  #origin="cdkOverlayOrigin"
13082
13529
  type="button"
13083
13530
  class="flex h-9 w-full items-center gap-2 rounded-md border border-input bg-transparent px-3 text-sm shadow-xs outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50"
13084
- [attr.aria-label]="ariaLabel() || placeholder()"
13531
+ [attr.aria-label]="ariaLabel() || placeholderText()"
13085
13532
  [attr.aria-expanded]="open()"
13086
13533
  [disabled]="disabled()"
13087
13534
  (click)="open.set(!open())"
@@ -13132,11 +13579,12 @@ class BuiDateRangePicker {
13132
13579
  [range]="value()"
13133
13580
  [minDate]="minDate()"
13134
13581
  [maxDate]="maxDate()"
13582
+ [locale]="locale()"
13135
13583
  (rangeChange)="onRange($event)"
13136
13584
  />
13137
13585
  </div>
13138
13586
  </ng-template>
13139
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i1.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "component", type: BuiCalendar, selector: "bui-calendar", inputs: ["value", "mode", "range", "values", "months", "weekStart", "minDate", "maxDate", "disabledDates", "disableWeekends", "showWeekNumbers", "captionLayout", "hideOutsideDays", "disabled", "class", "previousMonthLabel", "monthSelectLabel", "yearLabel", "nextMonthLabel"], outputs: ["valueChange", "rangeChange", "valuesChange", "disabledChange"] }] });
13587
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i1.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "component", type: BuiCalendar, selector: "bui-calendar", inputs: ["value", "mode", "range", "values", "months", "weekStart", "minDate", "maxDate", "disabledDates", "disableWeekends", "showWeekNumbers", "captionLayout", "hideOutsideDays", "disabled", "class", "locale", "monthFormat", "weekdayFormat", "weekdayLabels", "previousMonthLabel", "monthSelectLabel", "yearLabel", "nextMonthLabel", "weekLabel"], outputs: ["valueChange", "rangeChange", "valuesChange", "disabledChange"] }] });
13140
13588
  }
13141
13589
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiDateRangePicker, decorators: [{
13142
13590
  type: Component,
@@ -13154,7 +13602,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
13154
13602
  #origin="cdkOverlayOrigin"
13155
13603
  type="button"
13156
13604
  class="flex h-9 w-full items-center gap-2 rounded-md border border-input bg-transparent px-3 text-sm shadow-xs outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50"
13157
- [attr.aria-label]="ariaLabel() || placeholder()"
13605
+ [attr.aria-label]="ariaLabel() || placeholderText()"
13158
13606
  [attr.aria-expanded]="open()"
13159
13607
  [disabled]="disabled()"
13160
13608
  (click)="open.set(!open())"
@@ -13205,13 +13653,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
13205
13653
  [range]="value()"
13206
13654
  [minDate]="minDate()"
13207
13655
  [maxDate]="maxDate()"
13656
+ [locale]="locale()"
13208
13657
  (rangeChange)="onRange($event)"
13209
13658
  />
13210
13659
  </div>
13211
13660
  </ng-template>
13212
13661
  `,
13213
13662
  }]
13214
- }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], months: [{ type: i0.Input, args: [{ isSignal: true, alias: "months", required: false }] }], minDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "minDate", required: false }] }], maxDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxDate", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], presets: [{ type: i0.Input, args: [{ isSignal: true, alias: "presets", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-label", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
13663
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], months: [{ type: i0.Input, args: [{ isSignal: true, alias: "months", required: false }] }], minDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "minDate", required: false }] }], maxDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxDate", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], presets: [{ type: i0.Input, args: [{ isSignal: true, alias: "presets", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-label", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], dateFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFormat", required: false }] }] } });
13215
13664
 
13216
13665
  /** A chat composer: an autosizing textarea with a send button. Emits `submitted` on send. */
13217
13666
  class BuiPromptInput {
@@ -15629,6 +16078,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
15629
16078
  `, styles: ["[data-slot=org-chart] ul{display:flex;justify-content:center;gap:1rem;padding-top:1.25rem;list-style:none;margin:0;padding-inline-start:0}[data-slot=org-chart] li{position:relative;display:flex;flex-direction:column;align-items:center;padding:1.25rem .5rem 0}[data-slot=org-chart] li:before,[data-slot=org-chart] li:after{content:\"\";position:absolute;top:0;width:50%;height:1.25rem;border-top:1px solid var(--border)}[data-slot=org-chart] li:before{inset-inline-end:50%}[data-slot=org-chart] li:after{inset-inline-start:50%;border-inline-start:1px solid var(--border)}[data-slot=org-chart] li:only-child{padding-top:.5rem}[data-slot=org-chart] li:only-child:before,[data-slot=org-chart] li:only-child:after{display:none}[data-slot=org-chart] li:first-child:before,[data-slot=org-chart] li:last-child:after{border:0}[data-slot=org-chart] li:last-child:before{border-inline-end:1px solid var(--border)}[data-slot=org-chart] ul ul:before{content:\"\";position:absolute;top:0;inset-inline-start:50%;height:1.25rem;border-inline-start:1px solid var(--border)}[data-slot=org-chart]>ul{padding-top:0}[data-slot=org-chart]>ul>li{padding-top:0}[data-slot=org-chart]>ul>li:before,[data-slot=org-chart]>ul>li:after{display:none}\n"] }]
15630
16079
  }], propDecorators: { node: [{ type: i0.Input, args: [{ isSignal: true, alias: "node", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
15631
16080
 
16081
+ /** Two fraction digits ("1,234.50") — matches the pre-locale rendering in `en-US`. */
16082
+ const DEFAULT_NUMBER_FORMAT = {
16083
+ minimumFractionDigits: 2,
16084
+ maximumFractionDigits: 2,
16085
+ };
15632
16086
  /** A cart trigger with an item-count badge and a dropdown with line items + subtotal. */
15633
16087
  class BuiMiniCart {
15634
16088
  /** Line items in the cart, used for count and subtotal. */
@@ -15647,8 +16101,28 @@ class BuiMiniCart {
15647
16101
  /** Accessible label override for the cart dropdown dialog. */
15648
16102
  label = input(/* @ts-ignore */
15649
16103
  ...(ngDevMode ? [undefined, { debugName: "label" }] : /* istanbul ignore next */ []));
16104
+ /** Heading shown at the top of the cart panel. Falls back to `provideBuiLabels`. */
16105
+ title = input(/* @ts-ignore */
16106
+ ...(ngDevMode ? [undefined, { debugName: "title" }] : /* istanbul ignore next */ []));
16107
+ /** Label for the subtotal row. Falls back to `provideBuiLabels`. */
16108
+ subtotalLabel = input(/* @ts-ignore */
16109
+ ...(ngDevMode ? [undefined, { debugName: "subtotalLabel" }] : /* istanbul ignore next */ []));
16110
+ /** BCP 47 locale for number formatting. Defaults to the app's `LOCALE_ID`. */
16111
+ locale = input(/* @ts-ignore */
16112
+ ...(ngDevMode ? [undefined, { debugName: "locale" }] : /* istanbul ignore next */ []));
16113
+ /**
16114
+ * `Intl.NumberFormat` options for prices and subtotal. Replaces the default wholesale — pass
16115
+ * `{ style: 'currency', currency: 'EUR' }` to let ICU place the symbol itself.
16116
+ */
16117
+ numberFormat = input(DEFAULT_NUMBER_FORMAT, /* @ts-ignore */
16118
+ ...(ngDevMode ? [{ debugName: "numberFormat" }] : /* istanbul ignore next */ []));
16119
+ resolvedLocale = buiLocale(this.locale);
16120
+ formatter = computed(() => new Intl.NumberFormat(this.resolvedLocale(), this.numberFormat()), /* @ts-ignore */
16121
+ ...(ngDevMode ? [{ debugName: "formatter" }] : /* istanbul ignore next */ []));
15650
16122
  triggerText = buiLabel('miniCartTrigger', this.triggerLabel);
15651
16123
  labelText = buiLabel('miniCart', this.label);
16124
+ titleText = buiLabel('miniCartTitle', this.title);
16125
+ subtotalText = buiLabel('miniCartSubtotal', this.subtotalLabel);
15652
16126
  count = computed(() => this.items().reduce((total, item) => total + item.qty, 0), /* @ts-ignore */
15653
16127
  ...(ngDevMode ? [{ debugName: "count" }] : /* istanbul ignore next */ []));
15654
16128
  subtotal = computed(() => this.items().reduce((total, item) => total + item.price * item.qty, 0), /* @ts-ignore */
@@ -15656,11 +16130,10 @@ class BuiMiniCart {
15656
16130
  computedClass = computed(() => cn('relative inline-block', this.userClass()), /* @ts-ignore */
15657
16131
  ...(ngDevMode ? [{ debugName: "computedClass" }] : /* istanbul ignore next */ []));
15658
16132
  format(value) {
15659
- return (this.currency() +
15660
- value.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 }));
16133
+ return this.currency() + this.formatter().format(value);
15661
16134
  }
15662
16135
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiMiniCart, deps: [], target: i0.ɵɵFactoryTarget.Component });
15663
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: BuiMiniCart, isStandalone: true, selector: "bui-mini-cart", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, currency: { classPropertyName: "currency", publicName: "currency", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, triggerLabel: { classPropertyName: "triggerLabel", publicName: "triggerLabel", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange" }, host: { attributes: { "data-slot": "mini-cart" }, properties: { "class": "computedClass()" } }, ngImport: i0, template: `
16136
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: BuiMiniCart, isStandalone: true, selector: "bui-mini-cart", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, currency: { classPropertyName: "currency", publicName: "currency", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, triggerLabel: { classPropertyName: "triggerLabel", publicName: "triggerLabel", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, subtotalLabel: { classPropertyName: "subtotalLabel", publicName: "subtotalLabel", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, numberFormat: { classPropertyName: "numberFormat", publicName: "numberFormat", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange" }, host: { attributes: { "data-slot": "mini-cart" }, properties: { "class": "computedClass()" } }, ngImport: i0, template: `
15664
16137
  <button
15665
16138
  type="button"
15666
16139
  class="relative inline-flex size-9 items-center justify-center rounded-md border border-input hover:bg-accent"
@@ -15696,7 +16169,7 @@ class BuiMiniCart {
15696
16169
  role="dialog"
15697
16170
  [attr.aria-label]="labelText()"
15698
16171
  >
15699
- <div class="border-b p-3 text-sm font-medium">Your cart</div>
16172
+ <div class="border-b p-3 text-sm font-medium">{{ titleText() }}</div>
15700
16173
  @if (items().length === 0) {
15701
16174
  <p class="p-6 text-center text-sm text-muted-foreground">Your cart is empty.</p>
15702
16175
  } @else {
@@ -15722,7 +16195,7 @@ class BuiMiniCart {
15722
16195
  }
15723
16196
  </ul>
15724
16197
  <div class="flex items-center justify-between border-t p-3">
15725
- <span class="text-sm font-medium">Subtotal</span>
16198
+ <span class="text-sm font-medium">{{ subtotalText() }}</span>
15726
16199
  <span class="text-sm font-semibold tabular-nums">{{ format(subtotal()) }}</span>
15727
16200
  </div>
15728
16201
  <div class="p-3 pt-0">
@@ -15779,7 +16252,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
15779
16252
  role="dialog"
15780
16253
  [attr.aria-label]="labelText()"
15781
16254
  >
15782
- <div class="border-b p-3 text-sm font-medium">Your cart</div>
16255
+ <div class="border-b p-3 text-sm font-medium">{{ titleText() }}</div>
15783
16256
  @if (items().length === 0) {
15784
16257
  <p class="p-6 text-center text-sm text-muted-foreground">Your cart is empty.</p>
15785
16258
  } @else {
@@ -15805,7 +16278,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
15805
16278
  }
15806
16279
  </ul>
15807
16280
  <div class="flex items-center justify-between border-t p-3">
15808
- <span class="text-sm font-medium">Subtotal</span>
16281
+ <span class="text-sm font-medium">{{ subtotalText() }}</span>
15809
16282
  <span class="text-sm font-semibold tabular-nums">{{ format(subtotal()) }}</span>
15810
16283
  </div>
15811
16284
  <div class="p-3 pt-0">
@@ -15821,7 +16294,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
15821
16294
  }
15822
16295
  `,
15823
16296
  }]
15824
- }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], currency: [{ type: i0.Input, args: [{ isSignal: true, alias: "currency", required: false }] }], open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], triggerLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "triggerLabel", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }] } });
16297
+ }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], currency: [{ type: i0.Input, args: [{ isSignal: true, alias: "currency", required: false }] }], open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], triggerLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "triggerLabel", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], subtotalLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "subtotalLabel", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], numberFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "numberFormat", required: false }] }] } });
15825
16298
 
15826
16299
  /** An SVG beam connecting two elements (by selector) with a travelling light. SSR-safe. */
15827
16300
  class BuiAnimatedBeam {
@@ -16399,6 +16872,14 @@ class BuiMarkdownEditor {
16399
16872
  rows = input(8, /* @ts-ignore */
16400
16873
  ...(ngDevMode ? [{ debugName: "rows" }] : /* istanbul ignore next */ []));
16401
16874
  userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : /* istanbul ignore next */ {}), alias: 'class' });
16875
+ /** Text of the write tab. Falls back to `provideBuiLabels`. */
16876
+ writeLabel = input(/* @ts-ignore */
16877
+ ...(ngDevMode ? [undefined, { debugName: "writeLabel" }] : /* istanbul ignore next */ []));
16878
+ /** Text of the preview tab. Falls back to `provideBuiLabels`. */
16879
+ previewLabel = input(/* @ts-ignore */
16880
+ ...(ngDevMode ? [undefined, { debugName: "previewLabel" }] : /* istanbul ignore next */ []));
16881
+ writeText = buiLabel('markdownEditorWrite', this.writeLabel);
16882
+ previewText = buiLabel('markdownEditorPreview', this.previewLabel);
16402
16883
  tab = signal('write', /* @ts-ignore */
16403
16884
  ...(ngDevMode ? [{ debugName: "tab" }] : /* istanbul ignore next */ []));
16404
16885
  rendered = computed(() => renderMarkdown(this.value()), /* @ts-ignore */
@@ -16412,11 +16893,13 @@ class BuiMarkdownEditor {
16412
16893
  this.value.set(event.target.value);
16413
16894
  }
16414
16895
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiMarkdownEditor, deps: [], target: i0.ɵɵFactoryTarget.Component });
16415
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: BuiMarkdownEditor, isStandalone: true, selector: "bui-markdown-editor", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, host: { attributes: { "data-slot": "markdown-editor" }, properties: { "class": "computedClass()" } }, ngImport: i0, template: `
16896
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: BuiMarkdownEditor, isStandalone: true, selector: "bui-markdown-editor", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, writeLabel: { classPropertyName: "writeLabel", publicName: "writeLabel", isSignal: true, isRequired: false, transformFunction: null }, previewLabel: { classPropertyName: "previewLabel", publicName: "previewLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, host: { attributes: { "data-slot": "markdown-editor" }, properties: { "class": "computedClass()" } }, ngImport: i0, template: `
16416
16897
  <div class="flex border-b bg-muted/40">
16417
- <button type="button" [class]="tabClass('write')" (click)="tab.set('write')">Write</button>
16898
+ <button type="button" [class]="tabClass('write')" (click)="tab.set('write')">
16899
+ {{ writeText() }}
16900
+ </button>
16418
16901
  <button type="button" [class]="tabClass('preview')" (click)="tab.set('preview')">
16419
- Preview
16902
+ {{ previewText() }}
16420
16903
  </button>
16421
16904
  </div>
16422
16905
  @if (tab() === 'write') {
@@ -16444,9 +16927,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
16444
16927
  host: { 'data-slot': 'markdown-editor', '[class]': 'computedClass()' },
16445
16928
  template: `
16446
16929
  <div class="flex border-b bg-muted/40">
16447
- <button type="button" [class]="tabClass('write')" (click)="tab.set('write')">Write</button>
16930
+ <button type="button" [class]="tabClass('write')" (click)="tab.set('write')">
16931
+ {{ writeText() }}
16932
+ </button>
16448
16933
  <button type="button" [class]="tabClass('preview')" (click)="tab.set('preview')">
16449
- Preview
16934
+ {{ previewText() }}
16450
16935
  </button>
16451
16936
  </div>
16452
16937
  @if (tab() === 'write') {
@@ -16467,10 +16952,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
16467
16952
  }
16468
16953
  `,
16469
16954
  }]
16470
- }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
16955
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], writeLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "writeLabel", required: false }] }], previewLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "previewLabel", required: false }] }] } });
16471
16956
 
16472
16957
  // eslint-disable-next-line @typescript-eslint/no-empty-function
16473
16958
  const noop$3 = () => { };
16959
+ /** Pattern of the trigger text ("Jul 16, 2026") — matches the pre-locale rendering in `en-US`. */
16960
+ const DEFAULT_DATE_FORMAT$2 = {
16961
+ month: 'short',
16962
+ day: 'numeric',
16963
+ year: 'numeric',
16964
+ };
16474
16965
  const POPUP_POSITIONS$1 = [
16475
16966
  { originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4 },
16476
16967
  { originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom', offsetY: -4 },
@@ -16492,18 +16983,18 @@ class BuiDatePicker {
16492
16983
  /** Month grids shown in the popover (handy for range). */
16493
16984
  months = input(1, /* @ts-ignore */
16494
16985
  ...(ngDevMode ? [{ debugName: "months" }] : /* istanbul ignore next */ []));
16495
- /** Text shown on the trigger when no date is selected. */
16496
- placeholder = input('Pick a date', /* @ts-ignore */
16497
- ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
16986
+ /** Text shown on the trigger when no date is selected. Falls back to `provideBuiLabels`. */
16987
+ placeholder = input(/* @ts-ignore */
16988
+ ...(ngDevMode ? [undefined, { debugName: "placeholder" }] : /* istanbul ignore next */ []));
16498
16989
  /** Earliest selectable date (`yyyy-mm-dd`). */
16499
16990
  minDate = input('', /* @ts-ignore */
16500
16991
  ...(ngDevMode ? [{ debugName: "minDate" }] : /* istanbul ignore next */ []));
16501
16992
  /** Latest selectable date (`yyyy-mm-dd`). */
16502
16993
  maxDate = input('', /* @ts-ignore */
16503
16994
  ...(ngDevMode ? [{ debugName: "maxDate" }] : /* istanbul ignore next */ []));
16504
- /** First day of the week (0 = Sunday). */
16505
- weekStart = input(0, /* @ts-ignore */
16506
- ...(ngDevMode ? [{ debugName: "weekStart" }] : /* istanbul ignore next */ []));
16995
+ /** First day of the week (0 = Sunday). Defaults to the locale's own convention. */
16996
+ weekStart = input(/* @ts-ignore */
16997
+ ...(ngDevMode ? [undefined, { debugName: "weekStart" }] : /* istanbul ignore next */ []));
16507
16998
  /** Specific ISO dates (yyyy-mm-dd) to disable. */
16508
16999
  disabledDates = input([], /* @ts-ignore */
16509
17000
  ...(ngDevMode ? [{ debugName: "disabledDates" }] : /* istanbul ignore next */ []));
@@ -16523,23 +17014,41 @@ class BuiDatePicker {
16523
17014
  disabled = model(false, /* @ts-ignore */
16524
17015
  ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
16525
17016
  userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : /* istanbul ignore next */ {}), alias: 'class' });
17017
+ /** BCP 47 locale for the trigger text and the calendar. Defaults to the app's `LOCALE_ID`. */
17018
+ locale = input(/* @ts-ignore */
17019
+ ...(ngDevMode ? [undefined, { debugName: "locale" }] : /* istanbul ignore next */ []));
17020
+ /**
17021
+ * `Intl.DateTimeFormat` options for the trigger text. Replaces the default wholesale, so
17022
+ * `{ dateStyle: 'short' }` renders `16/07/2026` in `fr` (options cannot be mixed with it).
17023
+ */
17024
+ dateFormat = input(DEFAULT_DATE_FORMAT$2, /* @ts-ignore */
17025
+ ...(ngDevMode ? [{ debugName: "dateFormat" }] : /* istanbul ignore next */ []));
17026
+ placeholderText = buiLabel('datePickerPlaceholder', this.placeholder);
16526
17027
  onChange = noop$3;
16527
17028
  onTouched = noop$3;
16528
17029
  host = inject(ElementRef);
16529
17030
  open = signal(false, /* @ts-ignore */
16530
17031
  ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
17032
+ resolvedLocale = buiLocale(this.locale);
17033
+ formatter = computed(() =>
17034
+ // Gregorian by default so the trigger agrees with the grid it opens; caller's options win.
17035
+ new Intl.DateTimeFormat(this.resolvedLocale(), {
17036
+ calendar: BUI_GRID_CALENDAR,
17037
+ ...this.dateFormat(),
17038
+ }), /* @ts-ignore */
17039
+ ...(ngDevMode ? [{ debugName: "formatter" }] : /* istanbul ignore next */ []));
16531
17040
  hasValue = computed(() => (this.mode() === 'range' ? this.range().start : this.value()) !== '', /* @ts-ignore */
16532
17041
  ...(ngDevMode ? [{ debugName: "hasValue" }] : /* istanbul ignore next */ []));
16533
17042
  display = computed(() => {
16534
17043
  if (this.mode() === 'range') {
16535
17044
  const { start, end } = this.range();
16536
17045
  if (start === '') {
16537
- return this.placeholder();
17046
+ return this.placeholderText();
16538
17047
  }
16539
17048
  return end === '' ? `${this.fmt(start)} – …` : `${this.fmt(start)} – ${this.fmt(end)}`;
16540
17049
  }
16541
17050
  const value = this.value();
16542
- return value === '' ? this.placeholder() : this.fmt(value);
17051
+ return value === '' ? this.placeholderText() : this.fmt(value);
16543
17052
  }, /* @ts-ignore */
16544
17053
  ...(ngDevMode ? [{ debugName: "display" }] : /* istanbul ignore next */ []));
16545
17054
  popupPositions = POPUP_POSITIONS$1;
@@ -16558,11 +17067,7 @@ class BuiDatePicker {
16558
17067
  }
16559
17068
  }
16560
17069
  fmt(iso) {
16561
- return new Date(`${iso}T00:00:00`).toLocaleDateString('en-US', {
16562
- month: 'short',
16563
- day: 'numeric',
16564
- year: 'numeric',
16565
- });
17070
+ return this.formatter().format(new Date(`${iso}T00:00:00`));
16566
17071
  }
16567
17072
  // The calendar is portalled into a CDK overlay (outside the host); rely on the overlay's own
16568
17073
  // outside-click signal. Clicks on the trigger stay inside the host and are ignored here.
@@ -16586,7 +17091,7 @@ class BuiDatePicker {
16586
17091
  this.disabled.set(isDisabled);
16587
17092
  }
16588
17093
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiDatePicker, deps: [], target: i0.ɵɵFactoryTarget.Component });
16589
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.2", type: BuiDatePicker, isStandalone: true, selector: "bui-date-picker", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, range: { classPropertyName: "range", publicName: "range", isSignal: true, isRequired: false, transformFunction: null }, months: { classPropertyName: "months", publicName: "months", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: false, transformFunction: null }, weekStart: { classPropertyName: "weekStart", publicName: "weekStart", isSignal: true, isRequired: false, transformFunction: null }, disabledDates: { classPropertyName: "disabledDates", publicName: "disabledDates", isSignal: true, isRequired: false, transformFunction: null }, disableWeekends: { classPropertyName: "disableWeekends", publicName: "disableWeekends", isSignal: true, isRequired: false, transformFunction: null }, showWeekNumbers: { classPropertyName: "showWeekNumbers", publicName: "showWeekNumbers", isSignal: true, isRequired: false, transformFunction: null }, captionLayout: { classPropertyName: "captionLayout", publicName: "captionLayout", isSignal: true, isRequired: false, transformFunction: null }, hideOutsideDays: { classPropertyName: "hideOutsideDays", publicName: "hideOutsideDays", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", range: "rangeChange", disabled: "disabledChange" }, host: { attributes: { "data-slot": "date-picker" }, properties: { "class": "computedClass()" } }, providers: [
17094
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.2", type: BuiDatePicker, isStandalone: true, selector: "bui-date-picker", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, range: { classPropertyName: "range", publicName: "range", isSignal: true, isRequired: false, transformFunction: null }, months: { classPropertyName: "months", publicName: "months", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: false, transformFunction: null }, weekStart: { classPropertyName: "weekStart", publicName: "weekStart", isSignal: true, isRequired: false, transformFunction: null }, disabledDates: { classPropertyName: "disabledDates", publicName: "disabledDates", isSignal: true, isRequired: false, transformFunction: null }, disableWeekends: { classPropertyName: "disableWeekends", publicName: "disableWeekends", isSignal: true, isRequired: false, transformFunction: null }, showWeekNumbers: { classPropertyName: "showWeekNumbers", publicName: "showWeekNumbers", isSignal: true, isRequired: false, transformFunction: null }, captionLayout: { classPropertyName: "captionLayout", publicName: "captionLayout", isSignal: true, isRequired: false, transformFunction: null }, hideOutsideDays: { classPropertyName: "hideOutsideDays", publicName: "hideOutsideDays", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, dateFormat: { classPropertyName: "dateFormat", publicName: "dateFormat", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", range: "rangeChange", disabled: "disabledChange" }, host: { attributes: { "data-slot": "date-picker" }, properties: { "class": "computedClass()" } }, providers: [
16590
17095
  { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => BuiDatePicker), multi: true },
16591
17096
  ], ngImport: i0, template: `
16592
17097
  <button
@@ -16635,12 +17140,13 @@ class BuiDatePicker {
16635
17140
  [showWeekNumbers]="showWeekNumbers()"
16636
17141
  [captionLayout]="captionLayout()"
16637
17142
  [hideOutsideDays]="hideOutsideDays()"
17143
+ [locale]="locale()"
16638
17144
  (valueChange)="onPick($event)"
16639
17145
  (rangeChange)="onRange($event)"
16640
17146
  />
16641
17147
  </div>
16642
17148
  </ng-template>
16643
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i1.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "component", type: BuiCalendar, selector: "bui-calendar", inputs: ["value", "mode", "range", "values", "months", "weekStart", "minDate", "maxDate", "disabledDates", "disableWeekends", "showWeekNumbers", "captionLayout", "hideOutsideDays", "disabled", "class", "previousMonthLabel", "monthSelectLabel", "yearLabel", "nextMonthLabel"], outputs: ["valueChange", "rangeChange", "valuesChange", "disabledChange"] }] });
17149
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i1.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "component", type: BuiCalendar, selector: "bui-calendar", inputs: ["value", "mode", "range", "values", "months", "weekStart", "minDate", "maxDate", "disabledDates", "disableWeekends", "showWeekNumbers", "captionLayout", "hideOutsideDays", "disabled", "class", "locale", "monthFormat", "weekdayFormat", "weekdayLabels", "previousMonthLabel", "monthSelectLabel", "yearLabel", "nextMonthLabel", "weekLabel"], outputs: ["valueChange", "rangeChange", "valuesChange", "disabledChange"] }] });
16644
17150
  }
16645
17151
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiDatePicker, decorators: [{
16646
17152
  type: Component,
@@ -16701,6 +17207,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
16701
17207
  [showWeekNumbers]="showWeekNumbers()"
16702
17208
  [captionLayout]="captionLayout()"
16703
17209
  [hideOutsideDays]="hideOutsideDays()"
17210
+ [locale]="locale()"
16704
17211
  (valueChange)="onPick($event)"
16705
17212
  (rangeChange)="onRange($event)"
16706
17213
  />
@@ -16708,7 +17215,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
16708
17215
  </ng-template>
16709
17216
  `,
16710
17217
  }]
16711
- }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], range: [{ type: i0.Input, args: [{ isSignal: true, alias: "range", required: false }] }, { type: i0.Output, args: ["rangeChange"] }], months: [{ type: i0.Input, args: [{ isSignal: true, alias: "months", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], minDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "minDate", required: false }] }], maxDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxDate", required: false }] }], weekStart: [{ type: i0.Input, args: [{ isSignal: true, alias: "weekStart", required: false }] }], disabledDates: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabledDates", required: false }] }], disableWeekends: [{ type: i0.Input, args: [{ isSignal: true, alias: "disableWeekends", required: false }] }], showWeekNumbers: [{ type: i0.Input, args: [{ isSignal: true, alias: "showWeekNumbers", required: false }] }], captionLayout: [{ type: i0.Input, args: [{ isSignal: true, alias: "captionLayout", required: false }] }], hideOutsideDays: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideOutsideDays", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
17218
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], range: [{ type: i0.Input, args: [{ isSignal: true, alias: "range", required: false }] }, { type: i0.Output, args: ["rangeChange"] }], months: [{ type: i0.Input, args: [{ isSignal: true, alias: "months", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], minDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "minDate", required: false }] }], maxDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxDate", required: false }] }], weekStart: [{ type: i0.Input, args: [{ isSignal: true, alias: "weekStart", required: false }] }], disabledDates: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabledDates", required: false }] }], disableWeekends: [{ type: i0.Input, args: [{ isSignal: true, alias: "disableWeekends", required: false }] }], showWeekNumbers: [{ type: i0.Input, args: [{ isSignal: true, alias: "showWeekNumbers", required: false }] }], captionLayout: [{ type: i0.Input, args: [{ isSignal: true, alias: "captionLayout", required: false }] }], hideOutsideDays: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideOutsideDays", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], dateFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFormat", required: false }] }] } });
16712
17219
 
16713
17220
  /** A slide carousel. Project slides as direct children; arrows + dots navigate. SSR-safe. */
16714
17221
  class BuiCarousel {
@@ -18359,6 +18866,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
18359
18866
 
18360
18867
  // eslint-disable-next-line @typescript-eslint/no-empty-function
18361
18868
  const noop$2 = () => { };
18869
+ /**
18870
+ * Pattern of the trigger text ("Jul 16, 2:30 PM") — matches the pre-locale rendering in `en-US`.
18871
+ * Deliberately year-less, which is why the lever is full `Intl` options and not `dateStyle`.
18872
+ */
18873
+ const DEFAULT_DATE_FORMAT$1 = {
18874
+ month: 'short',
18875
+ day: 'numeric',
18876
+ hour: 'numeric',
18877
+ minute: '2-digit',
18878
+ };
18362
18879
  const POPUP_POSITIONS = [
18363
18880
  { originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4 },
18364
18881
  { originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom', offsetY: -4 },
@@ -18380,9 +18897,12 @@ class BuiDatetimePicker {
18380
18897
  /** Month grids shown in the popover (handy for range). */
18381
18898
  months = input(1, /* @ts-ignore */
18382
18899
  ...(ngDevMode ? [{ debugName: "months" }] : /* istanbul ignore next */ []));
18383
- /** Text shown on the trigger when nothing is selected. */
18384
- placeholder = input('Pick date & time', /* @ts-ignore */
18385
- ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
18900
+ /** Text shown on the trigger when nothing is selected. Falls back to `provideBuiLabels`. */
18901
+ placeholder = input(/* @ts-ignore */
18902
+ ...(ngDevMode ? [undefined, { debugName: "placeholder" }] : /* istanbul ignore next */ []));
18903
+ /** Label for the time field in the popover. Falls back to `provideBuiLabels`. */
18904
+ timeLabel = input(/* @ts-ignore */
18905
+ ...(ngDevMode ? [undefined, { debugName: "timeLabel" }] : /* istanbul ignore next */ []));
18386
18906
  /** Earliest selectable date (`yyyy-mm-dd`). */
18387
18907
  minDate = input('', /* @ts-ignore */
18388
18908
  ...(ngDevMode ? [{ debugName: "minDate" }] : /* istanbul ignore next */ []));
@@ -18395,15 +18915,41 @@ class BuiDatetimePicker {
18395
18915
  /** Whether to include seconds in the time field. */
18396
18916
  seconds = input(false, /* @ts-ignore */
18397
18917
  ...(ngDevMode ? [{ debugName: "seconds" }] : /* istanbul ignore next */ []));
18918
+ /**
18919
+ * How the popover's time field renders. The default native `input` is drawn by the browser in
18920
+ * *its* language, so it can disagree with a trigger formatted in `locale`; `select` follows
18921
+ * `locale` instead and keeps the whole picker on one clock.
18922
+ */
18923
+ timeMode = input('input', /* @ts-ignore */
18924
+ ...(ngDevMode ? [{ debugName: "timeMode" }] : /* istanbul ignore next */ []));
18398
18925
  /** Whether the picker is disabled. Two-way bindable with `[(disabled)]`. */
18399
18926
  disabled = model(false, /* @ts-ignore */
18400
18927
  ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
18401
18928
  userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : /* istanbul ignore next */ {}), alias: 'class' });
18929
+ /** BCP 47 locale for the trigger text and the calendar. Defaults to the app's `LOCALE_ID`. */
18930
+ locale = input(/* @ts-ignore */
18931
+ ...(ngDevMode ? [undefined, { debugName: "locale" }] : /* istanbul ignore next */ []));
18932
+ /**
18933
+ * `Intl.DateTimeFormat` options for the trigger text. Replaces the default wholesale, so
18934
+ * `{ dateStyle: 'short', timeStyle: 'short' }` is valid (options cannot be mixed with it).
18935
+ */
18936
+ dateFormat = input(DEFAULT_DATE_FORMAT$1, /* @ts-ignore */
18937
+ ...(ngDevMode ? [{ debugName: "dateFormat" }] : /* istanbul ignore next */ []));
18938
+ placeholderText = buiLabel('datetimePickerPlaceholder', this.placeholder);
18939
+ timeText = buiLabel('datetimePickerTime', this.timeLabel);
18402
18940
  onChange = noop$2;
18403
18941
  onTouched = noop$2;
18404
18942
  host = inject(ElementRef);
18405
18943
  open = signal(false, /* @ts-ignore */
18406
18944
  ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
18945
+ resolvedLocale = buiLocale(this.locale);
18946
+ formatter = computed(() =>
18947
+ // Gregorian by default so the trigger agrees with the grid it opens; caller's options win.
18948
+ new Intl.DateTimeFormat(this.resolvedLocale(), {
18949
+ calendar: BUI_GRID_CALENDAR,
18950
+ ...this.dateFormat(),
18951
+ }), /* @ts-ignore */
18952
+ ...(ngDevMode ? [{ debugName: "formatter" }] : /* istanbul ignore next */ []));
18407
18953
  datePart = computed(() => this.value().split('T', 1).at(0) ?? '', /* @ts-ignore */
18408
18954
  ...(ngDevMode ? [{ debugName: "datePart" }] : /* istanbul ignore next */ []));
18409
18955
  timePart = computed(() => {
@@ -18422,12 +18968,12 @@ class BuiDatetimePicker {
18422
18968
  if (this.mode() === 'range') {
18423
18969
  const { start, end } = this.range();
18424
18970
  if (start === '') {
18425
- return this.placeholder();
18971
+ return this.placeholderText();
18426
18972
  }
18427
18973
  return end === '' ? `${this.fmt(start)} – …` : `${this.fmt(start)} – ${this.fmt(end)}`;
18428
18974
  }
18429
18975
  const value = this.value();
18430
- return value === '' ? this.placeholder() : this.fmt(value);
18976
+ return value === '' ? this.placeholderText() : this.fmt(value);
18431
18977
  }, /* @ts-ignore */
18432
18978
  ...(ngDevMode ? [{ debugName: "display" }] : /* istanbul ignore next */ []));
18433
18979
  popupPositions = POPUP_POSITIONS;
@@ -18458,12 +19004,7 @@ class BuiDatetimePicker {
18458
19004
  this.onChange(this.value());
18459
19005
  }
18460
19006
  fmt(value) {
18461
- return new Date(value).toLocaleString('en-US', {
18462
- month: 'short',
18463
- day: 'numeric',
18464
- hour: 'numeric',
18465
- minute: '2-digit',
18466
- });
19007
+ return this.formatter().format(new Date(value));
18467
19008
  }
18468
19009
  // The popover is portalled into a CDK overlay (outside the host); rely on the overlay's own
18469
19010
  // outside-click signal. Clicks on the trigger stay inside the host and are ignored here.
@@ -18491,7 +19032,7 @@ class BuiDatetimePicker {
18491
19032
  return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`;
18492
19033
  }
18493
19034
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiDatetimePicker, deps: [], target: i0.ɵɵFactoryTarget.Component });
18494
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: BuiDatetimePicker, isStandalone: true, selector: "bui-datetime-picker", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, range: { classPropertyName: "range", publicName: "range", isSignal: true, isRequired: false, transformFunction: null }, months: { classPropertyName: "months", publicName: "months", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: false, transformFunction: null }, captionLayout: { classPropertyName: "captionLayout", publicName: "captionLayout", isSignal: true, isRequired: false, transformFunction: null }, seconds: { classPropertyName: "seconds", publicName: "seconds", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", range: "rangeChange", disabled: "disabledChange" }, host: { attributes: { "data-slot": "datetime-picker" }, properties: { "class": "computedClass()" } }, providers: [
19035
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: BuiDatetimePicker, isStandalone: true, selector: "bui-datetime-picker", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, range: { classPropertyName: "range", publicName: "range", isSignal: true, isRequired: false, transformFunction: null }, months: { classPropertyName: "months", publicName: "months", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, timeLabel: { classPropertyName: "timeLabel", publicName: "timeLabel", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: false, transformFunction: null }, captionLayout: { classPropertyName: "captionLayout", publicName: "captionLayout", isSignal: true, isRequired: false, transformFunction: null }, seconds: { classPropertyName: "seconds", publicName: "seconds", isSignal: true, isRequired: false, transformFunction: null }, timeMode: { classPropertyName: "timeMode", publicName: "timeMode", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, dateFormat: { classPropertyName: "dateFormat", publicName: "dateFormat", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", range: "rangeChange", disabled: "disabledChange" }, host: { attributes: { "data-slot": "datetime-picker" }, properties: { "class": "computedClass()" } }, providers: [
18495
19036
  { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => BuiDatetimePicker), multi: true },
18496
19037
  ], ngImport: i0, template: `
18497
19038
  <button
@@ -18535,6 +19076,7 @@ class BuiDatetimePicker {
18535
19076
  [minDate]="minDate()"
18536
19077
  [maxDate]="maxDate()"
18537
19078
  [captionLayout]="captionLayout()"
19079
+ [locale]="locale()"
18538
19080
  (rangeChange)="onRange($event)"
18539
19081
  />
18540
19082
  } @else {
@@ -18543,20 +19085,23 @@ class BuiDatetimePicker {
18543
19085
  [minDate]="minDate()"
18544
19086
  [maxDate]="maxDate()"
18545
19087
  [captionLayout]="captionLayout()"
19088
+ [locale]="locale()"
18546
19089
  (valueChange)="onDate($event)"
18547
19090
  />
18548
19091
  }
18549
19092
  <div class="flex items-center gap-2 border-t p-2">
18550
- <span class="text-xs text-muted-foreground">Time</span>
19093
+ <span class="text-xs text-muted-foreground">{{ timeText() }}</span>
18551
19094
  <bui-time-field
18552
19095
  [value]="timePart()"
18553
19096
  [seconds]="seconds()"
19097
+ [mode]="timeMode()"
19098
+ [locale]="locale()"
18554
19099
  (valueChange)="onTime($event)"
18555
19100
  />
18556
19101
  </div>
18557
19102
  </div>
18558
19103
  </ng-template>
18559
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i1.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "component", type: BuiCalendar, selector: "bui-calendar", inputs: ["value", "mode", "range", "values", "months", "weekStart", "minDate", "maxDate", "disabledDates", "disableWeekends", "showWeekNumbers", "captionLayout", "hideOutsideDays", "disabled", "class", "previousMonthLabel", "monthSelectLabel", "yearLabel", "nextMonthLabel"], outputs: ["valueChange", "rangeChange", "valuesChange", "disabledChange"] }, { kind: "component", type: BuiTimeField, selector: "bui-time-field", inputs: ["value", "name", "id", "min", "max", "seconds", "disabled", "mode", "minuteStep", "ariaLabel", "class"], outputs: ["valueChange", "disabledChange"] }] });
19104
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i1.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "component", type: BuiCalendar, selector: "bui-calendar", inputs: ["value", "mode", "range", "values", "months", "weekStart", "minDate", "maxDate", "disabledDates", "disableWeekends", "showWeekNumbers", "captionLayout", "hideOutsideDays", "disabled", "class", "locale", "monthFormat", "weekdayFormat", "weekdayLabels", "previousMonthLabel", "monthSelectLabel", "yearLabel", "nextMonthLabel", "weekLabel"], outputs: ["valueChange", "rangeChange", "valuesChange", "disabledChange"] }, { kind: "component", type: BuiTimeField, selector: "bui-time-field", inputs: ["value", "name", "id", "min", "max", "seconds", "disabled", "mode", "minuteStep", "ariaLabel", "class", "locale", "hourCycle"], outputs: ["valueChange", "disabledChange"] }] });
18560
19105
  }
18561
19106
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiDatetimePicker, decorators: [{
18562
19107
  type: Component,
@@ -18612,6 +19157,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
18612
19157
  [minDate]="minDate()"
18613
19158
  [maxDate]="maxDate()"
18614
19159
  [captionLayout]="captionLayout()"
19160
+ [locale]="locale()"
18615
19161
  (rangeChange)="onRange($event)"
18616
19162
  />
18617
19163
  } @else {
@@ -18620,14 +19166,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
18620
19166
  [minDate]="minDate()"
18621
19167
  [maxDate]="maxDate()"
18622
19168
  [captionLayout]="captionLayout()"
19169
+ [locale]="locale()"
18623
19170
  (valueChange)="onDate($event)"
18624
19171
  />
18625
19172
  }
18626
19173
  <div class="flex items-center gap-2 border-t p-2">
18627
- <span class="text-xs text-muted-foreground">Time</span>
19174
+ <span class="text-xs text-muted-foreground">{{ timeText() }}</span>
18628
19175
  <bui-time-field
18629
19176
  [value]="timePart()"
18630
19177
  [seconds]="seconds()"
19178
+ [mode]="timeMode()"
19179
+ [locale]="locale()"
18631
19180
  (valueChange)="onTime($event)"
18632
19181
  />
18633
19182
  </div>
@@ -18635,7 +19184,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
18635
19184
  </ng-template>
18636
19185
  `,
18637
19186
  }]
18638
- }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], range: [{ type: i0.Input, args: [{ isSignal: true, alias: "range", required: false }] }, { type: i0.Output, args: ["rangeChange"] }], months: [{ type: i0.Input, args: [{ isSignal: true, alias: "months", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], minDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "minDate", required: false }] }], maxDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxDate", required: false }] }], captionLayout: [{ type: i0.Input, args: [{ isSignal: true, alias: "captionLayout", required: false }] }], seconds: [{ type: i0.Input, args: [{ isSignal: true, alias: "seconds", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
19187
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], range: [{ type: i0.Input, args: [{ isSignal: true, alias: "range", required: false }] }, { type: i0.Output, args: ["rangeChange"] }], months: [{ type: i0.Input, args: [{ isSignal: true, alias: "months", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], timeLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "timeLabel", required: false }] }], minDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "minDate", required: false }] }], maxDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxDate", required: false }] }], captionLayout: [{ type: i0.Input, args: [{ isSignal: true, alias: "captionLayout", required: false }] }], seconds: [{ type: i0.Input, args: [{ isSignal: true, alias: "seconds", required: false }] }], timeMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "timeMode", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], dateFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFormat", required: false }] }] } });
18639
19188
 
18640
19189
  /** Suggestion panel placement relative to the field, in CDK preference order. */
18641
19190
  const PANEL_POSITIONS$1 = [
@@ -20412,15 +20961,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
20412
20961
  }]
20413
20962
  }], propDecorators: { lat: [{ type: i0.Input, args: [{ isSignal: true, alias: "lat", required: false }] }], lon: [{ type: i0.Input, args: [{ isSignal: true, alias: "lon", required: false }] }], zoom: [{ type: i0.Input, args: [{ isSignal: true, alias: "zoom", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], marker: [{ type: i0.Input, args: [{ isSignal: true, alias: "marker", required: false }] }], height: [{ type: i0.Input, args: [{ isSignal: true, alias: "height", required: false }] }], ratio: [{ type: i0.Input, args: [{ isSignal: true, alias: "ratio", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
20414
20963
 
20964
+ /** Pattern of the axis bound labels ("Jul 16") — matches the pre-locale rendering in `en-US`. */
20965
+ const DEFAULT_DATE_FORMAT = { month: 'short', day: 'numeric' };
20415
20966
  function toDay(iso) {
20416
20967
  return Math.floor(new Date(`${iso}T00:00:00`).getTime() / 86_400_000);
20417
20968
  }
20418
- function label(iso) {
20419
- return new Date(`${iso}T00:00:00`).toLocaleDateString('en-US', {
20420
- month: 'short',
20421
- day: 'numeric',
20422
- });
20423
- }
20424
20969
  /** A horizontal Gantt chart positioning task bars over a date range. SSR-safe. */
20425
20970
  class BuiGantt {
20426
20971
  /** Tasks to plot as horizontal bars across the date range. */
@@ -20436,6 +20981,27 @@ class BuiGantt {
20436
20981
  end = input('', /* @ts-ignore */
20437
20982
  ...(ngDevMode ? [{ debugName: "end" }] : /* istanbul ignore next */ []));
20438
20983
  userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : /* istanbul ignore next */ {}), alias: 'class' });
20984
+ /** BCP 47 locale used for the axis bound labels. Defaults to the app's `LOCALE_ID`. */
20985
+ locale = input(/* @ts-ignore */
20986
+ ...(ngDevMode ? [undefined, { debugName: "locale" }] : /* istanbul ignore next */ []));
20987
+ /**
20988
+ * `Intl.DateTimeFormat` options for the axis bound labels. Replaces the default wholesale, so
20989
+ * `{ dateStyle: 'short' }` is valid (its options cannot be mixed with `month`/`day`).
20990
+ */
20991
+ dateFormat = input(DEFAULT_DATE_FORMAT, /* @ts-ignore */
20992
+ ...(ngDevMode ? [{ debugName: "dateFormat" }] : /* istanbul ignore next */ []));
20993
+ /** Text shown when there are no tasks to plot. Falls back to `provideBuiLabels`. */
20994
+ emptyLabel = input(/* @ts-ignore */
20995
+ ...(ngDevMode ? [undefined, { debugName: "emptyLabel" }] : /* istanbul ignore next */ []));
20996
+ emptyText = buiLabel('ganttEmpty', this.emptyLabel);
20997
+ resolvedLocale = buiLocale(this.locale);
20998
+ formatter = computed(() =>
20999
+ // Gregorian by default so the bounds agree with the day-indexed axis; caller's options win.
21000
+ new Intl.DateTimeFormat(this.resolvedLocale(), {
21001
+ calendar: BUI_GRID_CALENDAR,
21002
+ ...this.dateFormat(),
21003
+ }), /* @ts-ignore */
21004
+ ...(ngDevMode ? [{ debugName: "formatter" }] : /* istanbul ignore next */ []));
20439
21005
  milestoneRows = computed(() => {
20440
21006
  const { min, span } = this.bounds();
20441
21007
  return this.milestones()
@@ -20452,7 +21018,11 @@ class BuiGantt {
20452
21018
  const ends = tasks.map((task) => toDay(task.end));
20453
21019
  const min = this.start() === '' ? Math.min(...starts) : toDay(this.start());
20454
21020
  const max = this.end() === '' ? Math.max(...ends) : toDay(this.end());
20455
- return { tasks, min, max, span: Math.max(1, max - min) };
21021
+ // Keep the latest end as its ISO string: `toDay` counts days from a *local* midnight, so
21022
+ // turning a day index back into a Date resolves to the day before east of UTC.
21023
+ // No tasks -> `Math.max()` is -Infinity -> `indexOf` misses -> empty label, no throw.
21024
+ const maxIso = tasks[ends.indexOf(Math.max(...ends))]?.end ?? '';
21025
+ return { tasks, min, max, maxIso, span: Math.max(1, max - min) };
20456
21026
  }, /* @ts-ignore */
20457
21027
  ...(ngDevMode ? [{ debugName: "bounds" }] : /* istanbul ignore next */ []));
20458
21028
  rows = computed(() => {
@@ -20472,24 +21042,27 @@ class BuiGantt {
20472
21042
  ...(ngDevMode ? [{ debugName: "rows" }] : /* istanbul ignore next */ []));
20473
21043
  rangeStart = computed(() => {
20474
21044
  const start = this.start();
20475
- return label(start === '' ? (this.tasks().at(0)?.start ?? '') : start);
21045
+ return this.label(start === '' ? (this.tasks().at(0)?.start ?? '') : start);
20476
21046
  }, /* @ts-ignore */
20477
21047
  ...(ngDevMode ? [{ debugName: "rangeStart" }] : /* istanbul ignore next */ []));
20478
21048
  rangeEnd = computed(() => {
20479
- const { tasks, max } = this.bounds();
21049
+ const { maxIso } = this.bounds();
20480
21050
  const end = this.end();
20481
- if (end !== '') {
20482
- return label(end);
20483
- }
20484
- return tasks.length > 0
20485
- ? new Date(max * 86_400_000).toLocaleDateString('en-US', { month: 'short', day: 'numeric' })
20486
- : '';
21051
+ return this.label(end === '' ? maxIso : end);
20487
21052
  }, /* @ts-ignore */
20488
21053
  ...(ngDevMode ? [{ debugName: "rangeEnd" }] : /* istanbul ignore next */ []));
20489
21054
  computedClass = computed(() => cn('block', this.userClass()), /* @ts-ignore */
20490
21055
  ...(ngDevMode ? [{ debugName: "computedClass" }] : /* istanbul ignore next */ []));
21056
+ label(iso) {
21057
+ return this.format(new Date(`${iso}T00:00:00`));
21058
+ }
21059
+ /** `Intl` throws on an invalid date where `toLocaleDateString` returned "Invalid Date"; an
21060
+ * empty bound (a task with no `start`) is a caller mistake, not a reason to break the chart. */
21061
+ format(date) {
21062
+ return Number.isNaN(date.getTime()) ? '' : this.formatter().format(date);
21063
+ }
20491
21064
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiGantt, deps: [], target: i0.ɵɵFactoryTarget.Component });
20492
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: BuiGantt, isStandalone: true, selector: "bui-gantt", inputs: { tasks: { classPropertyName: "tasks", publicName: "tasks", isSignal: true, isRequired: false, transformFunction: null }, milestones: { classPropertyName: "milestones", publicName: "milestones", isSignal: true, isRequired: false, transformFunction: null }, start: { classPropertyName: "start", publicName: "start", isSignal: true, isRequired: false, transformFunction: null }, end: { classPropertyName: "end", publicName: "end", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "data-slot": "gantt" }, properties: { "class": "computedClass()" } }, ngImport: i0, template: `
21065
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: BuiGantt, isStandalone: true, selector: "bui-gantt", inputs: { tasks: { classPropertyName: "tasks", publicName: "tasks", isSignal: true, isRequired: false, transformFunction: null }, milestones: { classPropertyName: "milestones", publicName: "milestones", isSignal: true, isRequired: false, transformFunction: null }, start: { classPropertyName: "start", publicName: "start", isSignal: true, isRequired: false, transformFunction: null }, end: { classPropertyName: "end", publicName: "end", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, dateFormat: { classPropertyName: "dateFormat", publicName: "dateFormat", isSignal: true, isRequired: false, transformFunction: null }, emptyLabel: { classPropertyName: "emptyLabel", publicName: "emptyLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "data-slot": "gantt" }, properties: { "class": "computedClass()" } }, ngImport: i0, template: `
20493
21066
  <div class="space-y-2">
20494
21067
  @for (row of rows(); track row.name) {
20495
21068
  <div class="grid grid-cols-[8rem_1fr] items-center gap-3">
@@ -20508,7 +21081,7 @@ class BuiGantt {
20508
21081
  </div>
20509
21082
  </div>
20510
21083
  } @empty {
20511
- <p class="text-sm text-muted-foreground">No tasks.</p>
21084
+ <p class="text-sm text-muted-foreground">{{ emptyText() }}</p>
20512
21085
  }
20513
21086
  @for (milestone of milestoneRows(); track milestone.name) {
20514
21087
  <div class="grid grid-cols-[8rem_1fr] items-center gap-3">
@@ -20558,7 +21131,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
20558
21131
  </div>
20559
21132
  </div>
20560
21133
  } @empty {
20561
- <p class="text-sm text-muted-foreground">No tasks.</p>
21134
+ <p class="text-sm text-muted-foreground">{{ emptyText() }}</p>
20562
21135
  }
20563
21136
  @for (milestone of milestoneRows(); track milestone.name) {
20564
21137
  <div class="grid grid-cols-[8rem_1fr] items-center gap-3">
@@ -20584,7 +21157,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
20584
21157
  }
20585
21158
  `,
20586
21159
  }]
20587
- }], propDecorators: { tasks: [{ type: i0.Input, args: [{ isSignal: true, alias: "tasks", required: false }] }], milestones: [{ type: i0.Input, args: [{ isSignal: true, alias: "milestones", required: false }] }], start: [{ type: i0.Input, args: [{ isSignal: true, alias: "start", required: false }] }], end: [{ type: i0.Input, args: [{ isSignal: true, alias: "end", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
21160
+ }], propDecorators: { tasks: [{ type: i0.Input, args: [{ isSignal: true, alias: "tasks", required: false }] }], milestones: [{ type: i0.Input, args: [{ isSignal: true, alias: "milestones", required: false }] }], start: [{ type: i0.Input, args: [{ isSignal: true, alias: "start", required: false }] }], end: [{ type: i0.Input, args: [{ isSignal: true, alias: "end", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], dateFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFormat", required: false }] }], emptyLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyLabel", required: false }] }] } });
20588
21161
 
20589
21162
  const WEEK = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
20590
21163
  function toMinutes(value) {
@@ -21874,5 +22447,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
21874
22447
  * Generated bundle index. Do not edit.
21875
22448
  */
21876
22449
 
21877
- export { BUI_DEFAULT_LABELS, BUI_LABELS, BuiAccent, BuiAccordion, BuiAccordionContent, BuiAccordionItem, BuiAccordionTrigger, BuiAddToCart, BuiAlert, BuiAlertDescription, BuiAlertDialogAction, BuiAlertDialogCancel, BuiAlertDialogContent, BuiAlertDialogDescription, BuiAlertDialogFooter, BuiAlertDialogHeader, BuiAlertDialogTitle, BuiAlertTitle, BuiAnimatedBeam, BuiAspectRatio, BuiAudioPlayer, BuiAurora, BuiAutocomplete, BuiAutosizeTextarea, BuiAvatar, BuiAvatarGroup, BuiBackToTop, BuiBadge, BuiBanner, BuiBentoGrid, BuiBentoItem, BuiBorderBeam, BuiBottomNavigation, BuiBottomNavigationItem, BuiBreadcrumb, BuiBreadcrumbEllipsis, BuiBreadcrumbItem, BuiBreadcrumbLink, BuiBreadcrumbList, BuiBreadcrumbPage, BuiBreadcrumbSeparator, BuiButton, BuiButtonGroup, BuiButtonGroupText, BuiCalendar, BuiCard, BuiCardAction, BuiCardContent, BuiCardDescription, BuiCardFooter, BuiCardHeader, BuiCardTitle, BuiCarousel, BuiChart, BuiChat, BuiChatMessage, BuiCheckbox, BuiCitation, BuiCodeBlock, BuiCollapsible, BuiCollapsibleContent, BuiCollapsibleTrigger, BuiColorPicker, BuiCombobox, BuiCommand, BuiComparisonSlider, BuiComparisonTable, BuiConfetti, BuiContainer, BuiContextMenu, BuiCookieConsent, BuiCopyButton, BuiCountdown, BuiDataTable, BuiDatePicker, BuiDateRangePicker, BuiDatetimePicker, BuiDescriptionItem, BuiDescriptionList, BuiDialogContent, BuiDialogDescription, BuiDialogFooter, BuiDialogHeader, BuiDialogTitle, BuiDiffViewer, BuiDock, BuiDockItem, BuiDotPattern, BuiDrawer, BuiDropdownMenu, BuiDropdownMenuItem, BuiDropdownMenuLabel, BuiDropdownMenuSeparator, BuiEditable, BuiEmpty, BuiEmptyContent, BuiEmptyDescription, BuiEmptyHeader, BuiEmptyMedia, BuiEmptyTitle, BuiField, BuiFieldContent, BuiFieldDescription, BuiFieldError, BuiFieldGroup, BuiFieldLabel, BuiFieldLegend, BuiFieldSeparator, BuiFieldSet, BuiFieldTitle, BuiFileUpload, BuiFlipCard, BuiGallery, BuiGantt, BuiGradientText, BuiGridPattern, BuiHeatmap, BuiHoverCard, BuiHoverCardContent, BuiIconTile, BuiImage, BuiInfiniteScroll, BuiInput, BuiInputField, BuiInputGroup, BuiInputGroupAddon, BuiInputGroupButton, BuiInputGroupInput, BuiInputGroupText, BuiInputMask, BuiInputOtp, BuiItem, BuiItemActions, BuiItemContent, BuiItemDescription, BuiItemGroup, BuiItemMedia, BuiItemTitle, BuiJsonViewer, BuiJsonViewerNode, BuiKanban, BuiKbd, BuiKbdGroup, BuiKnob, BuiLabel, BuiLink, BuiLoadingOverlay, BuiMap, BuiMarkdownEditor, BuiMarquee, BuiMasonry, BuiMentionInput, BuiMenubar, BuiMenubarTrigger, BuiMeteors, BuiMeter, BuiMiniCart, BuiMoneyInput, BuiNavigationMenu, BuiNotificationCenter, BuiNumberInput, BuiNumberTicker, BuiOnboardingTour, BuiOrgChart, BuiOrgChartNode, BuiPageHeader, BuiPagination, BuiPaginationContent, BuiPaginationEllipsis, BuiPaginationItem, BuiPaginationLink, BuiParallax, BuiPasswordStrength, BuiPhoneInput, BuiPopover, BuiPopoverContent, BuiPresence, BuiPrice, BuiProductCard, BuiProgress, BuiPromptInput, BuiQrCode, BuiQuantitySelector, BuiQuote, BuiRadioGroup, BuiRadioGroupItem, BuiRating, BuiReasoning, BuiRepeater, BuiResizableHandle, BuiResizablePanel, BuiResizablePanelGroup, BuiRichTextEditor, BuiScheduler, BuiScrollArea, BuiScrollspy, BuiSegmentedControl, BuiSelect, BuiSeparator, BuiSheet, BuiSidebar, BuiSidebarInset, BuiSidebarMenuButton, BuiSidebarProvider, BuiSidebarState, BuiSidebarTrigger, BuiSignaturePad, BuiSkeleton, BuiSlider, BuiSonner, BuiSparkline, BuiSpeedDial, BuiSpinner, BuiSpotlightCard, BuiStack, BuiStat, BuiStepper, BuiStepperItem, BuiStreamingText, BuiSwitch, BuiTabList, BuiTabPanel, BuiTabTrigger, BuiTable, BuiTableBody, BuiTableCaption, BuiTableCell, BuiTableContainer, BuiTableFooter, BuiTableHead, BuiTableHeader, BuiTableRow, BuiTabs, BuiTagsInput, BuiTerminal, BuiTextReveal, BuiTextarea, BuiThemeCustomizer, BuiTiltCard, BuiTimeField, BuiTimeline, BuiTimelineItem, BuiToaster, BuiToggle, BuiToggleGroup, BuiToggleGroupItem, BuiToolCall, BuiTooltip, BuiTooltipContent, BuiTopProgress, BuiTree, BuiTreeNode, BuiTreeTable, BuiTypewriter, BuiTypography, BuiVariantSelector, BuiVideo, BuiVisuallyHidden, THEME_TOKENS, ThemeStore, buiLabel, buttonVariants, cn, encodeQr, provideBuiLabels, toggleVariants };
22450
+ export { BUI_DEFAULT_LABELS, BUI_GRID_CALENDAR, BUI_LABELS, BuiAccent, BuiAccordion, BuiAccordionContent, BuiAccordionItem, BuiAccordionTrigger, BuiAddToCart, BuiAlert, BuiAlertDescription, BuiAlertDialogAction, BuiAlertDialogCancel, BuiAlertDialogContent, BuiAlertDialogDescription, BuiAlertDialogFooter, BuiAlertDialogHeader, BuiAlertDialogTitle, BuiAlertTitle, BuiAnimatedBeam, BuiAspectRatio, BuiAudioPlayer, BuiAurora, BuiAutocomplete, BuiAutosizeTextarea, BuiAvatar, BuiAvatarGroup, BuiBackToTop, BuiBadge, BuiBanner, BuiBentoGrid, BuiBentoItem, BuiBorderBeam, BuiBottomNavigation, BuiBottomNavigationItem, BuiBreadcrumb, BuiBreadcrumbEllipsis, BuiBreadcrumbItem, BuiBreadcrumbLink, BuiBreadcrumbList, BuiBreadcrumbPage, BuiBreadcrumbSeparator, BuiButton, BuiButtonGroup, BuiButtonGroupText, BuiCalendar, BuiCard, BuiCardAction, BuiCardContent, BuiCardDescription, BuiCardFooter, BuiCardHeader, BuiCardTitle, BuiCarousel, BuiChart, BuiChat, BuiChatMessage, BuiCheckbox, BuiCitation, BuiCodeBlock, BuiCollapsible, BuiCollapsibleContent, BuiCollapsibleTrigger, BuiColorPicker, BuiCombobox, BuiCommand, BuiComparisonSlider, BuiComparisonTable, BuiConfetti, BuiContainer, BuiContextMenu, BuiCookieConsent, BuiCopyButton, BuiCountdown, BuiDataTable, BuiDatePicker, BuiDateRangePicker, BuiDatetimePicker, BuiDescriptionItem, BuiDescriptionList, BuiDialogContent, BuiDialogDescription, BuiDialogFooter, BuiDialogHeader, BuiDialogTitle, BuiDiffViewer, BuiDock, BuiDockItem, BuiDotPattern, BuiDrawer, BuiDropdownMenu, BuiDropdownMenuItem, BuiDropdownMenuLabel, BuiDropdownMenuSeparator, BuiEditable, BuiEmpty, BuiEmptyContent, BuiEmptyDescription, BuiEmptyHeader, BuiEmptyMedia, BuiEmptyTitle, BuiField, BuiFieldContent, BuiFieldDescription, BuiFieldError, BuiFieldGroup, BuiFieldLabel, BuiFieldLegend, BuiFieldSeparator, BuiFieldSet, BuiFieldTitle, BuiFileUpload, BuiFlipCard, BuiGallery, BuiGantt, BuiGradientText, BuiGridPattern, BuiHeatmap, BuiHoverCard, BuiHoverCardContent, BuiIconTile, BuiImage, BuiInfiniteScroll, BuiInput, BuiInputField, BuiInputGroup, BuiInputGroupAddon, BuiInputGroupButton, BuiInputGroupInput, BuiInputGroupText, BuiInputMask, BuiInputOtp, BuiItem, BuiItemActions, BuiItemContent, BuiItemDescription, BuiItemGroup, BuiItemMedia, BuiItemTitle, BuiJsonViewer, BuiJsonViewerNode, BuiKanban, BuiKbd, BuiKbdGroup, BuiKnob, BuiLabel, BuiLink, BuiLoadingOverlay, BuiMap, BuiMarkdownEditor, BuiMarquee, BuiMasonry, BuiMentionInput, BuiMenubar, BuiMenubarTrigger, BuiMeteors, BuiMeter, BuiMiniCart, BuiMoneyInput, BuiNavigationMenu, BuiNotificationCenter, BuiNumberInput, BuiNumberTicker, BuiOnboardingTour, BuiOrgChart, BuiOrgChartNode, BuiPageHeader, BuiPagination, BuiPaginationContent, BuiPaginationEllipsis, BuiPaginationItem, BuiPaginationLink, BuiParallax, BuiPasswordStrength, BuiPhoneInput, BuiPopover, BuiPopoverContent, BuiPresence, BuiPrice, BuiProductCard, BuiProgress, BuiPromptInput, BuiQrCode, BuiQuantitySelector, BuiQuote, BuiRadioGroup, BuiRadioGroupItem, BuiRating, BuiReasoning, BuiRepeater, BuiResizableHandle, BuiResizablePanel, BuiResizablePanelGroup, BuiRichTextEditor, BuiScheduler, BuiScrollArea, BuiScrollspy, BuiSegmentedControl, BuiSelect, BuiSeparator, BuiSheet, BuiSidebar, BuiSidebarInset, BuiSidebarMenuButton, BuiSidebarProvider, BuiSidebarState, BuiSidebarTrigger, BuiSignaturePad, BuiSkeleton, BuiSlider, BuiSonner, BuiSparkline, BuiSpeedDial, BuiSpinner, BuiSpotlightCard, BuiStack, BuiStat, BuiStepper, BuiStepperItem, BuiStreamingText, BuiSwitch, BuiTabList, BuiTabPanel, BuiTabTrigger, BuiTable, BuiTableBody, BuiTableCaption, BuiTableCell, BuiTableContainer, BuiTableFooter, BuiTableHead, BuiTableHeader, BuiTableRow, BuiTabs, BuiTagsInput, BuiTerminal, BuiTextReveal, BuiTextarea, BuiThemeCustomizer, BuiTiltCard, BuiTimeField, BuiTimeline, BuiTimelineItem, BuiToaster, BuiToggle, BuiToggleGroup, BuiToggleGroupItem, BuiToolCall, BuiTooltip, BuiTooltipContent, BuiTopProgress, BuiTree, BuiTreeNode, BuiTreeTable, BuiTypewriter, BuiTypography, BuiVariantSelector, BuiVideo, BuiVisuallyHidden, THEME_TOKENS, ThemeStore, buiLabel, buiLocale, buiWeekInfo, buttonVariants, cn, encodeQr, provideBuiLabels, toggleVariants };
21878
22451
  //# sourceMappingURL=ng-blatui.mjs.map