@open-mercato/ui 0.6.7-develop.6788.1.c2a1520a30 → 0.6.7-develop.6814.1.0627c7e9f1

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,8 +1,19 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
- import { Button } from "../../primitives/button.js";
5
- import { Input } from "../../primitives/input.js";
4
+ import { DateRangePicker } from "../../primitives/date-range-picker.js";
5
+ import { IconButton } from "../../primitives/icon-button.js";
6
+ import {
7
+ SegmentedControl,
8
+ SegmentedControlItem
9
+ } from "../../primitives/segmented-control.js";
10
+ import {
11
+ Select,
12
+ SelectContent,
13
+ SelectItem,
14
+ SelectTrigger,
15
+ SelectValue
16
+ } from "../../primitives/select.js";
6
17
  import { cn } from "@open-mercato/shared/lib/utils";
7
18
  import { useT } from "@open-mercato/shared/lib/i18n/context";
8
19
  import { addDays } from "date-fns/addDays";
@@ -24,16 +35,19 @@ const VIEW_OPTIONS = [
24
35
  { id: "month", labelKey: "schedule.view.month", fallback: "Month" },
25
36
  { id: "agenda", labelKey: "schedule.view.agenda", fallback: "Agenda" }
26
37
  ];
27
- function formatDateInputValue(value) {
28
- const year = value.getFullYear();
29
- const month = String(value.getMonth() + 1).padStart(2, "0");
30
- const day = String(value.getDate()).padStart(2, "0");
31
- return `${year}-${month}-${day}`;
32
- }
33
- function parseDateInputValue(value, fallback) {
34
- if (!value) return fallback;
35
- const next = /* @__PURE__ */ new Date(`${value}T00:00:00`);
36
- return Number.isNaN(next.getTime()) ? fallback : next;
38
+ function getTimezoneOptions(current) {
39
+ const options = /* @__PURE__ */ new Set();
40
+ if (current) options.add(current);
41
+ options.add("UTC");
42
+ const resolved = Intl.DateTimeFormat().resolvedOptions().timeZone;
43
+ if (resolved) options.add(resolved);
44
+ const intlWithSupportedValues = Intl;
45
+ if (typeof intlWithSupportedValues.supportedValuesOf === "function") {
46
+ intlWithSupportedValues.supportedValuesOf("timeZone").forEach((timezone) => {
47
+ if (timezone) options.add(timezone);
48
+ });
49
+ }
50
+ return Array.from(options).sort((a, b) => a.localeCompare(b));
37
51
  }
38
52
  function ScheduleToolbar({
39
53
  view,
@@ -103,70 +117,73 @@ function ScheduleToolbar({
103
117
  const nextStart = startOfDay(addDays(range.start, multiplier * rangeLength));
104
118
  onRangeChange({ start: nextStart, end: endOfDay(addDays(nextStart, rangeLength - 1)) });
105
119
  }, [onRangeChange, range.start, rangeLength, view]);
106
- return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-3 rounded-xl border bg-card p-4 md:flex-row md:items-center md:justify-between", className), children: [
107
- /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center gap-2", children: VIEW_OPTIONS.map((option) => /* @__PURE__ */ jsx(
108
- Button,
120
+ const timezoneOptions = React.useMemo(() => getTimezoneOptions(timezone), [timezone]);
121
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-wrap items-center gap-x-4 gap-y-2 rounded-xl border bg-card p-3", className), children: [
122
+ /* @__PURE__ */ jsx(
123
+ SegmentedControl,
109
124
  {
110
- variant: view === option.id ? "default" : "outline",
111
- size: "sm",
112
- onClick: () => {
113
- if (option.id === view) return;
114
- onViewChange(option.id);
115
- onRangeChange(deriveRangeForView(/* @__PURE__ */ new Date(), option.id));
125
+ value: view,
126
+ onValueChange: (value) => {
127
+ const nextView = value;
128
+ if (nextView === view) return;
129
+ onViewChange(nextView);
130
+ onRangeChange(deriveRangeForView(/* @__PURE__ */ new Date(), nextView));
116
131
  },
117
- children: t(option.labelKey, option.fallback)
118
- },
119
- option.id
120
- )) }),
121
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
122
- /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => shiftRange("prev"), "aria-label": t("schedule.range.prev", "Previous"), children: /* @__PURE__ */ jsx(ChevronLeft, { className: "size-4", "aria-hidden": true }) }),
123
- /* @__PURE__ */ jsx("div", { className: "text-sm font-medium text-foreground", children: rangeLabel }),
124
- /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => shiftRange("next"), "aria-label": t("schedule.range.next", "Next"), children: /* @__PURE__ */ jsx(ChevronRight, { className: "size-4", "aria-hidden": true }) })
132
+ "aria-label": t("schedule.view.label", "Schedule view"),
133
+ className: "shrink-0",
134
+ children: VIEW_OPTIONS.map((option) => /* @__PURE__ */ jsx(SegmentedControlItem, { value: option.id, children: t(option.labelKey, option.fallback) }, option.id))
135
+ }
136
+ ),
137
+ /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [
138
+ /* @__PURE__ */ jsx(
139
+ IconButton,
140
+ {
141
+ type: "button",
142
+ variant: "outline",
143
+ onClick: () => shiftRange("prev"),
144
+ "aria-label": t("schedule.range.prev", "Previous"),
145
+ children: /* @__PURE__ */ jsx(ChevronLeft, { className: "size-4", "aria-hidden": true })
146
+ }
147
+ ),
148
+ /* @__PURE__ */ jsx("div", { className: "min-w-0 whitespace-nowrap px-1 text-sm font-medium text-foreground", children: rangeLabel }),
149
+ /* @__PURE__ */ jsx(
150
+ IconButton,
151
+ {
152
+ type: "button",
153
+ variant: "outline",
154
+ onClick: () => shiftRange("next"),
155
+ "aria-label": t("schedule.range.next", "Next"),
156
+ children: /* @__PURE__ */ jsx(ChevronRight, { className: "size-4", "aria-hidden": true })
157
+ }
158
+ )
125
159
  ] }),
126
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [
127
- /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
128
- /* @__PURE__ */ jsx("span", { children: t("schedule.range.start", "Start") }),
129
- /* @__PURE__ */ jsx(
130
- Input,
131
- {
132
- type: "date",
133
- value: formatDateInputValue(range.start),
134
- onChange: (event) => {
135
- const nextStart = parseDateInputValue(event.target.value, range.start);
136
- onRangeChange({ start: nextStart, end: range.end });
137
- },
138
- className: "h-8 w-full sm:w-[140px]"
139
- }
140
- )
141
- ] }),
142
- /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
143
- /* @__PURE__ */ jsx("span", { children: t("schedule.range.end", "End") }),
144
- /* @__PURE__ */ jsx(
145
- Input,
146
- {
147
- type: "date",
148
- value: formatDateInputValue(range.end),
149
- onChange: (event) => {
150
- const nextEnd = parseDateInputValue(event.target.value, range.end);
151
- onRangeChange({ start: range.start, end: nextEnd });
152
- },
153
- className: "h-8 w-full sm:w-[140px]"
154
- }
155
- )
156
- ] }),
157
- /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
158
- /* @__PURE__ */ jsx("span", { children: t("schedule.range.timezone", "Timezone") }),
160
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-x-3 gap-y-2 md:ml-auto", children: [
161
+ /* @__PURE__ */ jsx(
162
+ DateRangePicker,
163
+ {
164
+ value: range,
165
+ onChange: (next) => {
166
+ if (!next) return;
167
+ onRangeChange({ start: startOfDay(next.start), end: endOfDay(next.end) });
168
+ },
169
+ size: "sm",
170
+ showPresets: false,
171
+ numberOfMonths: 2,
172
+ "aria-label": t("schedule.range.label", "Date range")
173
+ }
174
+ ),
175
+ onTimezoneChange ? /* @__PURE__ */ jsxs(Select, { value: timezone ?? void 0, onValueChange: onTimezoneChange, children: [
159
176
  /* @__PURE__ */ jsx(
160
- Input,
177
+ SelectTrigger,
161
178
  {
162
- type: "text",
163
- value: timezone ?? "",
164
- onChange: (event) => onTimezoneChange?.(event.target.value),
165
- className: "h-8 w-full sm:w-[180px]",
166
- placeholder: t("schedule.range.timezone.placeholder", "UTC")
179
+ size: "sm",
180
+ className: "w-auto min-w-[10rem]",
181
+ "aria-label": t("schedule.range.timezone", "Timezone"),
182
+ children: /* @__PURE__ */ jsx(SelectValue, { placeholder: t("schedule.range.timezone.placeholder", "UTC") })
167
183
  }
168
- )
169
- ] })
184
+ ),
185
+ /* @__PURE__ */ jsx(SelectContent, { children: timezoneOptions.map((option) => /* @__PURE__ */ jsx(SelectItem, { value: option, children: option }, option)) })
186
+ ] }) : null
170
187
  ] })
171
188
  ] });
172
189
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/backend/schedule/ScheduleToolbar.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Button } from '../../primitives/button'\nimport { Input } from '../../primitives/input'\nimport type { ScheduleRange, ScheduleViewMode } from './types'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { addDays } from 'date-fns/addDays'\nimport { addMonths } from 'date-fns/addMonths'\nimport { addWeeks } from 'date-fns/addWeeks'\nimport { differenceInCalendarDays } from 'date-fns/differenceInCalendarDays'\nimport { endOfDay } from 'date-fns/endOfDay'\nimport { endOfMonth } from 'date-fns/endOfMonth'\nimport { endOfWeek } from 'date-fns/endOfWeek'\nimport { format } from 'date-fns/format'\nimport { startOfDay } from 'date-fns/startOfDay'\nimport { startOfMonth } from 'date-fns/startOfMonth'\nimport { startOfWeek } from 'date-fns/startOfWeek'\nimport { enUS } from 'date-fns/locale/en-US'\nimport { ChevronLeft, ChevronRight } from 'lucide-react'\n\nconst VIEW_OPTIONS: Array<{ id: ScheduleViewMode; labelKey: string; fallback: string }> = [\n { id: 'day', labelKey: 'schedule.view.day', fallback: 'Day' },\n { id: 'week', labelKey: 'schedule.view.week', fallback: 'Week' },\n { id: 'month', labelKey: 'schedule.view.month', fallback: 'Month' },\n { id: 'agenda', labelKey: 'schedule.view.agenda', fallback: 'Agenda' },\n]\n\nfunction formatDateInputValue(value: Date): string {\n const year = value.getFullYear()\n const month = String(value.getMonth() + 1).padStart(2, '0')\n const day = String(value.getDate()).padStart(2, '0')\n return `${year}-${month}-${day}`\n}\n\nfunction parseDateInputValue(value: string, fallback: Date): Date {\n if (!value) return fallback\n const next = new Date(`${value}T00:00:00`)\n return Number.isNaN(next.getTime()) ? fallback : next\n}\n\nexport type ScheduleToolbarProps = {\n view: ScheduleViewMode\n range: ScheduleRange\n timezone?: string\n onViewChange: (view: ScheduleViewMode) => void\n onRangeChange: (range: ScheduleRange) => void\n onTimezoneChange?: (timezone: string) => void\n className?: string\n}\n\nexport function ScheduleToolbar({\n view,\n range,\n timezone,\n onViewChange,\n onRangeChange,\n onTimezoneChange,\n className,\n}: ScheduleToolbarProps) {\n const t = useT()\n const rangeLength = React.useMemo(\n () => Math.max(1, differenceInCalendarDays(range.end, range.start) + 1),\n [range.end, range.start],\n )\n const deriveRangeForView = React.useCallback((base: Date, nextView: ScheduleViewMode): ScheduleRange => {\n if (nextView === 'day') {\n const start = startOfDay(base)\n return { start, end: endOfDay(start) }\n }\n if (nextView === 'week') {\n return { start: startOfWeek(base, { locale: enUS }), end: endOfWeek(base, { locale: enUS }) }\n }\n if (nextView === 'month') {\n return { start: startOfMonth(base), end: endOfMonth(base) }\n }\n const start = startOfDay(base)\n return { start, end: endOfDay(addDays(start, rangeLength - 1)) }\n }, [rangeLength])\n const rangeLabel = React.useMemo(() => {\n if (view === 'day') {\n return format(range.start, 'EEE, MMM d')\n }\n if (view === 'week') {\n const startLabel = format(range.start, 'MMM d')\n const endLabel = format(range.end, 'MMM d')\n const yearLabel = format(range.start, 'yyyy')\n return `${startLabel} - ${endLabel}, ${yearLabel}`\n }\n if (view === 'month') {\n return format(range.start, 'MMMM yyyy')\n }\n const startLabel = format(range.start, 'MMM d')\n const endLabel = format(range.end, 'MMM d, yyyy')\n return `${startLabel} - ${endLabel}`\n }, [range.end, range.start, view])\n\n const shiftRange = React.useCallback((direction: 'prev' | 'next') => {\n const multiplier = direction === 'prev' ? -1 : 1\n if (view === 'day') {\n const nextStart = startOfDay(addDays(range.start, multiplier))\n onRangeChange({ start: nextStart, end: endOfDay(nextStart) })\n return\n }\n if (view === 'week') {\n const base = addWeeks(range.start, multiplier)\n onRangeChange({\n start: startOfWeek(base, { locale: enUS }),\n end: endOfWeek(base, { locale: enUS }),\n })\n return\n }\n if (view === 'month') {\n const base = addMonths(range.start, multiplier)\n onRangeChange({ start: startOfMonth(base), end: endOfMonth(base) })\n return\n }\n const nextStart = startOfDay(addDays(range.start, multiplier * rangeLength))\n onRangeChange({ start: nextStart, end: endOfDay(addDays(nextStart, rangeLength - 1)) })\n }, [onRangeChange, range.start, rangeLength, view])\n\n return (\n <div className={cn('flex flex-col gap-3 rounded-xl border bg-card p-4 md:flex-row md:items-center md:justify-between', className)}>\n <div className=\"flex flex-wrap items-center gap-2\">\n {VIEW_OPTIONS.map((option) => (\n <Button\n key={option.id}\n variant={view === option.id ? 'default' : 'outline'}\n size=\"sm\"\n onClick={() => {\n if (option.id === view) return\n onViewChange(option.id)\n onRangeChange(deriveRangeForView(new Date(), option.id))\n }}\n >\n {t(option.labelKey, option.fallback)}\n </Button>\n ))}\n </div>\n <div className=\"flex flex-wrap items-center gap-2\">\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={() => shiftRange('prev')} aria-label={t('schedule.range.prev', 'Previous')}>\n <ChevronLeft className=\"size-4\" aria-hidden />\n </Button>\n <div className=\"text-sm font-medium text-foreground\">{rangeLabel}</div>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={() => shiftRange('next')} aria-label={t('schedule.range.next', 'Next')}>\n <ChevronRight className=\"size-4\" aria-hidden />\n </Button>\n </div>\n <div className=\"flex flex-wrap items-center gap-3\">\n <label className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n <span>{t('schedule.range.start', 'Start')}</span>\n <Input\n type=\"date\"\n value={formatDateInputValue(range.start)}\n onChange={(event) => {\n const nextStart = parseDateInputValue(event.target.value, range.start)\n onRangeChange({ start: nextStart, end: range.end })\n }}\n className=\"h-8 w-full sm:w-[140px]\"\n />\n </label>\n <label className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n <span>{t('schedule.range.end', 'End')}</span>\n <Input\n type=\"date\"\n value={formatDateInputValue(range.end)}\n onChange={(event) => {\n const nextEnd = parseDateInputValue(event.target.value, range.end)\n onRangeChange({ start: range.start, end: nextEnd })\n }}\n className=\"h-8 w-full sm:w-[140px]\"\n />\n </label>\n <label className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n <span>{t('schedule.range.timezone', 'Timezone')}</span>\n <Input\n type=\"text\"\n value={timezone ?? ''}\n onChange={(event) => onTimezoneChange?.(event.target.value)}\n className=\"h-8 w-full sm:w-[180px]\"\n placeholder={t('schedule.range.timezone.placeholder', 'UTC')}\n />\n </label>\n </div>\n </div>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { DateRangePicker } from '../../primitives/date-range-picker'\nimport { IconButton } from '../../primitives/icon-button'\nimport {\n SegmentedControl,\n SegmentedControlItem,\n} from '../../primitives/segmented-control'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '../../primitives/select'\nimport type { ScheduleRange, ScheduleViewMode } from './types'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { addDays } from 'date-fns/addDays'\nimport { addMonths } from 'date-fns/addMonths'\nimport { addWeeks } from 'date-fns/addWeeks'\nimport { differenceInCalendarDays } from 'date-fns/differenceInCalendarDays'\nimport { endOfDay } from 'date-fns/endOfDay'\nimport { endOfMonth } from 'date-fns/endOfMonth'\nimport { endOfWeek } from 'date-fns/endOfWeek'\nimport { format } from 'date-fns/format'\nimport { startOfDay } from 'date-fns/startOfDay'\nimport { startOfMonth } from 'date-fns/startOfMonth'\nimport { startOfWeek } from 'date-fns/startOfWeek'\nimport { enUS } from 'date-fns/locale/en-US'\nimport { ChevronLeft, ChevronRight } from 'lucide-react'\n\nconst VIEW_OPTIONS: Array<{ id: ScheduleViewMode; labelKey: string; fallback: string }> = [\n { id: 'day', labelKey: 'schedule.view.day', fallback: 'Day' },\n { id: 'week', labelKey: 'schedule.view.week', fallback: 'Week' },\n { id: 'month', labelKey: 'schedule.view.month', fallback: 'Month' },\n { id: 'agenda', labelKey: 'schedule.view.agenda', fallback: 'Agenda' },\n]\n\nfunction getTimezoneOptions(current?: string): string[] {\n const options = new Set<string>()\n if (current) options.add(current)\n options.add('UTC')\n const resolved = Intl.DateTimeFormat().resolvedOptions().timeZone\n if (resolved) options.add(resolved)\n const intlWithSupportedValues = Intl as typeof Intl & { supportedValuesOf?: (input: 'timeZone') => string[] }\n if (typeof intlWithSupportedValues.supportedValuesOf === 'function') {\n intlWithSupportedValues.supportedValuesOf('timeZone').forEach((timezone) => {\n if (timezone) options.add(timezone)\n })\n }\n return Array.from(options).sort((a, b) => a.localeCompare(b))\n}\n\nexport type ScheduleToolbarProps = {\n view: ScheduleViewMode\n range: ScheduleRange\n timezone?: string\n onViewChange: (view: ScheduleViewMode) => void\n onRangeChange: (range: ScheduleRange) => void\n onTimezoneChange?: (timezone: string) => void\n className?: string\n}\n\nexport function ScheduleToolbar({\n view,\n range,\n timezone,\n onViewChange,\n onRangeChange,\n onTimezoneChange,\n className,\n}: ScheduleToolbarProps) {\n const t = useT()\n const rangeLength = React.useMemo(\n () => Math.max(1, differenceInCalendarDays(range.end, range.start) + 1),\n [range.end, range.start],\n )\n const deriveRangeForView = React.useCallback((base: Date, nextView: ScheduleViewMode): ScheduleRange => {\n if (nextView === 'day') {\n const start = startOfDay(base)\n return { start, end: endOfDay(start) }\n }\n if (nextView === 'week') {\n return { start: startOfWeek(base, { locale: enUS }), end: endOfWeek(base, { locale: enUS }) }\n }\n if (nextView === 'month') {\n return { start: startOfMonth(base), end: endOfMonth(base) }\n }\n const start = startOfDay(base)\n return { start, end: endOfDay(addDays(start, rangeLength - 1)) }\n }, [rangeLength])\n const rangeLabel = React.useMemo(() => {\n if (view === 'day') {\n return format(range.start, 'EEE, MMM d')\n }\n if (view === 'week') {\n const startLabel = format(range.start, 'MMM d')\n const endLabel = format(range.end, 'MMM d')\n const yearLabel = format(range.start, 'yyyy')\n return `${startLabel} - ${endLabel}, ${yearLabel}`\n }\n if (view === 'month') {\n return format(range.start, 'MMMM yyyy')\n }\n const startLabel = format(range.start, 'MMM d')\n const endLabel = format(range.end, 'MMM d, yyyy')\n return `${startLabel} - ${endLabel}`\n }, [range.end, range.start, view])\n\n const shiftRange = React.useCallback((direction: 'prev' | 'next') => {\n const multiplier = direction === 'prev' ? -1 : 1\n if (view === 'day') {\n const nextStart = startOfDay(addDays(range.start, multiplier))\n onRangeChange({ start: nextStart, end: endOfDay(nextStart) })\n return\n }\n if (view === 'week') {\n const base = addWeeks(range.start, multiplier)\n onRangeChange({\n start: startOfWeek(base, { locale: enUS }),\n end: endOfWeek(base, { locale: enUS }),\n })\n return\n }\n if (view === 'month') {\n const base = addMonths(range.start, multiplier)\n onRangeChange({ start: startOfMonth(base), end: endOfMonth(base) })\n return\n }\n const nextStart = startOfDay(addDays(range.start, multiplier * rangeLength))\n onRangeChange({ start: nextStart, end: endOfDay(addDays(nextStart, rangeLength - 1)) })\n }, [onRangeChange, range.start, rangeLength, view])\n\n const timezoneOptions = React.useMemo(() => getTimezoneOptions(timezone), [timezone])\n\n return (\n <div className={cn('flex flex-wrap items-center gap-x-4 gap-y-2 rounded-xl border bg-card p-3', className)}>\n <SegmentedControl\n value={view}\n onValueChange={(value) => {\n const nextView = value as ScheduleViewMode\n if (nextView === view) return\n onViewChange(nextView)\n onRangeChange(deriveRangeForView(new Date(), nextView))\n }}\n aria-label={t('schedule.view.label', 'Schedule view')}\n className=\"shrink-0\"\n >\n {VIEW_OPTIONS.map((option) => (\n <SegmentedControlItem key={option.id} value={option.id}>\n {t(option.labelKey, option.fallback)}\n </SegmentedControlItem>\n ))}\n </SegmentedControl>\n <div className=\"flex shrink-0 items-center gap-1\">\n <IconButton\n type=\"button\"\n variant=\"outline\"\n onClick={() => shiftRange('prev')}\n aria-label={t('schedule.range.prev', 'Previous')}\n >\n <ChevronLeft className=\"size-4\" aria-hidden />\n </IconButton>\n <div className=\"min-w-0 whitespace-nowrap px-1 text-sm font-medium text-foreground\">{rangeLabel}</div>\n <IconButton\n type=\"button\"\n variant=\"outline\"\n onClick={() => shiftRange('next')}\n aria-label={t('schedule.range.next', 'Next')}\n >\n <ChevronRight className=\"size-4\" aria-hidden />\n </IconButton>\n </div>\n <div className=\"flex min-w-0 flex-wrap items-center gap-x-3 gap-y-2 md:ml-auto\">\n <DateRangePicker\n value={range}\n onChange={(next) => {\n if (!next) return\n onRangeChange({ start: startOfDay(next.start), end: endOfDay(next.end) })\n }}\n size=\"sm\"\n showPresets={false}\n numberOfMonths={2}\n aria-label={t('schedule.range.label', 'Date range')}\n />\n {onTimezoneChange ? (\n <Select value={timezone ?? undefined} onValueChange={onTimezoneChange}>\n <SelectTrigger\n size=\"sm\"\n className=\"w-auto min-w-[10rem]\"\n aria-label={t('schedule.range.timezone', 'Timezone')}\n >\n <SelectValue placeholder={t('schedule.range.timezone.placeholder', 'UTC')} />\n </SelectTrigger>\n <SelectContent>\n {timezoneOptions.map((option) => (\n <SelectItem key={option} value={option}>\n {option}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n ) : null}\n </div>\n </div>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["start", "startLabel", "endLabel", "nextStart"]
7
7
  }
@@ -0,0 +1,35 @@
1
+ import React from 'react'
2
+ import figma from '@figma/code-connect'
3
+ import { Alert, AlertDescription, AlertTitle } from '../src/primitives/alert'
4
+
5
+ figma.connect(Alert, 'https://www.figma.com/design/qCq9z6q1if0mpoRstV5OEA/Design-System?node-id=169-2358', {
6
+ imports: ["import { Alert, AlertTitle, AlertDescription } from '@open-mercato/ui/primitives/alert'"],
7
+ props: {
8
+ status: figma.enum('Status', {
9
+ Error: 'error',
10
+ Warning: 'warning',
11
+ Success: 'success',
12
+ Information: 'information',
13
+ Feature: 'feature',
14
+ }),
15
+ style: figma.enum('Style', {
16
+ Filled: 'filled',
17
+ Light: 'light',
18
+ Lighter: 'lighter',
19
+ Stroke: 'stroke',
20
+ }),
21
+ size: figma.enum('Size', {
22
+ XS: 'xs',
23
+ Small: 'sm',
24
+ Default: 'default',
25
+ }),
26
+ title: figma.string('Title'),
27
+ description: figma.string('Description'),
28
+ },
29
+ example: ({ status, style, size, title, description }) => (
30
+ <Alert status={status} style={style} size={size}>
31
+ <AlertTitle>{title}</AlertTitle>
32
+ <AlertDescription>{description}</AlertDescription>
33
+ </Alert>
34
+ ),
35
+ })
@@ -0,0 +1,33 @@
1
+ import React from 'react'
2
+ import figma from '@figma/code-connect'
3
+ import { Badge } from '../src/primitives/badge'
4
+
5
+ // TODO(figma): resolve the real node id in the DS file before ds:code-connect:publish.
6
+ figma.connect(Badge, 'https://www.figma.com/design/qCq9z6q1if0mpoRstV5OEA/Design-System?node-id=0-1', {
7
+ imports: ["import { Badge } from '@open-mercato/ui/primitives/badge'"],
8
+ props: {
9
+ variant: figma.enum('Variant', {
10
+ Default: 'default',
11
+ Secondary: 'secondary',
12
+ Outline: 'outline',
13
+ Muted: 'muted',
14
+ Success: 'success',
15
+ Warning: 'warning',
16
+ Info: 'info',
17
+ Neutral: 'neutral',
18
+ Error: 'error',
19
+ Brand: 'brand',
20
+ }),
21
+ size: figma.enum('Size', {
22
+ Small: 'sm',
23
+ Default: 'default',
24
+ Large: 'lg',
25
+ }),
26
+ label: figma.string('Label'),
27
+ },
28
+ example: ({ variant, size, label }) => (
29
+ <Badge variant={variant} size={size}>
30
+ {label}
31
+ </Badge>
32
+ ),
33
+ })
@@ -0,0 +1,33 @@
1
+ import React from 'react'
2
+ import figma from '@figma/code-connect'
3
+ import { Button } from '../src/primitives/button'
4
+
5
+ // TODO(figma): resolve the real node id in the DS file before ds:code-connect:publish.
6
+ figma.connect(Button, 'https://www.figma.com/design/qCq9z6q1if0mpoRstV5OEA/Design-System?node-id=0-1', {
7
+ imports: ["import { Button } from '@open-mercato/ui/primitives/button'"],
8
+ props: {
9
+ variant: figma.enum('Variant', {
10
+ Primary: 'default',
11
+ Destructive: 'destructive',
12
+ Outline: 'outline',
13
+ Secondary: 'secondary',
14
+ Ghost: 'ghost',
15
+ Muted: 'muted',
16
+ Link: 'link',
17
+ }),
18
+ size: figma.enum('Size', {
19
+ Default: 'default',
20
+ Small: 'sm',
21
+ Large: 'lg',
22
+ '2XS': '2xs',
23
+ Icon: 'icon',
24
+ }),
25
+ disabled: figma.boolean('Disabled'),
26
+ label: figma.string('Label'),
27
+ },
28
+ example: ({ variant, size, disabled, label }) => (
29
+ <Button variant={variant} size={size} disabled={disabled}>
30
+ {label}
31
+ </Button>
32
+ ),
33
+ })
@@ -0,0 +1,28 @@
1
+ import React from 'react'
2
+ import figma from '@figma/code-connect'
3
+ import { Checkbox } from '../src/primitives/checkbox'
4
+ import { CheckboxField } from '../src/primitives/checkbox-field'
5
+
6
+ // TODO(figma): resolve the real node id in the DS file before ds:code-connect:publish.
7
+ figma.connect(Checkbox, 'https://www.figma.com/design/qCq9z6q1if0mpoRstV5OEA/Design-System?node-id=0-1', {
8
+ imports: ["import { Checkbox } from '@open-mercato/ui/primitives/checkbox'"],
9
+ variant: { Label: 'False' },
10
+ props: {
11
+ checked: figma.boolean('Checked'),
12
+ disabled: figma.boolean('Disabled'),
13
+ },
14
+ example: ({ checked, disabled }) => <Checkbox checked={checked} disabled={disabled} />,
15
+ })
16
+
17
+ figma.connect(CheckboxField, 'https://www.figma.com/design/qCq9z6q1if0mpoRstV5OEA/Design-System?node-id=0-1', {
18
+ imports: ["import { CheckboxField } from '@open-mercato/ui/primitives/checkbox-field'"],
19
+ variant: { Label: 'True' },
20
+ props: {
21
+ checked: figma.boolean('Checked'),
22
+ disabled: figma.boolean('Disabled'),
23
+ label: figma.string('Label text'),
24
+ },
25
+ example: ({ checked, disabled, label }) => (
26
+ <CheckboxField checked={checked} disabled={disabled} label={label} />
27
+ ),
28
+ })
@@ -0,0 +1,40 @@
1
+ import React from 'react'
2
+ import figma from '@figma/code-connect'
3
+ import {
4
+ Drawer,
5
+ DrawerBody,
6
+ DrawerClose,
7
+ DrawerContent,
8
+ DrawerDescription,
9
+ DrawerFooter,
10
+ DrawerHeader,
11
+ DrawerTitle,
12
+ } from '../src/primitives/drawer'
13
+ import { Button } from '../src/primitives/button'
14
+
15
+ figma.connect(Drawer, 'https://www.figma.com/design/qCq9z6q1if0mpoRstV5OEA/Design-System?node-id=486-7366', {
16
+ imports: [
17
+ "import { Drawer, DrawerContent, DrawerHeader, DrawerTitle, DrawerDescription, DrawerBody, DrawerFooter, DrawerClose } from '@open-mercato/ui/primitives/drawer'",
18
+ ],
19
+ props: {
20
+ title: figma.string('Title'),
21
+ description: figma.string('Description'),
22
+ },
23
+ example: ({ title, description }) => (
24
+ <Drawer>
25
+ <DrawerContent>
26
+ <DrawerHeader>
27
+ <DrawerTitle>{title}</DrawerTitle>
28
+ <DrawerDescription>{description}</DrawerDescription>
29
+ </DrawerHeader>
30
+ <DrawerBody>Content</DrawerBody>
31
+ <DrawerFooter layout="equal">
32
+ <DrawerClose asChild>
33
+ <Button variant="outline">Cancel</Button>
34
+ </DrawerClose>
35
+ <Button>Save</Button>
36
+ </DrawerFooter>
37
+ </DrawerContent>
38
+ </Drawer>
39
+ ),
40
+ })
@@ -0,0 +1,58 @@
1
+ import React from 'react'
2
+ import figma from '@figma/code-connect'
3
+ import { Input } from '../src/primitives/input'
4
+ import { EmailInput } from '../src/primitives/email-input'
5
+ import { SearchInput } from '../src/primitives/search-input'
6
+ import { PasswordInput } from '../src/primitives/password-input'
7
+ import { WebsiteInput } from '../src/primitives/website-input'
8
+
9
+ // TODO(figma): resolve the real node id in the DS file before ds:code-connect:publish.
10
+ figma.connect(Input, 'https://www.figma.com/design/qCq9z6q1if0mpoRstV5OEA/Design-System?node-id=0-1', {
11
+ imports: ["import { Input } from '@open-mercato/ui/primitives/input'"],
12
+ variant: { Type: 'Text' },
13
+ props: {
14
+ placeholder: figma.string('Placeholder'),
15
+ disabled: figma.boolean('Disabled'),
16
+ },
17
+ example: ({ placeholder, disabled }) => <Input placeholder={placeholder} disabled={disabled} />,
18
+ })
19
+
20
+ figma.connect(EmailInput, 'https://www.figma.com/design/qCq9z6q1if0mpoRstV5OEA/Design-System?node-id=0-1', {
21
+ imports: ["import { EmailInput } from '@open-mercato/ui/primitives/email-input'"],
22
+ variant: { Type: 'Email' },
23
+ props: {
24
+ placeholder: figma.string('Placeholder'),
25
+ disabled: figma.boolean('Disabled'),
26
+ },
27
+ example: ({ placeholder, disabled }) => <EmailInput placeholder={placeholder} disabled={disabled} />,
28
+ })
29
+
30
+ figma.connect(SearchInput, 'https://www.figma.com/design/qCq9z6q1if0mpoRstV5OEA/Design-System?node-id=0-1', {
31
+ imports: ["import { SearchInput } from '@open-mercato/ui/primitives/search-input'"],
32
+ variant: { Type: 'Search' },
33
+ props: {
34
+ placeholder: figma.string('Placeholder'),
35
+ disabled: figma.boolean('Disabled'),
36
+ },
37
+ example: ({ placeholder, disabled }) => <SearchInput placeholder={placeholder} disabled={disabled} />,
38
+ })
39
+
40
+ figma.connect(PasswordInput, 'https://www.figma.com/design/qCq9z6q1if0mpoRstV5OEA/Design-System?node-id=0-1', {
41
+ imports: ["import { PasswordInput } from '@open-mercato/ui/primitives/password-input'"],
42
+ variant: { Type: 'Password' },
43
+ props: {
44
+ placeholder: figma.string('Placeholder'),
45
+ disabled: figma.boolean('Disabled'),
46
+ },
47
+ example: ({ placeholder, disabled }) => <PasswordInput placeholder={placeholder} disabled={disabled} />,
48
+ })
49
+
50
+ figma.connect(WebsiteInput, 'https://www.figma.com/design/qCq9z6q1if0mpoRstV5OEA/Design-System?node-id=0-1', {
51
+ imports: ["import { WebsiteInput } from '@open-mercato/ui/primitives/website-input'"],
52
+ variant: { Type: 'Website' },
53
+ props: {
54
+ placeholder: figma.string('Placeholder'),
55
+ disabled: figma.boolean('Disabled'),
56
+ },
57
+ example: ({ placeholder, disabled }) => <WebsiteInput placeholder={placeholder} disabled={disabled} />,
58
+ })
@@ -0,0 +1,16 @@
1
+ import React from 'react'
2
+ import figma from '@figma/code-connect'
3
+ import { Radio, RadioGroup } from '../src/primitives/radio'
4
+
5
+ // TODO(figma): resolve the real node id in the DS file before ds:code-connect:publish.
6
+ figma.connect(Radio, 'https://www.figma.com/design/qCq9z6q1if0mpoRstV5OEA/Design-System?node-id=0-1', {
7
+ imports: ["import { Radio, RadioGroup } from '@open-mercato/ui/primitives/radio'"],
8
+ props: {
9
+ disabled: figma.boolean('Disabled'),
10
+ },
11
+ example: ({ disabled }) => (
12
+ <RadioGroup defaultValue="first">
13
+ <Radio value="first" disabled={disabled} />
14
+ </RadioGroup>
15
+ ),
16
+ })
@@ -0,0 +1,24 @@
1
+ import React from 'react'
2
+ import figma from '@figma/code-connect'
3
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../src/primitives/select'
4
+
5
+ // TODO(figma): resolve the real node id in the DS file before ds:code-connect:publish.
6
+ figma.connect(Select, 'https://www.figma.com/design/qCq9z6q1if0mpoRstV5OEA/Design-System?node-id=0-1', {
7
+ imports: [
8
+ "import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from '@open-mercato/ui/primitives/select'",
9
+ ],
10
+ props: {
11
+ placeholder: figma.string('Placeholder'),
12
+ disabled: figma.boolean('Disabled'),
13
+ },
14
+ example: ({ placeholder, disabled }) => (
15
+ <Select>
16
+ <SelectTrigger disabled={disabled}>
17
+ <SelectValue placeholder={placeholder} />
18
+ </SelectTrigger>
19
+ <SelectContent>
20
+ <SelectItem value="first">First option</SelectItem>
21
+ </SelectContent>
22
+ </Select>
23
+ ),
24
+ })
@@ -0,0 +1,24 @@
1
+ import React from 'react'
2
+ import figma from '@figma/code-connect'
3
+ import { StatusBadge } from '../src/primitives/status-badge'
4
+
5
+ // TODO(figma): resolve the real node id in the DS file before ds:code-connect:publish.
6
+ figma.connect(StatusBadge, 'https://www.figma.com/design/qCq9z6q1if0mpoRstV5OEA/Design-System?node-id=0-1', {
7
+ imports: ["import { StatusBadge } from '@open-mercato/ui/primitives/status-badge'"],
8
+ props: {
9
+ variant: figma.enum('Variant', {
10
+ Success: 'success',
11
+ Warning: 'warning',
12
+ Error: 'error',
13
+ Info: 'info',
14
+ Neutral: 'neutral',
15
+ }),
16
+ dot: figma.boolean('Dot'),
17
+ label: figma.string('Label'),
18
+ },
19
+ example: ({ variant, dot, label }) => (
20
+ <StatusBadge variant={variant} dot={dot}>
21
+ {label}
22
+ </StatusBadge>
23
+ ),
24
+ })
@@ -0,0 +1,28 @@
1
+ import React from 'react'
2
+ import figma from '@figma/code-connect'
3
+ import { Switch } from '../src/primitives/switch'
4
+ import { SwitchField } from '../src/primitives/switch-field'
5
+
6
+ // TODO(figma): resolve the real node id in the DS file before ds:code-connect:publish.
7
+ figma.connect(Switch, 'https://www.figma.com/design/qCq9z6q1if0mpoRstV5OEA/Design-System?node-id=0-1', {
8
+ imports: ["import { Switch } from '@open-mercato/ui/primitives/switch'"],
9
+ variant: { Label: 'False' },
10
+ props: {
11
+ checked: figma.boolean('Checked'),
12
+ disabled: figma.boolean('Disabled'),
13
+ },
14
+ example: ({ checked, disabled }) => <Switch checked={checked} disabled={disabled} />,
15
+ })
16
+
17
+ figma.connect(SwitchField, 'https://www.figma.com/design/qCq9z6q1if0mpoRstV5OEA/Design-System?node-id=0-1', {
18
+ imports: ["import { SwitchField } from '@open-mercato/ui/primitives/switch-field'"],
19
+ variant: { Label: 'True' },
20
+ props: {
21
+ checked: figma.boolean('Checked'),
22
+ disabled: figma.boolean('Disabled'),
23
+ label: figma.string('Label text'),
24
+ },
25
+ example: ({ checked, disabled, label }) => (
26
+ <SwitchField checked={checked} disabled={disabled} label={label} />
27
+ ),
28
+ })
@@ -0,0 +1,22 @@
1
+ import React from 'react'
2
+ import figma from '@figma/code-connect'
3
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from '../src/primitives/tabs'
4
+
5
+ // TODO(figma): resolve the real node id in the DS file before ds:code-connect:publish.
6
+ figma.connect(Tabs, 'https://www.figma.com/design/qCq9z6q1if0mpoRstV5OEA/Design-System?node-id=0-1', {
7
+ imports: ["import { Tabs, TabsList, TabsTrigger, TabsContent } from '@open-mercato/ui/primitives/tabs'"],
8
+ props: {
9
+ label: figma.string('Label'),
10
+ count: figma.string('Count'),
11
+ },
12
+ example: ({ label, count }) => (
13
+ <Tabs defaultValue="first" variant="underline">
14
+ <TabsList aria-label="Sections">
15
+ <TabsTrigger value="first" count={count}>
16
+ {label}
17
+ </TabsTrigger>
18
+ </TabsList>
19
+ <TabsContent value="first">Content</TabsContent>
20
+ </Tabs>
21
+ ),
22
+ })