@almadar/ui 2.42.0 → 2.43.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.
@@ -1,5 +1,5 @@
1
1
  import * as React113 from 'react';
2
- import React113__default, { createContext, useCallback, useState, useRef, useEffect, useLayoutEffect, lazy, useContext, useSyncExternalStore, useMemo } from 'react';
2
+ import React113__default, { createContext, useCallback, useState, useRef, useEffect, useMemo, useLayoutEffect, lazy, useContext, useSyncExternalStore } from 'react';
3
3
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
4
  import { EventBusContext } from '@almadar/ui/providers';
5
5
  import 'react-dom';
@@ -247,7 +247,7 @@ var ThemeProvider = ({
247
247
  const newMode = resolvedMode === "dark" ? "light" : "dark";
248
248
  setMode(newMode);
249
249
  }, [resolvedMode, setMode]);
250
- const contextValue = useMemo(
250
+ const contextValue2 = useMemo(
251
251
  () => ({
252
252
  theme,
253
253
  mode,
@@ -269,30 +269,97 @@ var ThemeProvider = ({
269
269
  appliedTheme
270
270
  ]
271
271
  );
272
- return /* @__PURE__ */ jsx(ThemeContext.Provider, { value: contextValue, children });
272
+ return /* @__PURE__ */ jsx(ThemeContext.Provider, { value: contextValue2, children });
273
273
  };
274
274
  var store = /* @__PURE__ */ new Map();
275
275
  var storeListeners = /* @__PURE__ */ new Set();
276
276
  var watchCallbacks = /* @__PURE__ */ new Map();
277
- function advance(entityType, data) {
278
- const prev = store.get(entityType);
279
- const oldData = prev?.data ?? [];
280
- store.set(entityType, { data, version: (prev?.version ?? 0) + 1 });
277
+ function extractId(record) {
278
+ const r = record;
279
+ return String(r.id ?? r._id ?? r.key ?? "");
280
+ }
281
+ function materialize(snap) {
282
+ return snap.ids.map((id) => snap.entities.get(id));
283
+ }
284
+ function notifyListeners(entityType, prev) {
281
285
  for (const listener of storeListeners) {
282
286
  listener();
283
287
  }
284
288
  const cbs = watchCallbacks.get(entityType);
285
289
  if (cbs) {
290
+ const oldData = prev ? materialize(prev) : [];
291
+ const cur = store.get(entityType);
292
+ const newData = cur ? materialize(cur) : [];
286
293
  for (const cb of cbs) {
287
294
  try {
288
- cb(oldData, data);
295
+ cb(oldData, newData);
289
296
  } catch {
290
297
  }
291
298
  }
292
299
  }
293
300
  }
301
+ function setAll(entityType, records) {
302
+ const entities = /* @__PURE__ */ new Map();
303
+ const ids = [];
304
+ for (const r of records) {
305
+ const rec = r;
306
+ const id = extractId(rec);
307
+ if (id) {
308
+ entities.set(id, rec);
309
+ ids.push(id);
310
+ }
311
+ }
312
+ const prev = store.get(entityType);
313
+ store.set(entityType, { entities, ids, version: (prev?.version ?? 0) + 1 });
314
+ notifyListeners(entityType, prev);
315
+ }
316
+ function upsertOne(entityType, record) {
317
+ const id = extractId(record);
318
+ if (!id) return;
319
+ const prev = store.get(entityType);
320
+ const snapshot = prev ? { entities: new Map(prev.entities), ids: [...prev.ids], version: prev.version } : { entities: /* @__PURE__ */ new Map(), ids: [], version: 0 };
321
+ snapshot.entities.set(id, record);
322
+ if (!snapshot.ids.includes(id)) snapshot.ids.push(id);
323
+ snapshot.version++;
324
+ store.set(entityType, snapshot);
325
+ notifyListeners(entityType, prev);
326
+ }
327
+ function addOne(entityType, record) {
328
+ upsertOne(entityType, record);
329
+ }
330
+ function updateOne(entityType, id, changes) {
331
+ const prev = store.get(entityType);
332
+ if (!prev?.entities.has(id)) return;
333
+ const snapshot = {
334
+ entities: new Map(prev.entities),
335
+ ids: [...prev.ids],
336
+ version: prev.version
337
+ };
338
+ snapshot.entities.set(id, { ...snapshot.entities.get(id), ...changes });
339
+ snapshot.version++;
340
+ store.set(entityType, snapshot);
341
+ notifyListeners(entityType, prev);
342
+ }
343
+ function removeOne(entityType, id) {
344
+ const prev = store.get(entityType);
345
+ if (!prev) return;
346
+ const snapshot = {
347
+ entities: new Map(prev.entities),
348
+ ids: prev.ids.filter((i) => i !== id),
349
+ version: prev.version
350
+ };
351
+ snapshot.entities.delete(id);
352
+ snapshot.version++;
353
+ store.set(entityType, snapshot);
354
+ notifyListeners(entityType, prev);
355
+ }
294
356
  function getSnapshot(entityType) {
295
- return store.get(entityType)?.data ?? [];
357
+ const snap = store.get(entityType);
358
+ if (!snap) return [];
359
+ return materialize(snap);
360
+ }
361
+ function getById(entityType, id) {
362
+ return store.get(entityType)?.entities.get(id) ?? null;
296
363
  }
297
364
  function getVersion(entityType) {
298
365
  return store.get(entityType)?.version ?? 0;
@@ -327,6 +394,20 @@ function useEntityRef(entityType) {
327
394
  }, [entityType]);
328
395
  return useSyncExternalStore(subscribeToStore, getSnapshotStable, () => []);
329
396
  }
397
+ function useEntityById(entityType, id) {
398
+ const versionRef = useRef(0);
399
+ const dataRef = useRef(null);
400
+ const getSnapshotStable = React113__default.useCallback(() => {
401
+ if (!id) return null;
402
+ const currentVersion = getVersion(entityType);
403
+ if (currentVersion !== versionRef.current) {
404
+ versionRef.current = currentVersion;
405
+ dataRef.current = getById(entityType, id);
406
+ }
407
+ return dataRef.current;
408
+ }, [entityType, id]);
409
+ return useSyncExternalStore(subscribeToStore, getSnapshotStable, () => null);
410
+ }
330
411
  function useEntityWatch(entityType, callback) {
331
412
  const callbackRef = useRef(callback);
332
413
  callbackRef.current = callback;
@@ -336,15 +417,21 @@ function useEntityWatch(entityType, callback) {
336
417
  });
337
418
  }, [entityType]);
338
419
  }
339
- var EntityStoreContext = createContext({
340
- advance,
341
- getSnapshot
342
- });
420
+ var contextValue = {
421
+ setAll,
422
+ upsertOne,
423
+ addOne,
424
+ updateOne,
425
+ removeOne,
426
+ getSnapshot,
427
+ getById
428
+ };
429
+ var EntityStoreContext = createContext(contextValue);
343
430
  function useEntityStore() {
344
431
  return useContext(EntityStoreContext);
345
432
  }
346
433
  function EntityStoreProvider({ children }) {
347
- return /* @__PURE__ */ jsx(EntityStoreContext.Provider, { value: { advance, getSnapshot }, children });
434
+ return /* @__PURE__ */ jsx(EntityStoreContext.Provider, { value: contextValue, children });
348
435
  }
349
436
  function setGlobalEventBus(bus) {
350
437
  if (typeof window !== "undefined") {
@@ -519,7 +606,7 @@ function EventBusProvider({ children, debug: debug2 = false }) {
519
606
  }
520
607
  };
521
608
  }, [debug2]);
522
- const contextValue = useMemo(
609
+ const contextValue2 = useMemo(
523
610
  () => ({
524
611
  emit,
525
612
  on,
@@ -532,12 +619,12 @@ function EventBusProvider({ children, debug: debug2 = false }) {
532
619
  [emit, on, once, hasListeners, onAny, getSelectedEntity, clearSelectedEntity]
533
620
  );
534
621
  useEffect(() => {
535
- setGlobalEventBus(contextValue);
622
+ setGlobalEventBus(contextValue2);
536
623
  return () => {
537
624
  setGlobalEventBus(null);
538
625
  };
539
- }, [contextValue]);
540
- return /* @__PURE__ */ jsx(EventBusContext2.Provider, { value: contextValue, children });
626
+ }, [contextValue2]);
627
+ return /* @__PURE__ */ jsx(EventBusContext2.Provider, { value: contextValue2, children });
541
628
  }
542
629
  var SelectionContext = createContext(null);
543
630
  var defaultCompareEntities = (a, b) => {
@@ -607,13 +694,13 @@ function SelectionProvider({
607
694
  unsubCancel();
608
695
  };
609
696
  }, [eventBus, setSelected, clearSelection, debug2]);
610
- const contextValue = {
697
+ const contextValue2 = {
611
698
  selected,
612
699
  setSelected,
613
700
  clearSelection,
614
701
  isSelected
615
702
  };
616
- return /* @__PURE__ */ jsx(SelectionContext.Provider, { value: contextValue, children });
703
+ return /* @__PURE__ */ jsx(SelectionContext.Provider, { value: contextValue2, children });
617
704
  }
618
705
  function useSelection() {
619
706
  const context = useContext(SelectionContext);
@@ -3006,13 +3093,13 @@ function getState() {
3006
3093
  }
3007
3094
  return { checks: /* @__PURE__ */ new Map(), transitions: [], bridgeHealth: null, listeners: /* @__PURE__ */ new Set() };
3008
3095
  }
3009
- function notifyListeners() {
3096
+ function notifyListeners2() {
3010
3097
  getState().listeners.forEach((l) => l());
3011
3098
  exposeOnWindow();
3012
3099
  }
3013
3100
  function registerCheck(id, label, status = "pending", details) {
3014
3101
  getState().checks.set(id, { id, label, status, details, updatedAt: Date.now() });
3015
- notifyListeners();
3102
+ notifyListeners2();
3016
3103
  }
3017
3104
  function getAllChecks() {
3018
3105
  return Array.from(getState().checks.values());
@@ -3056,7 +3143,7 @@ function recordTransition(trace) {
3056
3143
  failedEffects.map((e) => `${e.type}: ${e.error}`).join("; ")
3057
3144
  );
3058
3145
  }
3059
- notifyListeners();
3146
+ notifyListeners2();
3060
3147
  }
3061
3148
  function getTransitions() {
3062
3149
  return [...getState().transitions];
@@ -3302,6 +3389,42 @@ var orbStyleOverrides = {
3302
3389
  "orb-op-async": { color: ORB_COLORS.dark.async }
3303
3390
  };
3304
3391
  var orbStyle = { ...dark, ...orbStyleOverrides };
3392
+ function computeFoldRegions(code) {
3393
+ const lines = code.split("\n");
3394
+ const regions = [];
3395
+ const stack = [];
3396
+ for (let i = 0; i < lines.length; i++) {
3397
+ const line = lines[i];
3398
+ let inString = false;
3399
+ for (let j = 0; j < line.length; j++) {
3400
+ const ch = line[j];
3401
+ if (ch === "\\" && inString) {
3402
+ j++;
3403
+ continue;
3404
+ }
3405
+ if (ch === '"') {
3406
+ inString = !inString;
3407
+ continue;
3408
+ }
3409
+ if (inString) continue;
3410
+ if (ch === "{" || ch === "[") {
3411
+ stack.push({ line: i, bracket: ch });
3412
+ } else if (ch === "}" || ch === "]") {
3413
+ const open = stack.pop();
3414
+ if (open && open.line < i) {
3415
+ regions.push({
3416
+ start: open.line,
3417
+ end: i,
3418
+ closeBracket: ch
3419
+ });
3420
+ }
3421
+ }
3422
+ }
3423
+ }
3424
+ return regions.sort((a, b) => a.start - b.start);
3425
+ }
3426
+ var LINE_PROPS_FN = (n) => ({ "data-line": String(n - 1) });
3427
+ var HIDDEN_LINE_NUMBERS = { display: "none" };
3305
3428
  var CodeBlock = React113__default.memo(
3306
3429
  ({
3307
3430
  code: rawCode,
@@ -3309,6 +3432,7 @@ var CodeBlock = React113__default.memo(
3309
3432
  showCopyButton = true,
3310
3433
  showLanguageBadge = true,
3311
3434
  maxHeight = "60vh",
3435
+ foldable: foldableProp,
3312
3436
  className
3313
3437
  }) => {
3314
3438
  const code = typeof rawCode === "string" ? rawCode : String(rawCode ?? "");
@@ -3317,8 +3441,114 @@ var CodeBlock = React113__default.memo(
3317
3441
  const eventBus = useEventBus();
3318
3442
  const { t: _t } = useTranslate();
3319
3443
  const scrollRef = useRef(null);
3444
+ const codeRef = useRef(null);
3320
3445
  const savedScrollLeftRef = useRef(0);
3321
3446
  const [copied, setCopied] = useState(false);
3447
+ const isFoldable = foldableProp ?? (language === "orb" || language === "json");
3448
+ const [collapsed, setCollapsed] = useState(() => /* @__PURE__ */ new Set());
3449
+ const foldRegions = useMemo(
3450
+ () => isFoldable ? computeFoldRegions(code) : [],
3451
+ [code, isFoldable]
3452
+ );
3453
+ const foldStartMap = useMemo(() => {
3454
+ const m = /* @__PURE__ */ new Map();
3455
+ for (const r of foldRegions) m.set(r.start, r);
3456
+ return m;
3457
+ }, [foldRegions]);
3458
+ const hiddenLines = useMemo(() => {
3459
+ const h = /* @__PURE__ */ new Set();
3460
+ for (const r of foldRegions) {
3461
+ if (!collapsed.has(r.start)) continue;
3462
+ for (let i = r.start + 1; i <= r.end; i++) h.add(i);
3463
+ }
3464
+ return h;
3465
+ }, [foldRegions, collapsed]);
3466
+ const collapsedRef = useRef(collapsed);
3467
+ collapsedRef.current = collapsed;
3468
+ const foldStartMapRef = useRef(foldStartMap);
3469
+ foldStartMapRef.current = foldStartMap;
3470
+ const toggleFold = useCallback((lineNum) => {
3471
+ setCollapsed((prev) => {
3472
+ const next = new Set(prev);
3473
+ if (next.has(lineNum)) next.delete(lineNum);
3474
+ else next.add(lineNum);
3475
+ return next;
3476
+ });
3477
+ }, []);
3478
+ const toggleFoldRef = useRef(toggleFold);
3479
+ toggleFoldRef.current = toggleFold;
3480
+ useEffect(() => {
3481
+ setCollapsed(/* @__PURE__ */ new Set());
3482
+ }, [code]);
3483
+ const highlightedElement = useMemo(
3484
+ () => /* @__PURE__ */ jsx(
3485
+ SyntaxHighlighter,
3486
+ {
3487
+ PreTag: "div",
3488
+ language,
3489
+ style: activeStyle,
3490
+ wrapLines: true,
3491
+ showLineNumbers: true,
3492
+ showInlineLineNumbers: false,
3493
+ lineNumberContainerStyle: HIDDEN_LINE_NUMBERS,
3494
+ lineProps: LINE_PROPS_FN,
3495
+ customStyle: {
3496
+ backgroundColor: "transparent",
3497
+ borderRadius: 0,
3498
+ padding: 0,
3499
+ margin: 0,
3500
+ whiteSpace: "pre",
3501
+ minWidth: "100%"
3502
+ },
3503
+ children: code
3504
+ }
3505
+ ),
3506
+ [code, language, activeStyle]
3507
+ );
3508
+ useLayoutEffect(() => {
3509
+ const container = codeRef.current;
3510
+ if (!container) return;
3511
+ container.querySelectorAll(".fold-toggle, .fold-summary").forEach((el) => el.remove());
3512
+ const lineEls = container.querySelectorAll("[data-line]");
3513
+ if (!isFoldable || foldRegions.length === 0) {
3514
+ lineEls.forEach((el) => {
3515
+ el.style.display = "";
3516
+ el.style.position = "";
3517
+ el.style.paddingLeft = "";
3518
+ });
3519
+ return;
3520
+ }
3521
+ lineEls.forEach((el) => {
3522
+ const num = parseInt(el.getAttribute("data-line") ?? "-1", 10);
3523
+ if (hiddenLines.has(num)) {
3524
+ el.style.display = "none";
3525
+ return;
3526
+ }
3527
+ el.style.display = "";
3528
+ el.style.position = "relative";
3529
+ el.style.paddingLeft = "1.2em";
3530
+ const region = foldStartMap.get(num);
3531
+ if (!region) return;
3532
+ const isCollapsed = collapsed.has(num);
3533
+ const toggle = document.createElement("span");
3534
+ toggle.className = "fold-toggle";
3535
+ toggle.textContent = isCollapsed ? "\u25B6" : "\u25BC";
3536
+ toggle.style.cssText = "position:absolute;left:0;top:0;width:1.2em;text-align:center;cursor:pointer;color:#858585;font-size:10px;user-select:none;line-height:inherit;height:100%";
3537
+ toggle.addEventListener("click", (e) => {
3538
+ e.stopPropagation();
3539
+ toggleFoldRef.current(num);
3540
+ });
3541
+ el.insertBefore(toggle, el.firstChild);
3542
+ if (isCollapsed) {
3543
+ const summary = document.createElement("span");
3544
+ summary.className = "fold-summary";
3545
+ summary.style.cssText = "color:#858585;font-style:italic";
3546
+ const count = region.end - region.start - 1;
3547
+ summary.textContent = ` ... ${count} line${count !== 1 ? "s" : ""} ${region.closeBracket}`;
3548
+ el.appendChild(summary);
3549
+ }
3550
+ });
3551
+ }, [collapsed, hiddenLines, foldStartMap, foldRegions, isFoldable]);
3322
3552
  useLayoutEffect(() => {
3323
3553
  const el = scrollRef.current;
3324
3554
  return () => {
@@ -3349,8 +3579,9 @@ var CodeBlock = React113__default.memo(
3349
3579
  eventBus.emit("UI:COPY_CODE", { language, success: false });
3350
3580
  }
3351
3581
  };
3582
+ const hasHeader = showLanguageBadge || showCopyButton;
3352
3583
  return /* @__PURE__ */ jsxs(Box, { className: `relative group ${className || ""}`, children: [
3353
- (showLanguageBadge || showCopyButton) && /* @__PURE__ */ jsxs(
3584
+ hasHeader && /* @__PURE__ */ jsxs(
3354
3585
  HStack,
3355
3586
  {
3356
3587
  justify: "between",
@@ -3385,31 +3616,14 @@ var CodeBlock = React113__default.memo(
3385
3616
  touchAction: "pan-x pan-y",
3386
3617
  contain: "paint",
3387
3618
  backgroundColor: "#1e1e1e",
3388
- borderRadius: showLanguageBadge || showCopyButton ? "0 0 0.5rem 0.5rem" : "0.5rem",
3389
- padding: "1rem"
3619
+ borderRadius: hasHeader ? "0 0 0.5rem 0.5rem" : "0.5rem"
3390
3620
  },
3391
- children: /* @__PURE__ */ jsx(
3392
- SyntaxHighlighter,
3393
- {
3394
- PreTag: "div",
3395
- language,
3396
- style: activeStyle,
3397
- customStyle: {
3398
- backgroundColor: "transparent",
3399
- borderRadius: 0,
3400
- padding: 0,
3401
- margin: 0,
3402
- whiteSpace: "pre",
3403
- minWidth: "100%"
3404
- },
3405
- children: code
3406
- }
3407
- )
3621
+ children: /* @__PURE__ */ jsx("div", { ref: codeRef, style: { padding: "1rem" }, children: highlightedElement })
3408
3622
  }
3409
3623
  )
3410
3624
  ] });
3411
3625
  },
3412
- (prev, next) => prev.language === next.language && prev.code === next.code && prev.showCopyButton === next.showCopyButton && prev.maxHeight === next.maxHeight
3626
+ (prev, next) => prev.language === next.language && prev.code === next.code && prev.showCopyButton === next.showCopyButton && prev.maxHeight === next.maxHeight && prev.foldable === next.foldable
3413
3627
  );
3414
3628
  CodeBlock.displayName = "CodeBlock";
3415
3629
 
@@ -3682,7 +3896,7 @@ function FetchedDataProvider({
3682
3896
  },
3683
3897
  [state.data]
3684
3898
  );
3685
- const getById = useCallback(
3899
+ const getById2 = useCallback(
3686
3900
  (entityName, id) => {
3687
3901
  const records = state.data[entityName];
3688
3902
  return records?.find((r) => r.id === id);
@@ -3746,10 +3960,10 @@ function FetchedDataProvider({
3746
3960
  const setError = useCallback((error) => {
3747
3961
  setState((prev) => ({ ...prev, error, loading: false }));
3748
3962
  }, []);
3749
- const contextValue = useMemo(
3963
+ const contextValue2 = useMemo(
3750
3964
  () => ({
3751
3965
  getData,
3752
- getById,
3966
+ getById: getById2,
3753
3967
  hasData,
3754
3968
  getFetchedAt,
3755
3969
  setData,
@@ -3762,7 +3976,7 @@ function FetchedDataProvider({
3762
3976
  }),
3763
3977
  [
3764
3978
  getData,
3765
- getById,
3979
+ getById2,
3766
3980
  hasData,
3767
3981
  getFetchedAt,
3768
3982
  setData,
@@ -3774,7 +3988,7 @@ function FetchedDataProvider({
3774
3988
  setError
3775
3989
  ]
3776
3990
  );
3777
- return /* @__PURE__ */ jsx(FetchedDataContext.Provider, { value: contextValue, children });
3991
+ return /* @__PURE__ */ jsx(FetchedDataContext.Provider, { value: contextValue2, children });
3778
3992
  }
3779
3993
  function useFetchedDataContext() {
3780
3994
  return useContext(FetchedDataContext);
@@ -3828,7 +4042,7 @@ function OfflineModeProvider({
3828
4042
  const [forceOffline, setForceOffline] = useState(false);
3829
4043
  const executor = useOfflineExecutor(executorOptions);
3830
4044
  const effectivelyOffline = executor.isOffline || forceOffline;
3831
- const contextValue = useMemo(
4045
+ const contextValue2 = useMemo(
3832
4046
  () => ({
3833
4047
  ...executor,
3834
4048
  forceOffline,
@@ -3837,7 +4051,7 @@ function OfflineModeProvider({
3837
4051
  }),
3838
4052
  [executor, forceOffline, effectivelyOffline]
3839
4053
  );
3840
- return /* @__PURE__ */ jsx(OfflineModeContext.Provider, { value: contextValue, children });
4054
+ return /* @__PURE__ */ jsx(OfflineModeContext.Provider, { value: contextValue2, children });
3841
4055
  }
3842
4056
  function useOfflineMode() {
3843
4057
  const context = useContext(OfflineModeContext);
@@ -3850,4 +4064,4 @@ function useOptionalOfflineMode() {
3850
4064
  return useContext(OfflineModeContext);
3851
4065
  }
3852
4066
 
3853
- export { EntityStoreContext, EntityStoreProvider, EventBusContext2 as EventBusContext, EventBusProvider, FetchedDataContext, FetchedDataProvider, OfflineModeProvider, OrbitalProvider, SelectionContext, SelectionProvider, VerificationProvider, useEntityRef, useEntityStore, useEntityWatch, useFetchedData, useFetchedDataContext, useFetchedEntity, useOfflineMode, useOptionalOfflineMode, useSelection, useSelectionOptional };
4067
+ export { EntityStoreContext, EntityStoreProvider, EventBusContext2 as EventBusContext, EventBusProvider, FetchedDataContext, FetchedDataProvider, OfflineModeProvider, OrbitalProvider, SelectionContext, SelectionProvider, VerificationProvider, useEntityById, useEntityRef, useEntityStore, useEntityWatch, useFetchedData, useFetchedDataContext, useFetchedEntity, useOfflineMode, useOptionalOfflineMode, useSelection, useSelectionOptional };