@motor-hero/ui-kit 0.45.0 → 0.46.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -16,7 +16,15 @@ export interface AppShellProps {
16
16
  headerActions?: ReactNode;
17
17
  collapsible?: boolean;
18
18
  defaultCollapsed?: boolean;
19
+ /**
20
+ * Bottom of the desktop sidebar, above the collapse control — a product
21
+ * credit, a version, a support link. Receives the collapsed state so it
22
+ * can shrink with the sidebar.
23
+ */
24
+ sidebarFooter?: ReactNode | ((collapsed: boolean) => ReactNode);
25
+ /** Above the header, full width of the content column — `UpdateBanner` goes here. */
26
+ banner?: ReactNode;
19
27
  children: ReactNode;
20
28
  }
21
- export declare function AppShell({ brand, brandCollapsed, navItems, activePath, isActive, isAdmin, user, userMenuItems, onLogout, renderLink, headerActions, collapsible, defaultCollapsed, children, }: AppShellProps): import("react").JSX.Element;
29
+ export declare function AppShell({ brand, brandCollapsed, navItems, activePath, isActive, isAdmin, user, userMenuItems, onLogout, renderLink, headerActions, collapsible, defaultCollapsed, sidebarFooter, banner, children, }: AppShellProps): import("react").JSX.Element;
22
30
  //# sourceMappingURL=app-shell.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"app-shell.d.ts","sourceRoot":"","sources":["../../src/components/app-shell.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,SAAS,EAAY,MAAM,OAAO,CAAA;AAEhD,OAAO,EAAc,KAAK,OAAO,EAAE,MAAM,eAAe,CAAA;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAEzC,OAAO,EAAY,KAAK,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAA;AAEvE,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,SAAS,CAAA;IAChB,cAAc,CAAC,EAAE,SAAS,CAAA;IAC1B,QAAQ,EAAE,OAAO,EAAE,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAA;IACzD,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,aAAa,CAAC,EAAE,YAAY,EAAE,CAAA;IAC9B,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,aAAa,CAAC,EAAE,SAAS,CAAA;IACzB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,QAAQ,EAAE,SAAS,CAAA;CACpB;AAED,wBAAgB,QAAQ,CAAC,EACvB,KAAK,EACL,cAAc,EACd,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,OAAe,EACf,IAAI,EACJ,aAAa,EACb,QAAQ,EACR,UAA8B,EAC9B,aAAa,EACb,WAAkB,EAClB,gBAAwB,EACxB,QAAQ,GACT,EAAE,aAAa,+BAsFf"}
1
+ {"version":3,"file":"app-shell.d.ts","sourceRoot":"","sources":["../../src/components/app-shell.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,SAAS,EAAY,MAAM,OAAO,CAAA;AAEhD,OAAO,EAAc,KAAK,OAAO,EAAE,MAAM,eAAe,CAAA;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAEzC,OAAO,EAAY,KAAK,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAA;AAEvE,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,SAAS,CAAA;IAChB,cAAc,CAAC,EAAE,SAAS,CAAA;IAC1B,QAAQ,EAAE,OAAO,EAAE,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAA;IACzD,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,aAAa,CAAC,EAAE,YAAY,EAAE,CAAA;IAC9B,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,aAAa,CAAC,EAAE,SAAS,CAAA;IACzB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B;;;;OAIG;IACH,aAAa,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,SAAS,EAAE,OAAO,KAAK,SAAS,CAAC,CAAA;IAC/D,qFAAqF;IACrF,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB,QAAQ,EAAE,SAAS,CAAA;CACpB;AAED,wBAAgB,QAAQ,CAAC,EACvB,KAAK,EACL,cAAc,EACd,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,OAAe,EACf,IAAI,EACJ,aAAa,EACb,QAAQ,EACR,UAA8B,EAC9B,aAAa,EACb,WAAkB,EAClB,gBAAwB,EACxB,aAAa,EACb,MAAM,EACN,QAAQ,GACT,EAAE,aAAa,+BA4Ff"}
@@ -49,10 +49,16 @@ export interface BaseDialogProps {
49
49
  }
50
50
  /**
51
51
  * Standardized, responsive dialog shell:
52
- * - mobile: bottom sheet (full width, up to 92vh tall)
53
- * - desktop: centered dialog (up to 90vh tall)
52
+ * - mobile: bottom sheet (full width, up to 92dvh tall)
53
+ * - desktop: centered dialog (up to 92dvh tall)
54
54
  * Header and footer stay fixed; only the body scrolls.
55
55
  *
56
+ * Heights use `dvh`, not `vh`: on iOS `vh` is locked to the large viewport
57
+ * (toolbars collapsed), so `92vh` can exceed the visible area by 10-15%. With
58
+ * the sheet anchored to `bottom-0` the overflow leaves through the top, and
59
+ * since the body is the only scrollable child, what goes off-screen is the
60
+ * header - title and close button. Does not reproduce outside real iOS.
61
+ *
56
62
  * Also fixes the known Radix bug where `body { pointer-events: none }`
57
63
  * can persist after closing a dialog that contained a Select/Popover,
58
64
  * which would otherwise make the rest of the page unclickable.
@@ -1 +1 @@
1
- {"version":3,"file":"base-dialog.d.ts","sourceRoot":"","sources":["../../src/components/base-dialog.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAKtC,QAAA,MAAM,WAAW;;;;;;;;;;;CAWP,CAAA;AAEV,MAAM,MAAM,cAAc,GAAG,MAAM,OAAO,WAAW,CAAA;AAErD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,SAAS,CAAA;IACvB,QAAQ,EAAE,SAAS,CAAA;IACnB,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB,IAAI,CAAC,EAAE,cAAc,CAAA;IACrB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,OAAO,CAAA;IACf;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B;;;OAGG;IACH,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,SAAS,KAAK,SAAS,CAAA;CACnD;AAED;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,EACzB,IAAI,EACJ,YAAY,EACZ,KAAK,EACL,WAAW,EACX,QAAQ,EACR,MAAM,EACN,IAAW,EACX,SAAS,EACT,KAAK,EACL,YAAmB,EACnB,iBAAiB,EACjB,cAAqC,GACtC,EAAE,eAAe,qBAuFjB"}
1
+ {"version":3,"file":"base-dialog.d.ts","sourceRoot":"","sources":["../../src/components/base-dialog.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAKtC,QAAA,MAAM,WAAW;;;;;;;;;;;CAWP,CAAA;AAEV,MAAM,MAAM,cAAc,GAAG,MAAM,OAAO,WAAW,CAAA;AAErD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,SAAS,CAAA;IACvB,QAAQ,EAAE,SAAS,CAAA;IACnB,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB,IAAI,CAAC,EAAE,cAAc,CAAA;IACrB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,OAAO,CAAA;IACf;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B;;;OAGG;IACH,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,SAAS,KAAK,SAAS,CAAA;CACnD;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,UAAU,CAAC,EACzB,IAAI,EACJ,YAAY,EACZ,KAAK,EACL,WAAW,EACX,QAAQ,EACR,MAAM,EACN,IAAW,EACX,SAAS,EACT,KAAK,EACL,YAAmB,EACnB,iBAAiB,EACjB,cAAqC,GACtC,EAAE,eAAe,qBAuFjB"}
@@ -0,0 +1,16 @@
1
+ import { type UseVersionCheckOptions } from "../hooks/use-version-check";
2
+ export interface UpdateBannerProps extends UseVersionCheckOptions {
3
+ title?: string;
4
+ description?: string;
5
+ actionLabel?: string;
6
+ className?: string;
7
+ }
8
+ /**
9
+ * A bar that appears when a newer build is deployed and stays until the
10
+ * person reloads — not a toast: a notice that can be missed or dismissed
11
+ * leaves the old bundle running against a new API. Themed with the product
12
+ * tokens so it matches light and dark alike. Put it in `AppShell`'s
13
+ * `banner` slot (or at the top of any page).
14
+ */
15
+ export declare function UpdateBanner({ title, description, actionLabel, className, ...options }: UpdateBannerProps): import("react").JSX.Element | null;
16
+ //# sourceMappingURL=update-banner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-banner.d.ts","sourceRoot":"","sources":["../../src/components/update-banner.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,sBAAsB,EAAmB,MAAM,4BAA4B,CAAA;AAEzF,MAAM,WAAW,iBAAkB,SAAQ,sBAAsB;IAC/D,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,EAC3B,KAAgC,EAChC,WAA+D,EAC/D,WAAyB,EACzB,SAAS,EACT,GAAG,OAAO,EACX,EAAE,iBAAiB,sCA4BnB"}
@@ -0,0 +1,24 @@
1
+ export interface UseVersionCheckOptions {
2
+ /** The build id baked into the running bundle (see `versionFile` in `@motor-hero/ui-kit/vite`). */
3
+ currentBuild: string | undefined;
4
+ /** Where the deployed build id is published. */
5
+ url?: string;
6
+ intervalMs?: number;
7
+ }
8
+ export interface VersionCheckState {
9
+ /** The deployed build differs from the running one. */
10
+ updateAvailable: boolean;
11
+ /** Grows on every poll that still sees a newer build. */
12
+ staleChecks: number;
13
+ latestBuild: string | null;
14
+ reload: () => void;
15
+ }
16
+ /**
17
+ * Polls the deployed `version.json` and compares its `buildTime` with the
18
+ * build id baked into this bundle. Nothing is inferred from a first fetch —
19
+ * a page loaded during a deploy, or a poll that fails while the server
20
+ * restarts, cannot make the running code believe it is current. Polling
21
+ * pauses while the tab is hidden and runs at once when it comes back.
22
+ */
23
+ export declare function useVersionCheck({ currentBuild, url, intervalMs, }: UseVersionCheckOptions): VersionCheckState;
24
+ //# sourceMappingURL=use-version-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-version-check.d.ts","sourceRoot":"","sources":["../../src/hooks/use-version-check.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,sBAAsB;IACrC,mGAAmG;IACnG,YAAY,EAAE,MAAM,GAAG,SAAS,CAAA;IAChC,gDAAgD;IAChD,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,uDAAuD;IACvD,eAAe,EAAE,OAAO,CAAA;IACxB,yDAAyD;IACzD,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,MAAM,EAAE,MAAM,IAAI,CAAA;CACnB;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,EAC9B,YAAY,EACZ,GAAqB,EACrB,UAAmB,GACpB,EAAE,sBAAsB,GAAG,iBAAiB,CAyC5C"}
package/dist/index.cjs CHANGED
@@ -65,6 +65,7 @@ __export(index_exports, {
65
65
  TableSkeleton: () => TableSkeleton,
66
66
  ThemeProvider: () => ThemeProvider,
67
67
  Toaster: () => Toaster,
68
+ UpdateBanner: () => UpdateBanner,
68
69
  UserMenu: () => UserMenu,
69
70
  applyCompanyTheme: () => applyCompanyTheme,
70
71
  cn: () => cn,
@@ -76,7 +77,8 @@ __export(index_exports, {
76
77
  useCustomToast: () => useCustomToast,
77
78
  useDisclosure: () => useDisclosure,
78
79
  useIsDesktop: () => useIsDesktop,
79
- useTheme: () => useTheme
80
+ useTheme: () => useTheme,
81
+ useVersionCheck: () => useVersionCheck
80
82
  });
81
83
  module.exports = __toCommonJS(index_exports);
82
84
 
@@ -341,6 +343,8 @@ function AppShell({
341
343
  headerActions,
342
344
  collapsible = true,
343
345
  defaultCollapsed = false,
346
+ sidebarFooter,
347
+ banner,
344
348
  children
345
349
  }) {
346
350
  const [collapsed, setCollapsed] = (0, import_react3.useState)(defaultCollapsed);
@@ -368,6 +372,7 @@ function AppShell({
368
372
  children: [
369
373
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex h-14 shrink-0 items-center border-b px-4", children: collapsed ? brandCollapsed ?? brand : brand }),
370
374
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex-1 overflow-y-auto px-2 py-4", children: nav(collapsed) }),
375
+ sidebarFooter && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "border-t px-3 py-2", "data-slot": "sidebar-footer", children: typeof sidebarFooter === "function" ? sidebarFooter(collapsed) : sidebarFooter }),
371
376
  collapsible && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "border-t p-2", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
372
377
  "button",
373
378
  {
@@ -409,6 +414,7 @@ function AppShell({
409
414
  }
410
415
  ),
411
416
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex flex-1 flex-col overflow-hidden", children: [
417
+ banner,
412
418
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("header", { className: "flex h-14 shrink-0 items-center gap-2 border-b bg-background px-4", children: [
413
419
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
414
420
  "button",
@@ -536,9 +542,9 @@ function BaseDialog({
536
542
  document.body.style.pointerEvents = "";
537
543
  },
538
544
  className: cn(
539
- "fixed z-50 flex max-h-[92vh] flex-col bg-background shadow-lg outline-none",
545
+ "fixed z-50 flex max-h-[92dvh] flex-col bg-background shadow-lg outline-none",
540
546
  "inset-x-0 bottom-0 rounded-t-2xl",
541
- "sm:inset-x-auto sm:bottom-auto sm:left-1/2 sm:top-1/2 sm:max-h-[92vh] sm:w-full sm:-translate-x-1/2 sm:-translate-y-1/2 sm:rounded-lg",
547
+ "sm:inset-x-auto sm:bottom-auto sm:left-1/2 sm:top-1/2 sm:max-h-[92dvh] sm:w-full sm:-translate-x-1/2 sm:-translate-y-1/2 sm:rounded-lg",
542
548
  "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
543
549
  sizeClasses[size],
544
550
  className
@@ -878,7 +884,7 @@ function Combobox({
878
884
  import_cmdk.Command.List,
879
885
  {
880
886
  ref: listRef,
881
- className: "max-h-[50vh] overflow-y-auto overflow-x-hidden p-1 sm:max-h-60",
887
+ className: "max-h-[50dvh] overflow-y-auto overflow-x-hidden p-1 sm:max-h-60",
882
888
  children: [
883
889
  !isServer && !showCreate && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_cmdk.Command.Empty, { className: "py-6 text-center text-sm text-muted-foreground", children: emptyMessage }),
884
890
  showCreate && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
@@ -946,7 +952,7 @@ function Combobox({
946
952
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_vaul2.Drawer.Trigger, { asChild: true, children: trigger }),
947
953
  /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_vaul2.Drawer.Portal, { children: [
948
954
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_vaul2.Drawer.Overlay, { className: "fixed inset-0 z-50 bg-black/80" }),
949
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_vaul2.Drawer.Content, { className: "fixed inset-x-0 bottom-0 z-50 mt-24 flex max-h-[85vh] flex-col rounded-t-2xl border bg-popover text-popover-foreground outline-none", children: [
955
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_vaul2.Drawer.Content, { className: "fixed inset-x-0 bottom-0 z-50 mt-24 flex max-h-[85dvh] flex-col rounded-t-2xl border bg-popover text-popover-foreground outline-none", children: [
950
956
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_vaul2.Drawer.Title, { className: "sr-only", children: placeholder }),
951
957
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "mx-auto my-3 h-1.5 w-12 shrink-0 rounded-full bg-muted" }),
952
958
  command
@@ -1328,7 +1334,7 @@ function DatePickerImpl({
1328
1334
  onInteractOutside: (event) => {
1329
1335
  if (triggerRef.current?.contains(event.target)) event.preventDefault();
1330
1336
  },
1331
- className: "fixed inset-x-0 bottom-0 z-50 mt-24 flex max-h-[85vh] flex-col rounded-t-2xl border bg-popover text-popover-foreground outline-none",
1337
+ className: "fixed inset-x-0 bottom-0 z-50 mt-24 flex max-h-[85dvh] flex-col rounded-t-2xl border bg-popover text-popover-foreground outline-none",
1332
1338
  children: [
1333
1339
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_vaul3.Drawer.Title, { className: "sr-only", children: withTime ? "Selecione a data e o hor\xE1rio" : "Selecione a data" }),
1334
1340
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "mx-auto my-3 h-1.5 w-12 shrink-0 rounded-full bg-muted" }),
@@ -1453,7 +1459,7 @@ function FilterPopover({
1453
1459
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_vaul4.Drawer.Trigger, { asChild: true, children: trigger }),
1454
1460
  /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_vaul4.Drawer.Portal, { children: [
1455
1461
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_vaul4.Drawer.Overlay, { className: "fixed inset-0 z-50 bg-black/80" }),
1456
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_vaul4.Drawer.Content, { className: "fixed inset-x-0 bottom-0 z-50 mt-24 flex max-h-[85vh] flex-col rounded-t-2xl border bg-popover text-popover-foreground outline-none", children: [
1462
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_vaul4.Drawer.Content, { className: "fixed inset-x-0 bottom-0 z-50 mt-24 flex max-h-[85dvh] flex-col rounded-t-2xl border bg-popover text-popover-foreground outline-none", children: [
1457
1463
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_vaul4.Drawer.Title, { className: "sr-only", children: title ?? label }),
1458
1464
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "mx-auto my-3 h-1.5 w-12 shrink-0 rounded-full bg-muted" }),
1459
1465
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "overflow-y-auto p-2", children: content })
@@ -1952,7 +1958,7 @@ function MultiCombobox({
1952
1958
  import_cmdk2.Command.List,
1953
1959
  {
1954
1960
  ref: listRef,
1955
- className: "max-h-[50vh] overflow-y-auto overflow-x-hidden p-1 sm:max-h-60",
1961
+ className: "max-h-[50dvh] overflow-y-auto overflow-x-hidden p-1 sm:max-h-60",
1956
1962
  children: [
1957
1963
  !isServer && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_cmdk2.Command.Empty, { className: "py-6 text-center text-sm text-muted-foreground", children: emptyMessage }),
1958
1964
  options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
@@ -2005,7 +2011,7 @@ function MultiCombobox({
2005
2011
  /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_vaul5.Drawer.Trigger, { asChild: true, disabled, children: trigger }),
2006
2012
  /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_vaul5.Drawer.Portal, { children: [
2007
2013
  /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_vaul5.Drawer.Overlay, { className: "fixed inset-0 z-50 bg-black/80" }),
2008
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_vaul5.Drawer.Content, { className: "fixed inset-x-0 bottom-0 z-50 mt-24 flex max-h-[85vh] flex-col rounded-t-2xl border bg-popover text-popover-foreground outline-none", children: [
2014
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_vaul5.Drawer.Content, { className: "fixed inset-x-0 bottom-0 z-50 mt-24 flex max-h-[85dvh] flex-col rounded-t-2xl border bg-popover text-popover-foreground outline-none", children: [
2009
2015
  /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_vaul5.Drawer.Title, { className: "sr-only", children: placeholder }),
2010
2016
  /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "mx-auto my-3 h-1.5 w-12 shrink-0 rounded-full bg-muted" }),
2011
2017
  command
@@ -2564,8 +2570,96 @@ function Toaster(props) {
2564
2570
  );
2565
2571
  }
2566
2572
 
2567
- // src/hooks/use-company-subdomain.ts
2573
+ // src/components/update-banner.tsx
2574
+ var import_lucide_react13 = require("lucide-react");
2575
+
2576
+ // src/hooks/use-version-check.ts
2568
2577
  var import_react8 = require("react");
2578
+ function useVersionCheck({
2579
+ currentBuild,
2580
+ url = "/version.json",
2581
+ intervalMs = 6e4
2582
+ }) {
2583
+ const [latestBuild, setLatestBuild] = (0, import_react8.useState)(null);
2584
+ const [staleChecks, setStaleChecks] = (0, import_react8.useState)(0);
2585
+ (0, import_react8.useEffect)(() => {
2586
+ if (!currentBuild) return;
2587
+ let cancelled = false;
2588
+ const check = async () => {
2589
+ if (document.visibilityState === "hidden") return;
2590
+ try {
2591
+ const res = await fetch(url, { cache: "no-store" });
2592
+ const contentType = res.headers.get("content-type") ?? "";
2593
+ if (!res.ok || !contentType.includes("application/json")) return;
2594
+ const data = await res.json();
2595
+ if (cancelled || typeof data.buildTime !== "string") return;
2596
+ if (data.buildTime !== currentBuild) {
2597
+ setLatestBuild(data.buildTime);
2598
+ setStaleChecks((n) => n + 1);
2599
+ }
2600
+ } catch (error) {
2601
+ console.error("Version check failed", error);
2602
+ }
2603
+ };
2604
+ check();
2605
+ const interval = setInterval(check, intervalMs);
2606
+ const onVisible = () => {
2607
+ if (document.visibilityState === "visible") check();
2608
+ };
2609
+ document.addEventListener("visibilitychange", onVisible);
2610
+ return () => {
2611
+ cancelled = true;
2612
+ clearInterval(interval);
2613
+ document.removeEventListener("visibilitychange", onVisible);
2614
+ };
2615
+ }, [currentBuild, url, intervalMs]);
2616
+ const reload = (0, import_react8.useCallback)(() => window.location.reload(), []);
2617
+ return { updateAvailable: latestBuild !== null, staleChecks, latestBuild, reload };
2618
+ }
2619
+
2620
+ // src/components/update-banner.tsx
2621
+ var import_jsx_runtime34 = require("react/jsx-runtime");
2622
+ function UpdateBanner({
2623
+ title = "Nova vers\xE3o dispon\xEDvel",
2624
+ description = "Atualize para continuar na vers\xE3o mais recente.",
2625
+ actionLabel = "Atualizar",
2626
+ className,
2627
+ ...options
2628
+ }) {
2629
+ const { updateAvailable, reload } = useVersionCheck(options);
2630
+ if (!updateAvailable) return null;
2631
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
2632
+ "div",
2633
+ {
2634
+ role: "status",
2635
+ "aria-live": "polite",
2636
+ "data-slot": "update-banner",
2637
+ className: cn(
2638
+ "flex flex-wrap items-center justify-between gap-3 border-b border-primary/30 bg-primary px-4 py-2 text-sm text-primary-foreground",
2639
+ className
2640
+ ),
2641
+ children: [
2642
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("span", { className: "flex min-w-0 items-center gap-2", children: [
2643
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_lucide_react13.RefreshCw, { className: "h-4 w-4 shrink-0 animate-spin [animation-duration:3s]", "aria-hidden": true }),
2644
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "font-medium", children: title }),
2645
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "hidden truncate opacity-80 sm:inline", children: description })
2646
+ ] }),
2647
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
2648
+ "button",
2649
+ {
2650
+ type: "button",
2651
+ onClick: reload,
2652
+ className: "shrink-0 rounded-md bg-background px-3 py-1 text-xs font-medium text-foreground transition-colors hover:bg-background/90",
2653
+ children: actionLabel
2654
+ }
2655
+ )
2656
+ ]
2657
+ }
2658
+ );
2659
+ }
2660
+
2661
+ // src/hooks/use-company-subdomain.ts
2662
+ var import_react9 = require("react");
2569
2663
  var ALWAYS_RESERVED = ["www", "localhost"];
2570
2664
  function getSubdomain(hostname, reservedSubdomains = []) {
2571
2665
  const labels = hostname.split(".");
@@ -2598,7 +2692,7 @@ function useCompanySubdomain(opts = {}) {
2598
2692
  overrideStorageKey = "company-subdomain",
2599
2693
  reservedSubdomains = []
2600
2694
  } = opts;
2601
- const [subdomain] = (0, import_react8.useState)(() => {
2695
+ const [subdomain] = (0, import_react9.useState)(() => {
2602
2696
  if (enableOverride) {
2603
2697
  const override = resolveOverride(overrideStorageKey);
2604
2698
  if (override) return override;
@@ -2610,20 +2704,20 @@ function useCompanySubdomain(opts = {}) {
2610
2704
  }
2611
2705
 
2612
2706
  // src/hooks/use-disclosure.ts
2613
- var import_react9 = require("react");
2707
+ var import_react10 = require("react");
2614
2708
  function useDisclosure(initial = false) {
2615
- const [open, setOpen] = (0, import_react9.useState)(initial);
2616
- const onOpen = (0, import_react9.useCallback)(() => setOpen(true), []);
2617
- const onClose = (0, import_react9.useCallback)(() => setOpen(false), []);
2618
- const onToggle = (0, import_react9.useCallback)(() => setOpen((v) => !v), []);
2709
+ const [open, setOpen] = (0, import_react10.useState)(initial);
2710
+ const onOpen = (0, import_react10.useCallback)(() => setOpen(true), []);
2711
+ const onClose = (0, import_react10.useCallback)(() => setOpen(false), []);
2712
+ const onToggle = (0, import_react10.useCallback)(() => setOpen((v) => !v), []);
2619
2713
  return { open, onOpen, onClose, onToggle, setOpen };
2620
2714
  }
2621
2715
 
2622
2716
  // src/hooks/use-toast.ts
2623
2717
  var import_sonner2 = require("sonner");
2624
- var import_react10 = require("react");
2718
+ var import_react11 = require("react");
2625
2719
  function useCustomToast() {
2626
- const showToast = (0, import_react10.useCallback)(
2720
+ const showToast = (0, import_react11.useCallback)(
2627
2721
  (title, description, status = "success") => {
2628
2722
  switch (status) {
2629
2723
  case "success":
@@ -2690,6 +2784,7 @@ function extractApiError(err, fallbackMessage = "Ocorreu um erro inesperado.") {
2690
2784
  TableSkeleton,
2691
2785
  ThemeProvider,
2692
2786
  Toaster,
2787
+ UpdateBanner,
2693
2788
  UserMenu,
2694
2789
  applyCompanyTheme,
2695
2790
  cn,
@@ -2701,6 +2796,7 @@ function extractApiError(err, fallbackMessage = "Ocorreu um erro inesperado.") {
2701
2796
  useCustomToast,
2702
2797
  useDisclosure,
2703
2798
  useIsDesktop,
2704
- useTheme
2799
+ useTheme,
2800
+ useVersionCheck
2705
2801
  });
2706
2802
  //# sourceMappingURL=index.cjs.map