sh3-core 0.19.3 → 0.19.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api.d.ts +5 -0
- package/dist/api.js +3 -0
- package/dist/chrome/CompactChrome.svelte +34 -1
- package/dist/chrome/CompactChrome.svelte.test.js +4 -2
- package/dist/chrome/FloatsSheet.svelte +236 -0
- package/dist/chrome/FloatsSheet.svelte.d.ts +7 -0
- package/dist/chrome/FloatsSheet.svelte.test.d.ts +1 -0
- package/dist/chrome/FloatsSheet.svelte.test.js +155 -0
- package/dist/documents/picker-api.d.ts +31 -0
- package/dist/documents/picker-api.js +1 -0
- package/dist/documents/picker-api.test.d.ts +1 -0
- package/dist/documents/picker-api.test.js +132 -0
- package/dist/documents/picker-primitive.d.ts +7 -0
- package/dist/documents/picker-primitive.js +58 -0
- package/dist/layout/compact/CompactRenderer.svelte +8 -2
- package/dist/layout/compact/rootStore.svelte.d.ts +20 -0
- package/dist/layout/compact/rootStore.svelte.js +59 -0
- package/dist/layout/compact/rootStore.svelte.test.d.ts +1 -0
- package/dist/layout/compact/rootStore.svelte.test.js +54 -0
- package/dist/layout/floats.d.ts +27 -0
- package/dist/layout/floats.js +20 -0
- package/dist/layout/floats.test.js +34 -1
- package/dist/layout/inspection.js +25 -2
- package/dist/layout/inspection.svelte.test.js +49 -0
- package/dist/overlays/FloatLayer.svelte +12 -1
- package/dist/overlays/float.d.ts +7 -0
- package/dist/overlays/float.js +76 -6
- package/dist/overlays/float.test.js +170 -0
- package/dist/primitives/widgets/DocumentFilePicker.d.ts +25 -0
- package/dist/primitives/widgets/DocumentFilePicker.js +74 -0
- package/dist/primitives/widgets/DocumentFilePicker.svelte +144 -0
- package/dist/primitives/widgets/DocumentFilePicker.svelte.d.ts +18 -0
- package/dist/primitives/widgets/DocumentOpener.svelte +36 -0
- package/dist/primitives/widgets/DocumentOpener.svelte.d.ts +17 -0
- package/dist/primitives/widgets/DocumentSaver.svelte +36 -0
- package/dist/primitives/widgets/DocumentSaver.svelte.d.ts +17 -0
- package/dist/primitives/widgets/_DocumentBrowser.svelte +339 -0
- package/dist/primitives/widgets/_DocumentBrowser.svelte.d.ts +12 -0
- package/dist/shards/activate.svelte.js +23 -14
- package/dist/shards/types.d.ts +8 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { CommitOnlyEvents } from './_contract';
|
|
2
|
+
import type { DocumentMeta } from '../../documents/types';
|
|
3
|
+
import type { SaverValue } from './DocumentFilePicker';
|
|
4
|
+
type DocListFn = () => Promise<Array<DocumentMeta & {
|
|
5
|
+
shardId: string;
|
|
6
|
+
}>>;
|
|
7
|
+
type $$ComponentProps = {
|
|
8
|
+
value?: SaverValue;
|
|
9
|
+
listDocuments: DocListFn;
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
invalid?: boolean;
|
|
12
|
+
size?: 'sm' | 'md';
|
|
13
|
+
buttonLabel?: string;
|
|
14
|
+
} & CommitOnlyEvents<SaverValue>;
|
|
15
|
+
declare const DocumentSaver: import("svelte").Component<$$ComponentProps, {}, "value">;
|
|
16
|
+
type DocumentSaver = ReturnType<typeof DocumentSaver>;
|
|
17
|
+
export default DocumentSaver;
|
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import {
|
|
3
|
+
buildTree,
|
|
4
|
+
formatSize,
|
|
5
|
+
formatDate,
|
|
6
|
+
iconForFile,
|
|
7
|
+
breadcrumbSegments,
|
|
8
|
+
type DocEntry,
|
|
9
|
+
type OpenerValue,
|
|
10
|
+
type SaverValue,
|
|
11
|
+
type FileItem,
|
|
12
|
+
} from './DocumentFilePicker';
|
|
13
|
+
|
|
14
|
+
let {
|
|
15
|
+
mode,
|
|
16
|
+
docs,
|
|
17
|
+
onCommit,
|
|
18
|
+
onCancel,
|
|
19
|
+
close,
|
|
20
|
+
suggestedName = '',
|
|
21
|
+
}: {
|
|
22
|
+
mode: 'open' | 'save';
|
|
23
|
+
docs: DocEntry[];
|
|
24
|
+
onCommit: (value: OpenerValue | SaverValue) => void;
|
|
25
|
+
onCancel: () => void;
|
|
26
|
+
close: () => void;
|
|
27
|
+
suggestedName?: string;
|
|
28
|
+
} = $props();
|
|
29
|
+
|
|
30
|
+
let shardId = $state<string | null>(null);
|
|
31
|
+
let prefix = $state('');
|
|
32
|
+
let selectedFile = $state<DocEntry | null>(null);
|
|
33
|
+
let filename = $state(suggestedName);
|
|
34
|
+
let activeIdx = $state(0);
|
|
35
|
+
let listEl = $state<HTMLElement | undefined>(undefined);
|
|
36
|
+
|
|
37
|
+
const items = $derived(buildTree(docs, shardId, prefix));
|
|
38
|
+
const crumbs = $derived(breadcrumbSegments(shardId, prefix));
|
|
39
|
+
|
|
40
|
+
$effect(() => {
|
|
41
|
+
items;
|
|
42
|
+
activeIdx = Math.min(activeIdx, items.length - 1);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
function navigateShard(id: string) {
|
|
46
|
+
shardId = id;
|
|
47
|
+
prefix = '';
|
|
48
|
+
selectedFile = null;
|
|
49
|
+
filename = '';
|
|
50
|
+
activeIdx = 0;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function navigatePrefix(p: string) {
|
|
54
|
+
if (shardId === null) {
|
|
55
|
+
navigateShard(p);
|
|
56
|
+
} else {
|
|
57
|
+
prefix = p;
|
|
58
|
+
selectedFile = null;
|
|
59
|
+
filename = '';
|
|
60
|
+
activeIdx = 0;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function selectFile(item: FileItem) {
|
|
65
|
+
if (item.kind === 'folder') {
|
|
66
|
+
navigatePrefix(item.fullPath);
|
|
67
|
+
} else {
|
|
68
|
+
if (mode === 'open') {
|
|
69
|
+
selectedFile = item.doc;
|
|
70
|
+
}
|
|
71
|
+
if (mode === 'save') {
|
|
72
|
+
filename = item.name;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function commit() {
|
|
78
|
+
if (mode === 'open' && selectedFile) {
|
|
79
|
+
onCommit({ shardId: selectedFile.shardId, path: selectedFile.path });
|
|
80
|
+
close();
|
|
81
|
+
} else if (mode === 'save' && filename.trim() && shardId) {
|
|
82
|
+
const p = prefix ? `${shardId}/${prefix}/${filename}` : `${shardId}/${filename}`;
|
|
83
|
+
onCommit(p);
|
|
84
|
+
close();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function cancel() {
|
|
89
|
+
onCancel();
|
|
90
|
+
close();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function canCommit(): boolean {
|
|
94
|
+
if (mode === 'open') return selectedFile !== null;
|
|
95
|
+
return filename.trim().length > 0 && shardId !== null;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function onKey(e: KeyboardEvent) {
|
|
99
|
+
if (e.target instanceof HTMLInputElement) return;
|
|
100
|
+
switch (e.key) {
|
|
101
|
+
case 'ArrowDown':
|
|
102
|
+
e.preventDefault();
|
|
103
|
+
activeIdx = Math.min(activeIdx + 1, items.length - 1);
|
|
104
|
+
break;
|
|
105
|
+
case 'ArrowUp':
|
|
106
|
+
e.preventDefault();
|
|
107
|
+
activeIdx = Math.max(activeIdx - 1, 0);
|
|
108
|
+
break;
|
|
109
|
+
case 'Enter':
|
|
110
|
+
e.preventDefault();
|
|
111
|
+
if (activeIdx >= 0 && activeIdx < items.length) {
|
|
112
|
+
selectFile(items[activeIdx]);
|
|
113
|
+
}
|
|
114
|
+
break;
|
|
115
|
+
case 'Escape':
|
|
116
|
+
e.preventDefault();
|
|
117
|
+
cancel();
|
|
118
|
+
break;
|
|
119
|
+
case 'Backspace':
|
|
120
|
+
if (prefix) {
|
|
121
|
+
e.preventDefault();
|
|
122
|
+
const parts = prefix.split('/');
|
|
123
|
+
parts.pop();
|
|
124
|
+
prefix = parts.join('/');
|
|
125
|
+
activeIdx = 0;
|
|
126
|
+
} else if (shardId) {
|
|
127
|
+
e.preventDefault();
|
|
128
|
+
shardId = null;
|
|
129
|
+
activeIdx = 0;
|
|
130
|
+
}
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function onDblClick(item: FileItem) {
|
|
136
|
+
if (item.kind === 'folder') {
|
|
137
|
+
navigatePrefix(item.fullPath);
|
|
138
|
+
} else if (mode === 'open') {
|
|
139
|
+
onCommit({ shardId: item.doc.shardId, path: item.doc.path });
|
|
140
|
+
close();
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
</script>
|
|
144
|
+
|
|
145
|
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
146
|
+
<div class="sh3-doc-browser" onkeydown={onKey} tabindex="-1">
|
|
147
|
+
<div class="sh3-doc-browser__head">
|
|
148
|
+
<span class="sh3-doc-browser__title">
|
|
149
|
+
{mode === 'open' ? 'Open Document' : 'Save Document'}
|
|
150
|
+
</span>
|
|
151
|
+
</div>
|
|
152
|
+
|
|
153
|
+
<nav class="sh3-doc-browser__crumbs">
|
|
154
|
+
{#each crumbs as seg, i}
|
|
155
|
+
{#if i > 0}<span class="sh3-doc-browser__crumb-sep">/</span>{/if}
|
|
156
|
+
<button
|
|
157
|
+
type="button"
|
|
158
|
+
class="sh3-doc-browser__crumb"
|
|
159
|
+
class:sh3-doc-browser__crumb--last={i === crumbs.length - 1}
|
|
160
|
+
onclick={() => {
|
|
161
|
+
shardId = seg.targetShard;
|
|
162
|
+
prefix = seg.targetPrefix;
|
|
163
|
+
selectedFile = null;
|
|
164
|
+
filename = '';
|
|
165
|
+
activeIdx = 0;
|
|
166
|
+
}}
|
|
167
|
+
>{seg.label}</button>
|
|
168
|
+
{/each}
|
|
169
|
+
</nav>
|
|
170
|
+
|
|
171
|
+
<div class="sh3-doc-browser__list" bind:this={listEl}>
|
|
172
|
+
{#if items.length === 0}
|
|
173
|
+
<div class="sh3-doc-browser__empty">
|
|
174
|
+
{shardId === null ? 'No shards available.' : prefix ? 'Empty directory.' : 'No documents in this shard.'}
|
|
175
|
+
</div>
|
|
176
|
+
{:else}
|
|
177
|
+
{#each items as item, i}
|
|
178
|
+
{@const isActive = i === activeIdx}
|
|
179
|
+
{@const isSelected = item.kind === 'file' && mode === 'open' && selectedFile?.path === item.doc.path && selectedFile?.shardId === item.doc.shardId}
|
|
180
|
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
181
|
+
<div
|
|
182
|
+
class="sh3-doc-browser__item"
|
|
183
|
+
class:sh3-doc-browser__item--active={isActive}
|
|
184
|
+
class:sh3-doc-browser__item--selected={isSelected}
|
|
185
|
+
class:sh3-doc-browser__item--folder={item.kind === 'folder'}
|
|
186
|
+
role="option"
|
|
187
|
+
tabindex="-1"
|
|
188
|
+
aria-selected={isSelected}
|
|
189
|
+
onclick={() => selectFile(item)}
|
|
190
|
+
onkeydown={(e) => { if (e.key === 'Enter') selectFile(item); }}
|
|
191
|
+
ondblclick={() => onDblClick(item)}
|
|
192
|
+
onmouseenter={() => activeIdx = i}
|
|
193
|
+
>
|
|
194
|
+
{#if item.kind === 'folder'}
|
|
195
|
+
<span class="sh3-doc-browser__icon sh3-doc-browser__icon--folder" aria-hidden="true">📁</span>
|
|
196
|
+
<span class="sh3-doc-browser__name">{item.name}</span>
|
|
197
|
+
<span class="sh3-doc-browser__meta"></span>
|
|
198
|
+
{:else}
|
|
199
|
+
<span class="sh3-doc-browser__icon" aria-hidden="true">{iconForFile(item.name)}</span>
|
|
200
|
+
<span class="sh3-doc-browser__name">{item.name}</span>
|
|
201
|
+
<span class="sh3-doc-browser__meta">
|
|
202
|
+
{formatSize(item.doc.size)}
|
|
203
|
+
<span class="sh3-doc-browser__date">{formatDate(item.doc.lastModified)}</span>
|
|
204
|
+
</span>
|
|
205
|
+
{/if}
|
|
206
|
+
</div>
|
|
207
|
+
{/each}
|
|
208
|
+
{/if}
|
|
209
|
+
</div>
|
|
210
|
+
|
|
211
|
+
{#if mode === 'save' && shardId !== null}
|
|
212
|
+
<div class="sh3-doc-browser__save-row">
|
|
213
|
+
<span class="sh3-doc-browser__save-label">Filename:</span>
|
|
214
|
+
<input
|
|
215
|
+
class="sh3-doc-browser__save-input"
|
|
216
|
+
type="text"
|
|
217
|
+
placeholder="filename.ext"
|
|
218
|
+
bind:value={filename}
|
|
219
|
+
onkeydown={(e) => { if (e.key === 'Enter' && canCommit()) commit(); }}
|
|
220
|
+
/>
|
|
221
|
+
</div>
|
|
222
|
+
{/if}
|
|
223
|
+
|
|
224
|
+
<div class="sh3-doc-browser__footer">
|
|
225
|
+
<button type="button" class="sh3-doc-browser__btn sh3-doc-browser__btn--cancel" onclick={cancel}>Cancel</button>
|
|
226
|
+
<button
|
|
227
|
+
type="button"
|
|
228
|
+
class="sh3-doc-browser__btn sh3-doc-browser__btn--primary"
|
|
229
|
+
disabled={!canCommit()}
|
|
230
|
+
onclick={commit}
|
|
231
|
+
>
|
|
232
|
+
{mode === 'open' ? 'Open' : 'Save'}
|
|
233
|
+
</button>
|
|
234
|
+
</div>
|
|
235
|
+
</div>
|
|
236
|
+
|
|
237
|
+
<style>
|
|
238
|
+
.sh3-doc-browser {
|
|
239
|
+
background: var(--sh3-bg-elevated);
|
|
240
|
+
border: 1px solid var(--sh3-border-strong);
|
|
241
|
+
border-radius: var(--sh3-widget-radius);
|
|
242
|
+
box-shadow: var(--sh3-shadow-lg);
|
|
243
|
+
width: 420px;
|
|
244
|
+
max-height: 480px;
|
|
245
|
+
display: flex; flex-direction: column;
|
|
246
|
+
overflow: hidden;
|
|
247
|
+
color: var(--sh3-fg);
|
|
248
|
+
font-size: 0.8125rem;
|
|
249
|
+
outline: none;
|
|
250
|
+
}
|
|
251
|
+
.sh3-doc-browser__head {
|
|
252
|
+
display: flex; align-items: center; justify-content: space-between;
|
|
253
|
+
padding: 8px 12px;
|
|
254
|
+
border-bottom: 1px solid var(--sh3-border);
|
|
255
|
+
}
|
|
256
|
+
.sh3-doc-browser__title { font-weight: 600; }
|
|
257
|
+
.sh3-doc-browser__crumbs {
|
|
258
|
+
display: flex; align-items: center; gap: 2px;
|
|
259
|
+
padding: 4px 8px;
|
|
260
|
+
border-bottom: 1px solid var(--sh3-border);
|
|
261
|
+
overflow-x: auto;
|
|
262
|
+
flex-shrink: 0;
|
|
263
|
+
}
|
|
264
|
+
.sh3-doc-browser__crumb {
|
|
265
|
+
display: inline-flex; align-items: center;
|
|
266
|
+
padding: 1px 4px;
|
|
267
|
+
border: none; background: none;
|
|
268
|
+
color: var(--sh3-fg-muted);
|
|
269
|
+
font: inherit; font-size: 0.75rem;
|
|
270
|
+
cursor: pointer;
|
|
271
|
+
border-radius: var(--sh3-radius-sm);
|
|
272
|
+
white-space: nowrap;
|
|
273
|
+
flex-shrink: 0;
|
|
274
|
+
}
|
|
275
|
+
.sh3-doc-browser__crumb:hover { background: var(--sh3-bg); color: var(--sh3-fg); }
|
|
276
|
+
.sh3-doc-browser__crumb--last { color: var(--sh3-fg); font-weight: 600; }
|
|
277
|
+
.sh3-doc-browser__crumb-sep { color: var(--sh3-fg-subtle); font-size: 0.75rem; flex-shrink: 0; }
|
|
278
|
+
.sh3-doc-browser__list { flex: 1; overflow-y: auto; padding: 4px 0; min-height: 0; }
|
|
279
|
+
.sh3-doc-browser__item { display: flex; align-items: center; gap: 8px; padding: 5px 12px; cursor: pointer; }
|
|
280
|
+
.sh3-doc-browser__item--active { background: var(--sh3-bg); }
|
|
281
|
+
.sh3-doc-browser__item--selected { background: var(--sh3-accent); color: var(--sh3-fg-on-accent); }
|
|
282
|
+
.sh3-doc-browser__item--active.sh3-doc-browser__item--selected { background: var(--sh3-accent); }
|
|
283
|
+
.sh3-doc-browser__icon { flex-shrink: 0; width: 18px; text-align: center; font-size: 0.875rem; }
|
|
284
|
+
.sh3-doc-browser__icon--folder { font-size: 0.75rem; }
|
|
285
|
+
.sh3-doc-browser__name {
|
|
286
|
+
flex: 1; min-width: 0;
|
|
287
|
+
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
288
|
+
font-family: var(--sh3-font-mono); font-size: 0.75rem;
|
|
289
|
+
}
|
|
290
|
+
.sh3-doc-browser__item--folder .sh3-doc-browser__name { font-family: inherit; font-size: 0.8125rem; }
|
|
291
|
+
.sh3-doc-browser__meta {
|
|
292
|
+
display: flex; align-items: center; gap: 10px;
|
|
293
|
+
flex-shrink: 0; font-size: 0.6875rem; color: var(--sh3-fg-muted);
|
|
294
|
+
}
|
|
295
|
+
.sh3-doc-browser__item--selected .sh3-doc-browser__meta { color: var(--sh3-fg-on-accent); opacity: 0.8; }
|
|
296
|
+
.sh3-doc-browser__date { color: var(--sh3-fg-subtle); }
|
|
297
|
+
.sh3-doc-browser__item--selected .sh3-doc-browser__date { color: var(--sh3-fg-on-accent); opacity: 0.65; }
|
|
298
|
+
.sh3-doc-browser__empty { padding: 20px 12px; text-align: center; color: var(--sh3-fg-muted); font-style: italic; }
|
|
299
|
+
.sh3-doc-browser__save-row {
|
|
300
|
+
display: flex; align-items: center; gap: 8px;
|
|
301
|
+
padding: 6px 12px; border-top: 1px solid var(--sh3-border);
|
|
302
|
+
}
|
|
303
|
+
.sh3-doc-browser__save-label { font-size: 0.75rem; color: var(--sh3-fg-muted); flex-shrink: 0; }
|
|
304
|
+
.sh3-doc-browser__save-input {
|
|
305
|
+
flex: 1;
|
|
306
|
+
height: var(--sh3-field-height-sm);
|
|
307
|
+
padding: 0 8px;
|
|
308
|
+
background: var(--sh3-input-bg);
|
|
309
|
+
border: 1px solid var(--sh3-border);
|
|
310
|
+
border-radius: var(--sh3-radius-sm);
|
|
311
|
+
color: var(--sh3-fg);
|
|
312
|
+
font: inherit; font-family: var(--sh3-font-mono); font-size: 0.75rem;
|
|
313
|
+
outline: none;
|
|
314
|
+
}
|
|
315
|
+
.sh3-doc-browser__save-input:focus { border-color: var(--sh3-input-border-focus); box-shadow: var(--sh3-focus-ring); }
|
|
316
|
+
.sh3-doc-browser__footer {
|
|
317
|
+
display: flex; justify-content: flex-end; gap: 8px;
|
|
318
|
+
padding: 8px 12px; border-top: 1px solid var(--sh3-border);
|
|
319
|
+
}
|
|
320
|
+
.sh3-doc-browser__btn {
|
|
321
|
+
display: inline-flex; align-items: center;
|
|
322
|
+
height: 26px; padding: 0 12px;
|
|
323
|
+
border: 1px solid var(--sh3-border);
|
|
324
|
+
border-radius: var(--sh3-radius-sm);
|
|
325
|
+
background: var(--sh3-bg-elevated);
|
|
326
|
+
color: var(--sh3-fg);
|
|
327
|
+
font: inherit; font-size: 0.75rem;
|
|
328
|
+
cursor: pointer;
|
|
329
|
+
}
|
|
330
|
+
.sh3-doc-browser__btn:hover { background: var(--sh3-bg); }
|
|
331
|
+
.sh3-doc-browser__btn--primary {
|
|
332
|
+
background: var(--sh3-accent);
|
|
333
|
+
color: var(--sh3-fg-on-accent);
|
|
334
|
+
border-color: var(--sh3-accent);
|
|
335
|
+
}
|
|
336
|
+
.sh3-doc-browser__btn--primary:hover { filter: brightness(1.1); }
|
|
337
|
+
.sh3-doc-browser__btn--primary:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
338
|
+
.sh3-doc-browser__btn--primary:disabled:hover { filter: none; }
|
|
339
|
+
</style>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type DocEntry, type OpenerValue, type SaverValue } from './DocumentFilePicker';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
mode: 'open' | 'save';
|
|
4
|
+
docs: DocEntry[];
|
|
5
|
+
onCommit: (value: OpenerValue | SaverValue) => void;
|
|
6
|
+
onCancel: () => void;
|
|
7
|
+
close: () => void;
|
|
8
|
+
suggestedName?: string;
|
|
9
|
+
};
|
|
10
|
+
declare const DocumentBrowser: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
11
|
+
type DocumentBrowser = ReturnType<typeof DocumentBrowser>;
|
|
12
|
+
export default DocumentBrowser;
|
|
@@ -28,6 +28,7 @@ import { createZoneManager } from '../state/manage';
|
|
|
28
28
|
import { PERMISSION_STATE_MANAGE } from '../state/types';
|
|
29
29
|
import { PERMISSION_DOCUMENTS_BROWSE, PERMISSION_DOCUMENTS_READ, PERMISSION_DOCUMENTS_WRITE, } from '../documents/types';
|
|
30
30
|
import { createBrowseCapability } from '../documents/browse';
|
|
31
|
+
import { createDocumentPicker } from '../documents/picker-primitive';
|
|
31
32
|
import { createShardKeysApi } from '../keys/client';
|
|
32
33
|
import { PERMISSION_KEYS_MINT } from '../keys/types';
|
|
33
34
|
import { subscribe } from '../keys/revocation-bus.svelte';
|
|
@@ -88,7 +89,7 @@ export function registerShard(shard) {
|
|
|
88
89
|
* @throws If the shard is not registered, if `shard.activate` throws, or if a manifest view has no factory after activation.
|
|
89
90
|
*/
|
|
90
91
|
export async function activateShard(id, opts) {
|
|
91
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
92
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
92
93
|
const shard = registeredShards.get(id);
|
|
93
94
|
if (!shard) {
|
|
94
95
|
throw new Error(`Cannot activate shard "${id}": not registered`);
|
|
@@ -143,6 +144,13 @@ export async function activateShard(id, opts) {
|
|
|
143
144
|
return off;
|
|
144
145
|
},
|
|
145
146
|
};
|
|
147
|
+
const hasBrowse = (_a = shard.manifest.permissions) === null || _a === void 0 ? void 0 : _a.includes(PERMISSION_DOCUMENTS_BROWSE);
|
|
148
|
+
const browseCap = hasBrowse
|
|
149
|
+
? createBrowseCapability(getTenantId(), getDocumentBackend(), {
|
|
150
|
+
canRead: (_c = (_b = shard.manifest.permissions) === null || _b === void 0 ? void 0 : _b.includes(PERMISSION_DOCUMENTS_READ)) !== null && _c !== void 0 ? _c : false,
|
|
151
|
+
canWrite: (_e = (_d = shard.manifest.permissions) === null || _d === void 0 ? void 0 : _d.includes(PERMISSION_DOCUMENTS_WRITE)) !== null && _e !== void 0 ? _e : false,
|
|
152
|
+
})
|
|
153
|
+
: undefined;
|
|
146
154
|
const ctx = {
|
|
147
155
|
state: (schema) => sh3.state(id, schema),
|
|
148
156
|
registerView: (viewId, factory) => {
|
|
@@ -212,19 +220,20 @@ export async function activateShard(id, opts) {
|
|
|
212
220
|
get tenantId() {
|
|
213
221
|
return getTenantId();
|
|
214
222
|
},
|
|
215
|
-
zones: ((
|
|
223
|
+
zones: ((_f = shard.manifest.permissions) === null || _f === void 0 ? void 0 : _f.includes(PERMISSION_STATE_MANAGE))
|
|
216
224
|
? createZoneManager()
|
|
217
225
|
: undefined,
|
|
218
|
-
browse:
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
226
|
+
browse: browseCap,
|
|
227
|
+
documentPicker: browseCap
|
|
228
|
+
? createDocumentPicker(() => browseCap.listDocuments())
|
|
229
|
+
: createDocumentPicker(async () => {
|
|
230
|
+
const docs = await getDocumentBackend().list(getTenantId(), id);
|
|
231
|
+
return docs.map(d => (Object.assign(Object.assign({}, d), { shardId: id })));
|
|
232
|
+
}),
|
|
233
|
+
keys: ((_g = shard.manifest.permissions) === null || _g === void 0 ? void 0 : _g.includes(PERMISSION_KEYS_MINT))
|
|
225
234
|
? createShardKeysApi({
|
|
226
235
|
shardId: id,
|
|
227
|
-
shardPermissions: (
|
|
236
|
+
shardPermissions: (_h = shard.manifest.permissions) !== null && _h !== void 0 ? _h : [],
|
|
228
237
|
})
|
|
229
238
|
: undefined,
|
|
230
239
|
contributions,
|
|
@@ -241,7 +250,7 @@ export async function activateShard(id, opts) {
|
|
|
241
250
|
sh3: makeSh3Api({
|
|
242
251
|
callerKind: 'shard',
|
|
243
252
|
callerShardId: id,
|
|
244
|
-
zones: ((
|
|
253
|
+
zones: ((_j = shard.manifest.permissions) === null || _j === void 0 ? void 0 : _j.includes(PERMISSION_STATE_MANAGE))
|
|
245
254
|
? createZoneManager()
|
|
246
255
|
: undefined,
|
|
247
256
|
}),
|
|
@@ -290,7 +299,7 @@ export async function activateShard(id, opts) {
|
|
|
290
299
|
try {
|
|
291
300
|
void fn();
|
|
292
301
|
}
|
|
293
|
-
catch (
|
|
302
|
+
catch (_m) {
|
|
294
303
|
// intentionally swallowed: original error is what matters.
|
|
295
304
|
}
|
|
296
305
|
}
|
|
@@ -304,7 +313,7 @@ export async function activateShard(id, opts) {
|
|
|
304
313
|
erroredShards.set(id, {
|
|
305
314
|
id,
|
|
306
315
|
error: err,
|
|
307
|
-
phase: (
|
|
316
|
+
phase: (_k = opts === null || opts === void 0 ? void 0 : opts.phase) !== null && _k !== void 0 ? _k : 'launch',
|
|
308
317
|
timestamp: Date.now(),
|
|
309
318
|
});
|
|
310
319
|
console.error(`[sh3] Shard "${id}" failed to activate:`, err);
|
|
@@ -312,7 +321,7 @@ export async function activateShard(id, opts) {
|
|
|
312
321
|
}
|
|
313
322
|
// Activation succeeded — clear any prior error record for this shard.
|
|
314
323
|
erroredShards.delete(id);
|
|
315
|
-
void ((
|
|
324
|
+
void ((_l = shard.autostart) === null || _l === void 0 ? void 0 : _l.call(shard, ctx));
|
|
316
325
|
}
|
|
317
326
|
/**
|
|
318
327
|
* Deactivate an active shard. Calls `shard.deactivate`, flushes and disposes
|
package/dist/shards/types.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { StateZones } from '../state/zones.svelte';
|
|
|
2
2
|
import type { ZoneSchema, ZoneManager } from '../state/types';
|
|
3
3
|
import type { DocumentHandle, DocumentHandleOptions } from '../documents/types';
|
|
4
4
|
import type { BrowseCapability } from '../documents/browse';
|
|
5
|
+
import type { DocumentPickerApi } from '../documents/picker-api';
|
|
5
6
|
import type { EnvState } from '../env/types';
|
|
6
7
|
import type { Verb } from '../verbs/types';
|
|
7
8
|
import type { Sh3Api } from '../verbs/types';
|
|
@@ -287,6 +288,13 @@ export interface ShardContext {
|
|
|
287
288
|
* owning shard's own `ctx.documents()` handle.
|
|
288
289
|
*/
|
|
289
290
|
browse?: BrowseCapability;
|
|
291
|
+
/**
|
|
292
|
+
* Programmatic document picker. Opens the DocumentBrowser popup scoped
|
|
293
|
+
* to this shard's document zone (or wider tree if the shard has the
|
|
294
|
+
* `documents:browse` permission). Returns the selected document reference
|
|
295
|
+
* or null if the user cancelled.
|
|
296
|
+
*/
|
|
297
|
+
documentPicker: DocumentPickerApi;
|
|
290
298
|
/**
|
|
291
299
|
* Mint/list/revoke keys minted by this shard. Only available when the
|
|
292
300
|
* manifest declares the `keys:mint` permission.
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** Auto-generated from package.json — do not edit manually. */
|
|
2
|
-
export declare const VERSION = "0.19.
|
|
2
|
+
export declare const VERSION = "0.19.6";
|
package/dist/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** Auto-generated from package.json — do not edit manually. */
|
|
2
|
-
export const VERSION = '0.19.
|
|
2
|
+
export const VERSION = '0.19.6';
|