lecom-ui 5.2.80 → 5.2.82

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/README.md CHANGED
@@ -1 +1 @@
1
- lecom-ui
1
+ lecom-ui
@@ -0,0 +1,94 @@
1
+ import * as React from 'react';
2
+ import { cn } from '../../lib/utils.js';
3
+ import * as AccordionPrimitive from '@radix-ui/react-accordion';
4
+ import { cva } from 'class-variance-authority';
5
+ import { ChevronRight } from 'lucide-react';
6
+
7
+ const collapseTriggerVariants = cva(
8
+ "flex items-center justify-between w-full transition-all text-left outline-none data-[state=open]:font-semibold",
9
+ {
10
+ variants: {
11
+ size: {
12
+ small: "text-sm py-1.5 px-4 min-h-8",
13
+ medium: "text-base py-2.5 px-4 min-h-10",
14
+ large: "text-lg py-3 px-4 min-h-12"
15
+ },
16
+ ghost: {
17
+ true: "bg-transparent border-none",
18
+ false: "border-t-none border-grey-400"
19
+ }
20
+ },
21
+ defaultVariants: {
22
+ size: "large",
23
+ ghost: false
24
+ }
25
+ }
26
+ );
27
+ const CollapseRoot = AccordionPrimitive.Root;
28
+ const CollapseItem = AccordionPrimitive.Item;
29
+ const CollapsePanel = React.forwardRef(
30
+ ({
31
+ header,
32
+ children,
33
+ extra,
34
+ expandIconPosition = "start",
35
+ size = "large",
36
+ ghost = false,
37
+ disabled = false,
38
+ className,
39
+ ...props
40
+ }, ref) => /* @__PURE__ */ React.createElement(
41
+ CollapseItem,
42
+ {
43
+ ref,
44
+ ...props,
45
+ className: cn(
46
+ "group w-full",
47
+ disabled && "pointer-events-none opacity-50",
48
+ className
49
+ )
50
+ },
51
+ /* @__PURE__ */ React.createElement(AccordionPrimitive.Header, { asChild: true }, /* @__PURE__ */ React.createElement(
52
+ AccordionPrimitive.Trigger,
53
+ {
54
+ disabled,
55
+ className: cn(
56
+ collapseTriggerVariants({ size, ghost }),
57
+ "flex gap-2 items-center text-left font-normal"
58
+ )
59
+ },
60
+ /* @__PURE__ */ React.createElement(
61
+ "div",
62
+ {
63
+ className: cn(
64
+ "flex flex-1 items-center justify-between gap-4 w-full",
65
+ expandIconPosition === "end" ? "flex-row-reverse" : ""
66
+ )
67
+ },
68
+ /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2 truncate" }, /* @__PURE__ */ React.createElement(
69
+ "span",
70
+ {
71
+ className: "flex items-center justify-center flex-shrink-0 min-w-4 min-h-4 transition-transform duration-300 group-data-[state=open]:rotate-90 text-grey-700 text-lg select-none font-normal"
72
+ },
73
+ /* @__PURE__ */ React.createElement(ChevronRight, { className: "size-4" })
74
+ ), /* @__PURE__ */ React.createElement("span", { className: "font-normal" }, header)),
75
+ extra && /* @__PURE__ */ React.createElement("div", { className: "text-sm text-grey-500" }, extra)
76
+ )
77
+ )),
78
+ /* @__PURE__ */ React.createElement(
79
+ AccordionPrimitive.Content,
80
+ {
81
+ className: cn(
82
+ "overflow-hidden data-[state=open]:animate-accordion-down data-[state=closed]:animate-accordion-up"
83
+ )
84
+ },
85
+ /* @__PURE__ */ React.createElement("div", { className: "text-sm text-grey-800 pt-2 pb-4 px-4" }, children)
86
+ )
87
+ )
88
+ );
89
+ CollapsePanel.displayName = "CollapsePanel";
90
+ const Collapse = Object.assign(CollapseRoot, {
91
+ Panel: CollapsePanel
92
+ });
93
+
94
+ export { Collapse, collapseTriggerVariants };
@@ -0,0 +1,128 @@
1
+ import * as React from 'react';
2
+ import { ChevronUpIcon, ChevronDownIcon } from 'lucide-react';
3
+ import { cn } from '../../lib/utils.js';
4
+ import { Button } from '../Button/Button.js';
5
+ import { Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem } from '../Command/Command.js';
6
+ import { Popover, PopoverTrigger, PopoverContent } from '../Popover/Popover.js';
7
+ import { Typography } from '../Typography/Typography.js';
8
+
9
+ function Combobox({
10
+ options,
11
+ value,
12
+ onChange,
13
+ placeholder = "Selecione...",
14
+ disabled = false,
15
+ notFoundContent = "Nenhuma op\xE7\xE3o encontrada.",
16
+ status = "default",
17
+ searchTerm = "Pesquisar...",
18
+ triggerClassName,
19
+ contentClassName
20
+ }) {
21
+ const [open, setOpen] = React.useState(false);
22
+ const [search, setSearch] = React.useState("");
23
+ const filterOptions = React.useCallback(
24
+ (opts) => {
25
+ const searchLower = search.toLowerCase();
26
+ return opts.map((item) => {
27
+ if ("options" in item) {
28
+ const filtered = item.options.filter(
29
+ (opt) => opt.label.toLowerCase().includes(searchLower) || opt.value.toLowerCase().includes(searchLower)
30
+ );
31
+ if (!filtered.length) return null;
32
+ return { ...item, options: filtered };
33
+ }
34
+ return item.label.toLowerCase().includes(searchLower) || item.value.toLowerCase().includes(searchLower) ? item : null;
35
+ }).filter(Boolean);
36
+ },
37
+ [search]
38
+ );
39
+ const filteredOptions = React.useMemo(
40
+ () => !search ? options : filterOptions(options),
41
+ [options, search, filterOptions]
42
+ );
43
+ const selectedLabel = options.flatMap((opt) => "options" in opt ? opt.options : [opt]).find((opt) => opt.value === value)?.label || placeholder;
44
+ React.useEffect(() => {
45
+ if (!open) setSearch("");
46
+ }, [open]);
47
+ return /* @__PURE__ */ React.createElement(Popover, { open, onOpenChange: setOpen }, /* @__PURE__ */ React.createElement(PopoverTrigger, { asChild: true, className: cn(contentClassName) }, /* @__PURE__ */ React.createElement(
48
+ Button,
49
+ {
50
+ type: "button",
51
+ role: "combobox",
52
+ "aria-expanded": open,
53
+ className: cn(
54
+ triggerClassName,
55
+ "w-full h-10 bg-white rounded-md px-3 text-left shadow-sm flex items-center justify-between transition",
56
+ status === "error" ? "border border-red-500 hover:ring-1 hover:ring-red-500 focus:ring-1 focus:ring-red-500" : "border border-gray-300 hover:ring-1 hover:ring-blue-600 focus:ring-1 focus:ring-blue-600",
57
+ !value && "text-gray-400",
58
+ disabled && "opacity-50 pointer-events-none",
59
+ "hover:bg-white focus:!bg-white active:!bg-white"
60
+ ),
61
+ disabled
62
+ },
63
+ /* @__PURE__ */ React.createElement(
64
+ "span",
65
+ {
66
+ className: cn(
67
+ value ? "text-black" : "text-gray-400",
68
+ "font-normal truncate max-w-[calc(100%-2.5rem)]"
69
+ )
70
+ },
71
+ /* @__PURE__ */ React.createElement(Typography, { variant: "body-medium-400" }, selectedLabel)
72
+ ),
73
+ open ? /* @__PURE__ */ React.createElement(
74
+ ChevronUpIcon,
75
+ {
76
+ className: "ml-2 h-4 w-4 shrink-0 text-gray-400",
77
+ color: "black"
78
+ }
79
+ ) : /* @__PURE__ */ React.createElement(
80
+ ChevronDownIcon,
81
+ {
82
+ className: "ml-2 h-4 w-4 shrink-0 text-gray-400",
83
+ color: "black"
84
+ }
85
+ )
86
+ )), /* @__PURE__ */ React.createElement(PopoverContent, { className: "w-[var(--radix-popover-trigger-width)] p-0" }, /* @__PURE__ */ React.createElement(Command, null, /* @__PURE__ */ React.createElement(
87
+ CommandInput,
88
+ {
89
+ placeholder: searchTerm,
90
+ value: search,
91
+ onValueChange: setSearch
92
+ }
93
+ ), /* @__PURE__ */ React.createElement(CommandList, null, /* @__PURE__ */ React.createElement(CommandEmpty, null, notFoundContent), filteredOptions.map(
94
+ (item, idx) => "options" in item ? /* @__PURE__ */ React.createElement(CommandGroup, { key: `${item.label}-${idx}`, heading: item.label }, item.options.map((opt) => /* @__PURE__ */ React.createElement(
95
+ CommandItem,
96
+ {
97
+ key: opt.value,
98
+ onSelect: () => {
99
+ if (opt.disabled) return;
100
+ onChange(opt.value === value ? null : opt.value);
101
+ setOpen(false);
102
+ },
103
+ className: cn(
104
+ opt.value === value ? "bg-blue-100 font-semibold text-black" : "hover:bg-gray-100",
105
+ opt.disabled && "opacity-50 pointer-events-none"
106
+ )
107
+ },
108
+ opt.label
109
+ ))) : /* @__PURE__ */ React.createElement(
110
+ CommandItem,
111
+ {
112
+ key: item.value,
113
+ onSelect: () => {
114
+ if (item.disabled) return;
115
+ onChange(item.value === value ? null : item.value);
116
+ setOpen(false);
117
+ },
118
+ className: cn(
119
+ item.value === value ? "bg-blue-100 font-semibold text-black" : "hover:bg-gray-100",
120
+ item.disabled && "opacity-50 pointer-events-none"
121
+ )
122
+ },
123
+ item.label
124
+ )
125
+ )))));
126
+ }
127
+
128
+ export { Combobox };
@@ -0,0 +1,207 @@
1
+ import * as React from 'react';
2
+ import { useFormContext, Controller } from 'react-hook-form';
3
+ import { cn } from '../../lib/utils.js';
4
+ import { Button } from '../Button/Button.js';
5
+
6
+ function DividerLine({
7
+ dashed,
8
+ plain,
9
+ isGroupDivider,
10
+ isActive,
11
+ className,
12
+ style
13
+ }) {
14
+ return /* @__PURE__ */ React.createElement(
15
+ "div",
16
+ {
17
+ className: cn(
18
+ "w-full",
19
+ isGroupDivider ? "my-4" : "my-2",
20
+ isActive ? "opacity-100" : "opacity-50",
21
+ className
22
+ ),
23
+ style
24
+ },
25
+ /* @__PURE__ */ React.createElement(
26
+ "div",
27
+ {
28
+ className: cn(
29
+ "w-full border-t",
30
+ dashed ? "border-dashed" : "border-solid",
31
+ plain ? "border-gray-200" : "border-gray-300"
32
+ )
33
+ }
34
+ )
35
+ );
36
+ }
37
+ function OptionButtons({
38
+ value,
39
+ onChange,
40
+ isActive,
41
+ plain,
42
+ optionLabels,
43
+ ButtonComponent,
44
+ buttonSize,
45
+ buttonClassName
46
+ }) {
47
+ const [labelAnd, labelOr] = optionLabels;
48
+ const Btn = ButtonComponent;
49
+ return /* @__PURE__ */ React.createElement(
50
+ "div",
51
+ {
52
+ className: cn(
53
+ "relative z-10 inline-flex overflow-hidden",
54
+ plain ? "bg-white" : "rounded-md border border-gray-300 bg-white shadow-sm"
55
+ )
56
+ },
57
+ /* @__PURE__ */ React.createElement(
58
+ Btn,
59
+ {
60
+ type: "button",
61
+ variant: "ghost",
62
+ color: "grey",
63
+ size: buttonSize,
64
+ onClick: () => onChange("AND"),
65
+ disabled: !isActive,
66
+ className: cn(
67
+ "px-4 py-1 text-sm transition !rounded-none",
68
+ value === "AND" ? "bg-blue-600 text-white hover:bg-blue-500" : "bg-white text-gray-700 hover:bg-blue-50",
69
+ buttonClassName
70
+ )
71
+ },
72
+ labelAnd
73
+ ),
74
+ /* @__PURE__ */ React.createElement(
75
+ Btn,
76
+ {
77
+ type: "button",
78
+ variant: "ghost",
79
+ color: "grey",
80
+ size: buttonSize,
81
+ onClick: () => onChange("OR"),
82
+ disabled: !isActive,
83
+ className: cn(
84
+ "px-4 py-1 text-sm transition !rounded-none",
85
+ value === "OR" ? "bg-blue-600 text-white hover:bg-blue-500" : "bg-white text-gray-700 hover:bg-blue-50",
86
+ buttonClassName
87
+ )
88
+ },
89
+ labelOr
90
+ )
91
+ );
92
+ }
93
+ function CustomDivider({
94
+ name,
95
+ control,
96
+ isActive = true,
97
+ isGroupDivider = false,
98
+ orientation = "center",
99
+ dashed = false,
100
+ plain = false,
101
+ lineOnly = false,
102
+ optionLabels = ["E", "OU"],
103
+ ButtonComponent = Button,
104
+ buttonSize = "medium",
105
+ buttonClassName,
106
+ className,
107
+ style,
108
+ children
109
+ }) {
110
+ const formContext = useFormContext();
111
+ const controlToUse = control ?? formContext?.control;
112
+ const justifyMap = {
113
+ left: "justify-start",
114
+ center: "justify-center",
115
+ right: "justify-end"
116
+ };
117
+ if (lineOnly && !children) {
118
+ return /* @__PURE__ */ React.createElement(
119
+ DividerLine,
120
+ {
121
+ dashed,
122
+ plain,
123
+ isGroupDivider,
124
+ isActive,
125
+ className,
126
+ style
127
+ }
128
+ );
129
+ }
130
+ if (children) {
131
+ return /* @__PURE__ */ React.createElement(
132
+ "div",
133
+ {
134
+ className: cn(
135
+ "relative w-full flex items-center",
136
+ isGroupDivider ? "my-4" : "my-2",
137
+ isActive ? "opacity-100" : "opacity-50",
138
+ justifyMap[orientation],
139
+ className
140
+ ),
141
+ style
142
+ },
143
+ /* @__PURE__ */ React.createElement(
144
+ "div",
145
+ {
146
+ className: cn(
147
+ "absolute inset-x-0 border-t",
148
+ dashed ? "border-dashed" : "border-solid",
149
+ plain ? "border-gray-200" : "border-gray-300"
150
+ )
151
+ }
152
+ ),
153
+ /* @__PURE__ */ React.createElement("span", { className: "relative z-10 px-2 bg-white" }, children)
154
+ );
155
+ }
156
+ if (!name) {
157
+ throw new Error(
158
+ "CustomDivider: prop `name` \xE9 obrigat\xF3ria se `lineOnly` for false."
159
+ );
160
+ }
161
+ return /* @__PURE__ */ React.createElement(
162
+ "div",
163
+ {
164
+ className: cn(
165
+ "relative w-full flex items-center",
166
+ isGroupDivider ? "my-4" : "my-2",
167
+ isActive ? "opacity-100" : "opacity-50",
168
+ justifyMap[orientation],
169
+ className
170
+ ),
171
+ style
172
+ },
173
+ /* @__PURE__ */ React.createElement(
174
+ "div",
175
+ {
176
+ className: cn(
177
+ "absolute inset-x-0 border-t",
178
+ dashed ? "border-dashed" : "border-solid",
179
+ plain ? "border-gray-200" : "border-gray-300"
180
+ )
181
+ }
182
+ ),
183
+ /* @__PURE__ */ React.createElement(
184
+ Controller,
185
+ {
186
+ name,
187
+ control: controlToUse,
188
+ render: ({ field: { value, onChange } }) => /* @__PURE__ */ React.createElement(
189
+ OptionButtons,
190
+ {
191
+ value,
192
+ onChange,
193
+ isActive,
194
+ plain,
195
+ optionLabels,
196
+ ButtonComponent,
197
+ buttonSize,
198
+ buttonClassName
199
+ }
200
+ )
201
+ }
202
+ )
203
+ );
204
+ }
205
+ CustomDivider.displayName = "CustomDivider";
206
+
207
+ export { CustomDivider };
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { cn } from '../../lib/utils.js';
3
- import { useReactTable, getFilteredRowModel, getSortedRowModel, getCoreRowModel } from '@tanstack/react-table';
3
+ import { useReactTable, getSortedRowModel, getCoreRowModel } from '@tanstack/react-table';
4
4
  import { Pagination } from '../Pagination/Pagination.js';
5
5
  import { ScrollArea, ScrollBar } from '../ScrollArea/ScrollArea.js';
6
6
  import { buildColumns } from './DataTable.utils.js';
@@ -21,39 +21,16 @@ function DataTable({
21
21
  onIsSelected
22
22
  }) {
23
23
  const [sorting, setSorting] = React.useState([]);
24
- const [columnFilters, setColumnFilters] = React.useState(
25
- []
26
- );
27
- const memoizedColumns = React.useMemo(
28
- () => buildColumns({ columns, size }),
29
- [columns, size]
30
- );
31
24
  const table = useReactTable({
32
25
  data,
33
- columns: memoizedColumns,
34
- onColumnFiltersChange: setColumnFilters,
26
+ columns: buildColumns({ columns, size }),
35
27
  getCoreRowModel: getCoreRowModel(),
36
28
  onSortingChange: setSorting,
37
29
  getSortedRowModel: getSortedRowModel(),
38
- getFilteredRowModel: getFilteredRowModel(),
39
30
  state: {
40
- sorting,
41
- columnFilters
31
+ sorting
42
32
  }
43
33
  });
44
- React.useEffect(() => {
45
- if (!table) return;
46
- columns.forEach((column) => {
47
- const value = column.filterProps?.value;
48
- const columnKey = column.key;
49
- if (value !== void 0) {
50
- const column2 = table.getColumn(columnKey);
51
- if (column2) {
52
- column2.setFilterValue(value);
53
- }
54
- }
55
- });
56
- }, [columns, table]);
57
34
  const styleDataTableContainer = () => ({
58
35
  width: vwDiff ? `calc(100vw - ${vwDiff}px)` : "100%",
59
36
  height: vhDiff ? `calc(100vh - ${vhDiff}px)` : "100%"
@@ -1,8 +1,7 @@
1
1
  import * as React from 'react';
2
- import { cn } from '../../lib/utils.js';
2
+ import { clsx } from 'clsx';
3
3
  import { ArrowUpDown } from 'lucide-react';
4
4
  import { Checkbox } from '../Checkbox/Checkbox.js';
5
- import { Input } from '../Input/Input.js';
6
5
  import { Typography } from '../Typography/Typography.js';
7
6
 
8
7
  function buildHeaderSelect({
@@ -54,77 +53,33 @@ function buildColumns({
54
53
  return null;
55
54
  }
56
55
  const hasSort = !!externalColumn.onSort || !!externalColumn.onSortClient;
57
- const isFilterable = !!externalColumn.filterable;
58
- const filterInputValue = column.getFilterValue() ?? "";
59
- const handleFilterInputChange = (event) => {
60
- const updatedValue = event.target.value;
61
- column.setFilterValue(updatedValue);
62
- };
63
56
  const title = typeof externalColumn.title === "function" ? externalColumn.title({ table, column }) : externalColumn.title;
64
- function renderFilterInput() {
65
- if (isFilterable && column.getCanFilter()) {
66
- return /* @__PURE__ */ React.createElement(
67
- "div",
68
- {
69
- className: cn(
70
- "ml-2 w-full flex items-center justify-start",
71
- externalColumn.filterProps?.className
72
- )
73
- },
74
- /* @__PURE__ */ React.createElement(
75
- Input,
76
- {
77
- ...externalColumn.filterProps?.inputProps,
78
- type: "text",
79
- value: filterInputValue,
80
- onChange: handleFilterInputChange,
81
- placeholder: externalColumn.filterProps?.placeholder
82
- }
83
- )
84
- );
85
- }
86
- return null;
87
- }
88
- function renderSortArrow() {
89
- if (hasSort) {
90
- return /* @__PURE__ */ React.createElement(
91
- ArrowUpDown,
92
- {
93
- size: 16,
94
- className: "ml-1 text-grey-400 group-hover:text-grey-950 hover:cursor-pointer",
95
- onClick: (e) => {
96
- e.stopPropagation();
97
- const handler = column.getToggleSortingHandler?.();
98
- if (handler) handler(e);
99
- else if (externalColumn.onSort) {
100
- externalColumn.onSort({ table, column });
101
- }
102
- }
103
- }
104
- );
105
- }
106
- return null;
107
- }
108
57
  return /* @__PURE__ */ React.createElement(
109
58
  "div",
110
59
  {
111
- className: cn(
60
+ className: clsx(
112
61
  "group flex items-center gap-1",
113
62
  hasSort && "hover:cursor-pointer"
114
- )
63
+ ),
64
+ onClick: () => externalColumn.onSort?.({ table, column })
115
65
  },
116
66
  typeof externalColumn.title === "string" ? /* @__PURE__ */ React.createElement(
117
67
  Typography,
118
68
  {
119
69
  variant: size === "small" ? "body-medium-500" : "body-large-500",
120
70
  textColor: "text-grey-950",
121
- className: "whitespace-normal break-words max-sm:truncate",
71
+ className: "truncate",
122
72
  title: externalColumn.title
123
73
  },
124
74
  externalColumn.title
125
75
  ) : title,
126
- renderSortArrow(),
127
- renderFilterInput()
76
+ hasSort && /* @__PURE__ */ React.createElement(
77
+ ArrowUpDown,
78
+ {
79
+ size: 16,
80
+ className: "text-grey-400 group-hover:text-grey-950"
81
+ }
82
+ )
128
83
  );
129
84
  },
130
85
  cell: ({ row }) => {
@@ -154,11 +109,6 @@ function buildColumns({
154
109
  row.getValue(externalColumn.key)
155
110
  );
156
111
  },
157
- filterFn: externalColumn.filterable ? (row, columnId, filterValue) => {
158
- const rawValue = row.getValue(columnId);
159
- const value = typeof rawValue === "string" ? rawValue : String(rawValue ?? "");
160
- return value.toLowerCase().includes(String(filterValue).toLowerCase());
161
- } : void 0,
162
112
  meta: {
163
113
  width: externalColumn.width,
164
114
  fixed: externalColumn.fixed,
@@ -54,7 +54,8 @@ function Table({
54
54
  style: styleColumn(
55
55
  header.column.columnDef.meta,
56
56
  "th"
57
- )
57
+ ),
58
+ onClick: header.column.getToggleSortingHandler()
58
59
  },
59
60
  header.isPlaceholder ? null : flexRender(
60
61
  header.column.columnDef.header,