@seedgrid/fe-components 0.2.8 → 0.2.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,349 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import React from "react";
4
+ import { ChevronDown } from "lucide-react";
5
+ import { SgInputText } from "./SgInputText";
6
+ import { t, useComponentsI18n } from "../i18n";
7
+ const TYPEAHEAD_RESET_MS = 700;
8
+ function defaultMapItem(raw) {
9
+ if (typeof raw === "string" || typeof raw === "number") {
10
+ return {
11
+ id: String(raw),
12
+ label: String(raw)
13
+ };
14
+ }
15
+ if (raw && typeof raw === "object") {
16
+ const asRecord = raw;
17
+ const id = asRecord.id ?? asRecord.value ?? asRecord.key ?? asRecord.label;
18
+ const label = asRecord.label ?? asRecord.name ?? asRecord.description ?? asRecord.title ?? id;
19
+ return {
20
+ id: typeof id === "string" || typeof id === "number" ? id : String(id ?? ""),
21
+ label: String(label ?? "")
22
+ };
23
+ }
24
+ return {
25
+ id: String(raw ?? ""),
26
+ label: String(raw ?? "")
27
+ };
28
+ }
29
+ function idEquals(left, right) {
30
+ if (right == null)
31
+ return false;
32
+ return String(left) === String(right);
33
+ }
34
+ function findTypeAheadMatchIndex(entries, query, startIndex) {
35
+ const normalized = query.trim().toLowerCase();
36
+ if (!normalized)
37
+ return -1;
38
+ if (!entries.length)
39
+ return -1;
40
+ for (let offset = 1; offset <= entries.length; offset += 1) {
41
+ const index = (startIndex + offset + entries.length) % entries.length;
42
+ const entry = entries[index];
43
+ if (!entry || entry.item.disabled)
44
+ continue;
45
+ const label = entry.item.label?.toLowerCase() ?? "";
46
+ if (label.startsWith(normalized))
47
+ return index;
48
+ }
49
+ return -1;
50
+ }
51
+ export function SgCombobox(props) {
52
+ const { source, mapItem: mapItemProp, value, onValueChange, grouped, groupped, loadingText: loadingTextProp, emptyText: emptyTextProp, openOnFocus = false, onSelect, renderItem, renderGroupHeader, renderFooter, itemTooltip, inputProps, enabled, ...rest } = props;
53
+ const i18n = useComponentsI18n();
54
+ const loadingText = loadingTextProp ?? t(i18n, "components.autocomplete.loading");
55
+ const emptyText = emptyTextProp ?? t(i18n, "components.autocomplete.empty");
56
+ const effectiveGrouped = grouped ?? groupped ?? false;
57
+ const isControlled = value !== undefined;
58
+ const wrapperRef = React.useRef(null);
59
+ const ignoreBlurRef = React.useRef(false);
60
+ const requestIdRef = React.useRef(0);
61
+ const typeAheadRef = React.useRef({
62
+ buffer: "",
63
+ ts: 0
64
+ });
65
+ const [open, setOpen] = React.useState(false);
66
+ const [loading, setLoading] = React.useState(false);
67
+ const [entries, setEntries] = React.useState([]);
68
+ const [activeIndex, setActiveIndex] = React.useState(-1);
69
+ const [internalValue, setInternalValue] = React.useState(null);
70
+ const [lastSelectedLabel, setLastSelectedLabel] = React.useState("");
71
+ const resolvedValue = isControlled ? value : internalValue;
72
+ const isDisabled = enabled === false;
73
+ const mapItem = React.useCallback((raw) => {
74
+ if (mapItemProp)
75
+ return mapItemProp(raw);
76
+ return defaultMapItem(raw);
77
+ }, [mapItemProp]);
78
+ const refreshFromSource = React.useCallback(async () => {
79
+ if (Array.isArray(source)) {
80
+ const nextEntries = source.map((raw) => ({
81
+ item: mapItem(raw),
82
+ raw
83
+ }));
84
+ setEntries(nextEntries);
85
+ return nextEntries;
86
+ }
87
+ setLoading(true);
88
+ const currentRequest = ++requestIdRef.current;
89
+ try {
90
+ const result = source("");
91
+ const data = typeof result?.then === "function"
92
+ ? await result
93
+ : result;
94
+ if (currentRequest !== requestIdRef.current)
95
+ return [];
96
+ const nextEntries = data.map((raw) => ({
97
+ item: mapItem(raw),
98
+ raw
99
+ }));
100
+ setEntries(nextEntries);
101
+ return nextEntries;
102
+ }
103
+ catch {
104
+ if (currentRequest !== requestIdRef.current)
105
+ return [];
106
+ setEntries([]);
107
+ return [];
108
+ }
109
+ finally {
110
+ if (currentRequest === requestIdRef.current) {
111
+ setLoading(false);
112
+ }
113
+ }
114
+ }, [mapItem, source]);
115
+ React.useEffect(() => {
116
+ if (!Array.isArray(source))
117
+ return;
118
+ setEntries(source.map((raw) => ({
119
+ item: mapItem(raw),
120
+ raw
121
+ })));
122
+ }, [mapItem, source]);
123
+ const selectedEntry = React.useMemo(() => entries.find((entry) => idEquals(entry.item.id, resolvedValue)), [entries, resolvedValue]);
124
+ React.useEffect(() => {
125
+ if (resolvedValue == null || resolvedValue === "") {
126
+ if (lastSelectedLabel !== "") {
127
+ setLastSelectedLabel("");
128
+ }
129
+ return;
130
+ }
131
+ if (selectedEntry) {
132
+ if (lastSelectedLabel !== selectedEntry.item.label) {
133
+ setLastSelectedLabel(selectedEntry.item.label);
134
+ }
135
+ return;
136
+ }
137
+ if (lastSelectedLabel !== "") {
138
+ setLastSelectedLabel("");
139
+ }
140
+ void refreshFromSource();
141
+ }, [lastSelectedLabel, refreshFromSource, resolvedValue, selectedEntry]);
142
+ const displayedValue = resolvedValue == null || resolvedValue === ""
143
+ ? ""
144
+ : selectedEntry?.item.label ?? lastSelectedLabel;
145
+ const setSelectedValue = React.useCallback((nextValue) => {
146
+ if (!isControlled) {
147
+ setInternalValue(nextValue);
148
+ }
149
+ onValueChange?.(nextValue);
150
+ }, [isControlled, onValueChange]);
151
+ const closeDropdown = React.useCallback(() => {
152
+ setOpen(false);
153
+ setActiveIndex(-1);
154
+ typeAheadRef.current = { buffer: "", ts: 0 };
155
+ }, []);
156
+ const openDropdown = React.useCallback(() => {
157
+ if (isDisabled)
158
+ return;
159
+ setOpen(true);
160
+ void refreshFromSource();
161
+ }, [isDisabled, refreshFromSource]);
162
+ const selectIndex = React.useCallback((index) => {
163
+ const entry = entries[index];
164
+ if (!entry || entry.item.disabled)
165
+ return;
166
+ setSelectedValue(entry.item.id);
167
+ setLastSelectedLabel(entry.item.label);
168
+ onSelect?.(entry.raw);
169
+ closeDropdown();
170
+ }, [closeDropdown, entries, onSelect, setSelectedValue]);
171
+ const handleTypeAhead = React.useCallback(async (typedKey) => {
172
+ const key = typedKey.toLowerCase();
173
+ const now = Date.now();
174
+ const previous = typeAheadRef.current;
175
+ const buffer = now - previous.ts > TYPEAHEAD_RESET_MS
176
+ ? key
177
+ : `${previous.buffer}${key}`;
178
+ typeAheadRef.current = {
179
+ buffer,
180
+ ts: now
181
+ };
182
+ let availableEntries = entries;
183
+ if (!availableEntries.length) {
184
+ availableEntries = await refreshFromSource();
185
+ }
186
+ if (!availableEntries.length)
187
+ return;
188
+ const selectedIndex = availableEntries.findIndex((entry) => idEquals(entry.item.id, resolvedValue));
189
+ const baseIndex = selectedIndex >= 0 ? selectedIndex : activeIndex;
190
+ let nextIndex = findTypeAheadMatchIndex(availableEntries, buffer, baseIndex);
191
+ if (nextIndex < 0 && buffer.length > 1) {
192
+ typeAheadRef.current = { buffer: key, ts: now };
193
+ nextIndex = findTypeAheadMatchIndex(availableEntries, key, baseIndex);
194
+ }
195
+ if (nextIndex < 0)
196
+ return;
197
+ const nextEntry = availableEntries[nextIndex];
198
+ if (!nextEntry || nextEntry.item.disabled)
199
+ return;
200
+ setSelectedValue(nextEntry.item.id);
201
+ setLastSelectedLabel(nextEntry.item.label);
202
+ onSelect?.(nextEntry.raw);
203
+ if (open) {
204
+ setActiveIndex(nextIndex);
205
+ }
206
+ }, [activeIndex, entries, onSelect, open, refreshFromSource, resolvedValue, setSelectedValue]);
207
+ React.useEffect(() => {
208
+ if (!open)
209
+ return;
210
+ const handleOutside = (event) => {
211
+ if (wrapperRef.current?.contains(event.target))
212
+ return;
213
+ closeDropdown();
214
+ };
215
+ document.addEventListener("mousedown", handleOutside);
216
+ return () => document.removeEventListener("mousedown", handleOutside);
217
+ }, [closeDropdown, open]);
218
+ React.useEffect(() => {
219
+ if (!open)
220
+ return;
221
+ if (!entries.length) {
222
+ setActiveIndex(-1);
223
+ return;
224
+ }
225
+ const selectedIndex = entries.findIndex((entry) => idEquals(entry.item.id, resolvedValue));
226
+ if (selectedIndex >= 0) {
227
+ setActiveIndex(selectedIndex);
228
+ return;
229
+ }
230
+ setActiveIndex(0);
231
+ }, [entries, open, resolvedValue]);
232
+ const groupedEntries = React.useMemo(() => {
233
+ if (!effectiveGrouped)
234
+ return null;
235
+ const map = new Map();
236
+ entries.forEach((entry, index) => {
237
+ const groupKey = entry.item.group ?? "";
238
+ if (!map.has(groupKey))
239
+ map.set(groupKey, []);
240
+ map.get(groupKey)?.push({ entry, index });
241
+ });
242
+ return Array.from(map.entries()).map(([group, list]) => ({
243
+ group,
244
+ list
245
+ }));
246
+ }, [effectiveGrouped, entries]);
247
+ const dropdownButton = (_jsx("button", { type: "button", className: "text-foreground/60 hover:text-foreground", onMouseDown: (event) => {
248
+ event.preventDefault();
249
+ ignoreBlurRef.current = true;
250
+ }, onClick: () => {
251
+ if (open) {
252
+ closeDropdown();
253
+ return;
254
+ }
255
+ openDropdown();
256
+ }, "aria-label": "Abrir lista", children: _jsx(ChevronDown, { size: 16 }) }));
257
+ return (_jsxs("div", { className: "relative", ref: wrapperRef, children: [_jsx(SgInputText, { ...rest, enabled: enabled, clearButton: false, readOnly: true, iconButtons: [dropdownButton], inputProps: {
258
+ ...inputProps,
259
+ value: displayedValue,
260
+ onMouseDown: (event) => {
261
+ inputProps?.onMouseDown?.(event);
262
+ if (isDisabled)
263
+ return;
264
+ if (!open) {
265
+ openDropdown();
266
+ }
267
+ },
268
+ onFocus: (event) => {
269
+ inputProps?.onFocus?.(event);
270
+ if (openOnFocus) {
271
+ openDropdown();
272
+ }
273
+ },
274
+ onBlur: (event) => {
275
+ inputProps?.onBlur?.(event);
276
+ if (event.relatedTarget && wrapperRef.current?.contains(event.relatedTarget)) {
277
+ return;
278
+ }
279
+ if (ignoreBlurRef.current) {
280
+ setTimeout(() => {
281
+ ignoreBlurRef.current = false;
282
+ }, 0);
283
+ return;
284
+ }
285
+ closeDropdown();
286
+ },
287
+ onKeyDown: (event) => {
288
+ inputProps?.onKeyDown?.(event);
289
+ if (event.defaultPrevented)
290
+ return;
291
+ if (isDisabled)
292
+ return;
293
+ if (!event.ctrlKey && !event.altKey && !event.metaKey && event.key.length === 1 && event.key !== " ") {
294
+ event.preventDefault();
295
+ void handleTypeAhead(event.key);
296
+ return;
297
+ }
298
+ if (event.key === "Tab") {
299
+ closeDropdown();
300
+ return;
301
+ }
302
+ if (event.key === "Escape") {
303
+ event.preventDefault();
304
+ closeDropdown();
305
+ return;
306
+ }
307
+ if (event.key === "ArrowDown") {
308
+ event.preventDefault();
309
+ if (!open) {
310
+ openDropdown();
311
+ return;
312
+ }
313
+ setActiveIndex((prev) => Math.min(prev + 1, entries.length - 1));
314
+ return;
315
+ }
316
+ if (event.key === "ArrowUp") {
317
+ event.preventDefault();
318
+ if (!open) {
319
+ openDropdown();
320
+ return;
321
+ }
322
+ setActiveIndex((prev) => Math.max(prev - 1, 0));
323
+ return;
324
+ }
325
+ if (event.key === "Enter" || event.key === " ") {
326
+ event.preventDefault();
327
+ if (!open) {
328
+ openDropdown();
329
+ return;
330
+ }
331
+ if (activeIndex >= 0) {
332
+ selectIndex(activeIndex);
333
+ }
334
+ }
335
+ }
336
+ } }), open && !isDisabled ? (_jsxs("div", { className: "absolute left-0 right-0 z-30 mt-1 overflow-hidden rounded-md border border-border bg-white shadow-lg", children: [_jsx("div", { className: "max-h-64 overflow-auto", children: loading ? (_jsx("div", { className: "px-3 py-2 text-sm text-muted-foreground", children: loadingText })) : entries.length === 0 ? (_jsx("div", { className: "px-3 py-2 text-sm text-muted-foreground", children: emptyText })) : groupedEntries ? (groupedEntries.map(({ group, list }) => (_jsxs("div", { className: "border-b border-border last:border-b-0", children: [_jsx("div", { className: "px-3 py-1 text-xs font-semibold text-muted-foreground", children: renderGroupHeader ? renderGroupHeader(group) : group || " " }), list.map(({ entry, index }) => {
337
+ const isActive = activeIndex === index;
338
+ return (_jsxs("div", { className: `group relative cursor-pointer px-3 py-2 text-sm ${isActive ? "bg-muted/60" : ""} ${entry.item.disabled ? "cursor-not-allowed opacity-50" : "hover:bg-muted/40"}`, onMouseEnter: () => setActiveIndex(index), onMouseDown: (event) => {
339
+ event.preventDefault();
340
+ ignoreBlurRef.current = true;
341
+ }, onClick: () => selectIndex(index), children: [renderItem ? renderItem(entry.item, isActive) : entry.item.label, itemTooltip ? (_jsx("div", { className: "pointer-events-none absolute left-full top-1/2 z-20 ml-2 -translate-y-1/2 rounded border border-border bg-white px-2 py-1 text-xs shadow-md opacity-0 transition-opacity group-hover:opacity-100", children: itemTooltip(entry.item) })) : null] }, entry.item.id));
342
+ })] }, group || "default")))) : (entries.map((entry, index) => {
343
+ const isActive = activeIndex === index;
344
+ return (_jsxs("div", { className: `group relative cursor-pointer px-3 py-2 text-sm ${isActive ? "bg-muted/60" : ""} ${entry.item.disabled ? "cursor-not-allowed opacity-50" : "hover:bg-muted/40"}`, onMouseEnter: () => setActiveIndex(index), onMouseDown: (event) => {
345
+ event.preventDefault();
346
+ ignoreBlurRef.current = true;
347
+ }, onClick: () => selectIndex(index), children: [renderItem ? renderItem(entry.item, isActive) : entry.item.label, itemTooltip ? (_jsx("div", { className: "pointer-events-none absolute left-full top-1/2 z-20 ml-2 -translate-y-1/2 rounded border border-border bg-white px-2 py-1 text-xs shadow-md opacity-0 transition-opacity group-hover:opacity-100", children: itemTooltip(entry.item) })) : null] }, entry.item.id));
348
+ })) }), renderFooter ? (_jsx("div", { className: "border-t border-border bg-white px-3 py-2", children: renderFooter("", entries.length > 0) })) : null] })) : null] }));
349
+ }
@@ -0,0 +1,74 @@
1
+ import React from "react";
2
+ import type { FieldValues, RegisterOptions, UseFormRegister } from "react-hook-form";
3
+ import type { RhfFieldProps } from "../rhf";
4
+ export type SgInputOTPRef = {
5
+ focus: (slotIndex?: number) => void;
6
+ clear: () => void;
7
+ getRawValue: () => string;
8
+ getMaskedValue: () => string;
9
+ };
10
+ export type SgInputOTPProps = {
11
+ id: string;
12
+ label?: string;
13
+ hintText?: string;
14
+ mask?: string;
15
+ value?: string;
16
+ defaultValue?: string;
17
+ error?: string;
18
+ className?: string;
19
+ groupClassName?: string;
20
+ slotClassName?: string;
21
+ separatorClassName?: string;
22
+ inputProps?: Omit<React.InputHTMLAttributes<HTMLInputElement>, "value" | "defaultValue"> & {
23
+ ref?: React.Ref<HTMLInputElement>;
24
+ };
25
+ width?: number | string;
26
+ enabled?: boolean;
27
+ readOnly?: boolean;
28
+ required?: boolean;
29
+ requiredMessage?: string;
30
+ validation?: (rawValue: string, maskedValue: string) => string | null;
31
+ validateOnBlur?: boolean;
32
+ onValidation?: (message: string | null) => void;
33
+ onChange?: (maskedValue: string) => void;
34
+ onRawChange?: (rawValue: string) => void;
35
+ onComplete?: (value: string) => void;
36
+ onEnter?: () => void;
37
+ onExit?: () => void;
38
+ onClear?: () => void;
39
+ register?: UseFormRegister<FieldValues>;
40
+ rules?: RegisterOptions<FieldValues>;
41
+ } & RhfFieldProps;
42
+ export declare const SgInputOTP: React.ForwardRefExoticComponent<{
43
+ id: string;
44
+ label?: string;
45
+ hintText?: string;
46
+ mask?: string;
47
+ value?: string;
48
+ defaultValue?: string;
49
+ error?: string;
50
+ className?: string;
51
+ groupClassName?: string;
52
+ slotClassName?: string;
53
+ separatorClassName?: string;
54
+ inputProps?: Omit<React.InputHTMLAttributes<HTMLInputElement>, "value" | "defaultValue"> & {
55
+ ref?: React.Ref<HTMLInputElement>;
56
+ };
57
+ width?: number | string;
58
+ enabled?: boolean;
59
+ readOnly?: boolean;
60
+ required?: boolean;
61
+ requiredMessage?: string;
62
+ validation?: (rawValue: string, maskedValue: string) => string | null;
63
+ validateOnBlur?: boolean;
64
+ onValidation?: (message: string | null) => void;
65
+ onChange?: (maskedValue: string) => void;
66
+ onRawChange?: (rawValue: string) => void;
67
+ onComplete?: (value: string) => void;
68
+ onEnter?: () => void;
69
+ onExit?: () => void;
70
+ onClear?: () => void;
71
+ register?: UseFormRegister<FieldValues>;
72
+ rules?: RegisterOptions<FieldValues>;
73
+ } & RhfFieldProps & React.RefAttributes<SgInputOTPRef>>;
74
+ //# sourceMappingURL=SgInputOTP.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SgInputOTP.d.ts","sourceRoot":"","sources":["../../src/inputs/SgInputOTP.tsx"],"names":[],"mappings":"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"}