@open-mercato/ui 0.6.2-develop.3406.1.2b403f40da → 0.6.2-develop.3446.1.bd060c6017

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/ai/AiAssistantLauncher.js +11 -10
  3. package/dist/ai/AiAssistantLauncher.js.map +2 -2
  4. package/dist/ai/AiChat.js +218 -83
  5. package/dist/ai/AiChat.js.map +2 -2
  6. package/dist/ai/AiIcon.js +1 -1
  7. package/dist/ai/AiIcon.js.map +2 -2
  8. package/dist/ai/parts/FieldDiffCard.js +4 -3
  9. package/dist/ai/parts/FieldDiffCard.js.map +2 -2
  10. package/dist/ai/useAiChat.js +98 -2
  11. package/dist/ai/useAiChat.js.map +2 -2
  12. package/dist/backend/DataTable.js +4 -13
  13. package/dist/backend/DataTable.js.map +2 -2
  14. package/dist/primitives/date-format.js +53 -0
  15. package/dist/primitives/date-format.js.map +7 -0
  16. package/dist/primitives/date-picker.js +3 -26
  17. package/dist/primitives/date-picker.js.map +2 -2
  18. package/dist/primitives/date-range-picker.js +3 -22
  19. package/dist/primitives/date-range-picker.js.map +2 -2
  20. package/package.json +4 -4
  21. package/src/ai/AiAssistantLauncher.tsx +11 -10
  22. package/src/ai/AiChat.tsx +200 -26
  23. package/src/ai/AiIcon.tsx +1 -1
  24. package/src/ai/__tests__/AiChat.task-plan.test.tsx +356 -0
  25. package/src/ai/__tests__/AiChat.test.tsx +44 -2
  26. package/src/ai/parts/FieldDiffCard.tsx +4 -3
  27. package/src/ai/parts/__tests__/FieldDiffCard.test.tsx +24 -0
  28. package/src/ai/parts/types.ts +3 -0
  29. package/src/ai/useAiChat.ts +154 -1
  30. package/src/backend/DataTable.tsx +12 -22
  31. package/src/primitives/__tests__/date-format.test.ts +43 -0
  32. package/src/primitives/date-format.ts +60 -0
  33. package/src/primitives/date-picker.tsx +5 -17
  34. package/src/primitives/date-range-picker.tsx +3 -13
@@ -0,0 +1,53 @@
1
+ import { format as formatDateFns } from "date-fns";
2
+ const DAY_FIRST_LOCALE_CODES = /* @__PURE__ */ new Set([
3
+ "pl",
4
+ "de",
5
+ "fr",
6
+ "es",
7
+ "it",
8
+ "pt",
9
+ "nl",
10
+ "ru",
11
+ "cs",
12
+ "sk",
13
+ "hu",
14
+ "ro"
15
+ ]);
16
+ const SYSTEM_FORMAT_VALUES = /* @__PURE__ */ new Set(["auto", "default", "locale", "system"]);
17
+ function getLocaleCode(locale) {
18
+ if (!locale) return "";
19
+ if (typeof locale === "string") return locale.split("-")[0]?.toLowerCase() ?? "";
20
+ return locale.code?.split("-")[0]?.toLowerCase() ?? "";
21
+ }
22
+ function normalizeDateFormatPattern(value) {
23
+ const trimmed = value?.trim();
24
+ if (!trimmed) return null;
25
+ if (SYSTEM_FORMAT_VALUES.has(trimmed.toLowerCase())) return null;
26
+ return trimmed.replace(/YYYY/g, "yyyy").replace(/YY/g, "yy").replace(/DD/g, "dd");
27
+ }
28
+ function deriveDateDisplayFormat(locale) {
29
+ const code = getLocaleCode(locale);
30
+ return code && DAY_FIRST_LOCALE_CODES.has(code) ? "d MMM yyyy" : "MMM d, yyyy";
31
+ }
32
+ function resolvePublicDateFormat(locale, explicitFormat) {
33
+ return normalizeDateFormatPattern(explicitFormat) ?? normalizeDateFormatPattern(process.env.NEXT_PUBLIC_OM_DATE_FORMAT) ?? normalizeDateFormatPattern(process.env.NEXT_PUBLIC_DATE_FORMAT) ?? deriveDateDisplayFormat(locale);
34
+ }
35
+ function resolvePublicDateTimeFormat(locale, explicitFormat) {
36
+ const dateFormat = deriveDateDisplayFormat(locale);
37
+ return normalizeDateFormatPattern(explicitFormat) ?? normalizeDateFormatPattern(process.env.NEXT_PUBLIC_OM_DATE_TIME_FORMAT) ?? normalizeDateFormatPattern(process.env.NEXT_PUBLIC_DATE_TIME_FORMAT) ?? normalizeDateFormatPattern(process.env.NEXT_PUBLIC_OM_DATE_FORMAT) ?? normalizeDateFormatPattern(process.env.NEXT_PUBLIC_DATE_FORMAT) ?? `${dateFormat} HH:mm`;
38
+ }
39
+ function formatWithPublicDateFormat(date, format, locale) {
40
+ try {
41
+ return formatDateFns(date, format, locale ? { locale } : void 0);
42
+ } catch {
43
+ return null;
44
+ }
45
+ }
46
+ export {
47
+ deriveDateDisplayFormat,
48
+ formatWithPublicDateFormat,
49
+ normalizeDateFormatPattern,
50
+ resolvePublicDateFormat,
51
+ resolvePublicDateTimeFormat
52
+ };
53
+ //# sourceMappingURL=date-format.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/primitives/date-format.ts"],
4
+ "sourcesContent": ["import { format as formatDateFns } from 'date-fns'\nimport type { Locale } from 'date-fns'\n\ntype LocaleLike = Locale | string | null | undefined\n\nconst DAY_FIRST_LOCALE_CODES = new Set([\n 'pl', 'de', 'fr', 'es', 'it', 'pt', 'nl', 'ru', 'cs', 'sk', 'hu', 'ro',\n])\n\nconst SYSTEM_FORMAT_VALUES = new Set(['auto', 'default', 'locale', 'system'])\n\nfunction getLocaleCode(locale?: LocaleLike): string {\n if (!locale) return ''\n if (typeof locale === 'string') return locale.split('-')[0]?.toLowerCase() ?? ''\n return locale.code?.split('-')[0]?.toLowerCase() ?? ''\n}\n\nexport function normalizeDateFormatPattern(value: string | null | undefined): string | null {\n const trimmed = value?.trim()\n if (!trimmed) return null\n if (SYSTEM_FORMAT_VALUES.has(trimmed.toLowerCase())) return null\n return trimmed\n .replace(/YYYY/g, 'yyyy')\n .replace(/YY/g, 'yy')\n .replace(/DD/g, 'dd')\n}\n\nexport function deriveDateDisplayFormat(locale?: LocaleLike): string {\n const code = getLocaleCode(locale)\n return code && DAY_FIRST_LOCALE_CODES.has(code) ? 'd MMM yyyy' : 'MMM d, yyyy'\n}\n\nexport function resolvePublicDateFormat(locale?: LocaleLike, explicitFormat?: string | null): string {\n return (\n normalizeDateFormatPattern(explicitFormat)\n ?? normalizeDateFormatPattern(process.env.NEXT_PUBLIC_OM_DATE_FORMAT)\n ?? normalizeDateFormatPattern(process.env.NEXT_PUBLIC_DATE_FORMAT)\n ?? deriveDateDisplayFormat(locale)\n )\n}\n\nexport function resolvePublicDateTimeFormat(locale?: LocaleLike, explicitFormat?: string | null): string {\n const dateFormat = deriveDateDisplayFormat(locale)\n return (\n normalizeDateFormatPattern(explicitFormat)\n ?? normalizeDateFormatPattern(process.env.NEXT_PUBLIC_OM_DATE_TIME_FORMAT)\n ?? normalizeDateFormatPattern(process.env.NEXT_PUBLIC_DATE_TIME_FORMAT)\n ?? normalizeDateFormatPattern(process.env.NEXT_PUBLIC_OM_DATE_FORMAT)\n ?? normalizeDateFormatPattern(process.env.NEXT_PUBLIC_DATE_FORMAT)\n ?? `${dateFormat} HH:mm`\n )\n}\n\nexport function formatWithPublicDateFormat(date: Date, format: string, locale?: Locale): string | null {\n try {\n return formatDateFns(date, format, locale ? { locale } : undefined)\n } catch {\n return null\n }\n}\n"],
5
+ "mappings": "AAAA,SAAS,UAAU,qBAAqB;AAKxC,MAAM,yBAAyB,oBAAI,IAAI;AAAA,EACrC;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AACpE,CAAC;AAED,MAAM,uBAAuB,oBAAI,IAAI,CAAC,QAAQ,WAAW,UAAU,QAAQ,CAAC;AAE5E,SAAS,cAAc,QAA6B;AAClD,MAAI,CAAC,OAAQ,QAAO;AACpB,MAAI,OAAO,WAAW,SAAU,QAAO,OAAO,MAAM,GAAG,EAAE,CAAC,GAAG,YAAY,KAAK;AAC9E,SAAO,OAAO,MAAM,MAAM,GAAG,EAAE,CAAC,GAAG,YAAY,KAAK;AACtD;AAEO,SAAS,2BAA2B,OAAiD;AAC1F,QAAM,UAAU,OAAO,KAAK;AAC5B,MAAI,CAAC,QAAS,QAAO;AACrB,MAAI,qBAAqB,IAAI,QAAQ,YAAY,CAAC,EAAG,QAAO;AAC5D,SAAO,QACJ,QAAQ,SAAS,MAAM,EACvB,QAAQ,OAAO,IAAI,EACnB,QAAQ,OAAO,IAAI;AACxB;AAEO,SAAS,wBAAwB,QAA6B;AACnE,QAAM,OAAO,cAAc,MAAM;AACjC,SAAO,QAAQ,uBAAuB,IAAI,IAAI,IAAI,eAAe;AACnE;AAEO,SAAS,wBAAwB,QAAqB,gBAAwC;AACnG,SACE,2BAA2B,cAAc,KACtC,2BAA2B,QAAQ,IAAI,0BAA0B,KACjE,2BAA2B,QAAQ,IAAI,uBAAuB,KAC9D,wBAAwB,MAAM;AAErC;AAEO,SAAS,4BAA4B,QAAqB,gBAAwC;AACvG,QAAM,aAAa,wBAAwB,MAAM;AACjD,SACE,2BAA2B,cAAc,KACtC,2BAA2B,QAAQ,IAAI,+BAA+B,KACtE,2BAA2B,QAAQ,IAAI,4BAA4B,KACnE,2BAA2B,QAAQ,IAAI,0BAA0B,KACjE,2BAA2B,QAAQ,IAAI,uBAAuB,KAC9D,GAAG,UAAU;AAEpB;AAEO,SAAS,2BAA2B,MAAY,QAAgB,QAAgC;AACrG,MAAI;AACF,WAAO,cAAc,MAAM,QAAQ,SAAS,EAAE,OAAO,IAAI,MAAS;AAAA,EACpE,QAAQ;AACN,WAAO;AAAA,EACT;AACF;",
6
+ "names": []
7
+ }
@@ -1,7 +1,6 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
- import { format } from "date-fns";
5
4
  import { CalendarIcon } from "lucide-react";
6
5
  import { cn } from "@open-mercato/shared/lib/utils";
7
6
  import { useT } from "@open-mercato/shared/lib/i18n/context";
@@ -10,25 +9,7 @@ import { Calendar } from "./calendar.js";
10
9
  import { Button } from "./button.js";
11
10
  import { LinkButton } from "./link-button.js";
12
11
  import { TimeInput } from "../backend/inputs/TimeInput.js";
13
- const DAY_FIRST_LOCALE_CODES = /* @__PURE__ */ new Set([
14
- "pl",
15
- "de",
16
- "fr",
17
- "es",
18
- "it",
19
- "pt",
20
- "nl",
21
- "ru",
22
- "cs",
23
- "sk",
24
- "hu",
25
- "ro"
26
- ]);
27
- function deriveDisplayFormat(locale, withTime) {
28
- const code = locale?.code?.split("-")[0]?.toLowerCase() ?? "";
29
- const dateFmt = code && DAY_FIRST_LOCALE_CODES.has(code) ? "d MMM yyyy" : "MMM d, yyyy";
30
- return withTime ? `${dateFmt} HH:mm` : dateFmt;
31
- }
12
+ import { formatWithPublicDateFormat, resolvePublicDateFormat, resolvePublicDateTimeFormat } from "./date-format.js";
32
13
  function extractTime(date) {
33
14
  return `${String(date.getHours()).padStart(2, "0")}:${String(date.getMinutes()).padStart(2, "0")}`;
34
15
  }
@@ -80,15 +61,11 @@ function DatePicker({
80
61
  React.useEffect(() => {
81
62
  if (open) setDraft(value ?? null);
82
63
  }, [open, value]);
83
- const resolvedFormat = displayFormat ?? deriveDisplayFormat(locale, withTime);
64
+ const resolvedFormat = withTime ? resolvePublicDateTimeFormat(locale, displayFormat) : resolvePublicDateFormat(locale, displayFormat);
84
65
  const placeholderText = placeholder ?? (withTime ? t("ui.dateTimePicker.placeholder", "Pick date and time") : t("ui.datePicker.placeholder", "Pick a date"));
85
66
  const formattedValue = React.useMemo(() => {
86
67
  if (!value) return null;
87
- try {
88
- return format(value, resolvedFormat, locale ? { locale } : void 0);
89
- } catch {
90
- return null;
91
- }
68
+ return formatWithPublicDateFormat(value, resolvedFormat, locale);
92
69
  }, [value, resolvedFormat, locale]);
93
70
  const handleDaySelect = React.useCallback(
94
71
  (day) => {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/primitives/date-picker.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { format } from 'date-fns'\nimport type { Locale } from 'date-fns'\nimport { CalendarIcon } from 'lucide-react'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Popover, PopoverContent, PopoverTrigger } from './popover'\nimport { Calendar } from './calendar'\nimport { Button } from './button'\nimport { LinkButton } from './link-button'\nimport { TimeInput } from '../backend/inputs/TimeInput'\n\nexport type DatePickerFooter = 'apply-cancel' | 'today-clear' | 'none'\n\nexport type DatePickerProps = {\n value?: Date | null\n onChange: (value: Date | null) => void\n placeholder?: string\n size?: 'sm' | 'default'\n disabled?: boolean\n readOnly?: boolean\n /**\n * Footer mode in the popover.\n * - `'apply-cancel'` (default, Figma-aligned): selecting a day stages a draft;\n * Apply commits and closes; Cancel reverts and closes.\n * - `'today-clear'`: legacy behavior \u2014 Today commits today, Clear sets null.\n * - `'none'`: no footer; selecting a day commits immediately and closes.\n */\n footer?: DatePickerFooter\n /**\n * Whether selecting a day commits the value and closes the popover.\n * - In `footer='apply-cancel'`: ignored (commit happens via Apply).\n * - In `footer='today-clear'`: default `true` for backward compatibility.\n * - In `footer='none'`: always `true` (popover always closes after selection).\n */\n closeOnSelect?: boolean\n /**\n * Whether to show the \"Today\" link in `footer='today-clear'` mode. Default `true`.\n * Only meaningful when `footer='today-clear'`.\n */\n showTodayButton?: boolean\n /**\n * Whether to show the \"Clear\" link in `footer='today-clear'` mode. Default `true`.\n * Only meaningful when `footer='today-clear'`.\n */\n showClearButton?: boolean\n withTime?: boolean\n minuteStep?: number\n align?: 'start' | 'center' | 'end'\n minDate?: Date\n maxDate?: Date\n locale?: Locale\n displayFormat?: string\n className?: string\n popoverClassName?: string\n id?: string\n name?: string\n required?: boolean\n 'aria-label'?: string\n 'aria-describedby'?: string\n}\n\nconst DAY_FIRST_LOCALE_CODES = new Set([\n 'pl', 'de', 'fr', 'es', 'it', 'pt', 'nl', 'ru', 'cs', 'sk', 'hu', 'ro',\n])\n\nfunction deriveDisplayFormat(locale: Locale | undefined, withTime: boolean): string {\n const code = locale?.code?.split('-')[0]?.toLowerCase() ?? ''\n const dateFmt = code && DAY_FIRST_LOCALE_CODES.has(code) ? 'd MMM yyyy' : 'MMM d, yyyy'\n return withTime ? `${dateFmt} HH:mm` : dateFmt\n}\n\nfunction extractTime(date: Date): string {\n return `${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`\n}\n\nfunction applyTimeToDate(base: Date, time: string): Date {\n const [hourStr = '0', minuteStr = '0'] = time.split(':')\n const hour = parseInt(hourStr, 10)\n const minute = parseInt(minuteStr, 10)\n const next = new Date(base)\n next.setHours(isNaN(hour) ? 0 : hour, isNaN(minute) ? 0 : minute, 0, 0)\n return next\n}\n\nfunction startOfDay(date: Date): Date {\n const next = new Date(date)\n next.setHours(0, 0, 0, 0)\n return next\n}\n\nexport function DatePicker({\n value,\n onChange,\n placeholder,\n size = 'default',\n disabled = false,\n readOnly = false,\n footer = 'apply-cancel',\n closeOnSelect,\n showTodayButton = true,\n showClearButton = true,\n withTime = false,\n minuteStep = 1,\n align = 'start',\n minDate,\n maxDate,\n locale,\n displayFormat,\n className,\n popoverClassName,\n id,\n name,\n required,\n 'aria-label': ariaLabel,\n 'aria-describedby': ariaDescribedBy,\n}: DatePickerProps) {\n const resolvedCloseOnSelect = closeOnSelect ?? footer === 'today-clear'\n const t = useT()\n const [open, setOpen] = React.useState(false)\n const [draft, setDraft] = React.useState<Date | null>(value ?? null)\n\n const isInteractive = !disabled && !readOnly\n const useDraft = footer === 'apply-cancel'\n\n React.useEffect(() => {\n if (open) setDraft(value ?? null)\n }, [open, value])\n\n const resolvedFormat = displayFormat ?? deriveDisplayFormat(locale, withTime)\n const placeholderText = placeholder ?? (\n withTime\n ? t('ui.dateTimePicker.placeholder', 'Pick date and time')\n : t('ui.datePicker.placeholder', 'Pick a date')\n )\n\n const formattedValue = React.useMemo(() => {\n if (!value) return null\n try {\n return format(value, resolvedFormat, locale ? { locale } : undefined)\n } catch {\n return null\n }\n }, [value, resolvedFormat, locale])\n\n const handleDaySelect = React.useCallback(\n (day: Date | undefined) => {\n if (!day || !isInteractive) return\n const reference = withTime ? (useDraft ? draft : value) : null\n const base = withTime\n ? applyTimeToDate(day, reference ? extractTime(reference) : '00:00')\n : startOfDay(day)\n if (useDraft) {\n setDraft(base)\n } else {\n onChange(base)\n if (footer === 'none' || resolvedCloseOnSelect) setOpen(false)\n }\n },\n [isInteractive, withTime, useDraft, draft, value, footer, resolvedCloseOnSelect, onChange],\n )\n\n const handleTimeChange = React.useCallback(\n (time: string) => {\n const target = useDraft ? draft : value\n if (!target) return\n const next = applyTimeToDate(target, time)\n if (useDraft) setDraft(next)\n else onChange(next)\n },\n [useDraft, draft, value, onChange],\n )\n\n const handleApply = React.useCallback(() => {\n onChange(draft)\n setOpen(false)\n }, [draft, onChange])\n\n const handleCancel = React.useCallback(() => {\n setDraft(value ?? null)\n setOpen(false)\n }, [value])\n\n const handleToday = React.useCallback(() => {\n const today = withTime ? new Date() : startOfDay(new Date())\n onChange(today)\n setOpen(false)\n }, [withTime, onChange])\n\n const handleClear = React.useCallback(() => {\n onChange(null)\n setOpen(false)\n }, [onChange])\n\n const disabledMatcher = React.useMemo(() => {\n if (!minDate && !maxDate) return undefined\n const matchers: import('react-day-picker').Matcher[] = []\n if (minDate) matchers.push({ before: minDate })\n if (maxDate) matchers.push({ after: maxDate })\n return matchers\n }, [minDate, maxDate])\n\n const heightClass = size === 'sm' ? 'h-8 px-2.5 text-xs' : 'h-9 px-3 text-sm'\n const selectedDate = useDraft ? draft : value\n\n return (\n <Popover open={open} onOpenChange={isInteractive ? setOpen : undefined}>\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n id={id}\n name={name}\n aria-label={ariaLabel}\n aria-describedby={ariaDescribedBy}\n aria-haspopup=\"dialog\"\n aria-required={required ? true : undefined}\n data-crud-focus-target=\"\"\n data-slot=\"date-picker-trigger\"\n disabled={disabled}\n className={cn(\n 'w-full inline-flex items-center gap-2 rounded-md border border-input bg-background shadow-xs transition-colors text-left',\n 'focus-visible:outline-none focus-visible:shadow-focus focus-visible:border-foreground',\n 'hover:bg-muted/40',\n 'disabled:bg-bg-disabled disabled:border-border-disabled disabled:shadow-none disabled:hover:bg-bg-disabled disabled:cursor-not-allowed',\n 'aria-invalid:border-destructive',\n heightClass,\n readOnly && 'cursor-default opacity-70',\n !formattedValue && 'text-muted-foreground',\n className,\n )}\n onClick={isInteractive ? undefined : (event) => event.preventDefault()}\n >\n <CalendarIcon className=\"h-4 w-4 shrink-0 text-muted-foreground\" aria-hidden=\"true\" />\n <span className=\"flex-1 truncate\">\n {formattedValue ?? placeholderText}\n </span>\n </button>\n </PopoverTrigger>\n <PopoverContent align={align} className={cn('w-auto p-0', popoverClassName)}>\n <Calendar\n mode=\"single\"\n selected={selectedDate ?? undefined}\n onSelect={handleDaySelect}\n locale={locale}\n disabled={disabledMatcher}\n initialFocus\n />\n {withTime && (\n <div className=\"flex items-center gap-2 border-t px-3 py-2\">\n <span className=\"text-sm text-muted-foreground shrink-0\">\n {t('ui.datePicker.timeLabel', 'Time')}:\n </span>\n <TimeInput\n value={selectedDate ? extractTime(selectedDate) : undefined}\n onChange={handleTimeChange}\n minuteStep={minuteStep}\n disabled={!isInteractive || !selectedDate}\n />\n </div>\n )}\n {footer === 'apply-cancel' && (\n <div className=\"flex items-center justify-end gap-2 border-t px-3 py-2\">\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={handleCancel}>\n {t('ui.datePicker.cancelButton', 'Cancel')}\n </Button>\n <Button type=\"button\" size=\"sm\" onClick={handleApply}>\n {t('ui.datePicker.applyButton', 'Apply')}\n </Button>\n </div>\n )}\n {footer === 'today-clear' && (showTodayButton || showClearButton) && (\n <div className=\"flex items-center justify-between gap-2 border-t px-3 py-2\">\n {showTodayButton ? (\n <LinkButton type=\"button\" variant=\"primary\" onClick={handleToday}>\n {t('ui.datePicker.todayButton', 'Today')}\n </LinkButton>\n ) : null}\n {showClearButton ? (\n <LinkButton type=\"button\" variant=\"gray\" onClick={handleClear} className=\"ml-auto\">\n {t('ui.datePicker.clearButton', 'Clear')}\n </LinkButton>\n ) : null}\n </div>\n )}\n </PopoverContent>\n </Popover>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport type { Locale } from 'date-fns'\nimport { CalendarIcon } from 'lucide-react'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Popover, PopoverContent, PopoverTrigger } from './popover'\nimport { Calendar } from './calendar'\nimport { Button } from './button'\nimport { LinkButton } from './link-button'\nimport { TimeInput } from '../backend/inputs/TimeInput'\nimport { formatWithPublicDateFormat, resolvePublicDateFormat, resolvePublicDateTimeFormat } from './date-format'\n\nexport type DatePickerFooter = 'apply-cancel' | 'today-clear' | 'none'\n\nexport type DatePickerProps = {\n value?: Date | null\n onChange: (value: Date | null) => void\n placeholder?: string\n size?: 'sm' | 'default'\n disabled?: boolean\n readOnly?: boolean\n /**\n * Footer mode in the popover.\n * - `'apply-cancel'` (default, Figma-aligned): selecting a day stages a draft;\n * Apply commits and closes; Cancel reverts and closes.\n * - `'today-clear'`: legacy behavior \u2014 Today commits today, Clear sets null.\n * - `'none'`: no footer; selecting a day commits immediately and closes.\n */\n footer?: DatePickerFooter\n /**\n * Whether selecting a day commits the value and closes the popover.\n * - In `footer='apply-cancel'`: ignored (commit happens via Apply).\n * - In `footer='today-clear'`: default `true` for backward compatibility.\n * - In `footer='none'`: always `true` (popover always closes after selection).\n */\n closeOnSelect?: boolean\n /**\n * Whether to show the \"Today\" link in `footer='today-clear'` mode. Default `true`.\n * Only meaningful when `footer='today-clear'`.\n */\n showTodayButton?: boolean\n /**\n * Whether to show the \"Clear\" link in `footer='today-clear'` mode. Default `true`.\n * Only meaningful when `footer='today-clear'`.\n */\n showClearButton?: boolean\n withTime?: boolean\n minuteStep?: number\n align?: 'start' | 'center' | 'end'\n minDate?: Date\n maxDate?: Date\n locale?: Locale\n displayFormat?: string\n className?: string\n popoverClassName?: string\n id?: string\n name?: string\n required?: boolean\n 'aria-label'?: string\n 'aria-describedby'?: string\n}\n\nfunction extractTime(date: Date): string {\n return `${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`\n}\n\nfunction applyTimeToDate(base: Date, time: string): Date {\n const [hourStr = '0', minuteStr = '0'] = time.split(':')\n const hour = parseInt(hourStr, 10)\n const minute = parseInt(minuteStr, 10)\n const next = new Date(base)\n next.setHours(isNaN(hour) ? 0 : hour, isNaN(minute) ? 0 : minute, 0, 0)\n return next\n}\n\nfunction startOfDay(date: Date): Date {\n const next = new Date(date)\n next.setHours(0, 0, 0, 0)\n return next\n}\n\nexport function DatePicker({\n value,\n onChange,\n placeholder,\n size = 'default',\n disabled = false,\n readOnly = false,\n footer = 'apply-cancel',\n closeOnSelect,\n showTodayButton = true,\n showClearButton = true,\n withTime = false,\n minuteStep = 1,\n align = 'start',\n minDate,\n maxDate,\n locale,\n displayFormat,\n className,\n popoverClassName,\n id,\n name,\n required,\n 'aria-label': ariaLabel,\n 'aria-describedby': ariaDescribedBy,\n}: DatePickerProps) {\n const resolvedCloseOnSelect = closeOnSelect ?? footer === 'today-clear'\n const t = useT()\n const [open, setOpen] = React.useState(false)\n const [draft, setDraft] = React.useState<Date | null>(value ?? null)\n\n const isInteractive = !disabled && !readOnly\n const useDraft = footer === 'apply-cancel'\n\n React.useEffect(() => {\n if (open) setDraft(value ?? null)\n }, [open, value])\n\n const resolvedFormat = withTime\n ? resolvePublicDateTimeFormat(locale, displayFormat)\n : resolvePublicDateFormat(locale, displayFormat)\n const placeholderText = placeholder ?? (\n withTime\n ? t('ui.dateTimePicker.placeholder', 'Pick date and time')\n : t('ui.datePicker.placeholder', 'Pick a date')\n )\n\n const formattedValue = React.useMemo(() => {\n if (!value) return null\n return formatWithPublicDateFormat(value, resolvedFormat, locale)\n }, [value, resolvedFormat, locale])\n\n const handleDaySelect = React.useCallback(\n (day: Date | undefined) => {\n if (!day || !isInteractive) return\n const reference = withTime ? (useDraft ? draft : value) : null\n const base = withTime\n ? applyTimeToDate(day, reference ? extractTime(reference) : '00:00')\n : startOfDay(day)\n if (useDraft) {\n setDraft(base)\n } else {\n onChange(base)\n if (footer === 'none' || resolvedCloseOnSelect) setOpen(false)\n }\n },\n [isInteractive, withTime, useDraft, draft, value, footer, resolvedCloseOnSelect, onChange],\n )\n\n const handleTimeChange = React.useCallback(\n (time: string) => {\n const target = useDraft ? draft : value\n if (!target) return\n const next = applyTimeToDate(target, time)\n if (useDraft) setDraft(next)\n else onChange(next)\n },\n [useDraft, draft, value, onChange],\n )\n\n const handleApply = React.useCallback(() => {\n onChange(draft)\n setOpen(false)\n }, [draft, onChange])\n\n const handleCancel = React.useCallback(() => {\n setDraft(value ?? null)\n setOpen(false)\n }, [value])\n\n const handleToday = React.useCallback(() => {\n const today = withTime ? new Date() : startOfDay(new Date())\n onChange(today)\n setOpen(false)\n }, [withTime, onChange])\n\n const handleClear = React.useCallback(() => {\n onChange(null)\n setOpen(false)\n }, [onChange])\n\n const disabledMatcher = React.useMemo(() => {\n if (!minDate && !maxDate) return undefined\n const matchers: import('react-day-picker').Matcher[] = []\n if (minDate) matchers.push({ before: minDate })\n if (maxDate) matchers.push({ after: maxDate })\n return matchers\n }, [minDate, maxDate])\n\n const heightClass = size === 'sm' ? 'h-8 px-2.5 text-xs' : 'h-9 px-3 text-sm'\n const selectedDate = useDraft ? draft : value\n\n return (\n <Popover open={open} onOpenChange={isInteractive ? setOpen : undefined}>\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n id={id}\n name={name}\n aria-label={ariaLabel}\n aria-describedby={ariaDescribedBy}\n aria-haspopup=\"dialog\"\n aria-required={required ? true : undefined}\n data-crud-focus-target=\"\"\n data-slot=\"date-picker-trigger\"\n disabled={disabled}\n className={cn(\n 'w-full inline-flex items-center gap-2 rounded-md border border-input bg-background shadow-xs transition-colors text-left',\n 'focus-visible:outline-none focus-visible:shadow-focus focus-visible:border-foreground',\n 'hover:bg-muted/40',\n 'disabled:bg-bg-disabled disabled:border-border-disabled disabled:shadow-none disabled:hover:bg-bg-disabled disabled:cursor-not-allowed',\n 'aria-invalid:border-destructive',\n heightClass,\n readOnly && 'cursor-default opacity-70',\n !formattedValue && 'text-muted-foreground',\n className,\n )}\n onClick={isInteractive ? undefined : (event) => event.preventDefault()}\n >\n <CalendarIcon className=\"h-4 w-4 shrink-0 text-muted-foreground\" aria-hidden=\"true\" />\n <span className=\"flex-1 truncate\">\n {formattedValue ?? placeholderText}\n </span>\n </button>\n </PopoverTrigger>\n <PopoverContent align={align} className={cn('w-auto p-0', popoverClassName)}>\n <Calendar\n mode=\"single\"\n selected={selectedDate ?? undefined}\n onSelect={handleDaySelect}\n locale={locale}\n disabled={disabledMatcher}\n initialFocus\n />\n {withTime && (\n <div className=\"flex items-center gap-2 border-t px-3 py-2\">\n <span className=\"text-sm text-muted-foreground shrink-0\">\n {t('ui.datePicker.timeLabel', 'Time')}:\n </span>\n <TimeInput\n value={selectedDate ? extractTime(selectedDate) : undefined}\n onChange={handleTimeChange}\n minuteStep={minuteStep}\n disabled={!isInteractive || !selectedDate}\n />\n </div>\n )}\n {footer === 'apply-cancel' && (\n <div className=\"flex items-center justify-end gap-2 border-t px-3 py-2\">\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={handleCancel}>\n {t('ui.datePicker.cancelButton', 'Cancel')}\n </Button>\n <Button type=\"button\" size=\"sm\" onClick={handleApply}>\n {t('ui.datePicker.applyButton', 'Apply')}\n </Button>\n </div>\n )}\n {footer === 'today-clear' && (showTodayButton || showClearButton) && (\n <div className=\"flex items-center justify-between gap-2 border-t px-3 py-2\">\n {showTodayButton ? (\n <LinkButton type=\"button\" variant=\"primary\" onClick={handleToday}>\n {t('ui.datePicker.todayButton', 'Today')}\n </LinkButton>\n ) : null}\n {showClearButton ? (\n <LinkButton type=\"button\" variant=\"gray\" onClick={handleClear} className=\"ml-auto\">\n {t('ui.datePicker.clearButton', 'Clear')}\n </LinkButton>\n ) : null}\n </div>\n )}\n </PopoverContent>\n </Popover>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,6 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
- import { format } from "date-fns";
5
4
  import { CalendarIcon } from "lucide-react";
6
5
  import { cn } from "@open-mercato/shared/lib/utils";
7
6
  import { useT } from "@open-mercato/shared/lib/i18n/context";
@@ -11,28 +10,10 @@ import { Button } from "./button.js";
11
10
  import {
12
11
  defaultDateRangePresets
13
12
  } from "./date-picker-helpers.js";
14
- const DAY_FIRST_LOCALE_CODES = /* @__PURE__ */ new Set([
15
- "pl",
16
- "de",
17
- "fr",
18
- "es",
19
- "it",
20
- "pt",
21
- "nl",
22
- "ru",
23
- "cs",
24
- "sk",
25
- "hu",
26
- "ro"
27
- ]);
28
- function deriveDateFormat(locale) {
29
- const code = locale?.code?.split("-")[0]?.toLowerCase() ?? "";
30
- return code && DAY_FIRST_LOCALE_CODES.has(code) ? "d MMM yyyy" : "MMM d, yyyy";
31
- }
13
+ import { formatWithPublicDateFormat, resolvePublicDateFormat } from "./date-format.js";
32
14
  function defaultFormatRange(range, locale) {
33
- const fmt = deriveDateFormat(locale);
34
- const opts = locale ? { locale } : void 0;
35
- return `${format(range.start, fmt, opts)} \u2013 ${format(range.end, fmt, opts)}`;
15
+ const fmt = resolvePublicDateFormat(locale);
16
+ return `${formatWithPublicDateFormat(range.start, fmt, locale) ?? ""} \u2013 ${formatWithPublicDateFormat(range.end, fmt, locale) ?? ""}`;
36
17
  }
37
18
  function toRDPRange(range) {
38
19
  if (!range) return void 0;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/primitives/date-range-picker.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { format } from 'date-fns'\nimport type { Locale } from 'date-fns'\nimport { CalendarIcon } from 'lucide-react'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Popover, PopoverContent, PopoverTrigger } from './popover'\nimport { Calendar } from './calendar'\nimport { Button } from './button'\nimport type { DateRange as RDPRange } from 'react-day-picker'\nimport type { DateRange } from '../backend/date-range/dateRanges'\nimport {\n defaultDateRangePresets,\n type DateRangePresetItem,\n} from './date-picker-helpers'\n\nexport type { DateRangePresetItem } from './date-picker-helpers'\n\nexport type DateRangePickerProps = {\n value?: DateRange | null\n onChange: (value: DateRange | null) => void\n presets?: DateRangePresetItem[]\n showPresets?: boolean\n placeholder?: string\n size?: 'sm' | 'default'\n disabled?: boolean\n readOnly?: boolean\n withFooter?: boolean\n align?: 'start' | 'center' | 'end'\n minDate?: Date\n maxDate?: Date\n numberOfMonths?: 1 | 2\n locale?: Locale\n formatRange?: (value: DateRange, locale?: Locale) => string\n className?: string\n popoverClassName?: string\n id?: string\n name?: string\n required?: boolean\n 'aria-label'?: string\n 'aria-describedby'?: string\n}\n\nconst DAY_FIRST_LOCALE_CODES = new Set([\n 'pl', 'de', 'fr', 'es', 'it', 'pt', 'nl', 'ru', 'cs', 'sk', 'hu', 'ro',\n])\n\nfunction deriveDateFormat(locale?: Locale): string {\n const code = locale?.code?.split('-')[0]?.toLowerCase() ?? ''\n return code && DAY_FIRST_LOCALE_CODES.has(code) ? 'd MMM yyyy' : 'MMM d, yyyy'\n}\n\nfunction defaultFormatRange(range: DateRange, locale?: Locale): string {\n const fmt = deriveDateFormat(locale)\n const opts = locale ? { locale } : undefined\n return `${format(range.start, fmt, opts)} \u2013 ${format(range.end, fmt, opts)}`\n}\n\nfunction toRDPRange(range: DateRange | null | undefined): RDPRange | undefined {\n if (!range) return undefined\n return { from: range.start, to: range.end }\n}\n\nfunction fromRDPRange(rdp: RDPRange | undefined): DateRange | null {\n if (!rdp || !rdp.from) return null\n return { start: rdp.from, end: rdp.to ?? rdp.from }\n}\n\nfunction rangesEqual(a: DateRange | null, b: DateRange | null): boolean {\n if (!a && !b) return true\n if (!a || !b) return false\n return a.start.getTime() === b.start.getTime() && a.end.getTime() === b.end.getTime()\n}\n\nexport function DateRangePicker({\n value,\n onChange,\n presets,\n showPresets = true,\n placeholder,\n size = 'default',\n disabled = false,\n readOnly = false,\n withFooter = true,\n align = 'start',\n minDate,\n maxDate,\n numberOfMonths = 2,\n locale,\n formatRange,\n className,\n popoverClassName,\n id,\n name,\n required,\n 'aria-label': ariaLabel,\n 'aria-describedby': ariaDescribedBy,\n}: DateRangePickerProps) {\n const t = useT()\n const [open, setOpen] = React.useState(false)\n const [draft, setDraft] = React.useState<DateRange | null>(value ?? null)\n const [activePresetId, setActivePresetId] = React.useState<string | null>(null)\n\n const isInteractive = !disabled && !readOnly\n const useDraft = withFooter\n\n React.useEffect(() => {\n if (open) {\n setDraft(value ?? null)\n setActivePresetId(null)\n }\n }, [open, value])\n\n const resolvedPresets = React.useMemo<DateRangePresetItem[]>(\n () => presets ?? defaultDateRangePresets(),\n [presets],\n )\n\n const placeholderText = placeholder ?? t('ui.dateRangePicker.placeholder', 'Pick a date range')\n const formatter = formatRange ?? defaultFormatRange\n const formattedValue = React.useMemo(() => {\n if (!value) return null\n return formatter(value, locale)\n }, [value, formatter, locale])\n\n const selectedDate = useDraft ? draft : value\n const rdpSelected = toRDPRange(selectedDate)\n\n const handleRangeSelect = React.useCallback(\n (rdpRange: RDPRange | undefined) => {\n if (!isInteractive) return\n const next = fromRDPRange(rdpRange)\n setActivePresetId(null)\n if (useDraft) {\n setDraft(next)\n } else {\n onChange(next)\n if (next?.start && next?.end) setOpen(false)\n }\n },\n [isInteractive, useDraft, onChange],\n )\n\n const handlePresetClick = React.useCallback(\n (preset: DateRangePresetItem) => {\n if (!isInteractive) return\n const range = preset.range()\n setActivePresetId(preset.id)\n if (useDraft) {\n setDraft(range)\n } else {\n onChange(range)\n setOpen(false)\n }\n },\n [isInteractive, useDraft, onChange],\n )\n\n const handleApply = React.useCallback(() => {\n onChange(draft)\n setOpen(false)\n }, [draft, onChange])\n\n const handleCancel = React.useCallback(() => {\n setDraft(value ?? null)\n setActivePresetId(null)\n setOpen(false)\n }, [value])\n\n const disabledMatcher = React.useMemo(() => {\n if (!minDate && !maxDate) return undefined\n const matchers: import('react-day-picker').Matcher[] = []\n if (minDate) matchers.push({ before: minDate })\n if (maxDate) matchers.push({ after: maxDate })\n return matchers\n }, [minDate, maxDate])\n\n const heightClass = size === 'sm' ? 'h-8 px-2.5 text-xs' : 'h-9 px-3 text-sm'\n\n return (\n <Popover open={open} onOpenChange={isInteractive ? setOpen : undefined}>\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n id={id}\n name={name}\n aria-label={ariaLabel}\n aria-describedby={ariaDescribedBy}\n aria-haspopup=\"dialog\"\n aria-required={required ? true : undefined}\n data-crud-focus-target=\"\"\n data-slot=\"date-range-picker-trigger\"\n disabled={disabled}\n className={cn(\n 'w-full inline-flex items-center gap-2 rounded-md border border-input bg-background shadow-xs transition-colors text-left',\n 'focus-visible:outline-none focus-visible:shadow-focus focus-visible:border-foreground',\n 'hover:bg-muted/40',\n 'disabled:bg-bg-disabled disabled:border-border-disabled disabled:shadow-none disabled:hover:bg-bg-disabled disabled:cursor-not-allowed',\n 'aria-invalid:border-destructive',\n heightClass,\n readOnly && 'cursor-default opacity-70',\n !formattedValue && 'text-muted-foreground',\n className,\n )}\n onClick={isInteractive ? undefined : (event) => event.preventDefault()}\n >\n <CalendarIcon className=\"h-4 w-4 shrink-0 text-muted-foreground\" aria-hidden=\"true\" />\n <span className=\"flex-1 truncate\">\n {formattedValue ?? placeholderText}\n </span>\n </button>\n </PopoverTrigger>\n <PopoverContent\n align={align}\n className={cn(\n 'w-auto p-0 flex flex-col overflow-hidden',\n 'max-h-[var(--radix-popover-content-available-height)]',\n popoverClassName,\n )}\n >\n <div className=\"flex min-h-0 flex-1 overflow-auto\">\n {showPresets ? (\n <div\n data-slot=\"date-range-presets\"\n className=\"flex w-[200px] shrink-0 flex-col gap-0.5 overflow-y-auto border-r p-2\"\n >\n {resolvedPresets.map((preset) => {\n const isActive = activePresetId === preset.id\n return (\n <button\n key={preset.id}\n type=\"button\"\n onClick={() => handlePresetClick(preset)}\n className={cn(\n 'inline-flex h-8 items-center rounded-md px-3 text-left text-sm transition-colors shrink-0',\n 'hover:bg-accent hover:text-accent-foreground',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',\n isActive && 'bg-muted font-medium text-foreground',\n )}\n >\n {t(preset.labelKey, preset.id.replace(/_/g, ' '))}\n </button>\n )\n })}\n </div>\n ) : null}\n <div className=\"p-3\">\n <Calendar\n mode=\"range\"\n selected={rdpSelected}\n onSelect={handleRangeSelect}\n locale={locale}\n disabled={disabledMatcher}\n numberOfMonths={numberOfMonths}\n initialFocus\n />\n </div>\n </div>\n {withFooter ? (\n <div className=\"flex shrink-0 items-center justify-between gap-3 border-t bg-popover px-3 py-2\">\n <span className=\"truncate text-xs text-muted-foreground\">\n {selectedDate\n ? `${t('ui.dateRangePicker.rangeLabel', 'Range')}: ${formatter(selectedDate, locale)}`\n : t('ui.dateRangePicker.rangeEmpty', 'No range selected')}\n </span>\n <div className=\"flex shrink-0 items-center gap-2\">\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={handleCancel}>\n {t('ui.dateRangePicker.cancelButton', 'Cancel')}\n </Button>\n <Button type=\"button\" size=\"sm\" onClick={handleApply}>\n {t('ui.dateRangePicker.applyButton', 'Apply')}\n </Button>\n </div>\n </div>\n ) : null}\n </PopoverContent>\n </Popover>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport type { Locale } from 'date-fns'\nimport { CalendarIcon } from 'lucide-react'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Popover, PopoverContent, PopoverTrigger } from './popover'\nimport { Calendar } from './calendar'\nimport { Button } from './button'\nimport type { DateRange as RDPRange } from 'react-day-picker'\nimport type { DateRange } from '../backend/date-range/dateRanges'\nimport {\n defaultDateRangePresets,\n type DateRangePresetItem,\n} from './date-picker-helpers'\nimport { formatWithPublicDateFormat, resolvePublicDateFormat } from './date-format'\n\nexport type { DateRangePresetItem } from './date-picker-helpers'\n\nexport type DateRangePickerProps = {\n value?: DateRange | null\n onChange: (value: DateRange | null) => void\n presets?: DateRangePresetItem[]\n showPresets?: boolean\n placeholder?: string\n size?: 'sm' | 'default'\n disabled?: boolean\n readOnly?: boolean\n withFooter?: boolean\n align?: 'start' | 'center' | 'end'\n minDate?: Date\n maxDate?: Date\n numberOfMonths?: 1 | 2\n locale?: Locale\n formatRange?: (value: DateRange, locale?: Locale) => string\n className?: string\n popoverClassName?: string\n id?: string\n name?: string\n required?: boolean\n 'aria-label'?: string\n 'aria-describedby'?: string\n}\n\nfunction defaultFormatRange(range: DateRange, locale?: Locale): string {\n const fmt = resolvePublicDateFormat(locale)\n return `${formatWithPublicDateFormat(range.start, fmt, locale) ?? ''} \u2013 ${formatWithPublicDateFormat(range.end, fmt, locale) ?? ''}`\n}\n\nfunction toRDPRange(range: DateRange | null | undefined): RDPRange | undefined {\n if (!range) return undefined\n return { from: range.start, to: range.end }\n}\n\nfunction fromRDPRange(rdp: RDPRange | undefined): DateRange | null {\n if (!rdp || !rdp.from) return null\n return { start: rdp.from, end: rdp.to ?? rdp.from }\n}\n\nfunction rangesEqual(a: DateRange | null, b: DateRange | null): boolean {\n if (!a && !b) return true\n if (!a || !b) return false\n return a.start.getTime() === b.start.getTime() && a.end.getTime() === b.end.getTime()\n}\n\nexport function DateRangePicker({\n value,\n onChange,\n presets,\n showPresets = true,\n placeholder,\n size = 'default',\n disabled = false,\n readOnly = false,\n withFooter = true,\n align = 'start',\n minDate,\n maxDate,\n numberOfMonths = 2,\n locale,\n formatRange,\n className,\n popoverClassName,\n id,\n name,\n required,\n 'aria-label': ariaLabel,\n 'aria-describedby': ariaDescribedBy,\n}: DateRangePickerProps) {\n const t = useT()\n const [open, setOpen] = React.useState(false)\n const [draft, setDraft] = React.useState<DateRange | null>(value ?? null)\n const [activePresetId, setActivePresetId] = React.useState<string | null>(null)\n\n const isInteractive = !disabled && !readOnly\n const useDraft = withFooter\n\n React.useEffect(() => {\n if (open) {\n setDraft(value ?? null)\n setActivePresetId(null)\n }\n }, [open, value])\n\n const resolvedPresets = React.useMemo<DateRangePresetItem[]>(\n () => presets ?? defaultDateRangePresets(),\n [presets],\n )\n\n const placeholderText = placeholder ?? t('ui.dateRangePicker.placeholder', 'Pick a date range')\n const formatter = formatRange ?? defaultFormatRange\n const formattedValue = React.useMemo(() => {\n if (!value) return null\n return formatter(value, locale)\n }, [value, formatter, locale])\n\n const selectedDate = useDraft ? draft : value\n const rdpSelected = toRDPRange(selectedDate)\n\n const handleRangeSelect = React.useCallback(\n (rdpRange: RDPRange | undefined) => {\n if (!isInteractive) return\n const next = fromRDPRange(rdpRange)\n setActivePresetId(null)\n if (useDraft) {\n setDraft(next)\n } else {\n onChange(next)\n if (next?.start && next?.end) setOpen(false)\n }\n },\n [isInteractive, useDraft, onChange],\n )\n\n const handlePresetClick = React.useCallback(\n (preset: DateRangePresetItem) => {\n if (!isInteractive) return\n const range = preset.range()\n setActivePresetId(preset.id)\n if (useDraft) {\n setDraft(range)\n } else {\n onChange(range)\n setOpen(false)\n }\n },\n [isInteractive, useDraft, onChange],\n )\n\n const handleApply = React.useCallback(() => {\n onChange(draft)\n setOpen(false)\n }, [draft, onChange])\n\n const handleCancel = React.useCallback(() => {\n setDraft(value ?? null)\n setActivePresetId(null)\n setOpen(false)\n }, [value])\n\n const disabledMatcher = React.useMemo(() => {\n if (!minDate && !maxDate) return undefined\n const matchers: import('react-day-picker').Matcher[] = []\n if (minDate) matchers.push({ before: minDate })\n if (maxDate) matchers.push({ after: maxDate })\n return matchers\n }, [minDate, maxDate])\n\n const heightClass = size === 'sm' ? 'h-8 px-2.5 text-xs' : 'h-9 px-3 text-sm'\n\n return (\n <Popover open={open} onOpenChange={isInteractive ? setOpen : undefined}>\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n id={id}\n name={name}\n aria-label={ariaLabel}\n aria-describedby={ariaDescribedBy}\n aria-haspopup=\"dialog\"\n aria-required={required ? true : undefined}\n data-crud-focus-target=\"\"\n data-slot=\"date-range-picker-trigger\"\n disabled={disabled}\n className={cn(\n 'w-full inline-flex items-center gap-2 rounded-md border border-input bg-background shadow-xs transition-colors text-left',\n 'focus-visible:outline-none focus-visible:shadow-focus focus-visible:border-foreground',\n 'hover:bg-muted/40',\n 'disabled:bg-bg-disabled disabled:border-border-disabled disabled:shadow-none disabled:hover:bg-bg-disabled disabled:cursor-not-allowed',\n 'aria-invalid:border-destructive',\n heightClass,\n readOnly && 'cursor-default opacity-70',\n !formattedValue && 'text-muted-foreground',\n className,\n )}\n onClick={isInteractive ? undefined : (event) => event.preventDefault()}\n >\n <CalendarIcon className=\"h-4 w-4 shrink-0 text-muted-foreground\" aria-hidden=\"true\" />\n <span className=\"flex-1 truncate\">\n {formattedValue ?? placeholderText}\n </span>\n </button>\n </PopoverTrigger>\n <PopoverContent\n align={align}\n className={cn(\n 'w-auto p-0 flex flex-col overflow-hidden',\n 'max-h-[var(--radix-popover-content-available-height)]',\n popoverClassName,\n )}\n >\n <div className=\"flex min-h-0 flex-1 overflow-auto\">\n {showPresets ? (\n <div\n data-slot=\"date-range-presets\"\n className=\"flex w-[200px] shrink-0 flex-col gap-0.5 overflow-y-auto border-r p-2\"\n >\n {resolvedPresets.map((preset) => {\n const isActive = activePresetId === preset.id\n return (\n <button\n key={preset.id}\n type=\"button\"\n onClick={() => handlePresetClick(preset)}\n className={cn(\n 'inline-flex h-8 items-center rounded-md px-3 text-left text-sm transition-colors shrink-0',\n 'hover:bg-accent hover:text-accent-foreground',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',\n isActive && 'bg-muted font-medium text-foreground',\n )}\n >\n {t(preset.labelKey, preset.id.replace(/_/g, ' '))}\n </button>\n )\n })}\n </div>\n ) : null}\n <div className=\"p-3\">\n <Calendar\n mode=\"range\"\n selected={rdpSelected}\n onSelect={handleRangeSelect}\n locale={locale}\n disabled={disabledMatcher}\n numberOfMonths={numberOfMonths}\n initialFocus\n />\n </div>\n </div>\n {withFooter ? (\n <div className=\"flex shrink-0 items-center justify-between gap-3 border-t bg-popover px-3 py-2\">\n <span className=\"truncate text-xs text-muted-foreground\">\n {selectedDate\n ? `${t('ui.dateRangePicker.rangeLabel', 'Range')}: ${formatter(selectedDate, locale)}`\n : t('ui.dateRangePicker.rangeEmpty', 'No range selected')}\n </span>\n <div className=\"flex shrink-0 items-center gap-2\">\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={handleCancel}>\n {t('ui.dateRangePicker.cancelButton', 'Cancel')}\n </Button>\n <Button type=\"button\" size=\"sm\" onClick={handleApply}>\n {t('ui.dateRangePicker.applyButton', 'Apply')}\n </Button>\n </div>\n </div>\n ) : null}\n </PopoverContent>\n </Popover>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/ui",
3
- "version": "0.6.2-develop.3406.1.2b403f40da",
3
+ "version": "0.6.2-develop.3446.1.bd060c6017",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "scripts": {
@@ -133,7 +133,7 @@
133
133
  "@radix-ui/react-select": "^2.1.6",
134
134
  "@radix-ui/react-tooltip": "^1.2.8",
135
135
  "@tanstack/react-virtual": "^3.13.24",
136
- "date-fns": "^4.1.0",
136
+ "date-fns": "4.1.0",
137
137
  "react-big-calendar": "^1.19.4",
138
138
  "react-day-picker": "^9.14.0",
139
139
  "react-markdown": "^10.1.0",
@@ -141,13 +141,13 @@
141
141
  "remark-gfm": "^4.0.1"
142
142
  },
143
143
  "peerDependencies": {
144
- "@open-mercato/shared": "0.6.2-develop.3406.1.2b403f40da",
144
+ "@open-mercato/shared": "0.6.2-develop.3446.1.bd060c6017",
145
145
  "react": ">=18.0.0",
146
146
  "react-dom": ">=18.0.0",
147
147
  "react-is": ">=18.0.0"
148
148
  },
149
149
  "devDependencies": {
150
- "@open-mercato/shared": "0.6.2-develop.3406.1.2b403f40da",
150
+ "@open-mercato/shared": "0.6.2-develop.3446.1.bd060c6017",
151
151
  "@testing-library/dom": "^10.4.1",
152
152
  "@testing-library/jest-dom": "^6.9.1",
153
153
  "@testing-library/react": "^16.3.1",
@@ -24,9 +24,10 @@
24
24
  import * as React from 'react'
25
25
  import {
26
26
  AlertTriangle,
27
- Bot,
27
+ BadgeQuestionMark,
28
+ Database,
28
29
  ExternalLink,
29
- HelpCircle,
30
+ FileQuestion,
30
31
  Lightbulb,
31
32
  Loader2,
32
33
  PanelRightOpen,
@@ -407,24 +408,24 @@ export function AiAssistantLauncher({
407
408
  {
408
409
  label: t('ai_assistant.launcher.welcome.suggestion1', 'What can you help me with?'),
409
410
  prompt: 'What can you help me with on this tenant?',
410
- icon: <AiIcon className="size-4" />,
411
+ icon: <BadgeQuestionMark className="size-4 text-foreground" />,
411
412
  },
412
413
  {
413
414
  label: t('ai_assistant.launcher.welcome.suggestion2', 'Show what data you can access'),
414
415
  prompt: 'Describe the data you can read for this tenant — entities, fields, and limits.',
415
- icon: <Bot className="size-4" />,
416
+ icon: <Database className="size-4 text-foreground" />,
416
417
  },
417
418
  {
418
419
  label: t('ai_assistant.launcher.welcome.suggestion3', 'Suggest things to try'),
419
420
  prompt:
420
421
  'Suggest five concrete questions I could ask you that would surface useful insights for this tenant.',
421
- icon: <Lightbulb className="size-4" />,
422
+ icon: <Lightbulb className="size-4 text-foreground" />,
422
423
  },
423
424
  {
424
425
  label: t('ai_assistant.launcher.welcome.suggestion4', 'How do I use this assistant?'),
425
426
  prompt:
426
427
  'Walk me through how to use this assistant: when to ask, what tools you call, and how confirmations work.',
427
- icon: <HelpCircle className="size-4" />,
428
+ icon: <FileQuestion className="size-4 text-foreground" />,
428
429
  },
429
430
  ]
430
431
  return [...(activeAgent?.suggestions ?? []), ...generic]
@@ -462,12 +463,12 @@ export function AiAssistantLauncher({
462
463
  variant="ghost"
463
464
  size="sm"
464
465
  onClick={openPicker}
465
- className={cn('hidden sm:inline-flex items-center gap-2', className)}
466
+ className={cn('hidden sm:inline-flex items-center gap-2 text-foreground [&_svg]:text-foreground', className)}
466
467
  data-ai-launcher-trigger=""
467
468
  aria-label={triggerLabel}
468
469
  title={triggerLabel}
469
470
  >
470
- <AiIcon className="size-4" />
471
+ <AiIcon className="size-4 text-foreground" />
471
472
  <span>{shortLabel}</span>
472
473
  <span className="ml-2 rounded border px-1 text-xs text-muted-foreground">
473
474
  ⌘L
@@ -478,12 +479,12 @@ export function AiAssistantLauncher({
478
479
  type="button"
479
480
  variant="ghost"
480
481
  size="sm"
481
- className="sm:hidden"
482
+ className="sm:hidden text-foreground [&_svg]:text-foreground"
482
483
  onClick={openPicker}
483
484
  aria-label={triggerLabel}
484
485
  data-ai-launcher-trigger-mobile=""
485
486
  >
486
- <AiIcon className="size-4" />
487
+ <AiIcon className="size-4 text-foreground" />
487
488
  </IconButton>
488
489
  <Dialog open={pickerOpen} onOpenChange={setPickerOpen}>
489
490
  <DialogContent