@arbidocs/blocks 0.4.108 → 0.4.110
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/{NativeDocxEditor-UAZUKZ77.js → NativeDocxEditor-4PY4YZYC.js} +3 -3
- package/dist/{NativeDocxEditor-UAZUKZ77.js.map → NativeDocxEditor-4PY4YZYC.js.map} +1 -1
- package/dist/{NativeDocxEditor-YX7B7OFH.cjs → NativeDocxEditor-WODZAURG.cjs} +7 -7
- package/dist/{NativeDocxEditor-YX7B7OFH.cjs.map → NativeDocxEditor-WODZAURG.cjs.map} +1 -1
- package/dist/agents/index.cjs +286 -286
- package/dist/agents/index.js +10 -10
- package/dist/agents/tasks/ConversationListView.d.ts +5 -1
- package/dist/agents/tasks/TaskActivityTimeline.d.ts +5 -1
- package/dist/calendar/EventDetails.d.ts +1 -1
- package/dist/calendar/index.cjs +13 -0
- package/dist/calendar/index.cjs.map +1 -1
- package/dist/calendar/index.js +13 -0
- package/dist/calendar/index.js.map +1 -1
- package/dist/calendar/types.d.ts +3 -0
- package/dist/calls/CallSidePanel.d.ts +17 -0
- package/dist/calls/CallStage.d.ts +57 -0
- package/dist/calls/ControlBar.d.ts +91 -0
- package/dist/calls/ControlButton.d.ts +44 -0
- package/dist/calls/PreJoin.d.ts +31 -0
- package/dist/calls/cards.d.ts +54 -0
- package/dist/calls/hooks.d.ts +20 -0
- package/dist/calls/index.cjs +1853 -0
- package/dist/calls/index.cjs.map +1 -0
- package/dist/calls/index.d.ts +20 -0
- package/dist/calls/index.js +1737 -0
- package/dist/calls/index.js.map +1 -0
- package/dist/calls/join-choices.d.ts +11 -0
- package/dist/calls/layout.d.ts +106 -0
- package/dist/calls/panels.d.ts +55 -0
- package/dist/calls/status.d.ts +69 -0
- package/dist/calls/tiles.d.ts +59 -0
- package/dist/chat/Message.d.ts +17 -2
- package/dist/chat/TranscriptLine.d.ts +50 -0
- package/dist/chat/index.cjs +147 -126
- package/dist/chat/index.d.ts +3 -1
- package/dist/chat/index.js +5 -4
- package/dist/chat/transcript-runs.d.ts +6 -0
- package/dist/{chunk-QT6EGMAJ.cjs → chunk-2NIL2ASF.cjs} +38 -294
- package/dist/chunk-2NIL2ASF.cjs.map +1 -0
- package/dist/{chunk-XMBYDLZQ.cjs → chunk-2UAJVK3C.cjs} +4 -4
- package/dist/{chunk-XMBYDLZQ.cjs.map → chunk-2UAJVK3C.cjs.map} +1 -1
- package/dist/{chunk-TTXK62YI.cjs → chunk-54WBIVHV.cjs} +5 -5
- package/dist/{chunk-TTXK62YI.cjs.map → chunk-54WBIVHV.cjs.map} +1 -1
- package/dist/{chunk-7C35WXYB.js → chunk-5HFPRI3W.js} +5 -5
- package/dist/chunk-5HFPRI3W.js.map +1 -0
- package/dist/{chunk-S7RHJI5Q.js → chunk-6RHHMBZ5.js} +158 -5
- package/dist/chunk-6RHHMBZ5.js.map +1 -0
- package/dist/{chunk-3Y6NQIDE.js → chunk-A35KT2II.js} +37 -19
- package/dist/chunk-A35KT2II.js.map +1 -0
- package/dist/{chunk-PGDL26TQ.js → chunk-AY32GGKU.js} +10 -4
- package/dist/{chunk-PGDL26TQ.js.map → chunk-AY32GGKU.js.map} +1 -1
- package/dist/{chunk-IXALYQT7.cjs → chunk-C2CWWEHO.cjs} +2 -2
- package/dist/chunk-C2CWWEHO.cjs.map +1 -0
- package/dist/{chunk-S55VDTX3.js → chunk-CECWAIHL.js} +3 -3
- package/dist/{chunk-S55VDTX3.js.map → chunk-CECWAIHL.js.map} +1 -1
- package/dist/{chunk-XQDM6T6C.js → chunk-CXZ7FPTQ.js} +3 -3
- package/dist/{chunk-XQDM6T6C.js.map → chunk-CXZ7FPTQ.js.map} +1 -1
- package/dist/{chunk-C2HRZSAT.cjs → chunk-DJM7DLCT.cjs} +5 -5
- package/dist/chunk-DJM7DLCT.cjs.map +1 -0
- package/dist/{chunk-XQKGYGCJ.js → chunk-DQCYCEDR.js} +3 -3
- package/dist/{chunk-XQKGYGCJ.js.map → chunk-DQCYCEDR.js.map} +1 -1
- package/dist/{chunk-ZYSY4L5L.cjs → chunk-ELDUWTRR.cjs} +4 -4
- package/dist/{chunk-ZYSY4L5L.cjs.map → chunk-ELDUWTRR.cjs.map} +1 -1
- package/dist/{chunk-A2MN2ZLX.js → chunk-GKDWQLVU.js} +13 -274
- package/dist/chunk-GKDWQLVU.js.map +1 -0
- package/dist/{chunk-24ND4S6Y.cjs → chunk-HBBJYRGI.cjs} +162 -5
- package/dist/{chunk-S7RHJI5Q.js.map → chunk-HBBJYRGI.cjs.map} +1 -1
- package/dist/{chunk-P2KPDPFF.js → chunk-IXTQYFIF.js} +23 -15
- package/dist/chunk-IXTQYFIF.js.map +1 -0
- package/dist/{chunk-JQVPGMLU.js → chunk-JB32KYAH.js} +3 -3
- package/dist/{chunk-JQVPGMLU.js.map → chunk-JB32KYAH.js.map} +1 -1
- package/dist/{chunk-PBS5MFIY.cjs → chunk-JK45LSIH.cjs} +3 -3
- package/dist/{chunk-PBS5MFIY.cjs.map → chunk-JK45LSIH.cjs.map} +1 -1
- package/dist/chunk-MWDW5UBW.cjs +199 -0
- package/dist/chunk-MWDW5UBW.cjs.map +1 -0
- package/dist/{chunk-ZPLG7QYF.js → chunk-N5YEF3LC.js} +2 -2
- package/dist/chunk-N5YEF3LC.js.map +1 -0
- package/dist/{chunk-EWSEQEPL.js → chunk-NRUPUDWB.js} +17 -7
- package/dist/chunk-NRUPUDWB.js.map +1 -0
- package/dist/{chunk-DDF5GPIJ.js → chunk-P5ST47VY.js} +3 -3
- package/dist/{chunk-DDF5GPIJ.js.map → chunk-P5ST47VY.js.map} +1 -1
- package/dist/{chunk-EGDWNEAG.js → chunk-PEHLUB52.js} +3 -3
- package/dist/{chunk-EGDWNEAG.js.map → chunk-PEHLUB52.js.map} +1 -1
- package/dist/{chunk-W7NZRZ54.js → chunk-SQNAJPNR.js} +4 -4
- package/dist/{chunk-W7NZRZ54.js.map → chunk-SQNAJPNR.js.map} +1 -1
- package/dist/{chunk-DTBSGG36.cjs → chunk-U6MPHCEB.cjs} +24 -16
- package/dist/chunk-U6MPHCEB.cjs.map +1 -0
- package/dist/{chunk-MP6FK43E.cjs → chunk-VP4KJ4LK.cjs} +17 -6
- package/dist/chunk-VP4KJ4LK.cjs.map +1 -0
- package/dist/{chunk-LLFW2T6S.cjs → chunk-VZKBI2KJ.cjs} +85 -67
- package/dist/chunk-VZKBI2KJ.cjs.map +1 -0
- package/dist/{chunk-5YXG342J.cjs → chunk-W7ZDBPJ3.cjs} +4 -4
- package/dist/{chunk-5YXG342J.cjs.map → chunk-W7ZDBPJ3.cjs.map} +1 -1
- package/dist/{chunk-SKSE4OT6.cjs → chunk-WPVIOGDG.cjs} +5 -5
- package/dist/{chunk-SKSE4OT6.cjs.map → chunk-WPVIOGDG.cjs.map} +1 -1
- package/dist/{chunk-3US5OIDQ.cjs → chunk-XSUOEJB3.cjs} +9 -3
- package/dist/chunk-XSUOEJB3.cjs.map +1 -0
- package/dist/chunk-Z3AZ7Q5X.js +177 -0
- package/dist/chunk-Z3AZ7Q5X.js.map +1 -0
- package/dist/{chunk-Z5VUZ6YD.cjs → chunk-ZV3BKLFY.cjs} +3 -3
- package/dist/{chunk-Z5VUZ6YD.cjs.map → chunk-ZV3BKLFY.cjs.map} +1 -1
- package/dist/citations/index.cjs +10 -10
- package/dist/citations/index.js +1 -1
- package/dist/collaboration/index.cjs +57 -57
- package/dist/collaboration/index.js +3 -3
- package/dist/connect/docx.cjs +6 -6
- package/dist/connect/docx.js +4 -4
- package/dist/connect/index.cjs +87 -87
- package/dist/connect/index.js +16 -16
- package/dist/databases/index.cjs +2 -2
- package/dist/databases/index.js +1 -1
- package/dist/docx/definitions/fragment.d.ts +2 -6
- package/dist/docx/definitions/port.d.ts +2 -57
- package/dist/docx/index.cjs +46 -46
- package/dist/docx/index.js +3 -3
- package/dist/docx/references/commands.d.ts +3 -31
- package/dist/docx/references/numbering.d.ts +3 -47
- package/dist/facts/index.cjs +5 -5
- package/dist/facts/index.js +4 -4
- package/dist/files/GridView.d.ts +4 -1
- package/dist/files/TagPassagePanel.d.ts +2 -0
- package/dist/files/index.cjs +89 -79
- package/dist/files/index.cjs.map +1 -1
- package/dist/files/index.js +88 -78
- package/dist/files/index.js.map +1 -1
- package/dist/home/index.cjs +17 -17
- package/dist/home/index.js +3 -3
- package/dist/index.cjs +739 -718
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +22 -21
- package/dist/index.js.map +1 -1
- package/dist/retrieval/index.cjs +1 -1
- package/dist/retrieval/index.js +1 -1
- package/dist/settings/FirmPool.d.ts +45 -0
- package/dist/settings/index.cjs +134 -37
- package/dist/settings/index.cjs.map +1 -1
- package/dist/settings/index.d.ts +1 -0
- package/dist/settings/index.js +100 -6
- package/dist/settings/index.js.map +1 -1
- package/dist/shell/index.cjs +12 -12
- package/dist/shell/index.js +4 -4
- package/dist/site/index.cjs +5 -5
- package/dist/site/index.js +1 -1
- package/dist/studio/index.cjs +5 -5
- package/dist/studio/index.js +4 -4
- package/dist/workflow-canvas/index.cjs +53 -53
- package/dist/workflow-canvas/index.js +10 -10
- package/dist/workspaces/index.cjs +3 -3
- package/dist/workspaces/index.cjs.map +1 -1
- package/dist/workspaces/index.js +3 -3
- package/dist/workspaces/index.js.map +1 -1
- package/node_modules/@arbidocs/coedit/dist/commands.cjs +356 -0
- package/node_modules/@arbidocs/coedit/dist/commands.cjs.map +1 -0
- package/node_modules/@arbidocs/coedit/dist/commands.d.cts +235 -0
- package/node_modules/@arbidocs/coedit/dist/commands.d.ts +235 -0
- package/node_modules/@arbidocs/coedit/dist/commands.js +338 -0
- package/node_modules/@arbidocs/coedit/dist/commands.js.map +1 -0
- package/node_modules/@arbidocs/coedit/package.json +6 -1
- package/package.json +15 -5
- package/src/calls/calls.css +157 -0
- package/dist/chunk-24ND4S6Y.cjs.map +0 -1
- package/dist/chunk-3US5OIDQ.cjs.map +0 -1
- package/dist/chunk-3Y6NQIDE.js.map +0 -1
- package/dist/chunk-7C35WXYB.js.map +0 -1
- package/dist/chunk-A2MN2ZLX.js.map +0 -1
- package/dist/chunk-C2HRZSAT.cjs.map +0 -1
- package/dist/chunk-DTBSGG36.cjs.map +0 -1
- package/dist/chunk-EWSEQEPL.js.map +0 -1
- package/dist/chunk-IXALYQT7.cjs.map +0 -1
- package/dist/chunk-LLFW2T6S.cjs.map +0 -1
- package/dist/chunk-MP6FK43E.cjs.map +0 -1
- package/dist/chunk-P2KPDPFF.js.map +0 -1
- package/dist/chunk-QT6EGMAJ.cjs.map +0 -1
- package/dist/chunk-ZPLG7QYF.js.map +0 -1
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
// src/calls/layout.ts
|
|
3
|
+
var TILE_ASPECT = 16 / 9;
|
|
4
|
+
var NOTICE_MS = 6e3;
|
|
5
|
+
var CAPTION_TTL_MS = 8e3;
|
|
6
|
+
var CAPTION_LINES = 2;
|
|
7
|
+
var MAX_GRID_TILES = 9;
|
|
8
|
+
var MIN_CELL_ASPECT = 0.6;
|
|
9
|
+
var MAX_CELL_ASPECT = 2.4;
|
|
10
|
+
var LANDSCAPE_SLACK = 0.85;
|
|
11
|
+
function gridLayout(count, width, height, gap = 8, aspect = TILE_ASPECT) {
|
|
12
|
+
const n = Math.max(0, Math.floor(count));
|
|
13
|
+
if (n === 0 || width <= 0 || height <= 0) {
|
|
14
|
+
return {
|
|
15
|
+
cols: 0,
|
|
16
|
+
rows: 0,
|
|
17
|
+
rowCounts: [],
|
|
18
|
+
tileWidth: 0,
|
|
19
|
+
tileHeight: 0,
|
|
20
|
+
cellWidth: 0,
|
|
21
|
+
cellHeight: 0
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
const options = [];
|
|
25
|
+
for (let cols2 = 1; cols2 <= n; cols2++) {
|
|
26
|
+
const rows2 = Math.ceil(n / cols2);
|
|
27
|
+
if (cols2 > 1 && Math.ceil(n / (cols2 - 1)) === rows2) continue;
|
|
28
|
+
const byWidth = (width - gap * (cols2 - 1)) / cols2;
|
|
29
|
+
const byHeight = (height - gap * (rows2 - 1)) / rows2 * aspect;
|
|
30
|
+
options.push({ cols: cols2, rows: rows2, tileWidth: Math.max(0, Math.min(byWidth, byHeight)) });
|
|
31
|
+
}
|
|
32
|
+
const cellAspect = (o) => (width - gap * (o.cols - 1)) / o.cols / ((height - gap * (o.rows - 1)) / o.rows);
|
|
33
|
+
const sane = options.filter((o) => {
|
|
34
|
+
const a = cellAspect(o);
|
|
35
|
+
return a >= MIN_CELL_ASPECT && a <= MAX_CELL_ASPECT;
|
|
36
|
+
});
|
|
37
|
+
const pool = sane.length ? sane : options;
|
|
38
|
+
const largest = pool.reduce((a, b) => b.tileWidth > a.tileWidth + 0.5 ? b : a);
|
|
39
|
+
const landscape = pool.filter((o) => o.cols >= o.rows && o.tileWidth >= largest.tileWidth * LANDSCAPE_SLACK).reduce((a, b) => !a || b.tileWidth > a.tileWidth ? b : a, null);
|
|
40
|
+
const best = landscape ?? largest;
|
|
41
|
+
const { cols, rows } = best;
|
|
42
|
+
const tileWidth = Math.floor(best.tileWidth);
|
|
43
|
+
return {
|
|
44
|
+
cols,
|
|
45
|
+
rows,
|
|
46
|
+
rowCounts: rowCounts(n, cols),
|
|
47
|
+
tileWidth,
|
|
48
|
+
tileHeight: Math.floor(tileWidth / aspect),
|
|
49
|
+
cellWidth: Math.floor((width - gap * (cols - 1)) / cols),
|
|
50
|
+
cellHeight: Math.floor((height - gap * (rows - 1)) / rows)
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function rowCounts(count, cols) {
|
|
54
|
+
if (count <= 0 || cols <= 0) return [];
|
|
55
|
+
const rows = Math.ceil(count / cols);
|
|
56
|
+
const base = Math.floor(count / rows);
|
|
57
|
+
const extra = count % rows;
|
|
58
|
+
return Array.from({ length: rows }, (_, i) => base + (i < extra ? 1 : 0));
|
|
59
|
+
}
|
|
60
|
+
function gridSlots(items, max = MAX_GRID_TILES) {
|
|
61
|
+
if (items.length <= max) return { shown: items, hidden: 0 };
|
|
62
|
+
return { shown: items.slice(0, max - 1), hidden: items.length - (max - 1) };
|
|
63
|
+
}
|
|
64
|
+
var SPEAKER_ACCENTS = [
|
|
65
|
+
"text-blue-text-strong",
|
|
66
|
+
"text-purple-text-strong",
|
|
67
|
+
"text-green-text-strong",
|
|
68
|
+
"text-yellow-text-strong",
|
|
69
|
+
"text-red-text-strong"
|
|
70
|
+
];
|
|
71
|
+
function speakerIndex(identity) {
|
|
72
|
+
let h = 0;
|
|
73
|
+
for (let i = 0; i < identity.length; i++) h = h * 31 + identity.charCodeAt(i) >>> 0;
|
|
74
|
+
return h % SPEAKER_ACCENTS.length;
|
|
75
|
+
}
|
|
76
|
+
function speakerAccent(identity) {
|
|
77
|
+
return SPEAKER_ACCENTS[speakerIndex(identity)];
|
|
78
|
+
}
|
|
79
|
+
var SPEAKER_BORDERS = [
|
|
80
|
+
"border-blue-text-strong",
|
|
81
|
+
"border-purple-text-strong",
|
|
82
|
+
"border-green-text-strong",
|
|
83
|
+
"border-yellow-text-strong",
|
|
84
|
+
"border-red-text-strong"
|
|
85
|
+
];
|
|
86
|
+
function speakerBorder(identity) {
|
|
87
|
+
return SPEAKER_BORDERS[speakerIndex(identity)];
|
|
88
|
+
}
|
|
89
|
+
var SPEAKER_DOTS = [
|
|
90
|
+
"bg-blue-text-strong",
|
|
91
|
+
"bg-purple-text-strong",
|
|
92
|
+
"bg-green-text-strong",
|
|
93
|
+
"bg-yellow-text-strong",
|
|
94
|
+
"bg-red-text-strong"
|
|
95
|
+
];
|
|
96
|
+
function speakerDot(identity) {
|
|
97
|
+
return SPEAKER_DOTS[speakerIndex(identity)];
|
|
98
|
+
}
|
|
99
|
+
function nearestCorner(x, y, width, height) {
|
|
100
|
+
const top = y < height / 2;
|
|
101
|
+
const left = x < width / 2;
|
|
102
|
+
return `${top ? "top" : "bottom"}-${left ? "left" : "right"}`;
|
|
103
|
+
}
|
|
104
|
+
function formatElapsed(ms) {
|
|
105
|
+
const total = Math.max(0, Math.floor(ms / 1e3));
|
|
106
|
+
const h = Math.floor(total / 3600);
|
|
107
|
+
const m = Math.floor(total % 3600 / 60);
|
|
108
|
+
const s = total % 60;
|
|
109
|
+
const ss = String(s).padStart(2, "0");
|
|
110
|
+
return h > 0 ? `${h}:${String(m).padStart(2, "0")}:${ss}` : `${m}:${ss}`;
|
|
111
|
+
}
|
|
112
|
+
function initialsOf(name) {
|
|
113
|
+
const words = name.trim().split(/\s+/).filter((w) => /[\p{L}\p{N}]/u.test(w));
|
|
114
|
+
if (!words.length) return "?";
|
|
115
|
+
const first = words[0].match(/[\p{L}\p{N}]/u)?.[0] ?? "";
|
|
116
|
+
const last = words.length > 1 ? words[words.length - 1].match(/[\p{L}\p{N}]/u)?.[0] ?? "" : "";
|
|
117
|
+
return (first + last).toUpperCase();
|
|
118
|
+
}
|
|
119
|
+
var INITIAL_SPOTLIGHT = { id: null, candidate: null, since: 0 };
|
|
120
|
+
var SPEAKING_LEVEL = 0.08;
|
|
121
|
+
function nextSpotlight(state, levels, now, { threshold = SPEAKING_LEVEL, holdMs = 800, margin = 1.5, exclude = [] } = {}) {
|
|
122
|
+
let loudest = null;
|
|
123
|
+
let max = threshold;
|
|
124
|
+
for (const [id, level] of Object.entries(levels)) {
|
|
125
|
+
if (exclude.includes(id)) continue;
|
|
126
|
+
if (level >= max) {
|
|
127
|
+
max = level;
|
|
128
|
+
loudest = id;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (!loudest || loudest === state.id) {
|
|
132
|
+
return state.candidate ? { ...state, candidate: null } : state;
|
|
133
|
+
}
|
|
134
|
+
if (!state.id) return { id: loudest, candidate: null, since: now };
|
|
135
|
+
const current = levels[state.id] ?? 0;
|
|
136
|
+
if (max < current * margin) return state.candidate ? { ...state, candidate: null } : state;
|
|
137
|
+
if (state.candidate !== loudest) return { ...state, candidate: loudest, since: now };
|
|
138
|
+
return now - state.since >= holdMs ? { id: loudest, candidate: null, since: now } : state;
|
|
139
|
+
}
|
|
140
|
+
function pickSpotlight(people, spotlightId) {
|
|
141
|
+
const spot = people.find((p) => p.id === spotlightId && !p.local);
|
|
142
|
+
if (spot) return spot.id;
|
|
143
|
+
return (people.find((p) => !p.local) ?? people[0])?.id;
|
|
144
|
+
}
|
|
145
|
+
function spotlightBox(width, height, others, narrow, gap = 8, aspect = TILE_ASPECT) {
|
|
146
|
+
if (width <= 0 || height <= 0) return { width: 0, height: 0 };
|
|
147
|
+
let w;
|
|
148
|
+
if (narrow) {
|
|
149
|
+
const rows = Math.ceil(others / 3);
|
|
150
|
+
const stripPerWidth = rows > 0 ? rows / 3 / aspect : 0;
|
|
151
|
+
const fixed = rows > 0 ? gap + rows * gap - rows * 2 * gap / 3 / aspect : 0;
|
|
152
|
+
w = Math.min(width, (height - fixed) / (1 / aspect + stripPerWidth));
|
|
153
|
+
} else {
|
|
154
|
+
const avail = others > 0 ? width - 240 - gap : width;
|
|
155
|
+
w = Math.min(avail, height * aspect);
|
|
156
|
+
}
|
|
157
|
+
w = Math.max(0, Math.floor(w));
|
|
158
|
+
return { width: w, height: Math.floor(w / aspect) };
|
|
159
|
+
}
|
|
160
|
+
function stageContentHeight(view, width, maxHeight, count, gap = 8, aspect = TILE_ASPECT) {
|
|
161
|
+
if (width <= 0 || maxHeight <= 0) return 0;
|
|
162
|
+
if (view === "grid") {
|
|
163
|
+
const g = gridLayout(count, width, maxHeight, gap, aspect);
|
|
164
|
+
return Math.min(maxHeight, g.rows * g.tileHeight + Math.max(0, g.rows - 1) * gap);
|
|
165
|
+
}
|
|
166
|
+
const others = Math.max(0, count - 1);
|
|
167
|
+
const narrow = width < 640;
|
|
168
|
+
const box = spotlightBox(width, maxHeight, others, narrow, gap, aspect);
|
|
169
|
+
if (!narrow || others === 0) return box.height;
|
|
170
|
+
const rows = Math.ceil(others / 3);
|
|
171
|
+
const thumb = (box.width - 2 * gap) / 3 / aspect;
|
|
172
|
+
return Math.min(maxHeight, Math.ceil(box.height + gap + rows * thumb + (rows - 1) * gap));
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export { CAPTION_LINES, CAPTION_TTL_MS, INITIAL_SPOTLIGHT, MAX_GRID_TILES, NOTICE_MS, SPEAKER_ACCENTS, SPEAKING_LEVEL, TILE_ASPECT, formatElapsed, gridLayout, gridSlots, initialsOf, nearestCorner, nextSpotlight, pickSpotlight, rowCounts, speakerAccent, speakerBorder, speakerDot, spotlightBox, stageContentHeight };
|
|
176
|
+
//# sourceMappingURL=chunk-Z3AZ7Q5X.js.map
|
|
177
|
+
//# sourceMappingURL=chunk-Z3AZ7Q5X.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/calls/layout.ts"],"names":["cols","rows"],"mappings":"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","file":"chunk-Z3AZ7Q5X.js","sourcesContent":["/**\n * Pure layout helpers for the call stage: the adaptive tile grid, the per-speaker caption accent,\n * the picture-in-picture corner and the elapsed-time label. No React, no LiveKit: unit-tested on\n * their own.\n */\n\n/** Tiles are 16:9, like the cameras they show. */\nexport const TILE_ASPECT = 16 / 9\n/** How long a status notice (\"Recording — started by X\") stays spelled out before it folds. */\nexport const NOTICE_MS = 6000\n/** How long a caption stays on screen. */\nexport const CAPTION_TTL_MS = 8000\n/** Caption lines shown at once (two lines, the newest at the bottom). */\nexport const CAPTION_LINES = 2\n/** Tiles shown in the grid before the rest fold into a \"+N\" tile. */\nexport const MAX_GRID_TILES = 9\n\n/** Cell shapes (width / height) a filled tile may take before faces get cropped badly. */\nconst MIN_CELL_ASPECT = 0.6\nconst MAX_CELL_ASPECT = 2.4\n/** A row-first grid may be this much smaller than the largest and still win. */\nconst LANDSCAPE_SLACK = 0.85\n\nexport interface GridLayout {\n cols: number\n rows: number\n /** Tiles per row, top to bottom (a short last row is centred: 3 → [2, 1]). */\n rowCounts: number[]\n tileWidth: number\n tileHeight: number\n /** The cell a tile fills when the grid fills the whole stage (the layout's rows × columns). */\n cellWidth: number\n cellHeight: number\n}\n\n/**\n * The grid that gives `count` tiles of a fixed aspect the largest size inside `width × height`\n * with `gap` between them, preferring a row-first layout when it is nearly as large.\n */\nexport function gridLayout(\n count: number,\n width: number,\n height: number,\n gap = 8,\n aspect = TILE_ASPECT\n): GridLayout {\n const n = Math.max(0, Math.floor(count))\n if (n === 0 || width <= 0 || height <= 0) {\n return {\n cols: 0,\n rows: 0,\n rowCounts: [],\n tileWidth: 0,\n tileHeight: 0,\n cellWidth: 0,\n cellHeight: 0,\n }\n }\n const options: { cols: number; rows: number; tileWidth: number }[] = []\n for (let cols = 1; cols <= n; cols++) {\n const rows = Math.ceil(n / cols)\n // A column count that leaves a whole row empty is never better than one fewer column.\n if (cols > 1 && Math.ceil(n / (cols - 1)) === rows) continue\n const byWidth = (width - gap * (cols - 1)) / cols\n const byHeight = ((height - gap * (rows - 1)) / rows) * aspect\n options.push({ cols, rows, tileWidth: Math.max(0, Math.min(byWidth, byHeight)) })\n }\n // Tiles fill their cells, so a cell far from 16:9 crops faces (a 3:1 strip, a 1:2 column):\n // keep to cells within a sane shape when any layout allows it.\n const cellAspect = (o: { cols: number; rows: number }) =>\n (width - gap * (o.cols - 1)) / o.cols / ((height - gap * (o.rows - 1)) / o.rows)\n const sane = options.filter((o) => {\n const a = cellAspect(o)\n return a >= MIN_CELL_ASPECT && a <= MAX_CELL_ASPECT\n })\n const pool = sane.length ? sane : options\n const largest = pool.reduce((a, b) => (b.tileWidth > a.tileWidth + 0.5 ? b : a))\n // Calls read left to right: on a landscape stage a row-first layout (2 side by side, 3 × 2)\n // beats a slightly larger column-first one.\n const landscape = pool\n .filter((o) => o.cols >= o.rows && o.tileWidth >= largest.tileWidth * LANDSCAPE_SLACK)\n .reduce<typeof largest | null>((a, b) => (!a || b.tileWidth > a.tileWidth ? b : a), null)\n const best = landscape ?? largest\n const { cols, rows } = best\n const tileWidth = Math.floor(best.tileWidth)\n return {\n cols,\n rows,\n rowCounts: rowCounts(n, cols),\n tileWidth,\n tileHeight: Math.floor(tileWidth / aspect),\n cellWidth: Math.floor((width - gap * (cols - 1)) / cols),\n cellHeight: Math.floor((height - gap * (rows - 1)) / rows),\n }\n}\n\n/** Spread `count` tiles over rows of at most `cols`, the fuller rows first: 5 in 3 → [3, 2]. */\nexport function rowCounts(count: number, cols: number): number[] {\n if (count <= 0 || cols <= 0) return []\n const rows = Math.ceil(count / cols)\n // Balanced: 7 in 3 columns → [3, 2, 2], not [3, 3, 1].\n const base = Math.floor(count / rows)\n const extra = count % rows\n return Array.from({ length: rows }, (_, i) => base + (i < extra ? 1 : 0))\n}\n\n/** What the grid shows: up to {@link MAX_GRID_TILES}; past that, one slot becomes \"+N more\". */\nexport function gridSlots<T>(items: T[], max = MAX_GRID_TILES): { shown: T[]; hidden: number } {\n if (items.length <= max) return { shown: items, hidden: 0 }\n return { shown: items.slice(0, max - 1), hidden: items.length - (max - 1) }\n}\n\n/**\n * Speaker accents for captions: semantic text tokens that meet AA contrast on the muted surface\n * in both themes. The same identity always gets the same colour.\n */\nexport const SPEAKER_ACCENTS = [\n 'text-blue-text-strong',\n 'text-purple-text-strong',\n 'text-green-text-strong',\n 'text-yellow-text-strong',\n 'text-red-text-strong',\n] as const\n\nfunction speakerIndex(identity: string): number {\n let h = 0\n for (let i = 0; i < identity.length; i++) h = (h * 31 + identity.charCodeAt(i)) >>> 0\n return h % SPEAKER_ACCENTS.length\n}\n\nexport function speakerAccent(identity: string): (typeof SPEAKER_ACCENTS)[number] {\n return SPEAKER_ACCENTS[speakerIndex(identity)]\n}\n\n/** The same speaker's colour as a border (the live transcript line). */\nexport const SPEAKER_BORDERS = [\n 'border-blue-text-strong',\n 'border-purple-text-strong',\n 'border-green-text-strong',\n 'border-yellow-text-strong',\n 'border-red-text-strong',\n] as const\n\nexport function speakerBorder(identity: string): (typeof SPEAKER_BORDERS)[number] {\n return SPEAKER_BORDERS[speakerIndex(identity)]\n}\n\n/** The speaker's colour as an inset ring (the line being spoken). */\nexport const SPEAKER_RINGS = [\n 'ring-blue-text-strong/40',\n 'ring-purple-text-strong/40',\n 'ring-green-text-strong/40',\n 'ring-yellow-text-strong/40',\n 'ring-red-text-strong/40',\n] as const\n\nexport function speakerRing(identity: string): (typeof SPEAKER_RINGS)[number] {\n return SPEAKER_RINGS[speakerIndex(identity)]\n}\n\n/** The speaker's colour as a fill (the \"is speaking\" dots). */\nexport const SPEAKER_DOTS = [\n 'bg-blue-text-strong',\n 'bg-purple-text-strong',\n 'bg-green-text-strong',\n 'bg-yellow-text-strong',\n 'bg-red-text-strong',\n] as const\n\nexport function speakerDot(identity: string): (typeof SPEAKER_DOTS)[number] {\n return SPEAKER_DOTS[speakerIndex(identity)]\n}\n\nexport type PipCorner = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'\n\n/** The viewport corner nearest to a point (where a dragged picture-in-picture card settles). */\nexport function nearestCorner(x: number, y: number, width: number, height: number): PipCorner {\n const top = y < height / 2\n const left = x < width / 2\n return `${top ? 'top' : 'bottom'}-${left ? 'left' : 'right'}` as PipCorner\n}\n\n/** `m:ss`, or `h:mm:ss` past an hour. */\nexport function formatElapsed(ms: number): string {\n const total = Math.max(0, Math.floor(ms / 1000))\n const h = Math.floor(total / 3600)\n const m = Math.floor((total % 3600) / 60)\n const s = total % 60\n const ss = String(s).padStart(2, '0')\n return h > 0 ? `${h}:${String(m).padStart(2, '0')}:${ss}` : `${m}:${ss}`\n}\n\n/** Up to two initials for a camera-off tile: \"Alice Morgan\" → \"AM\", \"usr-1a2b\" → \"U\". */\nexport function initialsOf(name: string): string {\n const words = name\n .trim()\n .split(/\\s+/)\n .filter((w) => /[\\p{L}\\p{N}]/u.test(w))\n if (!words.length) return '?'\n const first = words[0].match(/[\\p{L}\\p{N}]/u)?.[0] ?? ''\n const last = words.length > 1 ? (words[words.length - 1].match(/[\\p{L}\\p{N}]/u)?.[0] ?? '') : ''\n return (first + last).toUpperCase()\n}\n\n/** Who has the spotlight (speaker view), and who is waiting to take it. */\nexport interface SpotlightState {\n id: string | null\n /** A louder voice that must stay dominant for `holdMs` before it takes over. */\n candidate: string | null\n since: number\n}\n\nexport const INITIAL_SPOTLIGHT: SpotlightState = { id: null, candidate: null, since: 0 }\n\n/** A voice at or above this level (0..1) counts as speaking. */\nexport const SPEAKING_LEVEL = 0.08\n\n/**\n * The speaker view's spotlight, with hysteresis: a new voice takes the spotlight only after it has\n * dominated (`margin` × louder than the current one, above `threshold`) for `holdMs`, so a cough\n * does not flick the view; while several talk at once and nobody dominates, it stays put. With\n * nobody in the spotlight yet, the first voice takes it at once. `exclude` (my own identity) never\n * takes the spotlight: nobody needs to watch themselves large (Meet / Zoom behaviour).\n */\nexport function nextSpotlight(\n state: SpotlightState,\n levels: Record<string, number>,\n now: number,\n { threshold = SPEAKING_LEVEL, holdMs = 800, margin = 1.5, exclude = [] as readonly string[] } = {}\n): SpotlightState {\n let loudest: string | null = null\n let max = threshold\n for (const [id, level] of Object.entries(levels)) {\n if (exclude.includes(id)) continue\n if (level >= max) {\n max = level\n loudest = id\n }\n }\n if (!loudest || loudest === state.id) {\n return state.candidate ? { ...state, candidate: null } : state\n }\n if (!state.id) return { id: loudest, candidate: null, since: now }\n const current = levels[state.id] ?? 0\n if (max < current * margin) return state.candidate ? { ...state, candidate: null } : state\n if (state.candidate !== loudest) return { ...state, candidate: loudest, since: now }\n return now - state.since >= holdMs ? { id: loudest, candidate: null, since: now } : state\n}\n\n/**\n * Who fills the speaker view's large slot: the spotlight if it is someone else in the call, else\n * the first other person, else me (alone in the call). Never me while anyone else is there.\n */\nexport function pickSpotlight(\n people: readonly { id: string; local: boolean }[],\n spotlightId: string | null\n): string | undefined {\n const spot = people.find((p) => p.id === spotlightId && !p.local)\n if (spot) return spot.id\n return (people.find((p) => !p.local) ?? people[0])?.id\n}\n\n/**\n * The speaker view's large tile: the biggest 16:9 box that fits, leaving room for the filmstrip\n * (below it on a narrow stage — a row of three 16:9 thumbnails per line — or a 15rem column beside\n * it). It never takes a portrait shape: spare height stays blank under the filmstrip.\n */\nexport function spotlightBox(\n width: number,\n height: number,\n others: number,\n narrow: boolean,\n gap = 8,\n aspect = TILE_ASPECT\n): { width: number; height: number } {\n if (width <= 0 || height <= 0) return { width: 0, height: 0 }\n let w: number\n if (narrow) {\n // Filmstrip rows of three under the tile: each row is (w - 2 gaps) / 3 wide at 16:9.\n const rows = Math.ceil(others / 3)\n const stripPerWidth = rows > 0 ? rows / 3 / aspect : 0\n const fixed = rows > 0 ? gap + rows * gap - (rows * 2 * gap) / 3 / aspect : 0\n // h = w / aspect + w * stripPerWidth + fixed ≤ height\n w = Math.min(width, (height - fixed) / (1 / aspect + stripPerWidth))\n } else {\n const avail = others > 0 ? width - 240 - gap : width\n w = Math.min(avail, height * aspect)\n }\n w = Math.max(0, Math.floor(w))\n return { width: w, height: Math.floor(w / aspect) }\n}\n\n/**\n * How tall the call stage's tiles are, for a stage `width` wide and at most `maxHeight` tall:\n * speaker view (`focus`: the large 16:9 tile, plus the filmstrip under it on a narrow stage) or\n * gallery (`grid`). The panel gives the rest of its height to the participant list.\n */\nexport function stageContentHeight(\n view: 'focus' | 'grid',\n width: number,\n maxHeight: number,\n count: number,\n gap = 8,\n aspect = TILE_ASPECT\n): number {\n if (width <= 0 || maxHeight <= 0) return 0\n if (view === 'grid') {\n const g = gridLayout(count, width, maxHeight, gap, aspect)\n return Math.min(maxHeight, g.rows * g.tileHeight + Math.max(0, g.rows - 1) * gap)\n }\n const others = Math.max(0, count - 1)\n const narrow = width < 640\n const box = spotlightBox(width, maxHeight, others, narrow, gap, aspect)\n if (!narrow || others === 0) return box.height\n const rows = Math.ceil(others / 3)\n const thumb = (box.width - 2 * gap) / 3 / aspect\n return Math.min(maxHeight, Math.ceil(box.height + gap + rows * thumb + (rows - 1) * gap))\n}\n"]}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
var chunk7D737FLE_cjs = require('./chunk-7D737FLE.cjs');
|
|
5
5
|
var chunkOB5F4577_cjs = require('./chunk-OB5F4577.cjs');
|
|
6
6
|
var chunkPPCATBOY_cjs = require('./chunk-PPCATBOY.cjs');
|
|
7
|
-
var chunkKDG6FER6_cjs = require('./chunk-KDG6FER6.cjs');
|
|
8
7
|
var chunkMHVNT4J3_cjs = require('./chunk-MHVNT4J3.cjs');
|
|
8
|
+
var chunkKDG6FER6_cjs = require('./chunk-KDG6FER6.cjs');
|
|
9
9
|
var lucideReact = require('lucide-react');
|
|
10
10
|
var jsxRuntime = require('react/jsx-runtime');
|
|
11
11
|
var ui = require('@arbidocs/react/ui');
|
|
@@ -485,5 +485,5 @@ exports.SectionHeader = SectionHeader;
|
|
|
485
485
|
exports.SectionLabel = SectionLabel;
|
|
486
486
|
exports.StartTiles = StartTiles;
|
|
487
487
|
exports.useScopeSelection = useScopeSelection;
|
|
488
|
-
//# sourceMappingURL=chunk-
|
|
489
|
-
//# sourceMappingURL=chunk-
|
|
488
|
+
//# sourceMappingURL=chunk-ZV3BKLFY.cjs.map
|
|
489
|
+
//# sourceMappingURL=chunk-ZV3BKLFY.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/home/AddFilesFirst.tsx","../src/home/QuickActionDialogHeader.tsx","../src/lib/useScopeSelection.ts","../src/home/ScopePicker.tsx","../src/home/sections.tsx","../src/lib/balanced-columns.ts","../src/home/StartTiles.tsx"],"names":["jsxs","jsx","FolderPlus","DialogHeader","DialogTitle","DialogDescription","useMemo","formatCount","cn","Minus","Check","useState","FoldSection","testIdOr","Fragment","prefixedTestId","FileCheck2","ActionLink","Plus","useRef","useEffect","observeResize"],"mappings":"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","file":"chunk-Z5VUZ6YD.cjs","sourcesContent":["import type { ReactNode } from 'react'\nimport { FolderPlus } from 'lucide-react'\n\n/** Fixed strings of the empty-files state. */\nexport interface AddFilesFirstLabels {\n heading: string\n}\n\nexport const DEFAULT_ADD_FILES_FIRST_LABELS: AddFilesFirstLabels = {\n heading: 'Add files first',\n}\n\nexport interface AddFilesFirstProps {\n /** Why this action needs files, in the action's own words. */\n reason: string\n /** The host's own \"Add\" control. */\n action: ReactNode\n testId?: string\n labels?: Partial<AddFilesFirstLabels>\n}\n\n/**\n * What a quick-action dialog shows when the workspace has no files yet.\n *\n * Greying the action out says you cannot do it without saying how to get\n * there. Offering the same \"Add\" menu the Files view carries turns the dead\n * end into the first step: add files here, then run the action.\n */\nexport function AddFilesFirst({ reason, action, testId, labels }: AddFilesFirstProps) {\n const l = { ...DEFAULT_ADD_FILES_FIRST_LABELS, ...labels }\n return (\n <div\n className=\"flex flex-col items-center gap-3 rounded-lg border border-border bg-card shadow-xs px-4 py-8 text-center\"\n data-slot=\"add-files-first\"\n data-testid={testId}\n >\n <span className=\"flex size-11 items-center justify-center rounded-full bg-ai-soft text-ai-ink\">\n <FolderPlus className=\"size-5\" aria-hidden=\"true\" />\n </span>\n <div className=\"flex flex-col gap-1\">\n <p className=\"text-sm font-semibold text-foreground\">{l.heading}</p>\n <p className=\"text-xs leading-relaxed text-muted-foreground\">{reason}</p>\n </div>\n {action}\n </div>\n )\n}\n","import type { ReactNode } from 'react'\nimport { DialogDescription, DialogHeader, DialogTitle } from '@arbidocs/react/ui'\n\nexport interface QuickActionDialogHeaderProps {\n /** The tile's glyph, sized by the caller at `size-5`. */\n icon: ReactNode\n title: string\n /** One sentence on what the dialog does. Keep it to a line or two. */\n description: ReactNode\n /** Test id for the description, where a test asserts on the copy. */\n descriptionTestId?: string\n}\n\n/**\n * The header every \"Start\" quick-action dialog wears: the tile's own mark in\n * its disc, the action's name, and one line saying what the dialog will do.\n *\n * - The disc centres on the TITLE row, so it reads as the title's mark.\n * - The description keeps the title's left edge (`pl-13` = disc + gap), so the\n * header is one text column beside the mark rather than an L.\n * - `max-w-prose` + `text-pretty` cap the measure and stop two-word orphans.\n * - `pr-8` keeps the copy clear of the close button.\n */\nexport function QuickActionDialogHeader({\n icon,\n title,\n description,\n descriptionTestId,\n}: QuickActionDialogHeaderProps) {\n return (\n <DialogHeader className=\"space-y-0 text-left\" data-slot=\"quick-action-dialog-header\">\n <div className=\"flex items-center gap-3 pr-8\">\n <div className=\"flex size-10 shrink-0 items-center justify-center rounded-full bg-ai-soft text-ai-ink\">\n {icon}\n </div>\n <DialogTitle className=\"text-xl font-semibold leading-tight\">{title}</DialogTitle>\n </div>\n <DialogDescription\n className=\"mt-2 max-w-prose pl-13 pr-8 text-sm leading-relaxed text-pretty\"\n data-testid={descriptionTestId}\n >\n {description}\n </DialogDescription>\n </DialogHeader>\n )\n}\n","import { useMemo } from 'react'\n\n/** Which folders and labels a run is limited to. Empty = everything. */\nexport interface DocumentScope {\n /** Folder paths; `''` is the \"unfiled\" bucket. */\n folders: string[]\n /** Label (tag) ids. */\n labels: string[]\n}\n\nexport interface UseScopeSelectionOptions {\n /** Every folder path in the tree (not including the unfiled bucket). */\n folderPaths: string[]\n /** Whether the unfiled bucket is shown as a row. */\n hasUnfiled: boolean\n scope: DocumentScope\n onScopeChange: (scope: DocumentScope) => void\n}\n\n/**\n * Headless selection logic for a folder + label scope picker.\n *\n * Folders use hierarchical selection: ticking \"contracts\" also ticks\n * \"contracts/2024\", and unticking removes the whole subtree. \"All\" ticks every\n * row, which is NOT the same as an empty scope: empty means \"the whole\n * workspace, whatever lands in it later\", all-ticked means \"these folders, as\n * they are now\".\n */\nexport function useScopeSelection({\n folderPaths,\n hasUnfiled,\n scope,\n onScopeChange,\n}: UseScopeSelectionOptions) {\n const selectedFolders = useMemo(() => new Set(scope.folders), [scope.folders])\n const selectedLabels = useMemo(() => new Set(scope.labels), [scope.labels])\n\n /** Every row the folder list shows, \"unfiled\" included. */\n const allRowPaths = useMemo(\n () => [...(hasUnfiled ? [''] : []), ...folderPaths],\n [folderPaths, hasUnfiled]\n )\n const allSelected = allRowPaths.length > 0 && allRowPaths.every((p) => selectedFolders.has(p))\n const someSelected = selectedFolders.size > 0 && !allSelected\n\n const descendants = (path: string) => folderPaths.filter((p) => p.startsWith(path + '/'))\n\n const toggleFolder = (path: string) => {\n const next = new Set(selectedFolders)\n const family = [path, ...descendants(path)]\n if (next.has(path)) for (const p of family) next.delete(p)\n else for (const p of family) next.add(p)\n onScopeChange({ folders: [...next], labels: scope.labels })\n }\n\n const toggleAllFolders = () => {\n onScopeChange({ folders: allSelected ? [] : allRowPaths, labels: scope.labels })\n }\n\n const toggleLabel = (labelId: string) => {\n const next = new Set(selectedLabels)\n if (next.has(labelId)) next.delete(labelId)\n else next.add(labelId)\n onScopeChange({ folders: scope.folders, labels: [...next] })\n }\n\n return {\n selectedFolders,\n selectedLabels,\n allSelected,\n someSelected,\n hasSelection: scope.folders.length > 0 || scope.labels.length > 0,\n toggleFolder,\n toggleAllFolders,\n toggleLabel,\n }\n}\n","import { useMemo, useState } from 'react'\nimport { Check, FileCheck2, Minus } from 'lucide-react'\nimport { cn } from '@arbidocs/react/ui'\nimport { prefixedTestId, testIdOr } from '../chat/test-id'\nimport { useScopeSelection, type DocumentScope } from '../lib/useScopeSelection'\nimport { formatCount } from '../lib/format'\nimport { FoldSection } from './FoldSection'\n\n/**\n * Fixed strings of the picker. Passed as `uiLabels`: the `labels` prop is already the list of\n * document labels to scope by.\n */\nexport interface ScopePickerLabels {\n folders: string\n /** The Labels section heading. */\n labelsHeading: string\n all: string\n unfiled: string\n noFoldersYet: string\n noLabelsYet: string\n filesToInclude: string\n /** \"3 of 10 files\". */\n matchedOfTotal: (matched: number, total: number) => string\n selectedSuffix: string\n folderCount: (count: number) => string\n labelCount: (count: number) => string\n left: (count: number) => string\n /** \"All 10 files\". */\n allFiles: (total: number) => string\n includedSuffix: string\n}\n\nconst pluralize = (n: number, word: string) => `${n} ${word}${n !== 1 ? 's' : ''}`\n\nexport const DEFAULT_SCOPE_PICKER_LABELS: ScopePickerLabels = {\n folders: 'Folders',\n labelsHeading: 'Labels',\n all: 'All',\n unfiled: 'Unfiled',\n noFoldersYet: 'No folders yet',\n noLabelsYet: 'No labels yet — label files from the Files page to scope by them here.',\n filesToInclude: 'Files to include',\n matchedOfTotal: (matched, total) =>\n `${matched} of ${formatCount(total, { one: 'file', other: 'files' })}`,\n selectedSuffix: ' selected',\n folderCount: (count) => pluralize(count, 'folder'),\n labelCount: (count) => pluralize(count, 'label'),\n left: (count) => `${count} left`,\n allFiles: (total) => `All ${pluralize(total, 'file')}`,\n includedSuffix: ' in the workspace will be included',\n}\n\nexport interface ScopeFolder {\n /** Full path, e.g. `contracts/2024`. */\n path: string\n /** Last segment, shown. */\n label: string\n /** Documents under this folder. */\n count: number\n depth: number\n}\n\nexport interface ScopeLabel {\n id: string\n name: string\n /** Any CSS colour for the dot. */\n color: string\n /** Documents carrying this label. */\n count: number\n}\n\nexport interface ScopePickerProps {\n folders: ScopeFolder[]\n /** Documents with no folder; the \"Unfiled\" row is hidden at 0. */\n unfiledCount: number\n labels: ScopeLabel[]\n /** All documents the picker is scoping. */\n totalCount: number\n /** Documents the current scope matches (computed by the caller). */\n matchedCount: number\n scope: DocumentScope\n onScopeChange: (scope: DocumentScope) => void\n /** Reword the picker's fixed strings. */\n uiLabels?: Partial<ScopePickerLabels>\n /** Sub-element ids; defaults are the current ids. `labelChip` is a prefix (`<prefix>-<label id>`). */\n testIds?: Partial<\n Record<'foldersToggle' | 'labelsToggle' | 'noLabels' | 'labelChip' | 'summary', string>\n >\n}\n\ninterface FolderRowProps {\n label: string\n count: number\n depth: number\n isActive: boolean\n indeterminate?: boolean\n muted?: boolean\n onToggle: () => void\n}\n\n/** A checkbox row: the row is the checkbox (a nested real one would swallow the click). */\nfunction FolderRow({\n label,\n count,\n depth,\n isActive,\n indeterminate,\n muted,\n onToggle,\n}: FolderRowProps) {\n return (\n <button\n type=\"button\"\n onClick={onToggle}\n role=\"checkbox\"\n aria-checked={indeterminate ? 'mixed' : isActive}\n style={{ paddingLeft: `${4 + depth * 14}px` }}\n className={cn(\n 'flex w-full items-center gap-1 rounded-sm py-1 pr-2 text-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring [&:hover]:bg-accent pointer-coarse:min-h-11',\n isActive && 'bg-primary/10',\n muted && !isActive && 'text-muted-foreground'\n )}\n data-slot=\"scope-folder-row\"\n >\n <span className=\"flex w-4 shrink-0 items-center justify-center\">\n <span\n className={cn(\n 'flex size-3.5 items-center justify-center rounded-[3px] border transition-colors',\n isActive || indeterminate\n ? 'border-primary bg-primary text-primary-foreground'\n : 'border-muted-foreground/40'\n )}\n >\n {indeterminate ? (\n <Minus className=\"size-2.5\" />\n ) : (\n isActive && <Check className=\"size-2.5\" />\n )}\n </span>\n </span>\n {label !== '' && (\n <span className={cn('min-w-0 truncate', isActive && 'font-semibold text-primary')}>\n {label}\n </span>\n )}\n <span className=\"ml-auto pl-2 text-sm font-semibold text-muted-foreground\">{count}</span>\n </button>\n )\n}\n\n/**\n * Pick a folder + label scope for a run over documents. Controlled: the caller\n * owns the scope and computes `matchedCount`, so the submit button lives with\n * the caller. Both sections start shut: the default (every file) is what most\n * runs want, and the summary states it plainly.\n */\nexport function ScopePicker({\n folders,\n unfiledCount,\n labels,\n totalCount,\n matchedCount,\n scope,\n onScopeChange,\n uiLabels,\n testIds,\n}: ScopePickerProps) {\n const l = { ...DEFAULT_SCOPE_PICKER_LABELS, ...uiLabels }\n const [foldersOpen, setFoldersOpen] = useState(false)\n const [labelsOpen, setLabelsOpen] = useState(false)\n\n const folderPaths = useMemo(() => folders.map((f) => f.path), [folders])\n const selection = useScopeSelection({\n folderPaths,\n hasUnfiled: unfiledCount > 0,\n scope,\n onScopeChange,\n })\n const hasRows = folders.length > 0 || unfiledCount > 0\n\n return (\n <div className=\"flex flex-col gap-4\" data-slot=\"scope-picker\">\n <FoldSection\n label={l.folders}\n count={scope.folders.length}\n open={foldersOpen}\n onOpenChange={setFoldersOpen}\n testId={testIdOr(testIds?.foldersToggle, { testId: 'scope-picker-folders-toggle' })}\n >\n <div className=\"max-h-[180px] overflow-y-auto rounded-md border border-border p-1\">\n {hasRows && (\n <>\n <FolderRow\n label={l.all}\n count={totalCount}\n depth={0}\n isActive={selection.allSelected}\n indeterminate={selection.someSelected}\n onToggle={selection.toggleAllFolders}\n />\n <div className=\"my-1 border-t border-border\" />\n </>\n )}\n {unfiledCount > 0 && (\n <>\n <FolderRow\n label={l.unfiled}\n count={unfiledCount}\n depth={0}\n isActive={selection.selectedFolders.has('')}\n muted\n onToggle={() => selection.toggleFolder('')}\n />\n {folders.length > 0 && <div className=\"my-1 border-t border-border\" />}\n </>\n )}\n {folders.map((folder) => (\n <FolderRow\n key={folder.path}\n label={folder.label}\n count={folder.count}\n depth={folder.depth}\n isActive={selection.selectedFolders.has(folder.path)}\n onToggle={() => selection.toggleFolder(folder.path)}\n />\n ))}\n {!hasRows && <p className=\"px-2 py-1 text-sm text-muted-foreground\">{l.noFoldersYet}</p>}\n </div>\n </FoldSection>\n\n {/* Always present, like Folders: a workspace with no labels yet reads as\n \"you have not labelled anything\", not \"this cannot scope by label\". */}\n <FoldSection\n label={l.labelsHeading}\n count={scope.labels.length}\n open={labelsOpen}\n onOpenChange={setLabelsOpen}\n testId={testIdOr(testIds?.labelsToggle, { testId: 'scope-picker-labels-toggle' })}\n >\n {labels.length === 0 ? (\n <p\n className=\"px-2 py-1 text-sm text-muted-foreground\"\n data-testid={testIdOr(testIds?.noLabels, { testId: 'scope-picker-no-labels' })}\n >\n {l.noLabelsYet}\n </p>\n ) : (\n <div className=\"flex flex-wrap gap-1.5\">\n {labels.map((label) => {\n const isActive = selection.selectedLabels.has(label.id)\n return (\n <button\n key={label.id}\n type=\"button\"\n onClick={() => selection.toggleLabel(label.id)}\n aria-pressed={isActive}\n data-testid={prefixedTestId(testIds?.labelChip, label.id, {\n testId: `scope-picker-label-chip-${label.id}`,\n })}\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-md border px-2 py-1 text-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring pointer-coarse:min-h-11',\n isActive\n ? 'border-primary/40 bg-primary/10 text-primary'\n : 'border-border [&:hover]:bg-accent [&:hover]:text-accent-foreground'\n )}\n >\n <span\n className=\"size-2.5 shrink-0 rounded-full\"\n style={{ backgroundColor: label.color }}\n />\n <span className=\"truncate\">{label.name}</span>\n <span className=\"shrink-0 text-xs text-muted-foreground\">({label.count})</span>\n {isActive && <Check className=\"size-3.5 shrink-0\" />}\n </button>\n )\n })}\n </div>\n )}\n </FoldSection>\n\n <div\n className=\"rounded-lg bg-muted p-3\"\n data-testid={testIdOr(testIds?.summary, { testId: 'scope-picker-summary' })}\n >\n <div className=\"mb-2 flex items-center gap-1.5 text-xs font-medium text-muted-foreground\">\n <FileCheck2 className=\"size-4\" />\n {l.filesToInclude}\n </div>\n {selection.hasSelection ? (\n <div className=\"text-sm text-muted-foreground\">\n <span className=\"text-base font-semibold text-foreground\">\n {l.matchedOfTotal(matchedCount, totalCount)}\n </span>\n {l.selectedSuffix}\n {scope.folders.length > 0 && <span> — {l.folderCount(scope.folders.length)}</span>}\n {scope.folders.length > 0 && scope.labels.length > 0 && <span>, </span>}\n {scope.labels.length > 0 && <span>{l.labelCount(scope.labels.length)}</span>}\n <span className=\"text-xs\">\n {' · '}\n {l.left(totalCount - matchedCount)}\n </span>\n </div>\n ) : (\n <div className=\"text-sm text-muted-foreground\">\n <span className=\"text-base font-semibold text-foreground\">\n {l.allFiles(totalCount)}\n </span>\n {l.includedSuffix}\n </div>\n )}\n </div>\n </div>\n )\n}\n","import type { ReactNode } from 'react'\nimport { Plus, type LucideIcon } from 'lucide-react'\nimport { cn } from '@arbidocs/react/ui'\nimport { ActionLink } from '../components/ActionLink'\n\n/** The small label that names a band of a page (\"Start\", \"Recent\"). */\nexport function SectionLabel({\n children,\n className,\n testId,\n}: {\n children: ReactNode\n className?: string\n testId?: string\n}) {\n return (\n <p\n className={cn(\n 'flex items-center gap-3 text-sm font-semibold text-foreground after:h-px after:flex-1 after:bg-border',\n className\n )}\n data-slot=\"section-label\"\n data-testid={testId}\n >\n {children}\n </p>\n )\n}\n\nexport interface SectionHeaderProps {\n icon?: LucideIcon\n title: string\n count?: number\n /** Makes the title a button (open the full list). Omit for a static title. */\n onOpen?: () => void\n /** Real link target of the title; `onOpen` still fires on a plain click. */\n openHref?: string\n /** Test id of the title button. */\n openTestId?: string\n /** The section's one quiet action, rendered at the trailing edge. */\n action?: ReactNode\n className?: string\n}\n\n/** Title + count + one quiet action: the head of a list section. */\nexport function SectionHeader({\n icon: Icon,\n title,\n count,\n onOpen,\n openHref,\n openTestId,\n action,\n className,\n}: SectionHeaderProps) {\n return (\n <div\n className={cn('flex items-center justify-between gap-2', className)}\n data-slot=\"section-header\"\n >\n <ActionLink\n href={openHref}\n onSelect={onOpen}\n disabled={!onOpen && !openHref}\n className=\"flex min-w-0 cursor-pointer items-center gap-2 rounded-md py-1.5 pr-2 text-left transition-colors hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-default disabled:hover:text-foreground pointer-coarse:min-h-11\"\n data-testid={openTestId}\n >\n {Icon && <Icon className=\"size-4 shrink-0 text-muted-foreground\" aria-hidden=\"true\" />}\n <span className=\"whitespace-nowrap text-sm font-semibold text-foreground\">{title}</span>\n {count !== undefined && (\n <span className=\"text-sm tabular-nums text-muted-foreground\">{count}</span>\n )}\n </ActionLink>\n {action && <div className=\"shrink-0\">{action}</div>}\n </div>\n )\n}\n\nexport interface EmptyStripProps {\n icon?: LucideIcon\n label: ReactNode\n description?: ReactNode\n onSelect?: () => void\n testId?: string\n}\n\n/** One tonal strip that stands in for an empty section: an invitation, not a void. */\nexport function EmptyStrip({\n icon: Icon = Plus,\n label,\n description,\n onSelect,\n testId,\n}: EmptyStripProps) {\n return (\n <button\n type=\"button\"\n onClick={onSelect}\n disabled={!onSelect}\n className=\"flex w-full items-center gap-3 rounded-lg px-4 py-3 text-left border border-border bg-card shadow-xs transition-colors hover:border-ring/50 hover:bg-accent/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-default disabled:hover:bg-card disabled:hover:border-border pointer-coarse:min-h-11\"\n data-slot=\"empty-strip\"\n data-testid={testId}\n >\n <Icon className=\"size-5 shrink-0 text-muted-foreground\" aria-hidden=\"true\" />\n <span className=\"min-w-0 flex-1\">\n <span className=\"block text-sm font-semibold text-foreground\">{label}</span>\n {description && (\n <span className=\"block text-sm leading-snug text-muted-foreground\">{description}</span>\n )}\n </span>\n </button>\n )\n}\n","/**\n * The column count for a grid of `count` equal tiles in `width` pixels, chosen so the last row is\n * never left with a lone orphan: of the counts that fit (each column at least `minTile` wide),\n * take the one that leaves the fewest empty cells in the last row, preferring more columns on a\n * tie (never fewer than two columns when two fit). Four tiles resolve to 2x2 where three would fit\n * and 4 across when there is room for four; six resolve to 3x2.\n */\nexport function balancedColumns(count: number, width: number, minTile = 200, gap = 12): number {\n if (count <= 1) return 1\n const fit = Math.max(1, Math.min(count, Math.floor((width + gap) / (minTile + gap))))\n if (fit < 2) return 1\n let best = 2\n let bestEmpty = Number.POSITIVE_INFINITY\n for (let columns = 2; columns <= fit; columns++) {\n const empty = (columns - (count % columns)) % columns\n if (empty < bestEmpty || (empty === bestEmpty && columns > best)) {\n best = columns\n bestEmpty = empty\n }\n }\n return best\n}\n","import { useEffect, useRef, useState, type ReactNode } from 'react'\nimport type { LucideIcon } from 'lucide-react'\nimport { cn } from '@arbidocs/react/ui'\nimport { ActionLink } from '../components/ActionLink'\nimport { balancedColumns } from '../lib/balanced-columns'\nimport { observeResize } from '../lib/observe-resize'\nimport { SectionLabel } from './sections'\n\n/** One \"start something\" tile: an AI-driven action, one click from underway. */\nexport interface StartTile {\n id: string\n /** A Lucide glyph; `iconNode` wins when both are given. */\n icon?: LucideIcon\n /** A ready-made mark (host icon maps), wearing the same AI ink. */\n iconNode?: ReactNode\n title: string\n description: string\n onSelect: () => void\n /** Real link target (ctrl-click / new tab, in-SPA through `BlocksProvider`'s `linkComponent`). `onSelect` still fires on a plain click. */\n href?: string\n /** Rendered non-interactive and dimmed; `disabledReason` replaces the description. */\n disabled?: boolean\n disabledReason?: string\n testId?: string\n}\n\nexport interface StartTilesProps {\n items: StartTile[]\n /** Optional band label above the tiles (\"Start\"). */\n caption?: string\n captionTestId?: string\n className?: string\n testId?: string\n}\n\n/**\n * A band of tonal action tiles. The glyph wears the AI ink, because these are\n * the AI-driven starts. Nothing is hover-only: tiles are always rendered, hover\n * only nudges tone, and touch targets are at least 44px.\n */\nexport function StartTiles({ items, caption, captionTestId, className, testId }: StartTilesProps) {\n // The tiles reflow by their own container width (a docked tablet sidebar narrows it without\n // changing the viewport), choosing a column count that never leaves one tile alone on a row.\n const gridRef = useRef<HTMLDivElement>(null)\n const [columns, setColumns] = useState<number | null>(null)\n const count = items.length\n useEffect(() => {\n const grid = gridRef.current\n if (!grid || count === 0) return\n const measure = () => setColumns(balancedColumns(count, grid.clientWidth))\n measure()\n return observeResize(grid, measure)\n }, [count])\n\n if (count === 0) return null\n return (\n <section\n className={cn('flex flex-col gap-3', className)}\n data-slot=\"start-tiles\"\n data-testid={testId}\n >\n {caption && <SectionLabel testId={captionTestId}>{caption}</SectionLabel>}\n <div\n ref={gridRef}\n data-slot=\"start-tiles-grid\"\n data-columns={columns ?? undefined}\n className=\"grid gap-3\"\n style={{\n gridTemplateColumns:\n columns === null\n ? 'repeat(auto-fit, minmax(200px, 1fr))'\n : `repeat(${columns}, minmax(0, 1fr))`,\n }}\n >\n {items.map((item) => {\n const Icon = item.icon\n return (\n <ActionLink\n key={item.id}\n href={item.href}\n onSelect={item.onSelect}\n disabled={item.disabled}\n title={item.disabled ? item.disabledReason : undefined}\n className={cn(\n 'flex h-full flex-col items-start gap-3 rounded-lg p-4 text-left',\n 'border border-border bg-card shadow-xs transition-colors hover:border-ring/50 hover:bg-accent/40',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',\n 'disabled:cursor-default disabled:opacity-55 disabled:hover:bg-card disabled:hover:border-border',\n 'pointer-coarse:min-h-11'\n )}\n data-slot=\"start-tile\"\n data-testid={item.testId}\n >\n {item.iconNode ? (\n <span className=\"shrink-0 text-ai-ink [&>svg]:size-5\" aria-hidden=\"true\">\n {item.iconNode}\n </span>\n ) : (\n Icon && <Icon className=\"size-5 shrink-0 text-ai-ink\" aria-hidden=\"true\" />\n )}\n <span className=\"min-w-0\">\n <span className=\"block text-sm font-semibold text-foreground\">{item.title}</span>\n <span className=\"mt-1 block text-sm leading-snug text-muted-foreground\">\n {item.disabled && item.disabledReason ? item.disabledReason : item.description}\n </span>\n </span>\n </ActionLink>\n )\n })}\n </div>\n </section>\n )\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/home/AddFilesFirst.tsx","../src/home/QuickActionDialogHeader.tsx","../src/lib/useScopeSelection.ts","../src/home/ScopePicker.tsx","../src/home/sections.tsx","../src/lib/balanced-columns.ts","../src/home/StartTiles.tsx"],"names":["jsxs","jsx","FolderPlus","DialogHeader","DialogTitle","DialogDescription","useMemo","formatCount","cn","Minus","Check","useState","FoldSection","testIdOr","Fragment","prefixedTestId","FileCheck2","ActionLink","Plus","useRef","useEffect","observeResize"],"mappings":";;;;;;;;;;;;AAQO,IAAM,8BAAA,GAAsD;AAAA,EACjE,OAAA,EAAS;AACX;AAkBO,SAAS,cAAc,EAAE,MAAA,EAAQ,MAAA,EAAQ,MAAA,EAAQ,QAAO,EAAuB;AACpF,EAAA,MAAM,CAAA,GAAI,EAAE,GAAG,8BAAA,EAAgC,GAAG,MAAA,EAAO;AACzD,EAAA,uBACEA,eAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAU,0GAAA;AAAA,MACV,WAAA,EAAU,iBAAA;AAAA,MACV,aAAA,EAAa,MAAA;AAAA,MAEb,QAAA,EAAA;AAAA,wBAAAC,cAAA,CAAC,MAAA,EAAA,EAAK,WAAU,8EAAA,EACd,QAAA,kBAAAA,cAAA,CAACC,0BAAW,SAAA,EAAU,QAAA,EAAS,aAAA,EAAY,MAAA,EAAO,CAAA,EACpD,CAAA;AAAA,wBACAF,eAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,qBAAA,EACb,QAAA,EAAA;AAAA,0BAAAC,cAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,uCAAA,EAAyC,QAAA,EAAA,CAAA,CAAE,OAAA,EAAQ,CAAA;AAAA,0BAChEA,cAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,+CAAA,EAAiD,QAAA,EAAA,MAAA,EAAO;AAAA,SAAA,EACvE,CAAA;AAAA,QACC;AAAA;AAAA;AAAA,GACH;AAEJ;ACvBO,SAAS,uBAAA,CAAwB;AAAA,EACtC,IAAA;AAAA,EACA,KAAA;AAAA,EACA,WAAA;AAAA,EACA;AACF,CAAA,EAAiC;AAC/B,EAAA,uBACED,eAAAA,CAACG,eAAA,EAAA,EAAa,SAAA,EAAU,qBAAA,EAAsB,aAAU,4BAAA,EACtD,QAAA,EAAA;AAAA,oBAAAH,eAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,8BAAA,EACb,QAAA,EAAA;AAAA,sBAAAC,cAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,uFAAA,EACZ,QAAA,EAAA,IAAA,EACH,CAAA;AAAA,sBACAA,cAAAA,CAACG,cAAA,EAAA,EAAY,SAAA,EAAU,uCAAuC,QAAA,EAAA,KAAA,EAAM;AAAA,KAAA,EACtE,CAAA;AAAA,oBACAH,cAAAA;AAAA,MAACI,oBAAA;AAAA,MAAA;AAAA,QACC,SAAA,EAAU,iEAAA;AAAA,QACV,aAAA,EAAa,iBAAA;AAAA,QAEZ,QAAA,EAAA;AAAA;AAAA;AACH,GAAA,EACF,CAAA;AAEJ;ACjBO,SAAS,iBAAA,CAAkB;AAAA,EAChC,WAAA;AAAA,EACA,UAAA;AAAA,EACA,KAAA;AAAA,EACA;AACF,CAAA,EAA6B;AAC3B,EAAA,MAAM,eAAA,GAAkBC,aAAA,CAAQ,MAAM,IAAI,GAAA,CAAI,KAAA,CAAM,OAAO,CAAA,EAAG,CAAC,KAAA,CAAM,OAAO,CAAC,CAAA;AAC7E,EAAA,MAAM,cAAA,GAAiBA,aAAA,CAAQ,MAAM,IAAI,GAAA,CAAI,KAAA,CAAM,MAAM,CAAA,EAAG,CAAC,KAAA,CAAM,MAAM,CAAC,CAAA;AAG1E,EAAA,MAAM,WAAA,GAAcA,aAAA;AAAA,IAClB,MAAM,CAAC,GAAI,UAAA,GAAa,CAAC,EAAE,CAAA,GAAI,EAAC,EAAI,GAAG,WAAW,CAAA;AAAA,IAClD,CAAC,aAAa,UAAU;AAAA,GAC1B;AACA,EAAA,MAAM,WAAA,GAAc,WAAA,CAAY,MAAA,GAAS,CAAA,IAAK,WAAA,CAAY,KAAA,CAAM,CAAC,CAAA,KAAM,eAAA,CAAgB,GAAA,CAAI,CAAC,CAAC,CAAA;AAC7F,EAAA,MAAM,YAAA,GAAe,eAAA,CAAgB,IAAA,GAAO,CAAA,IAAK,CAAC,WAAA;AAElD,EAAA,MAAM,WAAA,GAAc,CAAC,IAAA,KAAiB,WAAA,CAAY,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,UAAA,CAAW,IAAA,GAAO,GAAG,CAAC,CAAA;AAExF,EAAA,MAAM,YAAA,GAAe,CAAC,IAAA,KAAiB;AACrC,IAAA,MAAM,IAAA,GAAO,IAAI,GAAA,CAAI,eAAe,CAAA;AACpC,IAAA,MAAM,SAAS,CAAC,IAAA,EAAM,GAAG,WAAA,CAAY,IAAI,CAAC,CAAA;AAC1C,IAAA,IAAI,IAAA,CAAK,IAAI,IAAI,CAAA,aAAc,CAAA,IAAK,MAAA,EAAQ,IAAA,CAAK,MAAA,CAAO,CAAC,CAAA;AAAA,SACpD,KAAA,MAAW,CAAA,IAAK,MAAA,EAAQ,IAAA,CAAK,IAAI,CAAC,CAAA;AACvC,IAAA,aAAA,CAAc,EAAE,SAAS,CAAC,GAAG,IAAI,CAAA,EAAG,MAAA,EAAQ,KAAA,CAAM,MAAA,EAAQ,CAAA;AAAA,EAC5D,CAAA;AAEA,EAAA,MAAM,mBAAmB,MAAM;AAC7B,IAAA,aAAA,CAAc,EAAE,SAAS,WAAA,GAAc,KAAK,WAAA,EAAa,MAAA,EAAQ,KAAA,CAAM,MAAA,EAAQ,CAAA;AAAA,EACjF,CAAA;AAEA,EAAA,MAAM,WAAA,GAAc,CAAC,OAAA,KAAoB;AACvC,IAAA,MAAM,IAAA,GAAO,IAAI,GAAA,CAAI,cAAc,CAAA;AACnC,IAAA,IAAI,KAAK,GAAA,CAAI,OAAO,CAAA,EAAG,IAAA,CAAK,OAAO,OAAO,CAAA;AAAA,SACrC,IAAA,CAAK,IAAI,OAAO,CAAA;AACrB,IAAA,aAAA,CAAc,EAAE,SAAS,KAAA,CAAM,OAAA,EAAS,QAAQ,CAAC,GAAG,IAAI,CAAA,EAAG,CAAA;AAAA,EAC7D,CAAA;AAEA,EAAA,OAAO;AAAA,IACL,eAAA;AAAA,IACA,cAAA;AAAA,IACA,WAAA;AAAA,IACA,YAAA;AAAA,IACA,cAAc,KAAA,CAAM,OAAA,CAAQ,SAAS,CAAA,IAAK,KAAA,CAAM,OAAO,MAAA,GAAS,CAAA;AAAA,IAChE,YAAA;AAAA,IACA,gBAAA;AAAA,IACA;AAAA,GACF;AACF;AC5CA,IAAM,SAAA,GAAY,CAAC,CAAA,EAAW,IAAA,KAAiB,CAAA,EAAG,CAAC,CAAA,CAAA,EAAI,IAAI,CAAA,EAAG,CAAA,KAAM,CAAA,GAAI,GAAA,GAAM,EAAE,CAAA,CAAA;AAEzE,IAAM,2BAAA,GAAiD;AAAA,EAC5D,OAAA,EAAS,SAAA;AAAA,EACT,aAAA,EAAe,QAAA;AAAA,EACf,GAAA,EAAK,KAAA;AAAA,EACL,OAAA,EAAS,SAAA;AAAA,EACT,YAAA,EAAc,gBAAA;AAAA,EACd,WAAA,EAAa,6EAAA;AAAA,EACb,cAAA,EAAgB,kBAAA;AAAA,EAChB,cAAA,EAAgB,CAAC,OAAA,EAAS,KAAA,KACxB,GAAG,OAAO,CAAA,IAAA,EAAOC,6BAAA,CAAY,KAAA,EAAO,EAAE,GAAA,EAAK,MAAA,EAAQ,KAAA,EAAO,OAAA,EAAS,CAAC,CAAA,CAAA;AAAA,EACtE,cAAA,EAAgB,WAAA;AAAA,EAChB,WAAA,EAAa,CAAC,KAAA,KAAU,SAAA,CAAU,OAAO,QAAQ,CAAA;AAAA,EACjD,UAAA,EAAY,CAAC,KAAA,KAAU,SAAA,CAAU,OAAO,OAAO,CAAA;AAAA,EAC/C,IAAA,EAAM,CAAC,KAAA,KAAU,CAAA,EAAG,KAAK,CAAA,KAAA,CAAA;AAAA,EACzB,UAAU,CAAC,KAAA,KAAU,OAAO,SAAA,CAAU,KAAA,EAAO,MAAM,CAAC,CAAA,CAAA;AAAA,EACpD,cAAA,EAAgB;AAClB;AAmDA,SAAS,SAAA,CAAU;AAAA,EACjB,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,QAAA;AAAA,EACA,aAAA;AAAA,EACA,KAAA;AAAA,EACA;AACF,CAAA,EAAmB;AACjB,EAAA,uBACEP,eAAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAK,QAAA;AAAA,MACL,OAAA,EAAS,QAAA;AAAA,MACT,IAAA,EAAK,UAAA;AAAA,MACL,cAAA,EAAc,gBAAgB,OAAA,GAAU,QAAA;AAAA,MACxC,OAAO,EAAE,WAAA,EAAa,GAAG,CAAA,GAAI,KAAA,GAAQ,EAAE,CAAA,EAAA,CAAA,EAAK;AAAA,MAC5C,SAAA,EAAWQ,KAAA;AAAA,QACT,mMAAA;AAAA,QACA,QAAA,IAAY,eAAA;AAAA,QACZ,KAAA,IAAS,CAAC,QAAA,IAAY;AAAA,OACxB;AAAA,MACA,WAAA,EAAU,kBAAA;AAAA,MAEV,QAAA,EAAA;AAAA,wBAAAP,cAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,+CAAA,EACd,QAAA,kBAAAA,cAAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAWO,KAAA;AAAA,cACT,kFAAA;AAAA,cACA,QAAA,IAAY,gBACR,mDAAA,GACA;AAAA,aACN;AAAA,YAEC,QAAA,EAAA,aAAA,mBACCP,cAAAA,CAACQ,iBAAA,EAAA,EAAM,SAAA,EAAU,UAAA,EAAW,CAAA,GAE5B,QAAA,oBAAYR,cAAAA,CAACS,iBAAA,EAAA,EAAM,SAAA,EAAU,UAAA,EAAW;AAAA;AAAA,SAE5C,EACF,CAAA;AAAA,QACC,KAAA,KAAU,EAAA,oBACTT,cAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAWO,KAAA,CAAG,kBAAA,EAAoB,QAAA,IAAY,4BAA4B,CAAA,EAC7E,QAAA,EAAA,KAAA,EACH,CAAA;AAAA,wBAEFP,cAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,4DAA4D,QAAA,EAAA,KAAA,EAAM;AAAA;AAAA;AAAA,GACpF;AAEJ;AAQO,SAAS,WAAA,CAAY;AAAA,EAC1B,OAAA;AAAA,EACA,YAAA;AAAA,EACA,MAAA;AAAA,EACA,UAAA;AAAA,EACA,YAAA;AAAA,EACA,KAAA;AAAA,EACA,aAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAA,EAAqB;AACnB,EAAA,MAAM,CAAA,GAAI,EAAE,GAAG,2BAAA,EAA6B,GAAG,QAAA,EAAS;AACxD,EAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAIU,eAAS,KAAK,CAAA;AACpD,EAAA,MAAM,CAAC,UAAA,EAAY,aAAa,CAAA,GAAIA,eAAS,KAAK,CAAA;AAElD,EAAA,MAAM,WAAA,GAAcL,aAAAA,CAAQ,MAAM,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,IAAI,CAAA,EAAG,CAAC,OAAO,CAAC,CAAA;AACvE,EAAA,MAAM,YAAY,iBAAA,CAAkB;AAAA,IAClC,WAAA;AAAA,IACA,YAAY,YAAA,GAAe,CAAA;AAAA,IAC3B,KAAA;AAAA,IACA;AAAA,GACD,CAAA;AACD,EAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,MAAA,GAAS,CAAA,IAAK,YAAA,GAAe,CAAA;AAErD,EAAA,uBACEN,eAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,qBAAA,EAAsB,aAAU,cAAA,EAC7C,QAAA,EAAA;AAAA,oBAAAC,cAAAA;AAAA,MAACW,6BAAA;AAAA,MAAA;AAAA,QACC,OAAO,CAAA,CAAE,OAAA;AAAA,QACT,KAAA,EAAO,MAAM,OAAA,CAAQ,MAAA;AAAA,QACrB,IAAA,EAAM,WAAA;AAAA,QACN,YAAA,EAAc,cAAA;AAAA,QACd,QAAQC,0BAAA,CAAS,OAAA,EAAS,eAAe,EAAE,MAAA,EAAQ,+BAA+B,CAAA;AAAA,QAElF,QAAA,kBAAAb,eAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,mEAAA,EACZ,QAAA,EAAA;AAAA,UAAA,OAAA,oBACCA,gBAAAc,mBAAA,EAAA,EACE,QAAA,EAAA;AAAA,4BAAAb,cAAAA;AAAA,cAAC,SAAA;AAAA,cAAA;AAAA,gBACC,OAAO,CAAA,CAAE,GAAA;AAAA,gBACT,KAAA,EAAO,UAAA;AAAA,gBACP,KAAA,EAAO,CAAA;AAAA,gBACP,UAAU,SAAA,CAAU,WAAA;AAAA,gBACpB,eAAe,SAAA,CAAU,YAAA;AAAA,gBACzB,UAAU,SAAA,CAAU;AAAA;AAAA,aACtB;AAAA,4BACAA,cAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,6BAAA,EAA8B;AAAA,WAAA,EAC/C,CAAA;AAAA,UAED,YAAA,GAAe,CAAA,oBACdD,eAAAA,CAAAc,mBAAA,EAAA,EACE,QAAA,EAAA;AAAA,4BAAAb,cAAAA;AAAA,cAAC,SAAA;AAAA,cAAA;AAAA,gBACC,OAAO,CAAA,CAAE,OAAA;AAAA,gBACT,KAAA,EAAO,YAAA;AAAA,gBACP,KAAA,EAAO,CAAA;AAAA,gBACP,QAAA,EAAU,SAAA,CAAU,eAAA,CAAgB,GAAA,CAAI,EAAE,CAAA;AAAA,gBAC1C,KAAA,EAAK,IAAA;AAAA,gBACL,QAAA,EAAU,MAAM,SAAA,CAAU,YAAA,CAAa,EAAE;AAAA;AAAA,aAC3C;AAAA,YACC,QAAQ,MAAA,GAAS,CAAA,oBAAKA,cAAAA,CAAC,KAAA,EAAA,EAAI,WAAU,6BAAA,EAA8B;AAAA,WAAA,EACtE,CAAA;AAAA,UAED,OAAA,CAAQ,GAAA,CAAI,CAAC,MAAA,qBACZA,cAAAA;AAAA,YAAC,SAAA;AAAA,YAAA;AAAA,cAEC,OAAO,MAAA,CAAO,KAAA;AAAA,cACd,OAAO,MAAA,CAAO,KAAA;AAAA,cACd,OAAO,MAAA,CAAO,KAAA;AAAA,cACd,QAAA,EAAU,SAAA,CAAU,eAAA,CAAgB,GAAA,CAAI,OAAO,IAAI,CAAA;AAAA,cACnD,QAAA,EAAU,MAAM,SAAA,CAAU,YAAA,CAAa,OAAO,IAAI;AAAA,aAAA;AAAA,YAL7C,MAAA,CAAO;AAAA,WAOf,CAAA;AAAA,UACA,CAAC,2BAAWA,cAAAA,CAAC,OAAE,SAAA,EAAU,yCAAA,EAA2C,YAAE,YAAA,EAAa;AAAA,SAAA,EACtF;AAAA;AAAA,KACF;AAAA,oBAIAA,cAAAA;AAAA,MAACW,6BAAA;AAAA,MAAA;AAAA,QACC,OAAO,CAAA,CAAE,aAAA;AAAA,QACT,KAAA,EAAO,MAAM,MAAA,CAAO,MAAA;AAAA,QACpB,IAAA,EAAM,UAAA;AAAA,QACN,YAAA,EAAc,aAAA;AAAA,QACd,QAAQC,0BAAA,CAAS,OAAA,EAAS,cAAc,EAAE,MAAA,EAAQ,8BAA8B,CAAA;AAAA,QAE/E,QAAA,EAAA,MAAA,CAAO,MAAA,KAAW,CAAA,mBACjBZ,cAAAA;AAAA,UAAC,GAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAU,yCAAA;AAAA,YACV,eAAaY,0BAAA,CAAS,OAAA,EAAS,UAAU,EAAE,MAAA,EAAQ,0BAA0B,CAAA;AAAA,YAE5E,QAAA,EAAA,CAAA,CAAE;AAAA;AAAA,SACL,mBAEAZ,cAAAA,CAAC,KAAA,EAAA,EAAI,WAAU,wBAAA,EACZ,QAAA,EAAA,MAAA,CAAO,GAAA,CAAI,CAAC,KAAA,KAAU;AACrB,UAAA,MAAM,QAAA,GAAW,SAAA,CAAU,cAAA,CAAe,GAAA,CAAI,MAAM,EAAE,CAAA;AACtD,UAAA,uBACED,eAAAA;AAAA,YAAC,QAAA;AAAA,YAAA;AAAA,cAEC,IAAA,EAAK,QAAA;AAAA,cACL,OAAA,EAAS,MAAM,SAAA,CAAU,WAAA,CAAY,MAAM,EAAE,CAAA;AAAA,cAC7C,cAAA,EAAc,QAAA;AAAA,cACd,aAAA,EAAae,gCAAA,CAAe,OAAA,EAAS,SAAA,EAAW,MAAM,EAAA,EAAI;AAAA,gBACxD,MAAA,EAAQ,CAAA,wBAAA,EAA2B,KAAA,CAAM,EAAE,CAAA;AAAA,eAC5C,CAAA;AAAA,cACD,SAAA,EAAWP,KAAA;AAAA,gBACT,wLAAA;AAAA,gBACA,WACI,8CAAA,GACA;AAAA,eACN;AAAA,cAEA,QAAA,EAAA;AAAA,gCAAAP,cAAAA;AAAA,kBAAC,MAAA;AAAA,kBAAA;AAAA,oBACC,SAAA,EAAU,gCAAA;AAAA,oBACV,KAAA,EAAO,EAAE,eAAA,EAAiB,KAAA,CAAM,KAAA;AAAM;AAAA,iBACxC;AAAA,gCACAA,cAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,UAAA,EAAY,gBAAM,IAAA,EAAK,CAAA;AAAA,gCACvCD,eAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,wCAAA,EAAyC,QAAA,EAAA;AAAA,kBAAA,GAAA;AAAA,kBAAE,KAAA,CAAM,KAAA;AAAA,kBAAM;AAAA,iBAAA,EAAC,CAAA;AAAA,gBACvE,QAAA,oBAAYC,cAAAA,CAACS,iBAAA,EAAA,EAAM,WAAU,mBAAA,EAAoB;AAAA;AAAA,aAAA;AAAA,YApB7C,KAAA,CAAM;AAAA,WAqBb;AAAA,QAEJ,CAAC,CAAA,EACH;AAAA;AAAA,KAEJ;AAAA,oBAEAV,eAAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,SAAA,EAAU,yBAAA;AAAA,QACV,eAAaa,0BAAA,CAAS,OAAA,EAAS,SAAS,EAAE,MAAA,EAAQ,wBAAwB,CAAA;AAAA,QAE1E,QAAA,EAAA;AAAA,0BAAAb,eAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,0EAAA,EACb,QAAA,EAAA;AAAA,4BAAAC,cAAAA,CAACe,sBAAA,EAAA,EAAW,SAAA,EAAU,QAAA,EAAS,CAAA;AAAA,YAC9B,CAAA,CAAE;AAAA,WAAA,EACL,CAAA;AAAA,UACC,UAAU,YAAA,mBACThB,eAAAA,CAAC,KAAA,EAAA,EAAI,WAAU,+BAAA,EACb,QAAA,EAAA;AAAA,4BAAAC,cAAAA,CAAC,UAAK,SAAA,EAAU,yCAAA,EACb,YAAE,cAAA,CAAe,YAAA,EAAc,UAAU,CAAA,EAC5C,CAAA;AAAA,YACC,CAAA,CAAE,cAAA;AAAA,YACF,MAAM,OAAA,CAAQ,MAAA,GAAS,CAAA,oBAAKD,gBAAC,MAAA,EAAA,EAAK,QAAA,EAAA;AAAA,cAAA,UAAA;AAAA,cAAI,CAAA,CAAE,WAAA,CAAY,KAAA,CAAM,OAAA,CAAQ,MAAM;AAAA,aAAA,EAAE,CAAA;AAAA,YAC1E,KAAA,CAAM,OAAA,CAAQ,MAAA,GAAS,CAAA,IAAK,KAAA,CAAM,MAAA,CAAO,MAAA,GAAS,CAAA,oBAAKC,cAAAA,CAAC,MAAA,EAAA,EAAK,QAAA,EAAA,IAAA,EAAE,CAAA;AAAA,YAC/D,KAAA,CAAM,MAAA,CAAO,MAAA,GAAS,CAAA,oBAAKA,cAAAA,CAAC,MAAA,EAAA,EAAM,QAAA,EAAA,CAAA,CAAE,UAAA,CAAW,KAAA,CAAM,MAAA,CAAO,MAAM,CAAA,EAAE,CAAA;AAAA,4BACrED,eAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,SAAA,EACb,QAAA,EAAA;AAAA,cAAA,QAAA;AAAA,cACA,CAAA,CAAE,IAAA,CAAK,UAAA,GAAa,YAAY;AAAA,aAAA,EACnC;AAAA,WAAA,EACF,CAAA,mBAEAA,eAAAA,CAAC,KAAA,EAAA,EAAI,WAAU,+BAAA,EACb,QAAA,EAAA;AAAA,4BAAAC,eAAC,MAAA,EAAA,EAAK,SAAA,EAAU,2CACb,QAAA,EAAA,CAAA,CAAE,QAAA,CAAS,UAAU,CAAA,EACxB,CAAA;AAAA,YACC,CAAA,CAAE;AAAA,WAAA,EACL;AAAA;AAAA;AAAA;AAEJ,GAAA,EACF,CAAA;AAEJ;ACnTO,SAAS,YAAA,CAAa;AAAA,EAC3B,QAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAAA,EAIG;AACD,EAAA,uBACEA,cAAAA;AAAA,IAAC,GAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAWO,KAAAA;AAAA,QACT,uGAAA;AAAA,QACA;AAAA,OACF;AAAA,MACA,WAAA,EAAU,eAAA;AAAA,MACV,aAAA,EAAa,MAAA;AAAA,MAEZ;AAAA;AAAA,GACH;AAEJ;AAkBO,SAAS,aAAA,CAAc;AAAA,EAC5B,IAAA,EAAM,IAAA;AAAA,EACN,KAAA;AAAA,EACA,KAAA;AAAA,EACA,MAAA;AAAA,EACA,QAAA;AAAA,EACA,UAAA;AAAA,EACA,MAAA;AAAA,EACA;AACF,CAAA,EAAuB;AACrB,EAAA,uBACER,eAAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAWQ,KAAAA,CAAG,yCAAA,EAA2C,SAAS,CAAA;AAAA,MAClE,WAAA,EAAU,gBAAA;AAAA,MAEV,QAAA,EAAA;AAAA,wBAAAR,eAAAA;AAAA,UAACiB,4BAAA;AAAA,UAAA;AAAA,YACC,IAAA,EAAM,QAAA;AAAA,YACN,QAAA,EAAU,MAAA;AAAA,YACV,QAAA,EAAU,CAAC,MAAA,IAAU,CAAC,QAAA;AAAA,YACtB,SAAA,EAAU,sRAAA;AAAA,YACV,aAAA,EAAa,UAAA;AAAA,YAEZ,QAAA,EAAA;AAAA,cAAA,IAAA,oBAAQhB,cAAAA,CAAC,IAAA,EAAA,EAAK,SAAA,EAAU,uCAAA,EAAwC,eAAY,MAAA,EAAO,CAAA;AAAA,8BACpFA,cAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,2DAA2D,QAAA,EAAA,KAAA,EAAM,CAAA;AAAA,cAChF,UAAU,MAAA,oBACTA,eAAC,MAAA,EAAA,EAAK,SAAA,EAAU,8CAA8C,QAAA,EAAA,KAAA,EAAM;AAAA;AAAA;AAAA,SAExE;AAAA,QACC,0BAAUA,cAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,YAAY,QAAA,EAAA,MAAA,EAAO;AAAA;AAAA;AAAA,GAC/C;AAEJ;AAWO,SAAS,UAAA,CAAW;AAAA,EACzB,MAAM,IAAA,GAAOiB,gBAAA;AAAA,EACb,KAAA;AAAA,EACA,WAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAA,EAAoB;AAClB,EAAA,uBACElB,eAAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAK,QAAA;AAAA,MACL,OAAA,EAAS,QAAA;AAAA,MACT,UAAU,CAAC,QAAA;AAAA,MACX,SAAA,EAAU,4UAAA;AAAA,MACV,WAAA,EAAU,aAAA;AAAA,MACV,aAAA,EAAa,MAAA;AAAA,MAEb,QAAA,EAAA;AAAA,wBAAAC,cAAAA,CAAC,IAAA,EAAA,EAAK,SAAA,EAAU,uCAAA,EAAwC,eAAY,MAAA,EAAO,CAAA;AAAA,wBAC3ED,eAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,gBAAA,EACd,QAAA,EAAA;AAAA,0BAAAC,cAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,6CAAA,EAA+C,QAAA,EAAA,KAAA,EAAM,CAAA;AAAA,UACpE,+BACCA,cAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,oDAAoD,QAAA,EAAA,WAAA,EAAY;AAAA,SAAA,EAEpF;AAAA;AAAA;AAAA,GACF;AAEJ;;;ACzGO,SAAS,gBAAgB,KAAA,EAAe,KAAA,EAAe,OAAA,GAAU,GAAA,EAAK,MAAM,EAAA,EAAY;AAC7F,EAAA,IAAI,KAAA,IAAS,GAAG,OAAO,CAAA;AACvB,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,KAAK,GAAA,CAAI,KAAA,EAAO,IAAA,CAAK,KAAA,CAAA,CAAO,KAAA,GAAQ,GAAA,KAAQ,OAAA,GAAU,GAAA,CAAI,CAAC,CAAC,CAAA;AACpF,EAAA,IAAI,GAAA,GAAM,GAAG,OAAO,CAAA;AACpB,EAAA,IAAI,IAAA,GAAO,CAAA;AACX,EAAA,IAAI,YAAY,MAAA,CAAO,iBAAA;AACvB,EAAA,KAAA,IAAS,OAAA,GAAU,CAAA,EAAG,OAAA,IAAW,GAAA,EAAK,OAAA,EAAA,EAAW;AAC/C,IAAA,MAAM,KAAA,GAAA,CAAS,OAAA,GAAW,KAAA,GAAQ,OAAA,IAAY,OAAA;AAC9C,IAAA,IAAI,KAAA,GAAQ,SAAA,IAAc,KAAA,KAAU,SAAA,IAAa,UAAU,IAAA,EAAO;AAChE,MAAA,IAAA,GAAO,OAAA;AACP,MAAA,SAAA,GAAY,KAAA;AAAA,IACd;AAAA,EACF;AACA,EAAA,OAAO,IAAA;AACT;ACmBO,SAAS,WAAW,EAAE,KAAA,EAAO,SAAS,aAAA,EAAe,SAAA,EAAW,QAAO,EAAoB;AAGhG,EAAA,MAAM,OAAA,GAAUkB,aAAuB,IAAI,CAAA;AAC3C,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIR,eAAwB,IAAI,CAAA;AAC1D,EAAA,MAAM,QAAQ,KAAA,CAAM,MAAA;AACpB,EAAAS,eAAA,CAAU,MAAM;AACd,IAAA,MAAM,OAAO,OAAA,CAAQ,OAAA;AACrB,IAAA,IAAI,CAAC,IAAA,IAAQ,KAAA,KAAU,CAAA,EAAG;AAC1B,IAAA,MAAM,UAAU,MAAM,UAAA,CAAW,gBAAgB,KAAA,EAAO,IAAA,CAAK,WAAW,CAAC,CAAA;AACzE,IAAA,OAAA,EAAQ;AACR,IAAA,OAAOC,+BAAA,CAAc,MAAM,OAAO,CAAA;AAAA,EACpC,CAAA,EAAG,CAAC,KAAK,CAAC,CAAA;AAEV,EAAA,IAAI,KAAA,KAAU,GAAG,OAAO,IAAA;AACxB,EAAA,uBACErB,eAAAA;AAAA,IAAC,SAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAWQ,KAAAA,CAAG,qBAAA,EAAuB,SAAS,CAAA;AAAA,MAC9C,WAAA,EAAU,aAAA;AAAA,MACV,aAAA,EAAa,MAAA;AAAA,MAEZ,QAAA,EAAA;AAAA,QAAA,OAAA,oBAAWP,cAAAA,CAAC,YAAA,EAAA,EAAa,MAAA,EAAQ,eAAgB,QAAA,EAAA,OAAA,EAAQ,CAAA;AAAA,wBAC1DA,cAAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,GAAA,EAAK,OAAA;AAAA,YACL,WAAA,EAAU,kBAAA;AAAA,YACV,gBAAc,OAAA,IAAW,MAAA;AAAA,YACzB,SAAA,EAAU,YAAA;AAAA,YACV,KAAA,EAAO;AAAA,cACL,mBAAA,EACE,OAAA,KAAY,IAAA,GACR,sCAAA,GACA,UAAU,OAAO,CAAA,iBAAA;AAAA,aACzB;AAAA,YAEC,QAAA,EAAA,KAAA,CAAM,GAAA,CAAI,CAAC,IAAA,KAAS;AACnB,cAAA,MAAM,OAAO,IAAA,CAAK,IAAA;AAClB,cAAA,uBACED,eAAAA;AAAA,gBAACiB,4BAAA;AAAA,gBAAA;AAAA,kBAEC,MAAM,IAAA,CAAK,IAAA;AAAA,kBACX,UAAU,IAAA,CAAK,QAAA;AAAA,kBACf,UAAU,IAAA,CAAK,QAAA;AAAA,kBACf,KAAA,EAAO,IAAA,CAAK,QAAA,GAAW,IAAA,CAAK,cAAA,GAAiB,MAAA;AAAA,kBAC7C,SAAA,EAAWT,KAAAA;AAAA,oBACT,iEAAA;AAAA,oBACA,kGAAA;AAAA,oBACA,yEAAA;AAAA,oBACA,iGAAA;AAAA,oBACA;AAAA,mBACF;AAAA,kBACA,WAAA,EAAU,YAAA;AAAA,kBACV,eAAa,IAAA,CAAK,MAAA;AAAA,kBAEjB,QAAA,EAAA;AAAA,oBAAA,IAAA,CAAK,2BACJP,cAAAA,CAAC,UAAK,SAAA,EAAU,qCAAA,EAAsC,eAAY,MAAA,EAC/D,QAAA,EAAA,IAAA,CAAK,QAAA,EACR,CAAA,GAEA,wBAAQA,cAAAA,CAAC,QAAK,SAAA,EAAU,6BAAA,EAA8B,eAAY,MAAA,EAAO,CAAA;AAAA,oCAE3ED,eAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,SAAA,EACd,QAAA,EAAA;AAAA,sCAAAC,cAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,6CAAA,EAA+C,eAAK,KAAA,EAAM,CAAA;AAAA,sCAC1EA,cAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,uDAAA,EACb,QAAA,EAAA,IAAA,CAAK,QAAA,IAAY,IAAA,CAAK,cAAA,GAAiB,IAAA,CAAK,cAAA,GAAiB,IAAA,CAAK,WAAA,EACrE;AAAA,qBAAA,EACF;AAAA;AAAA,iBAAA;AAAA,gBA3BK,IAAA,CAAK;AAAA,eA4BZ;AAAA,YAEJ,CAAC;AAAA;AAAA;AACH;AAAA;AAAA,GACF;AAEJ","file":"chunk-ZV3BKLFY.cjs","sourcesContent":["import type { ReactNode } from 'react'\nimport { FolderPlus } from 'lucide-react'\n\n/** Fixed strings of the empty-files state. */\nexport interface AddFilesFirstLabels {\n heading: string\n}\n\nexport const DEFAULT_ADD_FILES_FIRST_LABELS: AddFilesFirstLabels = {\n heading: 'Add files first',\n}\n\nexport interface AddFilesFirstProps {\n /** Why this action needs files, in the action's own words. */\n reason: string\n /** The host's own \"Add\" control. */\n action: ReactNode\n testId?: string\n labels?: Partial<AddFilesFirstLabels>\n}\n\n/**\n * What a quick-action dialog shows when the workspace has no files yet.\n *\n * Greying the action out says you cannot do it without saying how to get\n * there. Offering the same \"Add\" menu the Files view carries turns the dead\n * end into the first step: add files here, then run the action.\n */\nexport function AddFilesFirst({ reason, action, testId, labels }: AddFilesFirstProps) {\n const l = { ...DEFAULT_ADD_FILES_FIRST_LABELS, ...labels }\n return (\n <div\n className=\"flex flex-col items-center gap-3 rounded-lg border border-border bg-card shadow-xs px-4 py-8 text-center\"\n data-slot=\"add-files-first\"\n data-testid={testId}\n >\n <span className=\"flex size-11 items-center justify-center rounded-full bg-ai-soft text-ai-ink\">\n <FolderPlus className=\"size-5\" aria-hidden=\"true\" />\n </span>\n <div className=\"flex flex-col gap-1\">\n <p className=\"text-sm font-semibold text-foreground\">{l.heading}</p>\n <p className=\"text-xs leading-relaxed text-muted-foreground\">{reason}</p>\n </div>\n {action}\n </div>\n )\n}\n","import type { ReactNode } from 'react'\nimport { DialogDescription, DialogHeader, DialogTitle } from '@arbidocs/react/ui'\n\nexport interface QuickActionDialogHeaderProps {\n /** The tile's glyph, sized by the caller at `size-5`. */\n icon: ReactNode\n title: string\n /** One sentence on what the dialog does. Keep it to a line or two. */\n description: ReactNode\n /** Test id for the description, where a test asserts on the copy. */\n descriptionTestId?: string\n}\n\n/**\n * The header every \"Start\" quick-action dialog wears: the tile's own mark in\n * its disc, the action's name, and one line saying what the dialog will do.\n *\n * - The disc centres on the TITLE row, so it reads as the title's mark.\n * - The description keeps the title's left edge (`pl-13` = disc + gap), so the\n * header is one text column beside the mark rather than an L.\n * - `max-w-prose` + `text-pretty` cap the measure and stop two-word orphans.\n * - `pr-8` keeps the copy clear of the close button.\n */\nexport function QuickActionDialogHeader({\n icon,\n title,\n description,\n descriptionTestId,\n}: QuickActionDialogHeaderProps) {\n return (\n <DialogHeader className=\"space-y-0 text-left\" data-slot=\"quick-action-dialog-header\">\n <div className=\"flex items-center gap-3 pr-8\">\n <div className=\"flex size-10 shrink-0 items-center justify-center rounded-full bg-ai-soft text-ai-ink\">\n {icon}\n </div>\n <DialogTitle className=\"text-xl font-semibold leading-tight\">{title}</DialogTitle>\n </div>\n <DialogDescription\n className=\"mt-2 max-w-prose pl-13 pr-8 text-sm leading-relaxed text-pretty\"\n data-testid={descriptionTestId}\n >\n {description}\n </DialogDescription>\n </DialogHeader>\n )\n}\n","import { useMemo } from 'react'\n\n/** Which folders and labels a run is limited to. Empty = everything. */\nexport interface DocumentScope {\n /** Folder paths; `''` is the \"unfiled\" bucket. */\n folders: string[]\n /** Label (tag) ids. */\n labels: string[]\n}\n\nexport interface UseScopeSelectionOptions {\n /** Every folder path in the tree (not including the unfiled bucket). */\n folderPaths: string[]\n /** Whether the unfiled bucket is shown as a row. */\n hasUnfiled: boolean\n scope: DocumentScope\n onScopeChange: (scope: DocumentScope) => void\n}\n\n/**\n * Headless selection logic for a folder + label scope picker.\n *\n * Folders use hierarchical selection: ticking \"contracts\" also ticks\n * \"contracts/2024\", and unticking removes the whole subtree. \"All\" ticks every\n * row, which is NOT the same as an empty scope: empty means \"the whole\n * workspace, whatever lands in it later\", all-ticked means \"these folders, as\n * they are now\".\n */\nexport function useScopeSelection({\n folderPaths,\n hasUnfiled,\n scope,\n onScopeChange,\n}: UseScopeSelectionOptions) {\n const selectedFolders = useMemo(() => new Set(scope.folders), [scope.folders])\n const selectedLabels = useMemo(() => new Set(scope.labels), [scope.labels])\n\n /** Every row the folder list shows, \"unfiled\" included. */\n const allRowPaths = useMemo(\n () => [...(hasUnfiled ? [''] : []), ...folderPaths],\n [folderPaths, hasUnfiled]\n )\n const allSelected = allRowPaths.length > 0 && allRowPaths.every((p) => selectedFolders.has(p))\n const someSelected = selectedFolders.size > 0 && !allSelected\n\n const descendants = (path: string) => folderPaths.filter((p) => p.startsWith(path + '/'))\n\n const toggleFolder = (path: string) => {\n const next = new Set(selectedFolders)\n const family = [path, ...descendants(path)]\n if (next.has(path)) for (const p of family) next.delete(p)\n else for (const p of family) next.add(p)\n onScopeChange({ folders: [...next], labels: scope.labels })\n }\n\n const toggleAllFolders = () => {\n onScopeChange({ folders: allSelected ? [] : allRowPaths, labels: scope.labels })\n }\n\n const toggleLabel = (labelId: string) => {\n const next = new Set(selectedLabels)\n if (next.has(labelId)) next.delete(labelId)\n else next.add(labelId)\n onScopeChange({ folders: scope.folders, labels: [...next] })\n }\n\n return {\n selectedFolders,\n selectedLabels,\n allSelected,\n someSelected,\n hasSelection: scope.folders.length > 0 || scope.labels.length > 0,\n toggleFolder,\n toggleAllFolders,\n toggleLabel,\n }\n}\n","import { useMemo, useState } from 'react'\nimport { Check, FileCheck2, Minus } from 'lucide-react'\nimport { cn } from '@arbidocs/react/ui'\nimport { prefixedTestId, testIdOr } from '../chat/test-id'\nimport { useScopeSelection, type DocumentScope } from '../lib/useScopeSelection'\nimport { formatCount } from '../lib/format'\nimport { FoldSection } from './FoldSection'\n\n/**\n * Fixed strings of the picker. Passed as `uiLabels`: the `labels` prop is already the list of\n * document labels to scope by.\n */\nexport interface ScopePickerLabels {\n folders: string\n /** The Labels section heading. */\n labelsHeading: string\n all: string\n unfiled: string\n noFoldersYet: string\n noLabelsYet: string\n filesToInclude: string\n /** \"3 of 10 files\". */\n matchedOfTotal: (matched: number, total: number) => string\n selectedSuffix: string\n folderCount: (count: number) => string\n labelCount: (count: number) => string\n left: (count: number) => string\n /** \"All 10 files\". */\n allFiles: (total: number) => string\n includedSuffix: string\n}\n\nconst pluralize = (n: number, word: string) => `${n} ${word}${n !== 1 ? 's' : ''}`\n\nexport const DEFAULT_SCOPE_PICKER_LABELS: ScopePickerLabels = {\n folders: 'Folders',\n labelsHeading: 'Labels',\n all: 'All',\n unfiled: 'Unfiled',\n noFoldersYet: 'No folders yet',\n noLabelsYet: 'No labels yet — label files from the Files page to scope by them here.',\n filesToInclude: 'Files to include',\n matchedOfTotal: (matched, total) =>\n `${matched} of ${formatCount(total, { one: 'file', other: 'files' })}`,\n selectedSuffix: ' selected',\n folderCount: (count) => pluralize(count, 'folder'),\n labelCount: (count) => pluralize(count, 'label'),\n left: (count) => `${count} left`,\n allFiles: (total) => `All ${pluralize(total, 'file')}`,\n includedSuffix: ' in the workspace will be included',\n}\n\nexport interface ScopeFolder {\n /** Full path, e.g. `contracts/2024`. */\n path: string\n /** Last segment, shown. */\n label: string\n /** Documents under this folder. */\n count: number\n depth: number\n}\n\nexport interface ScopeLabel {\n id: string\n name: string\n /** Any CSS colour for the dot. */\n color: string\n /** Documents carrying this label. */\n count: number\n}\n\nexport interface ScopePickerProps {\n folders: ScopeFolder[]\n /** Documents with no folder; the \"Unfiled\" row is hidden at 0. */\n unfiledCount: number\n labels: ScopeLabel[]\n /** All documents the picker is scoping. */\n totalCount: number\n /** Documents the current scope matches (computed by the caller). */\n matchedCount: number\n scope: DocumentScope\n onScopeChange: (scope: DocumentScope) => void\n /** Reword the picker's fixed strings. */\n uiLabels?: Partial<ScopePickerLabels>\n /** Sub-element ids; defaults are the current ids. `labelChip` is a prefix (`<prefix>-<label id>`). */\n testIds?: Partial<\n Record<'foldersToggle' | 'labelsToggle' | 'noLabels' | 'labelChip' | 'summary', string>\n >\n}\n\ninterface FolderRowProps {\n label: string\n count: number\n depth: number\n isActive: boolean\n indeterminate?: boolean\n muted?: boolean\n onToggle: () => void\n}\n\n/** A checkbox row: the row is the checkbox (a nested real one would swallow the click). */\nfunction FolderRow({\n label,\n count,\n depth,\n isActive,\n indeterminate,\n muted,\n onToggle,\n}: FolderRowProps) {\n return (\n <button\n type=\"button\"\n onClick={onToggle}\n role=\"checkbox\"\n aria-checked={indeterminate ? 'mixed' : isActive}\n style={{ paddingLeft: `${4 + depth * 14}px` }}\n className={cn(\n 'flex w-full items-center gap-1 rounded-sm py-1 pr-2 text-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring [&:hover]:bg-accent pointer-coarse:min-h-11',\n isActive && 'bg-primary/10',\n muted && !isActive && 'text-muted-foreground'\n )}\n data-slot=\"scope-folder-row\"\n >\n <span className=\"flex w-4 shrink-0 items-center justify-center\">\n <span\n className={cn(\n 'flex size-3.5 items-center justify-center rounded-[3px] border transition-colors',\n isActive || indeterminate\n ? 'border-primary bg-primary text-primary-foreground'\n : 'border-muted-foreground/40'\n )}\n >\n {indeterminate ? (\n <Minus className=\"size-2.5\" />\n ) : (\n isActive && <Check className=\"size-2.5\" />\n )}\n </span>\n </span>\n {label !== '' && (\n <span className={cn('min-w-0 truncate', isActive && 'font-semibold text-primary')}>\n {label}\n </span>\n )}\n <span className=\"ml-auto pl-2 text-sm font-semibold text-muted-foreground\">{count}</span>\n </button>\n )\n}\n\n/**\n * Pick a folder + label scope for a run over documents. Controlled: the caller\n * owns the scope and computes `matchedCount`, so the submit button lives with\n * the caller. Both sections start shut: the default (every file) is what most\n * runs want, and the summary states it plainly.\n */\nexport function ScopePicker({\n folders,\n unfiledCount,\n labels,\n totalCount,\n matchedCount,\n scope,\n onScopeChange,\n uiLabels,\n testIds,\n}: ScopePickerProps) {\n const l = { ...DEFAULT_SCOPE_PICKER_LABELS, ...uiLabels }\n const [foldersOpen, setFoldersOpen] = useState(false)\n const [labelsOpen, setLabelsOpen] = useState(false)\n\n const folderPaths = useMemo(() => folders.map((f) => f.path), [folders])\n const selection = useScopeSelection({\n folderPaths,\n hasUnfiled: unfiledCount > 0,\n scope,\n onScopeChange,\n })\n const hasRows = folders.length > 0 || unfiledCount > 0\n\n return (\n <div className=\"flex flex-col gap-4\" data-slot=\"scope-picker\">\n <FoldSection\n label={l.folders}\n count={scope.folders.length}\n open={foldersOpen}\n onOpenChange={setFoldersOpen}\n testId={testIdOr(testIds?.foldersToggle, { testId: 'scope-picker-folders-toggle' })}\n >\n <div className=\"max-h-[180px] overflow-y-auto rounded-md border border-border p-1\">\n {hasRows && (\n <>\n <FolderRow\n label={l.all}\n count={totalCount}\n depth={0}\n isActive={selection.allSelected}\n indeterminate={selection.someSelected}\n onToggle={selection.toggleAllFolders}\n />\n <div className=\"my-1 border-t border-border\" />\n </>\n )}\n {unfiledCount > 0 && (\n <>\n <FolderRow\n label={l.unfiled}\n count={unfiledCount}\n depth={0}\n isActive={selection.selectedFolders.has('')}\n muted\n onToggle={() => selection.toggleFolder('')}\n />\n {folders.length > 0 && <div className=\"my-1 border-t border-border\" />}\n </>\n )}\n {folders.map((folder) => (\n <FolderRow\n key={folder.path}\n label={folder.label}\n count={folder.count}\n depth={folder.depth}\n isActive={selection.selectedFolders.has(folder.path)}\n onToggle={() => selection.toggleFolder(folder.path)}\n />\n ))}\n {!hasRows && <p className=\"px-2 py-1 text-sm text-muted-foreground\">{l.noFoldersYet}</p>}\n </div>\n </FoldSection>\n\n {/* Always present, like Folders: a workspace with no labels yet reads as\n \"you have not labelled anything\", not \"this cannot scope by label\". */}\n <FoldSection\n label={l.labelsHeading}\n count={scope.labels.length}\n open={labelsOpen}\n onOpenChange={setLabelsOpen}\n testId={testIdOr(testIds?.labelsToggle, { testId: 'scope-picker-labels-toggle' })}\n >\n {labels.length === 0 ? (\n <p\n className=\"px-2 py-1 text-sm text-muted-foreground\"\n data-testid={testIdOr(testIds?.noLabels, { testId: 'scope-picker-no-labels' })}\n >\n {l.noLabelsYet}\n </p>\n ) : (\n <div className=\"flex flex-wrap gap-1.5\">\n {labels.map((label) => {\n const isActive = selection.selectedLabels.has(label.id)\n return (\n <button\n key={label.id}\n type=\"button\"\n onClick={() => selection.toggleLabel(label.id)}\n aria-pressed={isActive}\n data-testid={prefixedTestId(testIds?.labelChip, label.id, {\n testId: `scope-picker-label-chip-${label.id}`,\n })}\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-md border px-2 py-1 text-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring pointer-coarse:min-h-11',\n isActive\n ? 'border-primary/40 bg-primary/10 text-primary'\n : 'border-border [&:hover]:bg-accent [&:hover]:text-accent-foreground'\n )}\n >\n <span\n className=\"size-2.5 shrink-0 rounded-full\"\n style={{ backgroundColor: label.color }}\n />\n <span className=\"truncate\">{label.name}</span>\n <span className=\"shrink-0 text-xs text-muted-foreground\">({label.count})</span>\n {isActive && <Check className=\"size-3.5 shrink-0\" />}\n </button>\n )\n })}\n </div>\n )}\n </FoldSection>\n\n <div\n className=\"rounded-lg bg-muted p-3\"\n data-testid={testIdOr(testIds?.summary, { testId: 'scope-picker-summary' })}\n >\n <div className=\"mb-2 flex items-center gap-1.5 text-xs font-medium text-muted-foreground\">\n <FileCheck2 className=\"size-4\" />\n {l.filesToInclude}\n </div>\n {selection.hasSelection ? (\n <div className=\"text-sm text-muted-foreground\">\n <span className=\"text-base font-semibold text-foreground\">\n {l.matchedOfTotal(matchedCount, totalCount)}\n </span>\n {l.selectedSuffix}\n {scope.folders.length > 0 && <span> — {l.folderCount(scope.folders.length)}</span>}\n {scope.folders.length > 0 && scope.labels.length > 0 && <span>, </span>}\n {scope.labels.length > 0 && <span>{l.labelCount(scope.labels.length)}</span>}\n <span className=\"text-xs\">\n {' · '}\n {l.left(totalCount - matchedCount)}\n </span>\n </div>\n ) : (\n <div className=\"text-sm text-muted-foreground\">\n <span className=\"text-base font-semibold text-foreground\">\n {l.allFiles(totalCount)}\n </span>\n {l.includedSuffix}\n </div>\n )}\n </div>\n </div>\n )\n}\n","import type { ReactNode } from 'react'\nimport { Plus, type LucideIcon } from 'lucide-react'\nimport { cn } from '@arbidocs/react/ui'\nimport { ActionLink } from '../components/ActionLink'\n\n/** The small label that names a band of a page (\"Start\", \"Recent\"). */\nexport function SectionLabel({\n children,\n className,\n testId,\n}: {\n children: ReactNode\n className?: string\n testId?: string\n}) {\n return (\n <p\n className={cn(\n 'flex items-center gap-3 text-sm font-semibold text-foreground after:h-px after:flex-1 after:bg-border',\n className\n )}\n data-slot=\"section-label\"\n data-testid={testId}\n >\n {children}\n </p>\n )\n}\n\nexport interface SectionHeaderProps {\n icon?: LucideIcon\n title: string\n count?: number\n /** Makes the title a button (open the full list). Omit for a static title. */\n onOpen?: () => void\n /** Real link target of the title; `onOpen` still fires on a plain click. */\n openHref?: string\n /** Test id of the title button. */\n openTestId?: string\n /** The section's one quiet action, rendered at the trailing edge. */\n action?: ReactNode\n className?: string\n}\n\n/** Title + count + one quiet action: the head of a list section. */\nexport function SectionHeader({\n icon: Icon,\n title,\n count,\n onOpen,\n openHref,\n openTestId,\n action,\n className,\n}: SectionHeaderProps) {\n return (\n <div\n className={cn('flex items-center justify-between gap-2', className)}\n data-slot=\"section-header\"\n >\n <ActionLink\n href={openHref}\n onSelect={onOpen}\n disabled={!onOpen && !openHref}\n className=\"flex min-w-0 cursor-pointer items-center gap-2 rounded-md py-1.5 pr-2 text-left transition-colors hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-default disabled:hover:text-foreground pointer-coarse:min-h-11\"\n data-testid={openTestId}\n >\n {Icon && <Icon className=\"size-4 shrink-0 text-muted-foreground\" aria-hidden=\"true\" />}\n <span className=\"whitespace-nowrap text-sm font-semibold text-foreground\">{title}</span>\n {count !== undefined && (\n <span className=\"text-sm tabular-nums text-muted-foreground\">{count}</span>\n )}\n </ActionLink>\n {action && <div className=\"shrink-0\">{action}</div>}\n </div>\n )\n}\n\nexport interface EmptyStripProps {\n icon?: LucideIcon\n label: ReactNode\n description?: ReactNode\n onSelect?: () => void\n testId?: string\n}\n\n/** One tonal strip that stands in for an empty section: an invitation, not a void. */\nexport function EmptyStrip({\n icon: Icon = Plus,\n label,\n description,\n onSelect,\n testId,\n}: EmptyStripProps) {\n return (\n <button\n type=\"button\"\n onClick={onSelect}\n disabled={!onSelect}\n className=\"flex w-full items-center gap-3 rounded-lg px-4 py-3 text-left border border-border bg-card shadow-xs transition-colors hover:border-ring/50 hover:bg-accent/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-default disabled:hover:bg-card disabled:hover:border-border pointer-coarse:min-h-11\"\n data-slot=\"empty-strip\"\n data-testid={testId}\n >\n <Icon className=\"size-5 shrink-0 text-muted-foreground\" aria-hidden=\"true\" />\n <span className=\"min-w-0 flex-1\">\n <span className=\"block text-sm font-semibold text-foreground\">{label}</span>\n {description && (\n <span className=\"block text-sm leading-snug text-muted-foreground\">{description}</span>\n )}\n </span>\n </button>\n )\n}\n","/**\n * The column count for a grid of `count` equal tiles in `width` pixels, chosen so the last row is\n * never left with a lone orphan: of the counts that fit (each column at least `minTile` wide),\n * take the one that leaves the fewest empty cells in the last row, preferring more columns on a\n * tie (never fewer than two columns when two fit). Four tiles resolve to 2x2 where three would fit\n * and 4 across when there is room for four; six resolve to 3x2.\n */\nexport function balancedColumns(count: number, width: number, minTile = 200, gap = 12): number {\n if (count <= 1) return 1\n const fit = Math.max(1, Math.min(count, Math.floor((width + gap) / (minTile + gap))))\n if (fit < 2) return 1\n let best = 2\n let bestEmpty = Number.POSITIVE_INFINITY\n for (let columns = 2; columns <= fit; columns++) {\n const empty = (columns - (count % columns)) % columns\n if (empty < bestEmpty || (empty === bestEmpty && columns > best)) {\n best = columns\n bestEmpty = empty\n }\n }\n return best\n}\n","import { useEffect, useRef, useState, type ReactNode } from 'react'\nimport type { LucideIcon } from 'lucide-react'\nimport { cn } from '@arbidocs/react/ui'\nimport { ActionLink } from '../components/ActionLink'\nimport { balancedColumns } from '../lib/balanced-columns'\nimport { observeResize } from '../lib/observe-resize'\nimport { SectionLabel } from './sections'\n\n/** One \"start something\" tile: an AI-driven action, one click from underway. */\nexport interface StartTile {\n id: string\n /** A Lucide glyph; `iconNode` wins when both are given. */\n icon?: LucideIcon\n /** A ready-made mark (host icon maps), wearing the same AI ink. */\n iconNode?: ReactNode\n title: string\n description: string\n onSelect: () => void\n /** Real link target (ctrl-click / new tab, in-SPA through `BlocksProvider`'s `linkComponent`). `onSelect` still fires on a plain click. */\n href?: string\n /** Rendered non-interactive and dimmed; `disabledReason` replaces the description. */\n disabled?: boolean\n disabledReason?: string\n testId?: string\n}\n\nexport interface StartTilesProps {\n items: StartTile[]\n /** Optional band label above the tiles (\"Start\"). */\n caption?: string\n captionTestId?: string\n className?: string\n testId?: string\n}\n\n/**\n * A band of tonal action tiles. The glyph wears the AI ink, because these are\n * the AI-driven starts. Nothing is hover-only: tiles are always rendered, hover\n * only nudges tone, and touch targets are at least 44px.\n */\nexport function StartTiles({ items, caption, captionTestId, className, testId }: StartTilesProps) {\n // The tiles reflow by their own container width (a docked tablet sidebar narrows it without\n // changing the viewport), choosing a column count that never leaves one tile alone on a row.\n const gridRef = useRef<HTMLDivElement>(null)\n const [columns, setColumns] = useState<number | null>(null)\n const count = items.length\n useEffect(() => {\n const grid = gridRef.current\n if (!grid || count === 0) return\n const measure = () => setColumns(balancedColumns(count, grid.clientWidth))\n measure()\n return observeResize(grid, measure)\n }, [count])\n\n if (count === 0) return null\n return (\n <section\n className={cn('flex flex-col gap-3', className)}\n data-slot=\"start-tiles\"\n data-testid={testId}\n >\n {caption && <SectionLabel testId={captionTestId}>{caption}</SectionLabel>}\n <div\n ref={gridRef}\n data-slot=\"start-tiles-grid\"\n data-columns={columns ?? undefined}\n className=\"grid gap-3\"\n style={{\n gridTemplateColumns:\n columns === null\n ? 'repeat(auto-fit, minmax(200px, 1fr))'\n : `repeat(${columns}, minmax(0, 1fr))`,\n }}\n >\n {items.map((item) => {\n const Icon = item.icon\n return (\n <ActionLink\n key={item.id}\n href={item.href}\n onSelect={item.onSelect}\n disabled={item.disabled}\n title={item.disabled ? item.disabledReason : undefined}\n className={cn(\n 'flex h-full flex-col items-start gap-3 rounded-lg p-4 text-left',\n 'border border-border bg-card shadow-xs transition-colors hover:border-ring/50 hover:bg-accent/40',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',\n 'disabled:cursor-default disabled:opacity-55 disabled:hover:bg-card disabled:hover:border-border',\n 'pointer-coarse:min-h-11'\n )}\n data-slot=\"start-tile\"\n data-testid={item.testId}\n >\n {item.iconNode ? (\n <span className=\"shrink-0 text-ai-ink [&>svg]:size-5\" aria-hidden=\"true\">\n {item.iconNode}\n </span>\n ) : (\n Icon && <Icon className=\"size-5 shrink-0 text-ai-ink\" aria-hidden=\"true\" />\n )}\n <span className=\"min-w-0\">\n <span className=\"block text-sm font-semibold text-foreground\">{item.title}</span>\n <span className=\"mt-1 block text-sm leading-snug text-muted-foreground\">\n {item.disabled && item.disabledReason ? item.disabledReason : item.description}\n </span>\n </span>\n </ActionLink>\n )\n })}\n </div>\n </section>\n )\n}\n"]}
|
package/dist/citations/index.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var
|
|
4
|
+
var chunkJK45LSIH_cjs = require('../chunk-JK45LSIH.cjs');
|
|
5
5
|
require('../chunk-C54XEN5T.cjs');
|
|
6
6
|
require('../chunk-KDG6FER6.cjs');
|
|
7
7
|
require('../chunk-DES3K4SD.cjs');
|
|
@@ -10,39 +10,39 @@ require('../chunk-DES3K4SD.cjs');
|
|
|
10
10
|
|
|
11
11
|
Object.defineProperty(exports, "CitationEditor", {
|
|
12
12
|
enumerable: true,
|
|
13
|
-
get: function () { return
|
|
13
|
+
get: function () { return chunkJK45LSIH_cjs.CitationEditor; }
|
|
14
14
|
});
|
|
15
15
|
Object.defineProperty(exports, "DEFAULT_PASSAGE_PILL_LABELS", {
|
|
16
16
|
enumerable: true,
|
|
17
|
-
get: function () { return
|
|
17
|
+
get: function () { return chunkJK45LSIH_cjs.DEFAULT_PASSAGE_PILL_LABELS; }
|
|
18
18
|
});
|
|
19
19
|
Object.defineProperty(exports, "DEFAULT_QUIET_MARK_LABELS", {
|
|
20
20
|
enumerable: true,
|
|
21
|
-
get: function () { return
|
|
21
|
+
get: function () { return chunkJK45LSIH_cjs.DEFAULT_QUIET_MARK_LABELS; }
|
|
22
22
|
});
|
|
23
23
|
Object.defineProperty(exports, "LabelMark", {
|
|
24
24
|
enumerable: true,
|
|
25
|
-
get: function () { return
|
|
25
|
+
get: function () { return chunkJK45LSIH_cjs.LabelMark; }
|
|
26
26
|
});
|
|
27
27
|
Object.defineProperty(exports, "NoteMark", {
|
|
28
28
|
enumerable: true,
|
|
29
|
-
get: function () { return
|
|
29
|
+
get: function () { return chunkJK45LSIH_cjs.NoteMark; }
|
|
30
30
|
});
|
|
31
31
|
Object.defineProperty(exports, "PassageMark", {
|
|
32
32
|
enumerable: true,
|
|
33
|
-
get: function () { return
|
|
33
|
+
get: function () { return chunkJK45LSIH_cjs.PassageMark; }
|
|
34
34
|
});
|
|
35
35
|
Object.defineProperty(exports, "PassagePill", {
|
|
36
36
|
enumerable: true,
|
|
37
|
-
get: function () { return
|
|
37
|
+
get: function () { return chunkJK45LSIH_cjs.PassagePill; }
|
|
38
38
|
});
|
|
39
39
|
Object.defineProperty(exports, "QuietLink", {
|
|
40
40
|
enumerable: true,
|
|
41
|
-
get: function () { return
|
|
41
|
+
get: function () { return chunkJK45LSIH_cjs.QuietLink; }
|
|
42
42
|
});
|
|
43
43
|
Object.defineProperty(exports, "useCopyText", {
|
|
44
44
|
enumerable: true,
|
|
45
|
-
get: function () { return
|
|
45
|
+
get: function () { return chunkJK45LSIH_cjs.useCopyText; }
|
|
46
46
|
});
|
|
47
47
|
//# sourceMappingURL=index.cjs.map
|
|
48
48
|
//# sourceMappingURL=index.cjs.map
|
package/dist/citations/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
export { CitationEditor, DEFAULT_PASSAGE_PILL_LABELS, DEFAULT_QUIET_MARK_LABELS, LabelMark, NoteMark, PassageMark, PassagePill, QuietLink, useCopyText } from '../chunk-
|
|
2
|
+
export { CitationEditor, DEFAULT_PASSAGE_PILL_LABELS, DEFAULT_QUIET_MARK_LABELS, LabelMark, NoteMark, PassageMark, PassagePill, QuietLink, useCopyText } from '../chunk-DQCYCEDR.js';
|
|
3
3
|
import '../chunk-76JDDMSP.js';
|
|
4
4
|
import '../chunk-OXF2IFXG.js';
|
|
5
5
|
import '../chunk-VUNV25KB.js';
|