@g4rcez/components 0.0.8 → 0.0.10
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/core/button.js +40 -0
- package/dist/components/core/polymorph.js +8 -0
- package/dist/components/display/card.js +6 -0
- package/dist/components/floating/dropdown.js +38 -0
- package/dist/components/floating/tooltip.js +32 -0
- package/dist/components/form/autocomplete.js +125 -0
- package/dist/components/form/file-upload.js +61 -0
- package/dist/components/form/form.js +28 -0
- package/dist/components/form/input-field.js +10 -0
- package/dist/components/form/input.js +39 -0
- package/dist/components/form/select.js +30 -0
- package/dist/components/form/switch.js +18 -0
- package/dist/components/index.js +14 -0
- package/dist/components/table/filter.js +79 -0
- package/dist/components/table/group.js +41 -0
- package/dist/components/table/index.js +82 -0
- package/dist/components/table/metadata.js +10 -0
- package/dist/components/table/sort.js +70 -0
- package/dist/components/table/table-lib.js +51 -0
- package/dist/components/table/thead.js +25 -0
- package/dist/hooks/use-form.js +126 -0
- package/dist/hooks/use-previous.js +8 -0
- package/dist/hooks/use-reactive.js +8 -0
- package/dist/index.css +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +3462 -3328
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +46 -46
- package/dist/index.umd.js.map +1 -1
- package/dist/lib/dom.js +22 -0
- package/dist/lib/fns.js +15 -0
- package/dist/preset/src/styles/theme.d.ts +1 -0
- package/dist/preset/src/styles/theme.d.ts.map +1 -1
- package/dist/preset/src/styles/theme.js +66 -0
- package/dist/styles/design-tokens.js +37 -0
- package/dist/styles/theme.d.ts +1 -0
- package/dist/styles/theme.d.ts.map +1 -1
- package/dist/styles/theme.js +132 -0
- package/dist/types.js +1 -0
- package/package.json +70 -44
- package/dist/next.svg +0 -1
- package/dist/vercel.svg +0 -1
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { __rest } from "tslib";
|
|
2
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { cva } from "class-variance-authority";
|
|
4
|
+
import { forwardRef } from "react";
|
|
5
|
+
import { Polymorph } from "~/components/core/polymorph";
|
|
6
|
+
import { css } from "~/lib/dom";
|
|
7
|
+
const buttonVariants = cva("inline-flex gap-1.5 text-main-foreground border-2 border-transparent items-center justify-center align-middle cursor-pointer whitespace-nowrap font-medium transition-colors ease-in disabled:cursor-not-allowed disabled:bg-opacity-50 disabled:text-opacity-60 focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-ring", {
|
|
8
|
+
variants: {
|
|
9
|
+
size: {
|
|
10
|
+
default: "h-10 px-4 py-2",
|
|
11
|
+
big: "h-12 px-6 py-4",
|
|
12
|
+
small: "h-10 p-2 text-sm",
|
|
13
|
+
icon: "p-1",
|
|
14
|
+
},
|
|
15
|
+
rounded: {
|
|
16
|
+
rough: "rounded-sm",
|
|
17
|
+
default: "rounded-md",
|
|
18
|
+
squared: "rounded-none",
|
|
19
|
+
circle: "rounded-full aspect-square",
|
|
20
|
+
},
|
|
21
|
+
theme: {
|
|
22
|
+
raw: "",
|
|
23
|
+
main: "bg-primary hover:bg-primary-hover text-primary-foreground",
|
|
24
|
+
loading: "animate-pulse bg-disabled duration-700 opacity-70",
|
|
25
|
+
disabled: "bg-disabled duration-700 opacity-70",
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
defaultVariants: { theme: "main", size: "default", rounded: "default" },
|
|
29
|
+
});
|
|
30
|
+
export const Button = forwardRef(function Button(_a, ref) {
|
|
31
|
+
var _b;
|
|
32
|
+
var { className, icon, loading, theme, type = "button", size, rounded } = _a, props = __rest(_a, ["className", "icon", "loading", "theme", "type", "size", "rounded"]);
|
|
33
|
+
const disabled = loading || props.disabled;
|
|
34
|
+
return (_jsxs(Polymorph, Object.assign({}, props, { ref: ref, type: type, "data-theme": theme, disabled: disabled, as: (_b = props.as) !== null && _b !== void 0 ? _b : "button", onClick: disabled ? undefined : props.onClick, className: css(buttonVariants({
|
|
35
|
+
size,
|
|
36
|
+
rounded,
|
|
37
|
+
theme: loading ? "loading" : disabled ? "disabled" : theme,
|
|
38
|
+
}), className), children: [props.children, icon] })));
|
|
39
|
+
});
|
|
40
|
+
export const ButtonGroup = (props) => (_jsx("ul", { className: "border-main-bg text-main-foreground flex w-full flex-row rounded-md border-2", children: props.buttons.map((button) => (_jsx("li", { className: "flex flex-1", children: _jsx("button", Object.assign({}, button, { type: button.type || "button", "data-active": props.active === button.name ? "true" : "false", className: css("border-main-bg flex flex-1 items-center gap-1.5 rounded-sm border-r-2 px-4 py-2 last:border-r-0", "hover:text-main cursor-pointer justify-center whitespace-nowrap align-middle font-medium", "focus-visible:ring-ring shadow-sm focus-visible:outline-none focus-visible:ring-2 disabled:text-opacity-80", "data-[active=true]:bg-main-bg text-body data-[active=true]:text-main transition-colors ease-in disabled:cursor-not-allowed disabled:bg-opacity-50") })) }, `button-group-${button.name}`))) }));
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { __rest } from "tslib";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { forwardRef } from "react";
|
|
4
|
+
export const Polymorph = forwardRef(function Polymorph(_a, ref) {
|
|
5
|
+
var { as } = _a, props = __rest(_a, ["as"]);
|
|
6
|
+
const Component = as || "span";
|
|
7
|
+
return _jsx(Component, Object.assign({}, props, { ref: ref }));
|
|
8
|
+
});
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Polymorph } from "~/components/core/polymorph";
|
|
3
|
+
import { css } from "~/lib/dom";
|
|
4
|
+
export const Card = (props) => {
|
|
5
|
+
return _jsx(Polymorph, Object.assign({}, props, { as: "div", className: css("rounded-lg bg-card-background p-8 border-card-border border shadow", props.className) }));
|
|
6
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { arrow, autoUpdate, flip, FloatingArrow, FloatingFocusManager, offset, shift, useClick, useDismiss, useFloating, useId, useInteractions, useRole, } from "@floating-ui/react";
|
|
3
|
+
import { Fragment, useMemo, useRef, useState } from "react";
|
|
4
|
+
export const Dropdown = (props) => {
|
|
5
|
+
const [open, setOpen] = useState(props.open);
|
|
6
|
+
const arrowRef = useRef(null);
|
|
7
|
+
const middleware = useMemo(() => [
|
|
8
|
+
offset(10),
|
|
9
|
+
flip({ fallbackAxisSideDirection: "end" }),
|
|
10
|
+
shift(),
|
|
11
|
+
arrow({
|
|
12
|
+
padding: 5,
|
|
13
|
+
element: arrowRef,
|
|
14
|
+
}),
|
|
15
|
+
], [props.arrow]);
|
|
16
|
+
const { refs, floatingStyles, context } = useFloating({
|
|
17
|
+
open,
|
|
18
|
+
transform: true,
|
|
19
|
+
whileElementsMounted: autoUpdate,
|
|
20
|
+
middleware,
|
|
21
|
+
onOpenChange: (nextValue, event) => {
|
|
22
|
+
var _a;
|
|
23
|
+
const element = event === null || event === void 0 ? void 0 : event.relatedTarget;
|
|
24
|
+
if (element) {
|
|
25
|
+
if (element.dataset.floating === "true" && !nextValue)
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
setOpen(nextValue);
|
|
29
|
+
(_a = props.onChange) === null || _a === void 0 ? void 0 : _a.call(props, nextValue);
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
const click = useClick(context);
|
|
33
|
+
const dismiss = useDismiss(context);
|
|
34
|
+
const role = useRole(context);
|
|
35
|
+
const { getReferenceProps, getFloatingProps } = useInteractions([click, dismiss, role]);
|
|
36
|
+
const headingId = useId();
|
|
37
|
+
return (_jsxs(Fragment, { children: [_jsx("button", Object.assign({ ref: refs.setReference }, getReferenceProps(), { children: props.trigger })), open && (_jsx(FloatingFocusManager, { returnFocus: true, visuallyHiddenDismiss: true, restoreFocus: true, context: context, modal: false, children: _jsxs("div", Object.assign({ className: "bg-floating-background isolate z-floating border shadow-2xl p-6 border-floating-border rounded-lg", ref: refs.setFloating, style: floatingStyles, "aria-labelledby": headingId }, getFloatingProps(), { children: [_jsx(FloatingArrow, { ref: arrowRef, context: context, strokeWidth: 0.1, className: "fill-floating-background stroke-floating-border" }), _jsx("header", { className: "mb-2", children: _jsx("h3", { className: "leading-snug font-medium text-2xl tracking-tight text-left", children: props.title }) }), props.children] })) }))] }));
|
|
38
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { __rest } from "tslib";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { arrow, autoUpdate, flip, FloatingArrow, FloatingPortal, offset, shift, useDismiss, useFloating, useFocus, useHover, useInteractions, useRole, } from "@floating-ui/react";
|
|
4
|
+
import { Fragment, useRef, useState } from "react";
|
|
5
|
+
import { Polymorph } from "~/components/core/polymorph";
|
|
6
|
+
export const Tooltip = (_a) => {
|
|
7
|
+
var { children, as, title } = _a, props = __rest(_a, ["children", "as", "title"]);
|
|
8
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
9
|
+
const arrowRef = useRef(null);
|
|
10
|
+
const Component = as || "div";
|
|
11
|
+
const { refs, floatingStyles, context } = useFloating({
|
|
12
|
+
open: isOpen,
|
|
13
|
+
onOpenChange: setIsOpen,
|
|
14
|
+
whileElementsMounted: autoUpdate,
|
|
15
|
+
transform: true,
|
|
16
|
+
middleware: [
|
|
17
|
+
offset(5),
|
|
18
|
+
flip({ fallbackAxisSideDirection: "start" }),
|
|
19
|
+
shift(),
|
|
20
|
+
arrow({
|
|
21
|
+
element: arrowRef,
|
|
22
|
+
padding: 5,
|
|
23
|
+
}),
|
|
24
|
+
],
|
|
25
|
+
});
|
|
26
|
+
const hover = useHover(context, { move: false });
|
|
27
|
+
const focus = useFocus(context);
|
|
28
|
+
const dismiss = useDismiss(context);
|
|
29
|
+
const role = useRole(context, { role: "tooltip" });
|
|
30
|
+
const { getReferenceProps, getFloatingProps } = useInteractions([hover, focus, dismiss, role]);
|
|
31
|
+
return (_jsxs(Fragment, { children: [_jsx(Component, Object.assign({ ref: refs.setReference }, getReferenceProps(props), { children: title })), _jsx(FloatingPortal, { children: isOpen && (_jsxs(Polymorph, Object.assign({ ref: refs.setFloating, style: floatingStyles }, getFloatingProps(), { className: "bg-tooltip-background text-foreground border border-tooltip-border p-4 rounded-lg", children: [_jsx(FloatingArrow, { ref: arrowRef, context: context, strokeWidth: 0.1, className: "fill-tooltip-background stroke-tooltip-border" }), children] }))) })] }));
|
|
32
|
+
};
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { __rest } from "tslib";
|
|
3
|
+
import { createElement as _createElement } from "react";
|
|
4
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
5
|
+
import { autoUpdate, FloatingFocusManager, FloatingPortal, offset, size, useDismiss, useFloating, useInteractions, useListNavigation, useRole, useTransitionStyles, } from "@floating-ui/react";
|
|
6
|
+
import Fuzzy from "fuzzy-search";
|
|
7
|
+
import { ChevronDown } from "lucide-react";
|
|
8
|
+
import { forwardRef, useImperativeHandle, useRef, useState } from "react";
|
|
9
|
+
import { InputField } from "~/components/form/input-field";
|
|
10
|
+
import { usePrevious } from "~/hooks/use-previous";
|
|
11
|
+
import { css } from "~/lib/dom";
|
|
12
|
+
export const Option = forwardRef((_a, ref) => {
|
|
13
|
+
var _b;
|
|
14
|
+
var { selected, active, onClick, option } = _a, rest = __rest(_a, ["selected", "active", "onClick", "option"]);
|
|
15
|
+
return (_jsx("li", Object.assign({}, rest, { ref: ref, role: "option", "aria-selected": selected, className: "w-full", children: _jsx("button", { type: "button", onClick: onClick, "aria-selected": selected, className: `p-2 w-full text-left cursor-pointer ${selected ? "bg-primary text-primary-foreground" : ""} ${active ? "bg-primary-subtle text-primary-foreground" : ""}`, children: (_b = option.label) !== null && _b !== void 0 ? _b : option.value }) })));
|
|
16
|
+
});
|
|
17
|
+
const transitionStyles = {
|
|
18
|
+
duration: 300,
|
|
19
|
+
initial: { transform: "scaleY(0)", opacity: 0.2 },
|
|
20
|
+
open: { transform: "scaleY(1)", opacity: 1 },
|
|
21
|
+
close: { transform: "scaleY(0)", opacity: 0 },
|
|
22
|
+
};
|
|
23
|
+
const fuzzyOptions = { caseSensitive: false, sort: false };
|
|
24
|
+
const emptyRef = [];
|
|
25
|
+
export const Autocomplete = forwardRef((_a, externalRef) => {
|
|
26
|
+
var _b, _c;
|
|
27
|
+
var { options, required = true } = _a, props = __rest(_a, ["options", "required"]);
|
|
28
|
+
const [open, setOpen] = useState(false);
|
|
29
|
+
const [shadow, setShadow] = useState("");
|
|
30
|
+
const [value, setValue] = useState((_c = (_b = props.value) !== null && _b !== void 0 ? _b : props.defaultValue) !== null && _c !== void 0 ? _c : "");
|
|
31
|
+
const [index, setIndex] = useState(null);
|
|
32
|
+
const listRef = useRef(emptyRef);
|
|
33
|
+
const previousIndex = usePrevious(index);
|
|
34
|
+
const list = new Fuzzy(options, ["value"], fuzzyOptions).search(shadow);
|
|
35
|
+
const { x, y, strategy, refs, context } = useFloating({
|
|
36
|
+
open,
|
|
37
|
+
transform: true,
|
|
38
|
+
onOpenChange: setOpen,
|
|
39
|
+
whileElementsMounted: autoUpdate,
|
|
40
|
+
middleware: [
|
|
41
|
+
offset(4),
|
|
42
|
+
size({
|
|
43
|
+
padding: 10,
|
|
44
|
+
apply(a) {
|
|
45
|
+
Object.assign(a.elements.floating.style, {
|
|
46
|
+
width: `${a.rects.reference.width}px`,
|
|
47
|
+
maxHeight: `${Math.min(480, a.availableHeight)}px`,
|
|
48
|
+
});
|
|
49
|
+
},
|
|
50
|
+
}),
|
|
51
|
+
],
|
|
52
|
+
});
|
|
53
|
+
useImperativeHandle(externalRef, () => { var _a; return (_a = refs.domReference) === null || _a === void 0 ? void 0 : _a.current; }, [refs]);
|
|
54
|
+
const transitions = useTransitionStyles(context, transitionStyles);
|
|
55
|
+
const { getReferenceProps, getFloatingProps, getItemProps } = useInteractions([
|
|
56
|
+
useRole(context, { role: "listbox" }),
|
|
57
|
+
useDismiss(context),
|
|
58
|
+
useListNavigation(context, {
|
|
59
|
+
listRef,
|
|
60
|
+
loop: true,
|
|
61
|
+
activeIndex: index,
|
|
62
|
+
allowEscape: true,
|
|
63
|
+
focusItemOnOpen: "auto",
|
|
64
|
+
openOnArrowKeyDown: true,
|
|
65
|
+
scrollItemIntoView: true,
|
|
66
|
+
selectedIndex: index,
|
|
67
|
+
virtual: true,
|
|
68
|
+
onNavigate: (n) => {
|
|
69
|
+
var _a;
|
|
70
|
+
const lastIndex = list.length - 1;
|
|
71
|
+
if (n === null && previousIndex === 0)
|
|
72
|
+
return setIndex(lastIndex);
|
|
73
|
+
if (n === null && previousIndex === lastIndex)
|
|
74
|
+
return setIndex(0);
|
|
75
|
+
const i = (_a = n !== null && n !== void 0 ? n : previousIndex) !== null && _a !== void 0 ? _a : null;
|
|
76
|
+
return i === null ? undefined : setIndex(i);
|
|
77
|
+
},
|
|
78
|
+
}),
|
|
79
|
+
]);
|
|
80
|
+
const onSelect = (opt) => {
|
|
81
|
+
setValue(opt.value);
|
|
82
|
+
setOpen(false);
|
|
83
|
+
setShadow("");
|
|
84
|
+
};
|
|
85
|
+
const onChange = (event) => {
|
|
86
|
+
var _a;
|
|
87
|
+
const value = event.target.value;
|
|
88
|
+
setShadow(value);
|
|
89
|
+
if (!open && value === "")
|
|
90
|
+
return setOpen(true);
|
|
91
|
+
return value ? setOpen(true) : (_a = props.onChange) === null || _a === void 0 ? void 0 : _a.call(props, event);
|
|
92
|
+
};
|
|
93
|
+
const onFocus = () => {
|
|
94
|
+
setOpen(true);
|
|
95
|
+
setShadow("");
|
|
96
|
+
};
|
|
97
|
+
const onClose = () => {
|
|
98
|
+
setShadow("");
|
|
99
|
+
setValue("");
|
|
100
|
+
setOpen(false);
|
|
101
|
+
};
|
|
102
|
+
return (_jsxs("fieldset", { className: "relative w-auto", children: [_jsx(InputField, Object.assign({}, props, { required: required, right: _jsxs("span", { className: "flex items-center gap-0.5", children: [_jsx(ChevronDown, { size: 20 }), value ? (_jsx("button", { type: "button", onClick: onClose, className: "link:text-danger transition-colors", children: _jsx("svg", { width: "15", height: "15", viewBox: "0 0 15 15", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: _jsx("path", { d: "M11.7816 4.03157C12.0062 3.80702 12.0062 3.44295 11.7816 3.2184C11.5571 2.99385 11.193 2.99385 10.9685 3.2184L7.50005 6.68682L4.03164 3.2184C3.80708 2.99385 3.44301 2.99385 3.21846 3.2184C2.99391 3.44295 2.99391 3.80702 3.21846 4.03157L6.68688 7.49999L3.21846 10.9684C2.99391 11.193 2.99391 11.557 3.21846 11.7816C3.44301 12.0061 3.80708 12.0061 4.03164 11.7816L7.50005 8.31316L10.9685 11.7816C11.193 12.0061 11.5571 12.0061 11.7816 11.7816C12.0062 11.557 12.0062 11.193 11.7816 10.9684L8.31322 7.49999L11.7816 4.03157Z", fill: "currentColor", fillRule: "evenodd", clipRule: "evenodd" }) }) })) : null] }), children: _jsx("input", Object.assign({}, getReferenceProps(Object.assign(Object.assign({}, props), { onChange,
|
|
103
|
+
onFocus, ref: refs.setReference, onClick: (e) => e.currentTarget.focus(), onKeyDown(event) {
|
|
104
|
+
if (event.key === "Escape") {
|
|
105
|
+
event.currentTarget.blur();
|
|
106
|
+
return setOpen(false);
|
|
107
|
+
}
|
|
108
|
+
if (event.key === "Enter") {
|
|
109
|
+
if (index !== null && list[index]) {
|
|
110
|
+
event.preventDefault();
|
|
111
|
+
return onSelect(list[index]);
|
|
112
|
+
}
|
|
113
|
+
if (list.length === 1) {
|
|
114
|
+
event.preventDefault();
|
|
115
|
+
return onSelect(list[0]);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
} })), { required: required, value: open ? shadow : value, "aria-autocomplete": "list", autoComplete: "off", className: css("input text-foreground group h-10 w-full flex-1 rounded-md bg-transparent p-2 placeholder-input-mask outline-none transition-colors group-error:text-danger group-error:placeholder-input-mask-error", !!props.right || shadow ? "pe-12" : "", !!props.left ? "ps-8" : "", props.className) })) })), _jsx(FloatingPortal, { preserveTabOrder: true, children: _jsx(FloatingFocusManager, { closeOnFocusOut: true, guards: true, returnFocus: true, context: context, initialFocus: -1, visuallyHiddenDismiss: true, children: _jsx("ul", Object.assign({}, getFloatingProps({
|
|
119
|
+
ref: refs.setFloating,
|
|
120
|
+
style: Object.assign({ position: strategy, left: x !== null && x !== void 0 ? x : 0, top: y !== null && y !== void 0 ? y : 0 }, transitions.styles),
|
|
121
|
+
}), { "data-floating": "true", className: "bg-floating-background shadow-floating text-foreground list-none p-0 m-0 rounded-b-lg overflow-auto origin-[top_center] overflow-y-auto z-floating", children: list.map((item, i) => (_createElement(Option, Object.assign({}, getItemProps({
|
|
122
|
+
onClick: () => onSelect(item),
|
|
123
|
+
ref: (node) => void (listRef.current[i] = node),
|
|
124
|
+
}), { key: `${item.value}-option`, option: item, selected: index === i, active: value === item.value })))) })) }) })] }));
|
|
125
|
+
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { __rest } from "tslib";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { FileIcon, Trash2Icon, UploadIcon } from "lucide-react";
|
|
4
|
+
import prettyBytes from "pretty-bytes";
|
|
5
|
+
import { Fragment, useEffect, useState } from "react";
|
|
6
|
+
import { useDropzone } from "react-dropzone";
|
|
7
|
+
import { Button } from "~/components/core/button";
|
|
8
|
+
const mime = {
|
|
9
|
+
isImage: (file) => file.type.includes("image"),
|
|
10
|
+
};
|
|
11
|
+
const FileViewer = (props) => {
|
|
12
|
+
const [info, setInfo] = useState({ url: "", type: "", size: "" });
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
if (mime.isImage(props.file)) {
|
|
15
|
+
const url = URL.createObjectURL(props.file);
|
|
16
|
+
setInfo({ url, type: "img", size: prettyBytes(props.file.size) });
|
|
17
|
+
return () => {
|
|
18
|
+
URL.revokeObjectURL(url);
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
setInfo({ url: "", type: props.file.type, size: prettyBytes(props.file.size) });
|
|
22
|
+
}, [props.file]);
|
|
23
|
+
if (info.type === "img") {
|
|
24
|
+
return (_jsxs("div", { className: "flex flex-row gap-jade-200 items-center justify-between w-full", children: [_jsxs("header", { className: "flex flex-row gap-jade-200 items-center", children: [_jsx("img", { src: info.url, className: "size-jade-500 rounded-jade-xsmall", alt: `Miniatura do arquivo ${props.file.name}` }), _jsxs("div", { className: "flex flex-col", children: [_jsx("span", { children: props.file.name }), _jsx("span", { children: info.size })] })] }), _jsx(Button, { className: "isolate", type: "button", theme: "raw", onClick: (e) => {
|
|
25
|
+
var _a;
|
|
26
|
+
e.stopPropagation();
|
|
27
|
+
(_a = props.onDeleteFile) === null || _a === void 0 ? void 0 : _a.call(props, props.file);
|
|
28
|
+
}, children: _jsx(Trash2Icon, {}) })] }));
|
|
29
|
+
}
|
|
30
|
+
return (_jsxs("div", { className: "flex flex-row gap-jade-200 items-center justify-between w-full", children: [_jsxs("header", { className: "flex flex-row gap-4 items-center", children: [_jsx(FileIcon, { size: 48 }), _jsxs("div", { className: "flex flex-col text-left justify-start items-start", children: [_jsx("span", { children: props.file.name }), _jsx("span", { children: info.size })] })] }), _jsx(Button, { className: "isolate", type: "button", theme: "raw", onClick: (e) => {
|
|
31
|
+
var _a;
|
|
32
|
+
e.stopPropagation();
|
|
33
|
+
(_a = props.onDeleteFile) === null || _a === void 0 ? void 0 : _a.call(props, props.file);
|
|
34
|
+
}, children: _jsx(Trash2Icon, { className: "text-danger" }) })] }));
|
|
35
|
+
};
|
|
36
|
+
const DefaultViewer = (props) => {
|
|
37
|
+
return (_jsx("ul", { className: "w-full space-y-jade-200", children: props.files.map((file) => {
|
|
38
|
+
return _jsx(FileViewer, { onDeleteFile: props.onDeleteFile, file: file }, file.name);
|
|
39
|
+
}) }));
|
|
40
|
+
};
|
|
41
|
+
const InteractiveArea = (props) => {
|
|
42
|
+
if (props.isDragActive) {
|
|
43
|
+
return _jsx("p", { children: "Solte os arquivos selecionados" });
|
|
44
|
+
}
|
|
45
|
+
if (props.files.length > 0) {
|
|
46
|
+
return _jsx(DefaultViewer, { onDeleteFile: props.onDeleteFile, files: props.files });
|
|
47
|
+
}
|
|
48
|
+
return _jsx(Fragment, { children: props.idle });
|
|
49
|
+
};
|
|
50
|
+
const DefaultIdle = (_jsxs("div", { className: "flex flex-col gap-4 justify-center items-center", children: [_jsx(UploadIcon, { size: 64 }), _jsxs("p", { children: ["You can drag your files or", " ", _jsx("button", { className: "text-primary underline", type: "button", children: "drag to here" })] })] }));
|
|
51
|
+
export const FileUpload = (_a) => {
|
|
52
|
+
var _b, _c;
|
|
53
|
+
var { idle = DefaultIdle, onDeleteFile, onDrop } = _a, props = __rest(_a, ["idle", "onDeleteFile", "onDrop"]);
|
|
54
|
+
const [files, setFiles] = useState([]);
|
|
55
|
+
const drop = (x) => {
|
|
56
|
+
onDrop === null || onDrop === void 0 ? void 0 : onDrop(x);
|
|
57
|
+
setFiles(x);
|
|
58
|
+
};
|
|
59
|
+
const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop: drop });
|
|
60
|
+
return (_jsxs("div", Object.assign({}, getRootProps(), { "data-active": ((_b = props.files) === null || _b === void 0 ? void 0 : _b.length) ? props.files.length > 0 : false, className: "flex text-foreground flex-col items-center justify-center border-2 rounded-lg p-6 border-card-border data-[active=true]:bg-card-background data-[active=true]:border-solid data-[active=false]:border-dashed", children: [_jsx("input", Object.assign({}, getInputProps(props), { name: props.name, id: props.name })), _jsx(InteractiveArea, { onDeleteFile: onDeleteFile, isDragActive: isDragActive, idle: idle, files: (_c = props.files) !== null && _c !== void 0 ? _c : files })] })));
|
|
61
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
const inputFields = ["INPUT", "SELECT"];
|
|
4
|
+
export const formReset = (form) => {
|
|
5
|
+
if (!form)
|
|
6
|
+
return;
|
|
7
|
+
const elements = Array.from(form.elements);
|
|
8
|
+
elements.forEach((field) => {
|
|
9
|
+
if (!inputFields.includes(field.tagName))
|
|
10
|
+
return;
|
|
11
|
+
if (field.tagName === "INPUT") {
|
|
12
|
+
field.value = field.defaultValue;
|
|
13
|
+
}
|
|
14
|
+
if (field.tagName === "SELECT") {
|
|
15
|
+
field.value = "";
|
|
16
|
+
}
|
|
17
|
+
field.setAttribute("data-initialized", "false");
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
export const Form = (props) => {
|
|
21
|
+
const onSubmit = (e) => {
|
|
22
|
+
var _a;
|
|
23
|
+
e.persist();
|
|
24
|
+
e.preventDefault();
|
|
25
|
+
(_a = props.onSubmit) === null || _a === void 0 ? void 0 : _a.call(props, e);
|
|
26
|
+
};
|
|
27
|
+
return _jsx("form", Object.assign({}, props, { onSubmit: onSubmit }));
|
|
28
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { CheckCircle, XCircle } from "lucide-react";
|
|
4
|
+
import { Fragment } from "react";
|
|
5
|
+
import { css } from "~/lib/dom";
|
|
6
|
+
export const InputFeedback = ({ reportStatus, hideLeft = false, className, children, title }) => (_jsxs("div", { className: css("w-full justify-between", hideLeft && children === null ? "hidden" : "flex", className), children: [hideLeft ? null : (_jsxs("span", { className: "flex items-center gap-1 group-hover:text-primary group-focus-within:text-primary transition-colors group-error:text-danger", children: [title, reportStatus ? (_jsxs("span", { className: "flex aspect-square h-4 w-4 items-center justify-center", children: [_jsx(CheckCircle, { className: "hidden aspect-square h-3 w-3 opacity-0 transition-opacity group-assert:block group-assert:text-success group-assert:opacity-100", "aria-hidden": "true", size: 16, strokeWidth: 1, absoluteStrokeWidth: true }), _jsx(XCircle, { className: "hidden aspect-square h-3 w-3 opacity-0 transition-opacity group-error:block group-error:opacity-100", "aria-hidden": "true", size: 16, strokeWidth: 1, absoluteStrokeWidth: true })] })) : null] })), children] }));
|
|
7
|
+
export const InputField = ({ optionalText = "Optional", left, rightLabel, container, right, children, error, form, id, name, title, placeholder, hideLeft, required, }) => {
|
|
8
|
+
const ID = id !== null && id !== void 0 ? id : name;
|
|
9
|
+
return (_jsxs("fieldset", { "data-error": !!error, form: form, className: css("group inline-block w-full", container), children: [_jsxs("label", { form: form, htmlFor: ID, className: "inline-flex w-full cursor-text flex-row flex-wrap justify-between gap-1 text-sm transition-colors empty:hidden group-error:text-danger group-hover:border-primary", children: [!hideLeft && !rightLabel ? (_jsx(InputFeedback, { hideLeft: hideLeft, reportStatus: true, title: title, placeholder: placeholder, children: optionalText || rightLabel ? (_jsxs(Fragment, { children: [!required ? _jsx("span", { className: "text-opacity-70", children: optionalText }) : null, rightLabel ? _jsx(Fragment, { children: rightLabel }) : null] })) : null })) : null, _jsxs("div", { className: "relative group flex w-full flex-row flex-nowrap items-center gap-x-2 gap-y-1 rounded-md border border-input-border bg-transparent transition-colors group-focus-within:border-primary group-hover:border-primary group-error:border-danger", children: [left ? _jsx("span", { className: "absolute left-0 flex flex-nowrap gap-1 whitespace-nowrap pl-2", children: left }) : null, children, right ? _jsx("span", { className: "absolute right-0 flex flex-nowrap gap-2 whitespace-nowrap pr-1", children: right }) : null] })] }), _jsx("p", { className: "mt-1 text-xs group-error:block group-error:text-danger", children: error })] }));
|
|
10
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { __rest } from "tslib";
|
|
3
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
4
|
+
import { forwardRef, useEffect, useRef } from "react";
|
|
5
|
+
import MaskInput from "the-mask-input";
|
|
6
|
+
import { InputField } from "~/components/form/input-field";
|
|
7
|
+
import { css, mergeRefs } from "~/lib/dom";
|
|
8
|
+
export const Input = forwardRef((_a, ref) => {
|
|
9
|
+
var _b;
|
|
10
|
+
var { type = "text", container, next, rightLabel, optionalText, hideLeft = false, right, left } = _a, props = __rest(_a, ["type", "container", "next", "rightLabel", "optionalText", "hideLeft", "right", "left"]);
|
|
11
|
+
const id = (_b = props.id) !== null && _b !== void 0 ? _b : props.name;
|
|
12
|
+
const inputRef = useRef(null);
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
if (inputRef.current === null)
|
|
15
|
+
return;
|
|
16
|
+
const input = inputRef.current;
|
|
17
|
+
const focus = () => input.setAttribute("data-initialized", "true");
|
|
18
|
+
const goNextInputImpl = (e) => {
|
|
19
|
+
const event = e;
|
|
20
|
+
if (event.key === "Enter" && input.enterKeyHint === "next") {
|
|
21
|
+
const focusNext = input.getAttribute("data-next");
|
|
22
|
+
if (focusNext) {
|
|
23
|
+
const el = document.getElementById(focusNext);
|
|
24
|
+
if (el) {
|
|
25
|
+
el.focus();
|
|
26
|
+
return void event.preventDefault();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
input.addEventListener("keydown", goNextInputImpl);
|
|
32
|
+
input.addEventListener("focus", focus);
|
|
33
|
+
return () => {
|
|
34
|
+
input.removeEventListener("keydown", goNextInputImpl);
|
|
35
|
+
input.removeEventListener("focus", focus);
|
|
36
|
+
};
|
|
37
|
+
}, []);
|
|
38
|
+
return (_jsx(InputField, Object.assign({}, props, { right: right, left: left, hideLeft: hideLeft, rightLabel: rightLabel, optionalText: optionalText, container: css("group inline-block w-full", container), children: _jsx(MaskInput, Object.assign({}, props, { type: type, "data-next": next, ref: mergeRefs(ref, inputRef), id: id, name: id, className: css("input text-foreground group h-10 w-full flex-1 rounded-md bg-transparent p-2 placeholder-input-mask outline-none transition-colors group-error:text-danger group-error:placeholder-input-mask-error", !!right ? "pe-4" : "", !!left ? "ps-4" : "", props.className) })) })));
|
|
39
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { __rest } from "tslib";
|
|
3
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { ChevronDown } from "lucide-react";
|
|
5
|
+
import { forwardRef, useEffect, useRef } from "react";
|
|
6
|
+
import { InputField } from "~/components/form/input-field";
|
|
7
|
+
import { css, mergeRefs } from "~/lib/dom";
|
|
8
|
+
export const Select = forwardRef((_a, ref) => {
|
|
9
|
+
var _b;
|
|
10
|
+
var { container, required = true, options } = _a, props = __rest(_a, ["container", "required", "options"]);
|
|
11
|
+
const inputRef = useRef(null);
|
|
12
|
+
const id = (_b = props.id) !== null && _b !== void 0 ? _b : props.name;
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
if (inputRef.current === null)
|
|
15
|
+
return;
|
|
16
|
+
const input = inputRef.current;
|
|
17
|
+
const focus = () => input.setAttribute("data-initialized", "true");
|
|
18
|
+
const change = () => input.setAttribute("data-selected", "true");
|
|
19
|
+
input.addEventListener("focus", focus);
|
|
20
|
+
input.addEventListener("change", change);
|
|
21
|
+
return () => {
|
|
22
|
+
input.removeEventListener("focus", focus);
|
|
23
|
+
input.removeEventListener("change", change);
|
|
24
|
+
};
|
|
25
|
+
}, []);
|
|
26
|
+
return (_jsx(InputField, Object.assign({}, props, { required: required, container: css("group inline-block w-full", container), right: _jsx(ChevronDown, { size: 20 }), children: _jsxs("select", Object.assign({}, props, { ref: mergeRefs(ref, inputRef), id: id, name: id, required: required, "data-selected": !!props.value || false, className: css("input bg-transparent text-foreground select group h-10 w-full flex-1 rounded-md p-2 placeholder-input-placeholder outline-none transition-colors group-error:text-danger group-error:placeholder-input-mask-error", "data-[selected=false]:text-input-placeholder", props.className), children: [_jsx("option", { value: "", hidden: true, disabled: true, children: props.placeholder }), options.map((option) => {
|
|
27
|
+
var _a;
|
|
28
|
+
return (_jsx("option", Object.assign({}, option, { children: (_a = option.label) !== null && _a !== void 0 ? _a : option.value }), `${id}-select-option-${option.value}`));
|
|
29
|
+
})] })) })));
|
|
30
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { __rest } from "tslib";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useId, useState } from "react";
|
|
4
|
+
export const Switch = (_a) => {
|
|
5
|
+
var _b;
|
|
6
|
+
var { children } = _a, props = __rest(_a, ["children"]);
|
|
7
|
+
const id = useId();
|
|
8
|
+
const [innerChecked, setInnerChecked] = useState(false);
|
|
9
|
+
const checked = (_b = props.checked) !== null && _b !== void 0 ? _b : innerChecked;
|
|
10
|
+
const onCheck = (e) => {
|
|
11
|
+
var _a;
|
|
12
|
+
const button = e.target;
|
|
13
|
+
const checked = !(button.dataset.checked === "true");
|
|
14
|
+
setInnerChecked(checked);
|
|
15
|
+
(_a = props === null || props === void 0 ? void 0 : props.onCheck) === null || _a === void 0 ? void 0 : _a.call(props, checked);
|
|
16
|
+
};
|
|
17
|
+
return (_jsxs("div", { className: "flex items-center", children: [_jsx("input", Object.assign({}, props, { hidden: true, type: "checkbox", checked: checked, onChange: (e) => setInnerChecked(e.target.checked) })), _jsx("button", { type: "button", role: "switch", onClick: onCheck, "aria-checked": checked, "data-checked": checked, "aria-labelledby": `${id}-label`, className: "relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent data-[checked=false]:bg-input-switch-bg data-[checked=true]:bg-primary transition-colors ease-in-out focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2", children: _jsx("span", { "aria-hidden": "true", "data-checked": checked, className: "data-[checked=false]:bg-disabled data-[checked=true]:bg-input-switch pointer-events-none inline-block size-5 aspect-square data-[checked=false]translate-x-0 data-[checked=true]:translate-x-5 transform rounded-full shadow ring-0 transition ease-in-out" }) }), _jsx("span", { className: "ml-3 text-sm", id: `${id}-label`, children: _jsx("span", { className: "font-medium text-foreground", children: children }) })] }));
|
|
18
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export * from "./form/autocomplete";
|
|
2
|
+
export * from "./form/input";
|
|
3
|
+
export * from "./form/select";
|
|
4
|
+
export * from "./form/file-upload";
|
|
5
|
+
export * from "./form/form";
|
|
6
|
+
export * from "./form/select";
|
|
7
|
+
export * from "./form/switch";
|
|
8
|
+
export * from "./form/input-field";
|
|
9
|
+
export * from "./core/button";
|
|
10
|
+
export * from "./core/polymorph";
|
|
11
|
+
export * from "./display/card";
|
|
12
|
+
export * from "./floating/dropdown";
|
|
13
|
+
export * from "./floating/tooltip";
|
|
14
|
+
export * from "./table/index";
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { PlusIcon, SearchIcon, Trash2Icon } from "lucide-react";
|
|
3
|
+
import { Fragment } from "react";
|
|
4
|
+
import { Dropdown } from "~/components/floating/dropdown";
|
|
5
|
+
import { Input } from "~/components/form/input";
|
|
6
|
+
import { Select } from "~/components/form/select";
|
|
7
|
+
import { uuid } from "~/lib/fns";
|
|
8
|
+
import { ColType, getLabel, valueFromType } from "./table-lib";
|
|
9
|
+
const operators = {
|
|
10
|
+
contains: { value: "contains", label: "Contains", symbol: "includes" },
|
|
11
|
+
is: { value: "is", label: "Is", symbol: "is" },
|
|
12
|
+
isNot: { value: "isNot", label: "Is not", symbol: "!==" },
|
|
13
|
+
notContains: { value: "notContains", label: "Does not contains", symbol: "notIncludes" },
|
|
14
|
+
lessThan: { value: "lessThan", label: "Less Than", symbol: "<=" },
|
|
15
|
+
greaterThan: { value: "greaterThan", label: "Greater than", symbol: ">=" },
|
|
16
|
+
startsWith: { value: "startsWith", label: "Starts with", symbol: "startsWith" },
|
|
17
|
+
endsWith: { value: "endsWith", label: "Ends with", symbol: "endsWith" },
|
|
18
|
+
};
|
|
19
|
+
const operatorOptions = {
|
|
20
|
+
[ColType.Text]: [operators.is, operators.isNot, operators.contains, operators.notContains, operators.startsWith, operators.endsWith],
|
|
21
|
+
[ColType.Boolean]: [operators.is, operators.isNot],
|
|
22
|
+
[ColType.Number]: [operators.is, operators.isNot, operators.greaterThan, operators.lessThan],
|
|
23
|
+
};
|
|
24
|
+
export const createFilterFromCol = (f, rest = {}) => {
|
|
25
|
+
var _a, _b;
|
|
26
|
+
const name = f.id;
|
|
27
|
+
const type = (_a = f.type) !== null && _a !== void 0 ? _a : ColType.Text;
|
|
28
|
+
const operatorId = (_b = operatorOptions[type]) === null || _b === void 0 ? void 0 : _b[0].value;
|
|
29
|
+
const operation = operators[operatorId];
|
|
30
|
+
return Object.assign({ id: uuid(), operation, label: getLabel(f), name, type, value: "" }, rest);
|
|
31
|
+
};
|
|
32
|
+
export const Filter = (props) => {
|
|
33
|
+
const onAddFilter = () => {
|
|
34
|
+
const col = props.cols.at(0);
|
|
35
|
+
props.set((prev) => [...prev, createFilterFromCol(col)]);
|
|
36
|
+
};
|
|
37
|
+
const onSelectProperty = (e) => {
|
|
38
|
+
const changedId = e.target.dataset.id || "";
|
|
39
|
+
const newId = e.target.value;
|
|
40
|
+
props.set((prev) => prev.map((x) => {
|
|
41
|
+
if (changedId !== x.id)
|
|
42
|
+
return x;
|
|
43
|
+
const col = props.cols.find((x) => newId === x.id);
|
|
44
|
+
return createFilterFromCol(col, { value: "" });
|
|
45
|
+
}));
|
|
46
|
+
};
|
|
47
|
+
const onSelectOperation = (e) => {
|
|
48
|
+
const id = e.target.dataset.id || "";
|
|
49
|
+
const operator = e.target.value;
|
|
50
|
+
props.set((prev) => prev.map((x) => (x.id === id ? Object.assign(Object.assign({}, x), { operation: operators[operator] }) : x)));
|
|
51
|
+
};
|
|
52
|
+
const onDelete = (e) => {
|
|
53
|
+
const id = e.currentTarget.dataset.id || "";
|
|
54
|
+
console.log({ id, f: props.filters });
|
|
55
|
+
props.set((prev) => prev.filter((x) => x.id !== id));
|
|
56
|
+
};
|
|
57
|
+
const onChangeValue = (e) => {
|
|
58
|
+
const id = e.target.dataset.id || "";
|
|
59
|
+
const value = valueFromType(e.target);
|
|
60
|
+
props.set((prev) => prev.map((x) => (x.id === id ? Object.assign(Object.assign({}, x), { value }) : x)));
|
|
61
|
+
};
|
|
62
|
+
return (_jsx(Fragment, { children: _jsx(Dropdown, { arrow: false, title: "Filters", trigger: _jsxs("span", { className: "flex items-center gap-1 proportional-nums", children: [_jsx(SearchIcon, { size: 14 }), "Filtros ", props.filters.length === 0 ? "" : ` (${props.filters.length})`] }), children: _jsxs("ul", { className: "mt-4 space-y-2", children: [props.filters.map((filter) => {
|
|
63
|
+
const operators = operatorOptions[filter.type];
|
|
64
|
+
return (_jsxs("li", { className: "flex flex-nowrap gap-3", children: [_jsx(Select, { title: "Filtro", options: props.options, placeholder: "Seleciona um campo...", value: filter.name, "data-id": filter.id, onChange: onSelectProperty }), _jsx(Select, { title: "Tipo do filtro", "data-id": filter.id, onChange: onSelectOperation, value: filter.operation.value, options: operators, placeholder: "Opera\u00E7\u00E3o..." }), _jsx(Input, { "data-id": filter.id, onChange: onChangeValue, placeholder: "Buscar por...", title: "Valor do filtro", type: filter.type, value: filter.value }), _jsx("div", { className: "flex items-center justify-center mt-5", children: _jsx("button", { "data-id": filter.id, type: "button", onClick: onDelete, children: _jsx(Trash2Icon, { className: "text-danger", size: 16 }) }) })] }, `filter-select-${filter.id}`));
|
|
65
|
+
}), _jsx("li", { children: _jsxs("button", { type: "button", onClick: onAddFilter, className: "text-primary flex items-center gap-1", children: [_jsx(PlusIcon, { size: 14 }), " Adicionar novo filtro"] }) })] }) }) }));
|
|
66
|
+
};
|
|
67
|
+
export const ColumnHeaderFilter = ({ filter, set }) => {
|
|
68
|
+
const onSelectOperation = (e) => {
|
|
69
|
+
const operator = e.target.value;
|
|
70
|
+
const id = e.target.dataset.id || "";
|
|
71
|
+
set((prev) => prev.map((x) => (x.id === id ? Object.assign(Object.assign({}, x), { operation: operators[operator] }) : x)));
|
|
72
|
+
};
|
|
73
|
+
const onChangeValue = (e) => {
|
|
74
|
+
const id = e.target.dataset.id || "";
|
|
75
|
+
const value = valueFromType(e.target);
|
|
76
|
+
set((prev) => prev.map((x) => (x.id === id ? Object.assign(Object.assign({}, x), { value }) : x)));
|
|
77
|
+
};
|
|
78
|
+
return (_jsxs("div", { className: "flex flex-nowrap items-center gap-4 py-2", children: [_jsx(Select, { onChange: onSelectOperation, value: filter.operation.value, options: operatorOptions[filter.type], placeholder: "Operation..." }), _jsx(Input, { type: filter.type, "data-id": filter.id, onChange: onChangeValue, placeholder: "Looking for...", value: filter.value })] }));
|
|
79
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { LayoutGroup, Reorder, useDragControls, useMotionValue } from "framer-motion";
|
|
4
|
+
import Linq from "linq-arrays";
|
|
5
|
+
import { GripVerticalIcon, GroupIcon, Trash2Icon } from "lucide-react";
|
|
6
|
+
import { Fragment, useState } from "react";
|
|
7
|
+
import { keys } from "sidekicker";
|
|
8
|
+
import { Button } from "~/components/core/button";
|
|
9
|
+
import { Dropdown } from "~/components/floating/dropdown";
|
|
10
|
+
import { Select } from "~/components/form/select";
|
|
11
|
+
import { uuid } from "~/lib/fns";
|
|
12
|
+
import { createOptionCols } from "./table-lib";
|
|
13
|
+
const Item = ({ item, onPointerDown }) => {
|
|
14
|
+
const y = useMotionValue(0);
|
|
15
|
+
return (_jsxs(Reorder.Item, { onPointerDown: onPointerDown, id: item.groupId, className: "flex flex-row items-center gap-2", value: item, style: { y }, children: [_jsx("button", { className: "cursor-grab", children: _jsx(GripVerticalIcon, { size: 14 }) }), _jsx("span", { children: item.groupName })] }, item.groupId));
|
|
16
|
+
};
|
|
17
|
+
export const Group = (props) => {
|
|
18
|
+
var _a;
|
|
19
|
+
const options = createOptionCols(props.cols);
|
|
20
|
+
const controls = useDragControls();
|
|
21
|
+
const [group, setGroup] = useState(((_a = props.groups[0]) === null || _a === void 0 ? void 0 : _a.thead) || "");
|
|
22
|
+
const onChange = (e) => {
|
|
23
|
+
var _a;
|
|
24
|
+
const select = e.target;
|
|
25
|
+
const key = select.value;
|
|
26
|
+
const index = select.options.selectedIndex;
|
|
27
|
+
const label = ((_a = select.options.item(index)) === null || _a === void 0 ? void 0 : _a.label) || "";
|
|
28
|
+
setGroup(label);
|
|
29
|
+
const groupBy = new Linq(props.rows).GroupBy(key);
|
|
30
|
+
const col = props.cols.find((x) => x.id === key);
|
|
31
|
+
props.setGroups(keys(groupBy).map((groupName, index) => {
|
|
32
|
+
const rows = groupBy[groupName];
|
|
33
|
+
return Object.assign(Object.assign({}, col), { groupId: uuid(), groupKey: key, index, rows, groupName: groupName });
|
|
34
|
+
}));
|
|
35
|
+
};
|
|
36
|
+
const onDelete = (e) => props.setGroups([]);
|
|
37
|
+
return (_jsx(Fragment, { children: _jsxs(Dropdown, { arrow: false, title: "Groups", trigger: _jsxs("span", { className: "flex items-center gap-1 proportional-nums", children: [_jsx(GroupIcon, { size: 14 }), "Groups", props.groups.length > 0 ? ` - ${group}(${props.groups.length})` : ""] }), children: [_jsxs("div", { className: "flex flex-nowrap items-center", children: [_jsx(Select, { value: group, title: "Tipo de agrupamento", onChange: onChange, options: options, placeholder: "Agrupar por..." }), _jsx(Button, { className: "mt-4", onClick: onDelete, theme: "raw", "data-id": group, children: _jsx(Trash2Icon, { size: 16, className: "text-danger" }) })] }), props.groups.length > 0 ? (_jsxs("section", { className: "my-4", children: [_jsx("header", { children: _jsx("h2", { className: "text-xl font-medium", children: "Ordenar grupos" }) }), _jsx(LayoutGroup, { children: _jsx(Reorder.Group, { axis: "y", className: "relative space-y-2", dragListener: false, dragControls: controls, drag: true, layoutScroll: true, onReorder: props.setGroups, values: props.groups, children: props.groups.map((item) => (_jsx(Item, { item: item, onPointerDown: (e) => {
|
|
38
|
+
controls.start(e);
|
|
39
|
+
props.setGroups([...props.groups]);
|
|
40
|
+
} }, item.groupId))) }) })] })) : null] }) }));
|
|
41
|
+
};
|