@nivaro/react 0.1.28 → 0.1.29

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.d.ts CHANGED
@@ -668,6 +668,15 @@ declare interface HeaderWidgetInfo {
668
668
  inputBindings: InputBinding[];
669
669
  }
670
670
 
671
+ /** Time without real input before someone counts as idle. */
672
+ export declare const IDLE_AFTER_MS: number;
673
+
674
+ /** The fields a presence heartbeat should carry. */
675
+ export declare function idleState(): {
676
+ is_idle: boolean;
677
+ last_active: string;
678
+ };
679
+
671
680
  export declare function ImportConsole({ realtime, defaultTab, initialJobId, onJobOpen }: ImportConsoleProps): JSX.Element;
672
681
 
673
682
  export declare interface ImportConsoleProps {
@@ -1056,6 +1065,13 @@ declare interface O2MFieldInfo {
1056
1065
  parentId: string;
1057
1066
  }
1058
1067
 
1068
+ /**
1069
+ * Called when idleness CHANGES, not on a timer — a host can push the flip
1070
+ * straight down its socket so coming back is seen in about a second instead of
1071
+ * on the next heartbeat. Returns an unsubscribe.
1072
+ */
1073
+ export declare function onIdleChange(fn: (idle: boolean) => void): () => void;
1074
+
1059
1075
  export declare function openDmWith(userId: string, displayName?: string): void;
1060
1076
 
1061
1077
  /**
@@ -1477,6 +1493,9 @@ export declare function TextField({ field, value, onChange, error, disabled, rea
1477
1493
 
1478
1494
  export declare function TipLayer(): ReactPortal | null;
1479
1495
 
1496
+ /** Install the listeners. Safe to call more than once. */
1497
+ export declare function trackActivity(): void;
1498
+
1480
1499
  /**
1481
1500
  * Translate scope values (target-collection IDS) into a filter's value space.
1482
1501
  * When the filter compares ids (valueField 'id'/undefined) this is identity;
package/dist/index.js CHANGED
@@ -3251,7 +3251,7 @@ function StripCell({
3251
3251
  const r = s.prefix ?? "", a = s.suffix ?? "", l = n ? null : formatStatValue(t, s.format ?? "");
3252
3252
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col justify-start px-4 py-2 min-w-0", children: [
3253
3253
  /* @__PURE__ */ jsx("span", { className: "flex h-4 items-end truncate text-[10px] font-medium leading-none text-slate-400 dark:text-slate-500", children: e }),
3254
- /* @__PURE__ */ jsx("span", { className: "mt-1 leading-none truncate max-w-[220px]", children: n ? /* @__PURE__ */ jsx("span", { className: "animate-pulse inline-block h-3.5 w-16 rounded bg-slate-200 dark:bg-[hsl(var(--nvr-skeleton))]" }) : /* @__PURE__ */ jsxs("span", { className: "text-[13px] font-semibold tabular-nums text-slate-900 dark:text-slate-100", children: [
3254
+ /* @__PURE__ */ jsx("span", { className: "mt-1 leading-tight truncate max-w-[220px]", children: n ? /* @__PURE__ */ jsx("span", { className: "animate-pulse inline-block h-3.5 w-16 rounded bg-slate-200 dark:bg-[hsl(var(--nvr-skeleton))]" }) : /* @__PURE__ */ jsxs("span", { className: "text-[13px] font-semibold tabular-nums text-slate-900 dark:text-slate-100", children: [
3255
3255
  r,
3256
3256
  l,
3257
3257
  a
@@ -21297,7 +21297,7 @@ function ItemEditForm({
21297
21297
  "div",
21298
21298
  {
21299
21299
  "data-header-field": W.field,
21300
- className: "group relative flex flex-col justify-start border-r border-slate-200 dark:border-border px-4 py-2 min-w-0 transition-colors hover:bg-white/60 dark:hover:bg-white/[0.025]",
21300
+ className: "group relative flex flex-col justify-start self-stretch border-r border-slate-200 dark:border-border px-4 py-2 min-w-0 transition-colors hover:bg-white/60 dark:hover:bg-white/[0.025]",
21301
21301
  children: [
21302
21302
  /* @__PURE__ */ jsx("span", { className: "flex h-4 items-end truncate text-[10px] font-medium leading-none text-slate-400 dark:text-slate-500", children: W.label }),
21303
21303
  /* @__PURE__ */ jsx("span", { className: ["mt-1 leading-tight truncate max-w-[220px] pb-px", Ze ? `rounded-full px-2 py-0.5 text-[11px] inline-block ${Ke} bg-current/10` : ut ? `rounded px-1.5 py-0.5 border border-current/30 text-[11px] inline-block ${Ke}` : ""].filter(Boolean).join(" "), children: (() => {
@@ -37216,12 +37216,12 @@ function PageRenderer({ slug: e, hideHeader: t, className: s }) {
37216
37216
  }
37217
37217
  const POLL_MS = 6e4;
37218
37218
  let baseline = null, updateInfo = null;
37219
- const listeners = /* @__PURE__ */ new Set();
37219
+ const listeners$1 = /* @__PURE__ */ new Set();
37220
37220
  let pollTimer = null, checking = !1, fetcher = null, watching = !1;
37221
37221
  const emit = (e) => {
37222
37222
  if ((e == null ? void 0 : e.version) !== (updateInfo == null ? void 0 : updateInfo.version)) {
37223
37223
  updateInfo = e;
37224
- for (const t of listeners) t();
37224
+ for (const t of listeners$1) t();
37225
37225
  }
37226
37226
  };
37227
37227
  async function checkApiVersion() {
@@ -37257,7 +37257,7 @@ function getApiUpdate() {
37257
37257
  }
37258
37258
  function useApiUpdate() {
37259
37259
  return useSyncExternalStore(
37260
- (e) => (listeners.add(e), () => listeners.delete(e)),
37260
+ (e) => (listeners$1.add(e), () => listeners$1.delete(e)),
37261
37261
  getApiUpdate,
37262
37262
  getApiUpdate
37263
37263
  );
@@ -37307,6 +37307,52 @@ function ApiUpdateBanner({
37307
37307
  }
37308
37308
  );
37309
37309
  }
37310
+ const IDLE_AFTER_MS = 5 * 6e4, ACTIVITY_EVENTS = [
37311
+ "pointerdown",
37312
+ "keydown",
37313
+ "wheel",
37314
+ "touchstart",
37315
+ "scroll",
37316
+ "mousemove",
37317
+ "focus"
37318
+ ];
37319
+ let lastActivity = Date.now(), installed = !1, lastReported = null;
37320
+ const listeners = /* @__PURE__ */ new Set();
37321
+ function onIdleChange(e) {
37322
+ return listeners.add(e), () => listeners.delete(e);
37323
+ }
37324
+ function publish() {
37325
+ const e = idleState().is_idle;
37326
+ if (e !== lastReported) {
37327
+ lastReported = e;
37328
+ for (const t of listeners)
37329
+ try {
37330
+ t(e);
37331
+ } catch {
37332
+ }
37333
+ }
37334
+ }
37335
+ function trackActivity() {
37336
+ if (installed || typeof window > "u") return;
37337
+ installed = !0;
37338
+ let e = 0;
37339
+ const t = () => {
37340
+ const s = Date.now();
37341
+ s - e < 1e3 || (e = s, lastActivity = s, publish());
37342
+ };
37343
+ for (const s of ACTIVITY_EVENTS)
37344
+ window.addEventListener(s, t, { passive: !0, capture: !0 });
37345
+ document.addEventListener("visibilitychange", () => {
37346
+ document.visibilityState === "visible" ? (lastActivity = Date.now(), e = 0) : lastActivity = 0, publish();
37347
+ }), setInterval(publish, 15e3);
37348
+ }
37349
+ function idleState() {
37350
+ const e = typeof document < "u" && document.visibilityState === "hidden", t = Date.now() - lastActivity > IDLE_AFTER_MS;
37351
+ return {
37352
+ is_idle: e || t,
37353
+ last_active: new Date(lastActivity || Date.now()).toISOString()
37354
+ };
37355
+ }
37310
37356
  function BooleanField({
37311
37357
  field: e,
37312
37358
  value: t,
@@ -40605,6 +40651,7 @@ export {
40605
40651
  DrilldownContext,
40606
40652
  FileField,
40607
40653
  GridFlushContext,
40654
+ IDLE_AFTER_MS,
40608
40655
  ImportConsole,
40609
40656
  ItemEditAuthContext,
40610
40657
  ItemEditForm,
@@ -40650,12 +40697,15 @@ export {
40650
40697
  fetchSchema,
40651
40698
  getApiUpdate,
40652
40699
  getMentionQuery,
40700
+ idleState,
40653
40701
  matchScopeDimension,
40654
40702
  normalizeFieldType,
40703
+ onIdleChange,
40655
40704
  openDmWith,
40656
40705
  registerDmOpener,
40657
40706
  splitMessageTokens,
40658
40707
  startApiVersionWatch,
40708
+ trackActivity,
40659
40709
  translateScopeValues,
40660
40710
  useApiUpdate,
40661
40711
  useChatConfig,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nivaro/react",
3
- "version": "0.1.28",
3
+ "version": "0.1.29",
4
4
  "description": "React hooks and components for Nivaro CMS forms",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",