@soulbatical/tetra-ui 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/FeatureFilters.d.ts +72 -0
- package/dist/components/FeatureFilters.d.ts.map +1 -0
- package/dist/components/FeatureFilters.js +229 -0
- package/dist/components/FeatureFilters.js.map +1 -0
- package/dist/components/FeatureForm.d.ts +100 -0
- package/dist/components/FeatureForm.d.ts.map +1 -0
- package/dist/components/FeatureForm.js +336 -0
- package/dist/components/FeatureForm.js.map +1 -0
- package/dist/components/FeatureTable.d.ts +95 -0
- package/dist/components/FeatureTable.d.ts.map +1 -0
- package/dist/components/FeatureTable.js +278 -0
- package/dist/components/FeatureTable.js.map +1 -0
- package/dist/components/ui/badge.d.ts +10 -0
- package/dist/components/ui/badge.d.ts.map +1 -0
- package/dist/components/ui/badge.js +21 -0
- package/dist/components/ui/badge.js.map +1 -0
- package/dist/components/ui/button.d.ts +12 -0
- package/dist/components/ui/button.d.ts.map +1 -0
- package/dist/components/ui/button.js +34 -0
- package/dist/components/ui/button.js.map +1 -0
- package/dist/components/ui/card.d.ts +9 -0
- package/dist/components/ui/card.d.ts.map +1 -0
- package/dist/components/ui/card.js +17 -0
- package/dist/components/ui/card.js.map +1 -0
- package/dist/components/ui/dialog.d.ts +20 -0
- package/dist/components/ui/dialog.d.ts.map +1 -0
- package/dist/components/ui/dialog.js +24 -0
- package/dist/components/ui/dialog.js.map +1 -0
- package/dist/components/ui/input.d.ts +6 -0
- package/dist/components/ui/input.d.ts.map +1 -0
- package/dist/components/ui/input.js +9 -0
- package/dist/components/ui/input.js.map +1 -0
- package/dist/components/ui/label.d.ts +8 -0
- package/dist/components/ui/label.d.ts.map +1 -0
- package/dist/components/ui/label.js +10 -0
- package/dist/components/ui/label.js.map +1 -0
- package/dist/components/ui/select.d.ts +14 -0
- package/dist/components/ui/select.d.ts.map +1 -0
- package/dist/components/ui/select.js +28 -0
- package/dist/components/ui/select.js.map +1 -0
- package/dist/components/ui/table.d.ts +11 -0
- package/dist/components/ui/table.d.ts.map +1 -0
- package/dist/components/ui/table.js +21 -0
- package/dist/components/ui/table.js.map +1 -0
- package/dist/components/ui/tabs.d.ts +8 -0
- package/dist/components/ui/tabs.d.ts.map +1 -0
- package/dist/components/ui/tabs.js +14 -0
- package/dist/components/ui/tabs.js.map +1 -0
- package/dist/components/ui/textarea.d.ts +6 -0
- package/dist/components/ui/textarea.d.ts.map +1 -0
- package/dist/components/ui/textarea.js +9 -0
- package/dist/components/ui/textarea.js.map +1 -0
- package/dist/hooks/useAffiliateDashboard.d.ts +86 -0
- package/dist/hooks/useAffiliateDashboard.d.ts.map +1 -0
- package/dist/hooks/useAffiliateDashboard.js +161 -0
- package/dist/hooks/useAffiliateDashboard.js.map +1 -0
- package/dist/hooks/useFeature.d.ts +100 -0
- package/dist/hooks/useFeature.d.ts.map +1 -0
- package/dist/hooks/useFeature.js +325 -0
- package/dist/hooks/useFeature.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -1
- package/dist/tailwind-preset.d.ts +17 -0
- package/dist/tailwind-preset.d.ts.map +1 -0
- package/dist/tailwind-preset.js +86 -0
- package/dist/tailwind-preset.js.map +1 -0
- package/package.json +37 -7
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FeatureFilters — Config-driven filter bar component
|
|
3
|
+
*
|
|
4
|
+
* Replaces ALL per-feature filter implementations with a single generic component
|
|
5
|
+
* driven by FeatureConfig.filters[].
|
|
6
|
+
*
|
|
7
|
+
* Filter type → UI mapping:
|
|
8
|
+
* - search → SearchInput (debounced text input)
|
|
9
|
+
* - enum → Select dropdown
|
|
10
|
+
* - column → Select dropdown (same as enum, column-based)
|
|
11
|
+
* - boolean → Toggle / Switch
|
|
12
|
+
* - multiselect → Multi-select with checkboxes
|
|
13
|
+
* - daterange → Date range picker (from/to)
|
|
14
|
+
* - time → Select dropdown (preset time periods)
|
|
15
|
+
* - nullable → Select dropdown (all/with/without)
|
|
16
|
+
* - related → Select dropdown (all/with/without)
|
|
17
|
+
* - numeric → Number range inputs (min/max)
|
|
18
|
+
* - array → Multi-select (same UI as multiselect)
|
|
19
|
+
*
|
|
20
|
+
* @module @tetra/ui
|
|
21
|
+
*/
|
|
22
|
+
import React from 'react';
|
|
23
|
+
import type { FeatureConfig, FilterConfig } from '@soulbatical/tetra-core';
|
|
24
|
+
import type { UseFeatureResult } from '../hooks/useFeature.js';
|
|
25
|
+
export interface FeatureFiltersProps<TItem = Record<string, unknown>> {
|
|
26
|
+
/** Feature configuration with filters[] */
|
|
27
|
+
config: FeatureConfig<TItem>;
|
|
28
|
+
/** Result from useFeature() hook */
|
|
29
|
+
feature: UseFeatureResult<TItem>;
|
|
30
|
+
/** CSS class for the filter bar wrapper */
|
|
31
|
+
className?: string;
|
|
32
|
+
/** Layout: horizontal bar or vertical stack (default: 'horizontal') */
|
|
33
|
+
layout?: 'horizontal' | 'vertical';
|
|
34
|
+
/** Show reset button (default: true) */
|
|
35
|
+
showReset?: boolean;
|
|
36
|
+
/** Reset button label (default: 'Reset') */
|
|
37
|
+
resetLabel?: string;
|
|
38
|
+
/** Show active filter count badge (default: true) */
|
|
39
|
+
showActiveCount?: boolean;
|
|
40
|
+
/** Collapse filters behind a "More filters" button (default: auto based on filter count) */
|
|
41
|
+
collapsible?: boolean;
|
|
42
|
+
/** Max visible filters before collapsing (default: 4) */
|
|
43
|
+
maxVisible?: number;
|
|
44
|
+
/** "More filters" button label (default: 'More filters') */
|
|
45
|
+
moreLabel?: string;
|
|
46
|
+
/** Show filter count badges from feature.counts (default: true) */
|
|
47
|
+
showCounts?: boolean;
|
|
48
|
+
/** Custom filter renderers (keyed by filter name) */
|
|
49
|
+
filterRenderers?: Record<string, (filter: FilterConfig, value: string | string[] | undefined, onChange: (value: string | string[] | undefined) => void, counts?: Record<string, number>) => React.ReactNode>;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* FeatureFilters — Config-driven filter bar
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```tsx
|
|
56
|
+
* import { ordersConfig } from '@/config/features/orders.config';
|
|
57
|
+
* import { useFeature, FeatureFilters, FeatureTable } from '@soulbatical/tetra-ui';
|
|
58
|
+
*
|
|
59
|
+
* function OrdersPage() {
|
|
60
|
+
* const feature = useFeature(ordersConfig, supabase, { organizationId });
|
|
61
|
+
*
|
|
62
|
+
* return (
|
|
63
|
+
* <div>
|
|
64
|
+
* <FeatureFilters config={ordersConfig} feature={feature} />
|
|
65
|
+
* <FeatureTable config={ordersConfig} feature={feature} />
|
|
66
|
+
* </div>
|
|
67
|
+
* );
|
|
68
|
+
* }
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export declare function FeatureFilters<TItem = Record<string, unknown>>({ config, feature, className, layout, showReset, resetLabel, showActiveCount, collapsible, maxVisible, moreLabel, showCounts, filterRenderers, }: FeatureFiltersProps<TItem>): import("react/jsx-runtime").JSX.Element;
|
|
72
|
+
//# sourceMappingURL=FeatureFilters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FeatureFilters.d.ts","sourceRoot":"","sources":["../../src/components/FeatureFilters.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAyC,MAAM,OAAO,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAkB,MAAM,yBAAyB,CAAC;AAC3F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAU/D,MAAM,WAAW,mBAAmB,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAClE,2CAA2C;IAC3C,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC;IAE7B,oCAAoC;IACpC,OAAO,EAAE,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAEjC,2CAA2C;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,uEAAuE;IACvE,MAAM,CAAC,EAAE,YAAY,GAAG,UAAU,CAAC;IAEnC,wCAAwC;IACxC,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,4CAA4C;IAC5C,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,qDAAqD;IACrD,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B,4FAA4F;IAC5F,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB,yDAAyD;IACzD,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,4DAA4D;IAC5D,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,mEAAmE;IACnE,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB,qDAAqD;IACrD,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAC/B,MAAM,EAAE,YAAY,EACpB,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EACpC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,KAAK,IAAI,EACxD,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAC5B,KAAK,CAAC,SAAS,CAAC,CAAC;CACvB;AAsZD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,cAAc,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAC9D,MAAM,EACN,OAAO,EACP,SAAS,EACT,MAAqB,EACrB,SAAgB,EAChB,UAAoB,EACpB,eAAsB,EACtB,WAAW,EACX,UAAc,EACd,SAA0B,EAC1B,UAAiB,EACjB,eAAe,GAChB,EAAE,mBAAmB,CAAC,KAAK,CAAC,2CA8H5B"}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* FeatureFilters — Config-driven filter bar component
|
|
4
|
+
*
|
|
5
|
+
* Replaces ALL per-feature filter implementations with a single generic component
|
|
6
|
+
* driven by FeatureConfig.filters[].
|
|
7
|
+
*
|
|
8
|
+
* Filter type → UI mapping:
|
|
9
|
+
* - search → SearchInput (debounced text input)
|
|
10
|
+
* - enum → Select dropdown
|
|
11
|
+
* - column → Select dropdown (same as enum, column-based)
|
|
12
|
+
* - boolean → Toggle / Switch
|
|
13
|
+
* - multiselect → Multi-select with checkboxes
|
|
14
|
+
* - daterange → Date range picker (from/to)
|
|
15
|
+
* - time → Select dropdown (preset time periods)
|
|
16
|
+
* - nullable → Select dropdown (all/with/without)
|
|
17
|
+
* - related → Select dropdown (all/with/without)
|
|
18
|
+
* - numeric → Number range inputs (min/max)
|
|
19
|
+
* - array → Multi-select (same UI as multiselect)
|
|
20
|
+
*
|
|
21
|
+
* @module @tetra/ui
|
|
22
|
+
*/
|
|
23
|
+
import { useCallback, useMemo, useState } from 'react';
|
|
24
|
+
// ─── DOM Helpers (no DOM lib in tsconfig) ───────────────────
|
|
25
|
+
function getInputValue(e) {
|
|
26
|
+
return e.target.value;
|
|
27
|
+
}
|
|
28
|
+
// ─── Filter Option Builders ─────────────────────────────────
|
|
29
|
+
function buildEnumOptions(filter) {
|
|
30
|
+
if (filter.ui?.options) {
|
|
31
|
+
return [
|
|
32
|
+
{ value: 'all', label: 'All' },
|
|
33
|
+
...filter.ui.options,
|
|
34
|
+
];
|
|
35
|
+
}
|
|
36
|
+
if (filter.values) {
|
|
37
|
+
return [
|
|
38
|
+
{ value: 'all', label: 'All' },
|
|
39
|
+
...filter.values.map(v => ({
|
|
40
|
+
value: v,
|
|
41
|
+
label: v.charAt(0).toUpperCase() + v.slice(1).replace(/_/g, ' '),
|
|
42
|
+
})),
|
|
43
|
+
];
|
|
44
|
+
}
|
|
45
|
+
return [{ value: 'all', label: 'All' }];
|
|
46
|
+
}
|
|
47
|
+
function buildNullableOptions(filter) {
|
|
48
|
+
const withLabel = filter.ui?.withLabel ?? 'With';
|
|
49
|
+
const withoutLabel = filter.ui?.withoutLabel ?? 'Without';
|
|
50
|
+
return [
|
|
51
|
+
{ value: 'all', label: 'All' },
|
|
52
|
+
{ value: 'with', label: withLabel },
|
|
53
|
+
{ value: 'without', label: withoutLabel },
|
|
54
|
+
];
|
|
55
|
+
}
|
|
56
|
+
function SearchFilter({ filter, value, onChange }) {
|
|
57
|
+
const ui = filter.ui;
|
|
58
|
+
return (_jsxs("div", { className: "relative", children: [_jsxs("svg", { className: "absolute left-2.5 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground pointer-events-none", xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("circle", { cx: "11", cy: "11", r: "8" }), _jsx("path", { d: "m21 21-4.3-4.3" })] }), _jsx("input", { type: "text", value: value || '', onChange: (e) => onChange(getInputValue(e) || undefined), placeholder: ui?.placeholder ?? 'Search...', className: "h-9 w-full rounded-md border border-input bg-background pl-8 pr-3 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", "aria-label": ui?.label ?? 'Search' }), value && (_jsx("button", { type: "button", onClick: () => onChange(undefined), className: "absolute right-2 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground", "aria-label": "Clear search", children: _jsx("svg", { className: "h-3.5 w-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: _jsx("path", { d: "M18 6 6 18M6 6l12 12" }) }) }))] }));
|
|
59
|
+
}
|
|
60
|
+
function SelectFilter({ filter, value, onChange, counts }) {
|
|
61
|
+
const ui = filter.ui;
|
|
62
|
+
let options;
|
|
63
|
+
if (filter.type === 'nullable' || filter.type === 'related') {
|
|
64
|
+
options = buildNullableOptions(filter);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
options = buildEnumOptions(filter);
|
|
68
|
+
}
|
|
69
|
+
return (_jsxs("div", { className: "flex flex-col gap-1", children: [ui?.label && (_jsx("label", { className: "text-xs font-medium text-muted-foreground", children: ui.label })), _jsx("select", { value: value || 'all', onChange: (e) => {
|
|
70
|
+
const val = getInputValue(e);
|
|
71
|
+
onChange(val === 'all' ? 'all' : val);
|
|
72
|
+
}, className: "h-9 rounded-md border border-input bg-background px-3 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", "aria-label": ui?.label ?? filter.name, children: options.map(opt => (_jsxs("option", { value: opt.value, children: [opt.label, counts && opt.value !== 'all' && counts[opt.value] !== undefined
|
|
73
|
+
? ` (${counts[opt.value]})`
|
|
74
|
+
: ''] }, opt.value))) })] }));
|
|
75
|
+
}
|
|
76
|
+
function BooleanFilter({ filter, value, onChange }) {
|
|
77
|
+
const ui = filter.ui;
|
|
78
|
+
const checked = value === 'true' || value === true;
|
|
79
|
+
return (_jsxs("label", { className: "flex items-center gap-2 cursor-pointer", children: [_jsx("button", { type: "button", role: "switch", "aria-checked": checked, "aria-label": ui?.label ?? filter.name, onClick: () => onChange(checked ? undefined : 'true'), className: `relative inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring ${checked ? 'bg-primary' : 'bg-input'}`, children: _jsx("span", { className: `pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform ${checked ? 'translate-x-4' : 'translate-x-0'}` }) }), ui?.label && (_jsx("span", { className: "text-sm font-medium", children: ui.label }))] }));
|
|
80
|
+
}
|
|
81
|
+
function MultiSelectFilter({ filter, value, onChange }) {
|
|
82
|
+
const ui = filter.ui;
|
|
83
|
+
const [open, setOpen] = useState(false);
|
|
84
|
+
const selectedValues = Array.isArray(value) ? value : value ? [value] : [];
|
|
85
|
+
const options = ui?.options ?? filter.values?.map(v => ({
|
|
86
|
+
value: v,
|
|
87
|
+
label: v.charAt(0).toUpperCase() + v.slice(1).replace(/_/g, ' '),
|
|
88
|
+
})) ?? [];
|
|
89
|
+
const handleToggle = useCallback((optionValue) => {
|
|
90
|
+
const next = selectedValues.includes(optionValue)
|
|
91
|
+
? selectedValues.filter(v => v !== optionValue)
|
|
92
|
+
: [...selectedValues, optionValue];
|
|
93
|
+
onChange(next.length > 0 ? next : undefined);
|
|
94
|
+
}, [selectedValues, onChange]);
|
|
95
|
+
const selectedLabel = selectedValues.length === 0
|
|
96
|
+
? (ui?.placeholder ?? 'Select...')
|
|
97
|
+
: selectedValues.length === 1
|
|
98
|
+
? options.find(o => o.value === selectedValues[0])?.label ?? selectedValues[0]
|
|
99
|
+
: `${selectedValues.length} selected`;
|
|
100
|
+
return (_jsxs("div", { className: "relative flex flex-col gap-1", children: [ui?.label && (_jsx("label", { className: "text-xs font-medium text-muted-foreground", children: ui.label })), _jsxs("button", { type: "button", onClick: () => setOpen(!open), className: "flex h-9 w-full items-center justify-between rounded-md border border-input bg-background px-3 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", "aria-expanded": open, "aria-label": ui?.label ?? filter.name, children: [_jsx("span", { className: selectedValues.length === 0 ? 'text-muted-foreground' : '', children: selectedLabel }), _jsx("svg", { className: "h-4 w-4 opacity-50", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: _jsx("path", { d: "m6 9 6 6 6-6" }) })] }), open && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-40", onClick: () => setOpen(false) }), _jsxs("div", { className: "absolute top-full left-0 z-50 mt-1 w-full rounded-md border bg-popover shadow-md", children: [_jsx("div", { className: "max-h-60 overflow-y-auto p-1", children: options.map(opt => (_jsxs("label", { className: "flex cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-sm hover:bg-accent", children: [_jsx("input", { type: "checkbox", checked: selectedValues.includes(opt.value), onChange: () => handleToggle(opt.value), className: "h-4 w-4 rounded border-input" }), opt.label] }, opt.value))) }), selectedValues.length > 0 && (_jsx("div", { className: "border-t p-1", children: _jsx("button", { type: "button", onClick: () => { onChange(undefined); setOpen(false); }, className: "w-full rounded-sm px-2 py-1.5 text-sm text-muted-foreground hover:bg-accent hover:text-foreground", children: "Clear selection" }) }))] })] }))] }));
|
|
101
|
+
}
|
|
102
|
+
function DateRangeFilter({ filter, value, onChange }) {
|
|
103
|
+
const ui = filter.ui;
|
|
104
|
+
const parts = typeof value === 'string' ? value.split('|') : ['', ''];
|
|
105
|
+
const startDate = parts[0] || '';
|
|
106
|
+
const endDate = parts[1] || '';
|
|
107
|
+
const handleChange = useCallback((start, end) => {
|
|
108
|
+
if (!start && !end) {
|
|
109
|
+
onChange(undefined);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
onChange(`${start}|${end}`);
|
|
113
|
+
}
|
|
114
|
+
}, [onChange]);
|
|
115
|
+
return (_jsxs("div", { className: "flex flex-col gap-1", children: [ui?.label && (_jsx("label", { className: "text-xs font-medium text-muted-foreground", children: ui.label })), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("input", { type: "date", value: startDate, onChange: (e) => handleChange(getInputValue(e), endDate), min: ui?.minDate, max: ui?.maxDate, className: "h-9 rounded-md border border-input bg-background px-3 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", "aria-label": `${ui?.label ?? filter.name} from` }), _jsx("span", { className: "text-muted-foreground text-sm", children: "\u2013" }), _jsx("input", { type: "date", value: endDate, onChange: (e) => handleChange(startDate, getInputValue(e)), min: ui?.minDate, max: ui?.maxDate, className: "h-9 rounded-md border border-input bg-background px-3 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", "aria-label": `${ui?.label ?? filter.name} to` })] })] }));
|
|
116
|
+
}
|
|
117
|
+
function NumericFilter({ filter, value, onChange }) {
|
|
118
|
+
const ui = filter.ui;
|
|
119
|
+
const parts = typeof value === 'string' ? value.split('|') : ['', ''];
|
|
120
|
+
const minVal = parts[0] || '';
|
|
121
|
+
const maxVal = parts[1] || '';
|
|
122
|
+
const handleChange = useCallback((min, max) => {
|
|
123
|
+
if (!min && !max) {
|
|
124
|
+
onChange(undefined);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
onChange(`${min}|${max}`);
|
|
128
|
+
}
|
|
129
|
+
}, [onChange]);
|
|
130
|
+
return (_jsxs("div", { className: "flex flex-col gap-1", children: [ui?.label && (_jsx("label", { className: "text-xs font-medium text-muted-foreground", children: ui.label })), _jsxs("div", { className: "flex items-center gap-2", children: [ui?.prefix && _jsx("span", { className: "text-sm text-muted-foreground", children: ui.prefix }), _jsx("input", { type: "number", value: minVal, onChange: (e) => handleChange(getInputValue(e), maxVal), placeholder: "Min", min: ui?.min, max: ui?.max, step: ui?.step, className: "h-9 w-24 rounded-md border border-input bg-background px-3 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", "aria-label": `${ui?.label ?? filter.name} minimum` }), _jsx("span", { className: "text-muted-foreground text-sm", children: "\u2013" }), _jsx("input", { type: "number", value: maxVal, onChange: (e) => handleChange(minVal, getInputValue(e)), placeholder: "Max", min: ui?.min, max: ui?.max, step: ui?.step, className: "h-9 w-24 rounded-md border border-input bg-background px-3 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", "aria-label": `${ui?.label ?? filter.name} maximum` }), ui?.suffix && _jsx("span", { className: "text-sm text-muted-foreground", children: ui.suffix })] })] }));
|
|
131
|
+
}
|
|
132
|
+
// ─── Filter Router ──────────────────────────────────────────
|
|
133
|
+
function renderFilter(filter, value, onChange, counts, customRenderer) {
|
|
134
|
+
if (customRenderer) {
|
|
135
|
+
return customRenderer(filter, value, onChange, counts);
|
|
136
|
+
}
|
|
137
|
+
const props = { filter, value, onChange, counts };
|
|
138
|
+
switch (filter.type) {
|
|
139
|
+
case 'search':
|
|
140
|
+
return _jsx(SearchFilter, { ...props });
|
|
141
|
+
case 'enum':
|
|
142
|
+
case 'column':
|
|
143
|
+
case 'time':
|
|
144
|
+
case 'nullable':
|
|
145
|
+
case 'related':
|
|
146
|
+
return _jsx(SelectFilter, { ...props });
|
|
147
|
+
case 'boolean':
|
|
148
|
+
return _jsx(BooleanFilter, { ...props });
|
|
149
|
+
case 'multiselect':
|
|
150
|
+
case 'array':
|
|
151
|
+
return _jsx(MultiSelectFilter, { ...props });
|
|
152
|
+
case 'daterange':
|
|
153
|
+
return _jsx(DateRangeFilter, { ...props });
|
|
154
|
+
case 'numeric':
|
|
155
|
+
return _jsx(NumericFilter, { ...props });
|
|
156
|
+
default:
|
|
157
|
+
return _jsx(SelectFilter, { ...props });
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
// ─── Active Filter Counter ──────────────────────────────────
|
|
161
|
+
function countActiveFilters(filters, filterConfigs) {
|
|
162
|
+
let count = 0;
|
|
163
|
+
for (const fc of filterConfigs) {
|
|
164
|
+
const val = filters[fc.name];
|
|
165
|
+
if (val === undefined || val === 'all')
|
|
166
|
+
continue;
|
|
167
|
+
if (Array.isArray(val) && val.length === 0)
|
|
168
|
+
continue;
|
|
169
|
+
if (typeof val === 'string' && val.trim() === '')
|
|
170
|
+
continue;
|
|
171
|
+
count++;
|
|
172
|
+
}
|
|
173
|
+
return count;
|
|
174
|
+
}
|
|
175
|
+
// ─── Main Component ─────────────────────────────────────────
|
|
176
|
+
/**
|
|
177
|
+
* FeatureFilters — Config-driven filter bar
|
|
178
|
+
*
|
|
179
|
+
* @example
|
|
180
|
+
* ```tsx
|
|
181
|
+
* import { ordersConfig } from '@/config/features/orders.config';
|
|
182
|
+
* import { useFeature, FeatureFilters, FeatureTable } from '@soulbatical/tetra-ui';
|
|
183
|
+
*
|
|
184
|
+
* function OrdersPage() {
|
|
185
|
+
* const feature = useFeature(ordersConfig, supabase, { organizationId });
|
|
186
|
+
*
|
|
187
|
+
* return (
|
|
188
|
+
* <div>
|
|
189
|
+
* <FeatureFilters config={ordersConfig} feature={feature} />
|
|
190
|
+
* <FeatureTable config={ordersConfig} feature={feature} />
|
|
191
|
+
* </div>
|
|
192
|
+
* );
|
|
193
|
+
* }
|
|
194
|
+
* ```
|
|
195
|
+
*/
|
|
196
|
+
export function FeatureFilters({ config, feature, className, layout = 'horizontal', showReset = true, resetLabel = 'Reset', showActiveCount = true, collapsible, maxVisible = 4, moreLabel = 'More filters', showCounts = true, filterRenderers, }) {
|
|
197
|
+
const { filters, setFilter, resetFilters, counts } = feature;
|
|
198
|
+
const [showMore, setShowMore] = useState(false);
|
|
199
|
+
const sortedFilters = useMemo(() => {
|
|
200
|
+
const filterConfigs = config.filters || [];
|
|
201
|
+
return [...filterConfigs].sort((a, b) => (a.ui?.order ?? 999) - (b.ui?.order ?? 999));
|
|
202
|
+
}, [config.filters]);
|
|
203
|
+
const shouldCollapse = collapsible ?? sortedFilters.length > maxVisible;
|
|
204
|
+
const { visibleFilters, collapsedFilters } = useMemo(() => {
|
|
205
|
+
if (!shouldCollapse) {
|
|
206
|
+
return { visibleFilters: sortedFilters, collapsedFilters: [] };
|
|
207
|
+
}
|
|
208
|
+
const alwaysVisible = sortedFilters.filter(f => f.ui?.defaultVisible !== false && (f.type === 'search' || f.ui?.defaultVisible === true));
|
|
209
|
+
const maybeCollapsed = sortedFilters.filter(f => !alwaysVisible.includes(f));
|
|
210
|
+
const slotsLeft = Math.max(0, maxVisible - alwaysVisible.length);
|
|
211
|
+
const visible = [...alwaysVisible, ...maybeCollapsed.slice(0, slotsLeft)];
|
|
212
|
+
const collapsed = maybeCollapsed.slice(slotsLeft);
|
|
213
|
+
return { visibleFilters: visible, collapsedFilters: collapsed };
|
|
214
|
+
}, [sortedFilters, shouldCollapse, maxVisible]);
|
|
215
|
+
const activeCount = useMemo(() => countActiveFilters(filters, sortedFilters), [filters, sortedFilters]);
|
|
216
|
+
const getFilterCounts = useCallback((filter) => {
|
|
217
|
+
if (!showCounts)
|
|
218
|
+
return undefined;
|
|
219
|
+
const key = filter.countsKey ?? filter.name;
|
|
220
|
+
const c = counts[key];
|
|
221
|
+
if (c && typeof c === 'object' && !Array.isArray(c)) {
|
|
222
|
+
return c;
|
|
223
|
+
}
|
|
224
|
+
return undefined;
|
|
225
|
+
}, [counts, showCounts]);
|
|
226
|
+
const isHorizontal = layout === 'horizontal';
|
|
227
|
+
return (_jsxs("div", { className: `${isHorizontal ? 'flex flex-wrap items-end gap-3' : 'flex flex-col gap-3'} ${className ?? ''}`, role: "search", "aria-label": "Filters", children: [visibleFilters.map(filter => (_jsx("div", { className: isHorizontal ? 'min-w-[160px]' : '', children: renderFilter(filter, filters[filter.name], (val) => setFilter(filter.name, val), getFilterCounts(filter), filterRenderers?.[filter.name]) }, filter.name))), collapsedFilters.length > 0 && (_jsxs(_Fragment, { children: [_jsxs("button", { type: "button", onClick: () => setShowMore(!showMore), className: "inline-flex h-9 items-center gap-1.5 rounded-md border border-dashed border-input px-3 text-sm font-medium text-muted-foreground hover:bg-accent hover:text-foreground", "aria-expanded": showMore, children: [_jsxs("svg", { className: "h-4 w-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [_jsx("line", { x1: "4", x2: "20", y1: "21", y2: "21" }), _jsx("line", { x1: "4", x2: "20", y1: "14", y2: "14" }), _jsx("line", { x1: "4", x2: "20", y1: "7", y2: "7" })] }), moreLabel, !showMore && activeCount > visibleFilters.length && (_jsx("span", { className: "inline-flex h-5 min-w-5 items-center justify-center rounded-full bg-primary px-1.5 text-xs font-medium text-primary-foreground", children: activeCount - countActiveFilters(filters, visibleFilters) }))] }), showMore && (_jsx("div", { className: `${isHorizontal ? 'flex flex-wrap items-end gap-3 basis-full' : 'flex flex-col gap-3'}`, children: collapsedFilters.map(filter => (_jsx("div", { className: isHorizontal ? 'min-w-[160px]' : '', children: renderFilter(filter, filters[filter.name], (val) => setFilter(filter.name, val), getFilterCounts(filter), filterRenderers?.[filter.name]) }, filter.name))) }))] })), showReset && activeCount > 0 && (_jsxs("button", { type: "button", onClick: resetFilters, className: "inline-flex h-9 items-center gap-1.5 rounded-md px-3 text-sm font-medium text-muted-foreground hover:bg-accent hover:text-foreground", children: [_jsx("svg", { className: "h-3.5 w-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: _jsx("path", { d: "M18 6 6 18M6 6l12 12" }) }), resetLabel, showActiveCount && (_jsx("span", { className: "inline-flex h-5 min-w-5 items-center justify-center rounded-full bg-muted px-1.5 text-xs font-medium", children: activeCount }))] }))] }));
|
|
228
|
+
}
|
|
229
|
+
//# sourceMappingURL=FeatureFilters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FeatureFilters.js","sourceRoot":"","sources":["../../src/components/FeatureFilters.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FeatureForm — Config-driven create/edit form component
|
|
3
|
+
*
|
|
4
|
+
* Replaces ALL per-feature form implementations with a single generic component
|
|
5
|
+
* driven by FeatureConfig.formFields[].
|
|
6
|
+
*
|
|
7
|
+
* Field type → UI mapping:
|
|
8
|
+
* - text/email/password/url/phone → text input
|
|
9
|
+
* - number/currency/percentage → number input (with prefix/suffix)
|
|
10
|
+
* - textarea → textarea
|
|
11
|
+
* - select/combobox → select dropdown
|
|
12
|
+
* - multiselect → multi-checkbox dropdown
|
|
13
|
+
* - boolean/switch/checkbox → toggle / checkbox
|
|
14
|
+
* - date/datetime → date/datetime input
|
|
15
|
+
* - daterange → two date inputs
|
|
16
|
+
* - color → color input
|
|
17
|
+
* - file/image → file input
|
|
18
|
+
* - hidden → hidden input
|
|
19
|
+
* - richtext → textarea (upgrade to rich editor via customComponents)
|
|
20
|
+
* - custom → custom component from registry
|
|
21
|
+
*
|
|
22
|
+
* @module @tetra/ui
|
|
23
|
+
*/
|
|
24
|
+
import React from 'react';
|
|
25
|
+
import type { FeatureConfig, FormFieldConfig } from '@soulbatical/tetra-core';
|
|
26
|
+
/** Registry of custom field components */
|
|
27
|
+
export type CustomComponentMap = Record<string, (props: {
|
|
28
|
+
field: FormFieldConfig;
|
|
29
|
+
value: unknown;
|
|
30
|
+
onChange: (value: unknown) => void;
|
|
31
|
+
error?: string;
|
|
32
|
+
disabled?: boolean;
|
|
33
|
+
}) => React.ReactNode>;
|
|
34
|
+
export interface FeatureFormProps<TItem = Record<string, unknown>> {
|
|
35
|
+
/** Feature configuration with formFields[] */
|
|
36
|
+
config: FeatureConfig<TItem>;
|
|
37
|
+
/** Form mode: determines which fields to show and submit label */
|
|
38
|
+
mode: 'create' | 'edit';
|
|
39
|
+
/** Initial values for edit mode (existing record data) */
|
|
40
|
+
defaultValues?: Partial<TItem>;
|
|
41
|
+
/** Submit handler — receives validated form data */
|
|
42
|
+
onSubmit: (data: Record<string, unknown>) => void | Promise<void>;
|
|
43
|
+
/** Cancel handler */
|
|
44
|
+
onCancel?: () => void;
|
|
45
|
+
/** External validation errors (e.g., from API response) */
|
|
46
|
+
errors?: Record<string, string>;
|
|
47
|
+
/** Zod schema for validation (optional — uses config.required as fallback) */
|
|
48
|
+
schema?: {
|
|
49
|
+
parse: (data: unknown) => unknown;
|
|
50
|
+
safeParse: (data: unknown) => {
|
|
51
|
+
success: boolean;
|
|
52
|
+
error?: {
|
|
53
|
+
issues: Array<{
|
|
54
|
+
path: Array<string | number>;
|
|
55
|
+
message: string;
|
|
56
|
+
}>;
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
/** Custom field components (keyed by customComponent name) */
|
|
61
|
+
customComponents?: CustomComponentMap;
|
|
62
|
+
/** Submit button label (default: 'Create' / 'Save') */
|
|
63
|
+
submitLabel?: string;
|
|
64
|
+
/** Cancel button label (default: 'Cancel') */
|
|
65
|
+
cancelLabel?: string;
|
|
66
|
+
/** Show cancel button (default: true if onCancel provided) */
|
|
67
|
+
showCancel?: boolean;
|
|
68
|
+
/** Form is submitting (shows loading state) */
|
|
69
|
+
submitting?: boolean;
|
|
70
|
+
/** CSS class for form wrapper */
|
|
71
|
+
className?: string;
|
|
72
|
+
/** Disable all fields (e.g., while submitting) */
|
|
73
|
+
disabled?: boolean;
|
|
74
|
+
/** Layout: single column or two columns (default: auto based on field.width) */
|
|
75
|
+
layout?: 'single' | 'grid';
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* FeatureForm — Config-driven create/edit form
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```tsx
|
|
82
|
+
* import { ordersConfig } from '@/config/features/orders.config';
|
|
83
|
+
* import { FeatureForm } from '@soulbatical/tetra-ui';
|
|
84
|
+
*
|
|
85
|
+
* function CreateOrderDialog() {
|
|
86
|
+
* return (
|
|
87
|
+
* <FeatureForm
|
|
88
|
+
* config={ordersConfig}
|
|
89
|
+
* mode="create"
|
|
90
|
+
* onSubmit={async (data) => {
|
|
91
|
+
* await createOrder(data);
|
|
92
|
+
* }}
|
|
93
|
+
* onCancel={() => setOpen(false)}
|
|
94
|
+
* />
|
|
95
|
+
* );
|
|
96
|
+
* }
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
export declare function FeatureForm<TItem = Record<string, unknown>>({ config, mode, defaultValues, onSubmit, onCancel, errors: externalErrors, schema, customComponents, submitLabel, cancelLabel, showCancel, submitting, className, disabled: formDisabled, layout, }: FeatureFormProps<TItem>): import("react/jsx-runtime").JSX.Element;
|
|
100
|
+
//# sourceMappingURL=FeatureForm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FeatureForm.d.ts","sourceRoot":"","sources":["../../src/components/FeatureForm.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAyC,MAAM,OAAO,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAmB9E,0CAA0C;AAC1C,MAAM,MAAM,kBAAkB,GAAG,MAAM,CACrC,MAAM,EACN,CAAC,KAAK,EAAE;IACN,KAAK,EAAE,eAAe,CAAC;IACvB,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,KAAK,KAAK,CAAC,SAAS,CACtB,CAAC;AAEF,MAAM,WAAW,gBAAgB,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC/D,8CAA8C;IAC9C,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC;IAE7B,kEAAkE;IAClE,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC;IAExB,0DAA0D;IAC1D,aAAa,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IAE/B,oDAAoD;IACpD,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAElE,qBAAqB;IACrB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IAEtB,2DAA2D;IAC3D,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEhC,8EAA8E;IAC9E,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC;QAAC,SAAS,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK;YAAE,OAAO,EAAE,OAAO,CAAC;YAAC,KAAK,CAAC,EAAE;gBAAE,MAAM,EAAE,KAAK,CAAC;oBAAE,IAAI,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;oBAAC,OAAO,EAAE,MAAM,CAAA;iBAAE,CAAC,CAAA;aAAE,CAAA;SAAE,CAAA;KAAE,CAAC;IAEjL,8DAA8D;IAC9D,gBAAgB,CAAC,EAAE,kBAAkB,CAAC;IAEtC,uDAAuD;IACvD,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,8CAA8C;IAC9C,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,8DAA8D;IAC9D,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB,+CAA+C;IAC/C,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB,iCAAiC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,kDAAkD;IAClD,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,gFAAgF;IAChF,MAAM,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;CAC5B;AAwgBD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,WAAW,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAC3D,MAAM,EACN,IAAI,EACJ,aAAa,EACb,QAAQ,EACR,QAAQ,EACR,MAAM,EAAE,cAAc,EACtB,MAAM,EACN,gBAAgB,EAChB,WAAW,EACX,WAAsB,EACtB,UAAU,EACV,UAAkB,EAClB,SAAS,EACT,QAAQ,EAAE,YAAoB,EAC9B,MAAM,GACP,EAAE,gBAAgB,CAAC,KAAK,CAAC,2CAoMzB"}
|