@arbidocs/blocks 0.4.5 → 0.4.6

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 (131) hide show
  1. package/README.md +46 -6
  2. package/dist/agents/index.cjs +163 -162
  3. package/dist/agents/index.js +6 -5
  4. package/dist/chat/ChatMessageContent.d.ts +16 -0
  5. package/dist/chat/ChatPage.d.ts +11 -8
  6. package/dist/chat/ChatThreads.d.ts +3 -1
  7. package/dist/chat/CitationMark.d.ts +18 -0
  8. package/dist/chat/chat-page-types.d.ts +75 -1
  9. package/dist/chat/index.cjs +126 -117
  10. package/dist/chat/index.d.ts +3 -1
  11. package/dist/chat/index.js +5 -4
  12. package/dist/{chunk-3MIQASHO.cjs → chunk-23XL6SVZ.cjs} +39 -19
  13. package/dist/chunk-23XL6SVZ.cjs.map +1 -0
  14. package/dist/{chunk-ULWRNGGE.cjs → chunk-2ZTONLT5.cjs} +4 -25
  15. package/dist/chunk-2ZTONLT5.cjs.map +1 -0
  16. package/dist/{chunk-O637DUKS.cjs → chunk-56BUD74K.cjs} +28 -28
  17. package/dist/{chunk-O637DUKS.cjs.map → chunk-56BUD74K.cjs.map} +1 -1
  18. package/dist/{chunk-YLOKCIQJ.cjs → chunk-5SLLMK5K.cjs} +421 -115
  19. package/dist/chunk-5SLLMK5K.cjs.map +1 -0
  20. package/dist/{chunk-SS23F63U.cjs → chunk-5ZBP7TCD.cjs} +55 -3
  21. package/dist/chunk-5ZBP7TCD.cjs.map +1 -0
  22. package/dist/{chunk-3PZPRAAR.cjs → chunk-67HGXV4I.cjs} +14 -14
  23. package/dist/{chunk-3PZPRAAR.cjs.map → chunk-67HGXV4I.cjs.map} +1 -1
  24. package/dist/{chunk-RCP6THBS.js → chunk-7OCFHEE6.js} +3 -3
  25. package/dist/{chunk-RCP6THBS.js.map → chunk-7OCFHEE6.js.map} +1 -1
  26. package/dist/{chunk-TX2ZICS7.js → chunk-CPMNAJLF.js} +4 -24
  27. package/dist/chunk-CPMNAJLF.js.map +1 -0
  28. package/dist/{chunk-5XTZFH65.js → chunk-CVFBSUXL.js} +5 -5
  29. package/dist/{chunk-5XTZFH65.js.map → chunk-CVFBSUXL.js.map} +1 -1
  30. package/dist/chunk-DCDVWPMB.cjs +29 -0
  31. package/dist/chunk-DCDVWPMB.cjs.map +1 -0
  32. package/dist/{chunk-TI4UTYRL.js → chunk-EY2RJW27.js} +258 -10
  33. package/dist/chunk-EY2RJW27.js.map +1 -0
  34. package/dist/{chunk-7YADKWZT.js → chunk-G2E3O3HI.js} +3 -3
  35. package/dist/{chunk-7YADKWZT.js.map → chunk-G2E3O3HI.js.map} +1 -1
  36. package/dist/{chunk-6YHWXMPQ.js → chunk-G2T3KTZ3.js} +419 -115
  37. package/dist/chunk-G2T3KTZ3.js.map +1 -0
  38. package/dist/{chunk-2NNTQLBY.js → chunk-IAKUTBPX.js} +4 -4
  39. package/dist/{chunk-2NNTQLBY.js.map → chunk-IAKUTBPX.js.map} +1 -1
  40. package/dist/{chunk-IZHWP6WQ.cjs → chunk-JG4TFS3Z.cjs} +6 -6
  41. package/dist/{chunk-IZHWP6WQ.cjs.map → chunk-JG4TFS3Z.cjs.map} +1 -1
  42. package/dist/chunk-JLOYWXRB.js +1156 -0
  43. package/dist/chunk-JLOYWXRB.js.map +1 -0
  44. package/dist/{chunk-WJZBJUPX.js → chunk-KXMDOTGW.js} +56 -4
  45. package/dist/chunk-KXMDOTGW.js.map +1 -0
  46. package/dist/{chunk-2VBJ763Y.js → chunk-KZJAG7T3.js} +37 -7
  47. package/dist/chunk-KZJAG7T3.js.map +1 -0
  48. package/dist/{chunk-RIL7G7AS.cjs → chunk-MGUHR3JI.cjs} +4 -4
  49. package/dist/{chunk-RIL7G7AS.cjs.map → chunk-MGUHR3JI.cjs.map} +1 -1
  50. package/dist/{chunk-NPKGUQU5.js → chunk-NJL4LIXX.js} +4 -4
  51. package/dist/{chunk-NPKGUQU5.js.map → chunk-NJL4LIXX.js.map} +1 -1
  52. package/dist/{chunk-DN3NFNIA.cjs → chunk-QMDLPO3M.cjs} +266 -10
  53. package/dist/chunk-QMDLPO3M.cjs.map +1 -0
  54. package/dist/chunk-TJMKFY5P.js +27 -0
  55. package/dist/chunk-TJMKFY5P.js.map +1 -0
  56. package/dist/{chunk-3PJCET7H.js → chunk-UHVNYKV2.js} +38 -18
  57. package/dist/chunk-UHVNYKV2.js.map +1 -0
  58. package/dist/{chunk-6CHMNKXC.cjs → chunk-UTYQPVIW.cjs} +11 -11
  59. package/dist/chunk-UTYQPVIW.cjs.map +1 -0
  60. package/dist/{chunk-KHX2BX3S.cjs → chunk-VGOFFCMT.cjs} +37 -5
  61. package/dist/chunk-VGOFFCMT.cjs.map +1 -0
  62. package/dist/{chunk-67MKU5U7.js → chunk-YMHGF6R5.js} +8 -8
  63. package/dist/chunk-YMHGF6R5.js.map +1 -0
  64. package/dist/chunk-YVIOCITQ.cjs +1186 -0
  65. package/dist/chunk-YVIOCITQ.cjs.map +1 -0
  66. package/dist/{chunk-MVNCQDDE.cjs → chunk-ZVPTFTGV.cjs} +4 -4
  67. package/dist/{chunk-MVNCQDDE.cjs.map → chunk-ZVPTFTGV.cjs.map} +1 -1
  68. package/dist/collaboration/index.cjs +38 -37
  69. package/dist/collaboration/index.js +3 -2
  70. package/dist/connect/index.cjs +358 -19
  71. package/dist/connect/index.cjs.map +1 -1
  72. package/dist/connect/index.d.ts +1 -0
  73. package/dist/connect/index.js +341 -9
  74. package/dist/connect/index.js.map +1 -1
  75. package/dist/connection/ConnectedSettings.d.ts +64 -0
  76. package/dist/facts/index.cjs +2 -2
  77. package/dist/facts/index.js +2 -2
  78. package/dist/files/index.cjs +15 -14
  79. package/dist/files/index.cjs.map +1 -1
  80. package/dist/files/index.js +5 -4
  81. package/dist/files/index.js.map +1 -1
  82. package/dist/home/index.cjs +19 -19
  83. package/dist/home/index.js +4 -4
  84. package/dist/index.cjs +526 -477
  85. package/dist/index.cjs.map +1 -1
  86. package/dist/index.js +17 -16
  87. package/dist/index.js.map +1 -1
  88. package/dist/lib/bottom-inset.d.ts +16 -0
  89. package/dist/lib/useElementSize.d.ts +13 -0
  90. package/dist/lib/useFillHeight.d.ts +10 -0
  91. package/dist/settings/account-views.d.ts +55 -0
  92. package/dist/settings/index.cjs +179 -1148
  93. package/dist/settings/index.cjs.map +1 -1
  94. package/dist/settings/index.d.ts +1 -0
  95. package/dist/settings/index.js +10 -1073
  96. package/dist/settings/index.js.map +1 -1
  97. package/dist/shell/InstallPrompt.d.ts +28 -0
  98. package/dist/shell/MobileBars.d.ts +1 -1
  99. package/dist/shell/index.cjs +85 -45
  100. package/dist/shell/index.d.ts +4 -0
  101. package/dist/shell/index.js +3 -3
  102. package/dist/shell/install-instructions.d.ts +19 -0
  103. package/dist/shell/types.d.ts +6 -0
  104. package/dist/shell/use-install-prompt.d.ts +49 -0
  105. package/dist/site/index.cjs +62 -62
  106. package/dist/site/index.js +2 -2
  107. package/dist/studio/index.cjs +78 -77
  108. package/dist/studio/index.cjs.map +1 -1
  109. package/dist/studio/index.js +8 -7
  110. package/dist/studio/index.js.map +1 -1
  111. package/dist/theme/ThemeEditor.d.ts +4 -2
  112. package/dist/workspaces/index.cjs +4 -3
  113. package/dist/workspaces/index.cjs.map +1 -1
  114. package/dist/workspaces/index.js +3 -2
  115. package/dist/workspaces/index.js.map +1 -1
  116. package/package.json +8 -4
  117. package/src/blocks.css +30 -0
  118. package/dist/chunk-2VBJ763Y.js.map +0 -1
  119. package/dist/chunk-3MIQASHO.cjs.map +0 -1
  120. package/dist/chunk-3PJCET7H.js.map +0 -1
  121. package/dist/chunk-67MKU5U7.js.map +0 -1
  122. package/dist/chunk-6CHMNKXC.cjs.map +0 -1
  123. package/dist/chunk-6YHWXMPQ.js.map +0 -1
  124. package/dist/chunk-DN3NFNIA.cjs.map +0 -1
  125. package/dist/chunk-KHX2BX3S.cjs.map +0 -1
  126. package/dist/chunk-SS23F63U.cjs.map +0 -1
  127. package/dist/chunk-TI4UTYRL.js.map +0 -1
  128. package/dist/chunk-TX2ZICS7.js.map +0 -1
  129. package/dist/chunk-ULWRNGGE.cjs.map +0 -1
  130. package/dist/chunk-WJZBJUPX.js.map +0 -1
  131. package/dist/chunk-YLOKCIQJ.cjs.map +0 -1
@@ -0,0 +1,29 @@
1
+ "use client";
2
+ 'use strict';
3
+
4
+ var react = require('react');
5
+
6
+ // src/lib/useRestoreFocus.ts
7
+ function useRestoreFocus() {
8
+ const origin = react.useRef(null);
9
+ return react.useMemo(
10
+ () => ({
11
+ onOpenAutoFocus: () => {
12
+ origin.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
13
+ },
14
+ onCloseAutoFocus: (event) => {
15
+ const element = origin.current;
16
+ origin.current = null;
17
+ if (element && element.isConnected && element !== document.body) {
18
+ event.preventDefault();
19
+ element.focus();
20
+ }
21
+ }
22
+ }),
23
+ []
24
+ );
25
+ }
26
+
27
+ exports.useRestoreFocus = useRestoreFocus;
28
+ //# sourceMappingURL=chunk-DCDVWPMB.cjs.map
29
+ //# sourceMappingURL=chunk-DCDVWPMB.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/useRestoreFocus.ts"],"names":["useRef","useMemo"],"mappings":";;;;;AASO,SAAS,eAAA,GAGd;AACA,EAAA,MAAM,MAAA,GAASA,aAA2B,IAAI,CAAA;AAC9C,EAAA,OAAOC,aAAA;AAAA,IACL,OAAO;AAAA,MACL,iBAAiB,MAAM;AAErB,QAAA,MAAA,CAAO,OAAA,GACL,QAAA,CAAS,aAAA,YAAyB,WAAA,GAAc,SAAS,aAAA,GAAgB,IAAA;AAAA,MAC7E,CAAA;AAAA,MACA,gBAAA,EAAkB,CAAC,KAAA,KAAiB;AAClC,QAAA,MAAM,UAAU,MAAA,CAAO,OAAA;AACvB,QAAA,MAAA,CAAO,OAAA,GAAU,IAAA;AACjB,QAAA,IAAI,OAAA,IAAW,OAAA,CAAQ,WAAA,IAAe,OAAA,KAAY,SAAS,IAAA,EAAM;AAC/D,UAAA,KAAA,CAAM,cAAA,EAAe;AACrB,UAAA,OAAA,CAAQ,KAAA,EAAM;AAAA,QAChB;AAAA,MACF;AAAA,KACF,CAAA;AAAA,IACA;AAAC,GACH;AACF","file":"chunk-DCDVWPMB.cjs","sourcesContent":["import { useMemo, useRef } from 'react'\n\n/**\n * Props for a Radix `DialogContent` that put focus back where it was when the dialog opened.\n *\n * Radix Dialog returns focus to its `Trigger` on close and, when the dialog is opened from state\n * (no `DialogTrigger`, as every controlled dialog in the blocks is), drops it to `<body>`:\n * a keyboard or screen-reader user loses their place. Spread the result on `DialogContent`.\n */\nexport function useRestoreFocus(): {\n onOpenAutoFocus: (event: Event) => void\n onCloseAutoFocus: (event: Event) => void\n} {\n const origin = useRef<HTMLElement | null>(null)\n return useMemo(\n () => ({\n onOpenAutoFocus: () => {\n // Runs before the dialog moves focus inside, so this is still the opener.\n origin.current =\n document.activeElement instanceof HTMLElement ? document.activeElement : null\n },\n onCloseAutoFocus: (event: Event) => {\n const element = origin.current\n origin.current = null\n if (element && element.isConnected && element !== document.body) {\n event.preventDefault()\n element.focus()\n }\n },\n }),\n []\n )\n}\n"]}
@@ -1,9 +1,9 @@
1
1
  "use client";
2
2
  import { ActionLink } from './chunk-S7PSMMRG.js';
3
- import { useDrawerBehavior, BlocksTooltipProvider } from './chunk-2VBJ763Y.js';
3
+ import { useDrawerBehavior, BlocksTooltipProvider, useShellBottomInset } from './chunk-KZJAG7T3.js';
4
4
  import { testIdOr, prefixedTestId } from './chunk-7F6CBP3Z.js';
5
- import { createContext, forwardRef, useContext, useMemo, useRef, useState, useId, useEffect } from 'react';
6
- import { PanelLeftClose, PanelLeftOpen, X, Globe, Users, Lock, ChevronDown, LayoutGrid, Plus, Sparkles, Search, ArrowUp, Menu, TriangleAlert, CheckCircle2, Loader2, RefreshCw, WifiOff, MousePointerClick, Lightbulb, Pencil, ChevronLeft, ChevronRight, Info } from 'lucide-react';
5
+ import { createContext, forwardRef, useContext, useMemo, useRef, useState, useEffect, useCallback, useId } from 'react';
6
+ import { PanelLeftClose, PanelLeftOpen, X, Globe, Users, Lock, ChevronDown, LayoutGrid, Plus, Sparkles, Search, ArrowUp, Menu, Download, TriangleAlert, CheckCircle2, Loader2, RefreshCw, WifiOff, MousePointerClick, Lightbulb, Pencil, ChevronLeft, ChevronRight, Info } from 'lucide-react';
7
7
  import { cn, Tooltip, TooltipTrigger, TooltipContent, DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuLabel, Button } from '@arbidocs/react/ui';
8
8
  export { UserMenu } from '@arbidocs/react/ui';
9
9
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
@@ -119,7 +119,7 @@ function SidebarRoot({
119
119
  useDrawerBehavior(isDrawer, onBackdropClick ?? noop, drawerRef);
120
120
  const ariaLabel = ariaLabelProp ?? mergedLabels.mainNavigation;
121
121
  const contextValue = useMemo(() => ({ expanded, labels: mergedLabels }), [expanded, mergedLabels]);
122
- const navBase = "group/sidebar bg-sidebar border-r border-border text-foreground flex flex-col h-full overflow-y-auto overflow-x-hidden pb-safe pt-3 transition-all duration-300 ease-in-out";
122
+ const navBase = "group/sidebar bg-sidebar border-r border-border text-foreground scrollbar-themed flex flex-col h-full overflow-y-auto overflow-x-hidden pb-safe pt-3 transition-all duration-300 ease-in-out";
123
123
  const common = {
124
124
  "aria-label": ariaLabel,
125
125
  "data-testid": testIdOr(testId, { testId: "sidebar" }),
@@ -1055,6 +1055,15 @@ function MobileAppBar({
1055
1055
  }
1056
1056
  );
1057
1057
  }
1058
+ function TabLabel({ item }) {
1059
+ const wrap = "max-w-full text-balance px-0.5 text-center [overflow-wrap:normal] @max-[4.5rem]:text-[10px]";
1060
+ if (!item.shortLabel) return /* @__PURE__ */ jsx("span", { className: wrap, children: item.label });
1061
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1062
+ /* @__PURE__ */ jsx("span", { "data-slot": "tab-short-label", "aria-hidden": "true", className: cn(wrap, "@[5.5rem]:hidden"), children: item.shortLabel }),
1063
+ /* @__PURE__ */ jsx("span", { className: cn(wrap, "hidden @[5.5rem]:block"), children: item.label }),
1064
+ /* @__PURE__ */ jsx("span", { className: "sr-only @[5.5rem]:hidden", children: item.label })
1065
+ ] });
1066
+ }
1058
1067
  function MobileTabBar({
1059
1068
  items,
1060
1069
  label,
@@ -1063,14 +1072,17 @@ function MobileTabBar({
1063
1072
  className,
1064
1073
  "data-testid": testId
1065
1074
  }) {
1075
+ const navRef = useRef(null);
1076
+ useShellBottomInset(navRef);
1066
1077
  return /* @__PURE__ */ jsx(
1067
1078
  "nav",
1068
1079
  {
1080
+ ref: navRef,
1069
1081
  "aria-label": label ?? labels?.workspaceSections ?? DEFAULT_MOBILE_BARS_LABELS.workspaceSections,
1070
1082
  "data-slot": "mobile-tab-bar",
1071
1083
  "data-testid": testIdOr(testId, { testId: "mobile-tab-bar" }),
1072
1084
  className: cn(
1073
- "flex h-16 flex-shrink-0 items-stretch bg-sidebar px-2 pb-safe sm:hidden",
1085
+ "flex min-h-16 flex-shrink-0 items-stretch bg-sidebar px-2 pb-safe sm:hidden",
1074
1086
  className
1075
1087
  ),
1076
1088
  children: items.map((item) => /* @__PURE__ */ jsxs(
@@ -1081,13 +1093,14 @@ function MobileTabBar({
1081
1093
  disabled: item.disabled,
1082
1094
  "aria-current": item.active ? "page" : void 0,
1083
1095
  className: cn(
1084
- "flex min-h-12 min-w-0 flex-1 flex-col items-center justify-center gap-0.5 rounded-md text-xs transition-colors",
1096
+ // Each tab is a size container: a `shortLabel` replaces the label when it is narrow.
1097
+ "@container flex min-h-12 min-w-0 flex-1 flex-col items-center justify-center gap-0.5 rounded-md text-[11px] leading-tight transition-colors",
1085
1098
  item.active ? "font-semibold text-primary" : "font-medium text-muted-foreground hover:text-foreground"
1086
1099
  ),
1087
1100
  "data-testid": prefixedTestId(testIdPrefix, item.id, { testId: `mobile-tab-${item.id}` }),
1088
1101
  children: [
1089
1102
  item.icon,
1090
- /* @__PURE__ */ jsx("span", { className: "max-w-full truncate px-1", children: item.label })
1103
+ /* @__PURE__ */ jsx(TabLabel, { item })
1091
1104
  ]
1092
1105
  },
1093
1106
  item.id
@@ -1095,6 +1108,241 @@ function MobileTabBar({
1095
1108
  }
1096
1109
  );
1097
1110
  }
1111
+
1112
+ // src/shell/install-instructions.ts
1113
+ function isIosDevice() {
1114
+ if (typeof navigator === "undefined") return false;
1115
+ return /iPad|iPhone|iPod/.test(navigator.userAgent) || navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1;
1116
+ }
1117
+ function getInstallInstructions({
1118
+ appName = "this app"
1119
+ } = {}) {
1120
+ if (typeof navigator === "undefined" || typeof window === "undefined") {
1121
+ return {
1122
+ heading: `Install ${appName}`,
1123
+ steps: [`Open ${appName} in Chrome, Edge, or Safari to install it.`]
1124
+ };
1125
+ }
1126
+ const ua = navigator.userAgent;
1127
+ const isChromium = "onbeforeinstallprompt" in window;
1128
+ const isFirefox = /firefox|fxios/i.test(ua);
1129
+ const isMac = /Macintosh|Mac OS X/.test(ua);
1130
+ if (isIosDevice()) {
1131
+ return {
1132
+ heading: "Install on iPhone or iPad",
1133
+ steps: [
1134
+ `Open ${appName} in Safari, then tap the Share button.`,
1135
+ "Scroll down and tap \u201CAdd to Home Screen\u201D.",
1136
+ `Tap \u201CAdd\u201D: ${appName} appears on your home screen.`
1137
+ ]
1138
+ };
1139
+ }
1140
+ if (isChromium) {
1141
+ return {
1142
+ heading: `Install ${appName}`,
1143
+ steps: [
1144
+ "Click the install icon at the right of the address bar (a small monitor with a down arrow).",
1145
+ "Choose \u201CInstall\u201D in the dialog that appears."
1146
+ ],
1147
+ note: `On a phone, open the browser menu and choose \u201CInstall app\u201D / \u201CAdd to Home screen\u201D. If you don\u2019t see the option, ${appName} may already be installed.`
1148
+ };
1149
+ }
1150
+ if (isMac && !isFirefox) {
1151
+ return {
1152
+ heading: "Install on macOS Safari",
1153
+ steps: ["In the menu bar, open the File menu.", "Choose \u201CAdd to Dock\u201D."],
1154
+ note: "Requires Safari 17 or later (macOS Sonoma). On older Safari, use Chrome or Edge to install."
1155
+ };
1156
+ }
1157
+ if (isFirefox) {
1158
+ return {
1159
+ heading: "Firefox can\u2019t install web apps",
1160
+ steps: [`Open ${appName} in Chrome, Edge, or Safari to install it as an app.`]
1161
+ };
1162
+ }
1163
+ return {
1164
+ heading: `Install ${appName}`,
1165
+ steps: [
1166
+ "Look for an \u201CInstall\u201D or \u201CAdd to Home Screen\u201D option in your browser\u2019s menu or address bar."
1167
+ ]
1168
+ };
1169
+ }
1170
+
1171
+ // src/shell/use-install-prompt.ts
1172
+ var deferredPrompt = null;
1173
+ var installed = false;
1174
+ var initialized = false;
1175
+ var autoPromptParam = null;
1176
+ var subscribers = /* @__PURE__ */ new Set();
1177
+ var notify = () => subscribers.forEach((fn) => fn());
1178
+ function isStandalone() {
1179
+ if (typeof window === "undefined") return false;
1180
+ const iosStandalone = navigator.standalone === true;
1181
+ return window.matchMedia?.("(display-mode: standalone)").matches === true || iosStandalone;
1182
+ }
1183
+ function wantsAutoPrompt() {
1184
+ if (!autoPromptParam) return false;
1185
+ return new URLSearchParams(window.location.search).get(autoPromptParam) === "true";
1186
+ }
1187
+ function onBeforeInstallPrompt(event) {
1188
+ event.preventDefault();
1189
+ deferredPrompt = event;
1190
+ notify();
1191
+ if (wantsAutoPrompt()) void promptAppInstall();
1192
+ }
1193
+ function onAppInstalled() {
1194
+ installed = true;
1195
+ deferredPrompt = null;
1196
+ notify();
1197
+ }
1198
+ function initInstallPrompt(options = {}) {
1199
+ if (options.autoPromptParam) autoPromptParam = options.autoPromptParam;
1200
+ if (initialized || typeof window === "undefined") return;
1201
+ initialized = true;
1202
+ installed = isStandalone();
1203
+ window.addEventListener("beforeinstallprompt", onBeforeInstallPrompt);
1204
+ window.addEventListener("appinstalled", onAppInstalled);
1205
+ }
1206
+ async function promptAppInstall() {
1207
+ if (!deferredPrompt) return false;
1208
+ const prompt = deferredPrompt;
1209
+ deferredPrompt = null;
1210
+ notify();
1211
+ try {
1212
+ await prompt.prompt();
1213
+ } catch {
1214
+ }
1215
+ return true;
1216
+ }
1217
+ var INSTALL_PROMPT_DISMISSED_KEY = "arbi-blocks:install-prompt-dismissed";
1218
+ var DAY_MS = 24 * 60 * 60 * 1e3;
1219
+ function readDismissedAt(key) {
1220
+ try {
1221
+ const raw = window.localStorage.getItem(key);
1222
+ const at = raw ? Number(raw) : NaN;
1223
+ return Number.isFinite(at) ? at : null;
1224
+ } catch {
1225
+ return null;
1226
+ }
1227
+ }
1228
+ function useInstallPrompt({
1229
+ storageKey = INSTALL_PROMPT_DISMISSED_KEY,
1230
+ dismissDays = 30,
1231
+ autoPromptParam: autoParam,
1232
+ appName
1233
+ } = {}) {
1234
+ const [, forceRender] = useState(0);
1235
+ const [dismissedAt, setDismissedAt] = useState(
1236
+ () => typeof window === "undefined" ? null : readDismissedAt(storageKey)
1237
+ );
1238
+ useEffect(() => {
1239
+ initInstallPrompt({ autoPromptParam: autoParam });
1240
+ const onChange = () => forceRender((n) => n + 1);
1241
+ subscribers.add(onChange);
1242
+ onChange();
1243
+ return () => {
1244
+ subscribers.delete(onChange);
1245
+ };
1246
+ }, [autoParam]);
1247
+ const dismiss = useCallback(() => {
1248
+ const now = Date.now();
1249
+ setDismissedAt(now);
1250
+ try {
1251
+ window.localStorage.setItem(storageKey, String(now));
1252
+ } catch {
1253
+ }
1254
+ }, [storageKey]);
1255
+ const isDismissed = dismissedAt !== null && Date.now() - dismissedAt < dismissDays * DAY_MS;
1256
+ const isInstalled = installed || isStandalone();
1257
+ return {
1258
+ canPrompt: !isInstalled && deferredPrompt !== null,
1259
+ isInstalled,
1260
+ isIos: isIosDevice(),
1261
+ isDismissed,
1262
+ promptInstall: promptAppInstall,
1263
+ dismiss,
1264
+ instructions: getInstallInstructions({ appName })
1265
+ };
1266
+ }
1267
+ var DEFAULT_INSTALL_PROMPT_LABELS = {
1268
+ install: "Install app",
1269
+ dismiss: "Dismiss install prompt",
1270
+ installAs: "Install {app} as an app"
1271
+ };
1272
+ function InstallPrompt({
1273
+ placement = "start",
1274
+ labels,
1275
+ className,
1276
+ "data-testid": testId,
1277
+ ...options
1278
+ }) {
1279
+ const l = { ...DEFAULT_INSTALL_PROMPT_LABELS, ...labels };
1280
+ const install = useInstallPrompt(options);
1281
+ const [showSteps, setShowSteps] = useState(false);
1282
+ const isOffer = install.canPrompt || install.isIos;
1283
+ if (install.isInstalled || install.isDismissed || !isOffer) return null;
1284
+ const appName = options.appName ?? "this app";
1285
+ const onInstall = async () => {
1286
+ if (install.canPrompt) await install.promptInstall();
1287
+ else setShowSteps((open) => !open);
1288
+ };
1289
+ return /* @__PURE__ */ jsxs(
1290
+ "div",
1291
+ {
1292
+ "data-slot": "install-prompt",
1293
+ "data-testid": testIdOr(testId, { testId: "install-app-prompt" }),
1294
+ className: cn(
1295
+ "fixed z-30 flex max-w-[calc(100vw-1.5rem)] flex-col gap-2",
1296
+ // Above the bottom bars (tab bar / composer) and the home indicator on a phone, a plain
1297
+ // corner offset from `sm` up where the tab bar is gone.
1298
+ "bottom-[calc(max(var(--shell-bottom-inset,0px),env(safe-area-inset-bottom,0px))+0.75rem)] sm:bottom-[calc(env(safe-area-inset-bottom,0px)+0.75rem)]",
1299
+ placement === "start" ? "left-3 items-start" : "right-3 items-end",
1300
+ className
1301
+ ),
1302
+ children: [
1303
+ showSteps && /* @__PURE__ */ jsxs(
1304
+ "div",
1305
+ {
1306
+ "data-slot": "install-prompt-steps",
1307
+ className: "w-72 max-w-full rounded-lg border border-border bg-card p-3 text-sm text-card-foreground shadow-lg",
1308
+ children: [
1309
+ /* @__PURE__ */ jsx("p", { className: "font-medium", children: install.instructions.heading }),
1310
+ /* @__PURE__ */ jsx("ol", { className: "mt-2 list-decimal space-y-1 pl-5 text-muted-foreground", children: install.instructions.steps.map((step) => /* @__PURE__ */ jsx("li", { children: step }, step)) })
1311
+ ]
1312
+ }
1313
+ ),
1314
+ /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center rounded-full border border-border bg-card/95 text-foreground shadow-sm backdrop-blur", children: [
1315
+ /* @__PURE__ */ jsxs(
1316
+ "button",
1317
+ {
1318
+ type: "button",
1319
+ onClick: () => void onInstall(),
1320
+ "aria-label": l.installAs.replace("{app}", appName),
1321
+ "aria-expanded": install.canPrompt ? void 0 : showSteps,
1322
+ "data-slot": "install-prompt-action",
1323
+ className: "inline-flex min-h-11 items-center gap-1.5 rounded-full pl-4 pr-2 text-xs font-medium transition-colors hover:bg-accent sm:min-h-9 sm:pl-3",
1324
+ children: [
1325
+ /* @__PURE__ */ jsx(Download, { className: "size-3.5", "aria-hidden": "true" }),
1326
+ l.install
1327
+ ]
1328
+ }
1329
+ ),
1330
+ /* @__PURE__ */ jsx(
1331
+ "button",
1332
+ {
1333
+ type: "button",
1334
+ onClick: install.dismiss,
1335
+ "aria-label": l.dismiss,
1336
+ "data-slot": "install-prompt-dismiss",
1337
+ className: "inline-flex size-11 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-accent hover:text-foreground sm:size-9",
1338
+ children: /* @__PURE__ */ jsx(X, { className: "size-3.5", "aria-hidden": "true" })
1339
+ }
1340
+ )
1341
+ ] })
1342
+ ]
1343
+ }
1344
+ );
1345
+ }
1098
1346
  function ActionCluster({
1099
1347
  layout = "bar",
1100
1348
  status,
@@ -1571,6 +1819,6 @@ function SplitLayout({
1571
1819
  );
1572
1820
  }
1573
1821
 
1574
- export { ActionCluster, AskField, AskRow, AskTrigger, DEFAULT_ASK_FIELD_LABELS, DEFAULT_MOBILE_BARS_LABELS, DEFAULT_OFFLINE_PILL_LABELS, DEFAULT_REMOTE_CONTROL_PILL_LABELS, DEFAULT_SIDEBAR_LABELS, DEFAULT_TIP_CARD_LABELS, DEFAULT_WORKSPACE_KIND_LABELS, DEFAULT_WORKSPACE_SWITCHER_LABELS, InfoBar, MobileAppBar, MobileTabBar, OfflinePill, RemoteControlPill, Sidebar, SidebarBadgeRow, SidebarRowAction, SidebarRowHoverContext, SplitLayout, StatusRow, TipCard, WorkspaceIdentity, WorkspaceSwitcher, resolveSidebarLayout, useSidebarContext, useSidebarSettle, workspaceKindColor, workspaceKindMeta };
1575
- //# sourceMappingURL=chunk-TI4UTYRL.js.map
1576
- //# sourceMappingURL=chunk-TI4UTYRL.js.map
1822
+ export { ActionCluster, AskField, AskRow, AskTrigger, DEFAULT_ASK_FIELD_LABELS, DEFAULT_INSTALL_PROMPT_LABELS, DEFAULT_MOBILE_BARS_LABELS, DEFAULT_OFFLINE_PILL_LABELS, DEFAULT_REMOTE_CONTROL_PILL_LABELS, DEFAULT_SIDEBAR_LABELS, DEFAULT_TIP_CARD_LABELS, DEFAULT_WORKSPACE_KIND_LABELS, DEFAULT_WORKSPACE_SWITCHER_LABELS, INSTALL_PROMPT_DISMISSED_KEY, InfoBar, InstallPrompt, MobileAppBar, MobileTabBar, OfflinePill, RemoteControlPill, Sidebar, SidebarBadgeRow, SidebarRowAction, SidebarRowHoverContext, SplitLayout, StatusRow, TipCard, WorkspaceIdentity, WorkspaceSwitcher, getInstallInstructions, initInstallPrompt, isIosDevice, promptAppInstall, resolveSidebarLayout, useInstallPrompt, useSidebarContext, useSidebarSettle, workspaceKindColor, workspaceKindMeta };
1823
+ //# sourceMappingURL=chunk-EY2RJW27.js.map
1824
+ //# sourceMappingURL=chunk-EY2RJW27.js.map