@hexdspace/react 0.1.36 → 0.1.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +420 -6
- package/dist/index.js +1819 -113
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -353,8 +353,8 @@ var NotificationHost = ({
|
|
|
353
353
|
return isDark() ? "dark" : "light";
|
|
354
354
|
}, [isDark]);
|
|
355
355
|
const transition = useMemo2(() => {
|
|
356
|
-
const
|
|
357
|
-
return
|
|
356
|
+
const config2 = resolvedTheme.transition;
|
|
357
|
+
return config2 ? cssTransition(config2) : Slide;
|
|
358
358
|
}, [resolvedTheme.transition]);
|
|
359
359
|
const style = useMemo2(
|
|
360
360
|
() => ({
|
|
@@ -490,17 +490,17 @@ var AutoRefreshDecorator = class _AutoRefreshDecorator {
|
|
|
490
490
|
this.refresh = refresh2;
|
|
491
491
|
}
|
|
492
492
|
static inFlightRefresh = null;
|
|
493
|
-
async get(url,
|
|
494
|
-
return this.tryRequest(() => this.httpClient.get(url,
|
|
493
|
+
async get(url, config2) {
|
|
494
|
+
return this.tryRequest(() => this.httpClient.get(url, config2));
|
|
495
495
|
}
|
|
496
|
-
async post(url, data,
|
|
497
|
-
return this.tryRequest(() => this.httpClient.post(url, data,
|
|
496
|
+
async post(url, data, config2) {
|
|
497
|
+
return this.tryRequest(() => this.httpClient.post(url, data, config2));
|
|
498
498
|
}
|
|
499
|
-
async put(url, data,
|
|
500
|
-
return this.tryRequest(() => this.httpClient.put(url, data,
|
|
499
|
+
async put(url, data, config2) {
|
|
500
|
+
return this.tryRequest(() => this.httpClient.put(url, data, config2));
|
|
501
501
|
}
|
|
502
|
-
async delete(url,
|
|
503
|
-
return this.tryRequest(() => this.httpClient.delete(url,
|
|
502
|
+
async delete(url, config2) {
|
|
503
|
+
return this.tryRequest(() => this.httpClient.delete(url, config2));
|
|
504
504
|
}
|
|
505
505
|
async tryRequest(fn) {
|
|
506
506
|
try {
|
|
@@ -538,21 +538,21 @@ var FetchHttpClient = class {
|
|
|
538
538
|
constructor(baseURL = "/api") {
|
|
539
539
|
this.baseURL = baseURL;
|
|
540
540
|
}
|
|
541
|
-
async get(url,
|
|
542
|
-
return this.doRequest("GET", url, void 0,
|
|
541
|
+
async get(url, config2) {
|
|
542
|
+
return this.doRequest("GET", url, void 0, config2);
|
|
543
543
|
}
|
|
544
|
-
async post(url, data,
|
|
545
|
-
return this.doRequest("POST", url, data,
|
|
544
|
+
async post(url, data, config2) {
|
|
545
|
+
return this.doRequest("POST", url, data, config2);
|
|
546
546
|
}
|
|
547
|
-
async put(url, data,
|
|
548
|
-
return this.doRequest("PUT", url, data,
|
|
547
|
+
async put(url, data, config2) {
|
|
548
|
+
return this.doRequest("PUT", url, data, config2);
|
|
549
549
|
}
|
|
550
|
-
async delete(url,
|
|
551
|
-
return this.doRequest("DELETE", url, void 0,
|
|
550
|
+
async delete(url, config2) {
|
|
551
|
+
return this.doRequest("DELETE", url, void 0, config2);
|
|
552
552
|
}
|
|
553
|
-
async doRequest(method, url, body,
|
|
553
|
+
async doRequest(method, url, body, config2) {
|
|
554
554
|
const isFormData = body instanceof FormData;
|
|
555
|
-
const headers = { ...
|
|
555
|
+
const headers = { ...config2?.headers };
|
|
556
556
|
let parsedBody;
|
|
557
557
|
if (body !== void 0) {
|
|
558
558
|
parsedBody = isFormData ? body : JSON.stringify(body);
|
|
@@ -564,9 +564,9 @@ var FetchHttpClient = class {
|
|
|
564
564
|
const res = await fetch(this.resolve(url), {
|
|
565
565
|
method,
|
|
566
566
|
body: parsedBody,
|
|
567
|
-
headers: { ...headers, ...
|
|
567
|
+
headers: { ...headers, ...config2?.headers },
|
|
568
568
|
credentials: "include",
|
|
569
|
-
signal:
|
|
569
|
+
signal: config2?.signal
|
|
570
570
|
});
|
|
571
571
|
const data = await (res.headers.get("content-type")?.includes("application/json") ? res.json() : res.text());
|
|
572
572
|
if (!res.ok) {
|
|
@@ -630,24 +630,24 @@ var MockHttpClient = class {
|
|
|
630
630
|
reset() {
|
|
631
631
|
this.handlers.clear();
|
|
632
632
|
}
|
|
633
|
-
get(url,
|
|
634
|
-
return this.invoke("GET", url, void 0,
|
|
633
|
+
get(url, config2) {
|
|
634
|
+
return this.invoke("GET", url, void 0, config2);
|
|
635
635
|
}
|
|
636
|
-
post(url, data,
|
|
637
|
-
return this.invoke("POST", url, data,
|
|
636
|
+
post(url, data, config2) {
|
|
637
|
+
return this.invoke("POST", url, data, config2);
|
|
638
638
|
}
|
|
639
|
-
put(url, data,
|
|
640
|
-
return this.invoke("PUT", url, data,
|
|
639
|
+
put(url, data, config2) {
|
|
640
|
+
return this.invoke("PUT", url, data, config2);
|
|
641
641
|
}
|
|
642
|
-
delete(url,
|
|
643
|
-
return this.invoke("DELETE", url, void 0,
|
|
642
|
+
delete(url, config2) {
|
|
643
|
+
return this.invoke("DELETE", url, void 0, config2);
|
|
644
644
|
}
|
|
645
|
-
invoke(method, url, data,
|
|
645
|
+
invoke(method, url, data, config2) {
|
|
646
646
|
const handler = this.handlers.get(getKey(method, url));
|
|
647
647
|
if (!handler) {
|
|
648
648
|
return Promise.reject(new Error(`No mock handler registered for ${method} ${url}`));
|
|
649
649
|
}
|
|
650
|
-
const result = handler({ url, data, config });
|
|
650
|
+
const result = handler({ url, data, config: config2 });
|
|
651
651
|
return Promise.resolve(result);
|
|
652
652
|
}
|
|
653
653
|
};
|
|
@@ -903,7 +903,7 @@ function useAuthActions() {
|
|
|
903
903
|
const logout = useCallback2(() => {
|
|
904
904
|
authController2.logout().then(() => dispatch({ type: "LOGOUT" }));
|
|
905
905
|
}, [dispatch, authController2]);
|
|
906
|
-
const
|
|
906
|
+
const register2 = useCallback2(
|
|
907
907
|
async (email, password, attributes) => {
|
|
908
908
|
dispatch({ type: "REQUEST" });
|
|
909
909
|
const res = await authController2.register(email, password, attributes);
|
|
@@ -912,7 +912,7 @@ function useAuthActions() {
|
|
|
912
912
|
},
|
|
913
913
|
[dispatch, authController2]
|
|
914
914
|
);
|
|
915
|
-
return { login, logout, register };
|
|
915
|
+
return { login, logout, register: register2 };
|
|
916
916
|
}
|
|
917
917
|
function dispatchLoginResult(res, dispatch) {
|
|
918
918
|
if (res.ok) {
|
|
@@ -2032,8 +2032,8 @@ var InMemoryDialogRegistry = class {
|
|
|
2032
2032
|
|
|
2033
2033
|
// src/feature/dialog/infra/controller/dialog-controller.ts
|
|
2034
2034
|
var DialogController = class {
|
|
2035
|
-
constructor(
|
|
2036
|
-
this.registry =
|
|
2035
|
+
constructor(registry3, open2, resolve2, dismiss2, closeTop2) {
|
|
2036
|
+
this.registry = registry3;
|
|
2037
2037
|
this.open = open2;
|
|
2038
2038
|
this.resolve = resolve2;
|
|
2039
2039
|
this.dismiss = dismiss2;
|
|
@@ -2154,14 +2154,1661 @@ function useDialog() {
|
|
|
2154
2154
|
);
|
|
2155
2155
|
}
|
|
2156
2156
|
|
|
2157
|
+
// src/util/math-util.ts
|
|
2158
|
+
function clamp(n, min, max) {
|
|
2159
|
+
return Math.max(min, Math.min(max, n));
|
|
2160
|
+
}
|
|
2161
|
+
|
|
2162
|
+
// src/feature/selection/application/use-case/handle-selection-use-case.ts
|
|
2163
|
+
var DEFAULT_CLEAR_ARGS = {
|
|
2164
|
+
clearToggles: true,
|
|
2165
|
+
exitSelectMode: true,
|
|
2166
|
+
clearAnchor: true
|
|
2167
|
+
};
|
|
2168
|
+
var HandleSelectionUseCase = class {
|
|
2169
|
+
constructor(store) {
|
|
2170
|
+
this.store = store;
|
|
2171
|
+
}
|
|
2172
|
+
pushScope(scopeId) {
|
|
2173
|
+
const prev = this.store.get();
|
|
2174
|
+
const next = cloneState(prev);
|
|
2175
|
+
ensureScope(next, scopeId);
|
|
2176
|
+
removeFromStack(next.scopeStack, scopeId);
|
|
2177
|
+
next.scopeStack.push(scopeId);
|
|
2178
|
+
this.store.set(next);
|
|
2179
|
+
}
|
|
2180
|
+
popScope() {
|
|
2181
|
+
const prev = this.store.get();
|
|
2182
|
+
const next = cloneState(prev);
|
|
2183
|
+
const popped = next.scopeStack.pop() ?? null;
|
|
2184
|
+
this.store.set(next);
|
|
2185
|
+
return popped;
|
|
2186
|
+
}
|
|
2187
|
+
setActiveScope(scopeId) {
|
|
2188
|
+
const prev = this.store.get();
|
|
2189
|
+
const next = cloneState(prev);
|
|
2190
|
+
ensureScope(next, scopeId);
|
|
2191
|
+
removeFromStack(next.scopeStack, scopeId);
|
|
2192
|
+
next.scopeStack.push(scopeId);
|
|
2193
|
+
this.store.set(next);
|
|
2194
|
+
}
|
|
2195
|
+
ensureScope(scopeId) {
|
|
2196
|
+
const prev = this.store.get();
|
|
2197
|
+
const next = cloneState(prev);
|
|
2198
|
+
ensureScope(next, scopeId);
|
|
2199
|
+
this.store.set(next);
|
|
2200
|
+
}
|
|
2201
|
+
registerRegion(args) {
|
|
2202
|
+
const prev = this.store.get();
|
|
2203
|
+
const next = cloneState(prev);
|
|
2204
|
+
const scope = ensureScope(next, args.key.scopeId);
|
|
2205
|
+
const region = ensureRegion(scope, args.key.regionId);
|
|
2206
|
+
const hasInitialCursor = args.initialCursor !== void 0;
|
|
2207
|
+
if (hasInitialCursor) {
|
|
2208
|
+
region.cursor = args.initialCursor ?? null;
|
|
2209
|
+
}
|
|
2210
|
+
const items = args.getRegionItems();
|
|
2211
|
+
const previousItems = prev.items[toItemsKey(args.key)];
|
|
2212
|
+
const fallback = args.initialCursor ? items.includes(args.initialCursor) ? { kind: "id", id: args.initialCursor } : { kind: "first" } : void 0;
|
|
2213
|
+
reconcileRegionState(region, items, fallback, previousItems);
|
|
2214
|
+
if (args.makeActive) {
|
|
2215
|
+
scope.activeRegion = args.key.regionId;
|
|
2216
|
+
}
|
|
2217
|
+
next.items[toItemsKey(args.key)] = items;
|
|
2218
|
+
this.store.set(next);
|
|
2219
|
+
return (fallback2) => {
|
|
2220
|
+
this.refreshRegion(args.key, args.getRegionItems, fallback2);
|
|
2221
|
+
};
|
|
2222
|
+
}
|
|
2223
|
+
unregisterRegion(key) {
|
|
2224
|
+
const prev = this.store.get();
|
|
2225
|
+
const next = cloneState(prev);
|
|
2226
|
+
const scope = next.scopes[key.scopeId];
|
|
2227
|
+
if (!scope) {
|
|
2228
|
+
return;
|
|
2229
|
+
}
|
|
2230
|
+
const wasActive = scope.activeRegion === key.regionId;
|
|
2231
|
+
delete scope.regions[key.regionId];
|
|
2232
|
+
delete next.items[toItemsKey(key)];
|
|
2233
|
+
if (wasActive) {
|
|
2234
|
+
scope.activeRegion = null;
|
|
2235
|
+
if (scope.mode === "select") {
|
|
2236
|
+
scope.mode = "move";
|
|
2237
|
+
}
|
|
2238
|
+
}
|
|
2239
|
+
this.store.set(next);
|
|
2240
|
+
}
|
|
2241
|
+
setActiveRegion(key) {
|
|
2242
|
+
const prev = this.store.get();
|
|
2243
|
+
const next = cloneState(prev);
|
|
2244
|
+
const scope = ensureScope(next, key.scopeId);
|
|
2245
|
+
ensureRegion(scope, key.regionId);
|
|
2246
|
+
if (scope.activeRegion && scope.activeRegion !== key.regionId) {
|
|
2247
|
+
const prevRegion = scope.regions[scope.activeRegion];
|
|
2248
|
+
if (prevRegion) {
|
|
2249
|
+
prevRegion.cursor = null;
|
|
2250
|
+
}
|
|
2251
|
+
if (scope.mode === "select") {
|
|
2252
|
+
scope.mode = "move";
|
|
2253
|
+
for (const region of Object.values(scope.regions)) {
|
|
2254
|
+
region.selectAnchor = null;
|
|
2255
|
+
}
|
|
2256
|
+
}
|
|
2257
|
+
}
|
|
2258
|
+
scope.activeRegion = key.regionId;
|
|
2259
|
+
this.store.set(next);
|
|
2260
|
+
}
|
|
2261
|
+
setCursor(key, itemId) {
|
|
2262
|
+
const prev = this.store.get();
|
|
2263
|
+
const next = cloneState(prev);
|
|
2264
|
+
const scope = ensureScope(next, key.scopeId);
|
|
2265
|
+
const region = ensureRegion(scope, key.regionId);
|
|
2266
|
+
region.cursor = itemId;
|
|
2267
|
+
this.store.set(next);
|
|
2268
|
+
}
|
|
2269
|
+
moveCursor(key, delta) {
|
|
2270
|
+
const prev = this.store.get();
|
|
2271
|
+
const next = cloneState(prev);
|
|
2272
|
+
const scope = ensureScope(next, key.scopeId);
|
|
2273
|
+
const region = ensureRegion(scope, key.regionId);
|
|
2274
|
+
const items = getStoredItems(prev, key);
|
|
2275
|
+
if (items.length === 0) {
|
|
2276
|
+
region.cursor = null;
|
|
2277
|
+
this.store.set(next);
|
|
2278
|
+
return;
|
|
2279
|
+
}
|
|
2280
|
+
const index = region.cursor ? getIndex(items, region.cursor) : null;
|
|
2281
|
+
if (index === null) {
|
|
2282
|
+
if (delta === 0) {
|
|
2283
|
+
this.store.set(next);
|
|
2284
|
+
return;
|
|
2285
|
+
}
|
|
2286
|
+
region.cursor = delta > 0 ? items[0] : items[items.length - 1];
|
|
2287
|
+
this.store.set(next);
|
|
2288
|
+
return;
|
|
2289
|
+
}
|
|
2290
|
+
const nextIndex = clamp(index + delta, 0, items.length - 1);
|
|
2291
|
+
region.cursor = items[nextIndex];
|
|
2292
|
+
this.store.set(next);
|
|
2293
|
+
}
|
|
2294
|
+
enterSelectMode(key) {
|
|
2295
|
+
const prev = this.store.get();
|
|
2296
|
+
const next = cloneState(prev);
|
|
2297
|
+
const scope = ensureScope(next, key.scopeId);
|
|
2298
|
+
const region = ensureRegion(scope, key.regionId);
|
|
2299
|
+
if (!region.cursor) {
|
|
2300
|
+
const items = getStoredItems(prev, key);
|
|
2301
|
+
region.cursor = getFallbackCursor(items, { kind: "first" });
|
|
2302
|
+
}
|
|
2303
|
+
removeFromStack(next.scopeStack, key.scopeId);
|
|
2304
|
+
next.scopeStack.push(key.scopeId);
|
|
2305
|
+
scope.mode = "select";
|
|
2306
|
+
scope.activeRegion = key.regionId;
|
|
2307
|
+
region.selectAnchor = region.cursor;
|
|
2308
|
+
this.store.set(next);
|
|
2309
|
+
}
|
|
2310
|
+
exitSelectMode(scopeId) {
|
|
2311
|
+
const prev = this.store.get();
|
|
2312
|
+
const next = cloneState(prev);
|
|
2313
|
+
const scope = ensureScope(next, scopeId);
|
|
2314
|
+
scope.mode = "move";
|
|
2315
|
+
for (const region of Object.values(scope.regions)) {
|
|
2316
|
+
region.selectAnchor = null;
|
|
2317
|
+
}
|
|
2318
|
+
this.store.set(next);
|
|
2319
|
+
}
|
|
2320
|
+
toggleItem(key, itemId) {
|
|
2321
|
+
const prev = this.store.get();
|
|
2322
|
+
const targetId = itemId ?? prev.scopes[key.scopeId]?.regions[key.regionId]?.cursor ?? null;
|
|
2323
|
+
if (!targetId) {
|
|
2324
|
+
return;
|
|
2325
|
+
}
|
|
2326
|
+
const next = cloneState(prev);
|
|
2327
|
+
const scope = ensureScope(next, key.scopeId);
|
|
2328
|
+
const region = ensureRegion(scope, key.regionId);
|
|
2329
|
+
if (region.toggled.has(targetId)) {
|
|
2330
|
+
region.toggled.delete(targetId);
|
|
2331
|
+
} else {
|
|
2332
|
+
region.toggled.add(targetId);
|
|
2333
|
+
}
|
|
2334
|
+
this.store.set(next);
|
|
2335
|
+
}
|
|
2336
|
+
clearSelection(target, args) {
|
|
2337
|
+
const prev = this.store.get();
|
|
2338
|
+
const next = cloneState(prev);
|
|
2339
|
+
const opts = { ...DEFAULT_CLEAR_ARGS, ...args };
|
|
2340
|
+
if (target.kind === "activeScope") {
|
|
2341
|
+
const scopeId = getActiveScopeId(next);
|
|
2342
|
+
if (!scopeId) {
|
|
2343
|
+
return;
|
|
2344
|
+
}
|
|
2345
|
+
const scope = next.scopes[scopeId];
|
|
2346
|
+
if (!scope) {
|
|
2347
|
+
return;
|
|
2348
|
+
}
|
|
2349
|
+
clearScope(scope, opts);
|
|
2350
|
+
this.store.set(next);
|
|
2351
|
+
return;
|
|
2352
|
+
}
|
|
2353
|
+
if (target.kind === "scope") {
|
|
2354
|
+
const scope = next.scopes[target.scopeId];
|
|
2355
|
+
if (!scope) {
|
|
2356
|
+
return;
|
|
2357
|
+
}
|
|
2358
|
+
clearScope(scope, opts);
|
|
2359
|
+
this.store.set(next);
|
|
2360
|
+
return;
|
|
2361
|
+
}
|
|
2362
|
+
if (target.kind === "activeRegion") {
|
|
2363
|
+
const scopeId = getActiveScopeId(next);
|
|
2364
|
+
if (!scopeId) {
|
|
2365
|
+
return;
|
|
2366
|
+
}
|
|
2367
|
+
const scope = next.scopes[scopeId];
|
|
2368
|
+
const regionId = scope?.activeRegion;
|
|
2369
|
+
if (!scope || !regionId) {
|
|
2370
|
+
return;
|
|
2371
|
+
}
|
|
2372
|
+
clearRegion(scope, regionId, opts);
|
|
2373
|
+
this.store.set(next);
|
|
2374
|
+
return;
|
|
2375
|
+
}
|
|
2376
|
+
if (target.kind === "region") {
|
|
2377
|
+
const scope = next.scopes[target.key.scopeId];
|
|
2378
|
+
if (!scope) {
|
|
2379
|
+
return;
|
|
2380
|
+
}
|
|
2381
|
+
clearRegion(scope, target.key.regionId, opts);
|
|
2382
|
+
this.store.set(next);
|
|
2383
|
+
}
|
|
2384
|
+
}
|
|
2385
|
+
refreshRegion(key, getRegionItems, fallbackOverride) {
|
|
2386
|
+
const prev = this.store.get();
|
|
2387
|
+
const prevScope = prev.scopes[key.scopeId];
|
|
2388
|
+
if (!prevScope || !prevScope.regions[key.regionId]) {
|
|
2389
|
+
return;
|
|
2390
|
+
}
|
|
2391
|
+
const next = cloneState(prev);
|
|
2392
|
+
const scope = ensureScope(next, key.scopeId);
|
|
2393
|
+
const region = ensureRegion(scope, key.regionId);
|
|
2394
|
+
const items = getRegionItems();
|
|
2395
|
+
const previousItems = prev.items[toItemsKey(key)];
|
|
2396
|
+
const fallback = fallbackOverride ?? (region.cursor ? { kind: "nearestTo", id: region.cursor } : void 0);
|
|
2397
|
+
reconcileRegionState(region, items, fallback, previousItems);
|
|
2398
|
+
next.items[toItemsKey(key)] = items;
|
|
2399
|
+
this.store.set(next);
|
|
2400
|
+
}
|
|
2401
|
+
};
|
|
2402
|
+
function cloneState(prev) {
|
|
2403
|
+
const scopes2 = {};
|
|
2404
|
+
for (const [scopeId, scope] of Object.entries(prev.scopes)) {
|
|
2405
|
+
const regions = {};
|
|
2406
|
+
for (const [regionId, region] of Object.entries(scope.regions)) {
|
|
2407
|
+
regions[regionId] = {
|
|
2408
|
+
cursor: region.cursor,
|
|
2409
|
+
toggled: new Set(region.toggled),
|
|
2410
|
+
selectAnchor: region.selectAnchor
|
|
2411
|
+
};
|
|
2412
|
+
}
|
|
2413
|
+
scopes2[scopeId] = {
|
|
2414
|
+
activeRegion: scope.activeRegion,
|
|
2415
|
+
mode: scope.mode,
|
|
2416
|
+
regions
|
|
2417
|
+
};
|
|
2418
|
+
}
|
|
2419
|
+
return {
|
|
2420
|
+
scopeStack: [...prev.scopeStack],
|
|
2421
|
+
scopes: scopes2,
|
|
2422
|
+
items: { ...prev.items }
|
|
2423
|
+
};
|
|
2424
|
+
}
|
|
2425
|
+
function ensureScope(state, scopeId) {
|
|
2426
|
+
if (!state.scopes[scopeId]) {
|
|
2427
|
+
state.scopes[scopeId] = {
|
|
2428
|
+
activeRegion: null,
|
|
2429
|
+
mode: "move",
|
|
2430
|
+
regions: {}
|
|
2431
|
+
};
|
|
2432
|
+
}
|
|
2433
|
+
return state.scopes[scopeId];
|
|
2434
|
+
}
|
|
2435
|
+
function ensureRegion(scope, regionId) {
|
|
2436
|
+
if (!scope.regions[regionId]) {
|
|
2437
|
+
scope.regions[regionId] = {
|
|
2438
|
+
cursor: null,
|
|
2439
|
+
toggled: /* @__PURE__ */ new Set(),
|
|
2440
|
+
selectAnchor: null
|
|
2441
|
+
};
|
|
2442
|
+
}
|
|
2443
|
+
return scope.regions[regionId];
|
|
2444
|
+
}
|
|
2445
|
+
function removeFromStack(stack, scopeId) {
|
|
2446
|
+
const index = stack.indexOf(scopeId);
|
|
2447
|
+
if (index >= 0) {
|
|
2448
|
+
stack.splice(index, 1);
|
|
2449
|
+
}
|
|
2450
|
+
}
|
|
2451
|
+
function getActiveScopeId(state) {
|
|
2452
|
+
return state.scopeStack.length > 0 ? state.scopeStack[state.scopeStack.length - 1] : null;
|
|
2453
|
+
}
|
|
2454
|
+
function clearScope(scope, args) {
|
|
2455
|
+
if (args.exitSelectMode) {
|
|
2456
|
+
scope.mode = "move";
|
|
2457
|
+
}
|
|
2458
|
+
for (const region of Object.values(scope.regions)) {
|
|
2459
|
+
if (args.clearToggles) {
|
|
2460
|
+
region.toggled = /* @__PURE__ */ new Set();
|
|
2461
|
+
}
|
|
2462
|
+
if (args.clearAnchor) {
|
|
2463
|
+
region.selectAnchor = null;
|
|
2464
|
+
}
|
|
2465
|
+
}
|
|
2466
|
+
}
|
|
2467
|
+
function clearRegion(scope, regionId, args) {
|
|
2468
|
+
if (args.exitSelectMode) {
|
|
2469
|
+
scope.mode = "move";
|
|
2470
|
+
}
|
|
2471
|
+
const region = scope.regions[regionId];
|
|
2472
|
+
if (!region) {
|
|
2473
|
+
return;
|
|
2474
|
+
}
|
|
2475
|
+
if (args.clearToggles) {
|
|
2476
|
+
region.toggled = /* @__PURE__ */ new Set();
|
|
2477
|
+
}
|
|
2478
|
+
if (args.clearAnchor) {
|
|
2479
|
+
region.selectAnchor = null;
|
|
2480
|
+
}
|
|
2481
|
+
}
|
|
2482
|
+
function reconcileRegionState(region, items, fallback, previousItems) {
|
|
2483
|
+
if (items.length === 0) {
|
|
2484
|
+
region.cursor = null;
|
|
2485
|
+
region.selectAnchor = null;
|
|
2486
|
+
region.toggled = /* @__PURE__ */ new Set();
|
|
2487
|
+
return;
|
|
2488
|
+
}
|
|
2489
|
+
const itemSet = new Set(items);
|
|
2490
|
+
if (!region.cursor) {
|
|
2491
|
+
region.cursor = getFallbackCursor(items, fallback, previousItems);
|
|
2492
|
+
} else if (!itemSet.has(region.cursor)) {
|
|
2493
|
+
region.cursor = getFallbackCursor(items, fallback, previousItems);
|
|
2494
|
+
}
|
|
2495
|
+
if (region.selectAnchor && !itemSet.has(region.selectAnchor)) {
|
|
2496
|
+
region.selectAnchor = null;
|
|
2497
|
+
}
|
|
2498
|
+
if (region.toggled.size > 0) {
|
|
2499
|
+
for (const id of region.toggled) {
|
|
2500
|
+
if (!itemSet.has(id)) {
|
|
2501
|
+
region.toggled.delete(id);
|
|
2502
|
+
}
|
|
2503
|
+
}
|
|
2504
|
+
}
|
|
2505
|
+
}
|
|
2506
|
+
function getFallbackCursor(items, fallback, previousItems) {
|
|
2507
|
+
if (!fallback || fallback.kind === "none") {
|
|
2508
|
+
return null;
|
|
2509
|
+
}
|
|
2510
|
+
if (fallback.kind === "first") {
|
|
2511
|
+
return items[0] ?? null;
|
|
2512
|
+
}
|
|
2513
|
+
if (fallback.kind === "last") {
|
|
2514
|
+
return items[items.length - 1] ?? null;
|
|
2515
|
+
}
|
|
2516
|
+
if (fallback.kind === "id") {
|
|
2517
|
+
return items.includes(fallback.id) ? fallback.id : null;
|
|
2518
|
+
}
|
|
2519
|
+
if (fallback.kind === "nth") {
|
|
2520
|
+
const idx = clamp(fallback.idx, 0, items.length - 1);
|
|
2521
|
+
return items[idx] ?? null;
|
|
2522
|
+
}
|
|
2523
|
+
if (fallback.kind === "nearestTo") {
|
|
2524
|
+
return getNearestCursor(items, fallback.id, previousItems);
|
|
2525
|
+
}
|
|
2526
|
+
if (fallback.kind === "sameIndex") {
|
|
2527
|
+
return null;
|
|
2528
|
+
}
|
|
2529
|
+
throw new Error(`Invalid cursor fallback type of: ${JSON.stringify(fallback)} did not match any handler.`);
|
|
2530
|
+
}
|
|
2531
|
+
function getNearestCursor(items, id, previousItems) {
|
|
2532
|
+
if (items.includes(id)) {
|
|
2533
|
+
return id;
|
|
2534
|
+
}
|
|
2535
|
+
const prevList = previousItems ?? [];
|
|
2536
|
+
const prevIndex = prevList.indexOf(id);
|
|
2537
|
+
if (prevIndex < 0) {
|
|
2538
|
+
return null;
|
|
2539
|
+
}
|
|
2540
|
+
const itemSet = new Set(items);
|
|
2541
|
+
for (let offset = 1; offset < prevList.length; offset += 1) {
|
|
2542
|
+
const forwardIndex = prevIndex + offset;
|
|
2543
|
+
if (forwardIndex < prevList.length) {
|
|
2544
|
+
const forwardId = prevList[forwardIndex];
|
|
2545
|
+
if (forwardId && itemSet.has(forwardId)) {
|
|
2546
|
+
return forwardId;
|
|
2547
|
+
}
|
|
2548
|
+
}
|
|
2549
|
+
const backwardIndex = prevIndex - offset;
|
|
2550
|
+
if (backwardIndex >= 0) {
|
|
2551
|
+
const backwardId = prevList[backwardIndex];
|
|
2552
|
+
if (backwardId && itemSet.has(backwardId)) {
|
|
2553
|
+
return backwardId;
|
|
2554
|
+
}
|
|
2555
|
+
}
|
|
2556
|
+
}
|
|
2557
|
+
return null;
|
|
2558
|
+
}
|
|
2559
|
+
function getIndex(items, itemId) {
|
|
2560
|
+
const index = items.indexOf(itemId);
|
|
2561
|
+
return index >= 0 ? index : null;
|
|
2562
|
+
}
|
|
2563
|
+
function toItemsKey(key) {
|
|
2564
|
+
return `${key.scopeId}:${key.regionId}`;
|
|
2565
|
+
}
|
|
2566
|
+
function getStoredItems(state, key) {
|
|
2567
|
+
return state.items[toItemsKey(key)] ?? [];
|
|
2568
|
+
}
|
|
2569
|
+
|
|
2570
|
+
// src/feature/selection/application/use-case/query-selection-use-case.ts
|
|
2571
|
+
var QuerySelectionUseCase = class {
|
|
2572
|
+
constructor(store, combineMode = "xor") {
|
|
2573
|
+
this.store = store;
|
|
2574
|
+
this.combineMode = combineMode;
|
|
2575
|
+
}
|
|
2576
|
+
getActiveScope() {
|
|
2577
|
+
return getActiveScopeId2(this.store.get());
|
|
2578
|
+
}
|
|
2579
|
+
getActiveRegion(scopeId) {
|
|
2580
|
+
const scope = this.store.get().scopes[scopeId];
|
|
2581
|
+
if (!scope || !scope.activeRegion) {
|
|
2582
|
+
return null;
|
|
2583
|
+
}
|
|
2584
|
+
return { scopeId, regionId: scope.activeRegion };
|
|
2585
|
+
}
|
|
2586
|
+
getMode(scopeId) {
|
|
2587
|
+
return this.store.get().scopes[scopeId]?.mode ?? "move";
|
|
2588
|
+
}
|
|
2589
|
+
getCursor(key) {
|
|
2590
|
+
return this.store.get().scopes[key.scopeId]?.regions[key.regionId]?.cursor ?? null;
|
|
2591
|
+
}
|
|
2592
|
+
isSelected(key, itemId) {
|
|
2593
|
+
const state = this.store.get();
|
|
2594
|
+
const selection = getRegionSelection(state, key);
|
|
2595
|
+
if (!selection) {
|
|
2596
|
+
return false;
|
|
2597
|
+
}
|
|
2598
|
+
const scopeMode = state.scopes[key.scopeId]?.mode ?? "move";
|
|
2599
|
+
const items = getStoredItems2(state, key);
|
|
2600
|
+
return isSelectedItem(items, selection, itemId, scopeMode, this.combineMode);
|
|
2601
|
+
}
|
|
2602
|
+
getSelectedIds(key) {
|
|
2603
|
+
const state = this.store.get();
|
|
2604
|
+
const selection = getRegionSelection(state, key);
|
|
2605
|
+
if (!selection) {
|
|
2606
|
+
return [];
|
|
2607
|
+
}
|
|
2608
|
+
const scopeMode = state.scopes[key.scopeId]?.mode ?? "move";
|
|
2609
|
+
const items = getStoredItems2(state, key);
|
|
2610
|
+
return getSelectedIds(items, selection, scopeMode, this.combineMode);
|
|
2611
|
+
}
|
|
2612
|
+
getToggledIds(key) {
|
|
2613
|
+
const selection = getRegionSelection(this.store.get(), key);
|
|
2614
|
+
if (!selection) {
|
|
2615
|
+
return [];
|
|
2616
|
+
}
|
|
2617
|
+
const items = getStoredItems2(this.store.get(), key);
|
|
2618
|
+
return items.filter((id) => selection.toggled.has(id));
|
|
2619
|
+
}
|
|
2620
|
+
getRangeIds(key) {
|
|
2621
|
+
const state = this.store.get();
|
|
2622
|
+
const selection = getRegionSelection(state, key);
|
|
2623
|
+
if (!selection) {
|
|
2624
|
+
return [];
|
|
2625
|
+
}
|
|
2626
|
+
const scopeMode = state.scopes[key.scopeId]?.mode ?? "move";
|
|
2627
|
+
if (scopeMode !== "select") {
|
|
2628
|
+
return [];
|
|
2629
|
+
}
|
|
2630
|
+
const items = getStoredItems2(state, key);
|
|
2631
|
+
return getRangeIds(items, selection.selectAnchor, selection.cursor);
|
|
2632
|
+
}
|
|
2633
|
+
};
|
|
2634
|
+
function getRegionSelection(state, key) {
|
|
2635
|
+
return state.scopes[key.scopeId]?.regions[key.regionId] ?? null;
|
|
2636
|
+
}
|
|
2637
|
+
function getActiveScopeId2(state) {
|
|
2638
|
+
return state.scopeStack.length > 0 ? state.scopeStack[state.scopeStack.length - 1] : null;
|
|
2639
|
+
}
|
|
2640
|
+
function getStoredItems2(state, key) {
|
|
2641
|
+
return state.items[`${key.scopeId}:${key.regionId}`] ?? [];
|
|
2642
|
+
}
|
|
2643
|
+
function getRangeIds(items, anchor, cursor) {
|
|
2644
|
+
if (!anchor || !cursor) {
|
|
2645
|
+
return [];
|
|
2646
|
+
}
|
|
2647
|
+
const anchorIndex = items.indexOf(anchor);
|
|
2648
|
+
const cursorIndex = items.indexOf(cursor);
|
|
2649
|
+
if (anchorIndex < 0 || cursorIndex < 0) {
|
|
2650
|
+
return [];
|
|
2651
|
+
}
|
|
2652
|
+
const start = Math.min(anchorIndex, cursorIndex);
|
|
2653
|
+
const end = Math.max(anchorIndex, cursorIndex);
|
|
2654
|
+
return items.slice(start, end + 1);
|
|
2655
|
+
}
|
|
2656
|
+
function getSelectedIds(items, selection, mode, combineMode) {
|
|
2657
|
+
if (mode === "move") {
|
|
2658
|
+
if (selection.toggled.size === 0) {
|
|
2659
|
+
return [];
|
|
2660
|
+
}
|
|
2661
|
+
return items.filter((id) => selection.toggled.has(id));
|
|
2662
|
+
}
|
|
2663
|
+
const rangeIds = new Set(getRangeIds(items, selection.selectAnchor, selection.cursor));
|
|
2664
|
+
if (selection.toggled.size === 0 && rangeIds.size === 0) {
|
|
2665
|
+
return [];
|
|
2666
|
+
}
|
|
2667
|
+
return items.filter(
|
|
2668
|
+
(id) => combineMode === "union" ? rangeIds.has(id) || selection.toggled.has(id) : rangeIds.has(id) !== selection.toggled.has(id)
|
|
2669
|
+
);
|
|
2670
|
+
}
|
|
2671
|
+
function isSelectedItem(items, selection, itemId, mode, combineMode) {
|
|
2672
|
+
if (mode === "move") {
|
|
2673
|
+
return selection.toggled.has(itemId);
|
|
2674
|
+
}
|
|
2675
|
+
const rangeIds = new Set(getRangeIds(items, selection.selectAnchor, selection.cursor));
|
|
2676
|
+
return combineMode === "union" ? rangeIds.has(itemId) || selection.toggled.has(itemId) : rangeIds.has(itemId) !== selection.toggled.has(itemId);
|
|
2677
|
+
}
|
|
2678
|
+
|
|
2679
|
+
// src/feature/selection/infra/in-memory-selection-store.ts
|
|
2680
|
+
var InMemorySelectionStore = class {
|
|
2681
|
+
constructor(state = { scopeStack: [], scopes: {}, items: {} }) {
|
|
2682
|
+
this.state = state;
|
|
2683
|
+
}
|
|
2684
|
+
get() {
|
|
2685
|
+
return this.state;
|
|
2686
|
+
}
|
|
2687
|
+
set(next) {
|
|
2688
|
+
this.state = next;
|
|
2689
|
+
}
|
|
2690
|
+
};
|
|
2691
|
+
|
|
2692
|
+
// src/feature/selection/infra/controller/selection-controller.ts
|
|
2693
|
+
var SelectionController = class {
|
|
2694
|
+
handleSelection;
|
|
2695
|
+
querySelection;
|
|
2696
|
+
selectionStore;
|
|
2697
|
+
subscribeFn;
|
|
2698
|
+
version = 0;
|
|
2699
|
+
constructor(deps) {
|
|
2700
|
+
this.handleSelection = deps.handleSelection;
|
|
2701
|
+
this.querySelection = deps.querySelection;
|
|
2702
|
+
this.selectionStore = deps.selectionStore;
|
|
2703
|
+
this.subscribeFn = createSubscriptionAdapter(this.selectionStore, () => {
|
|
2704
|
+
this.version += 1;
|
|
2705
|
+
});
|
|
2706
|
+
}
|
|
2707
|
+
registerRegion(args) {
|
|
2708
|
+
return this.handleSelection.registerRegion(args);
|
|
2709
|
+
}
|
|
2710
|
+
pushScope(scopeId) {
|
|
2711
|
+
this.handleSelection.pushScope(scopeId);
|
|
2712
|
+
}
|
|
2713
|
+
popScope() {
|
|
2714
|
+
return this.handleSelection.popScope();
|
|
2715
|
+
}
|
|
2716
|
+
setActiveScope(scopeId) {
|
|
2717
|
+
this.handleSelection.setActiveScope(scopeId);
|
|
2718
|
+
}
|
|
2719
|
+
ensureScope(scopeId) {
|
|
2720
|
+
this.handleSelection.ensureScope(scopeId);
|
|
2721
|
+
}
|
|
2722
|
+
unregisterRegion(key) {
|
|
2723
|
+
this.handleSelection.unregisterRegion(key);
|
|
2724
|
+
}
|
|
2725
|
+
setActiveRegion(key) {
|
|
2726
|
+
this.handleSelection.setActiveRegion(key);
|
|
2727
|
+
}
|
|
2728
|
+
setCursor(key, itemId) {
|
|
2729
|
+
this.handleSelection.setCursor(key, itemId);
|
|
2730
|
+
}
|
|
2731
|
+
moveCursor(key, delta) {
|
|
2732
|
+
this.handleSelection.moveCursor(key, delta);
|
|
2733
|
+
}
|
|
2734
|
+
enterSelectMode(key) {
|
|
2735
|
+
this.handleSelection.enterSelectMode(key);
|
|
2736
|
+
}
|
|
2737
|
+
exitSelectMode(scopeId) {
|
|
2738
|
+
this.handleSelection.exitSelectMode(scopeId);
|
|
2739
|
+
}
|
|
2740
|
+
toggleItem(key, itemId) {
|
|
2741
|
+
this.handleSelection.toggleItem(key, itemId);
|
|
2742
|
+
}
|
|
2743
|
+
clearSelection(target, args) {
|
|
2744
|
+
this.handleSelection.clearSelection(target, args);
|
|
2745
|
+
}
|
|
2746
|
+
getActiveScope() {
|
|
2747
|
+
return this.querySelection.getActiveScope();
|
|
2748
|
+
}
|
|
2749
|
+
getActiveRegion(scopeId) {
|
|
2750
|
+
return this.querySelection.getActiveRegion(scopeId);
|
|
2751
|
+
}
|
|
2752
|
+
getActiveItem(key) {
|
|
2753
|
+
const resolved = this.resolveKey(key);
|
|
2754
|
+
if (!resolved) {
|
|
2755
|
+
return null;
|
|
2756
|
+
}
|
|
2757
|
+
return this.querySelection.getCursor(resolved);
|
|
2758
|
+
}
|
|
2759
|
+
getItems(key) {
|
|
2760
|
+
const resolved = this.resolveKey(key);
|
|
2761
|
+
if (!resolved) {
|
|
2762
|
+
return [];
|
|
2763
|
+
}
|
|
2764
|
+
return this.selectionStore.get().items[toItemsKey2(resolved)] ?? [];
|
|
2765
|
+
}
|
|
2766
|
+
getSelectedIds(key) {
|
|
2767
|
+
const resolved = this.resolveKey(key);
|
|
2768
|
+
if (!resolved) {
|
|
2769
|
+
return [];
|
|
2770
|
+
}
|
|
2771
|
+
return this.querySelection.getSelectedIds(resolved);
|
|
2772
|
+
}
|
|
2773
|
+
getToggledIds(key) {
|
|
2774
|
+
const resolved = this.resolveKey(key);
|
|
2775
|
+
if (!resolved) {
|
|
2776
|
+
return [];
|
|
2777
|
+
}
|
|
2778
|
+
return this.querySelection.getToggledIds(resolved);
|
|
2779
|
+
}
|
|
2780
|
+
getRangeIds(key) {
|
|
2781
|
+
const resolved = this.resolveKey(key);
|
|
2782
|
+
if (!resolved) {
|
|
2783
|
+
return [];
|
|
2784
|
+
}
|
|
2785
|
+
return this.querySelection.getRangeIds(resolved);
|
|
2786
|
+
}
|
|
2787
|
+
isSelected(key, itemId) {
|
|
2788
|
+
return this.querySelection.isSelected(key, itemId);
|
|
2789
|
+
}
|
|
2790
|
+
getMode(scopeId) {
|
|
2791
|
+
return this.querySelection.getMode(scopeId);
|
|
2792
|
+
}
|
|
2793
|
+
getQuery() {
|
|
2794
|
+
return this.querySelection;
|
|
2795
|
+
}
|
|
2796
|
+
getStore() {
|
|
2797
|
+
return this.selectionStore;
|
|
2798
|
+
}
|
|
2799
|
+
getHandle() {
|
|
2800
|
+
return this.handleSelection;
|
|
2801
|
+
}
|
|
2802
|
+
subscribe(listener) {
|
|
2803
|
+
return this.subscribeFn(listener);
|
|
2804
|
+
}
|
|
2805
|
+
getVersion() {
|
|
2806
|
+
return this.version;
|
|
2807
|
+
}
|
|
2808
|
+
resolveKey(key) {
|
|
2809
|
+
if (key) {
|
|
2810
|
+
return key;
|
|
2811
|
+
}
|
|
2812
|
+
const scopeId = this.querySelection.getActiveScope();
|
|
2813
|
+
if (!scopeId) {
|
|
2814
|
+
return null;
|
|
2815
|
+
}
|
|
2816
|
+
return this.querySelection.getActiveRegion(scopeId);
|
|
2817
|
+
}
|
|
2818
|
+
};
|
|
2819
|
+
function toItemsKey2(key) {
|
|
2820
|
+
return `${key.scopeId}:${key.regionId}`;
|
|
2821
|
+
}
|
|
2822
|
+
var createSelectionController = controllerFactory(
|
|
2823
|
+
(deps) => new SelectionController(deps),
|
|
2824
|
+
(overrides) => {
|
|
2825
|
+
const hasCustomUseCases = !!overrides.handleSelection || !!overrides.querySelection;
|
|
2826
|
+
if (hasCustomUseCases && !overrides.selectionStore) {
|
|
2827
|
+
throw new Error("createSelectionController requires selectionStore when overriding use cases");
|
|
2828
|
+
}
|
|
2829
|
+
const selectionStore = overrides.selectionStore ?? new InMemorySelectionStore();
|
|
2830
|
+
const handleSelection = overrides.handleSelection ?? new HandleSelectionUseCase(selectionStore);
|
|
2831
|
+
const querySelection = overrides.querySelection ?? new QuerySelectionUseCase(selectionStore);
|
|
2832
|
+
return {
|
|
2833
|
+
handleSelection,
|
|
2834
|
+
querySelection,
|
|
2835
|
+
selectionStore
|
|
2836
|
+
};
|
|
2837
|
+
}
|
|
2838
|
+
);
|
|
2839
|
+
function createSubscriptionAdapter(store, onChange) {
|
|
2840
|
+
const maybeStore = store;
|
|
2841
|
+
if (typeof maybeStore.subscribe === "function") {
|
|
2842
|
+
return (listener) => maybeStore.subscribe?.(() => {
|
|
2843
|
+
onChange();
|
|
2844
|
+
listener();
|
|
2845
|
+
}) ?? (() => {
|
|
2846
|
+
});
|
|
2847
|
+
}
|
|
2848
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
2849
|
+
const originalSet = store.set.bind(store);
|
|
2850
|
+
store.set = (next) => {
|
|
2851
|
+
originalSet(next);
|
|
2852
|
+
onChange();
|
|
2853
|
+
for (const listener of listeners) {
|
|
2854
|
+
listener();
|
|
2855
|
+
}
|
|
2856
|
+
};
|
|
2857
|
+
return (listener) => {
|
|
2858
|
+
listeners.add(listener);
|
|
2859
|
+
return () => {
|
|
2860
|
+
listeners.delete(listener);
|
|
2861
|
+
};
|
|
2862
|
+
};
|
|
2863
|
+
}
|
|
2864
|
+
|
|
2865
|
+
// src/feature/selection/infra/web/react/SelectionControllerProvider.tsx
|
|
2866
|
+
import { createContext as createContext3, useContext as useContext4 } from "react";
|
|
2867
|
+
import { jsx as jsx12 } from "react/jsx-runtime";
|
|
2868
|
+
var SelectionControllerCtx = createContext3(null);
|
|
2869
|
+
function SelectionControllerProvider({ children, controller }) {
|
|
2870
|
+
return /* @__PURE__ */ jsx12(SelectionControllerCtx.Provider, { value: controller, children });
|
|
2871
|
+
}
|
|
2872
|
+
function useSelectionController() {
|
|
2873
|
+
const controller = useContext4(SelectionControllerCtx);
|
|
2874
|
+
if (!controller) throw new Error("useSelectionController must be used within <SelectionControllerProvider>");
|
|
2875
|
+
return controller;
|
|
2876
|
+
}
|
|
2877
|
+
|
|
2878
|
+
// src/feature/keyboard/entity/scope-manager.ts
|
|
2879
|
+
var ScopeManager = class {
|
|
2880
|
+
scopes = /* @__PURE__ */ new Map();
|
|
2881
|
+
define(id, priority, exclusive = false) {
|
|
2882
|
+
if (!this.scopes.has(id)) {
|
|
2883
|
+
this.scopes.set(id, { id, enabled: false, refCount: 0, priority, exclusive });
|
|
2884
|
+
}
|
|
2885
|
+
}
|
|
2886
|
+
enable(id) {
|
|
2887
|
+
const s = this.scopes.get(id);
|
|
2888
|
+
if (!s) return;
|
|
2889
|
+
const nextRefCount = (s.refCount ?? 0) + 1;
|
|
2890
|
+
s.refCount = nextRefCount;
|
|
2891
|
+
s.enabled = nextRefCount > 0;
|
|
2892
|
+
this.scopes.set(id, s);
|
|
2893
|
+
}
|
|
2894
|
+
disable(id) {
|
|
2895
|
+
const s = this.scopes.get(id);
|
|
2896
|
+
if (!s) return;
|
|
2897
|
+
const nextRefCount = Math.max(0, (s.refCount ?? 0) - 1);
|
|
2898
|
+
s.refCount = nextRefCount;
|
|
2899
|
+
s.enabled = nextRefCount > 0;
|
|
2900
|
+
this.scopes.set(id, s);
|
|
2901
|
+
}
|
|
2902
|
+
isAnyExclusiveActiveAbove(priority) {
|
|
2903
|
+
for (const s of this.scopes.values()) {
|
|
2904
|
+
if (s.enabled && s.exclusive && s.priority > priority) return true;
|
|
2905
|
+
}
|
|
2906
|
+
return false;
|
|
2907
|
+
}
|
|
2908
|
+
isScopeActive(id) {
|
|
2909
|
+
const s = this.scopes.get(id);
|
|
2910
|
+
if (!s || !s.enabled) return false;
|
|
2911
|
+
return !this.isAnyExclusiveActiveAbove(s.priority);
|
|
2912
|
+
}
|
|
2913
|
+
getState(id) {
|
|
2914
|
+
return this.scopes.get(id) ?? null;
|
|
2915
|
+
}
|
|
2916
|
+
};
|
|
2917
|
+
|
|
2918
|
+
// src/feature/keyboard/application/use-case/enable-scope-use-case.ts
|
|
2919
|
+
var EnableScopeUseCase = class {
|
|
2920
|
+
constructor(scopes2) {
|
|
2921
|
+
this.scopes = scopes2;
|
|
2922
|
+
}
|
|
2923
|
+
enableScope(id) {
|
|
2924
|
+
this.scopes.enable(id);
|
|
2925
|
+
}
|
|
2926
|
+
};
|
|
2927
|
+
|
|
2928
|
+
// src/feature/keyboard/application/use-case/disable-scope-use-case.ts
|
|
2929
|
+
var DisableScopeUseCase = class {
|
|
2930
|
+
constructor(scopes2) {
|
|
2931
|
+
this.scopes = scopes2;
|
|
2932
|
+
}
|
|
2933
|
+
disableScope(id) {
|
|
2934
|
+
this.scopes.disable(id);
|
|
2935
|
+
}
|
|
2936
|
+
};
|
|
2937
|
+
|
|
2938
|
+
// src/feature/keyboard/application/use-case/list-shortcuts-use-case.ts
|
|
2939
|
+
var ListShortcutsUseCase = class {
|
|
2940
|
+
constructor(registry3) {
|
|
2941
|
+
this.registry = registry3;
|
|
2942
|
+
}
|
|
2943
|
+
listShortcutsByScope() {
|
|
2944
|
+
return this.registry.snapshotGroupedByScope();
|
|
2945
|
+
}
|
|
2946
|
+
};
|
|
2947
|
+
|
|
2948
|
+
// src/feature/keyboard/application/use-case/register-shortcut-use-case.ts
|
|
2949
|
+
import { v4 as uuid2 } from "uuid";
|
|
2950
|
+
var RegisterShortcutUseCase = class {
|
|
2951
|
+
constructor(engine2, scopes2, registry3) {
|
|
2952
|
+
this.engine = engine2;
|
|
2953
|
+
this.scopes = scopes2;
|
|
2954
|
+
this.registry = registry3;
|
|
2955
|
+
}
|
|
2956
|
+
store = /* @__PURE__ */ new Map();
|
|
2957
|
+
registerShortcut(regInput) {
|
|
2958
|
+
const id = uuid2();
|
|
2959
|
+
const reg = { preventDefault: true, ignoreTyping: true, ...regInput, id };
|
|
2960
|
+
const guard = (e) => {
|
|
2961
|
+
if (reg.ignoreTyping && isTyping(e)) return false;
|
|
2962
|
+
return this.scopes.isScopeActive(reg.scopeId);
|
|
2963
|
+
};
|
|
2964
|
+
const handle = this.engine.register(reg.bindings, { guard, preventDefault: reg.preventDefault });
|
|
2965
|
+
this.registry.addMany(
|
|
2966
|
+
reg.bindings.map((b) => ({
|
|
2967
|
+
registrationId: id,
|
|
2968
|
+
scopeId: reg.scopeId,
|
|
2969
|
+
combos: b.combos,
|
|
2970
|
+
description: b.description,
|
|
2971
|
+
group: b.group
|
|
2972
|
+
}))
|
|
2973
|
+
);
|
|
2974
|
+
this.store.set(id, { handle, reg });
|
|
2975
|
+
return id;
|
|
2976
|
+
}
|
|
2977
|
+
unregister(id) {
|
|
2978
|
+
const item = this.store.get(id);
|
|
2979
|
+
if (!item) return;
|
|
2980
|
+
item.handle.dispose();
|
|
2981
|
+
this.store.delete(id);
|
|
2982
|
+
this.registry.removeByRegistration(id);
|
|
2983
|
+
}
|
|
2984
|
+
};
|
|
2985
|
+
function isTyping(e) {
|
|
2986
|
+
const el = e.target;
|
|
2987
|
+
if (!el) return false;
|
|
2988
|
+
const inText = el.tagName === "INPUT" || el.tagName === "TEXTAREA" || el.isContentEditable;
|
|
2989
|
+
if (!inText) return false;
|
|
2990
|
+
const k = e.key;
|
|
2991
|
+
const allow = k === "Escape" || k === "Tab" || k.startsWith("Arrow") || k === "PageUp" || k === "PageDown" || k === "Home" || k === "End" || e.ctrlKey || e.metaKey || e.altKey;
|
|
2992
|
+
return !allow;
|
|
2993
|
+
}
|
|
2994
|
+
|
|
2995
|
+
// src/feature/keyboard/application/use-case/unregister-shortcut-use-case.ts
|
|
2996
|
+
var UnregisterShortcutUseCase = class {
|
|
2997
|
+
constructor(registry3) {
|
|
2998
|
+
this.registry = registry3;
|
|
2999
|
+
}
|
|
3000
|
+
unregisterShortcut(id) {
|
|
3001
|
+
this.registry.unregister(id);
|
|
3002
|
+
}
|
|
3003
|
+
};
|
|
3004
|
+
|
|
3005
|
+
// src/feature/keyboard/infra/web/react/KeyboardProvider.tsx
|
|
3006
|
+
import { createContext as createContext4, useContext as useContext5, useMemo as useMemo4 } from "react";
|
|
3007
|
+
|
|
3008
|
+
// src/feature/keyboard/infra/providers/in-memory-shortcuts-registry.ts
|
|
3009
|
+
function compareStringArrays(a, b) {
|
|
3010
|
+
const len = Math.min(a.length, b.length);
|
|
3011
|
+
for (let i = 0; i < len; i++) {
|
|
3012
|
+
const c = a[i].localeCompare(b[i]);
|
|
3013
|
+
if (c !== 0) return c;
|
|
3014
|
+
}
|
|
3015
|
+
return a.length - b.length;
|
|
3016
|
+
}
|
|
3017
|
+
var InMemoryShortcutRegistry = class {
|
|
3018
|
+
byReg = /* @__PURE__ */ new Map();
|
|
3019
|
+
addMany(items) {
|
|
3020
|
+
for (const it of items) {
|
|
3021
|
+
const arr = this.byReg.get(it.registrationId) ?? [];
|
|
3022
|
+
arr.push(it);
|
|
3023
|
+
this.byReg.set(it.registrationId, arr);
|
|
3024
|
+
}
|
|
3025
|
+
}
|
|
3026
|
+
removeByRegistration(registrationId) {
|
|
3027
|
+
this.byReg.delete(registrationId);
|
|
3028
|
+
}
|
|
3029
|
+
snapshotGroupedByScope() {
|
|
3030
|
+
const grouped = {};
|
|
3031
|
+
for (const items of this.byReg.values()) {
|
|
3032
|
+
for (const it of items) {
|
|
3033
|
+
const existing = grouped[it.scopeId];
|
|
3034
|
+
if (existing) {
|
|
3035
|
+
existing.push({ ...it });
|
|
3036
|
+
continue;
|
|
3037
|
+
}
|
|
3038
|
+
grouped[it.scopeId] = [{ ...it }];
|
|
3039
|
+
}
|
|
3040
|
+
}
|
|
3041
|
+
for (const scopeId of Object.keys(grouped)) {
|
|
3042
|
+
grouped[scopeId].sort(
|
|
3043
|
+
(a, b) => (a.group ?? "").localeCompare(b.group ?? "") || a.description.localeCompare(b.description) || compareStringArrays(a.combos, b.combos)
|
|
3044
|
+
);
|
|
3045
|
+
}
|
|
3046
|
+
return grouped;
|
|
3047
|
+
}
|
|
3048
|
+
};
|
|
3049
|
+
|
|
3050
|
+
// src/feature/keyboard/infra/providers/tinykeys-hotkey-engine.ts
|
|
3051
|
+
import { tinykeys } from "tinykeys";
|
|
3052
|
+
var TinykeysHotkeyEngine = class {
|
|
3053
|
+
register(bindings, opts = {}) {
|
|
3054
|
+
const target = opts.target ?? window;
|
|
3055
|
+
const codeMap = {};
|
|
3056
|
+
const charMap = [];
|
|
3057
|
+
const wrap = (fn) => (e) => {
|
|
3058
|
+
if (opts.guard && !opts.guard(e)) return;
|
|
3059
|
+
if (opts.preventDefault) e.preventDefault();
|
|
3060
|
+
fn(e);
|
|
3061
|
+
};
|
|
3062
|
+
for (const b of bindings) {
|
|
3063
|
+
for (const combo of b.combos) {
|
|
3064
|
+
const m = combo.match(/^char:(.+)$/i);
|
|
3065
|
+
if (m) {
|
|
3066
|
+
charMap.push({ char: m[1], handler: b.handler });
|
|
3067
|
+
} else {
|
|
3068
|
+
codeMap[combo] = wrap(b.handler);
|
|
3069
|
+
}
|
|
3070
|
+
}
|
|
3071
|
+
}
|
|
3072
|
+
const disposers = [];
|
|
3073
|
+
if (Object.keys(codeMap).length) {
|
|
3074
|
+
const tk = tinykeys;
|
|
3075
|
+
const unbind = tk(target, codeMap);
|
|
3076
|
+
disposers.push(unbind);
|
|
3077
|
+
}
|
|
3078
|
+
if (charMap.length) {
|
|
3079
|
+
const onKeyDown = (e) => {
|
|
3080
|
+
for (const { char, handler } of charMap) {
|
|
3081
|
+
if (e.key === char) {
|
|
3082
|
+
if (opts.guard && !opts.guard(e)) return;
|
|
3083
|
+
if (opts.preventDefault) e.preventDefault();
|
|
3084
|
+
handler(e);
|
|
3085
|
+
return;
|
|
3086
|
+
}
|
|
3087
|
+
}
|
|
3088
|
+
};
|
|
3089
|
+
const et = target;
|
|
3090
|
+
et.addEventListener("keydown", onKeyDown);
|
|
3091
|
+
disposers.push(() => et.removeEventListener("keydown", onKeyDown));
|
|
3092
|
+
}
|
|
3093
|
+
return {
|
|
3094
|
+
dispose: () => {
|
|
3095
|
+
for (const dispose of disposers) {
|
|
3096
|
+
dispose();
|
|
3097
|
+
}
|
|
3098
|
+
}
|
|
3099
|
+
};
|
|
3100
|
+
}
|
|
3101
|
+
};
|
|
3102
|
+
|
|
3103
|
+
// src/feature/keyboard/infra/controllers/keyboard-controller.ts
|
|
3104
|
+
var KeyboardController = class {
|
|
3105
|
+
constructor(scopes2, register2, unregister2, enableScope2, disableScope2, listShortcuts2, config2) {
|
|
3106
|
+
this.scopes = scopes2;
|
|
3107
|
+
this.register = register2;
|
|
3108
|
+
this.unregister = unregister2;
|
|
3109
|
+
this.enableScope = enableScope2;
|
|
3110
|
+
this.disableScope = disableScope2;
|
|
3111
|
+
this.listShortcuts = listShortcuts2;
|
|
3112
|
+
for (const s of config2?.predefinedScopes ?? []) {
|
|
3113
|
+
this.scopes.define(s.id, s.priority, !!s.exclusive);
|
|
3114
|
+
if (s.enabled) this.scopes.enable(s.id);
|
|
3115
|
+
}
|
|
3116
|
+
}
|
|
3117
|
+
handleDefineScope(id, priority, exclusive = false) {
|
|
3118
|
+
this.scopes.define(id, priority, exclusive);
|
|
3119
|
+
}
|
|
3120
|
+
handleEnableScope(id) {
|
|
3121
|
+
this.enableScope.enableScope(id);
|
|
3122
|
+
}
|
|
3123
|
+
handleDisableScope(id) {
|
|
3124
|
+
this.disableScope.disableScope(id);
|
|
3125
|
+
}
|
|
3126
|
+
handleRegisterShortcut(params) {
|
|
3127
|
+
return this.register.registerShortcut(params);
|
|
3128
|
+
}
|
|
3129
|
+
handleUnregisterShortcut(id) {
|
|
3130
|
+
this.unregister.unregisterShortcut(id);
|
|
3131
|
+
}
|
|
3132
|
+
handleListShortcutsByScope() {
|
|
3133
|
+
return this.listShortcuts.listShortcutsByScope();
|
|
3134
|
+
}
|
|
3135
|
+
};
|
|
3136
|
+
var scopes = new ScopeManager();
|
|
3137
|
+
var engine = new TinykeysHotkeyEngine();
|
|
3138
|
+
var registry2 = new InMemoryShortcutRegistry();
|
|
3139
|
+
var register = new RegisterShortcutUseCase(engine, scopes, registry2);
|
|
3140
|
+
var unregister = new UnregisterShortcutUseCase(register);
|
|
3141
|
+
var enableScope = new EnableScopeUseCase(scopes);
|
|
3142
|
+
var disableScope = new DisableScopeUseCase(scopes);
|
|
3143
|
+
var listShortcuts = new ListShortcutsUseCase(registry2);
|
|
3144
|
+
var config = {
|
|
3145
|
+
predefinedScopes: [
|
|
3146
|
+
{ id: "global", priority: 10, exclusive: false, enabled: true },
|
|
3147
|
+
{ id: "page", priority: 50, exclusive: false, enabled: false },
|
|
3148
|
+
{ id: "dialog", priority: 100, exclusive: true, enabled: false }
|
|
3149
|
+
]
|
|
3150
|
+
};
|
|
3151
|
+
var keyboardController = new KeyboardController(
|
|
3152
|
+
scopes,
|
|
3153
|
+
register,
|
|
3154
|
+
unregister,
|
|
3155
|
+
enableScope,
|
|
3156
|
+
disableScope,
|
|
3157
|
+
listShortcuts,
|
|
3158
|
+
config
|
|
3159
|
+
);
|
|
3160
|
+
|
|
3161
|
+
// src/feature/keyboard/infra/web/react/KeyboardProvider.tsx
|
|
3162
|
+
import { jsx as jsx13 } from "react/jsx-runtime";
|
|
3163
|
+
var KeyboardCtx = createContext4(null);
|
|
3164
|
+
var KeyboardProvider = ({ children }) => {
|
|
3165
|
+
const controller = useMemo4(() => keyboardController, []);
|
|
3166
|
+
return /* @__PURE__ */ jsx13(KeyboardCtx.Provider, { value: { controller }, children });
|
|
3167
|
+
};
|
|
3168
|
+
function useKeyboardController() {
|
|
3169
|
+
const ctx = useContext5(KeyboardCtx);
|
|
3170
|
+
if (!ctx) throw new Error("useKeyboardController must be used within <KeyboardProvider>");
|
|
3171
|
+
return ctx.controller;
|
|
3172
|
+
}
|
|
3173
|
+
|
|
3174
|
+
// src/feature/keyboard/infra/web/react/useShortcut.tsx
|
|
3175
|
+
import { useEffect as useEffect5, useMemo as useMemo5 } from "react";
|
|
3176
|
+
function useShortcut(scopeId, bindings, opts) {
|
|
3177
|
+
const controller = useKeyboardController();
|
|
3178
|
+
const stableBindings = useMemo5(() => bindings, [bindings]);
|
|
3179
|
+
useEffect5(() => {
|
|
3180
|
+
const id = controller.handleRegisterShortcut({
|
|
3181
|
+
scopeId,
|
|
3182
|
+
bindings: stableBindings,
|
|
3183
|
+
ignoreTyping: opts?.ignoreTyping ?? true,
|
|
3184
|
+
preventDefault: opts?.preventDefault ?? true
|
|
3185
|
+
});
|
|
3186
|
+
return () => controller.handleUnregisterShortcut(id);
|
|
3187
|
+
}, [controller, stableBindings, opts?.ignoreTyping, opts?.preventDefault, scopeId]);
|
|
3188
|
+
}
|
|
3189
|
+
|
|
3190
|
+
// src/feature/keyboard/infra/web/react/useShortcutScope.tsx
|
|
3191
|
+
import { useEffect as useEffect6 } from "react";
|
|
3192
|
+
function useShortcutScope(scopeId, enabled = true) {
|
|
3193
|
+
const controller = useKeyboardController();
|
|
3194
|
+
useEffect6(() => {
|
|
3195
|
+
if (!enabled) return void 0;
|
|
3196
|
+
controller.handleEnableScope(scopeId);
|
|
3197
|
+
return () => controller.handleDisableScope(scopeId);
|
|
3198
|
+
}, [controller, scopeId, enabled]);
|
|
3199
|
+
}
|
|
3200
|
+
|
|
3201
|
+
// src/feature/vim-navigation/entity/vim-region-registry.ts
|
|
3202
|
+
var VimRegionRegistry = class {
|
|
3203
|
+
byScope = /* @__PURE__ */ new Map();
|
|
3204
|
+
register(meta) {
|
|
3205
|
+
const scopeMap = this.byScope.get(meta.key.scopeId) ?? /* @__PURE__ */ new Map();
|
|
3206
|
+
scopeMap.set(meta.key.regionId, meta);
|
|
3207
|
+
this.byScope.set(meta.key.scopeId, scopeMap);
|
|
3208
|
+
}
|
|
3209
|
+
unregister(key) {
|
|
3210
|
+
const scopeMap = this.byScope.get(key.scopeId);
|
|
3211
|
+
if (!scopeMap) return;
|
|
3212
|
+
scopeMap.delete(key.regionId);
|
|
3213
|
+
if (scopeMap.size === 0) {
|
|
3214
|
+
this.byScope.delete(key.scopeId);
|
|
3215
|
+
}
|
|
3216
|
+
}
|
|
3217
|
+
get(key) {
|
|
3218
|
+
return this.byScope.get(key.scopeId)?.get(key.regionId) ?? null;
|
|
3219
|
+
}
|
|
3220
|
+
list(scopeId) {
|
|
3221
|
+
const scopeMap = this.byScope.get(scopeId);
|
|
3222
|
+
if (!scopeMap) return [];
|
|
3223
|
+
return Array.from(scopeMap.values()).sort((a, b) => a.orderIndex - b.orderIndex);
|
|
3224
|
+
}
|
|
3225
|
+
neighbor(scopeId, current, dir, count) {
|
|
3226
|
+
const regs = this.list(scopeId);
|
|
3227
|
+
if (regs.length === 0) return null;
|
|
3228
|
+
const currentIndex = regs.findIndex((r) => r.key.regionId === current.regionId);
|
|
3229
|
+
const start = currentIndex >= 0 ? currentIndex : 0;
|
|
3230
|
+
const step = dir === "right" ? 1 : -1;
|
|
3231
|
+
const moveBy = Math.max(1, count);
|
|
3232
|
+
const raw = start + step * moveBy;
|
|
3233
|
+
const nextIndex = clamp2(raw, 0, regs.length - 1);
|
|
3234
|
+
return regs[nextIndex]?.key ?? null;
|
|
3235
|
+
}
|
|
3236
|
+
};
|
|
3237
|
+
function clamp2(n, min, max) {
|
|
3238
|
+
return Math.max(min, Math.min(max, n));
|
|
3239
|
+
}
|
|
3240
|
+
|
|
3241
|
+
// src/feature/vim-navigation/application/use-case/vim-handle-key-use-case.ts
|
|
3242
|
+
var VimHandleKeyUseCase = class {
|
|
3243
|
+
constructor(selection, query, getItems, regions) {
|
|
3244
|
+
this.selection = selection;
|
|
3245
|
+
this.query = query;
|
|
3246
|
+
this.getItems = getItems;
|
|
3247
|
+
this.regions = regions;
|
|
3248
|
+
}
|
|
3249
|
+
stateByScope = /* @__PURE__ */ new Map();
|
|
3250
|
+
reset(scopeId) {
|
|
3251
|
+
if (!scopeId) {
|
|
3252
|
+
this.stateByScope.clear();
|
|
3253
|
+
return;
|
|
3254
|
+
}
|
|
3255
|
+
this.stateByScope.delete(scopeId);
|
|
3256
|
+
}
|
|
3257
|
+
handleChar(char, e) {
|
|
3258
|
+
if (e.ctrlKey || e.metaKey || e.altKey) return;
|
|
3259
|
+
const scopeId = this.query.getActiveScope();
|
|
3260
|
+
if (!scopeId) return;
|
|
3261
|
+
const activeKey = this.query.getActiveRegion(scopeId);
|
|
3262
|
+
if (!activeKey) return;
|
|
3263
|
+
const st = this.stateByScope.get(scopeId) ?? { count: "", pending: null };
|
|
3264
|
+
this.stateByScope.set(scopeId, st);
|
|
3265
|
+
if (isDigit(char)) {
|
|
3266
|
+
if (char === "0" && st.count.length === 0) return;
|
|
3267
|
+
st.count += char;
|
|
3268
|
+
return;
|
|
3269
|
+
}
|
|
3270
|
+
if (st.pending === "g") {
|
|
3271
|
+
st.pending = null;
|
|
3272
|
+
if (char === "g") {
|
|
3273
|
+
const count = consumeCount(st, 1);
|
|
3274
|
+
this.goToIndex(activeKey, count);
|
|
3275
|
+
this.afterCursorChange(activeKey);
|
|
3276
|
+
return;
|
|
3277
|
+
}
|
|
3278
|
+
}
|
|
3279
|
+
if (char === "g") {
|
|
3280
|
+
st.pending = "g";
|
|
3281
|
+
return;
|
|
3282
|
+
}
|
|
3283
|
+
if (char === "v") {
|
|
3284
|
+
const mode = this.query.getMode(scopeId);
|
|
3285
|
+
if (mode === "move") {
|
|
3286
|
+
this.selection.enterSelectMode(activeKey);
|
|
3287
|
+
this.afterRegionChange(activeKey);
|
|
3288
|
+
} else {
|
|
3289
|
+
this.selection.exitSelectMode(scopeId);
|
|
3290
|
+
this.afterRegionChange(activeKey);
|
|
3291
|
+
}
|
|
3292
|
+
st.count = "";
|
|
3293
|
+
st.pending = null;
|
|
3294
|
+
return;
|
|
3295
|
+
}
|
|
3296
|
+
if (char === " ") {
|
|
3297
|
+
this.selection.toggleItem(activeKey);
|
|
3298
|
+
st.count = "";
|
|
3299
|
+
st.pending = null;
|
|
3300
|
+
return;
|
|
3301
|
+
}
|
|
3302
|
+
if (char === "h" || char === "j" || char === "k" || char === "l") {
|
|
3303
|
+
const dir = mapHjkl(char);
|
|
3304
|
+
const count = consumeCount(st, 1);
|
|
3305
|
+
this.applyDirectional(scopeId, activeKey, dir, count);
|
|
3306
|
+
st.pending = null;
|
|
3307
|
+
return;
|
|
3308
|
+
}
|
|
3309
|
+
if (char === "G") {
|
|
3310
|
+
const count = consumeCount(st, 0);
|
|
3311
|
+
if (count > 0) {
|
|
3312
|
+
this.goToIndex(activeKey, count);
|
|
3313
|
+
} else {
|
|
3314
|
+
this.goToLast(activeKey);
|
|
3315
|
+
}
|
|
3316
|
+
this.afterCursorChange(activeKey);
|
|
3317
|
+
st.pending = null;
|
|
3318
|
+
return;
|
|
3319
|
+
}
|
|
3320
|
+
st.count = "";
|
|
3321
|
+
st.pending = null;
|
|
3322
|
+
}
|
|
3323
|
+
handleEscape(e) {
|
|
3324
|
+
if (e.ctrlKey || e.metaKey || e.altKey) return;
|
|
3325
|
+
const scopeId = this.query.getActiveScope();
|
|
3326
|
+
if (!scopeId) return;
|
|
3327
|
+
this.selection.exitSelectMode(scopeId);
|
|
3328
|
+
const activeKey = this.query.getActiveRegion(scopeId);
|
|
3329
|
+
if (activeKey) {
|
|
3330
|
+
this.afterRegionChange(activeKey);
|
|
3331
|
+
}
|
|
3332
|
+
const st = this.stateByScope.get(scopeId);
|
|
3333
|
+
if (st) {
|
|
3334
|
+
st.count = "";
|
|
3335
|
+
st.pending = null;
|
|
3336
|
+
}
|
|
3337
|
+
}
|
|
3338
|
+
applyDirectional(scopeId, activeKey, dir, count) {
|
|
3339
|
+
const meta = this.regions.get(activeKey);
|
|
3340
|
+
if (meta?.intra.has(dir)) {
|
|
3341
|
+
const delta = directionToDelta(dir, count);
|
|
3342
|
+
this.selection.moveCursor(activeKey, delta);
|
|
3343
|
+
this.afterCursorChange(activeKey);
|
|
3344
|
+
return;
|
|
3345
|
+
}
|
|
3346
|
+
if (dir === "left" || dir === "right") {
|
|
3347
|
+
const interDir = dir;
|
|
3348
|
+
if (meta && !meta.inter.has(interDir)) return;
|
|
3349
|
+
const nextKey = this.regions.neighbor(scopeId, activeKey, interDir, count);
|
|
3350
|
+
if (!nextKey) return;
|
|
3351
|
+
const prevIndex = this.getCursorIndex(activeKey);
|
|
3352
|
+
this.selection.setActiveRegion(nextKey);
|
|
3353
|
+
const enteredMeta = this.regions.get(nextKey);
|
|
3354
|
+
const fallback = enteredMeta?.enterCursorFallback;
|
|
3355
|
+
const nextCursor = this.query.getCursor(nextKey);
|
|
3356
|
+
if (!nextCursor && fallback) {
|
|
3357
|
+
const resolved = this.resolveInterRegionFallback(fallback, prevIndex);
|
|
3358
|
+
if (resolved) {
|
|
3359
|
+
this.applyFallbackCursor(nextKey, resolved);
|
|
3360
|
+
}
|
|
3361
|
+
}
|
|
3362
|
+
this.afterRegionChange(nextKey);
|
|
3363
|
+
}
|
|
3364
|
+
}
|
|
3365
|
+
goToLast(key) {
|
|
3366
|
+
const items = this.getItems(key);
|
|
3367
|
+
if (items.length === 0) {
|
|
3368
|
+
this.selection.setCursor(key, null);
|
|
3369
|
+
return;
|
|
3370
|
+
}
|
|
3371
|
+
const last = items[items.length - 1] ?? null;
|
|
3372
|
+
this.selection.setCursor(key, last);
|
|
3373
|
+
}
|
|
3374
|
+
goToIndex(key, index1) {
|
|
3375
|
+
const items = this.getItems(key);
|
|
3376
|
+
if (items.length === 0) {
|
|
3377
|
+
this.selection.setCursor(key, null);
|
|
3378
|
+
return;
|
|
3379
|
+
}
|
|
3380
|
+
const idx0 = clamp3(index1 - 1, 0, items.length - 1);
|
|
3381
|
+
this.selection.setCursor(key, items[idx0] ?? null);
|
|
3382
|
+
}
|
|
3383
|
+
afterRegionChange(key) {
|
|
3384
|
+
const meta = this.regions.get(key);
|
|
3385
|
+
meta?.focusContainer?.();
|
|
3386
|
+
meta?.scrollToCursor?.();
|
|
3387
|
+
}
|
|
3388
|
+
afterCursorChange(key) {
|
|
3389
|
+
const meta = this.regions.get(key);
|
|
3390
|
+
meta?.scrollToCursor?.();
|
|
3391
|
+
if (meta?.focusOnCursorChange !== false) {
|
|
3392
|
+
meta?.focusContainer?.();
|
|
3393
|
+
}
|
|
3394
|
+
}
|
|
3395
|
+
applyFallbackCursor(key, fallback) {
|
|
3396
|
+
const items = this.getItems(key);
|
|
3397
|
+
const nextCursor = getFallbackCursor2(items, fallback);
|
|
3398
|
+
if (nextCursor === null) {
|
|
3399
|
+
return;
|
|
3400
|
+
}
|
|
3401
|
+
this.selection.setCursor(key, nextCursor);
|
|
3402
|
+
}
|
|
3403
|
+
getCursorIndex(key) {
|
|
3404
|
+
const cursor = this.query.getCursor(key);
|
|
3405
|
+
if (!cursor) {
|
|
3406
|
+
return null;
|
|
3407
|
+
}
|
|
3408
|
+
const items = this.getItems(key);
|
|
3409
|
+
const index = items.indexOf(cursor);
|
|
3410
|
+
return index >= 0 ? index : null;
|
|
3411
|
+
}
|
|
3412
|
+
resolveInterRegionFallback(fallback, prevIndex) {
|
|
3413
|
+
if (fallback.kind === "sameIndex") {
|
|
3414
|
+
if (prevIndex === null) {
|
|
3415
|
+
return null;
|
|
3416
|
+
}
|
|
3417
|
+
return { kind: "nth", idx: prevIndex };
|
|
3418
|
+
}
|
|
3419
|
+
if (fallback.kind !== "nth") {
|
|
3420
|
+
return fallback;
|
|
3421
|
+
}
|
|
3422
|
+
if (fallback.idx >= 0) {
|
|
3423
|
+
return fallback;
|
|
3424
|
+
}
|
|
3425
|
+
if (prevIndex === null) {
|
|
3426
|
+
return null;
|
|
3427
|
+
}
|
|
3428
|
+
return { kind: "nth", idx: prevIndex };
|
|
3429
|
+
}
|
|
3430
|
+
};
|
|
3431
|
+
function isDigit(ch) {
|
|
3432
|
+
return ch.length === 1 && ch >= "0" && ch <= "9";
|
|
3433
|
+
}
|
|
3434
|
+
function consumeCount(st, def) {
|
|
3435
|
+
if (!st.count) return def;
|
|
3436
|
+
const n = Number(st.count);
|
|
3437
|
+
st.count = "";
|
|
3438
|
+
if (!Number.isFinite(n) || n < 0) return def;
|
|
3439
|
+
return Math.floor(n);
|
|
3440
|
+
}
|
|
3441
|
+
function mapHjkl(ch) {
|
|
3442
|
+
switch (ch) {
|
|
3443
|
+
case "h":
|
|
3444
|
+
return "left";
|
|
3445
|
+
case "j":
|
|
3446
|
+
return "down";
|
|
3447
|
+
case "k":
|
|
3448
|
+
return "up";
|
|
3449
|
+
case "l":
|
|
3450
|
+
return "right";
|
|
3451
|
+
}
|
|
3452
|
+
}
|
|
3453
|
+
function getFallbackCursor2(items, fallback) {
|
|
3454
|
+
if (fallback.kind === "none") {
|
|
3455
|
+
return null;
|
|
3456
|
+
}
|
|
3457
|
+
if (fallback.kind === "first") {
|
|
3458
|
+
return items[0] ?? null;
|
|
3459
|
+
}
|
|
3460
|
+
if (fallback.kind === "last") {
|
|
3461
|
+
return items[items.length - 1] ?? null;
|
|
3462
|
+
}
|
|
3463
|
+
if (fallback.kind === "id") {
|
|
3464
|
+
return items.includes(fallback.id) ? fallback.id : null;
|
|
3465
|
+
}
|
|
3466
|
+
if (fallback.kind === "nth") {
|
|
3467
|
+
const idx = clamp3(fallback.idx, 0, items.length - 1);
|
|
3468
|
+
return items[idx] ?? null;
|
|
3469
|
+
}
|
|
3470
|
+
if (fallback.kind === "nearestTo") {
|
|
3471
|
+
return getNearestCursor2(items, fallback.id);
|
|
3472
|
+
}
|
|
3473
|
+
throw new Error(`Invalid cursor fallback type of: ${JSON.stringify(fallback)} did not match any handler.`);
|
|
3474
|
+
}
|
|
3475
|
+
function getNearestCursor2(items, id) {
|
|
3476
|
+
if (items.includes(id)) {
|
|
3477
|
+
return id;
|
|
3478
|
+
}
|
|
3479
|
+
return null;
|
|
3480
|
+
}
|
|
3481
|
+
function directionToDelta(dir, count) {
|
|
3482
|
+
const n = Math.max(1, count);
|
|
3483
|
+
switch (dir) {
|
|
3484
|
+
case "down":
|
|
3485
|
+
return n;
|
|
3486
|
+
case "up":
|
|
3487
|
+
return -n;
|
|
3488
|
+
case "right":
|
|
3489
|
+
return n;
|
|
3490
|
+
case "left":
|
|
3491
|
+
return -n;
|
|
3492
|
+
}
|
|
3493
|
+
}
|
|
3494
|
+
function clamp3(n, min, max) {
|
|
3495
|
+
return Math.max(min, Math.min(max, n));
|
|
3496
|
+
}
|
|
3497
|
+
|
|
3498
|
+
// src/feature/vim-navigation/infra/controller/vim-controller.ts
|
|
3499
|
+
var VimController = class {
|
|
3500
|
+
regions;
|
|
3501
|
+
handleKey;
|
|
3502
|
+
selection;
|
|
3503
|
+
constructor(selection, regions = new VimRegionRegistry(), handleKey = new VimHandleKeyUseCase(
|
|
3504
|
+
selection.getHandle(),
|
|
3505
|
+
selection.getQuery(),
|
|
3506
|
+
(key) => selection.getItems(key),
|
|
3507
|
+
regions
|
|
3508
|
+
)) {
|
|
3509
|
+
this.regions = regions;
|
|
3510
|
+
this.handleKey = handleKey;
|
|
3511
|
+
this.selection = selection;
|
|
3512
|
+
}
|
|
3513
|
+
handleRegisterRegionMeta(meta) {
|
|
3514
|
+
this.regions.register(meta);
|
|
3515
|
+
}
|
|
3516
|
+
handleUnregisterRegionMeta(key) {
|
|
3517
|
+
this.regions.unregister(key);
|
|
3518
|
+
}
|
|
3519
|
+
handleCharKey(char, e) {
|
|
3520
|
+
this.handleKey.handleChar(char, e);
|
|
3521
|
+
}
|
|
3522
|
+
handleEscape(e) {
|
|
3523
|
+
this.handleKey.handleEscape(e);
|
|
3524
|
+
}
|
|
3525
|
+
resetActiveScope() {
|
|
3526
|
+
const scopeId = this.selection.getActiveScope();
|
|
3527
|
+
if (!scopeId) return;
|
|
3528
|
+
this.handleKey.reset(scopeId);
|
|
3529
|
+
}
|
|
3530
|
+
getSelection() {
|
|
3531
|
+
return this.selection;
|
|
3532
|
+
}
|
|
3533
|
+
};
|
|
3534
|
+
var createVimController = controllerFactory(
|
|
3535
|
+
(deps) => new VimController(deps.selection, deps.regions, deps.handleKey),
|
|
3536
|
+
(overrides) => {
|
|
3537
|
+
const selection = overrides.selection;
|
|
3538
|
+
if (!selection) {
|
|
3539
|
+
throw new Error("createVimController requires selection");
|
|
3540
|
+
}
|
|
3541
|
+
const regions = overrides.regions ?? new VimRegionRegistry();
|
|
3542
|
+
const handleKey = overrides.handleKey ?? new VimHandleKeyUseCase(
|
|
3543
|
+
selection.getHandle(),
|
|
3544
|
+
selection.getQuery(),
|
|
3545
|
+
(key) => selection.getItems(key),
|
|
3546
|
+
regions
|
|
3547
|
+
);
|
|
3548
|
+
return {
|
|
3549
|
+
selection,
|
|
3550
|
+
regions,
|
|
3551
|
+
handleKey
|
|
3552
|
+
};
|
|
3553
|
+
}
|
|
3554
|
+
);
|
|
3555
|
+
|
|
3556
|
+
// src/feature/vim-navigation/infra/web/react/VimControllerProvider.tsx
|
|
3557
|
+
import { createContext as createContext5, useContext as useContext6 } from "react";
|
|
3558
|
+
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
3559
|
+
var VimControllerCtx = createContext5(null);
|
|
3560
|
+
function VimControllerProvider({ children, controller }) {
|
|
3561
|
+
return /* @__PURE__ */ jsx14(VimControllerCtx.Provider, { value: controller, children });
|
|
3562
|
+
}
|
|
3563
|
+
function useVimController() {
|
|
3564
|
+
const controller = useContext6(VimControllerCtx);
|
|
3565
|
+
if (!controller) throw new Error("useVimController must be used within <VimControllerProvider>");
|
|
3566
|
+
return controller;
|
|
3567
|
+
}
|
|
3568
|
+
|
|
3569
|
+
// src/feature/vim-navigation/infra/web/react/hook/use-vim-bindings.tsx
|
|
3570
|
+
import { useCallback as useCallback5, useEffect as useEffect7, useMemo as useMemo6, useRef as useRef3, useState as useState5 } from "react";
|
|
3571
|
+
var scopeBindings = /* @__PURE__ */ new Map();
|
|
3572
|
+
function notify(entry) {
|
|
3573
|
+
for (const notifySub of entry.subscribers.values()) {
|
|
3574
|
+
notifySub(entry.ownerId);
|
|
3575
|
+
}
|
|
3576
|
+
}
|
|
3577
|
+
function useVimBindings(keyboardScopeId, options = {}) {
|
|
3578
|
+
const vim = useVimController();
|
|
3579
|
+
const enabled = options.enabled ?? true;
|
|
3580
|
+
const ownerIdRef = useRef3(Symbol("vim-binding-owner"));
|
|
3581
|
+
const [isOwner, setIsOwner] = useState5(false);
|
|
3582
|
+
const handleOwnerChange = useCallback5((ownerId) => {
|
|
3583
|
+
setIsOwner(ownerId === ownerIdRef.current);
|
|
3584
|
+
}, []);
|
|
3585
|
+
useEffect7(() => {
|
|
3586
|
+
if (!enabled) {
|
|
3587
|
+
setIsOwner(false);
|
|
3588
|
+
return;
|
|
3589
|
+
}
|
|
3590
|
+
const entry = scopeBindings.get(keyboardScopeId) ?? {
|
|
3591
|
+
ownerId: null,
|
|
3592
|
+
subscribers: /* @__PURE__ */ new Map()
|
|
3593
|
+
};
|
|
3594
|
+
scopeBindings.set(keyboardScopeId, entry);
|
|
3595
|
+
entry.subscribers.set(ownerIdRef.current, handleOwnerChange);
|
|
3596
|
+
if (!entry.ownerId) {
|
|
3597
|
+
entry.ownerId = ownerIdRef.current;
|
|
3598
|
+
}
|
|
3599
|
+
notify(entry);
|
|
3600
|
+
return () => {
|
|
3601
|
+
entry.subscribers.delete(ownerIdRef.current);
|
|
3602
|
+
if (entry.ownerId === ownerIdRef.current) {
|
|
3603
|
+
const nextOwner = entry.subscribers.keys().next().value ?? null;
|
|
3604
|
+
entry.ownerId = nextOwner;
|
|
3605
|
+
if (!nextOwner && entry.subscribers.size === 0) {
|
|
3606
|
+
scopeBindings.delete(keyboardScopeId);
|
|
3607
|
+
return;
|
|
3608
|
+
}
|
|
3609
|
+
notify(entry);
|
|
3610
|
+
return;
|
|
3611
|
+
}
|
|
3612
|
+
if (entry.subscribers.size === 0) {
|
|
3613
|
+
scopeBindings.delete(keyboardScopeId);
|
|
3614
|
+
}
|
|
3615
|
+
};
|
|
3616
|
+
}, [enabled, handleOwnerChange, keyboardScopeId]);
|
|
3617
|
+
const bindings = useMemo6(() => {
|
|
3618
|
+
if (!enabled || !isOwner) {
|
|
3619
|
+
return [];
|
|
3620
|
+
}
|
|
3621
|
+
const charCombo = (c) => `char:${c}`;
|
|
3622
|
+
const onChar = (c) => (e) => vim.handleCharKey(c, e);
|
|
3623
|
+
const digitBindings = [];
|
|
3624
|
+
for (let i = 0; i <= 9; i += 1) {
|
|
3625
|
+
const d = String(i);
|
|
3626
|
+
digitBindings.push({
|
|
3627
|
+
combos: [charCombo(d)],
|
|
3628
|
+
handler: onChar(d),
|
|
3629
|
+
description: `vim: count ${d}`,
|
|
3630
|
+
group: "vim"
|
|
3631
|
+
});
|
|
3632
|
+
}
|
|
3633
|
+
return [
|
|
3634
|
+
...digitBindings,
|
|
3635
|
+
{ combos: [charCombo("h")], handler: onChar("h"), description: "vim: left", group: "vim" },
|
|
3636
|
+
{ combos: [charCombo("j")], handler: onChar("j"), description: "vim: down", group: "vim" },
|
|
3637
|
+
{ combos: [charCombo("k")], handler: onChar("k"), description: "vim: up", group: "vim" },
|
|
3638
|
+
{ combos: [charCombo("l")], handler: onChar("l"), description: "vim: right", group: "vim" },
|
|
3639
|
+
{ combos: [charCombo("g")], handler: onChar("g"), description: "vim: g prefix", group: "vim" },
|
|
3640
|
+
{ combos: [charCombo("G")], handler: onChar("G"), description: "vim: G", group: "vim" },
|
|
3641
|
+
{
|
|
3642
|
+
combos: [charCombo("v"), charCombo("V")],
|
|
3643
|
+
handler: onChar("v"),
|
|
3644
|
+
description: "vim: toggle select",
|
|
3645
|
+
group: "vim"
|
|
3646
|
+
},
|
|
3647
|
+
{ combos: [charCombo(" ")], handler: onChar(" "), description: "vim: toggle item", group: "vim" },
|
|
3648
|
+
{ combos: ["Escape"], handler: (e) => vim.handleEscape(e), description: "vim: escape", group: "vim" }
|
|
3649
|
+
];
|
|
3650
|
+
}, [enabled, isOwner, vim]);
|
|
3651
|
+
useShortcut(keyboardScopeId, bindings, { ignoreTyping: true, preventDefault: true });
|
|
3652
|
+
}
|
|
3653
|
+
|
|
3654
|
+
// src/feature/vim-navigation/infra/web/react/hook/use-vim-region.tsx
|
|
3655
|
+
import { useEffect as useEffect9, useMemo as useMemo8, useRef as useRef4, useSyncExternalStore } from "react";
|
|
3656
|
+
|
|
3657
|
+
// src/feature/vim-navigation/infra/web/react/hook/use-vim-region-meta.tsx
|
|
3658
|
+
import { useEffect as useEffect8, useMemo as useMemo7 } from "react";
|
|
3659
|
+
function useVimRegionMeta(containerRef, args) {
|
|
3660
|
+
const vim = useVimController();
|
|
3661
|
+
const selection = vim.getSelection();
|
|
3662
|
+
const intraSet = useMemo7(() => new Set(args.intra ?? ["up", "down"]), [args.intra]);
|
|
3663
|
+
const interSet = useMemo7(() => new Set(args.inter ?? ["left", "right"]), [args.inter]);
|
|
3664
|
+
const itemAttr = args.itemDataAttr ?? "data-vim-item-id";
|
|
3665
|
+
const focusContainer = useMemo7(() => {
|
|
3666
|
+
return () => {
|
|
3667
|
+
const el = containerRef.current;
|
|
3668
|
+
if (!el) return;
|
|
3669
|
+
const activeId = selection.getActiveItem(args.key);
|
|
3670
|
+
const selector = activeId ? `[${itemAttr}="${cssEscape(activeId)}"]` : `[${itemAttr}]`;
|
|
3671
|
+
const itemEl = el.querySelector(selector);
|
|
3672
|
+
itemEl?.focus();
|
|
3673
|
+
};
|
|
3674
|
+
}, [args.key, containerRef, itemAttr, selection]);
|
|
3675
|
+
const scrollToCursor = useMemo7(() => {
|
|
3676
|
+
return () => {
|
|
3677
|
+
const el = containerRef.current;
|
|
3678
|
+
if (!el) return;
|
|
3679
|
+
const cursor = selection.getActiveItem(args.key);
|
|
3680
|
+
if (!cursor) return;
|
|
3681
|
+
const selector = `[${itemAttr}="${cssEscape(cursor)}"]`;
|
|
3682
|
+
const itemEl = el.querySelector(selector);
|
|
3683
|
+
if (!itemEl) return;
|
|
3684
|
+
itemEl.scrollIntoView({ block: "nearest" });
|
|
3685
|
+
};
|
|
3686
|
+
}, [args.key, containerRef, selection, itemAttr]);
|
|
3687
|
+
useEffect8(() => {
|
|
3688
|
+
const meta = {
|
|
3689
|
+
key: args.key,
|
|
3690
|
+
orderIndex: args.orderIndex,
|
|
3691
|
+
intra: intraSet,
|
|
3692
|
+
inter: interSet,
|
|
3693
|
+
focusContainer,
|
|
3694
|
+
scrollToCursor,
|
|
3695
|
+
enterCursorFallback: args.enterCursorFallback,
|
|
3696
|
+
focusOnCursorChange: args.focusOnCursorChange ?? true
|
|
3697
|
+
};
|
|
3698
|
+
vim.handleRegisterRegionMeta(meta);
|
|
3699
|
+
return () => {
|
|
3700
|
+
vim.handleUnregisterRegionMeta(args.key);
|
|
3701
|
+
};
|
|
3702
|
+
}, []);
|
|
3703
|
+
function getItemProps(itemId) {
|
|
3704
|
+
return { [itemAttr]: itemId };
|
|
3705
|
+
}
|
|
3706
|
+
return { getItemProps };
|
|
3707
|
+
}
|
|
3708
|
+
function cssEscape(value) {
|
|
3709
|
+
const cssObj = typeof CSS === "undefined" ? void 0 : CSS;
|
|
3710
|
+
if (cssObj && typeof cssObj.escape === "function") {
|
|
3711
|
+
return cssObj.escape(value);
|
|
3712
|
+
}
|
|
3713
|
+
return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
3714
|
+
}
|
|
3715
|
+
|
|
3716
|
+
// src/feature/vim-navigation/infra/web/react/hook/use-vim-region.tsx
|
|
3717
|
+
function useVimRegion(containerRef, args) {
|
|
3718
|
+
const vim = useVimController();
|
|
3719
|
+
const selection = vim.getSelection();
|
|
3720
|
+
const keyboard = useKeyboardController();
|
|
3721
|
+
const refreshRef = useRef4(null);
|
|
3722
|
+
const getRegionItemsRef = useRef4(args.getRegionItems);
|
|
3723
|
+
const bindKeys = args.bindKeys ?? true;
|
|
3724
|
+
const keyboardScopeId = args.keyboardScopeId ?? args.key.scopeId;
|
|
3725
|
+
useEffect9(() => {
|
|
3726
|
+
keyboard.handleDefineScope(keyboardScopeId, 50, false);
|
|
3727
|
+
if (!bindKeys) {
|
|
3728
|
+
return;
|
|
3729
|
+
}
|
|
3730
|
+
keyboard.handleEnableScope(keyboardScopeId);
|
|
3731
|
+
return () => keyboard.handleDisableScope(keyboardScopeId);
|
|
3732
|
+
}, [bindKeys, keyboard, keyboardScopeId]);
|
|
3733
|
+
useVimBindings(keyboardScopeId, { enabled: bindKeys });
|
|
3734
|
+
useSyncExternalStore(
|
|
3735
|
+
(listener) => selection.subscribe(listener),
|
|
3736
|
+
() => selection.getVersion(),
|
|
3737
|
+
() => selection.getVersion()
|
|
3738
|
+
);
|
|
3739
|
+
const metaArgs = useMemo8(
|
|
3740
|
+
() => ({
|
|
3741
|
+
key: args.key,
|
|
3742
|
+
orderIndex: args.orderIndex,
|
|
3743
|
+
intra: args.intra,
|
|
3744
|
+
inter: args.inter,
|
|
3745
|
+
enterCursorFallback: args.enterCursorFallback,
|
|
3746
|
+
itemDataAttr: args.itemDataAttr,
|
|
3747
|
+
focusOnCursorChange: args.focusOnCursorChange
|
|
3748
|
+
}),
|
|
3749
|
+
[
|
|
3750
|
+
args.enterCursorFallback,
|
|
3751
|
+
args.focusOnCursorChange,
|
|
3752
|
+
args.inter,
|
|
3753
|
+
args.intra,
|
|
3754
|
+
args.itemDataAttr,
|
|
3755
|
+
args.key,
|
|
3756
|
+
args.orderIndex
|
|
3757
|
+
]
|
|
3758
|
+
);
|
|
3759
|
+
const { getItemProps } = useVimRegionMeta(containerRef, metaArgs);
|
|
3760
|
+
useEffect9(() => {
|
|
3761
|
+
getRegionItemsRef.current = args.getRegionItems;
|
|
3762
|
+
}, [args.getRegionItems]);
|
|
3763
|
+
useEffect9(() => {
|
|
3764
|
+
const refresh2 = selection.registerRegion({
|
|
3765
|
+
key: args.key,
|
|
3766
|
+
getRegionItems: () => getRegionItemsRef.current(),
|
|
3767
|
+
makeActive: args.makeActive,
|
|
3768
|
+
initialCursor: args.initialCursor
|
|
3769
|
+
});
|
|
3770
|
+
refreshRef.current = refresh2;
|
|
3771
|
+
if (!selection.getActiveScope()) {
|
|
3772
|
+
selection.setActiveScope(args.key.scopeId);
|
|
3773
|
+
}
|
|
3774
|
+
refresh2();
|
|
3775
|
+
return () => {
|
|
3776
|
+
selection.unregisterRegion(args.key);
|
|
3777
|
+
refreshRef.current = null;
|
|
3778
|
+
};
|
|
3779
|
+
}, [args.initialCursor, args.key, args.makeActive, selection]);
|
|
3780
|
+
useEffect9(() => {
|
|
3781
|
+
if (!args.refreshDeps) {
|
|
3782
|
+
return;
|
|
3783
|
+
}
|
|
3784
|
+
refreshRef.current?.();
|
|
3785
|
+
}, args.refreshDeps ?? []);
|
|
3786
|
+
const activeId = selection.getActiveItem(args.key);
|
|
3787
|
+
const selectedIds = selection.getSelectedIds(args.key);
|
|
3788
|
+
const rangeIds = selection.getRangeIds(args.key);
|
|
3789
|
+
const toggledIds = selection.getToggledIds(args.key);
|
|
3790
|
+
const mode = selection.getMode(args.key.scopeId);
|
|
3791
|
+
const isSelected = (itemId) => selection.isSelected(args.key, itemId);
|
|
3792
|
+
return {
|
|
3793
|
+
getItemProps,
|
|
3794
|
+
refresh: (fallback) => refreshRef.current?.(fallback),
|
|
3795
|
+
activeId,
|
|
3796
|
+
selectedIds,
|
|
3797
|
+
rangeIds,
|
|
3798
|
+
toggledIds,
|
|
3799
|
+
mode,
|
|
3800
|
+
isSelected
|
|
3801
|
+
};
|
|
3802
|
+
}
|
|
3803
|
+
|
|
2157
3804
|
// src/ui/components/Field.tsx
|
|
2158
3805
|
import * as React6 from "react";
|
|
2159
3806
|
|
|
2160
3807
|
// src/ui/components/Label.tsx
|
|
2161
3808
|
import * as React5 from "react";
|
|
2162
|
-
import { jsx as
|
|
3809
|
+
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
2163
3810
|
var Label = React5.forwardRef(
|
|
2164
|
-
({ className, htmlFor, children, ...props }, ref) => /* @__PURE__ */
|
|
3811
|
+
({ className, htmlFor, children, ...props }, ref) => /* @__PURE__ */ jsx15(
|
|
2165
3812
|
"label",
|
|
2166
3813
|
{
|
|
2167
3814
|
ref,
|
|
@@ -2175,7 +3822,7 @@ var Label = React5.forwardRef(
|
|
|
2175
3822
|
Label.displayName = "Label";
|
|
2176
3823
|
|
|
2177
3824
|
// src/ui/components/Field.tsx
|
|
2178
|
-
import { jsx as
|
|
3825
|
+
import { jsx as jsx16, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
2179
3826
|
function Field({ label, hint, error, required, disabled, id, children, className, ...props }) {
|
|
2180
3827
|
const reactId = React6.useId();
|
|
2181
3828
|
const controlId = id ?? `field-${reactId}`;
|
|
@@ -2195,7 +3842,7 @@ function Field({ label, hint, error, required, disabled, id, children, className
|
|
|
2195
3842
|
"aria-describedby": ariaDescribedBy
|
|
2196
3843
|
});
|
|
2197
3844
|
return /* @__PURE__ */ jsxs7("div", { className: cn("grid gap-1.5", className), ...props, children: [
|
|
2198
|
-
label ? /* @__PURE__ */
|
|
3845
|
+
label ? /* @__PURE__ */ jsx16("div", { className: "flex items-center justify-between gap-3", children: /* @__PURE__ */ jsxs7(Label, { htmlFor: controlId, children: [
|
|
2199
3846
|
label,
|
|
2200
3847
|
resolvedRequired ? /* @__PURE__ */ jsxs7("span", { "aria-hidden": "true", className: "text-(--muted)", children: [
|
|
2201
3848
|
" ",
|
|
@@ -2203,15 +3850,15 @@ function Field({ label, hint, error, required, disabled, id, children, className
|
|
|
2203
3850
|
] }) : null
|
|
2204
3851
|
] }) }) : null,
|
|
2205
3852
|
control,
|
|
2206
|
-
error ? /* @__PURE__ */
|
|
2207
|
-
hint ? /* @__PURE__ */
|
|
3853
|
+
error ? /* @__PURE__ */ jsx16("p", { id: errorId, className: "text-xs leading-5 text-(--danger-contrast)", role: "alert", children: error }) : null,
|
|
3854
|
+
hint ? /* @__PURE__ */ jsx16("p", { id: hintId, className: "text-xs leading-5 text-(--muted)", children: hint }) : null
|
|
2208
3855
|
] });
|
|
2209
3856
|
}
|
|
2210
3857
|
|
|
2211
3858
|
// src/ui/components/Input.tsx
|
|
2212
3859
|
import { cva as cva3 } from "class-variance-authority";
|
|
2213
3860
|
import * as React7 from "react";
|
|
2214
|
-
import { jsx as
|
|
3861
|
+
import { jsx as jsx17, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2215
3862
|
var controlShellBase = cn(
|
|
2216
3863
|
"relative inline-flex items-center gap-2",
|
|
2217
3864
|
"rounded-[var(--radius-input)]",
|
|
@@ -2291,7 +3938,7 @@ var Input = React7.forwardRef(
|
|
|
2291
3938
|
"data-invalid": invalid ? "" : void 0,
|
|
2292
3939
|
"data-disabled": isDisabled ? "" : void 0,
|
|
2293
3940
|
children: [
|
|
2294
|
-
showLeftSlot ? /* @__PURE__ */
|
|
3941
|
+
showLeftSlot ? /* @__PURE__ */ jsx17(
|
|
2295
3942
|
"span",
|
|
2296
3943
|
{
|
|
2297
3944
|
className: cn(slotBase, reserveLeftSlot && slotReserve),
|
|
@@ -2299,7 +3946,7 @@ var Input = React7.forwardRef(
|
|
|
2299
3946
|
children: leftSlot
|
|
2300
3947
|
}
|
|
2301
3948
|
) : null,
|
|
2302
|
-
/* @__PURE__ */
|
|
3949
|
+
/* @__PURE__ */ jsx17(
|
|
2303
3950
|
"input",
|
|
2304
3951
|
{
|
|
2305
3952
|
ref,
|
|
@@ -2309,7 +3956,7 @@ var Input = React7.forwardRef(
|
|
|
2309
3956
|
...props
|
|
2310
3957
|
}
|
|
2311
3958
|
),
|
|
2312
|
-
showRightSlot ? /* @__PURE__ */
|
|
3959
|
+
showRightSlot ? /* @__PURE__ */ jsx17(
|
|
2313
3960
|
"span",
|
|
2314
3961
|
{
|
|
2315
3962
|
className: cn(slotBase, reserveRightSlot && slotReserve),
|
|
@@ -2328,7 +3975,7 @@ Input.displayName = "Input";
|
|
|
2328
3975
|
import { cva as cva4 } from "class-variance-authority";
|
|
2329
3976
|
import { Slot as Slot2 } from "radix-ui";
|
|
2330
3977
|
import * as React8 from "react";
|
|
2331
|
-
import { jsx as
|
|
3978
|
+
import { jsx as jsx18 } from "react/jsx-runtime";
|
|
2332
3979
|
var skeletonBase = cn(
|
|
2333
3980
|
"relative isolate inline-flex overflow-hidden",
|
|
2334
3981
|
"bg-[color:color-mix(in_oklab,var(--surface-2),var(--border)_25%)]",
|
|
@@ -2386,7 +4033,7 @@ var Skeleton = React8.forwardRef(
|
|
|
2386
4033
|
({ variant, size, radius, fullWidth, animation, preset, animate, asChild, className, children, ...props }, ref) => {
|
|
2387
4034
|
const resolvedAnimation = animation ?? (animate === false ? "none" : animate ? "pulse" : void 0);
|
|
2388
4035
|
const Component = asChild ? Slot2.Root : "div";
|
|
2389
|
-
return /* @__PURE__ */
|
|
4036
|
+
return /* @__PURE__ */ jsx18(
|
|
2390
4037
|
Component,
|
|
2391
4038
|
{
|
|
2392
4039
|
ref,
|
|
@@ -2403,7 +4050,7 @@ var Skeleton = React8.forwardRef(
|
|
|
2403
4050
|
),
|
|
2404
4051
|
"aria-hidden": props["aria-hidden"] ?? true,
|
|
2405
4052
|
...props,
|
|
2406
|
-
children: asChild ? /* @__PURE__ */
|
|
4053
|
+
children: asChild ? /* @__PURE__ */ jsx18(Slot2.Slottable, { children }) : children
|
|
2407
4054
|
}
|
|
2408
4055
|
);
|
|
2409
4056
|
}
|
|
@@ -2413,7 +4060,7 @@ Skeleton.displayName = "Skeleton";
|
|
|
2413
4060
|
// src/ui/components/Textarea.tsx
|
|
2414
4061
|
import { cva as cva5 } from "class-variance-authority";
|
|
2415
4062
|
import * as React9 from "react";
|
|
2416
|
-
import { jsx as
|
|
4063
|
+
import { jsx as jsx19 } from "react/jsx-runtime";
|
|
2417
4064
|
var controlShellBase2 = cn(
|
|
2418
4065
|
"relative inline-flex w-full",
|
|
2419
4066
|
"rounded-[var(--radius-input)]",
|
|
@@ -2508,13 +4155,13 @@ var Textarea = React9.forwardRef(
|
|
|
2508
4155
|
React9.useLayoutEffect(() => {
|
|
2509
4156
|
resize();
|
|
2510
4157
|
}, [resize, value]);
|
|
2511
|
-
return /* @__PURE__ */
|
|
4158
|
+
return /* @__PURE__ */ jsx19(
|
|
2512
4159
|
"div",
|
|
2513
4160
|
{
|
|
2514
4161
|
className: cn(textareaShellVariants({ variant, size, fullWidth }), className),
|
|
2515
4162
|
"data-invalid": invalid ? "" : void 0,
|
|
2516
4163
|
"data-disabled": isDisabled ? "" : void 0,
|
|
2517
|
-
children: /* @__PURE__ */
|
|
4164
|
+
children: /* @__PURE__ */ jsx19(
|
|
2518
4165
|
"textarea",
|
|
2519
4166
|
{
|
|
2520
4167
|
ref: mergeRefs(innerRef, ref),
|
|
@@ -2541,7 +4188,7 @@ Textarea.displayName = "Textarea";
|
|
|
2541
4188
|
import { AnimatePresence as AnimatePresence2, motion as motion2 } from "motion/react";
|
|
2542
4189
|
import { Tooltip as TooltipPrimitive } from "radix-ui";
|
|
2543
4190
|
import * as React10 from "react";
|
|
2544
|
-
import { jsx as
|
|
4191
|
+
import { jsx as jsx20, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2545
4192
|
var tooltipContentBase = cn(
|
|
2546
4193
|
"panel shadow-none px-4 py-2.5 text-xs z-5000 select-none",
|
|
2547
4194
|
"origin-center",
|
|
@@ -2561,9 +4208,9 @@ function Tooltip({
|
|
|
2561
4208
|
}) {
|
|
2562
4209
|
const [open2, setOpen] = React10.useState(false);
|
|
2563
4210
|
const motionDuration = useMotionDuration("--motion-fast", 0.14);
|
|
2564
|
-
return /* @__PURE__ */
|
|
2565
|
-
/* @__PURE__ */
|
|
2566
|
-
/* @__PURE__ */
|
|
4211
|
+
return /* @__PURE__ */ jsx20(TooltipPrimitive.Provider, { delayDuration: delayMs, children: /* @__PURE__ */ jsxs9(TooltipPrimitive.Root, { onOpenChange: setOpen, children: [
|
|
4212
|
+
/* @__PURE__ */ jsx20(TooltipPrimitive.Trigger, { asChild: true, children }),
|
|
4213
|
+
/* @__PURE__ */ jsx20(TooltipPrimitive.Portal, { forceMount: true, children: /* @__PURE__ */ jsx20(AnimatePresence2, { children: open2 ? /* @__PURE__ */ jsx20(TooltipPrimitive.Content, { asChild: true, forceMount: true, side, sideOffset, children: /* @__PURE__ */ jsxs9(
|
|
2567
4214
|
motion2.div,
|
|
2568
4215
|
{
|
|
2569
4216
|
className: tooltipContentBase,
|
|
@@ -2591,7 +4238,7 @@ function Tooltip({
|
|
|
2591
4238
|
},
|
|
2592
4239
|
children: [
|
|
2593
4240
|
content,
|
|
2594
|
-
/* @__PURE__ */
|
|
4241
|
+
/* @__PURE__ */ jsx20(TooltipPrimitive.Arrow, { style: { fill: "var(--surface-2)" } })
|
|
2595
4242
|
]
|
|
2596
4243
|
}
|
|
2597
4244
|
) }) : null }) })
|
|
@@ -2603,7 +4250,7 @@ import { cva as cva6 } from "class-variance-authority";
|
|
|
2603
4250
|
import { AnimatePresence as AnimatePresence3, motion as motion3 } from "motion/react";
|
|
2604
4251
|
import { Popover as PopoverPrimitive } from "radix-ui";
|
|
2605
4252
|
import * as React11 from "react";
|
|
2606
|
-
import { jsx as
|
|
4253
|
+
import { jsx as jsx21, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2607
4254
|
var popoverContentVariants = cva6(
|
|
2608
4255
|
cn(
|
|
2609
4256
|
"p-3 text-sm z-5000",
|
|
@@ -2675,7 +4322,7 @@ function Popover({
|
|
|
2675
4322
|
onOpenChange?.(nextOpen);
|
|
2676
4323
|
};
|
|
2677
4324
|
return /* @__PURE__ */ jsxs10(PopoverPrimitive.Root, { open: resolvedOpen, onOpenChange: handleOpenChange, modal, children: [
|
|
2678
|
-
/* @__PURE__ */
|
|
4325
|
+
/* @__PURE__ */ jsx21(
|
|
2679
4326
|
PopoverPrimitive.Trigger,
|
|
2680
4327
|
{
|
|
2681
4328
|
asChild: true,
|
|
@@ -2684,7 +4331,7 @@ function Popover({
|
|
|
2684
4331
|
children: trigger
|
|
2685
4332
|
}
|
|
2686
4333
|
),
|
|
2687
|
-
/* @__PURE__ */
|
|
4334
|
+
/* @__PURE__ */ jsx21(PopoverPrimitive.Portal, { forceMount: true, container: portalContainer, children: /* @__PURE__ */ jsx21(AnimatePresence3, { children: resolvedOpen ? /* @__PURE__ */ jsx21(
|
|
2688
4335
|
PopoverPrimitive.Content,
|
|
2689
4336
|
{
|
|
2690
4337
|
asChild: true,
|
|
@@ -2719,7 +4366,7 @@ function Popover({
|
|
|
2719
4366
|
style,
|
|
2720
4367
|
children: [
|
|
2721
4368
|
children,
|
|
2722
|
-
withArrow ? /* @__PURE__ */
|
|
4369
|
+
withArrow ? /* @__PURE__ */ jsx21(
|
|
2723
4370
|
PopoverPrimitive.Arrow,
|
|
2724
4371
|
{
|
|
2725
4372
|
className: arrowClassName,
|
|
@@ -2761,7 +4408,7 @@ function useComposedRefs(...refs) {
|
|
|
2761
4408
|
}
|
|
2762
4409
|
|
|
2763
4410
|
// src/ui/components/DropdownMenu.tsx
|
|
2764
|
-
import { jsx as
|
|
4411
|
+
import { jsx as jsx22, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
2765
4412
|
var dropdownMenuContentVariants = cva7(
|
|
2766
4413
|
cn(
|
|
2767
4414
|
"min-w-[14rem] p-2 text-sm z-5000",
|
|
@@ -2884,6 +4531,7 @@ function DropdownMenu({
|
|
|
2884
4531
|
children,
|
|
2885
4532
|
open: open2,
|
|
2886
4533
|
defaultOpen,
|
|
4534
|
+
keepMounted = false,
|
|
2887
4535
|
onOpenChange,
|
|
2888
4536
|
hoverOpen = false,
|
|
2889
4537
|
hoverCloseDelayMs = 50,
|
|
@@ -2989,9 +4637,43 @@ function DropdownMenu({
|
|
|
2989
4637
|
);
|
|
2990
4638
|
const onPointerDownOutside = (event) => {
|
|
2991
4639
|
restContentProps.onPointerDownOutside?.(event);
|
|
4640
|
+
if (keepMounted) {
|
|
4641
|
+
const target = event.target;
|
|
4642
|
+
const isTriggerEvent = target instanceof Node && triggerRef.current?.contains(target);
|
|
4643
|
+
if (!resolvedOpen || isTriggerEvent) {
|
|
4644
|
+
event.preventDefault();
|
|
4645
|
+
}
|
|
4646
|
+
}
|
|
4647
|
+
};
|
|
4648
|
+
const keepMountedClassName = keepMounted && !resolvedOpen ? "pointer-events-none" : void 0;
|
|
4649
|
+
const initialMotionState = {
|
|
4650
|
+
opacity: 0,
|
|
4651
|
+
scale: 0.98,
|
|
4652
|
+
x: "var(--menu-x)",
|
|
4653
|
+
y: "var(--menu-y)"
|
|
4654
|
+
};
|
|
4655
|
+
const openMotionState = {
|
|
4656
|
+
opacity: 1,
|
|
4657
|
+
scale: 1,
|
|
4658
|
+
x: 0,
|
|
4659
|
+
y: 0
|
|
4660
|
+
};
|
|
4661
|
+
const closedMotionState = {
|
|
4662
|
+
opacity: 0,
|
|
4663
|
+
scale: 0.98,
|
|
4664
|
+
x: "var(--menu-x)",
|
|
4665
|
+
y: "var(--menu-y)"
|
|
2992
4666
|
};
|
|
4667
|
+
const motionEase = keepMounted ? resolvedOpen ? "easeOut" : "easeIn" : "easeOut";
|
|
2993
4668
|
const onInteractOutside = (event) => {
|
|
2994
4669
|
restContentProps.onInteractOutside?.(event);
|
|
4670
|
+
if (keepMounted) {
|
|
4671
|
+
const target = event.target;
|
|
4672
|
+
const isTriggerEvent = target instanceof Node && triggerRef.current?.contains(target);
|
|
4673
|
+
if (!resolvedOpen || isTriggerEvent) {
|
|
4674
|
+
event.preventDefault();
|
|
4675
|
+
}
|
|
4676
|
+
}
|
|
2995
4677
|
};
|
|
2996
4678
|
const resolvedContentProps = hoverOpen ? {
|
|
2997
4679
|
...restContentProps,
|
|
@@ -3013,59 +4695,61 @@ function DropdownMenu({
|
|
|
3013
4695
|
onInteractOutside
|
|
3014
4696
|
} : {
|
|
3015
4697
|
...restContentProps,
|
|
3016
|
-
onKeyDown: handleContentKeyDown
|
|
4698
|
+
onKeyDown: handleContentKeyDown,
|
|
4699
|
+
...keepMounted ? { onPointerDownOutside, onInteractOutside } : void 0
|
|
3017
4700
|
};
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
4701
|
+
const contentNode = /* @__PURE__ */ jsx22(
|
|
4702
|
+
DropdownMenuPrimitive.Content,
|
|
4703
|
+
{
|
|
4704
|
+
asChild: true,
|
|
4705
|
+
forceMount: true,
|
|
4706
|
+
side,
|
|
4707
|
+
align,
|
|
4708
|
+
sideOffset,
|
|
4709
|
+
alignOffset,
|
|
4710
|
+
collisionPadding,
|
|
4711
|
+
"aria-label": ariaLabelledBy ? void 0 : ariaLabel,
|
|
4712
|
+
"aria-labelledby": ariaLabelledBy,
|
|
4713
|
+
...resolvedContentProps,
|
|
4714
|
+
children: /* @__PURE__ */ jsx22(
|
|
4715
|
+
motion4.div,
|
|
4716
|
+
{
|
|
4717
|
+
"aria-hidden": keepMounted ? !resolvedOpen : void 0,
|
|
4718
|
+
className: cn(
|
|
4719
|
+
dropdownMenuContentVariants({ chrome, orientation }),
|
|
4720
|
+
keepMountedClassName,
|
|
4721
|
+
className,
|
|
4722
|
+
contentClassName
|
|
4723
|
+
),
|
|
4724
|
+
ref: composedContentRef,
|
|
4725
|
+
initial: initialMotionState,
|
|
4726
|
+
animate: keepMounted ? resolvedOpen ? openMotionState : closedMotionState : openMotionState,
|
|
4727
|
+
exit: keepMounted ? void 0 : {
|
|
4728
|
+
opacity: 0,
|
|
4729
|
+
scale: 0.98,
|
|
4730
|
+
x: "var(--menu-x)",
|
|
4731
|
+
y: "var(--menu-y)",
|
|
4732
|
+
transition: { duration: motionDuration, ease: "easeIn" }
|
|
4733
|
+
},
|
|
4734
|
+
transition: {
|
|
4735
|
+
duration: motionDuration,
|
|
4736
|
+
ease: motionEase
|
|
4737
|
+
},
|
|
4738
|
+
style: { ...style, ...contentStyle },
|
|
4739
|
+
children
|
|
4740
|
+
}
|
|
4741
|
+
)
|
|
4742
|
+
}
|
|
4743
|
+
);
|
|
4744
|
+
return /* @__PURE__ */ jsx22(DropdownMenuOrientationContext.Provider, { value: resolvedItemsOrientation, children: /* @__PURE__ */ jsxs11(DropdownMenuPrimitive.Root, { open: resolvedOpen, onOpenChange: handleOpenChange, modal, children: [
|
|
4745
|
+
/* @__PURE__ */ jsx22(DropdownMenuPrimitive.Trigger, { asChild: true, children: resolvedTrigger }),
|
|
4746
|
+
/* @__PURE__ */ jsx22(DropdownMenuPrimitive.Portal, { forceMount: true, container: portalContainer, children: keepMounted ? contentNode : /* @__PURE__ */ jsx22(AnimatePresence4, { children: resolvedOpen ? contentNode : null }) })
|
|
3063
4747
|
] }) });
|
|
3064
4748
|
}
|
|
3065
4749
|
var DropdownMenuItem = React13.forwardRef(
|
|
3066
4750
|
({ className, inset, destructive, ...props }, ref) => {
|
|
3067
4751
|
const orientation = React13.useContext(DropdownMenuOrientationContext);
|
|
3068
|
-
return /* @__PURE__ */
|
|
4752
|
+
return /* @__PURE__ */ jsx22(
|
|
3069
4753
|
DropdownMenuPrimitive.Item,
|
|
3070
4754
|
{
|
|
3071
4755
|
ref,
|
|
@@ -3079,14 +4763,14 @@ DropdownMenuItem.displayName = "DropdownMenuItem";
|
|
|
3079
4763
|
var DropdownMenuSeparator = React13.forwardRef(({ className, ...props }, ref) => {
|
|
3080
4764
|
const orientation = React13.useContext(DropdownMenuOrientationContext);
|
|
3081
4765
|
const orientationClassName = orientation === "horizontal" ? "mx-1 w-px self-stretch bg-(--divider)" : "my-1 h-px bg-(--divider)";
|
|
3082
|
-
return /* @__PURE__ */
|
|
4766
|
+
return /* @__PURE__ */ jsx22(DropdownMenuPrimitive.Separator, { ref, className: cn(orientationClassName, className), ...props });
|
|
3083
4767
|
});
|
|
3084
4768
|
DropdownMenuSeparator.displayName = "DropdownMenuSeparator";
|
|
3085
4769
|
|
|
3086
4770
|
// src/ui/components/Kbd.tsx
|
|
3087
4771
|
import { cva as cva8 } from "class-variance-authority";
|
|
3088
4772
|
import * as React14 from "react";
|
|
3089
|
-
import { jsx as
|
|
4773
|
+
import { jsx as jsx23 } from "react/jsx-runtime";
|
|
3090
4774
|
var kbdVariants = cva8(
|
|
3091
4775
|
cn(
|
|
3092
4776
|
"inline-flex min-w-7 items-center justify-center gap-1",
|
|
@@ -3108,7 +4792,7 @@ var kbdVariants = cva8(
|
|
|
3108
4792
|
}
|
|
3109
4793
|
}
|
|
3110
4794
|
);
|
|
3111
|
-
var Kbd = React14.forwardRef(({ className, variant, ...props }, ref) => /* @__PURE__ */
|
|
4795
|
+
var Kbd = React14.forwardRef(({ className, variant, ...props }, ref) => /* @__PURE__ */ jsx23("span", { ref, className: cn(kbdVariants({ variant }), className), ...props }));
|
|
3112
4796
|
Kbd.displayName = "Kbd";
|
|
3113
4797
|
export {
|
|
3114
4798
|
AuthController,
|
|
@@ -3126,27 +4810,42 @@ export {
|
|
|
3126
4810
|
DialogContent,
|
|
3127
4811
|
DialogController,
|
|
3128
4812
|
DialogHost,
|
|
4813
|
+
DisableScopeUseCase,
|
|
3129
4814
|
DropdownMenu,
|
|
3130
4815
|
DropdownMenuItem,
|
|
3131
4816
|
DropdownMenuSeparator,
|
|
4817
|
+
EnableScopeUseCase,
|
|
3132
4818
|
Field,
|
|
3133
4819
|
HttpError,
|
|
4820
|
+
InMemorySelectionStore,
|
|
3134
4821
|
InfoDialog,
|
|
3135
4822
|
Input,
|
|
3136
4823
|
Kbd,
|
|
4824
|
+
KeyboardProvider,
|
|
4825
|
+
ListShortcutsUseCase,
|
|
3137
4826
|
MockAuthHttpClient,
|
|
3138
4827
|
MockHttpClient,
|
|
3139
4828
|
NotificationHost,
|
|
3140
4829
|
NotifierController,
|
|
3141
4830
|
Popover,
|
|
3142
4831
|
RedirectIfAuthed,
|
|
4832
|
+
RegisterShortcutUseCase,
|
|
3143
4833
|
RequireAuth,
|
|
4834
|
+
ScopeManager,
|
|
4835
|
+
SelectionController,
|
|
4836
|
+
SelectionControllerProvider,
|
|
3144
4837
|
Skeleton,
|
|
3145
4838
|
Textarea,
|
|
3146
4839
|
Tooltip,
|
|
4840
|
+
UnregisterShortcutUseCase,
|
|
4841
|
+
VimController,
|
|
4842
|
+
VimControllerProvider,
|
|
4843
|
+
VimRegionRegistry,
|
|
3147
4844
|
authController,
|
|
3148
4845
|
controllerFactory,
|
|
3149
4846
|
createAuthController,
|
|
4847
|
+
createSelectionController,
|
|
4848
|
+
createVimController,
|
|
3150
4849
|
dialogController,
|
|
3151
4850
|
httpClient as fetchHttpClient,
|
|
3152
4851
|
getDialogTemplate,
|
|
@@ -3162,5 +4861,12 @@ export {
|
|
|
3162
4861
|
useAuthDispatch,
|
|
3163
4862
|
useAuthedUser,
|
|
3164
4863
|
useDialog,
|
|
3165
|
-
|
|
4864
|
+
useKeyboardController,
|
|
4865
|
+
useResponsiveMutation,
|
|
4866
|
+
useSelectionController,
|
|
4867
|
+
useShortcut,
|
|
4868
|
+
useShortcutScope,
|
|
4869
|
+
useVimBindings,
|
|
4870
|
+
useVimController,
|
|
4871
|
+
useVimRegion
|
|
3166
4872
|
};
|