@open-mercato/ui 0.4.5-develop-eeccf7adf4 → 0.4.5-develop-5191db4ef3

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.
@@ -261,13 +261,13 @@ function FilterOverlay({
261
261
  ] }, f.id))
262
262
  ] }),
263
263
  /* @__PURE__ */ jsxs("div", { className: "p-4 border-t flex items-center justify-between gap-2", children: [
264
- /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: handleClear, children: "Clear" }),
264
+ /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: handleClear, children: t("ui.filters.actions.clear", "Clear") }),
265
265
  /* @__PURE__ */ jsxs(Button, { onClick: handleApply, children: [
266
266
  /* @__PURE__ */ jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", "aria-hidden": "true", className: "opacity-80", children: [
267
267
  /* @__PURE__ */ jsx("path", { d: "M3 4h18" }),
268
268
  /* @__PURE__ */ jsx("path", { d: "M6 8h12l-3 8H9L6 8z" })
269
269
  ] }),
270
- "Apply"
270
+ t("ui.filters.actions.apply", "Apply")
271
271
  ] })
272
272
  ] })
273
273
  ] })
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/backend/FilterOverlay.tsx"],
4
- "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { Button } from '../primitives/button'\nimport { TagsInput, type TagsInputOption } from './inputs/TagsInput'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\nexport type FilterOption = { value: string; label: string; description?: string | null }\n\nexport type FilterDef = {\n id: string\n label: string\n type: 'text' | 'select' | 'checkbox' | 'dateRange' | 'tags'\n options?: FilterOption[]\n // Optional async loader for options (used by select/tags)\n loadOptions?: (query?: string) => Promise<FilterOption[]>\n multiple?: boolean\n placeholder?: string\n group?: string\n formatValue?: (value: string) => string\n formatDescription?: (value: string) => string | null | undefined\n}\n\nexport type FilterValues = Record<string, any>\n\nexport type FilterOverlayProps = {\n title?: string\n filters: FilterDef[]\n initialValues: FilterValues\n open: boolean\n onOpenChange: (open: boolean) => void\n onApply: (values: FilterValues) => void\n onClear?: () => void\n extraContent?: React.ReactNode\n}\n\nconst EMPTY_FILTER_VALUES: FilterValues = {}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return value != null && typeof value === 'object' && !Array.isArray(value)\n}\n\nfunction normalizeKeys(source: FilterValues | null | undefined): string[] {\n if (!source) return []\n return Object.keys(source).filter((key) => source[key] !== undefined)\n}\n\nfunction areFieldValuesEqual(a: any, b: any): boolean {\n if (a === b) return true\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false\n for (let i = 0; i < a.length; i += 1) {\n if (!areFieldValuesEqual(a[i], b[i])) return false\n }\n return true\n }\n if (isPlainObject(a) && isPlainObject(b)) {\n const keysA = normalizeKeys(a as FilterValues)\n const keysB = normalizeKeys(b as FilterValues)\n if (keysA.length !== keysB.length) return false\n for (const key of keysA) {\n if (!keysB.includes(key)) return false\n if (!areFieldValuesEqual((a as FilterValues)[key], (b as FilterValues)[key])) return false\n }\n return true\n }\n return false\n}\n\nfunction areFilterValuesEqual(a?: FilterValues | null, b?: FilterValues | null): boolean {\n if (a === b) return true\n const keysA = normalizeKeys(a || EMPTY_FILTER_VALUES)\n const keysB = normalizeKeys(b || EMPTY_FILTER_VALUES)\n if (keysA.length !== keysB.length) return false\n for (const key of keysA) {\n if (!keysB.includes(key)) return false\n if (!areFieldValuesEqual(a?.[key], b?.[key])) return false\n }\n return true\n}\n\nexport function FilterOverlay({\n title,\n filters,\n initialValues,\n open,\n onOpenChange,\n onApply,\n onClear,\n extraContent,\n}: FilterOverlayProps) {\n const t = useT()\n const defaultTitle = title ?? t('ui.filters.title', 'Filters')\n const [values, setValues] = React.useState<FilterValues>(initialValues)\n React.useEffect(() => {\n setValues((prev) => (areFilterValuesEqual(prev, initialValues) ? prev : initialValues))\n }, [initialValues])\n const filtersSignature = React.useMemo(\n () => filters.map((f) => `${f.id}:${f.type}:${Boolean((f as any).loadOptions)}:${(f.options || []).length}`).join('|'),\n [filters]\n )\n const lastLoadedSignatureRef = React.useRef<string | null>(null)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const stableFilters = React.useMemo(() => filters, [filtersSignature])\n\n // Load dynamic options for filters that request it\n const [dynamicOptions, setDynamicOptions] = React.useState<Record<string, FilterOption[]>>({})\n React.useEffect(() => {\n if (!open) return\n if (lastLoadedSignatureRef.current === filtersSignature) return\n lastLoadedSignatureRef.current = filtersSignature\n setDynamicOptions({})\n let cancelled = false\n const loadAll = async () => {\n const loaders = filters\n .filter((f): f is FilterDef & { loadOptions: (query?: string) => Promise<FilterOption[]> } => (f as any).loadOptions != null)\n .map(async (f) => {\n try {\n const opts = await (f as any).loadOptions()\n if (!cancelled) setDynamicOptions((prev) => ({ ...prev, [f.id]: opts }))\n } catch {\n // ignore\n }\n })\n await Promise.all(loaders)\n }\n loadAll()\n return () => {\n cancelled = true\n }\n }, [filters, filtersSignature, open])\n React.useEffect(() => {\n if (!open) {\n lastLoadedSignatureRef.current = null\n }\n }, [open])\n\n const setValue = (id: string, v: any) => setValues((prev) => ({ ...prev, [id]: v }))\n\n const handleApply = () => {\n onApply(values)\n onOpenChange(false)\n }\n\n const handleClear = () => {\n setValues({})\n onClear?.()\n }\n\n const tagLoaders = React.useMemo(() => {\n const map = new Map<string, (q?: string) => Promise<Array<string | TagsInputOption>>>()\n for (const f of stableFilters) {\n if (f.type === 'tags' && typeof f.loadOptions === 'function') {\n const fieldId = f.id\n const load = f.loadOptions as (query?: string) => Promise<FilterOption[]>\n map.set(fieldId, async (q?: string) => {\n const query = (q ?? '').trim()\n if (!query.length) return []\n try {\n const opts = await load(query)\n setDynamicOptions((prev) => ({ ...prev, [fieldId]: opts }))\n return opts.map((o) => ({ value: o.value, label: o.label, description: o.description ?? null }))\n } catch {\n return []\n }\n })\n }\n }\n return map\n }, [stableFilters])\n\n return (\n <>\n {open && (\n <div className=\"fixed inset-0 z-50\">\n <div className=\"absolute inset-0 bg-black/30\" onClick={() => onOpenChange(false)} />\n <div className=\"absolute left-0 top-0 h-full w-full sm:w-[380px] bg-background shadow-xl border-r flex flex-col\">\n <div className=\"flex items-center justify-between p-4 border-b\">\n <h2 className=\"text-base font-semibold\">{defaultTitle}</h2>\n <Button variant=\"muted\" size=\"sm\" onClick={() => onOpenChange(false)}>{t('common.close')}</Button>\n </div>\n {/* Top actions: duplicate Clear/Apply */}\n <div className=\"px-4 py-2 border-b flex items-center justify-between gap-2\">\n <Button variant=\"outline\" size=\"sm\" onClick={handleClear}>{t('ui.filters.actions.clear', 'Clear')}</Button>\n <Button size=\"sm\" onClick={handleApply}>\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" aria-hidden=\"true\" className=\"opacity-80\"><path d=\"M3 4h18\"/><path d=\"M6 8h12l-3 8H9L6 8z\"/></svg>\n {t('ui.filters.actions.apply', 'Apply')}\n </Button>\n </div>\n <div className=\"flex-1 overflow-auto p-4 space-y-4\">\n {extraContent ? <div className=\"space-y-2 rounded-md border bg-muted/30 p-3\">{extraContent}</div> : null}\n {filters.map((f) => (\n <div key={f.id} className=\"space-y-2\">\n <div className=\"text-sm font-medium\">{f.label}</div>\n {f.type === 'text' && (\n <input\n type=\"text\"\n className=\"w-full h-11 rounded border px-2 text-sm\"\n placeholder={f.placeholder}\n value={values[f.id] ?? ''}\n onChange={(e) => setValue(f.id, e.target.value || undefined)}\n />\n )}\n {f.type === 'dateRange' && (\n <div className=\"grid grid-cols-1 gap-2\">\n <div>\n <div className=\"text-xs text-muted-foreground mb-1\">{t('ui.filters.dateRange.from', 'From')}</div>\n <input\n type=\"date\"\n className=\"w-full h-11 rounded border px-2 text-sm\"\n value={values[f.id]?.from ?? ''}\n onChange={(e) => setValue(f.id, { ...(values[f.id] ?? {}), from: e.target.value || undefined })}\n />\n </div>\n <div>\n <div className=\"text-xs text-muted-foreground mb-1\">{t('ui.filters.dateRange.to', 'To')}</div>\n <input\n type=\"date\"\n className=\"w-full h-11 rounded border px-2 text-sm\"\n value={values[f.id]?.to ?? ''}\n onChange={(e) => setValue(f.id, { ...(values[f.id] ?? {}), to: e.target.value || undefined })}\n />\n </div>\n </div>\n )}\n {f.type === 'select' && (\n <div className=\"space-y-1\">\n {f.multiple ? (\n <div className=\"flex flex-col gap-1\">\n {(f.options || dynamicOptions[f.id] || []).map((opt) => {\n const arr: string[] = Array.isArray(values[f.id]) ? values[f.id] : []\n const checked = arr.includes(opt.value)\n return (\n <label key={opt.value} className=\"inline-flex items-center gap-2\">\n <input\n type=\"checkbox\"\n checked={checked}\n onChange={(e) => {\n const next = new Set(arr)\n if (e.target.checked) next.add(opt.value)\n else next.delete(opt.value)\n setValue(f.id, Array.from(next))\n }}\n />\n <span className=\"text-sm\">{opt.label}</span>\n </label>\n )\n })}\n </div>\n ) : (\n <select\n className=\"w-full h-11 rounded border px-2 text-sm\"\n value={values[f.id] ?? ''}\n onChange={(e) => setValue(f.id, e.target.value || undefined)}\n >\n <option value=\"\">{t('ui.forms.select.emptyOption', '\u2014')}</option>\n {(f.options || dynamicOptions[f.id] || []).map((opt) => (\n <option key={opt.value} value={opt.value}>{opt.label}</option>\n ))}\n </select>\n )}\n </div>\n )}\n {f.type === 'tags' && (() => {\n const arr: string[] = Array.isArray(values[f.id]) ? values[f.id] : []\n const staticOptions = f.options || []\n const dynamic = dynamicOptions[f.id] || []\n const optionMap = new Map<string, FilterOption>()\n staticOptions.forEach((opt) => optionMap.set(opt.value, opt))\n dynamic.forEach((opt) => optionMap.set(opt.value, opt))\n const loadSuggestions = tagLoaders.get(f.id)\n const resolveTagLabel = f.formatValue\n ? (val: string) => f.formatValue!(val)\n : (val: string) => optionMap.get(val)?.label ?? val\n const resolveTagDescription = f.formatDescription\n ? (val: string) => f.formatDescription!(val) ?? null\n : (val: string) => optionMap.get(val)?.description ?? null\n const suggestionList: TagsInputOption[] = Array.from(optionMap.values()).map((opt) => ({\n value: opt.value,\n label: opt.label,\n description: opt.description ?? null,\n }))\n return (\n <TagsInput\n value={arr}\n suggestions={suggestionList}\n loadSuggestions={loadSuggestions}\n allowCustomValues={false}\n resolveLabel={resolveTagLabel}\n resolveDescription={resolveTagDescription}\n placeholder={f.placeholder}\n onChange={(next) => setValue(f.id, next.length ? next : undefined)}\n />\n )\n })()}\n {f.type === 'checkbox' && (\n <div>\n <select\n className=\"w-full h-11 rounded border px-2 text-sm\"\n value={values[f.id] === true ? 'true' : values[f.id] === false ? 'false' : ''}\n onChange={(e) => {\n const v = e.target.value\n if (v === '') setValue(f.id, undefined)\n else if (v === 'true') setValue(f.id, true)\n else if (v === 'false') setValue(f.id, false)\n }}\n >\n <option value=\"\">{t('ui.forms.select.emptyOption', '\u2014')}</option>\n <option value=\"true\">{t('common.yes', 'Yes')}</option>\n <option value=\"false\">{t('common.no', 'No')}</option>\n </select>\n </div>\n )}\n </div>\n ))}\n </div>\n <div className=\"p-4 border-t flex items-center justify-between gap-2\">\n <Button variant=\"outline\" onClick={handleClear}>Clear</Button>\n <Button onClick={handleApply}>\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" aria-hidden=\"true\" className=\"opacity-80\"><path d=\"M3 4h18\"/><path d=\"M6 8h12l-3 8H9L6 8z\"/></svg>\n Apply\n </Button>\n </div>\n </div>\n </div>\n )}\n </>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { Button } from '../primitives/button'\nimport { TagsInput, type TagsInputOption } from './inputs/TagsInput'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\nexport type FilterOption = { value: string; label: string; description?: string | null }\n\nexport type FilterDef = {\n id: string\n label: string\n type: 'text' | 'select' | 'checkbox' | 'dateRange' | 'tags'\n options?: FilterOption[]\n // Optional async loader for options (used by select/tags)\n loadOptions?: (query?: string) => Promise<FilterOption[]>\n multiple?: boolean\n placeholder?: string\n group?: string\n formatValue?: (value: string) => string\n formatDescription?: (value: string) => string | null | undefined\n}\n\nexport type FilterValues = Record<string, any>\n\nexport type FilterOverlayProps = {\n title?: string\n filters: FilterDef[]\n initialValues: FilterValues\n open: boolean\n onOpenChange: (open: boolean) => void\n onApply: (values: FilterValues) => void\n onClear?: () => void\n extraContent?: React.ReactNode\n}\n\nconst EMPTY_FILTER_VALUES: FilterValues = {}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return value != null && typeof value === 'object' && !Array.isArray(value)\n}\n\nfunction normalizeKeys(source: FilterValues | null | undefined): string[] {\n if (!source) return []\n return Object.keys(source).filter((key) => source[key] !== undefined)\n}\n\nfunction areFieldValuesEqual(a: any, b: any): boolean {\n if (a === b) return true\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false\n for (let i = 0; i < a.length; i += 1) {\n if (!areFieldValuesEqual(a[i], b[i])) return false\n }\n return true\n }\n if (isPlainObject(a) && isPlainObject(b)) {\n const keysA = normalizeKeys(a as FilterValues)\n const keysB = normalizeKeys(b as FilterValues)\n if (keysA.length !== keysB.length) return false\n for (const key of keysA) {\n if (!keysB.includes(key)) return false\n if (!areFieldValuesEqual((a as FilterValues)[key], (b as FilterValues)[key])) return false\n }\n return true\n }\n return false\n}\n\nfunction areFilterValuesEqual(a?: FilterValues | null, b?: FilterValues | null): boolean {\n if (a === b) return true\n const keysA = normalizeKeys(a || EMPTY_FILTER_VALUES)\n const keysB = normalizeKeys(b || EMPTY_FILTER_VALUES)\n if (keysA.length !== keysB.length) return false\n for (const key of keysA) {\n if (!keysB.includes(key)) return false\n if (!areFieldValuesEqual(a?.[key], b?.[key])) return false\n }\n return true\n}\n\nexport function FilterOverlay({\n title,\n filters,\n initialValues,\n open,\n onOpenChange,\n onApply,\n onClear,\n extraContent,\n}: FilterOverlayProps) {\n const t = useT()\n const defaultTitle = title ?? t('ui.filters.title', 'Filters')\n const [values, setValues] = React.useState<FilterValues>(initialValues)\n React.useEffect(() => {\n setValues((prev) => (areFilterValuesEqual(prev, initialValues) ? prev : initialValues))\n }, [initialValues])\n const filtersSignature = React.useMemo(\n () => filters.map((f) => `${f.id}:${f.type}:${Boolean((f as any).loadOptions)}:${(f.options || []).length}`).join('|'),\n [filters]\n )\n const lastLoadedSignatureRef = React.useRef<string | null>(null)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const stableFilters = React.useMemo(() => filters, [filtersSignature])\n\n // Load dynamic options for filters that request it\n const [dynamicOptions, setDynamicOptions] = React.useState<Record<string, FilterOption[]>>({})\n React.useEffect(() => {\n if (!open) return\n if (lastLoadedSignatureRef.current === filtersSignature) return\n lastLoadedSignatureRef.current = filtersSignature\n setDynamicOptions({})\n let cancelled = false\n const loadAll = async () => {\n const loaders = filters\n .filter((f): f is FilterDef & { loadOptions: (query?: string) => Promise<FilterOption[]> } => (f as any).loadOptions != null)\n .map(async (f) => {\n try {\n const opts = await (f as any).loadOptions()\n if (!cancelled) setDynamicOptions((prev) => ({ ...prev, [f.id]: opts }))\n } catch {\n // ignore\n }\n })\n await Promise.all(loaders)\n }\n loadAll()\n return () => {\n cancelled = true\n }\n }, [filters, filtersSignature, open])\n React.useEffect(() => {\n if (!open) {\n lastLoadedSignatureRef.current = null\n }\n }, [open])\n\n const setValue = (id: string, v: any) => setValues((prev) => ({ ...prev, [id]: v }))\n\n const handleApply = () => {\n onApply(values)\n onOpenChange(false)\n }\n\n const handleClear = () => {\n setValues({})\n onClear?.()\n }\n\n const tagLoaders = React.useMemo(() => {\n const map = new Map<string, (q?: string) => Promise<Array<string | TagsInputOption>>>()\n for (const f of stableFilters) {\n if (f.type === 'tags' && typeof f.loadOptions === 'function') {\n const fieldId = f.id\n const load = f.loadOptions as (query?: string) => Promise<FilterOption[]>\n map.set(fieldId, async (q?: string) => {\n const query = (q ?? '').trim()\n if (!query.length) return []\n try {\n const opts = await load(query)\n setDynamicOptions((prev) => ({ ...prev, [fieldId]: opts }))\n return opts.map((o) => ({ value: o.value, label: o.label, description: o.description ?? null }))\n } catch {\n return []\n }\n })\n }\n }\n return map\n }, [stableFilters])\n\n return (\n <>\n {open && (\n <div className=\"fixed inset-0 z-50\">\n <div className=\"absolute inset-0 bg-black/30\" onClick={() => onOpenChange(false)} />\n <div className=\"absolute left-0 top-0 h-full w-full sm:w-[380px] bg-background shadow-xl border-r flex flex-col\">\n <div className=\"flex items-center justify-between p-4 border-b\">\n <h2 className=\"text-base font-semibold\">{defaultTitle}</h2>\n <Button variant=\"muted\" size=\"sm\" onClick={() => onOpenChange(false)}>{t('common.close')}</Button>\n </div>\n {/* Top actions: duplicate Clear/Apply */}\n <div className=\"px-4 py-2 border-b flex items-center justify-between gap-2\">\n <Button variant=\"outline\" size=\"sm\" onClick={handleClear}>{t('ui.filters.actions.clear', 'Clear')}</Button>\n <Button size=\"sm\" onClick={handleApply}>\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" aria-hidden=\"true\" className=\"opacity-80\"><path d=\"M3 4h18\"/><path d=\"M6 8h12l-3 8H9L6 8z\"/></svg>\n {t('ui.filters.actions.apply', 'Apply')}\n </Button>\n </div>\n <div className=\"flex-1 overflow-auto p-4 space-y-4\">\n {extraContent ? <div className=\"space-y-2 rounded-md border bg-muted/30 p-3\">{extraContent}</div> : null}\n {filters.map((f) => (\n <div key={f.id} className=\"space-y-2\">\n <div className=\"text-sm font-medium\">{f.label}</div>\n {f.type === 'text' && (\n <input\n type=\"text\"\n className=\"w-full h-11 rounded border px-2 text-sm\"\n placeholder={f.placeholder}\n value={values[f.id] ?? ''}\n onChange={(e) => setValue(f.id, e.target.value || undefined)}\n />\n )}\n {f.type === 'dateRange' && (\n <div className=\"grid grid-cols-1 gap-2\">\n <div>\n <div className=\"text-xs text-muted-foreground mb-1\">{t('ui.filters.dateRange.from', 'From')}</div>\n <input\n type=\"date\"\n className=\"w-full h-11 rounded border px-2 text-sm\"\n value={values[f.id]?.from ?? ''}\n onChange={(e) => setValue(f.id, { ...(values[f.id] ?? {}), from: e.target.value || undefined })}\n />\n </div>\n <div>\n <div className=\"text-xs text-muted-foreground mb-1\">{t('ui.filters.dateRange.to', 'To')}</div>\n <input\n type=\"date\"\n className=\"w-full h-11 rounded border px-2 text-sm\"\n value={values[f.id]?.to ?? ''}\n onChange={(e) => setValue(f.id, { ...(values[f.id] ?? {}), to: e.target.value || undefined })}\n />\n </div>\n </div>\n )}\n {f.type === 'select' && (\n <div className=\"space-y-1\">\n {f.multiple ? (\n <div className=\"flex flex-col gap-1\">\n {(f.options || dynamicOptions[f.id] || []).map((opt) => {\n const arr: string[] = Array.isArray(values[f.id]) ? values[f.id] : []\n const checked = arr.includes(opt.value)\n return (\n <label key={opt.value} className=\"inline-flex items-center gap-2\">\n <input\n type=\"checkbox\"\n checked={checked}\n onChange={(e) => {\n const next = new Set(arr)\n if (e.target.checked) next.add(opt.value)\n else next.delete(opt.value)\n setValue(f.id, Array.from(next))\n }}\n />\n <span className=\"text-sm\">{opt.label}</span>\n </label>\n )\n })}\n </div>\n ) : (\n <select\n className=\"w-full h-11 rounded border px-2 text-sm\"\n value={values[f.id] ?? ''}\n onChange={(e) => setValue(f.id, e.target.value || undefined)}\n >\n <option value=\"\">{t('ui.forms.select.emptyOption', '\u2014')}</option>\n {(f.options || dynamicOptions[f.id] || []).map((opt) => (\n <option key={opt.value} value={opt.value}>{opt.label}</option>\n ))}\n </select>\n )}\n </div>\n )}\n {f.type === 'tags' && (() => {\n const arr: string[] = Array.isArray(values[f.id]) ? values[f.id] : []\n const staticOptions = f.options || []\n const dynamic = dynamicOptions[f.id] || []\n const optionMap = new Map<string, FilterOption>()\n staticOptions.forEach((opt) => optionMap.set(opt.value, opt))\n dynamic.forEach((opt) => optionMap.set(opt.value, opt))\n const loadSuggestions = tagLoaders.get(f.id)\n const resolveTagLabel = f.formatValue\n ? (val: string) => f.formatValue!(val)\n : (val: string) => optionMap.get(val)?.label ?? val\n const resolveTagDescription = f.formatDescription\n ? (val: string) => f.formatDescription!(val) ?? null\n : (val: string) => optionMap.get(val)?.description ?? null\n const suggestionList: TagsInputOption[] = Array.from(optionMap.values()).map((opt) => ({\n value: opt.value,\n label: opt.label,\n description: opt.description ?? null,\n }))\n return (\n <TagsInput\n value={arr}\n suggestions={suggestionList}\n loadSuggestions={loadSuggestions}\n allowCustomValues={false}\n resolveLabel={resolveTagLabel}\n resolveDescription={resolveTagDescription}\n placeholder={f.placeholder}\n onChange={(next) => setValue(f.id, next.length ? next : undefined)}\n />\n )\n })()}\n {f.type === 'checkbox' && (\n <div>\n <select\n className=\"w-full h-11 rounded border px-2 text-sm\"\n value={values[f.id] === true ? 'true' : values[f.id] === false ? 'false' : ''}\n onChange={(e) => {\n const v = e.target.value\n if (v === '') setValue(f.id, undefined)\n else if (v === 'true') setValue(f.id, true)\n else if (v === 'false') setValue(f.id, false)\n }}\n >\n <option value=\"\">{t('ui.forms.select.emptyOption', '\u2014')}</option>\n <option value=\"true\">{t('common.yes', 'Yes')}</option>\n <option value=\"false\">{t('common.no', 'No')}</option>\n </select>\n </div>\n )}\n </div>\n ))}\n </div>\n <div className=\"p-4 border-t flex items-center justify-between gap-2\">\n <Button variant=\"outline\" onClick={handleClear}>{t('ui.filters.actions.clear', 'Clear')}</Button>\n <Button onClick={handleApply}>\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" aria-hidden=\"true\" className=\"opacity-80\"><path d=\"M3 4h18\"/><path d=\"M6 8h12l-3 8H9L6 8z\"/></svg>\n {t('ui.filters.actions.apply', 'Apply')}\n </Button>\n </div>\n </div>\n </div>\n )}\n </>\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.4.5-develop-eeccf7adf4",
3
+ "version": "0.4.5-develop-5191db4ef3",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "scripts": {
@@ -112,7 +112,7 @@
112
112
  }
113
113
  },
114
114
  "dependencies": {
115
- "@open-mercato/shared": "0.4.5-develop-eeccf7adf4",
115
+ "@open-mercato/shared": "0.4.5-develop-5191db4ef3",
116
116
  "@radix-ui/react-popover": "^1.1.6",
117
117
  "@radix-ui/react-tooltip": "^1.2.8",
118
118
  "date-fns": "^4.1.0",
@@ -314,10 +314,10 @@ export function FilterOverlay({
314
314
  ))}
315
315
  </div>
316
316
  <div className="p-4 border-t flex items-center justify-between gap-2">
317
- <Button variant="outline" onClick={handleClear}>Clear</Button>
317
+ <Button variant="outline" onClick={handleClear}>{t('ui.filters.actions.clear', 'Clear')}</Button>
318
318
  <Button onClick={handleApply}>
319
319
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" aria-hidden="true" className="opacity-80"><path d="M3 4h18"/><path d="M6 8h12l-3 8H9L6 8z"/></svg>
320
- Apply
320
+ {t('ui.filters.actions.apply', 'Apply')}
321
321
  </Button>
322
322
  </div>
323
323
  </div>