@g4rcez/components 2.0.32 → 2.0.34

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.
Files changed (184) hide show
  1. package/dist/components/core/{button.js → button.jsx} +5 -3
  2. package/dist/components/core/heading.d.ts +1 -1
  3. package/dist/components/core/heading.d.ts.map +1 -1
  4. package/dist/components/core/heading.jsx +4 -0
  5. package/dist/components/core/{polymorph.js → polymorph.jsx} +1 -2
  6. package/dist/components/core/render-on-view.d.ts +1 -1
  7. package/dist/components/core/render-on-view.d.ts.map +1 -1
  8. package/dist/components/core/{render-on-view.js → render-on-view.jsx} +4 -3
  9. package/dist/components/core/resizable.d.ts +1 -1
  10. package/dist/components/core/resizable.d.ts.map +1 -1
  11. package/dist/components/core/{resizable.js → resizable.jsx} +4 -3
  12. package/dist/components/core/{slot.js → slot.jsx} +8 -5
  13. package/dist/components/core/{tag.js → tag.jsx} +6 -3
  14. package/dist/components/core/typography.d.ts +5 -5
  15. package/dist/components/core/typography.d.ts.map +1 -1
  16. package/dist/components/core/typography.jsx +26 -0
  17. package/dist/components/display/alert.d.ts +1 -1
  18. package/dist/components/display/alert.d.ts.map +1 -1
  19. package/dist/components/display/alert.jsx +56 -0
  20. package/dist/components/display/calendar.d.ts +1 -1
  21. package/dist/components/display/calendar.d.ts.map +1 -1
  22. package/dist/components/display/{calendar.js → calendar.jsx} +83 -21
  23. package/dist/components/display/card.d.ts +3 -3
  24. package/dist/components/display/card.d.ts.map +1 -1
  25. package/dist/components/display/card.jsx +43 -0
  26. package/dist/components/display/empty.d.ts +1 -1
  27. package/dist/components/display/empty.d.ts.map +1 -1
  28. package/dist/components/display/empty.jsx +11 -0
  29. package/dist/components/display/list.d.ts +2 -2
  30. package/dist/components/display/list.d.ts.map +1 -1
  31. package/dist/components/display/list.jsx +81 -0
  32. package/dist/components/display/notifications.d.ts +1 -1
  33. package/dist/components/display/notifications.d.ts.map +1 -1
  34. package/dist/components/display/{notifications.js → notifications.jsx} +34 -10
  35. package/dist/components/display/progress.d.ts +1 -1
  36. package/dist/components/display/progress.d.ts.map +1 -1
  37. package/dist/components/display/progress.jsx +13 -0
  38. package/dist/components/display/shortcut.d.ts +1 -1
  39. package/dist/components/display/shortcut.d.ts.map +1 -1
  40. package/dist/components/display/shortcut.jsx +23 -0
  41. package/dist/components/display/skeleton.d.ts +4 -4
  42. package/dist/components/display/skeleton.d.ts.map +1 -1
  43. package/dist/components/display/skeleton.jsx +14 -0
  44. package/dist/components/display/spinner.d.ts +2 -2
  45. package/dist/components/display/spinner.d.ts.map +1 -1
  46. package/dist/components/display/spinner.jsx +7 -0
  47. package/dist/components/display/stats.d.ts +1 -1
  48. package/dist/components/display/stats.d.ts.map +1 -1
  49. package/dist/components/display/stats.jsx +20 -0
  50. package/dist/components/display/step.d.ts +2 -2
  51. package/dist/components/display/step.d.ts.map +1 -1
  52. package/dist/components/display/step.jsx +133 -0
  53. package/dist/components/display/tabs.d.ts +3 -3
  54. package/dist/components/display/tabs.d.ts.map +1 -1
  55. package/dist/components/display/{tabs.js → tabs.jsx} +21 -7
  56. package/dist/components/display/timeline.d.ts +6 -6
  57. package/dist/components/display/timeline.d.ts.map +1 -1
  58. package/dist/components/display/timeline.jsx +25 -0
  59. package/dist/components/floating/command-palette.d.ts +1 -1
  60. package/dist/components/floating/command-palette.d.ts.map +1 -1
  61. package/dist/components/floating/command-palette.jsx +187 -0
  62. package/dist/components/floating/dropdown.d.ts +1 -1
  63. package/dist/components/floating/dropdown.d.ts.map +1 -1
  64. package/dist/components/floating/{dropdown.js → dropdown.jsx} +17 -3
  65. package/dist/components/floating/expand.d.ts +1 -1
  66. package/dist/components/floating/expand.d.ts.map +1 -1
  67. package/dist/components/floating/{expand.js → expand.jsx} +14 -2
  68. package/dist/components/floating/{menu.js → menu.jsx} +52 -27
  69. package/dist/components/floating/modal.d.ts +10 -2
  70. package/dist/components/floating/modal.d.ts.map +1 -1
  71. package/dist/components/floating/modal.jsx +240 -0
  72. package/dist/components/floating/toolbar.d.ts +1 -1
  73. package/dist/components/floating/toolbar.d.ts.map +1 -1
  74. package/dist/components/floating/toolbar.jsx +5 -0
  75. package/dist/components/floating/{tooltip.js → tooltip.jsx} +12 -3
  76. package/dist/components/floating/wizard.d.ts +1 -1
  77. package/dist/components/floating/wizard.d.ts.map +1 -1
  78. package/dist/components/floating/{wizard.js → wizard.jsx} +64 -19
  79. package/dist/components/form/autocomplete.jsx +276 -0
  80. package/dist/components/form/checkbox.jsx +12 -0
  81. package/dist/components/form/{date-picker.js → date-picker.jsx} +15 -4
  82. package/dist/components/form/file-upload.d.ts +1 -1
  83. package/dist/components/form/file-upload.d.ts.map +1 -1
  84. package/dist/components/form/file-upload.jsx +133 -0
  85. package/dist/components/form/form.d.ts +1 -1
  86. package/dist/components/form/form.d.ts.map +1 -1
  87. package/dist/components/form/{form.js → form.jsx} +2 -2
  88. package/dist/components/form/{free-text.js → free-text.jsx} +4 -3
  89. package/dist/components/form/input-field.d.ts +1 -1
  90. package/dist/components/form/input-field.d.ts.map +1 -1
  91. package/dist/components/form/input-field.jsx +54 -0
  92. package/dist/components/form/multi-select.jsx +328 -0
  93. package/dist/components/form/radiobox.d.ts +1 -1
  94. package/dist/components/form/radiobox.d.ts.map +1 -1
  95. package/dist/components/form/radiobox.jsx +6 -0
  96. package/dist/components/form/select.jsx +42 -0
  97. package/dist/components/form/slider.d.ts +1 -1
  98. package/dist/components/form/slider.d.ts.map +1 -1
  99. package/dist/components/form/{slider.js → slider.jsx} +11 -3
  100. package/dist/components/form/switch.jsx +46 -0
  101. package/dist/components/form/task-list.d.ts +1 -1
  102. package/dist/components/form/task-list.d.ts.map +1 -1
  103. package/dist/components/form/{task-list.js → task-list.jsx} +1 -2
  104. package/dist/components/form/transfer-list.d.ts +1 -1
  105. package/dist/components/form/transfer-list.d.ts.map +1 -1
  106. package/dist/components/form/transfer-list.jsx +39 -0
  107. package/dist/components/table/filter.d.ts +2 -2
  108. package/dist/components/table/filter.d.ts.map +1 -1
  109. package/dist/components/table/{filter.js → filter.jsx} +35 -7
  110. package/dist/components/table/group.d.ts +1 -1
  111. package/dist/components/table/group.d.ts.map +1 -1
  112. package/dist/components/table/group.jsx +68 -0
  113. package/dist/components/table/index.d.ts +1 -1
  114. package/dist/components/table/index.d.ts.map +1 -1
  115. package/dist/components/table/{index.js → index.jsx} +10 -2
  116. package/dist/components/table/inner-table.d.ts +1 -1
  117. package/dist/components/table/inner-table.d.ts.map +1 -1
  118. package/dist/components/table/{inner-table.js → inner-table.jsx} +21 -9
  119. package/dist/components/table/metadata.d.ts +1 -1
  120. package/dist/components/table/metadata.d.ts.map +1 -1
  121. package/dist/components/table/metadata.jsx +37 -0
  122. package/dist/components/table/pagination.d.ts +1 -1
  123. package/dist/components/table/pagination.d.ts.map +1 -1
  124. package/dist/components/table/pagination.jsx +73 -0
  125. package/dist/components/table/row.d.ts +1 -1
  126. package/dist/components/table/row.d.ts.map +1 -1
  127. package/dist/components/table/row.jsx +58 -0
  128. package/dist/components/table/sort.d.ts +2 -2
  129. package/dist/components/table/sort.d.ts.map +1 -1
  130. package/dist/components/table/{sort.js → sort.jsx} +32 -6
  131. package/dist/components/table/thead.d.ts +2 -1
  132. package/dist/components/table/thead.d.ts.map +1 -1
  133. package/dist/components/table/thead.jsx +103 -0
  134. package/dist/config/default-translations.d.ts +1 -1
  135. package/dist/config/{default-translations.js → default-translations.jsx} +5 -3
  136. package/dist/flow/flow.d.ts +1 -1
  137. package/dist/flow/flow.d.ts.map +1 -1
  138. package/dist/flow/flow.jsx +111 -0
  139. package/dist/hooks/use-components-provider.d.ts +2 -2
  140. package/dist/hooks/use-components-provider.d.ts.map +1 -1
  141. package/dist/hooks/{use-components-provider.js → use-components-provider.jsx} +2 -3
  142. package/dist/hooks/use-translations.d.ts +1 -1
  143. package/dist/index.css +1 -1
  144. package/dist/index.js.map +1 -1
  145. package/dist/index.mjs +13463 -16070
  146. package/dist/index.mjs.map +1 -1
  147. package/dist/index.umd.js +14 -31
  148. package/dist/index.umd.js.map +1 -1
  149. package/package.json +1 -1
  150. package/dist/components/core/heading.js +0 -5
  151. package/dist/components/core/typography.js +0 -10
  152. package/dist/components/display/alert.js +0 -37
  153. package/dist/components/display/card.js +0 -18
  154. package/dist/components/display/empty.js +0 -8
  155. package/dist/components/display/list.js +0 -32
  156. package/dist/components/display/progress.js +0 -9
  157. package/dist/components/display/shortcut.js +0 -19
  158. package/dist/components/display/skeleton.js +0 -13
  159. package/dist/components/display/spinner.js +0 -6
  160. package/dist/components/display/stats.js +0 -5
  161. package/dist/components/display/step.js +0 -122
  162. package/dist/components/display/timeline.js +0 -14
  163. package/dist/components/floating/command-palette.js +0 -155
  164. package/dist/components/floating/modal.js +0 -195
  165. package/dist/components/floating/toolbar.js +0 -4
  166. package/dist/components/form/autocomplete.js +0 -247
  167. package/dist/components/form/checkbox.js +0 -7
  168. package/dist/components/form/file-upload.js +0 -88
  169. package/dist/components/form/input-field.js +0 -17
  170. package/dist/components/form/multi-select.js +0 -277
  171. package/dist/components/form/radiobox.js +0 -3
  172. package/dist/components/form/select.js +0 -31
  173. package/dist/components/form/switch.js +0 -36
  174. package/dist/components/form/transfer-list.js +0 -22
  175. package/dist/components/table/group.js +0 -41
  176. package/dist/components/table/metadata.js +0 -10
  177. package/dist/components/table/pagination.js +0 -42
  178. package/dist/components/table/row.js +0 -47
  179. package/dist/components/table/thead.js +0 -71
  180. package/dist/flow/flow.js +0 -77
  181. /package/dist/components/form/{formReset.js → formReset.jsx} +0 -0
  182. /package/dist/components/form/{input.js → input.jsx} +0 -0
  183. /package/dist/components/form/{textarea.js → textarea.jsx} +0 -0
  184. /package/dist/components/table/{table.context.js → table.context.jsx} +0 -0
@@ -0,0 +1,276 @@
1
+ "use client";
2
+ import { 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: 300,
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">
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 } = useFloating({
70
+ open,
71
+ transform: true,
72
+ onOpenChange: setOpen,
73
+ placement: "bottom-start",
74
+ whileElementsMounted: autoUpdate,
75
+ middleware: [
76
+ offset(4),
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
+ return (<InputField {...props} left={left} error={error} ref={fieldset} form={props.form} loading={loading} name={props.name} feedback={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">
179
+ {right}
180
+ <button type="button" className="p-2 transition-colors md:p-1 link:text-primary" onClick={onCaretDownClick}>
181
+ <ChevronDown size={20}/>
182
+ <span className="sr-only">{translation.inputCaretDown}</span>
183
+ </button>
184
+ {value ? (<button type="button" onClick={onClose} className="p-2 transition-colors md:p-1 link:text-danger">
185
+ <svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
186
+ <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"/>
187
+ </svg>
188
+ </button>) : null}
189
+ </span>}>
190
+ <input data-shadow="true" {...getReferenceProps({
191
+ ...props,
192
+ onFocus,
193
+ pattern,
194
+ onChange,
195
+ id: shadowId,
196
+ name: shadowId,
197
+ ref: refs.setReference,
198
+ onClick: (e) => e.currentTarget.focus(),
199
+ onKeyDown(event) {
200
+ if (event.key === "Escape") {
201
+ event.currentTarget.blur();
202
+ return setClosed();
203
+ }
204
+ if (!open)
205
+ return;
206
+ if (event.key === "ArrowDown") {
207
+ let next = Is.number(index) ? index + 1 : 0;
208
+ if (next > displayList.length - 1)
209
+ next = 0;
210
+ virtuoso.current?.scrollIntoView({ index: next });
211
+ return setIndex(next);
212
+ }
213
+ if (event.key === "ArrowUp") {
214
+ let next = Is.number(index) ? index - 1 : displayList.length - 1;
215
+ if (next < 0)
216
+ next = displayList.length - 1;
217
+ virtuoso.current?.scrollIntoView({ index: next });
218
+ return setIndex(next);
219
+ }
220
+ if (event.key === "Enter") {
221
+ if (index !== null && displayList[index]) {
222
+ event.preventDefault();
223
+ return onSelect(displayList[index], index);
224
+ }
225
+ if (displayList.length === 1) {
226
+ event.preventDefault();
227
+ return onSelect(displayList[0], 0);
228
+ }
229
+ }
230
+ },
231
+ })} 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-none 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)}/>
232
+ <input id={id} name={id} type="hidden" data-origin={id} ref={externalRef} required={required} defaultValue={props.value || value || undefined}/>
233
+ <FloatingPortal preserveTabOrder>
234
+ {open ? (<FloatingFocusManager modal guards returnFocus={false} context={context} initialFocus={-1} visuallyHiddenDismiss>
235
+ <motion.div {...getFloatingProps({
236
+ ref: mergeRefs(removeScrollRef, refs.setFloating),
237
+ style: { ...transitions.styles, left: x, top: y ?? 0, position: strategy, height: "auto" },
238
+ })} initial={false} data-floating="true" animate={{ height: isEmpty ? "auto" : h }} className="overscroll-contain p-0 m-0 max-h-80 list-none rounded-t-lg rounded-b-lg border ease-in-out isolate z-floating origin-[top_center] border-floating-border bg-floating-background text-foreground shadow-floating" onAnimationComplete={() => {
239
+ if (!open)
240
+ return setH(0);
241
+ const ul = refs.floating.current;
242
+ const li = ul.querySelectorAll("li").item(0);
243
+ const sum = (li ? li.getBoundingClientRect().height : MIN_SIZE) * displayList.length;
244
+ return flushSync(() => setH(sum + 10));
245
+ }}>
246
+ {isEmpty ? (<div role="option" className="w-full border-b border-tooltip-border">
247
+ <span className="flex justify-between p-2 w-full text-left text-disabled">
248
+ {emptyMessage || translation.autocompleteEmpty}
249
+ </span>
250
+ </div>) : null}
251
+ <Virtuoso overscan={40} ref={virtuoso} hidden={isEmpty} data={displayList}
252
+ // style={{ height: h - 10 }}
253
+ 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) => {
254
+ const Label = option.Render ?? Frag;
255
+ const active = value === option.value || value === option.label;
256
+ const selected = index === i;
257
+ const children = option.label ?? option.value;
258
+ return (<button data-value={option.value} {...getItemProps({
259
+ ref: (node) => void (listRef.current[i] = node),
260
+ role: "option",
261
+ type: "button",
262
+ "aria-checked": active,
263
+ "aria-current": active,
264
+ "aria-selected": active,
265
+ "aria-busy": option.disabled,
266
+ onClick: () => onSelect(option, i),
267
+ 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" : ""}`,
268
+ })}>
269
+ <Label {...props} label={option.label} value={option.value} children={children}/>
270
+ </button>);
271
+ }}/>
272
+ </motion.div>
273
+ </FloatingFocusManager>) : null}
274
+ </FloatingPortal>
275
+ </InputField>);
276
+ });
@@ -0,0 +1,12 @@
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 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,8 +1,7 @@
1
1
  "use client";
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
2
  import { format, isValid, parse, startOfDay } from "date-fns";
4
3
  import { CalendarIcon } from "lucide-react";
5
- import { forwardRef, Fragment, useEffect, useId, useMemo, useState } from "react";
4
+ import React, { forwardRef, Fragment, useEffect, useId, useMemo, useState } from "react";
6
5
  import { Is } from "sidekicker";
7
6
  import { useLocale } from "../../hooks/use-locale";
8
7
  import { useTranslations } from "../../hooks/use-translations";
@@ -99,6 +98,18 @@ export const DatePicker = forwardRef(({ date, locale: inputLocal, disabledDate,
99
98
  };
100
99
  const validDate = isValid(innerDate);
101
100
  const htmlValue = validDate ? innerDate.toISOString() : undefined;
102
- const CalendarComponent = _jsx(Calendar, { ...props, type: type, locale: locale, changeOnlyOnClick: true, markToday: markToday, onChange: onChangeDate, disabledDate: disabledDate, date: validDate ? innerDate : undefined });
103
- return (_jsx(Fragment, { children: _jsx(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 ? _jsxs(Fragment, { children: [_jsx("input", { "data-origin": props.name, defaultValue: htmlValue, form: props.form, hidden: true, id: props.name, name: props.name, ref: externalRef, type: "date" }), _jsx(Dropdown, { open: open, onChange: setOpen, buttonProps: { "aria-describedby": labelId }, trigger: _jsxs("span", { "aria-labelledby": labelId, children: [_jsx("span", { id: labelId, className: "sr-only", children: translation.datePickerCalendarButtonLabel }), _jsx(CalendarIcon, {})] }), children: CalendarComponent })] }) : null }) }));
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>);
104
115
  });
@@ -10,6 +10,6 @@ type Props = Override<React.ComponentProps<"input">, DropzoneProps> & {
10
10
  onDrop?: (file: File[]) => void;
11
11
  onDeleteFile?: (file: File) => void;
12
12
  };
13
- export declare const FileUpload: ({ idle, onDeleteFile, File, onDrop, ...props }: Props) => import("react/jsx-runtime").JSX.Element;
13
+ export declare const FileUpload: ({ idle, onDeleteFile, File, onDrop, ...props }: Props) => React.JSX.Element;
14
14
  export {};
15
15
  //# sourceMappingURL=file-upload.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"file-upload.d.ts","sourceRoot":"","sources":["../../../src/components/form/file-upload.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAmE,MAAM,OAAO,CAAC;AACxF,OAAO,EAAE,aAAa,EAAe,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAatC,KAAK,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,aAAa,CAAC,GAAG;IAClE,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC;IACf,IAAI,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC;IAC1B,IAAI,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC;QAAE,IAAI,EAAE,IAAI,CAAA;KAAE,CAAC,CAAC;IAChC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,IAAI,CAAC;IAChC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;CACvC,CAAC;AAgJF,eAAO,MAAM,UAAU,GAAI,gDAA8D,KAAK,4CA8B7F,CAAC"}
1
+ {"version":3,"file":"file-upload.d.ts","sourceRoot":"","sources":["../../../src/components/form/file-upload.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAmE,MAAM,OAAO,CAAC;AACxF,OAAO,EAAE,aAAa,EAAe,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAatC,KAAK,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,aAAa,CAAC,GAAG;IAClE,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC;IACf,IAAI,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC;IAC1B,IAAI,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC;QAAE,IAAI,EAAE,IAAI,CAAA;KAAE,CAAC,CAAC;IAChC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,IAAI,CAAC;IAChC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;CACvC,CAAC;AAgJF,eAAO,MAAM,UAAU,GAAI,gDAA8D,KAAK,sBA8B7F,CAAC"}
@@ -0,0 +1,133 @@
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,3 +1,3 @@
1
1
  import React from "react";
2
- export declare const Form: (props: React.ComponentProps<"form">) => import("react/jsx-runtime").JSX.Element;
2
+ export declare const Form: (props: React.ComponentProps<"form">) => React.JSX.Element;
3
3
  //# sourceMappingURL=form.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"form.d.ts","sourceRoot":"","sources":["../../../src/components/form/form.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,eAAO,MAAM,IAAI,GAAI,OAAO,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,4CAOvD,CAAC"}
1
+ {"version":3,"file":"form.d.ts","sourceRoot":"","sources":["../../../src/components/form/form.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,eAAO,MAAM,IAAI,GAAI,OAAO,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,sBAOvD,CAAC"}
@@ -1,10 +1,10 @@
1
1
  "use client";
2
- import { jsx as _jsx } from "react/jsx-runtime";
2
+ import React from "react";
3
3
  export const Form = (props) => {
4
4
  const onSubmit = (e) => {
5
5
  e.persist();
6
6
  e.preventDefault();
7
7
  props.onSubmit?.(e);
8
8
  };
9
- return _jsx("form", { ...props, onSubmit: onSubmit });
9
+ return <form {...props} onSubmit={onSubmit}/>;
10
10
  };
@@ -1,6 +1,5 @@
1
1
  "use client";
2
- import { jsx as _jsx } from "react/jsx-runtime";
3
- import { forwardRef, useEffect, useRef } from "react";
2
+ import React, { forwardRef, useEffect, useRef } from "react";
4
3
  import { css, initializeInputDataset, mergeRefs } from "../../lib/dom";
5
4
  import { InputField } from "./input-field";
6
5
  export const createFreeText = (Element, elementName, defaultProps, register) => {
@@ -34,7 +33,9 @@ export const createFreeText = (Element, elementName, defaultProps, register) =>
34
33
  input.removeEventListener("keydown", goNextInputImpl);
35
34
  };
36
35
  }, []);
37
- return (_jsx(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, children: _jsx(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-none 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) }) }));
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-none 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>);
38
39
  });
39
40
  return FreeText;
40
41
  };
@@ -10,7 +10,7 @@ export type FeedbackProps = React.PropsWithChildren<Partial<{
10
10
  placeholder: string;
11
11
  reportStatus: boolean;
12
12
  }>>;
13
- export declare const InputFeedback: ({ reportStatus, id, hideLeft, className, info, children, title }: FeedbackProps) => import("react/jsx-runtime").JSX.Element;
13
+ export declare const InputFeedback: ({ reportStatus, id, hideLeft, className, info, children, title }: FeedbackProps) => React.JSX.Element;
14
14
  export type InputFieldProps<T extends "input" | "select" | "textarea"> = PolymorphicProps<Partial<Override<FeedbackProps, {
15
15
  loading: boolean;
16
16
  componentName: string;
@@ -1 +1 @@
1
- {"version":3,"file":"input-field.d.ts","sourceRoot":"","sources":["../../../src/components/form/input-field.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAAwB,KAAK,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAI5E,OAAO,EAAE,KAAK,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAG1D,MAAM,MAAM,aAAa,GAAG,KAAK,CAAC,iBAAiB,CAC/C,OAAO,CAAC;IACJ,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,KAAK,CAAC;IACZ,KAAK,EAAE,KAAK,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;CACzB,CAAC,CACL,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,kEAA0E,aAAa,4CA8CpH,CAAC;AAEF,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,OAAO,GAAG,QAAQ,GAAG,UAAU,IAAI,gBAAgB,CACrF,OAAO,CACH,QAAQ,CACJ,aAAa,EACb;IACI,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,KAAK,CAAC;IACZ,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,KAAK,CAAC;IACZ,QAAQ,EAAE,KAAK,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,KAAK,CAAC;IACb,UAAU,EAAE,KAAK,CAAC;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACvB,CACJ,CACJ,EACD,CAAC,CACJ,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,CAAC,CAAC,SAAS,OAAO,GAAG,QAAQ,GAAG,UAAU,EAAE,KAAK,EAAE,iBAAiB,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,YA6EpH,CAAC"}
1
+ {"version":3,"file":"input-field.d.ts","sourceRoot":"","sources":["../../../src/components/form/input-field.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAAwB,KAAK,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAI5E,OAAO,EAAE,KAAK,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAG1D,MAAM,MAAM,aAAa,GAAG,KAAK,CAAC,iBAAiB,CAC/C,OAAO,CAAC;IACJ,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,KAAK,CAAC;IACZ,KAAK,EAAE,KAAK,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;CACzB,CAAC,CACL,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,kEAA0E,aAAa,sBA8CpH,CAAC;AAEF,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,OAAO,GAAG,QAAQ,GAAG,UAAU,IAAI,gBAAgB,CACrF,OAAO,CACH,QAAQ,CACJ,aAAa,EACb;IACI,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,KAAK,CAAC;IACZ,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,KAAK,CAAC;IACZ,QAAQ,EAAE,KAAK,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,KAAK,CAAC;IACb,UAAU,EAAE,KAAK,CAAC;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACvB,CACJ,CACJ,EACD,CAAC,CACJ,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,CAAC,CAAC,SAAS,OAAO,GAAG,QAAQ,GAAG,UAAU,EAAE,KAAK,EAAE,iBAAiB,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,YA6EpH,CAAC"}
@@ -0,0 +1,54 @@
1
+ "use client";
2
+ import { CheckCircle, InfoIcon, XCircle } from "lucide-react";
3
+ import React, { forwardRef, Fragment } from "react";
4
+ import { useTranslations } from "../../hooks/use-translations";
5
+ import { useTweaks } from "../../hooks/use-tweaks";
6
+ import { css } from "../../lib/dom";
7
+ import { Tooltip } from "../floating/tooltip";
8
+ export const InputFeedback = ({ reportStatus, id, hideLeft = false, className, info, children, title }) => (<span className={css("w-full justify-between", hideLeft && children === null ? "hidden" : "flex", className)}>
9
+ {hideLeft ? null : (<span className="flex items-center gap-1 transition-colors group-focus-within:text-primary group-hover:text-primary group-disabled:text-disabled group-error:text-danger">
10
+ {title}
11
+ {reportStatus || info ? (<span className="flex items-center justify-center gap-1">
12
+ {info ? (<Tooltip as="button" type="button" aria-label={typeof info === "string" ? info : undefined} aria-describedby={typeof info === "string" ? undefined : id ? `tooltip-info-content-${id}` : undefined} title={<span className="cursor-help">
13
+ <InfoIcon className="aspect-square size-3" aria-hidden="true" size={16} strokeWidth={1} absoluteStrokeWidth/>
14
+ </span>}>
15
+ <div id={id ? `tooltip-info-content-${id}` : undefined} className="w-full max-w-48 whitespace-break-spaces break-words">{info}</div>
16
+ </Tooltip>) : null}
17
+ {reportStatus ? (<span className="flex h-3 min-w-6 items-center">
18
+ <CheckCircle className="hidden aspect-square size-3 opacity-0 transition-opacity group-assert:block group-assert:text-success group-assert:opacity-100" aria-hidden="true" size={16} strokeWidth={1} absoluteStrokeWidth/>
19
+ <XCircle className="hidden aspect-square size-3 opacity-0 transition-opacity group-error:block group-error:opacity-100" aria-hidden="true" size={16} strokeWidth={1} absoluteStrokeWidth/>
20
+ </span>) : null}
21
+ </span>) : null}
22
+ </span>)}
23
+ {children}
24
+ </span>);
25
+ export const InputField = forwardRef(({ optionalText: _optionalText, left, rightLabel, container, feedback, interactive, right, info, children, error, form, id, labelClassName = "", name, title, componentName, placeholder, hideLeft = false, required, disabled, reportStatus, }, ref) => {
26
+ const tweaks = useTweaks();
27
+ const reportStatusDefault = reportStatus !== undefined ? reportStatus : tweaks.input.iconFeedback;
28
+ const ID = id ?? name;
29
+ const translation = useTranslations();
30
+ const optionalText = _optionalText ?? translation.inputOptionalLabel;
31
+ return (<fieldset ref={ref} form={form} disabled={disabled} data-error={!!error} aria-disabled={disabled} data-component={componentName} data-interactive={!!interactive} className={css("group flex min-h-0 max-w-full min-w-0 flex-col items-start", container)}>
32
+ <label form={form} htmlFor={ID} className="text-field-label max-w-full w-full relative inline-flex cursor-text flex-row flex-wrap justify-between gap-1 text-sm transition-colors empty:hidden group-disabled:cursor-not-allowed group-error:text-danger">
33
+ <InputFeedback info={info} hideLeft={hideLeft} reportStatus={reportStatusDefault} title={title} placeholder={placeholder}>
34
+ {optionalText || rightLabel ? (<Fragment>
35
+ {!required ? (<span aria-disabled={disabled} className="transition-colors text-opacity-70 aria-disabled:text-disabled group-focus-within:text-primary group-hover:text-primary">
36
+ {optionalText}
37
+ </span>) : null}
38
+ {rightLabel ? <Fragment>{rightLabel}</Fragment> : null}
39
+ </Fragment>) : null}
40
+ </InputFeedback>
41
+ <div className={`group relative 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-hover:border-primary group-disabled:border-disabled group-error:border-danger ${labelClassName}`}>
42
+ {left ? <span className="flex flex-nowrap gap-1 whitespace-nowrap pl-2">{left}</span> : null}
43
+ {children}
44
+ {right ? <span className="flex flex-nowrap gap-2 whitespace-nowrap pr-2">{right}</span> : null}
45
+ </div>
46
+ </label>
47
+ <p className="mt-input-gap hidden whitespace-pre-wrap text-wrap text-xs empty:mt-0 empty:hidden group-has-[input:not(:focus):invalid[data-initialized=true]]:flex group-error:flex group-error:text-danger">
48
+ {error}
49
+ </p>
50
+ <p className="mt-input-gap text-xs empty:mt-0 empty:hidden group-has-[input:not(:focus):valid[data-initialized=true]]:block group-assert:block group-error:hidden">
51
+ {feedback}
52
+ </p>
53
+ </fieldset>);
54
+ });