@almadar/ui 5.146.3 → 5.148.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.
- package/dist/avl/index.cjs +363 -35
- package/dist/avl/index.js +363 -35
- package/dist/{cn-BdGFhYe3.d.cts → cn-BAn68sNO.d.cts} +92 -2
- package/dist/{cn-DNkqAWZK.d.ts → cn-CWxxLkri.d.ts} +92 -2
- package/dist/components/index.cjs +364 -36
- package/dist/components/index.d.cts +99 -175
- package/dist/components/index.d.ts +99 -175
- package/dist/components/index.js +364 -36
- package/dist/lib/index.cjs +104 -0
- package/dist/lib/index.d.cts +2 -1
- package/dist/lib/index.d.ts +2 -1
- package/dist/lib/index.js +104 -1
- package/dist/providers/index.cjs +363 -35
- package/dist/providers/index.js +363 -35
- package/dist/runtime/index.cjs +363 -35
- package/dist/runtime/index.js +363 -35
- package/package.json +6 -6
- package/themes/bloomberg-dense.css +266 -229
- package/themes/retro.css +30 -30
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { OrbitalSchema, SExpr, Effect, OrbitalVerificationAPI, TraitStateSnapshot, EventPayload, BusEvent, VerificationCheck, BridgeHealth, VerificationSnapshot, VerificationSummary, TransitionTrace, ServerResponseTrace, CheckStatus, AssetLoadStatus } from '@almadar/core';
|
|
2
|
+
import React__default from 'react';
|
|
2
3
|
import { D as DrawableNode } from './paintDispatch-Cb_hQj4Y.js';
|
|
3
4
|
import { ClassValue } from 'clsx';
|
|
4
5
|
|
|
@@ -34,7 +35,7 @@ type ContentSegment = {
|
|
|
34
35
|
* Splits markdown into segments of plain markdown and fenced code blocks.
|
|
35
36
|
* JSON/orb code blocks containing orbital schemas are tagged as 'orbital'.
|
|
36
37
|
*/
|
|
37
|
-
declare function parseMarkdownWithCodeBlocks(content: string | undefined | null): ContentSegment[];
|
|
38
|
+
declare function parseMarkdownWithCodeBlocks$1(content: string | undefined | null): ContentSegment[];
|
|
38
39
|
/**
|
|
39
40
|
* Parse content to extract all segments including quiz tags and code blocks.
|
|
40
41
|
*
|
|
@@ -45,6 +46,95 @@ declare function parseMarkdownWithCodeBlocks(content: string | undefined | null)
|
|
|
45
46
|
*/
|
|
46
47
|
declare function parseContentSegments(content: string | undefined | null): ContentSegment[];
|
|
47
48
|
|
|
49
|
+
/**
|
|
50
|
+
* BloomQuizBlock Molecule Component
|
|
51
|
+
*
|
|
52
|
+
* Practice Q&A with Bloom's Taxonomy level badge. Emits `UI:ANSWER_BLOOM { index, level }`.
|
|
53
|
+
*
|
|
54
|
+
* Event Contract:
|
|
55
|
+
* - Emits: UI:ANSWER_BLOOM { index, level }
|
|
56
|
+
* - entityAware: false
|
|
57
|
+
*/
|
|
58
|
+
|
|
59
|
+
type BloomLevel = 'remember' | 'understand' | 'apply' | 'analyze' | 'evaluate' | 'create';
|
|
60
|
+
interface BloomQuizBlockProps {
|
|
61
|
+
level: BloomLevel;
|
|
62
|
+
question: string;
|
|
63
|
+
answer: string;
|
|
64
|
+
/** Zero-based index (used in the emitted event payload) */
|
|
65
|
+
index?: number;
|
|
66
|
+
/** Whether the learner has already answered */
|
|
67
|
+
isAnswered?: boolean;
|
|
68
|
+
/** Event name emitted on first reveal (as `UI:<answerEvent>`). Defaults to 'ANSWER_BLOOM'. */
|
|
69
|
+
answerEvent?: string;
|
|
70
|
+
/** Additional CSS classes */
|
|
71
|
+
className?: string;
|
|
72
|
+
}
|
|
73
|
+
declare const BloomQuizBlock: React__default.FC<BloomQuizBlockProps>;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Utility for lesson-segment parsing: splits a markdown string into alternating
|
|
77
|
+
* markdown and fenced-code-block segments. Exported so SegmentRenderer and
|
|
78
|
+
* BloomQuizBlock can reuse without circular imports.
|
|
79
|
+
*/
|
|
80
|
+
type MarkdownSegment = {
|
|
81
|
+
type: 'markdown';
|
|
82
|
+
content: string;
|
|
83
|
+
};
|
|
84
|
+
type CodeSegment = {
|
|
85
|
+
type: 'code';
|
|
86
|
+
language: string;
|
|
87
|
+
content: string;
|
|
88
|
+
runnable?: boolean;
|
|
89
|
+
};
|
|
90
|
+
type MixedSegment = MarkdownSegment | CodeSegment;
|
|
91
|
+
/** Splits markdown content into markdown and fenced-code-block segments. */
|
|
92
|
+
declare function parseMarkdownWithCodeBlocks(content: string): MixedSegment[];
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* parseLessonSegments — parses lesson markdown with embedded learning-science
|
|
96
|
+
* XML-style tags into a typed Segment array.
|
|
97
|
+
*
|
|
98
|
+
* Supported tags: <activate>, <connect>, <reflect>, <bloom level="...">,
|
|
99
|
+
* <question>/<answer>, <visualize type="..." description="..." />.
|
|
100
|
+
*
|
|
101
|
+
* Tags may be open (unclosed) — the parser falls back to consuming content
|
|
102
|
+
* until the next recognised tag, a section heading (`\n\n#`), or end-of-input.
|
|
103
|
+
*/
|
|
104
|
+
|
|
105
|
+
type InteractiveOrbitalType = 'algorithms' | 'math' | 'physics' | 'biology' | 'chemistry' | 'probability';
|
|
106
|
+
type LessonSegment = MixedSegment | {
|
|
107
|
+
type: 'quiz';
|
|
108
|
+
question: string;
|
|
109
|
+
answer: string;
|
|
110
|
+
} | {
|
|
111
|
+
type: 'activate';
|
|
112
|
+
question: string;
|
|
113
|
+
} | {
|
|
114
|
+
type: 'connect';
|
|
115
|
+
content: string;
|
|
116
|
+
} | {
|
|
117
|
+
type: 'reflect';
|
|
118
|
+
prompt: string;
|
|
119
|
+
} | {
|
|
120
|
+
type: 'bloom';
|
|
121
|
+
level: BloomLevel;
|
|
122
|
+
question: string;
|
|
123
|
+
answer: string;
|
|
124
|
+
} | {
|
|
125
|
+
type: 'visualization';
|
|
126
|
+
visualizationType: InteractiveOrbitalType;
|
|
127
|
+
description: string;
|
|
128
|
+
};
|
|
129
|
+
/** User progress state passed into SegmentRenderer. */
|
|
130
|
+
interface LessonUserProgress {
|
|
131
|
+
activationResponse?: string;
|
|
132
|
+
reflectionNotes?: string[];
|
|
133
|
+
bloomAnswered?: Record<number, boolean>;
|
|
134
|
+
}
|
|
135
|
+
/** Parse a lesson string into typed segments. Returns `[]` when input is empty. */
|
|
136
|
+
declare function parseLessonSegments(lesson: string | undefined): LessonSegment[];
|
|
137
|
+
|
|
48
138
|
/**
|
|
49
139
|
* Orbital State Machine Visualizer
|
|
50
140
|
*
|
|
@@ -292,4 +382,4 @@ declare function clearVerification(): void;
|
|
|
292
382
|
*/
|
|
293
383
|
declare function cn(...inputs: ClassValue[]): string;
|
|
294
384
|
|
|
295
|
-
export { parseMarkdownWithCodeBlocks as A,
|
|
385
|
+
export { parseMarkdownWithCodeBlocks as $, parseLessonSegments as A, parseMarkdownWithCodeBlocks$1 as B, type ContentSegment as C, DEFAULT_CONFIG as D, type EntityDefinition as E, recordServerResponse as F, recordTransition as G, registerCheck as H, registerTraitSnapshot as I, renderStateMachineToDomData as J, renderStateMachineToSvg as K, type LessonSegment as L, subscribeToVerification as M, updateAssetStatus as N, updateBridgeHealth as O, updateCheck as P, waitForTransition as Q, type RenderOptions as R, type StateDefinition as S, type TraitSnapshotGetter as T, type LessonUserProgress as U, type VisualizerConfig as V, type InteractiveOrbitalType as W, type BloomLevel as X, BloomQuizBlock as Y, type BloomQuizBlockProps as Z, type MixedSegment as _, type DomEntityBox as a, type DomLayoutData as b, type DomOutputsBox as c, type DomStateNode as d, type DomTransitionLabel as e, type DomTransitionPath as f, type StateMachineDefinition as g, type TransitionDefinition as h, bindCanvasCapture as i, bindEventBus as j, bindLastDrawables as k, bindTraitStateGetter as l, clearVerification as m, cn as n, extractOutputsFromTransitions as o, extractStateMachine as p, formatGuard as q, getAllChecks as r, getBridgeHealth as s, getEffectSummary as t, getSnapshot as u, getSummary as v, getTraitSnapshots as w, getTransitions as x, getTransitionsForTrait as y, parseContentSegments as z };
|
|
@@ -8690,7 +8690,10 @@ var init_LearningCanvas = __esm({
|
|
|
8690
8690
|
ctx.fillRect(0, 0, width, height);
|
|
8691
8691
|
}
|
|
8692
8692
|
for (const shape of shapes) {
|
|
8693
|
-
drawShape(ctx, shape, width, height);
|
|
8693
|
+
if (shape.type !== "text") drawShape(ctx, shape, width, height);
|
|
8694
|
+
}
|
|
8695
|
+
for (const shape of shapes) {
|
|
8696
|
+
if (shape.type === "text") drawShape(ctx, shape, width, height);
|
|
8694
8697
|
}
|
|
8695
8698
|
}, [width, height, backgroundColor, shapes]);
|
|
8696
8699
|
React77.useEffect(() => {
|
|
@@ -8771,7 +8774,7 @@ var init_AlgorithmCanvas = __esm({
|
|
|
8771
8774
|
DEFAULT_CELL_COLOR = "#e5e7eb";
|
|
8772
8775
|
DEFAULT_POINTER_COLOR = "#dc2626";
|
|
8773
8776
|
POINTER_BAND = 34;
|
|
8774
|
-
TOP_PAD =
|
|
8777
|
+
TOP_PAD = 26;
|
|
8775
8778
|
exports.AlgorithmCanvas = ({
|
|
8776
8779
|
className,
|
|
8777
8780
|
width = 600,
|
|
@@ -23756,6 +23759,7 @@ var init_FilterGroup = __esm({
|
|
|
23756
23759
|
init_Badge();
|
|
23757
23760
|
init_Stack();
|
|
23758
23761
|
init_Icon();
|
|
23762
|
+
init_RangeSlider();
|
|
23759
23763
|
init_useEventBus();
|
|
23760
23764
|
init_useQuerySingleton();
|
|
23761
23765
|
resolveFilterType = (filter) => filter.filterType ?? filter.type;
|
|
@@ -23950,6 +23954,35 @@ var init_FilterGroup = __esm({
|
|
|
23950
23954
|
onClear: () => handleFilterSelect(`${filter.field}_to`, null)
|
|
23951
23955
|
}
|
|
23952
23956
|
)
|
|
23957
|
+
] }) : resolveFilterType(filter) === "numberrange" || resolveFilterType(filter) === "number-range" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
23958
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
23959
|
+
exports.RangeSlider,
|
|
23960
|
+
{
|
|
23961
|
+
min: filter.min ?? 0,
|
|
23962
|
+
max: filter.max ?? 100,
|
|
23963
|
+
step: filter.step ?? 1,
|
|
23964
|
+
value: Number(
|
|
23965
|
+
selectedValues[`${filter.field}_min`] ?? filter.min ?? 0
|
|
23966
|
+
),
|
|
23967
|
+
onChange: (v) => handleFilterSelect(`${filter.field}_min`, String(v)),
|
|
23968
|
+
showTooltip: true,
|
|
23969
|
+
"aria-label": t("filterGroup.from")
|
|
23970
|
+
}
|
|
23971
|
+
),
|
|
23972
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
23973
|
+
exports.RangeSlider,
|
|
23974
|
+
{
|
|
23975
|
+
min: filter.min ?? 0,
|
|
23976
|
+
max: filter.max ?? 100,
|
|
23977
|
+
step: filter.step ?? 1,
|
|
23978
|
+
value: Number(
|
|
23979
|
+
selectedValues[`${filter.field}_max`] ?? filter.max ?? 100
|
|
23980
|
+
),
|
|
23981
|
+
onChange: (v) => handleFilterSelect(`${filter.field}_max`, String(v)),
|
|
23982
|
+
showTooltip: true,
|
|
23983
|
+
"aria-label": t("filterGroup.to")
|
|
23984
|
+
}
|
|
23985
|
+
)
|
|
23953
23986
|
] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
23954
23987
|
exports.Input,
|
|
23955
23988
|
{
|
|
@@ -24032,6 +24065,36 @@ var init_FilterGroup = __esm({
|
|
|
24032
24065
|
className: "text-sm min-w-[100px]"
|
|
24033
24066
|
}
|
|
24034
24067
|
)
|
|
24068
|
+
] }) : resolveFilterType(filter) === "numberrange" || resolveFilterType(filter) === "number-range" ? /* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "xs", align: "center", children: [
|
|
24069
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
24070
|
+
exports.RangeSlider,
|
|
24071
|
+
{
|
|
24072
|
+
min: filter.min ?? 0,
|
|
24073
|
+
max: filter.max ?? 100,
|
|
24074
|
+
step: filter.step ?? 1,
|
|
24075
|
+
value: Number(
|
|
24076
|
+
selectedValues[`${filter.field}_min`] ?? filter.min ?? 0
|
|
24077
|
+
),
|
|
24078
|
+
onChange: (v) => handleFilterSelect(`${filter.field}_min`, String(v)),
|
|
24079
|
+
className: "min-w-[100px]",
|
|
24080
|
+
"aria-label": t("filterGroup.from")
|
|
24081
|
+
}
|
|
24082
|
+
),
|
|
24083
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "-" }),
|
|
24084
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
24085
|
+
exports.RangeSlider,
|
|
24086
|
+
{
|
|
24087
|
+
min: filter.min ?? 0,
|
|
24088
|
+
max: filter.max ?? 100,
|
|
24089
|
+
step: filter.step ?? 1,
|
|
24090
|
+
value: Number(
|
|
24091
|
+
selectedValues[`${filter.field}_max`] ?? filter.max ?? 100
|
|
24092
|
+
),
|
|
24093
|
+
onChange: (v) => handleFilterSelect(`${filter.field}_max`, String(v)),
|
|
24094
|
+
className: "min-w-[100px]",
|
|
24095
|
+
"aria-label": t("filterGroup.to")
|
|
24096
|
+
}
|
|
24097
|
+
)
|
|
24035
24098
|
] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
24036
24099
|
exports.Input,
|
|
24037
24100
|
{
|
|
@@ -24150,6 +24213,38 @@ var init_FilterGroup = __esm({
|
|
|
24150
24213
|
className: "min-w-[130px]"
|
|
24151
24214
|
}
|
|
24152
24215
|
)
|
|
24216
|
+
] }) : resolveFilterType(filter) === "numberrange" || resolveFilterType(filter) === "number-range" ? /* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "xs", align: "center", children: [
|
|
24217
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
24218
|
+
exports.RangeSlider,
|
|
24219
|
+
{
|
|
24220
|
+
min: filter.min ?? 0,
|
|
24221
|
+
max: filter.max ?? 100,
|
|
24222
|
+
step: filter.step ?? 1,
|
|
24223
|
+
value: Number(
|
|
24224
|
+
selectedValues[`${filter.field}_min`] ?? filter.min ?? 0
|
|
24225
|
+
),
|
|
24226
|
+
onChange: (v) => handleFilterSelect(`${filter.field}_min`, String(v)),
|
|
24227
|
+
showTooltip: true,
|
|
24228
|
+
className: "min-w-[130px]",
|
|
24229
|
+
"aria-label": t("filterGroup.from")
|
|
24230
|
+
}
|
|
24231
|
+
),
|
|
24232
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "-" }),
|
|
24233
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
24234
|
+
exports.RangeSlider,
|
|
24235
|
+
{
|
|
24236
|
+
min: filter.min ?? 0,
|
|
24237
|
+
max: filter.max ?? 100,
|
|
24238
|
+
step: filter.step ?? 1,
|
|
24239
|
+
value: Number(
|
|
24240
|
+
selectedValues[`${filter.field}_max`] ?? filter.max ?? 100
|
|
24241
|
+
),
|
|
24242
|
+
onChange: (v) => handleFilterSelect(`${filter.field}_max`, String(v)),
|
|
24243
|
+
showTooltip: true,
|
|
24244
|
+
className: "min-w-[130px]",
|
|
24245
|
+
"aria-label": t("filterGroup.to")
|
|
24246
|
+
}
|
|
24247
|
+
)
|
|
24153
24248
|
] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
24154
24249
|
exports.Input,
|
|
24155
24250
|
{
|
|
@@ -26299,7 +26394,12 @@ function daysAgo(n) {
|
|
|
26299
26394
|
d.setDate(d.getDate() - n);
|
|
26300
26395
|
return d;
|
|
26301
26396
|
}
|
|
26302
|
-
|
|
26397
|
+
function resolvePresetRange(preset) {
|
|
26398
|
+
if (typeof preset.range === "function") return preset.range();
|
|
26399
|
+
if (preset.range) return preset.range;
|
|
26400
|
+
return TOKEN_RANGES[preset.value]?.() ?? null;
|
|
26401
|
+
}
|
|
26402
|
+
var TOKEN_RANGES, DEFAULT_PRESETS; exports.DateRangePicker = void 0;
|
|
26303
26403
|
var init_DateRangePicker = __esm({
|
|
26304
26404
|
"components/core/molecules/DateRangePicker.tsx"() {
|
|
26305
26405
|
"use client";
|
|
@@ -26309,32 +26409,19 @@ var init_DateRangePicker = __esm({
|
|
|
26309
26409
|
init_Stack();
|
|
26310
26410
|
init_Typography();
|
|
26311
26411
|
init_useEventBus();
|
|
26412
|
+
TOKEN_RANGES = {
|
|
26413
|
+
"7d": () => ({ from: toISODate(daysAgo(7)), to: toISODate(/* @__PURE__ */ new Date()) }),
|
|
26414
|
+
"30d": () => ({ from: toISODate(daysAgo(30)), to: toISODate(/* @__PURE__ */ new Date()) }),
|
|
26415
|
+
month: () => ({ from: toISODate(startOfMonth(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) }),
|
|
26416
|
+
quarter: () => ({ from: toISODate(startOfQuarter(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) }),
|
|
26417
|
+
ytd: () => ({ from: toISODate(startOfYear(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
26418
|
+
};
|
|
26312
26419
|
DEFAULT_PRESETS = [
|
|
26313
|
-
{
|
|
26314
|
-
|
|
26315
|
-
|
|
26316
|
-
|
|
26317
|
-
}
|
|
26318
|
-
{
|
|
26319
|
-
label: "Last 30 days",
|
|
26320
|
-
value: "30d",
|
|
26321
|
-
range: () => ({ from: toISODate(daysAgo(30)), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
26322
|
-
},
|
|
26323
|
-
{
|
|
26324
|
-
label: "This Month",
|
|
26325
|
-
value: "month",
|
|
26326
|
-
range: () => ({ from: toISODate(startOfMonth(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
26327
|
-
},
|
|
26328
|
-
{
|
|
26329
|
-
label: "This Quarter",
|
|
26330
|
-
value: "quarter",
|
|
26331
|
-
range: () => ({ from: toISODate(startOfQuarter(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
26332
|
-
},
|
|
26333
|
-
{
|
|
26334
|
-
label: "YTD",
|
|
26335
|
-
value: "ytd",
|
|
26336
|
-
range: () => ({ from: toISODate(startOfYear(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
26337
|
-
}
|
|
26420
|
+
{ label: "Last 7 days", value: "7d" },
|
|
26421
|
+
{ label: "Last 30 days", value: "30d" },
|
|
26422
|
+
{ label: "This Month", value: "month" },
|
|
26423
|
+
{ label: "This Quarter", value: "quarter" },
|
|
26424
|
+
{ label: "YTD", value: "ytd" }
|
|
26338
26425
|
];
|
|
26339
26426
|
exports.DateRangePicker = ({
|
|
26340
26427
|
from: fromProp,
|
|
@@ -26375,7 +26462,8 @@ var init_DateRangePicker = __esm({
|
|
|
26375
26462
|
);
|
|
26376
26463
|
const handlePreset = React77.useCallback(
|
|
26377
26464
|
(preset) => {
|
|
26378
|
-
const range = preset
|
|
26465
|
+
const range = resolvePresetRange(preset);
|
|
26466
|
+
if (range === null) return;
|
|
26379
26467
|
setFrom(range.from);
|
|
26380
26468
|
setTo(range.to);
|
|
26381
26469
|
setActivePreset(preset.value);
|
|
@@ -26383,8 +26471,12 @@ var init_DateRangePicker = __esm({
|
|
|
26383
26471
|
},
|
|
26384
26472
|
[emit]
|
|
26385
26473
|
);
|
|
26474
|
+
const renderablePresets = React77.useMemo(
|
|
26475
|
+
() => presets.filter((p) => p.range !== void 0 || TOKEN_RANGES[p.value] !== void 0),
|
|
26476
|
+
[presets]
|
|
26477
|
+
);
|
|
26386
26478
|
const presetButtons = React77.useMemo(
|
|
26387
|
-
() =>
|
|
26479
|
+
() => renderablePresets.map((preset) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
26388
26480
|
exports.Button,
|
|
26389
26481
|
{
|
|
26390
26482
|
variant: activePreset === preset.value ? "primary" : "ghost",
|
|
@@ -26394,7 +26486,7 @@ var init_DateRangePicker = __esm({
|
|
|
26394
26486
|
},
|
|
26395
26487
|
preset.value
|
|
26396
26488
|
)),
|
|
26397
|
-
[
|
|
26489
|
+
[renderablePresets, activePreset, handlePreset]
|
|
26398
26490
|
);
|
|
26399
26491
|
return /* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { gap: "sm", className: cn(className), children: [
|
|
26400
26492
|
/* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "md", align: "end", children: [
|
|
@@ -26421,7 +26513,7 @@ var init_DateRangePicker = __esm({
|
|
|
26421
26513
|
)
|
|
26422
26514
|
] })
|
|
26423
26515
|
] }),
|
|
26424
|
-
|
|
26516
|
+
renderablePresets.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(exports.HStack, { gap: "xs", wrap: true, children: presetButtons })
|
|
26425
26517
|
] });
|
|
26426
26518
|
};
|
|
26427
26519
|
exports.DateRangePicker.displayName = "DateRangePicker";
|
|
@@ -29297,6 +29389,208 @@ var init_PhysicsCanvas = __esm({
|
|
|
29297
29389
|
};
|
|
29298
29390
|
}
|
|
29299
29391
|
});
|
|
29392
|
+
|
|
29393
|
+
// lib/graphViewLayouts.ts
|
|
29394
|
+
function buildAdjacency(nodeIds, edges) {
|
|
29395
|
+
const known = new Set(nodeIds);
|
|
29396
|
+
const out = /* @__PURE__ */ new Map();
|
|
29397
|
+
const inMap = /* @__PURE__ */ new Map();
|
|
29398
|
+
for (const id of nodeIds) {
|
|
29399
|
+
out.set(id, []);
|
|
29400
|
+
inMap.set(id, []);
|
|
29401
|
+
}
|
|
29402
|
+
for (const edge of edges) {
|
|
29403
|
+
if (!known.has(edge.source) || !known.has(edge.target)) continue;
|
|
29404
|
+
out.get(edge.source)?.push(edge.target);
|
|
29405
|
+
inMap.get(edge.target)?.push(edge.source);
|
|
29406
|
+
}
|
|
29407
|
+
return { out, in: inMap };
|
|
29408
|
+
}
|
|
29409
|
+
function findRoots(nodeIds, adjacency) {
|
|
29410
|
+
return nodeIds.filter((id) => (adjacency.in.get(id)?.length ?? 0) === 0);
|
|
29411
|
+
}
|
|
29412
|
+
function assignLayers(nodeIds, adjacency, roots) {
|
|
29413
|
+
const layer = new Map(nodeIds.map((id) => [id, 0]));
|
|
29414
|
+
const onStack = /* @__PURE__ */ new Set();
|
|
29415
|
+
const visit = (id) => {
|
|
29416
|
+
onStack.add(id);
|
|
29417
|
+
const currentLayer = layer.get(id) ?? 0;
|
|
29418
|
+
for (const next of adjacency.out.get(id) ?? []) {
|
|
29419
|
+
if (onStack.has(next)) continue;
|
|
29420
|
+
const candidate = currentLayer + 1;
|
|
29421
|
+
if (candidate > (layer.get(next) ?? 0)) {
|
|
29422
|
+
layer.set(next, candidate);
|
|
29423
|
+
}
|
|
29424
|
+
visit(next);
|
|
29425
|
+
}
|
|
29426
|
+
onStack.delete(id);
|
|
29427
|
+
};
|
|
29428
|
+
for (const root of roots) visit(root);
|
|
29429
|
+
return layer;
|
|
29430
|
+
}
|
|
29431
|
+
function computeVisitOrder(nodeIds, adjacency, roots) {
|
|
29432
|
+
const order = /* @__PURE__ */ new Map();
|
|
29433
|
+
const visited = /* @__PURE__ */ new Set();
|
|
29434
|
+
let counter = 0;
|
|
29435
|
+
const visit = (id) => {
|
|
29436
|
+
if (visited.has(id)) return;
|
|
29437
|
+
visited.add(id);
|
|
29438
|
+
order.set(id, counter++);
|
|
29439
|
+
for (const next of adjacency.out.get(id) ?? []) visit(next);
|
|
29440
|
+
};
|
|
29441
|
+
for (const root of roots) visit(root);
|
|
29442
|
+
for (const id of nodeIds) {
|
|
29443
|
+
if (!visited.has(id)) order.set(id, counter++);
|
|
29444
|
+
}
|
|
29445
|
+
return order;
|
|
29446
|
+
}
|
|
29447
|
+
function bfsDepthAndOrder(nodeIds, adjacency, roots) {
|
|
29448
|
+
const depth = new Map(nodeIds.map((id) => [id, 0]));
|
|
29449
|
+
const visitOrder = /* @__PURE__ */ new Map();
|
|
29450
|
+
const visited = /* @__PURE__ */ new Set();
|
|
29451
|
+
const queue = [];
|
|
29452
|
+
let counter = 0;
|
|
29453
|
+
for (const root of roots) {
|
|
29454
|
+
if (visited.has(root)) continue;
|
|
29455
|
+
visited.add(root);
|
|
29456
|
+
depth.set(root, 0);
|
|
29457
|
+
visitOrder.set(root, counter++);
|
|
29458
|
+
queue.push(root);
|
|
29459
|
+
}
|
|
29460
|
+
let head = 0;
|
|
29461
|
+
while (head < queue.length) {
|
|
29462
|
+
const id = queue[head++];
|
|
29463
|
+
const d = depth.get(id) ?? 0;
|
|
29464
|
+
for (const next of adjacency.out.get(id) ?? []) {
|
|
29465
|
+
if (visited.has(next)) continue;
|
|
29466
|
+
visited.add(next);
|
|
29467
|
+
depth.set(next, d + 1);
|
|
29468
|
+
visitOrder.set(next, counter++);
|
|
29469
|
+
queue.push(next);
|
|
29470
|
+
}
|
|
29471
|
+
}
|
|
29472
|
+
for (const id of nodeIds) {
|
|
29473
|
+
if (!visited.has(id)) visitOrder.set(id, counter++);
|
|
29474
|
+
}
|
|
29475
|
+
return { depth, visitOrder };
|
|
29476
|
+
}
|
|
29477
|
+
function edgeWalkOrder(nodeIds, adjacency) {
|
|
29478
|
+
const visited = /* @__PURE__ */ new Set();
|
|
29479
|
+
const result = [];
|
|
29480
|
+
for (const start of nodeIds) {
|
|
29481
|
+
if (visited.has(start)) continue;
|
|
29482
|
+
let current = start;
|
|
29483
|
+
while (current !== void 0 && !visited.has(current)) {
|
|
29484
|
+
visited.add(current);
|
|
29485
|
+
result.push(current);
|
|
29486
|
+
const outs = adjacency.out.get(current) ?? [];
|
|
29487
|
+
current = outs.find((next) => !visited.has(next));
|
|
29488
|
+
}
|
|
29489
|
+
}
|
|
29490
|
+
return result;
|
|
29491
|
+
}
|
|
29492
|
+
function groupByTier(nodeIds, tierOf, maxTier) {
|
|
29493
|
+
const groups = Array.from({ length: maxTier + 1 }, () => []);
|
|
29494
|
+
for (const id of nodeIds) {
|
|
29495
|
+
groups[tierOf.get(id) ?? 0].push(id);
|
|
29496
|
+
}
|
|
29497
|
+
return groups;
|
|
29498
|
+
}
|
|
29499
|
+
function distributeAxis(count, start, end) {
|
|
29500
|
+
if (count <= 0) return [];
|
|
29501
|
+
const slot = (end - start) / count;
|
|
29502
|
+
return Array.from({ length: count }, (_, i) => start + slot * (i + 0.5));
|
|
29503
|
+
}
|
|
29504
|
+
function orderByParentPositionThenInput(group, adjacency, positioned, inputIndex) {
|
|
29505
|
+
const withKey = group.map((id) => {
|
|
29506
|
+
const parentValues = (adjacency.in.get(id) ?? []).map((p) => positioned.get(p)).filter((v) => v !== void 0);
|
|
29507
|
+
const avg = parentValues.length > 0 ? parentValues.reduce((a, b) => a + b, 0) / parentValues.length : Number.POSITIVE_INFINITY;
|
|
29508
|
+
return { id, avg, idx: inputIndex.get(id) ?? 0 };
|
|
29509
|
+
});
|
|
29510
|
+
withKey.sort((a, b) => a.avg !== b.avg ? a.avg - b.avg : a.idx - b.idx);
|
|
29511
|
+
return withKey.map((k) => k.id);
|
|
29512
|
+
}
|
|
29513
|
+
function layoutFlow(nodeIds, adjacency, roots, width, height, margin) {
|
|
29514
|
+
const inputIndex = new Map(nodeIds.map((id, i) => [id, i]));
|
|
29515
|
+
const layers = assignLayers(nodeIds, adjacency, roots);
|
|
29516
|
+
const maxLayer = Math.max(...Array.from(layers.values()));
|
|
29517
|
+
const layerGroups = groupByTier(nodeIds, layers, maxLayer);
|
|
29518
|
+
const positions = /* @__PURE__ */ new Map();
|
|
29519
|
+
const yById = /* @__PURE__ */ new Map();
|
|
29520
|
+
for (let l = 0; l <= maxLayer; l++) {
|
|
29521
|
+
const x = margin + l * (width - 2 * margin) / Math.max(1, maxLayer);
|
|
29522
|
+
const ordered2 = orderByParentPositionThenInput(layerGroups[l], adjacency, yById, inputIndex);
|
|
29523
|
+
const ys = distributeAxis(ordered2.length, margin, height - margin);
|
|
29524
|
+
ordered2.forEach((id, i) => {
|
|
29525
|
+
positions.set(id, { id, x, y: ys[i] });
|
|
29526
|
+
yById.set(id, ys[i]);
|
|
29527
|
+
});
|
|
29528
|
+
}
|
|
29529
|
+
return nodeIds.map((id) => positions.get(id));
|
|
29530
|
+
}
|
|
29531
|
+
function layoutTree(nodeIds, adjacency, roots, width, height, margin) {
|
|
29532
|
+
const effectiveRoots = roots.length > 0 ? roots : [nodeIds[0]];
|
|
29533
|
+
const layers = assignLayers(nodeIds, adjacency, effectiveRoots);
|
|
29534
|
+
const maxLayer = Math.max(...Array.from(layers.values()));
|
|
29535
|
+
const visitOrder = computeVisitOrder(nodeIds, adjacency, effectiveRoots);
|
|
29536
|
+
const layerGroups = groupByTier(nodeIds, layers, maxLayer);
|
|
29537
|
+
const positions = /* @__PURE__ */ new Map();
|
|
29538
|
+
for (let l = 0; l <= maxLayer; l++) {
|
|
29539
|
+
const ordered2 = [...layerGroups[l]].sort(
|
|
29540
|
+
(a, b) => (visitOrder.get(a) ?? 0) - (visitOrder.get(b) ?? 0)
|
|
29541
|
+
);
|
|
29542
|
+
const y = margin + l * (height - 2 * margin) / Math.max(1, maxLayer);
|
|
29543
|
+
const xs = distributeAxis(ordered2.length, margin, width - margin);
|
|
29544
|
+
ordered2.forEach((id, i) => positions.set(id, { id, x: xs[i], y }));
|
|
29545
|
+
}
|
|
29546
|
+
return nodeIds.map((id) => positions.get(id));
|
|
29547
|
+
}
|
|
29548
|
+
function layoutRadial(nodeIds, adjacency, roots, width, height, margin) {
|
|
29549
|
+
const cx = width / 2;
|
|
29550
|
+
const cy = height / 2;
|
|
29551
|
+
const maxRadius = Math.min(width, height) / 2 - margin;
|
|
29552
|
+
if (roots.length === 0) {
|
|
29553
|
+
const order = edgeWalkOrder(nodeIds, adjacency);
|
|
29554
|
+
const k = order.length;
|
|
29555
|
+
const positions2 = /* @__PURE__ */ new Map();
|
|
29556
|
+
order.forEach((id, i) => {
|
|
29557
|
+
const angle = i / k * 2 * Math.PI;
|
|
29558
|
+
positions2.set(id, { id, x: cx + maxRadius * Math.cos(angle), y: cy + maxRadius * Math.sin(angle) });
|
|
29559
|
+
});
|
|
29560
|
+
return nodeIds.map((id) => positions2.get(id));
|
|
29561
|
+
}
|
|
29562
|
+
const { depth, visitOrder } = bfsDepthAndOrder(nodeIds, adjacency, roots);
|
|
29563
|
+
const maxDepth = Math.max(...Array.from(depth.values()));
|
|
29564
|
+
const ringGroups = groupByTier(nodeIds, depth, maxDepth);
|
|
29565
|
+
const positions = /* @__PURE__ */ new Map();
|
|
29566
|
+
for (let d = 0; d <= maxDepth; d++) {
|
|
29567
|
+
const ordered2 = [...ringGroups[d]].sort(
|
|
29568
|
+
(a, b) => (visitOrder.get(a) ?? 0) - (visitOrder.get(b) ?? 0)
|
|
29569
|
+
);
|
|
29570
|
+
const radius = d * maxRadius / Math.max(1, maxDepth);
|
|
29571
|
+
const k = ordered2.length;
|
|
29572
|
+
ordered2.forEach((id, i) => {
|
|
29573
|
+
const angle = i / k * 2 * Math.PI;
|
|
29574
|
+
positions.set(id, { id, x: cx + radius * Math.cos(angle), y: cy + radius * Math.sin(angle) });
|
|
29575
|
+
});
|
|
29576
|
+
}
|
|
29577
|
+
return nodeIds.map((id) => positions.get(id));
|
|
29578
|
+
}
|
|
29579
|
+
function computeStaticLayout(mode, input) {
|
|
29580
|
+
const { nodeIds, edges, width, height } = input;
|
|
29581
|
+
const margin = input.margin ?? 40;
|
|
29582
|
+
if (nodeIds.length === 0) return [];
|
|
29583
|
+
if (nodeIds.length === 1) return [{ id: nodeIds[0], x: width / 2, y: height / 2 }];
|
|
29584
|
+
const adjacency = buildAdjacency(nodeIds, edges);
|
|
29585
|
+
const roots = findRoots(nodeIds, adjacency);
|
|
29586
|
+
if (mode === "flow") return layoutFlow(nodeIds, adjacency, roots, width, height, margin);
|
|
29587
|
+
if (mode === "tree") return layoutTree(nodeIds, adjacency, roots, width, height, margin);
|
|
29588
|
+
return layoutRadial(nodeIds, adjacency, roots, width, height, margin);
|
|
29589
|
+
}
|
|
29590
|
+
var init_graphViewLayouts = __esm({
|
|
29591
|
+
"lib/graphViewLayouts.ts"() {
|
|
29592
|
+
}
|
|
29593
|
+
});
|
|
29300
29594
|
function resolveNodeColor(node, groups) {
|
|
29301
29595
|
if (node.color) return node.color;
|
|
29302
29596
|
if (node.group) {
|
|
@@ -29311,6 +29605,7 @@ var init_GraphView = __esm({
|
|
|
29311
29605
|
"use client";
|
|
29312
29606
|
init_cn();
|
|
29313
29607
|
init_atoms();
|
|
29608
|
+
init_graphViewLayouts();
|
|
29314
29609
|
GROUP_COLORS = [
|
|
29315
29610
|
"#3b82f6",
|
|
29316
29611
|
// blue-500
|
|
@@ -29341,11 +29636,13 @@ var init_GraphView = __esm({
|
|
|
29341
29636
|
height: propHeight,
|
|
29342
29637
|
className,
|
|
29343
29638
|
showLabels = true,
|
|
29344
|
-
zoomToFit = true
|
|
29639
|
+
zoomToFit = true,
|
|
29640
|
+
layout = "force"
|
|
29345
29641
|
}) => {
|
|
29346
29642
|
const { t } = hooks.useTranslate();
|
|
29347
29643
|
const containerRef = React77.useRef(null);
|
|
29348
29644
|
const animRef = React77.useRef(0);
|
|
29645
|
+
const arrowMarkerId = React77.useId();
|
|
29349
29646
|
const [simNodes, setSimNodes] = React77.useState([]);
|
|
29350
29647
|
const [settled, setSettled] = React77.useState(false);
|
|
29351
29648
|
const [hoveredId, setHoveredId] = React77.useState(null);
|
|
@@ -29402,6 +29699,22 @@ var init_GraphView = __esm({
|
|
|
29402
29699
|
fy: 0
|
|
29403
29700
|
};
|
|
29404
29701
|
});
|
|
29702
|
+
if (layout !== "force") {
|
|
29703
|
+
const points = computeStaticLayout(layout, {
|
|
29704
|
+
nodeIds: nodes.map((n) => n.id),
|
|
29705
|
+
edges,
|
|
29706
|
+
width: w,
|
|
29707
|
+
height: h
|
|
29708
|
+
});
|
|
29709
|
+
const pointById = new Map(points.map((p) => [p.id, p]));
|
|
29710
|
+
const laidOut = initialNodes.map((node) => {
|
|
29711
|
+
const point = pointById.get(node.id);
|
|
29712
|
+
return point ? { ...node, x: point.x, y: point.y } : node;
|
|
29713
|
+
});
|
|
29714
|
+
setSimNodes(laidOut);
|
|
29715
|
+
setSettled(true);
|
|
29716
|
+
return;
|
|
29717
|
+
}
|
|
29405
29718
|
let iterations = 0;
|
|
29406
29719
|
const maxIterations = 120;
|
|
29407
29720
|
let currentNodes = initialNodes;
|
|
@@ -29470,7 +29783,7 @@ var init_GraphView = __esm({
|
|
|
29470
29783
|
return () => {
|
|
29471
29784
|
cancelAnimationFrame(animRef.current);
|
|
29472
29785
|
};
|
|
29473
|
-
}, [nodes, edges, w, h, groups]);
|
|
29786
|
+
}, [nodes, edges, w, h, groups, layout]);
|
|
29474
29787
|
const viewBox = React77.useMemo(() => {
|
|
29475
29788
|
if (!zoomToFit || !settled || simNodes.length === 0) {
|
|
29476
29789
|
return `0 0 ${w} ${h}`;
|
|
@@ -29545,6 +29858,19 @@ var init_GraphView = __esm({
|
|
|
29545
29858
|
viewBox,
|
|
29546
29859
|
preserveAspectRatio: "xMidYMid meet",
|
|
29547
29860
|
children: [
|
|
29861
|
+
layout !== "force" && /* @__PURE__ */ jsxRuntime.jsx("defs", { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
29862
|
+
"marker",
|
|
29863
|
+
{
|
|
29864
|
+
id: arrowMarkerId,
|
|
29865
|
+
viewBox: "0 0 10 10",
|
|
29866
|
+
refX: "9",
|
|
29867
|
+
refY: "5",
|
|
29868
|
+
markerWidth: "6",
|
|
29869
|
+
markerHeight: "6",
|
|
29870
|
+
orient: "auto-start-reverse",
|
|
29871
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M0,0 L10,5 L0,10 z", fill: "currentColor" })
|
|
29872
|
+
}
|
|
29873
|
+
) }),
|
|
29548
29874
|
edges.map((edge, idx) => {
|
|
29549
29875
|
const source = nodeMap.get(edge.source);
|
|
29550
29876
|
const target = nodeMap.get(edge.target);
|
|
@@ -29559,8 +29885,10 @@ var init_GraphView = __esm({
|
|
|
29559
29885
|
x2: target.x,
|
|
29560
29886
|
y2: target.y,
|
|
29561
29887
|
stroke: edge.color ?? DEFAULT_EDGE_COLOR,
|
|
29888
|
+
color: edge.color ?? DEFAULT_EDGE_COLOR,
|
|
29562
29889
|
strokeWidth: 1.5,
|
|
29563
|
-
opacity: isHighlighted ? 0.8 : 0.15
|
|
29890
|
+
opacity: isHighlighted ? 0.8 : 0.15,
|
|
29891
|
+
markerEnd: layout !== "force" ? `url(#${arrowMarkerId})` : void 0
|
|
29564
29892
|
}
|
|
29565
29893
|
),
|
|
29566
29894
|
showLabels && edge.label && /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -39351,7 +39679,7 @@ function parseLessonSegments(lesson) {
|
|
|
39351
39679
|
content = content.replace(connectResult.fullMatch, "").trim();
|
|
39352
39680
|
}
|
|
39353
39681
|
const tagRegex = new RegExp(
|
|
39354
|
-
'(?<reflect><reflect>(?<reflectClosed>[\\s\\S]*?)<\\/reflect>)|(?<reflectUnclosed><reflect>(?<reflectOpen>[\\s\\S]*?)(?=<(?:activate|connect|reflect|bloom|prq|question|answer|visualize)|\\n\\n#|$))|(?<bloom><bloom\\s+level="(?<bloomLevel>remember|understand|apply|analyze|evaluate|create)">(?<bloomClosed>[\\s\\S]*?)<\\/bloom>)|(?<bloomUnclosed><bloom\\s+level="(?<bloomLevelUn>remember|understand|apply|analyze|evaluate|create)">(?<bloomOpen>[\\s\\S]*?)(?=<(?:activate|connect|reflect|bloom|prq|question|answer|visualize)|\\n\\n#|$))|(?<quiz><question>(?<quizQuestion>[\\s\\S]*?)<\\/question>\\s*<answer>(?<quizAnswer>[\\s\\S]*?)<\\/answer>)|(?<visualize><visualize\\s+type="(?<vizType>algorithms|math|physics|biology|chemistry|probability
|
|
39682
|
+
'(?<reflect><reflect>(?<reflectClosed>[\\s\\S]*?)<\\/reflect>)|(?<reflectUnclosed><reflect>(?<reflectOpen>[\\s\\S]*?)(?=<(?:activate|connect|reflect|bloom|prq|question|answer|visualize)|\\n\\n#|$))|(?<bloom><bloom\\s+level="(?<bloomLevel>remember|understand|apply|analyze|evaluate|create)">(?<bloomClosed>[\\s\\S]*?)<\\/bloom>)|(?<bloomUnclosed><bloom\\s+level="(?<bloomLevelUn>remember|understand|apply|analyze|evaluate|create)">(?<bloomOpen>[\\s\\S]*?)(?=<(?:activate|connect|reflect|bloom|prq|question|answer|visualize)|\\n\\n#|$))|(?<quiz><question>(?<quizQuestion>[\\s\\S]*?)<\\/question>\\s*<answer>(?<quizAnswer>[\\s\\S]*?)<\\/answer>)|(?<visualize><visualize\\s+type="(?<vizType>algorithms|math|physics|biology|chemistry|probability)"\\s+description="(?<vizDesc>[^"]*?)"\\s*\\/?>)',
|
|
39355
39683
|
"gi"
|
|
39356
39684
|
);
|
|
39357
39685
|
let lastIndex = 0;
|