@g4rcez/components 3.0.0-0 → 3.0.1
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/ai/SKILL.md +266 -0
- package/dist/ai/docs/Alert.md +167 -0
- package/dist/ai/docs/AnimatedList.md +205 -0
- package/dist/ai/docs/Autocomplete.md +225 -0
- package/dist/ai/docs/Button.md +182 -0
- package/dist/ai/docs/Calendar.md +219 -0
- package/dist/ai/docs/Card.md +174 -0
- package/dist/ai/docs/Checkbox.md +199 -0
- package/dist/ai/docs/CommandPalette.md +293 -0
- package/dist/ai/docs/DatePicker.md +171 -0
- package/dist/ai/docs/Dropdown.md +223 -0
- package/dist/ai/docs/Empty.md +163 -0
- package/dist/ai/docs/Expand.md +143 -0
- package/dist/ai/docs/FileUpload.md +225 -0
- package/dist/ai/docs/Form.md +107 -0
- package/dist/ai/docs/FormReset.md +117 -0
- package/dist/ai/docs/Heading.md +88 -0
- package/dist/ai/docs/Input.md +237 -0
- package/dist/ai/docs/InputField.md +170 -0
- package/dist/ai/docs/List.md +205 -0
- package/dist/ai/docs/Menu.md +166 -0
- package/dist/ai/docs/Modal.md +280 -0
- package/dist/ai/docs/MultiSelect.md +196 -0
- package/dist/ai/docs/Notifications.md +231 -0
- package/dist/ai/docs/PageCalendar.md +271 -0
- package/dist/ai/docs/Polymorph.md +159 -0
- package/dist/ai/docs/Progress.md +145 -0
- package/dist/ai/docs/Radiobox.md +128 -0
- package/dist/ai/docs/RenderOnView.md +138 -0
- package/dist/ai/docs/Resizable.md +159 -0
- package/dist/ai/docs/Select.md +284 -0
- package/dist/ai/docs/Shortcut.md +105 -0
- package/dist/ai/docs/Skeleton.md +166 -0
- package/dist/ai/docs/Slider.md +144 -0
- package/dist/ai/docs/Slot.md +173 -0
- package/dist/ai/docs/Spinner.md +118 -0
- package/dist/ai/docs/Stats.md +137 -0
- package/dist/ai/docs/Step.md +159 -0
- package/dist/ai/docs/Switch.md +167 -0
- package/dist/ai/docs/Table.md +298 -0
- package/dist/ai/docs/Tabs.md +191 -0
- package/dist/ai/docs/Tag.md +224 -0
- package/dist/ai/docs/TaskList.md +144 -0
- package/dist/ai/docs/Textarea.md +167 -0
- package/dist/ai/docs/Timeline.md +210 -0
- package/dist/ai/docs/Toolbar.md +132 -0
- package/dist/ai/docs/Tooltip.md +231 -0
- package/dist/ai/docs/TransferList.md +142 -0
- package/dist/ai/docs/Typography.md +187 -0
- package/dist/ai/docs/Wizard.md +213 -0
- package/dist/ai/docs/index.md +183 -0
- package/dist/components/core/button.d.ts +2 -8
- package/dist/components/core/button.d.ts.map +1 -1
- package/dist/components/core/polymorph.d.ts.map +1 -1
- package/dist/components/core/slot.d.ts +1 -1
- package/dist/components/core/slot.d.ts.map +1 -1
- package/dist/components/core/tag.d.ts +2 -2
- package/dist/components/core/tag.d.ts.map +1 -1
- package/dist/components/core/typography.d.ts.map +1 -1
- package/dist/components/display/alert.d.ts.map +1 -1
- package/dist/components/display/calendar.d.ts.map +1 -1
- package/dist/components/display/card.d.ts.map +1 -1
- package/dist/components/display/list.d.ts.map +1 -1
- package/dist/components/display/notifications.d.ts +2 -0
- package/dist/components/display/notifications.d.ts.map +1 -1
- package/dist/components/display/progress.d.ts.map +1 -1
- package/dist/components/display/skeleton.d.ts.map +1 -1
- package/dist/components/display/step.d.ts.map +1 -1
- package/dist/components/display/tabs.d.ts.map +1 -1
- package/dist/components/floating/command-palette.d.ts +1 -0
- package/dist/components/floating/command-palette.d.ts.map +1 -1
- package/dist/components/floating/dropdown.d.ts +1 -0
- package/dist/components/floating/dropdown.d.ts.map +1 -1
- package/dist/components/floating/menu.d.ts +2 -2
- package/dist/components/floating/menu.d.ts.map +1 -1
- package/dist/components/floating/modal.d.ts +20 -53
- package/dist/components/floating/modal.d.ts.map +1 -1
- package/dist/components/floating/tooltip.d.ts.map +1 -1
- package/dist/components/floating/wizard.d.ts +1 -1
- package/dist/components/floating/wizard.d.ts.map +1 -1
- package/dist/components/form/autocomplete.d.ts.map +1 -1
- package/dist/components/form/date-picker.d.ts.map +1 -1
- package/dist/components/form/free-text.d.ts.map +1 -1
- package/dist/components/form/input-field.d.ts +3 -2
- package/dist/components/form/input-field.d.ts.map +1 -1
- package/dist/components/form/multi-select.d.ts.map +1 -1
- package/dist/components/form/select.d.ts.map +1 -1
- package/dist/components/form/slider.d.ts.map +1 -1
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/page-calendar/calendar-header.d.ts +16 -0
- package/dist/components/page-calendar/calendar-header.d.ts.map +1 -0
- package/dist/components/page-calendar/day-view.d.ts +12 -0
- package/dist/components/page-calendar/day-view.d.ts.map +1 -0
- package/dist/components/page-calendar/event-pill.d.ts +9 -0
- package/dist/components/page-calendar/event-pill.d.ts.map +1 -0
- package/dist/components/page-calendar/index.d.ts +4 -0
- package/dist/components/page-calendar/index.d.ts.map +1 -0
- package/dist/components/page-calendar/month-view.d.ts +11 -0
- package/dist/components/page-calendar/month-view.d.ts.map +1 -0
- package/dist/components/page-calendar/page-calendar.d.ts +18 -0
- package/dist/components/page-calendar/page-calendar.d.ts.map +1 -0
- package/dist/components/page-calendar/page-calendar.types.d.ts +18 -0
- package/dist/components/page-calendar/page-calendar.types.d.ts.map +1 -0
- package/dist/components/page-calendar/page-calendar.utils.d.ts +18 -0
- package/dist/components/page-calendar/page-calendar.utils.d.ts.map +1 -0
- package/dist/components/page-calendar/week-view.d.ts +11 -0
- package/dist/components/page-calendar/week-view.d.ts.map +1 -0
- package/dist/components/table/index.d.ts.map +1 -1
- package/dist/components/table/inner-table.d.ts.map +1 -1
- package/dist/components/table/metadata.d.ts.map +1 -1
- package/dist/components/table/row.d.ts.map +1 -1
- package/dist/components/table/table-lib.d.ts.map +1 -1
- package/dist/components/table/thead.d.ts.map +1 -1
- package/dist/config/context.d.ts.map +1 -1
- package/dist/config/default-translations.d.ts +21 -4
- package/dist/config/default-translations.d.ts.map +1 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/hooks/use-components-provider.d.ts.map +1 -1
- package/dist/hooks/use-form.d.ts +11 -11
- package/dist/hooks/use-form.d.ts.map +1 -1
- package/dist/hooks/use-input-id.d.ts.map +1 -1
- package/dist/hooks/use-preferences.d.ts.map +1 -1
- package/dist/hooks/use-previous.d.ts.map +1 -1
- package/dist/hooks/use-reactive.d.ts.map +1 -1
- package/dist/hooks/use-resize-observer.d.ts.map +1 -1
- package/dist/hooks/use-stable-ref.d.ts.map +1 -1
- package/dist/hooks/use-swipe.d.ts.map +1 -1
- package/dist/hooks/use-translations.d.ts +21 -4
- package/dist/hooks/use-translations.d.ts.map +1 -1
- package/dist/index.css +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +28 -20
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +13862 -12512
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +24 -17
- package/dist/index.umd.js.map +1 -1
- package/dist/lib/dom.d.ts +1 -0
- package/dist/lib/dom.d.ts.map +1 -1
- package/dist/lib/fns.d.ts.map +1 -1
- package/dist/preset/plugin.tailwind.d.ts +9 -0
- package/dist/preset/plugin.tailwind.d.ts.map +1 -0
- package/dist/preset/plugin.tailwind.js +27 -0
- package/dist/preset/preset.tailwind.d.ts +8 -0
- package/dist/preset/preset.tailwind.d.ts.map +1 -0
- package/dist/preset/preset.tailwind.js +54 -0
- package/dist/preset/src/styles/common.d.ts +2 -14
- package/dist/preset/src/styles/common.d.ts.map +1 -1
- package/dist/preset/src/styles/common.js +1 -0
- package/dist/preset/src/styles/dark.d.ts.map +1 -1
- package/dist/preset/src/styles/dark.js +119 -114
- package/dist/preset/src/styles/light.d.ts.map +1 -1
- package/dist/preset/src/styles/light.js +111 -106
- package/dist/preset/src/styles/theme.types.d.ts +17 -8
- package/dist/preset/src/styles/theme.types.d.ts.map +1 -1
- package/dist/styles/common.d.ts +2 -14
- package/dist/styles/common.d.ts.map +1 -1
- package/dist/styles/dark.d.ts.map +1 -1
- package/dist/styles/light.d.ts.map +1 -1
- package/dist/styles/theme.types.d.ts +17 -8
- package/dist/styles/theme.types.d.ts.map +1 -1
- package/package.json +299 -301
- package/dist/components/core/button.jsx +0 -86
- package/dist/components/core/heading.jsx +0 -4
- package/dist/components/core/polymorph.jsx +0 -5
- package/dist/components/core/render-on-view.jsx +0 -31
- package/dist/components/core/resizable.jsx +0 -51
- package/dist/components/core/slot.jsx +0 -163
- package/dist/components/core/tag.jsx +0 -51
- package/dist/components/core/typography.jsx +0 -26
- package/dist/components/display/alert.jsx +0 -56
- package/dist/components/display/calendar.jsx +0 -301
- package/dist/components/display/card.jsx +0 -43
- package/dist/components/display/empty.jsx +0 -11
- package/dist/components/display/list.jsx +0 -81
- package/dist/components/display/notifications.jsx +0 -98
- package/dist/components/display/progress.jsx +0 -13
- package/dist/components/display/shortcut.jsx +0 -23
- package/dist/components/display/skeleton.jsx +0 -14
- package/dist/components/display/spinner.jsx +0 -7
- package/dist/components/display/stats.jsx +0 -20
- package/dist/components/display/step.jsx +0 -131
- package/dist/components/display/tabs.jsx +0 -100
- package/dist/components/display/timeline.jsx +0 -25
- package/dist/components/floating/command-palette.jsx +0 -172
- package/dist/components/floating/dropdown.jsx +0 -53
- package/dist/components/floating/expand.jsx +0 -44
- package/dist/components/floating/menu.jsx +0 -147
- package/dist/components/floating/modal.jsx +0 -241
- package/dist/components/floating/toolbar.jsx +0 -5
- package/dist/components/floating/tooltip.jsx +0 -64
- package/dist/components/floating/wizard.jsx +0 -164
- package/dist/components/form/autocomplete.jsx +0 -275
- package/dist/components/form/checkbox.jsx +0 -12
- package/dist/components/form/date-picker.jsx +0 -115
- package/dist/components/form/file-upload.jsx +0 -133
- package/dist/components/form/form.jsx +0 -10
- package/dist/components/form/formReset.jsx +0 -17
- package/dist/components/form/free-text.jsx +0 -41
- package/dist/components/form/input-field.jsx +0 -54
- package/dist/components/form/input.jsx +0 -36
- package/dist/components/form/multi-select.jsx +0 -328
- package/dist/components/form/radiobox.jsx +0 -6
- package/dist/components/form/select.jsx +0 -42
- package/dist/components/form/slider.jsx +0 -45
- package/dist/components/form/switch.jsx +0 -46
- package/dist/components/form/task-list.jsx +0 -26
- package/dist/components/form/textarea.jsx +0 -12
- package/dist/components/form/transfer-list.jsx +0 -39
- package/dist/components/index.js +0 -43
- package/dist/components/table/filter.jsx +0 -141
- package/dist/components/table/group.jsx +0 -68
- package/dist/components/table/index.jsx +0 -60
- package/dist/components/table/inner-table.jsx +0 -104
- package/dist/components/table/metadata.jsx +0 -37
- package/dist/components/table/pagination.jsx +0 -73
- package/dist/components/table/row.jsx +0 -58
- package/dist/components/table/sort.jsx +0 -105
- package/dist/components/table/table-lib.js +0 -84
- package/dist/components/table/table.context.jsx +0 -4
- package/dist/components/table/thead.jsx +0 -103
- package/dist/config/context.js +0 -12
- package/dist/config/default-translations.jsx +0 -66
- package/dist/config/default-tweaks.js +0 -4
- package/dist/constants.js +0 -2
- package/dist/hooks/use-click-outside.js +0 -17
- package/dist/hooks/use-color-parser.js +0 -9
- package/dist/hooks/use-components-provider.jsx +0 -16
- package/dist/hooks/use-debounce.js +0 -12
- package/dist/hooks/use-floating-ref.js +0 -6
- package/dist/hooks/use-form.js +0 -549
- package/dist/hooks/use-hover.js +0 -18
- package/dist/hooks/use-input-id.js +0 -5
- package/dist/hooks/use-is-coarse-device.js +0 -12
- package/dist/hooks/use-locale.js +0 -10
- package/dist/hooks/use-media-query.js +0 -25
- package/dist/hooks/use-on-event.js +0 -7
- package/dist/hooks/use-parent.js +0 -21
- package/dist/hooks/use-preferences.js +0 -23
- package/dist/hooks/use-previous.js +0 -8
- package/dist/hooks/use-reactive.js +0 -8
- package/dist/hooks/use-remove-scroll.js +0 -61
- package/dist/hooks/use-resize-observer.js +0 -17
- package/dist/hooks/use-stable-ref.js +0 -8
- package/dist/hooks/use-swipe.js +0 -16
- package/dist/hooks/use-translations.js +0 -9
- package/dist/hooks/use-tweaks.js +0 -9
- package/dist/hooks/use-window-size.js +0 -14
- package/dist/lib/combi-keys.js +0 -60
- package/dist/lib/dict.js +0 -39
- package/dist/lib/dom.js +0 -44
- package/dist/lib/fns.js +0 -46
- package/dist/lib/fzf.js +0 -117
- package/dist/lib/keyboard-area.js +0 -14
- package/dist/preset/tailwindcssv4.d.ts +0 -3
- package/dist/preset/tailwindcssv4.d.ts.map +0 -1
- package/dist/preset/tailwindcssv4.js +0 -75
- package/dist/styles/common.js +0 -28
- package/dist/styles/dark.js +0 -209
- package/dist/styles/design-tokens.js +0 -69
- package/dist/styles/light.js +0 -209
- package/dist/styles/theme.js +0 -4
- package/dist/styles/theme.types.js +0 -1
- package/dist/types.js +0 -1
|
@@ -1,275 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { autoPlacement, autoUpdate, FloatingFocusManager, FloatingPortal, offset, size, useDismiss, useFloating, useInteractions, useListNavigation, useRole, useTransitionStyles, } from "@floating-ui/react";
|
|
3
|
-
import { ChevronDown } from "lucide-react";
|
|
4
|
-
import { AnimatePresence, motion } from "motion/react";
|
|
5
|
-
import React, { forwardRef, Fragment, useEffect, useRef, useState } from "react";
|
|
6
|
-
import { flushSync } from "react-dom";
|
|
7
|
-
import { Virtuoso } from "react-virtuoso";
|
|
8
|
-
import { Is } from "sidekicker";
|
|
9
|
-
import { useRemoveScroll } from "../../hooks/use-remove-scroll";
|
|
10
|
-
import { useTranslations } from "../../hooks/use-translations";
|
|
11
|
-
import { css, dispatchInput, getRemainingSize, initializeInputDataset, mergeRefs } from "../../lib/dom";
|
|
12
|
-
import { safeRegex } from "../../lib/fns";
|
|
13
|
-
import { fzf } from "../../lib/fzf";
|
|
14
|
-
import { InputField } from "./input-field";
|
|
15
|
-
const Frag = (props) => <Fragment>{props.children}</Fragment>;
|
|
16
|
-
const transitionStyles = {
|
|
17
|
-
duration: 200,
|
|
18
|
-
initial: { transform: "scaleY(0)", opacity: 0.2 },
|
|
19
|
-
open: { transform: "scaleY(1)", opacity: 1 },
|
|
20
|
-
close: { transform: "scaleY(0)", opacity: 0 },
|
|
21
|
-
};
|
|
22
|
-
const emptyRef = [];
|
|
23
|
-
const List = forwardRef(function VirtualList(props, ref) {
|
|
24
|
-
return (<motion.ul {...props} ref={ref} className="overscroll-contain w-full rounded-lg h-96">
|
|
25
|
-
<AnimatePresence>{props.children}</AnimatePresence>
|
|
26
|
-
</motion.ul>);
|
|
27
|
-
});
|
|
28
|
-
const Item = forwardRef(function VirtualItem({ item, context, ...props }, ref) {
|
|
29
|
-
return <motion.li {...props} ref={ref} className="first:rounded-t-lg last:rounded-t-lg"/>;
|
|
30
|
-
});
|
|
31
|
-
const components = { List, Item };
|
|
32
|
-
const MIN_SIZE = 40;
|
|
33
|
-
export const Autocomplete = forwardRef(({ left, error, right, loading, options, container, rightLabel, interactive, emptyMessage, optionalText, labelClassName, feedback = null, hideLeft = false, required = false, dynamicOption = false, ...props }, externalRef) => {
|
|
34
|
-
const scroller = useRef(null);
|
|
35
|
-
const fieldset = useRef(null);
|
|
36
|
-
const virtuoso = useRef(null);
|
|
37
|
-
const defaults = props.value ?? props.defaultValue ?? "";
|
|
38
|
-
const translation = useTranslations();
|
|
39
|
-
const [h, setH] = useState(() => Math.min(320, MIN_SIZE * options.length));
|
|
40
|
-
const [open, setOpen] = useState(false);
|
|
41
|
-
const [shadow, setShadow] = useState("");
|
|
42
|
-
const [value, setValue] = useState(defaults);
|
|
43
|
-
const [label, setLabel] = useState(() => options.find((x) => x.value === defaults)?.label ?? defaults);
|
|
44
|
-
const [index, setIndex] = useState(null);
|
|
45
|
-
const listRef = useRef(emptyRef);
|
|
46
|
-
const removeScrollRef = useRemoveScroll(open, "block-only");
|
|
47
|
-
const innerOptions = dynamicOption && shadow !== ""
|
|
48
|
-
? [
|
|
49
|
-
{
|
|
50
|
-
value: shadow,
|
|
51
|
-
label: shadow,
|
|
52
|
-
"data-dynamic": "true",
|
|
53
|
-
},
|
|
54
|
-
...options,
|
|
55
|
-
]
|
|
56
|
-
: options;
|
|
57
|
-
const openDropdown = () => flushSync(() => setOpen(true));
|
|
58
|
-
const list = shadow
|
|
59
|
-
? fzf(innerOptions, "value", [{ key: "value", value: shadow }, { key: "label", value: shadow }])
|
|
60
|
-
: innerOptions;
|
|
61
|
-
const setClosed = () => {
|
|
62
|
-
setOpen(false);
|
|
63
|
-
setH(0);
|
|
64
|
-
};
|
|
65
|
-
const displayList = list.filter((x) => x.hidden !== true);
|
|
66
|
-
const pattern = dynamicOption
|
|
67
|
-
? undefined
|
|
68
|
-
: `^(${options.map((x) => `${safeRegex(x.value)}${x.label ? "|" + safeRegex(x.label) : ""}`).join("|")})$`;
|
|
69
|
-
const { x, y, strategy, refs, context, placement } = useFloating({
|
|
70
|
-
open,
|
|
71
|
-
transform: true,
|
|
72
|
-
onOpenChange: setOpen,
|
|
73
|
-
whileElementsMounted: autoUpdate,
|
|
74
|
-
middleware: [
|
|
75
|
-
offset(4),
|
|
76
|
-
autoPlacement({ allowedPlacements: ['top-start', 'bottom-start'], alignment: "start" }),
|
|
77
|
-
size({
|
|
78
|
-
padding: 10,
|
|
79
|
-
elementContext: "reference",
|
|
80
|
-
apply(args) {
|
|
81
|
-
const ul = args.elements.floating.querySelector("ul");
|
|
82
|
-
const fullSize = ul?.getBoundingClientRect().height || 0;
|
|
83
|
-
const DEFAULT_SIZE = getRemainingSize(refs.reference.current, window.innerHeight);
|
|
84
|
-
const maxH = Math.min(fullSize < MIN_SIZE ? DEFAULT_SIZE : fullSize, DEFAULT_SIZE, args.availableHeight);
|
|
85
|
-
const size = displayList.length === 0 ? MIN_SIZE : Math.min(maxH, DEFAULT_SIZE, fullSize);
|
|
86
|
-
const mw = `${fieldset.current.getBoundingClientRect().width}px`;
|
|
87
|
-
Object.assign(args.elements.floating.style, { width: mw, maxWidth: mw, height: size });
|
|
88
|
-
},
|
|
89
|
-
}),
|
|
90
|
-
],
|
|
91
|
-
});
|
|
92
|
-
const transitions = useTransitionStyles(context, transitionStyles);
|
|
93
|
-
const { getReferenceProps, getFloatingProps, getItemProps } = useInteractions([
|
|
94
|
-
useRole(context, { role: "listbox" }),
|
|
95
|
-
useDismiss(context),
|
|
96
|
-
useListNavigation(context, {
|
|
97
|
-
cols: 0,
|
|
98
|
-
listRef,
|
|
99
|
-
loop: true,
|
|
100
|
-
virtual: true,
|
|
101
|
-
allowEscape: true,
|
|
102
|
-
activeIndex: index,
|
|
103
|
-
selectedIndex: index,
|
|
104
|
-
focusItemOnOpen: "auto",
|
|
105
|
-
openOnArrowKeyDown: true,
|
|
106
|
-
scrollItemIntoView: true,
|
|
107
|
-
}),
|
|
108
|
-
]);
|
|
109
|
-
useEffect(() => {
|
|
110
|
-
if (props.value) {
|
|
111
|
-
const item = options.find((x) => x.value === props.value);
|
|
112
|
-
if (item) {
|
|
113
|
-
setLabel(item.label ?? item.value);
|
|
114
|
-
setValue(props.value);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}, [props.value, options.length]);
|
|
118
|
-
useEffect(() => {
|
|
119
|
-
if (!open)
|
|
120
|
-
return setH(0);
|
|
121
|
-
const inputRef = refs.reference;
|
|
122
|
-
if (inputRef.current === null)
|
|
123
|
-
return;
|
|
124
|
-
const s = getRemainingSize(inputRef.current, window.innerHeight);
|
|
125
|
-
setTimeout(() => setH(Math.min(s, displayList.length * MIN_SIZE)), 100);
|
|
126
|
-
}, [shadow, open, refs.reference, displayList.length]);
|
|
127
|
-
useEffect(() => {
|
|
128
|
-
const input = refs.reference.current;
|
|
129
|
-
if (!input)
|
|
130
|
-
return;
|
|
131
|
-
return initializeInputDataset(input);
|
|
132
|
-
}, []);
|
|
133
|
-
const onSelect = (opt, i) => {
|
|
134
|
-
setValue(opt.value);
|
|
135
|
-
const input = refs.reference.current;
|
|
136
|
-
if (!input)
|
|
137
|
-
return;
|
|
138
|
-
input?.setAttribute("data-value", opt.value);
|
|
139
|
-
input.value = opt.value;
|
|
140
|
-
const event = new Event("change", { bubbles: false, cancelable: true });
|
|
141
|
-
input.dispatchEvent(event);
|
|
142
|
-
if (props.onChange)
|
|
143
|
-
props.onChange(event);
|
|
144
|
-
setLabel(opt.label ?? "");
|
|
145
|
-
setClosed();
|
|
146
|
-
setShadow("");
|
|
147
|
-
setIndex(i);
|
|
148
|
-
};
|
|
149
|
-
const onChange = (event) => {
|
|
150
|
-
const value = event.target.value;
|
|
151
|
-
setShadow(value);
|
|
152
|
-
if (!open && value === "")
|
|
153
|
-
return setOpen(true);
|
|
154
|
-
event.target.name = props.name || "";
|
|
155
|
-
return value ? setOpen(true) : props.onChange?.(event);
|
|
156
|
-
};
|
|
157
|
-
const onCaretDownClick = () => {
|
|
158
|
-
openDropdown();
|
|
159
|
-
setShadow("");
|
|
160
|
-
refs.reference.current?.focus();
|
|
161
|
-
};
|
|
162
|
-
const onFocus = () => {
|
|
163
|
-
setIndex((prev) => (prev === null ? 0 : prev));
|
|
164
|
-
openDropdown();
|
|
165
|
-
setShadow("");
|
|
166
|
-
};
|
|
167
|
-
const onClose = () => {
|
|
168
|
-
refs.reference.current?.setAttribute("data-value", "");
|
|
169
|
-
setShadow("");
|
|
170
|
-
setValue("");
|
|
171
|
-
setLabel("");
|
|
172
|
-
dispatchInput(refs.reference.current);
|
|
173
|
-
setClosed();
|
|
174
|
-
};
|
|
175
|
-
const id = props.id || props.name;
|
|
176
|
-
const shadowId = `${id}-shadow`;
|
|
177
|
-
const isEmpty = displayList.length === 0;
|
|
178
|
-
const isTopPlacement = placement === "top" || placement === "top-start";
|
|
179
|
-
return (<InputField {...props} left={left} error={error} ref={fieldset} form={props.form} loading={loading} name={props.name} feedback={open && (isTopPlacement) ? props.title : feedback} hideLeft={hideLeft} required={required} title={props.title} container={container} rightLabel={rightLabel} interactive={interactive} id={shadowId} optionalText={optionalText} componentName="autocomplete" labelClassName={labelClassName} placeholder={props.placeholder} right={<span className="flex gap-0.5 items-center">
|
|
180
|
-
{right}
|
|
181
|
-
<button type="button" className="p-2 transition-colors md:p-1 link:text-primary" onClick={onCaretDownClick}>
|
|
182
|
-
<ChevronDown size={20}/>
|
|
183
|
-
<span className="sr-only">{translation.inputCaretDown}</span>
|
|
184
|
-
</button>
|
|
185
|
-
{value ? (<button type="button" onClick={onClose} className="p-2 transition-colors md:p-1 link:text-danger">
|
|
186
|
-
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
187
|
-
<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"/>
|
|
188
|
-
</svg>
|
|
189
|
-
</button>) : null}
|
|
190
|
-
</span>}>
|
|
191
|
-
<input data-shadow="true" {...getReferenceProps({
|
|
192
|
-
...props,
|
|
193
|
-
onFocus,
|
|
194
|
-
pattern,
|
|
195
|
-
onChange,
|
|
196
|
-
id: shadowId,
|
|
197
|
-
name: shadowId,
|
|
198
|
-
ref: refs.setReference,
|
|
199
|
-
onClick: (e) => e.currentTarget.focus(),
|
|
200
|
-
onKeyDown(event) {
|
|
201
|
-
if (event.key === "Escape") {
|
|
202
|
-
event.currentTarget.blur();
|
|
203
|
-
return setClosed();
|
|
204
|
-
}
|
|
205
|
-
if (!open)
|
|
206
|
-
return;
|
|
207
|
-
if (event.key === "ArrowDown") {
|
|
208
|
-
let next = Is.number(index) ? index + 1 : 0;
|
|
209
|
-
if (next > displayList.length - 1)
|
|
210
|
-
next = 0;
|
|
211
|
-
virtuoso.current?.scrollIntoView({ index: next });
|
|
212
|
-
return setIndex(next);
|
|
213
|
-
}
|
|
214
|
-
if (event.key === "ArrowUp") {
|
|
215
|
-
let next = Is.number(index) ? index - 1 : displayList.length - 1;
|
|
216
|
-
if (next < 0)
|
|
217
|
-
next = displayList.length - 1;
|
|
218
|
-
virtuoso.current?.scrollIntoView({ index: next });
|
|
219
|
-
return setIndex(next);
|
|
220
|
-
}
|
|
221
|
-
if (event.key === "Enter") {
|
|
222
|
-
if (index !== null && displayList[index]) {
|
|
223
|
-
event.preventDefault();
|
|
224
|
-
return onSelect(displayList[index], index);
|
|
225
|
-
}
|
|
226
|
-
if (displayList.length === 1) {
|
|
227
|
-
event.preventDefault();
|
|
228
|
-
return onSelect(displayList[0], 0);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
},
|
|
232
|
-
})} data-value={value} data-error={!!error} data-name={id} data-target={id} required={required} value={open ? shadow : options.length === 0 ? "" : label || value} aria-autocomplete="list" autoComplete="off" className={css("input placeholder-input-mask group h-input-height w-full flex-1", "rounded-md bg-transparent px-input-x py-input-y text-foreground", "outline-hidden transition-colors focus:ring-2 focus:ring-inset focus:ring-primary", "group-error:text-danger group-error:placeholder-input-mask-error", "text-base group-focus-within:border-primary group-hover:border-primary", props.className)}/>
|
|
233
|
-
<input id={id} name={id} type="hidden" data-origin={id} ref={externalRef} required={required} defaultValue={props.value || value || undefined}/>
|
|
234
|
-
<FloatingPortal preserveTabOrder>
|
|
235
|
-
{open ? (<FloatingFocusManager modal guards returnFocus={false} context={context} initialFocus={-1} visuallyHiddenDismiss>
|
|
236
|
-
<motion.div {...getFloatingProps({
|
|
237
|
-
ref: mergeRefs(removeScrollRef, refs.setFloating),
|
|
238
|
-
style: { ...transitions.styles, left: x, top: y ?? 0, position: strategy, height: "auto" },
|
|
239
|
-
})} initial={false} data-floating="true" animate={{ height: isEmpty ? "auto" : h }} className={css("overscroll-contain p-0 m-0 max-h-80 list-none rounded-t-lg rounded-b-lg border ease-in-out isolate z-floating border-floating-border bg-floating-background text-foreground shadow-floating", isTopPlacement ? "origin-[bottom_center]" : "origin-[top_center]")} onAnimationComplete={() => {
|
|
240
|
-
if (!open)
|
|
241
|
-
return setH(0);
|
|
242
|
-
const ul = refs.floating.current;
|
|
243
|
-
const li = ul.querySelectorAll("li").item(0);
|
|
244
|
-
const sum = (li ? li.getBoundingClientRect().height : MIN_SIZE) * displayList.length;
|
|
245
|
-
return flushSync(() => setH(sum + 2));
|
|
246
|
-
}}>
|
|
247
|
-
{isEmpty ? (<div role="option" className="w-full border-b border-tooltip-border">
|
|
248
|
-
<span className="flex justify-between p-2 w-full text-left text-disabled">
|
|
249
|
-
{emptyMessage || translation.autocompleteEmpty}
|
|
250
|
-
</span>
|
|
251
|
-
</div>) : null}
|
|
252
|
-
<Virtuoso overscan={40} ref={virtuoso} hidden={isEmpty} data={displayList} style={{ height: h }} defaultItemHeight={MIN_SIZE} components={components} scrollerRef={(e) => void (scroller.current = e)} className="overscroll-contain p-0 max-h-full rounded-lg border-floating bg-floating-background text-foreground" itemContent={(i, option) => {
|
|
253
|
-
const Label = option.Render ?? Frag;
|
|
254
|
-
const active = value === option.value || value === option.label;
|
|
255
|
-
const selected = index === i;
|
|
256
|
-
const children = option.label ?? option.value;
|
|
257
|
-
return (<button data-value={option.value} {...getItemProps({
|
|
258
|
-
ref: (node) => void (listRef.current[i] = node),
|
|
259
|
-
role: "option",
|
|
260
|
-
type: "button",
|
|
261
|
-
"aria-checked": active,
|
|
262
|
-
"aria-current": active,
|
|
263
|
-
"aria-selected": active,
|
|
264
|
-
"aria-busy": option.disabled,
|
|
265
|
-
onClick: () => onSelect(option, i),
|
|
266
|
-
className: `cursor-pointer min-h-10 hover:bg-floating-hover w-full p-2 text-left ${active ? "bg-primary-hover text-primary-foreground" : ""} ${selected ? "bg-floating-hover text-floating-foreground" : ""}`,
|
|
267
|
-
})}>
|
|
268
|
-
<Label {...props} label={option.label} value={option.value} children={children}/>
|
|
269
|
-
</button>);
|
|
270
|
-
}}/>
|
|
271
|
-
</motion.div>
|
|
272
|
-
</FloatingFocusManager>) : null}
|
|
273
|
-
</FloatingPortal>
|
|
274
|
-
</InputField>);
|
|
275
|
-
});
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import React, { forwardRef } from "react";
|
|
2
|
-
import { css } from "../../lib/dom";
|
|
3
|
-
export const Checkbox = forwardRef(({ children, asTask = false, labelClassName, loading, error, className = "", size, container, ...props }, ref) => {
|
|
4
|
-
const d = props.disabled || loading;
|
|
5
|
-
return (<label aria-disabled={d} data-disabled={d} data-task={asTask} data-component="checkbox" className={css("group flex w-fit flex-wrap items-center font-normal data-[disabled=true]:cursor-not-allowed", asTask ? "group-checkbox-checked:line-through" : "", container)}>
|
|
6
|
-
<input {...props} ref={ref} disabled={d} type="checkbox" data-task={asTask} className={css("form-checkbox mr-2 inline-block size-4 appearance-none rounded-sm border-card-border bg-origin-border text-primary focus:ring-primary disabled:opacity-70 group-aria-disabled:cursor-not-allowed", className)}/>
|
|
7
|
-
{children}
|
|
8
|
-
<span data-name="checkbox-label" className={css("min-w-full flex-1 text-xs text-danger empty:mt-0 empty:hidden", labelClassName)}>
|
|
9
|
-
{error}
|
|
10
|
-
</span>
|
|
11
|
-
</label>);
|
|
12
|
-
});
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { format, isValid, parse, startOfDay } from "date-fns";
|
|
3
|
-
import { CalendarIcon } from "lucide-react";
|
|
4
|
-
import React, { forwardRef, Fragment, useEffect, useId, useMemo, useState } from "react";
|
|
5
|
-
import { Is } from "sidekicker";
|
|
6
|
-
import { useLocale } from "../../hooks/use-locale";
|
|
7
|
-
import { useTranslations } from "../../hooks/use-translations";
|
|
8
|
-
import { Calendar } from "../display/calendar";
|
|
9
|
-
import { Dropdown } from "../floating/dropdown";
|
|
10
|
-
import { Input } from "./input";
|
|
11
|
-
const fixedDate = new Date(1970, 11, 31);
|
|
12
|
-
const parts = {
|
|
13
|
-
year: () => [/\d/, /\d/, /\d/, /\d/],
|
|
14
|
-
month: () => [/\d/, /\d/],
|
|
15
|
-
day: () => [/\d/, /\d/],
|
|
16
|
-
hour: () => [/\d/, /\d/],
|
|
17
|
-
minute: () => [/\d/, /\d/],
|
|
18
|
-
literal: (str) => str.split(""),
|
|
19
|
-
};
|
|
20
|
-
const placeholders = {
|
|
21
|
-
day: () => "dd",
|
|
22
|
-
hour: () => "HH",
|
|
23
|
-
month: () => "MM",
|
|
24
|
-
minute: () => "mm",
|
|
25
|
-
year: () => "yyyy",
|
|
26
|
-
literal: (str) => str,
|
|
27
|
-
};
|
|
28
|
-
const partValues = {
|
|
29
|
-
literal: (_, str) => str,
|
|
30
|
-
year: (date) => date.getFullYear().toString(),
|
|
31
|
-
day: (date) => date.getDate().toString().padStart(2, "0"),
|
|
32
|
-
hour: (date) => date.getHours().toString().padStart(2, "0"),
|
|
33
|
-
minute: (date) => date.getMinutes().toString().padStart(2, "0"),
|
|
34
|
-
month: (date) => (date.getMonth() + 1).toString().padStart(2, "0"),
|
|
35
|
-
};
|
|
36
|
-
const formatParts = (datetimeFormat, date) => {
|
|
37
|
-
try {
|
|
38
|
-
return datetimeFormat.formatToParts(date).map(x => {
|
|
39
|
-
if ((x.type === "literal" && x.value === ", ")) {
|
|
40
|
-
return { type: x.type, value: " " };
|
|
41
|
-
}
|
|
42
|
-
return x;
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
catch (e) {
|
|
46
|
-
return [];
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
|
-
const DATE_TIME_FORMAT = { day: "numeric", month: "numeric", year: "numeric", hour: "numeric", minute: "numeric" };
|
|
50
|
-
const DATE_FORMAT = { day: "numeric", month: "numeric", year: "numeric" };
|
|
51
|
-
export const DatePicker = forwardRef(({ date, locale: inputLocal, disabledDate, onChange, markToday, clickToClose, floating = true, type, ...props }, externalRef) => {
|
|
52
|
-
const locale = useLocale(inputLocal);
|
|
53
|
-
const labelId = useId();
|
|
54
|
-
const translation = useTranslations();
|
|
55
|
-
const datetimeFormat = useMemo(() => new Intl.DateTimeFormat(locale, type === "datetime" ? DATE_TIME_FORMAT : DATE_FORMAT), [locale, type]);
|
|
56
|
-
const [innerDate, setInnerDate] = useState(date || undefined);
|
|
57
|
-
const [open, setOpen] = useState(false);
|
|
58
|
-
const mask = formatParts(datetimeFormat, fixedDate).flatMap((x) => (Is.keyof(parts, x.type) ? parts[x.type](x.value) : []));
|
|
59
|
-
const placeholder = useMemo(() => {
|
|
60
|
-
return formatParts(datetimeFormat, fixedDate).reduce((acc, x) => acc + (Is.keyof(placeholders, x.type) ? placeholders[x.type](x.value) : ""), "");
|
|
61
|
-
}, [datetimeFormat]);
|
|
62
|
-
const isoDateEffect = date?.toISOString();
|
|
63
|
-
const [value, setValue] = useState(!innerDate
|
|
64
|
-
? ""
|
|
65
|
-
: formatParts(datetimeFormat, innerDate).reduce((acc, x) => acc + (Is.keyof(parts, x.type) ? partValues[x.type](innerDate, x.value) : ""), ""));
|
|
66
|
-
const onChangeDateInput = (e) => {
|
|
67
|
-
const v = e.target.value;
|
|
68
|
-
setValue(v);
|
|
69
|
-
if (mask.length === v.length) {
|
|
70
|
-
const matches = mask.every((x, i) => {
|
|
71
|
-
const c = v.charAt(i);
|
|
72
|
-
return typeof x === "string" ? c === x : x.test(c);
|
|
73
|
-
});
|
|
74
|
-
if (matches) {
|
|
75
|
-
const parsed = parse(v, placeholder, new Date());
|
|
76
|
-
const d = type === "datetime" ? parsed : startOfDay(parsed);
|
|
77
|
-
setInnerDate(d);
|
|
78
|
-
return onChange?.(d);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
setInnerDate(undefined);
|
|
82
|
-
return onChange?.(undefined);
|
|
83
|
-
};
|
|
84
|
-
useEffect(() => {
|
|
85
|
-
if (isValid(date)) {
|
|
86
|
-
setInnerDate(date);
|
|
87
|
-
setValue(format(date, placeholder));
|
|
88
|
-
}
|
|
89
|
-
}, [isoDateEffect, placeholder]);
|
|
90
|
-
const onChangeDate = (d) => {
|
|
91
|
-
setInnerDate(d);
|
|
92
|
-
onChange?.(d);
|
|
93
|
-
if (clickToClose)
|
|
94
|
-
setOpen(false);
|
|
95
|
-
if (d)
|
|
96
|
-
return setValue(format(d, placeholder));
|
|
97
|
-
return setValue("");
|
|
98
|
-
};
|
|
99
|
-
const validDate = isValid(innerDate);
|
|
100
|
-
const htmlValue = validDate ? innerDate.toISOString() : undefined;
|
|
101
|
-
const CalendarComponent = <Calendar {...props} type={type} locale={locale} changeOnlyOnClick markToday={markToday} onChange={onChangeDate} disabledDate={disabledDate} date={validDate ? innerDate : undefined}/>;
|
|
102
|
-
return (<Fragment>
|
|
103
|
-
<Input {...props} mask={mask} value={value} id={undefined} name={undefined} data-value={htmlValue} formNoValidate={!open} data-target={props.name} data-component="date-picker" onChange={onChangeDateInput} required={props.required ?? true} error={open ? undefined : props.error} placeholder={props.placeholder || translation.datepickerPlaceholder(placeholder)} right={floating ? <Fragment>
|
|
104
|
-
<input data-origin={props.name} defaultValue={htmlValue} form={props.form} hidden id={props.name} name={props.name} ref={externalRef} type="date"/>
|
|
105
|
-
<Dropdown open={open} onChange={setOpen} buttonProps={{ "aria-describedby": labelId }} trigger={<span aria-labelledby={labelId}>
|
|
106
|
-
<span id={labelId} className="sr-only">
|
|
107
|
-
{translation.datePickerCalendarButtonLabel}
|
|
108
|
-
</span>
|
|
109
|
-
<CalendarIcon />
|
|
110
|
-
</span>}>
|
|
111
|
-
{CalendarComponent}
|
|
112
|
-
</Dropdown>
|
|
113
|
-
</Fragment> : null}/>
|
|
114
|
-
</Fragment>);
|
|
115
|
-
});
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { AudioLinesIcon, FileIcon, FileJsonIcon, FileTextIcon, FileVideo2, FolderIcon, FolderOpenIcon, SheetIcon, XIcon, } from "lucide-react";
|
|
3
|
-
import prettyBytes from "pretty-bytes";
|
|
4
|
-
import React, { createContext, Fragment, useContext, useEffect, useState } from "react";
|
|
5
|
-
import { useDropzone } from "react-dropzone";
|
|
6
|
-
import { useTranslations } from "../../hooks/use-translations";
|
|
7
|
-
import { Modal } from "../floating/modal";
|
|
8
|
-
const Context = createContext([null, () => { }]);
|
|
9
|
-
const useFileManager = () => useContext(Context);
|
|
10
|
-
const getMimeType = (file) => {
|
|
11
|
-
if (file.type.startsWith("image/"))
|
|
12
|
-
return "img";
|
|
13
|
-
if (file.type.startsWith("audio/"))
|
|
14
|
-
return "audio";
|
|
15
|
-
if (file.type.startsWith("video/"))
|
|
16
|
-
return "video";
|
|
17
|
-
return file.type;
|
|
18
|
-
};
|
|
19
|
-
const extensionMap = {
|
|
20
|
-
csv: SheetIcon,
|
|
21
|
-
xls: SheetIcon,
|
|
22
|
-
mov: FileVideo2,
|
|
23
|
-
mp4: FileVideo2,
|
|
24
|
-
xlsx: SheetIcon,
|
|
25
|
-
pdf: FileTextIcon,
|
|
26
|
-
txt: FileTextIcon,
|
|
27
|
-
json: FileJsonIcon,
|
|
28
|
-
mp3: AudioLinesIcon,
|
|
29
|
-
};
|
|
30
|
-
const ItemViewer = (props) => {
|
|
31
|
-
const [, setManager] = useFileManager();
|
|
32
|
-
const [info, setInfo] = useState({ url: "", type: "", size: "" });
|
|
33
|
-
useEffect(() => {
|
|
34
|
-
const file = props.file;
|
|
35
|
-
const url = URL.createObjectURL(file);
|
|
36
|
-
setInfo({ url, type: getMimeType(file), size: prettyBytes(file.size) });
|
|
37
|
-
return () => URL.revokeObjectURL(url);
|
|
38
|
-
}, [props.file]);
|
|
39
|
-
const onViewFile = (e) => {
|
|
40
|
-
e.stopPropagation();
|
|
41
|
-
e.preventDefault();
|
|
42
|
-
setManager({ ...info, file: props.file });
|
|
43
|
-
};
|
|
44
|
-
const onDeleteFile = (e) => {
|
|
45
|
-
e.preventDefault();
|
|
46
|
-
e.stopPropagation();
|
|
47
|
-
props.onDeleteFile?.(props.file);
|
|
48
|
-
};
|
|
49
|
-
const Icon = extensionMap[props.file.name.split(".").at(-1)] ?? FileIcon;
|
|
50
|
-
const Element = info.type === "img" ? (<img src={info.url} className="object-contain w-full" alt={props.file.name}/>) : (<Icon strokeWidth={2} absoluteStrokeWidth size={48}/>);
|
|
51
|
-
return (<li className="flex flex-row gap-4 justify-between w-full border-b border-card-border last:border-b-transparent">
|
|
52
|
-
<div className="flex flex-col gap-4">
|
|
53
|
-
<div className="flex flex-row gap-4 items-center">
|
|
54
|
-
<button type="button" onClick={onViewFile} className="flex overflow-hidden justify-center items-center max-w-16 m-2 size-16">
|
|
55
|
-
{Element}
|
|
56
|
-
</button>
|
|
57
|
-
<div className="flex flex-col justify-start items-start text-left">
|
|
58
|
-
<span>{props.file.name}</span>
|
|
59
|
-
<span className="text-sm italic">{info.size}</span>
|
|
60
|
-
</div>
|
|
61
|
-
</div>
|
|
62
|
-
{props.File ? (<div className="flex-1 min-w-full">
|
|
63
|
-
<props.File file={props.file}/>
|
|
64
|
-
</div>) : null}
|
|
65
|
-
</div>
|
|
66
|
-
<div className="flex justify-start py-4 transition-colors duration-300 ease-linear align-start hover:text-danger-hover">
|
|
67
|
-
<button onClick={onDeleteFile} type="button" className="flex justify-center items-center size-6">
|
|
68
|
-
<XIcon size={16}/>
|
|
69
|
-
</button>
|
|
70
|
-
</div>
|
|
71
|
-
</li>);
|
|
72
|
-
};
|
|
73
|
-
const FilesList = (props) => (<ul className="space-y-8 w-full">
|
|
74
|
-
{props.files.map((file) => {
|
|
75
|
-
return <ItemViewer File={props.File} onDeleteFile={props.onDeleteFile} key={file.name} file={file}/>;
|
|
76
|
-
})}
|
|
77
|
-
</ul>);
|
|
78
|
-
const Idle = (props) => {
|
|
79
|
-
const t = useTranslations();
|
|
80
|
-
const Icon = props.dragging ? FolderOpenIcon : FolderIcon;
|
|
81
|
-
return (<div className="flex flex-col justify-center items-center">
|
|
82
|
-
<div className="flex flex-col gap-2 justify-center items-center">
|
|
83
|
-
<Icon className="text-primary" size={80}/>
|
|
84
|
-
</div>
|
|
85
|
-
<div className="flex flex-col gap-1 items-center my-4">
|
|
86
|
-
<p>{t.uploadIdle}</p>
|
|
87
|
-
<button className="underline text-primary" type="button">
|
|
88
|
-
{t.uploadIdleButton}
|
|
89
|
-
</button>
|
|
90
|
-
</div>
|
|
91
|
-
</div>);
|
|
92
|
-
};
|
|
93
|
-
const InteractiveArea = (props) => {
|
|
94
|
-
if (props.isDragActive)
|
|
95
|
-
return <Idle files={props.files} dragging/>;
|
|
96
|
-
if (props.files.length > 0) {
|
|
97
|
-
return <FilesList File={props.File} onDeleteFile={props.onDeleteFile} files={props.files}/>;
|
|
98
|
-
}
|
|
99
|
-
return <Fragment>{props.idle}</Fragment>;
|
|
100
|
-
};
|
|
101
|
-
const DefaultIdle = <Idle dragging={false}/>;
|
|
102
|
-
const FileViewer = (props) => {
|
|
103
|
-
const file = props.item.file;
|
|
104
|
-
const type = props.item.type;
|
|
105
|
-
return (<div className="flex flex-col gap-4">
|
|
106
|
-
<p className="text-lg font-medium">{props.item.file.name}</p>
|
|
107
|
-
<p className="text-base">{props.item.size}</p>
|
|
108
|
-
{type === "img" ? (<img className="container inline-block w-full max-w-96" src={props.item.url} alt={file.name}/>) : type === "video" ? (<video className="container block w-full max-w-96" src={props.item.url} controls muted/>) : type === "audio" ? (<figure>
|
|
109
|
-
<audio controls src={props.item.url}></audio>
|
|
110
|
-
</figure>) : null}
|
|
111
|
-
</div>);
|
|
112
|
-
};
|
|
113
|
-
export const FileUpload = ({ idle = DefaultIdle, onDeleteFile, File, onDrop, ...props }) => {
|
|
114
|
-
const t = useTranslations();
|
|
115
|
-
const state = useState(null);
|
|
116
|
-
const [files, setFiles] = useState([]);
|
|
117
|
-
const items = props.files ?? files;
|
|
118
|
-
const close = () => state[1](null);
|
|
119
|
-
const drop = (x) => {
|
|
120
|
-
onDrop?.(x);
|
|
121
|
-
setFiles((prev) => prev.concat(x));
|
|
122
|
-
};
|
|
123
|
-
const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop: drop });
|
|
124
|
-
return (<Context.Provider value={state}>
|
|
125
|
-
<Modal overlayClickClose title={t.uploadDialogTitle} ariaTitle={t.uploadDialogTitle} open={state[0] !== null} onChange={close}>
|
|
126
|
-
{state[0] ? <FileViewer item={state[0]}/> : null}
|
|
127
|
-
</Modal>
|
|
128
|
-
<div {...getRootProps()} data-active={items ? items.length > 0 : false} className="flex flex-col items-center justify-center rounded-lg border border-card-border p-6 text-foreground data-[active=true]:border-solid data-[active=false]:border-dashed data-[active=true]:border-transparent data-[active=true]:bg-card-background">
|
|
129
|
-
<input {...getInputProps(props)} name={props.name} id={props.name}/>
|
|
130
|
-
<InteractiveArea File={File} onDeleteFile={onDeleteFile} isDragActive={isDragActive} idle={idle} files={items}/>
|
|
131
|
-
</div>
|
|
132
|
-
</Context.Provider>);
|
|
133
|
-
};
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
const inputFields = ["INPUT", "SELECT"];
|
|
2
|
-
export const formReset = (form) => {
|
|
3
|
-
if (!form)
|
|
4
|
-
return;
|
|
5
|
-
const elements = Array.from(form.elements);
|
|
6
|
-
elements.forEach((field) => {
|
|
7
|
-
if (!inputFields.includes(field.tagName))
|
|
8
|
-
return;
|
|
9
|
-
if (field.tagName === "INPUT") {
|
|
10
|
-
field.value = field.defaultValue;
|
|
11
|
-
}
|
|
12
|
-
if (field.tagName === "SELECT") {
|
|
13
|
-
field.value = "";
|
|
14
|
-
}
|
|
15
|
-
field.setAttribute("data-initialized", "false");
|
|
16
|
-
});
|
|
17
|
-
};
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import React, { forwardRef, useEffect, useRef } from "react";
|
|
3
|
-
import { css, initializeInputDataset, mergeRefs } from "../../lib/dom";
|
|
4
|
-
import { InputField } from "./input-field";
|
|
5
|
-
export const createFreeText = (Element, elementName, defaultProps, register) => {
|
|
6
|
-
const FreeText = forwardRef(({ info, left, next, error, right, container, rightLabel, interactive, optionalText, type = "text", labelClassName, feedback = null, hideLeft = false, loading, ...props }, ref) => {
|
|
7
|
-
const Render = Element;
|
|
8
|
-
const id = props.id ?? props.name;
|
|
9
|
-
const inputRef = useRef(null);
|
|
10
|
-
useEffect(() => {
|
|
11
|
-
if (inputRef.current === null)
|
|
12
|
-
return;
|
|
13
|
-
const input = inputRef.current;
|
|
14
|
-
const focus = initializeInputDataset(inputRef.current);
|
|
15
|
-
const registered = register?.(input);
|
|
16
|
-
const goNextInputImpl = (e) => {
|
|
17
|
-
const event = e;
|
|
18
|
-
if (event.key === "Enter" && input.enterKeyHint === "next") {
|
|
19
|
-
const focusNext = input.getAttribute("data-next");
|
|
20
|
-
if (focusNext) {
|
|
21
|
-
const el = document.getElementById(focusNext);
|
|
22
|
-
if (el) {
|
|
23
|
-
el.focus();
|
|
24
|
-
return void event.preventDefault();
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
};
|
|
29
|
-
input.addEventListener("keydown", goNextInputImpl);
|
|
30
|
-
return () => {
|
|
31
|
-
registered?.();
|
|
32
|
-
focus();
|
|
33
|
-
input.removeEventListener("keydown", goNextInputImpl);
|
|
34
|
-
};
|
|
35
|
-
}, []);
|
|
36
|
-
return (<InputField {...defaultProps} info={info} left={left} error={error} right={right} loading={loading} form={props.form} name={props.name} feedback={feedback} hideLeft={hideLeft} title={props.title} container={css(container, defaultProps.container)} rightLabel={rightLabel} disabled={props.disabled} interactive={interactive} required={props.required} componentName={elementName} id={props.name || props.id} optionalText={optionalText} labelClassName={labelClassName} placeholder={props.placeholder}>
|
|
37
|
-
<Render {...defaultProps} {...props} id={id} name={id} type={type} data-next={next} aria-busy={props.disabled} aria-disabled={props.disabled} aria-readonly={props.readOnly} ref={mergeRefs(ref, inputRef)} className={css("input placeholder-input-mask group h-input-height w-full flex-1", "rounded-md bg-transparent px-input-x py-input-y text-base text-foreground", "outline-hidden transition-colors focus:ring-2 focus:ring-inset focus:ring-primary", "group-error:text-danger group-error:placeholder-input-mask-error", "resize-y group-focus-within:border-primary group-hover:border-primary", "disabled:cursor-not-allowed disabled:text-disabled", props.className)}/>
|
|
38
|
-
</InputField>);
|
|
39
|
-
});
|
|
40
|
-
return FreeText;
|
|
41
|
-
};
|