@fayz-ai/ui 0.23.0 → 0.24.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.
@@ -7,7 +7,7 @@ import React15__default, { useState, useRef, useEffect, useMemo, useCallback } f
7
7
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
8
8
  import { cva } from 'class-variance-authority';
9
9
  import * as DialogPrimitive from '@radix-ui/react-dialog';
10
- import { X, ChevronDown, ChevronUp, Check, ArrowLeft, MoreHorizontal, Search, ChevronLeft, ChevronRight, ImageIcon, RefreshCw, Clock, Plus, Download, Calendar, Loader2, CalendarDays, SlidersHorizontal } from 'lucide-react';
10
+ import { X, ChevronDown, ChevronUp, Check, ArrowLeft, MoreHorizontal, Search, ChevronsLeft, ChevronLeft, ChevronRight, ChevronsRight, ImageIcon, RefreshCw, Clock, Plus, Download, Calendar, Loader2, CalendarDays, SlidersHorizontal } from 'lucide-react';
11
11
  import * as SelectPrimitive from '@radix-ui/react-select';
12
12
  import { Toaster } from 'sonner';
13
13
  export { toast } from 'sonner';
@@ -564,6 +564,9 @@ function ChevronPager({ page, pageSize, total, onPageChange, noun }) {
564
564
  const from = total === 0 ? 0 : (page - 1) * pageSize + 1;
565
565
  const to = Math.min(page * pageSize, total);
566
566
  const button = "flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground disabled:pointer-events-none disabled:opacity-40";
567
+ const JANELA = 5;
568
+ const inicio = Math.max(1, Math.min(page - Math.floor(JANELA / 2), pages - JANELA + 1));
569
+ const numeros = Array.from({ length: Math.min(JANELA, pages) }, (_, i) => inicio + i);
567
570
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2 border-t border-border px-3 py-2", children: [
568
571
  /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
569
572
  from.toLocaleString(),
@@ -574,6 +577,17 @@ function ChevronPager({ page, pageSize, total, onPageChange, noun }) {
574
577
  noun ? ` ${noun}` : ""
575
578
  ] }),
576
579
  pages > 1 && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
580
+ pages > JANELA && /* @__PURE__ */ jsx(
581
+ "button",
582
+ {
583
+ type: "button",
584
+ "aria-label": "Primeira p\xE1gina",
585
+ className: button,
586
+ disabled: page <= 1,
587
+ onClick: () => onPageChange(1),
588
+ children: /* @__PURE__ */ jsx(ChevronsLeft, { className: "h-4 w-4" })
589
+ }
590
+ ),
577
591
  /* @__PURE__ */ jsx(
578
592
  "button",
579
593
  {
@@ -585,11 +599,18 @@ function ChevronPager({ page, pageSize, total, onPageChange, noun }) {
585
599
  children: /* @__PURE__ */ jsx(ChevronLeft, { className: "h-4 w-4" })
586
600
  }
587
601
  ),
588
- /* @__PURE__ */ jsxs("span", { className: "px-1 text-xs tabular-nums text-muted-foreground", children: [
589
- page.toLocaleString(),
590
- " / ",
591
- pages.toLocaleString()
592
- ] }),
602
+ numeros.map((n) => /* @__PURE__ */ jsx(
603
+ "button",
604
+ {
605
+ type: "button",
606
+ "aria-label": `P\xE1gina ${n}`,
607
+ "aria-current": n === page ? "page" : void 0,
608
+ onClick: () => onPageChange(n),
609
+ className: n === page ? "flex h-7 min-w-7 items-center justify-center rounded-md bg-primary px-1.5 text-xs font-medium tabular-nums text-primary-foreground" : "flex h-7 min-w-7 items-center justify-center rounded-md px-1.5 text-xs tabular-nums text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
610
+ children: n.toLocaleString()
611
+ },
612
+ n
613
+ )),
593
614
  /* @__PURE__ */ jsx(
594
615
  "button",
595
616
  {
@@ -600,6 +621,17 @@ function ChevronPager({ page, pageSize, total, onPageChange, noun }) {
600
621
  onClick: () => onPageChange(page + 1),
601
622
  children: /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4" })
602
623
  }
624
+ ),
625
+ pages > JANELA && /* @__PURE__ */ jsx(
626
+ "button",
627
+ {
628
+ type: "button",
629
+ "aria-label": "\xDAltima p\xE1gina",
630
+ className: button,
631
+ disabled: page >= pages,
632
+ onClick: () => onPageChange(pages),
633
+ children: /* @__PURE__ */ jsx(ChevronsRight, { className: "h-4 w-4" })
634
+ }
603
635
  )
604
636
  ] })
605
637
  ] });
@@ -1124,6 +1156,7 @@ function ListView({
1124
1156
  search: controlledSearch,
1125
1157
  onSearchChange,
1126
1158
  searchDebounce = 300,
1159
+ searchOwnRow,
1127
1160
  tags,
1128
1161
  allTagLabel = "All",
1129
1162
  tagsLabel,
@@ -1142,8 +1175,11 @@ function ListView({
1142
1175
  page = 1,
1143
1176
  pageSize = 25,
1144
1177
  rangeOfLabel = "of",
1178
+ firstPageLabel = "First page",
1145
1179
  prevPageLabel = "Previous page",
1146
1180
  nextPageLabel = "Next page",
1181
+ lastPageLabel = "Last page",
1182
+ pageLabel = "Page",
1147
1183
  onPageChange,
1148
1184
  toolbar,
1149
1185
  filters,
@@ -1171,6 +1207,9 @@ function ListView({
1171
1207
  }, [onSearchChange, searchDebounce]);
1172
1208
  const totalItems = total ?? data.length;
1173
1209
  const totalPages = Math.max(1, Math.ceil(totalItems / pageSize));
1210
+ const PAGE_WINDOW = 5;
1211
+ const windowStart = Math.max(1, Math.min(page - Math.floor(PAGE_WINDOW / 2), totalPages - PAGE_WINDOW + 1));
1212
+ const pageWindow = Array.from({ length: Math.min(PAGE_WINDOW, totalPages) }, (_, i) => windowStart + i);
1174
1213
  const showPagination = onPageChange && totalItems > pageSize;
1175
1214
  const showSearch = !!onSearchChange;
1176
1215
  const showTags = tags && tags.length > 0 && onTagChange;
@@ -1219,7 +1258,11 @@ function ListView({
1219
1258
  actions: selection.barActions
1220
1259
  }
1221
1260
  ) : /* @__PURE__ */ jsxs(Fragment, { children: [
1222
- showSearch && /* @__PURE__ */ jsxs("div", { className: "relative min-w-0 flex-1", children: [
1261
+ showSearch && // `basis-full` e não uma segunda `div`: o contentor é
1262
+ // `flex-wrap`, então uma primeira cria que ocupa a linha
1263
+ // inteira empurra o resto para baixo sozinha. Sem filtros,
1264
+ // a busca volta a partilhar a linha com atualizar/exportar.
1265
+ /* @__PURE__ */ jsxs("div", { className: cn("relative min-w-0 flex-1", searchOwnRow && "basis-full"), children: [
1223
1266
  /* @__PURE__ */ jsx(Search, { className: "pointer-events-none absolute left-2.5 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground" }),
1224
1267
  /* @__PURE__ */ jsx(
1225
1268
  "input",
@@ -1280,8 +1323,8 @@ function ListView({
1280
1323
  getRowId
1281
1324
  }
1282
1325
  ),
1283
- showPagination && /* @__PURE__ */ jsxs("div", { className: "-mt-px flex flex-wrap items-center justify-between gap-2 rounded-b-card border-t border-border px-3 py-2", children: [
1284
- /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
1326
+ showPagination && /* @__PURE__ */ jsxs("div", { className: "-mt-px flex min-h-9 flex-col items-center gap-2 rounded-b-card border-t border-border px-3 py-2 sm:grid sm:grid-cols-[1fr_auto_1fr] sm:gap-3", children: [
1327
+ /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground sm:justify-self-start", children: [
1285
1328
  (page - 1) * pageSize + 1,
1286
1329
  "\u2013",
1287
1330
  Math.min(page * pageSize, totalItems),
@@ -1291,6 +1334,17 @@ function ListView({
1291
1334
  totalItems.toLocaleString()
1292
1335
  ] }),
1293
1336
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
1337
+ totalPages > PAGE_WINDOW && /* @__PURE__ */ jsx(
1338
+ "button",
1339
+ {
1340
+ type: "button",
1341
+ onClick: () => onPageChange(1),
1342
+ disabled: page <= 1,
1343
+ "aria-label": firstPageLabel,
1344
+ className: PAGER_BTN,
1345
+ children: /* @__PURE__ */ jsx(ChevronsLeft, { className: "h-4 w-4" })
1346
+ }
1347
+ ),
1294
1348
  /* @__PURE__ */ jsx(
1295
1349
  "button",
1296
1350
  {
@@ -1302,11 +1356,18 @@ function ListView({
1302
1356
  children: /* @__PURE__ */ jsx(ChevronLeft, { className: "h-4 w-4" })
1303
1357
  }
1304
1358
  ),
1305
- /* @__PURE__ */ jsxs("span", { className: "px-1 text-xs tabular-nums text-muted-foreground", children: [
1306
- page,
1307
- " / ",
1308
- totalPages
1309
- ] }),
1359
+ pageWindow.map((n) => /* @__PURE__ */ jsx(
1360
+ "button",
1361
+ {
1362
+ type: "button",
1363
+ onClick: () => onPageChange(n),
1364
+ "aria-label": `${pageLabel} ${n}`,
1365
+ "aria-current": n === page ? "page" : void 0,
1366
+ className: n === page ? "flex h-7 min-w-7 items-center justify-center rounded-md bg-primary px-1.5 text-xs font-medium tabular-nums text-primary-foreground" : "flex h-7 min-w-7 items-center justify-center rounded-md px-1.5 text-xs tabular-nums text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
1367
+ children: n
1368
+ },
1369
+ n
1370
+ )),
1310
1371
  /* @__PURE__ */ jsx(
1311
1372
  "button",
1312
1373
  {
@@ -1317,6 +1378,17 @@ function ListView({
1317
1378
  className: PAGER_BTN,
1318
1379
  children: /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4" })
1319
1380
  }
1381
+ ),
1382
+ totalPages > PAGE_WINDOW && /* @__PURE__ */ jsx(
1383
+ "button",
1384
+ {
1385
+ type: "button",
1386
+ onClick: () => onPageChange(totalPages),
1387
+ disabled: page >= totalPages,
1388
+ "aria-label": lastPageLabel,
1389
+ className: PAGER_BTN,
1390
+ children: /* @__PURE__ */ jsx(ChevronsRight, { className: "h-4 w-4" })
1391
+ }
1320
1392
  )
1321
1393
  ] })
1322
1394
  ] })
@@ -2141,7 +2213,9 @@ function MultiSelect({
2141
2213
  emptyLabel = "Nada encontrado",
2142
2214
  disabled,
2143
2215
  className,
2144
- searchThreshold = 8
2216
+ searchThreshold = 8,
2217
+ variant = "field",
2218
+ icon: Icon2
2145
2219
  }) {
2146
2220
  const [query, setQuery] = React15.useState("");
2147
2221
  const selected = React15.useMemo(() => new Set(value), [value]);
@@ -2160,15 +2234,22 @@ function MultiSelect({
2160
2234
  {
2161
2235
  type: "button",
2162
2236
  disabled,
2237
+ "aria-label": allLabel,
2163
2238
  className: cn(
2164
- "flex h-9 w-full items-center justify-between gap-2 rounded-input border border-input bg-card px-3 py-1.5 text-xs",
2165
- "shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] transition-colors hover:bg-muted/40",
2166
2239
  "disabled:cursor-not-allowed disabled:opacity-50",
2167
- value.length === 0 && "text-muted-foreground",
2240
+ variant === "chip" ? cn(
2241
+ "inline-flex shrink-0 items-center gap-1 rounded-full border px-2.5 py-1 text-xs font-medium transition-colors",
2242
+ value.length > 0 ? "border-primary/30 bg-primary/10 text-primary hover:bg-primary/15" : "border-transparent bg-muted/70 text-muted-foreground hover:bg-muted hover:text-foreground"
2243
+ ) : cn(
2244
+ "flex h-9 w-full items-center justify-between gap-2 rounded-input border border-input bg-card px-3 py-1.5 text-xs",
2245
+ "shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] transition-colors hover:bg-muted/40",
2246
+ value.length === 0 && "text-muted-foreground"
2247
+ ),
2168
2248
  className
2169
2249
  ),
2170
2250
  children: [
2171
- /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", children: label }),
2251
+ variant === "chip" && Icon2 && /* @__PURE__ */ jsx(Icon2, { className: "h-3 w-3 shrink-0 opacity-70" }),
2252
+ /* @__PURE__ */ jsx("span", { className: cn("min-w-0 truncate", variant === "chip" && "max-w-[12rem]"), children: label }),
2172
2253
  /* @__PURE__ */ jsxs("span", { className: "flex shrink-0 items-center gap-1", children: [
2173
2254
  value.length > 0 && // Limpar dentro do gatilho: a alternativa é desmarcar cinco itens
2174
2255
  // um a um para voltar a "todos", e é o caminho de volta mais
@@ -2188,43 +2269,64 @@ function MultiSelect({
2188
2269
  children: /* @__PURE__ */ jsx(X, { className: "h-3 w-3" })
2189
2270
  }
2190
2271
  ),
2191
- /* @__PURE__ */ jsx(ChevronDown, { className: "h-3.5 w-3.5 shrink-0 opacity-50" })
2272
+ /* @__PURE__ */ jsx(ChevronDown, { className: cn("shrink-0", variant === "chip" ? "h-3 w-3 opacity-60" : "h-3.5 w-3.5 opacity-50") })
2192
2273
  ] })
2193
2274
  ]
2194
2275
  }
2195
2276
  ) }),
2196
- /* @__PURE__ */ jsxs(DropdownContent, { align: "start", className: "w-[--radix-dropdown-menu-trigger-width] p-0", children: [
2197
- options.length >= searchThreshold && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-b px-2 py-1.5", children: [
2198
- /* @__PURE__ */ jsx(Search, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
2199
- /* @__PURE__ */ jsx(
2200
- "input",
2201
- {
2202
- value: query,
2203
- onChange: (e) => setQuery(e.target.value),
2204
- placeholder: searchPlaceholder,
2205
- onKeyDown: (e) => e.stopPropagation(),
2206
- className: "w-full bg-transparent text-xs outline-none placeholder:text-muted-foreground"
2207
- }
2208
- )
2209
- ] }),
2210
- /* @__PURE__ */ jsx("div", { className: "max-h-64 overflow-y-auto py-1", children: filtered.length === 0 ? /* @__PURE__ */ jsx("p", { className: "px-3 py-4 text-center text-xs text-muted-foreground", children: emptyLabel }) : filtered.map((o) => /* @__PURE__ */ jsxs(
2211
- "button",
2212
- {
2213
- type: "button",
2214
- onClick: (e) => {
2215
- e.preventDefault();
2216
- toggle(o.value);
2217
- },
2218
- className: "flex w-full items-center gap-2 px-3 py-1.5 text-left text-xs transition-colors hover:bg-muted",
2219
- children: [
2220
- /* @__PURE__ */ jsx(Checkbox, { checked: selected.has(o.value), onChange: () => toggle(o.value) }),
2221
- /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: o.label }),
2222
- o.hint && /* @__PURE__ */ jsx("span", { className: "shrink-0 text-[10px] text-muted-foreground", children: o.hint })
2223
- ]
2224
- },
2225
- o.value
2226
- )) })
2227
- ] })
2277
+ /* @__PURE__ */ jsxs(
2278
+ DropdownContent,
2279
+ {
2280
+ align: "start",
2281
+ className: cn(
2282
+ "p-0",
2283
+ // Em `field` o painel casa com o campo, que é largo. Em `chip` a
2284
+ // largura do gatilho é a do rótulo — herdá-la daria uma lista de
2285
+ // dois dedos. Aqui ele ganha a sua própria medida de leitura.
2286
+ variant === "chip" ? "w-[min(16rem,calc(100vw-1.5rem))]" : "w-[--radix-dropdown-menu-trigger-width]"
2287
+ ),
2288
+ children: [
2289
+ options.length >= searchThreshold && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-b px-2 py-1.5", children: [
2290
+ /* @__PURE__ */ jsx(Search, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
2291
+ /* @__PURE__ */ jsx(
2292
+ "input",
2293
+ {
2294
+ value: query,
2295
+ onChange: (e) => setQuery(e.target.value),
2296
+ placeholder: searchPlaceholder,
2297
+ onKeyDown: (e) => e.stopPropagation(),
2298
+ className: "w-full bg-transparent text-xs outline-none placeholder:text-muted-foreground"
2299
+ }
2300
+ )
2301
+ ] }),
2302
+ /* @__PURE__ */ jsx("div", { className: "max-h-64 overflow-y-auto py-1", children: filtered.length === 0 ? /* @__PURE__ */ jsx("p", { className: "px-3 py-4 text-center text-xs text-muted-foreground", children: emptyLabel }) : filtered.map((o) => /* @__PURE__ */ jsxs(
2303
+ "button",
2304
+ {
2305
+ type: "button",
2306
+ onClick: (e) => {
2307
+ e.preventDefault();
2308
+ toggle(o.value);
2309
+ },
2310
+ className: "flex w-full items-center gap-2 px-3 py-1.5 text-left text-xs transition-colors hover:bg-muted",
2311
+ children: [
2312
+ /* @__PURE__ */ jsx(Checkbox, { checked: selected.has(o.value), onChange: () => toggle(o.value) }),
2313
+ o.color && /* @__PURE__ */ jsx(
2314
+ "span",
2315
+ {
2316
+ "aria-hidden": true,
2317
+ className: "h-2 w-2 shrink-0 rounded-full ring-1 ring-inset ring-black/10",
2318
+ style: { backgroundColor: o.color }
2319
+ }
2320
+ ),
2321
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: o.label }),
2322
+ o.hint && /* @__PURE__ */ jsx("span", { className: "shrink-0 text-[10px] text-muted-foreground", children: o.hint })
2323
+ ]
2324
+ },
2325
+ o.value
2326
+ )) })
2327
+ ]
2328
+ }
2329
+ )
2228
2330
  ] });
2229
2331
  }
2230
2332
  var INLINE_TOKEN = /(\*\*[^*]+\*\*|\*[^*]+\*|`[^`]+`)/g;
@@ -2772,5 +2874,5 @@ function StockEntryForm({
2772
2874
  }
2773
2875
 
2774
2876
  export { Badge, Breadcrumb, BulkActionBar, ChevronPager, CurrencyInput, DatePicker, DateRangeChip, DotBadge, DraftCommitBar, FilterCheckBox, FilterCheckList, FilterCheckRow, FilterChip, FilterSection, Input, ListView, Markdown, MarkdownEditor, MiniCalendar, Modal, ModalBody, ModalClose, ModalContent, ModalDescription, ModalFooter, ModalHeader, ModalOverlay, ModalPortal, ModalTitle, ModalTrigger, MultiSelect, PhoneField, PhoneLink, RefreshButton, RowActions, SearchCombobox, SearchField, SearchSelect, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator2 as Separator, StatTiles, StockEntryForm, Tabs, TabsContent, TabsList, TabsTrigger, Thumbnail, TimePicker, ToastProvider, WHATSAPP_BRAND_COLOR, WhatsAppIcon, badgeVariants, formatPhone2 as formatPhone, normalizePhone, renderMarkdown, setRowActionsLabel, toLocalISODate, useRowSelection };
2775
- //# sourceMappingURL=chunk-XEUIYSW2.js.map
2776
- //# sourceMappingURL=chunk-XEUIYSW2.js.map
2877
+ //# sourceMappingURL=chunk-NXFVYZY7.js.map
2878
+ //# sourceMappingURL=chunk-NXFVYZY7.js.map