@facter/ds-core 1.10.0 → 1.12.0

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/index.mjs CHANGED
@@ -5,7 +5,7 @@ import { cva } from 'class-variance-authority';
5
5
  import { clsx } from 'clsx';
6
6
  import { twMerge } from 'tailwind-merge';
7
7
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
- import { ChevronDown, Check, Inbox, ChevronsLeft, ChevronLeft, ChevronRight, ChevronsRight, X, Circle, PinOff, Pin, ArrowDown, ArrowUp, ChevronsUpDown, FileText, FileSpreadsheet, Download, Rows4, Rows3, LayoutList, SlidersHorizontal, Info, AlertTriangle, XCircle, CheckCircle2, Building2, Star, ArrowRight, Search, User, LogOut, Menu, AlertCircle, TrendingUp, TrendingDown, Sun, Moon, Bell, MoreHorizontal, Settings } from 'lucide-react';
8
+ import { ChevronDown, Check, Inbox, ChevronsLeft, ChevronLeft, ChevronRight, ChevronsRight, X, Circle, PinOff, Pin, ArrowDown, ArrowUp, ChevronsUpDown, FileText, FileSpreadsheet, Download, Rows4, Rows3, LayoutList, SlidersHorizontal, Info, AlertTriangle, XCircle, CheckCircle2, Building2, Star, ArrowRight, Search, User, LogOut, Menu, Loader2, AlertCircle, TrendingUp, TrendingDown, Sun, Moon, Bell, MoreHorizontal, Settings } from 'lucide-react';
9
9
  import { AnimatePresence, motion } from 'framer-motion';
10
10
  import * as SelectPrimitive from '@radix-ui/react-select';
11
11
  import * as TabsPrimitive from '@radix-ui/react-tabs';
@@ -17,10 +17,10 @@ import { toast as toast$1, Toaster as Toaster$1 } from 'sonner';
17
17
  import * as SwitchPrimitives from '@radix-ui/react-switch';
18
18
  import { FormProvider, useFormContext, Controller } from 'react-hook-form';
19
19
  export { FormProvider, useFormContext } from 'react-hook-form';
20
+ import * as PopoverPrimitive from '@radix-ui/react-popover';
20
21
  import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
21
22
  import * as AvatarPrimitive from '@radix-ui/react-avatar';
22
23
  import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
23
- import * as PopoverPrimitive from '@radix-ui/react-popover';
24
24
  import * as TooltipPrimitive from '@radix-ui/react-tooltip';
25
25
  import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
26
26
  import * as SeparatorPrimitive from '@radix-ui/react-separator';
@@ -3208,6 +3208,22 @@ function FormInput({
3208
3208
  ) });
3209
3209
  }
3210
3210
  FormInput.displayName = "Form.Input";
3211
+ var Popover = PopoverPrimitive.Root;
3212
+ var PopoverTrigger = PopoverPrimitive.Trigger;
3213
+ var PopoverContent = React10.forwardRef(({ className, align = "center", sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx(
3214
+ PopoverPrimitive.Content,
3215
+ {
3216
+ ref,
3217
+ align,
3218
+ sideOffset,
3219
+ className: cn(
3220
+ "z-50 w-auto rounded-md border bg-popover p-4 text-popover-foreground shadow-lg outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
3221
+ className
3222
+ ),
3223
+ ...props
3224
+ }
3225
+ ) }));
3226
+ PopoverContent.displayName = PopoverPrimitive.Content.displayName;
3211
3227
  function FormSelect({
3212
3228
  name,
3213
3229
  label,
@@ -3221,7 +3237,13 @@ function FormSelect({
3221
3237
  hideError = false,
3222
3238
  selectSize = "default",
3223
3239
  emptyText = "Nenhuma op\xE7\xE3o dispon\xEDvel",
3224
- loading = false
3240
+ loading = false,
3241
+ variant = "default",
3242
+ searchable = false,
3243
+ onSearch,
3244
+ onLoadMore,
3245
+ hasMore,
3246
+ searchPlaceholder = "Buscar..."
3225
3247
  }) {
3226
3248
  const form = useFormContext();
3227
3249
  const fieldState = form.getFieldState(name, form.formState);
@@ -3232,7 +3254,26 @@ function FormSelect({
3232
3254
  control: form.control,
3233
3255
  name,
3234
3256
  render: ({ field }) => /* @__PURE__ */ jsxs("div", { className: cn("space-y-1", className), children: [
3235
- /* @__PURE__ */ jsx(
3257
+ variant === "card" ? /* @__PURE__ */ jsx(
3258
+ CardSelect,
3259
+ {
3260
+ options,
3261
+ value: field.value,
3262
+ onChange: (v) => field.onChange(v || void 0),
3263
+ disabled,
3264
+ label,
3265
+ required,
3266
+ error: !!error,
3267
+ placeholder,
3268
+ searchable,
3269
+ onSearch,
3270
+ onLoadMore,
3271
+ hasMore,
3272
+ loading,
3273
+ emptyText,
3274
+ searchPlaceholder
3275
+ }
3276
+ ) : /* @__PURE__ */ jsx(
3236
3277
  Select,
3237
3278
  {
3238
3279
  value: field.value ?? "",
@@ -3270,6 +3311,170 @@ function FormSelect({
3270
3311
  ) });
3271
3312
  }
3272
3313
  FormSelect.displayName = "Form.Select";
3314
+ function CardSelect({
3315
+ options,
3316
+ value,
3317
+ onChange,
3318
+ disabled,
3319
+ label,
3320
+ required,
3321
+ error,
3322
+ placeholder = "Selecione...",
3323
+ searchable,
3324
+ onSearch,
3325
+ onLoadMore,
3326
+ hasMore,
3327
+ loading,
3328
+ emptyText = "Nenhuma op\xE7\xE3o dispon\xEDvel",
3329
+ searchPlaceholder = "Buscar..."
3330
+ }) {
3331
+ const [open, setOpen] = React10.useState(false);
3332
+ const [search, setSearch] = React10.useState("");
3333
+ const selected = options.find((o) => o.value === value);
3334
+ const listRef = React10.useRef(null);
3335
+ const searchRef = React10.useRef(null);
3336
+ const filteredOptions = React10.useMemo(() => {
3337
+ if (!searchable || onSearch || !search) return options;
3338
+ const q = search.toLowerCase();
3339
+ return options.filter(
3340
+ (o) => o.label.toLowerCase().includes(q) || o.description?.toLowerCase().includes(q)
3341
+ );
3342
+ }, [options, search, searchable, onSearch]);
3343
+ const handleSearch = React10.useCallback(
3344
+ (value2) => {
3345
+ setSearch(value2);
3346
+ if (onSearch) onSearch(value2);
3347
+ },
3348
+ [onSearch]
3349
+ );
3350
+ React10.useEffect(() => {
3351
+ if (!open) {
3352
+ setSearch("");
3353
+ if (onSearch) onSearch("");
3354
+ }
3355
+ }, [open, onSearch]);
3356
+ React10.useEffect(() => {
3357
+ if (open && searchable) {
3358
+ setTimeout(() => searchRef.current?.focus(), 0);
3359
+ }
3360
+ }, [open, searchable]);
3361
+ const handleScroll = React10.useCallback(() => {
3362
+ if (!onLoadMore || !hasMore || loading) return;
3363
+ const el = listRef.current;
3364
+ if (!el) return;
3365
+ const { scrollTop, scrollHeight, clientHeight } = el;
3366
+ if (scrollHeight - scrollTop - clientHeight < 80) {
3367
+ onLoadMore();
3368
+ }
3369
+ }, [onLoadMore, hasMore, loading]);
3370
+ return /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: setOpen, modal: false, children: [
3371
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
3372
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, disabled, children: /* @__PURE__ */ jsxs(
3373
+ "button",
3374
+ {
3375
+ type: "button",
3376
+ className: cn(
3377
+ "flex w-full items-center justify-between rounded-md border-2 bg-background px-3 text-sm transition-colors",
3378
+ "focus:outline-none focus:border-primary",
3379
+ "disabled:cursor-not-allowed disabled:opacity-50",
3380
+ label ? "h-12 pt-4 pb-2" : "h-9 py-2",
3381
+ error ? "border-red-500" : "border-border",
3382
+ open && !error && "border-primary"
3383
+ ),
3384
+ children: [
3385
+ selected ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 truncate", children: [
3386
+ selected.icon && /* @__PURE__ */ jsx(selected.icon, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
3387
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: selected.label })
3388
+ ] }) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: placeholder }),
3389
+ /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4 shrink-0 opacity-50" })
3390
+ ]
3391
+ }
3392
+ ) }),
3393
+ label && /* @__PURE__ */ jsxs(
3394
+ "label",
3395
+ {
3396
+ className: cn(
3397
+ "absolute left-3 top-[-6px] text-xs font-medium bg-background px-1 pointer-events-none",
3398
+ error ? "text-red-500" : "text-foreground"
3399
+ ),
3400
+ children: [
3401
+ label,
3402
+ required && /* @__PURE__ */ jsx("span", { className: "text-red-500 ml-0.5", children: "*" })
3403
+ ]
3404
+ }
3405
+ )
3406
+ ] }),
3407
+ /* @__PURE__ */ jsxs(
3408
+ PopoverContent,
3409
+ {
3410
+ align: "start",
3411
+ className: "p-0 overflow-hidden",
3412
+ style: {
3413
+ width: "var(--radix-popover-trigger-width)",
3414
+ maxHeight: "var(--radix-popover-content-available-height)"
3415
+ },
3416
+ children: [
3417
+ searchable && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-3 py-2 border-b border-border", children: [
3418
+ /* @__PURE__ */ jsx(Search, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
3419
+ /* @__PURE__ */ jsx(
3420
+ "input",
3421
+ {
3422
+ ref: searchRef,
3423
+ type: "text",
3424
+ value: search,
3425
+ onChange: (e) => handleSearch(e.target.value),
3426
+ placeholder: searchPlaceholder,
3427
+ className: "flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground"
3428
+ }
3429
+ )
3430
+ ] }),
3431
+ /* @__PURE__ */ jsx(
3432
+ "div",
3433
+ {
3434
+ ref: listRef,
3435
+ className: "overflow-y-auto overscroll-contain",
3436
+ style: { maxHeight: searchable ? "calc(var(--radix-popover-content-available-height) - 45px)" : "var(--radix-popover-content-available-height)" },
3437
+ onScroll: handleScroll,
3438
+ children: /* @__PURE__ */ jsxs("div", { className: "divide-y divide-border/50 p-2", children: [
3439
+ filteredOptions.length === 0 && !loading ? /* @__PURE__ */ jsx("p", { className: "py-4 text-center text-sm text-muted-foreground", children: emptyText }) : filteredOptions.map((option) => {
3440
+ const isSelected = value === option.value;
3441
+ const isDisabled = option.disabled || disabled;
3442
+ return /* @__PURE__ */ jsxs(
3443
+ "button",
3444
+ {
3445
+ type: "button",
3446
+ disabled: isDisabled,
3447
+ onClick: () => {
3448
+ onChange(option.value);
3449
+ setOpen(false);
3450
+ },
3451
+ className: cn(
3452
+ "flex w-full items-center gap-3 p-3 text-left transition-all",
3453
+ "cursor-pointer hover:bg-accent",
3454
+ isSelected && "bg-primary/5",
3455
+ isDisabled && "cursor-not-allowed opacity-50 hover:bg-transparent"
3456
+ ),
3457
+ children: [
3458
+ option.icon && /* @__PURE__ */ jsx("div", { className: "flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-primary/10", children: /* @__PURE__ */ jsx(option.icon, { className: "h-5 w-5 text-primary" }) }),
3459
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
3460
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium leading-tight", children: option.label }),
3461
+ option.description && /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-xs leading-tight text-muted-foreground", children: option.description })
3462
+ ] }),
3463
+ isSelected && /* @__PURE__ */ jsx("span", { className: "flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-primary text-primary-foreground", children: /* @__PURE__ */ jsx(Check, { className: "h-3 w-3" }) })
3464
+ ]
3465
+ },
3466
+ option.value
3467
+ );
3468
+ }),
3469
+ loading && /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-3", children: /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin text-muted-foreground" }) })
3470
+ ] })
3471
+ }
3472
+ )
3473
+ ]
3474
+ }
3475
+ )
3476
+ ] });
3477
+ }
3273
3478
  function FormTextarea({
3274
3479
  name,
3275
3480
  label,
@@ -3831,22 +4036,6 @@ var DropdownMenuShortcut = ({
3831
4036
  );
3832
4037
  };
3833
4038
  DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
3834
- var Popover = PopoverPrimitive.Root;
3835
- var PopoverTrigger = PopoverPrimitive.Trigger;
3836
- var PopoverContent = React10.forwardRef(({ className, align = "center", sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx(
3837
- PopoverPrimitive.Content,
3838
- {
3839
- ref,
3840
- align,
3841
- sideOffset,
3842
- className: cn(
3843
- "z-50 w-auto rounded-md border bg-popover p-4 text-popover-foreground shadow-lg outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
3844
- className
3845
- ),
3846
- ...props
3847
- }
3848
- ) }));
3849
- PopoverContent.displayName = PopoverPrimitive.Content.displayName;
3850
4039
  var TooltipProvider = TooltipPrimitive.Provider;
3851
4040
  var TooltipRoot = TooltipPrimitive.Root;
3852
4041
  var TooltipTrigger = TooltipPrimitive.Trigger;