@officina/ui 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,19 @@
1
+ import { dayPickerClassNames } from './chunk-GE4PQEOQ.js';
2
+ import { DayPicker } from 'react-day-picker';
3
+ import { jsx } from 'react/jsx-runtime';
4
+
5
+ function DateRangeFilterCalendar({ value, onChange }) {
6
+ return /* @__PURE__ */ jsx("div", { className: "w-full", children: /* @__PURE__ */ jsx(
7
+ DayPicker,
8
+ {
9
+ mode: "range",
10
+ resetOnSelect: true,
11
+ selected: value,
12
+ onSelect: (range) => onChange(range ?? { from: void 0, to: void 0 }),
13
+ numberOfMonths: 2,
14
+ classNames: dayPickerClassNames
15
+ }
16
+ ) });
17
+ }
18
+
19
+ export { DateRangeFilterCalendar };
@@ -0,0 +1 @@
1
+ export { FilterGroupEditor } from './chunk-BNEIT5XY.js';
@@ -0,0 +1,129 @@
1
+ import { useFiltersContext, Select, Button, isGroup, FilterBuilder, DEFAULT_OPERATOR, defaultValueForOperator } from './chunk-LMM3LYFT.js';
2
+ import { nanoid } from 'nanoid';
3
+ import { jsx, jsxs } from 'react/jsx-runtime';
4
+
5
+ var makeCondition = (fields) => {
6
+ const field = fields[0];
7
+ if (!field) return null;
8
+ const op = field.operators?.[0] ?? DEFAULT_OPERATOR[field.type];
9
+ return {
10
+ id: nanoid(),
11
+ field: field.id,
12
+ op,
13
+ value: defaultValueForOperator(op, field)
14
+ };
15
+ };
16
+ var updateGroupById = (group, id, update) => {
17
+ if (group.id === id) return update(group);
18
+ return {
19
+ ...group,
20
+ conditions: group.conditions.map(
21
+ (node) => isGroup(node) ? updateGroupById(node, id, update) : node
22
+ )
23
+ };
24
+ };
25
+ function GroupNode({
26
+ group,
27
+ fields,
28
+ depth,
29
+ maxDepth,
30
+ root
31
+ }) {
32
+ const filters = useFiltersContext();
33
+ const canNest = depth + 1 < maxDepth;
34
+ const updateGroup = (update) => {
35
+ filters.setState((state) => ({
36
+ root: updateGroupById(state.root, group.id, update)
37
+ }));
38
+ };
39
+ const addCondition = () => {
40
+ const condition = makeCondition(fields);
41
+ if (!condition) return;
42
+ updateGroup((current) => ({
43
+ ...current,
44
+ conditions: [...current.conditions, condition]
45
+ }));
46
+ };
47
+ const addGroup = () => {
48
+ const condition = makeCondition(fields);
49
+ const nested = {
50
+ id: nanoid(),
51
+ combinator: group.combinator === "AND" ? "OR" : "AND",
52
+ conditions: condition ? [condition] : []
53
+ };
54
+ updateGroup((current) => ({
55
+ ...current,
56
+ conditions: [...current.conditions, nested]
57
+ }));
58
+ };
59
+ return /* @__PURE__ */ jsxs(
60
+ "div",
61
+ {
62
+ className: root ? "space-y-3" : "space-y-3 rounded-md border border-[var(--color-border)] bg-[var(--color-bg-subtle)] p-3",
63
+ children: [
64
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
65
+ /* @__PURE__ */ jsxs(
66
+ Select,
67
+ {
68
+ value: group.combinator,
69
+ onChange: (event) => updateGroup((current) => ({
70
+ ...current,
71
+ combinator: event.target.value
72
+ })),
73
+ "aria-label": root ? "Root filter combinator" : "Group filter combinator",
74
+ className: "h-8 w-24 text-xs",
75
+ children: [
76
+ /* @__PURE__ */ jsx("option", { value: "AND", children: "AND" }),
77
+ /* @__PURE__ */ jsx("option", { value: "OR", children: "OR" })
78
+ ]
79
+ }
80
+ ),
81
+ /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "xs", onClick: addCondition, disabled: fields.length === 0, children: "Add rule" }),
82
+ canNest ? /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "xs", onClick: addGroup, disabled: fields.length === 0, children: "Add group" }) : null,
83
+ !root ? /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "xs", onClick: () => filters.removeCondition(group.id), children: "Remove group" }) : null
84
+ ] }),
85
+ group.conditions.length === 0 ? /* @__PURE__ */ jsx("p", { className: "rounded-md border border-dashed border-[var(--color-border)] px-3 py-4 text-sm text-[var(--color-fg-subtle)]", children: "No rules in this group" }) : /* @__PURE__ */ jsx("div", { className: "space-y-2", children: group.conditions.map(
86
+ (node) => isGroup(node) ? /* @__PURE__ */ jsx(
87
+ GroupNode,
88
+ {
89
+ group: node,
90
+ fields,
91
+ depth: depth + 1,
92
+ maxDepth,
93
+ root: false
94
+ },
95
+ node.id
96
+ ) : /* @__PURE__ */ jsx(
97
+ FilterBuilder,
98
+ {
99
+ condition: node,
100
+ fields,
101
+ onChange: filters.updateCondition,
102
+ onRemove: filters.removeCondition
103
+ },
104
+ node.id
105
+ )
106
+ ) })
107
+ ]
108
+ }
109
+ );
110
+ }
111
+ function FilterGroupEditorPanel({
112
+ fields,
113
+ maxDepth = 2
114
+ }) {
115
+ const filters = useFiltersContext();
116
+ const actualFields = fields ?? filters.fields;
117
+ return /* @__PURE__ */ jsx(
118
+ GroupNode,
119
+ {
120
+ group: filters.state.root,
121
+ fields: actualFields,
122
+ depth: 0,
123
+ maxDepth,
124
+ root: true
125
+ }
126
+ );
127
+ }
128
+
129
+ export { FilterGroupEditorPanel };
@@ -0,0 +1,23 @@
1
+ import { lazy, Suspense } from 'react';
2
+ import { jsx } from 'react/jsx-runtime';
3
+
4
+ var LazyFilterGroupEditorPanel = lazy(
5
+ () => import('./FilterGroupEditorPanel-KC6INLHT.js').then((module) => ({ default: module.FilterGroupEditorPanel }))
6
+ );
7
+ function FilterGroupEditor(props) {
8
+ return /* @__PURE__ */ jsx(
9
+ Suspense,
10
+ {
11
+ fallback: /* @__PURE__ */ jsx(
12
+ "div",
13
+ {
14
+ "aria-busy": "true",
15
+ className: "h-28 rounded-md border border-dashed border-[var(--color-border)] bg-[var(--color-bg-subtle)]"
16
+ }
17
+ ),
18
+ children: /* @__PURE__ */ jsx(LazyFilterGroupEditorPanel, { ...props })
19
+ }
20
+ );
21
+ }
22
+
23
+ export { FilterGroupEditor };
@@ -0,0 +1,27 @@
1
+ // src/components/primitives/DatePicker/dayPickerStyles.ts
2
+ var dayPickerClassNames = {
3
+ root: "relative w-full text-[var(--color-fg-base)]",
4
+ months: "pt-9 flex flex-col gap-4 sm:flex-row sm:gap-5",
5
+ month: "w-full space-y-3",
6
+ month_caption: "flex h-8 items-center justify-center",
7
+ caption_label: "text-base font-semibold tracking-tight text-[var(--color-fg-base)]",
8
+ nav: "absolute right-0 top-0 flex items-center gap-1",
9
+ button_previous: "inline-flex size-8 items-center justify-center rounded-md border border-transparent text-[var(--color-accent)] transition-colors duration-[var(--motion-fast)] ease-[var(--ease-standard)] hover:bg-[var(--color-bg-muted)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-accent)]/30",
10
+ button_next: "inline-flex size-8 items-center justify-center rounded-md border border-transparent text-[var(--color-accent)] transition-colors duration-[var(--motion-fast)] ease-[var(--ease-standard)] hover:bg-[var(--color-bg-muted)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-accent)]/30",
11
+ month_grid: "w-full border-collapse",
12
+ weekdays: "mt-2 grid grid-cols-7",
13
+ weekday: "py-1 text-center text-xs font-medium text-[var(--color-fg-muted)]",
14
+ weeks: "block",
15
+ week: "mt-1 grid grid-cols-7",
16
+ day: "flex items-center justify-center p-0",
17
+ day_button: "inline-flex size-9 items-center justify-center rounded-full text-sm text-[var(--color-fg-base)] transition-colors duration-[var(--motion-fast)] ease-[var(--ease-standard)] hover:bg-[var(--color-bg-muted)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-accent)]/30",
18
+ selected: "bg-[var(--color-accent)] text-[var(--color-accent-contrast)] hover:bg-[var(--color-accent)] focus-visible:ring-[var(--color-accent)]/40",
19
+ today: "font-semibold ring-1 ring-[var(--color-accent)]/45",
20
+ outside: "text-[var(--color-fg-muted)]/45",
21
+ disabled: "cursor-not-allowed text-[var(--color-fg-muted)]/30 hover:bg-transparent",
22
+ range_middle: "bg-[var(--color-accent)]/14 [&>.rdp-day_button]:rounded-none [&>.rdp-day_button]:bg-transparent [&>.rdp-day_button]:text-[var(--color-fg-base)]",
23
+ range_start: "bg-[var(--color-accent)]/14 [&>.rdp-day_button]:rounded-full [&>.rdp-day_button]:bg-[var(--color-accent)] [&>.rdp-day_button]:text-[var(--color-accent-contrast)]",
24
+ range_end: "bg-[var(--color-accent)]/14 [&>.rdp-day_button]:rounded-full [&>.rdp-day_button]:bg-[var(--color-accent)] [&>.rdp-day_button]:text-[var(--color-accent-contrast)]"
25
+ };
26
+
27
+ export { dayPickerClassNames };