@proveanything/smartlinks-utils-ui 0.3.12 → 0.3.14
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/{chunk-TY2UIZ24.js → chunk-76Y4UTYQ.js} +14 -5
- package/dist/chunk-76Y4UTYQ.js.map +1 -0
- package/dist/{chunk-MZ6JSCXO.js → chunk-JMCV6FOW.js} +2 -2
- package/dist/{chunk-MZ6JSCXO.js.map → chunk-JMCV6FOW.js.map} +1 -1
- package/dist/chunk-LLSIDR6U.js +28 -0
- package/dist/chunk-LLSIDR6U.js.map +1 -0
- package/dist/chunk-S27GIYV7.js +3 -0
- package/dist/chunk-S27GIYV7.js.map +1 -0
- package/dist/components/AssetPicker/index.js +1 -1
- package/dist/components/ConditionsEditor/index.js +1 -1
- package/dist/components/FacetRuleEditor/index.js +2 -1
- package/dist/components/FontPicker/index.js +1 -1
- package/dist/components/IconPicker/index.js +1 -1
- package/dist/components/RecordsAdmin/index.d.ts +58 -4
- package/dist/components/RecordsAdmin/index.js +441 -64
- package/dist/components/RecordsAdmin/index.js.map +1 -1
- package/dist/index.js +3 -2
- package/dist/records-AUJWCB7Q.js +3 -0
- package/dist/{records-66QWR67J.js.map → records-AUJWCB7Q.js.map} +1 -1
- package/package.json +1 -1
- package/dist/chunk-3BLWNYM4.js +0 -28
- package/dist/chunk-3BLWNYM4.js.map +0 -1
- package/dist/chunk-TY2UIZ24.js.map +0 -1
- package/dist/records-66QWR67J.js +0 -3
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import { styleInject } from '../../chunk-
|
|
1
|
+
import { styleInject } from '../../chunk-LLSIDR6U.js';
|
|
2
|
+
import { FacetRuleEditor } from '../../chunk-JMCV6FOW.js';
|
|
3
|
+
import { useFacets } from '../../chunk-4LHF5JB7.js';
|
|
2
4
|
import { cn } from '../../chunk-L7FQ52F5.js';
|
|
3
|
-
import { listRecords, parsedRefToTarget, parsedRefToScope, matchRecords, scopesEqual, upsertRecord, deleteRecord } from '../../chunk-
|
|
4
|
-
export { bulkDelete, bulkUpsert, deleteRecord, getRecordByRef, listRecords, matchRecords, parsedRefToScope, parsedRefToTarget, restoreRecord, scopesEqual, upsertRecord } from '../../chunk-
|
|
5
|
+
import { listRecords, getRecordByRef, parsedRefToTarget, parsedRefToScope, matchRecords, scopesEqual, upsertRecord, deleteRecord } from '../../chunk-76Y4UTYQ.js';
|
|
6
|
+
export { bulkDelete, bulkUpsert, deleteRecord, getRecordByRef, listRecords, matchRecords, parsedRefToScope, parsedRefToTarget, restoreRecord, scopesEqual, upsertRecord } from '../../chunk-76Y4UTYQ.js';
|
|
5
7
|
import { createContext, useMemo, useState, useEffect, useCallback, useRef, useContext, createElement } from 'react';
|
|
6
|
-
import { ChevronDown, Database, Lightbulb, SearchX, Inbox, LayoutGrid, Eye, MoreHorizontal, Download, Upload, Trash2, Copy, Pencil, Plus, CircleDashed, ArrowDownLeft, CheckCircle2, SlidersHorizontal, Globe, Tag, Boxes, Layers, Package, Rows3, List, ChevronRight, Eraser, ClipboardPaste, Box, X, Image, Table, ArrowLeft, ChevronLeft, AlertTriangle, Info, HelpCircle, Search, CornerDownLeft, Circle, AlertCircle, Undo2, Save } from 'lucide-react';
|
|
8
|
+
import { ChevronDown, Database, Lightbulb, SearchX, Inbox, LayoutGrid, Eye, MoreHorizontal, Download, Upload, Trash2, Copy, Pencil, Plus, CircleDashed, ArrowDownLeft, CheckCircle2, SlidersHorizontal, Globe, Tag, Boxes, Layers, Package, Rows3, List, ChevronRight, Eraser, ClipboardPaste, Box, X, Image, Table, ArrowLeft, ChevronLeft, AlertTriangle, Info, HelpCircle, Search, CornerDownLeft, Circle, AlertCircle, Undo2, Save, Target, Settings2 } from 'lucide-react';
|
|
7
9
|
import { useQueryClient, useInfiniteQuery, useQuery } from '@tanstack/react-query';
|
|
8
10
|
import { createPortal } from 'react-dom';
|
|
9
11
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
@@ -255,7 +257,8 @@ var toSummary = (rec) => {
|
|
|
255
257
|
const ref = rec.ref ?? "";
|
|
256
258
|
const scope = parseRef(ref);
|
|
257
259
|
const facetRule = rec.facetRule ?? null;
|
|
258
|
-
const
|
|
260
|
+
const ruleLabel = facetRule && facetRule.all && facetRule.all.length > 0 ? facetRule.all.length === 1 ? "Rule \xB7 1 facet" : `Rule \xB7 ${facetRule.all.length} facets` : null;
|
|
261
|
+
const fallbackLabel = scope.batchId ?? scope.variantId ?? scope.productId ?? scope.facetValue ?? scope.facetId ?? ruleLabel ?? (ref.startsWith("rule:") ? "Rule-targeted record" : ref || "Global record");
|
|
259
262
|
return {
|
|
260
263
|
id: rec.id,
|
|
261
264
|
ref,
|
|
@@ -361,6 +364,17 @@ var useRecordList = (args) => {
|
|
|
361
364
|
|
|
362
365
|
// src/components/RecordsAdmin/data/resolveRecord.ts
|
|
363
366
|
var resolveRecord = async (args) => {
|
|
367
|
+
if (args.target.kind === "rule" && args.target.raw) {
|
|
368
|
+
const rec = await getRecordByRef(args.ctx, args.target.raw).catch(() => null);
|
|
369
|
+
if (!rec) return { data: null, source: "empty" };
|
|
370
|
+
const recFacetRule = rec.facetRule ?? null;
|
|
371
|
+
return {
|
|
372
|
+
data: rec.data,
|
|
373
|
+
source: "self",
|
|
374
|
+
sourceRef: rec.ref ?? args.target.raw,
|
|
375
|
+
facetRule: recFacetRule
|
|
376
|
+
};
|
|
377
|
+
}
|
|
364
378
|
const target = parsedRefToTarget(args.target);
|
|
365
379
|
const editingScope = parsedRefToScope(args.target);
|
|
366
380
|
const result = await matchRecords(args.ctx, target, { strategy: "all" }).catch(() => null);
|
|
@@ -418,6 +432,7 @@ var resolvedRecordQueryKey = (args) => [
|
|
|
418
432
|
args.facetId ?? null,
|
|
419
433
|
args.facetValue ?? null,
|
|
420
434
|
args.proofId ?? null,
|
|
435
|
+
args.ref ?? null,
|
|
421
436
|
args.withParent ?? true
|
|
422
437
|
];
|
|
423
438
|
function useResolvedRecord(args) {
|
|
@@ -432,6 +447,7 @@ function useResolvedRecord(args) {
|
|
|
432
447
|
facetId,
|
|
433
448
|
facetValue,
|
|
434
449
|
proofId,
|
|
450
|
+
ref,
|
|
435
451
|
supportedScopes = DEFAULT_SCOPES,
|
|
436
452
|
enabled = true,
|
|
437
453
|
withParent = true
|
|
@@ -447,12 +463,13 @@ function useResolvedRecord(args) {
|
|
|
447
463
|
facetId,
|
|
448
464
|
facetValue,
|
|
449
465
|
proofId,
|
|
466
|
+
ref,
|
|
450
467
|
withParent
|
|
451
468
|
}),
|
|
452
469
|
enabled: enabled && !!collectionId && !!appId,
|
|
453
470
|
staleTime: 15e3,
|
|
454
471
|
queryFn: async () => {
|
|
455
|
-
const target = parseRef("");
|
|
472
|
+
const target = ref ? parseRef(ref) : parseRef("");
|
|
456
473
|
target.productId = productId;
|
|
457
474
|
target.variantId = variantId;
|
|
458
475
|
target.batchId = batchId;
|
|
@@ -473,6 +490,49 @@ function useResolvedRecord(args) {
|
|
|
473
490
|
error: query.error ?? null
|
|
474
491
|
};
|
|
475
492
|
}
|
|
493
|
+
var isFacetRuleValid = (rule) => {
|
|
494
|
+
if (!rule || !Array.isArray(rule.all) || rule.all.length === 0) return false;
|
|
495
|
+
return rule.all.every(
|
|
496
|
+
(c) => !!c.facetKey && Array.isArray(c.anyOf) && c.anyOf.length > 0
|
|
497
|
+
);
|
|
498
|
+
};
|
|
499
|
+
function useRulePreview(args) {
|
|
500
|
+
const {
|
|
501
|
+
SL,
|
|
502
|
+
collectionId,
|
|
503
|
+
appId,
|
|
504
|
+
rule,
|
|
505
|
+
limit = 20,
|
|
506
|
+
debounceMs = 350,
|
|
507
|
+
enabled = true
|
|
508
|
+
} = args;
|
|
509
|
+
const [debouncedRule, setDebouncedRule] = useState(rule);
|
|
510
|
+
const timer = useRef(null);
|
|
511
|
+
useEffect(() => {
|
|
512
|
+
if (timer.current) clearTimeout(timer.current);
|
|
513
|
+
timer.current = setTimeout(() => setDebouncedRule(rule), debounceMs);
|
|
514
|
+
return () => {
|
|
515
|
+
if (timer.current) clearTimeout(timer.current);
|
|
516
|
+
};
|
|
517
|
+
}, [rule, debounceMs]);
|
|
518
|
+
const valid = isFacetRuleValid(debouncedRule);
|
|
519
|
+
const query = useQuery({
|
|
520
|
+
queryKey: ["records-admin", "preview-rule", collectionId, appId, debouncedRule, limit],
|
|
521
|
+
enabled: enabled && !!collectionId && !!appId && valid,
|
|
522
|
+
staleTime: 3e4,
|
|
523
|
+
queryFn: () => SL.app.records.previewRule(collectionId, appId, {
|
|
524
|
+
facetRule: debouncedRule,
|
|
525
|
+
limit
|
|
526
|
+
})
|
|
527
|
+
});
|
|
528
|
+
return {
|
|
529
|
+
totalMatches: query.data?.totalMatches ?? null,
|
|
530
|
+
sampleProductIds: query.data?.sampleProductIds ?? [],
|
|
531
|
+
isLoading: query.isFetching,
|
|
532
|
+
isStale: rule !== debouncedRule,
|
|
533
|
+
error: query.error ?? null
|
|
534
|
+
};
|
|
535
|
+
}
|
|
476
536
|
|
|
477
537
|
// src/components/RecordsAdmin/hooks/useRecordEditor.ts
|
|
478
538
|
var isEqual = (a, b) => {
|
|
@@ -502,12 +562,15 @@ function useRecordEditor(args) {
|
|
|
502
562
|
onSaved,
|
|
503
563
|
onDeleted,
|
|
504
564
|
onSaveError,
|
|
505
|
-
reseed = "always"
|
|
565
|
+
reseed = "always",
|
|
566
|
+
initialFacetRule = null
|
|
506
567
|
} = args;
|
|
507
568
|
const queryClient = useQueryClient();
|
|
508
569
|
const seed = cloneSeed(resolved, defaultData);
|
|
509
570
|
const [value, setValue] = useState(seed);
|
|
510
571
|
const [savedSnapshot, setSavedSnapshot] = useState(seed);
|
|
572
|
+
const [facetRule, setFacetRule] = useState(initialFacetRule);
|
|
573
|
+
const [savedFacetRule, setSavedFacetRule] = useState(initialFacetRule);
|
|
511
574
|
const [optimisticSource, setOptimisticSource] = useState(null);
|
|
512
575
|
const [isSaving, setIsSaving] = useState(false);
|
|
513
576
|
const [saveError, setSaveError] = useState(null);
|
|
@@ -524,12 +587,15 @@ function useRecordEditor(args) {
|
|
|
524
587
|
setValue(fresh);
|
|
525
588
|
}
|
|
526
589
|
setSavedSnapshot(fresh);
|
|
590
|
+
setFacetRule(initialFacetRule);
|
|
591
|
+
setSavedFacetRule(initialFacetRule);
|
|
527
592
|
setOptimisticSource(null);
|
|
528
593
|
}, [scope.raw, resolved.source, resolved.sourceRef]);
|
|
529
|
-
const isDirty = !isEqual(value, savedSnapshot);
|
|
594
|
+
const isDirty = !isEqual(value, savedSnapshot) || !isEqual(facetRule, savedFacetRule);
|
|
530
595
|
const save = useCallback(async () => {
|
|
531
596
|
if (!scope.raw) return;
|
|
532
597
|
const previousSnapshot = savedSnapshot;
|
|
598
|
+
const previousRuleSnapshot = savedFacetRule;
|
|
533
599
|
resolved.source;
|
|
534
600
|
const cacheKey = resolvedRecordQueryKey({
|
|
535
601
|
collectionId: ctx.collectionId,
|
|
@@ -541,12 +607,14 @@ function useRecordEditor(args) {
|
|
|
541
607
|
facetId: scope.facetId,
|
|
542
608
|
facetValue: scope.facetValue,
|
|
543
609
|
proofId: scope.proofId,
|
|
610
|
+
ref: scope.raw,
|
|
544
611
|
withParent: true
|
|
545
612
|
});
|
|
546
613
|
const previousCache = queryClient.getQueryData(cacheKey);
|
|
547
614
|
setSaveError(null);
|
|
548
615
|
setIsSaving(true);
|
|
549
616
|
setSavedSnapshot(value);
|
|
617
|
+
setSavedFacetRule(facetRule);
|
|
550
618
|
setOptimisticSource("self");
|
|
551
619
|
queryClient.setQueryData(cacheKey, {
|
|
552
620
|
data: value,
|
|
@@ -558,11 +626,13 @@ function useRecordEditor(args) {
|
|
|
558
626
|
await upsertRecord(ctx, {
|
|
559
627
|
ref: scope.raw,
|
|
560
628
|
scope: parsedRefToScope(scope),
|
|
561
|
-
data: value
|
|
629
|
+
data: value,
|
|
630
|
+
facetRule
|
|
562
631
|
});
|
|
563
632
|
onSaved?.();
|
|
564
633
|
} catch (err) {
|
|
565
634
|
setSavedSnapshot(previousSnapshot);
|
|
635
|
+
setSavedFacetRule(previousRuleSnapshot);
|
|
566
636
|
setOptimisticSource(null);
|
|
567
637
|
if (previousCache !== void 0) {
|
|
568
638
|
queryClient.setQueryData(cacheKey, previousCache);
|
|
@@ -575,16 +645,21 @@ function useRecordEditor(args) {
|
|
|
575
645
|
} finally {
|
|
576
646
|
setIsSaving(false);
|
|
577
647
|
}
|
|
578
|
-
}, [scope.raw, value, savedSnapshot, resolved.source, resolved.parentValue]);
|
|
648
|
+
}, [scope.raw, value, savedSnapshot, facetRule, savedFacetRule, resolved.source, resolved.parentValue]);
|
|
579
649
|
const reset = useCallback(() => {
|
|
580
650
|
setValue(savedSnapshot);
|
|
581
|
-
|
|
651
|
+
setFacetRule(savedFacetRule);
|
|
652
|
+
}, [savedSnapshot, savedFacetRule]);
|
|
582
653
|
const remove = useCallback(async () => {
|
|
583
654
|
if (resolved.source !== "self" || !scope.raw) return;
|
|
584
655
|
await deleteRecord(ctx, scope.raw);
|
|
585
656
|
onDeleted?.();
|
|
586
657
|
}, [resolved.source, scope.raw]);
|
|
587
658
|
const effectiveSource = optimisticSource ?? resolved.source;
|
|
659
|
+
const isRuleScope = scope.kind === "rule";
|
|
660
|
+
const ruleValid = !isRuleScope || isFacetRuleValid(facetRule);
|
|
661
|
+
const canSave = ruleValid;
|
|
662
|
+
const cannotSaveReason = !ruleValid ? "Pick at least one value for every facet in the rule before saving." : void 0;
|
|
588
663
|
return {
|
|
589
664
|
value,
|
|
590
665
|
onChange: setValue,
|
|
@@ -596,8 +671,12 @@ function useRecordEditor(args) {
|
|
|
596
671
|
reset,
|
|
597
672
|
remove,
|
|
598
673
|
canRemove: effectiveSource === "self",
|
|
674
|
+
canSave,
|
|
675
|
+
cannotSaveReason,
|
|
599
676
|
isSaving,
|
|
600
|
-
saveError
|
|
677
|
+
saveError,
|
|
678
|
+
facetRule,
|
|
679
|
+
onFacetRuleChange: setFacetRule
|
|
601
680
|
};
|
|
602
681
|
}
|
|
603
682
|
var RT_KEY = (recordType) => recordType ?? "_default";
|
|
@@ -1471,12 +1550,26 @@ function formatFacetRule(rule) {
|
|
|
1471
1550
|
});
|
|
1472
1551
|
return parts.join(" AND ");
|
|
1473
1552
|
}
|
|
1553
|
+
function summarizeFacetRule(rule) {
|
|
1554
|
+
if (!rule || !rule.all || rule.all.length === 0) return [];
|
|
1555
|
+
return rule.all.map((c) => {
|
|
1556
|
+
const values = (c.anyOf ?? []).filter(Boolean);
|
|
1557
|
+
let label;
|
|
1558
|
+
if (values.length === 0) label = `${c.facetKey}: \u2014`;
|
|
1559
|
+
else if (values.length === 1) label = `${c.facetKey}: ${values[0]}`;
|
|
1560
|
+
else if (values.length <= 3) label = `${c.facetKey}: ${values.join(", ")}`;
|
|
1561
|
+
else label = `${c.facetKey}: ${values.slice(0, 2).join(", ")} +${values.length - 2}`;
|
|
1562
|
+
return { facetKey: c.facetKey, values, label };
|
|
1563
|
+
});
|
|
1564
|
+
}
|
|
1474
1565
|
var DefaultRecordRow = ({ record, ctx, compact = false }) => {
|
|
1475
1566
|
const { selected, onSelect, isDirty, onCopy, onPaste, canPaste, pasteWillReplace, clipboardSourceLabel } = ctx;
|
|
1476
1567
|
const ScopeIcon = record.scope.kind && record.scope.kind !== "collection" ? DEFAULT_ICONS.scope[record.scope.kind] : DEFAULT_ICONS.scope.product;
|
|
1477
1568
|
const tone = resolveTone(void 0, record.status);
|
|
1478
1569
|
const ruleSummary = formatFacetRule(record.facetRule);
|
|
1479
|
-
const
|
|
1570
|
+
const ruleClauses = summarizeFacetRule(record.facetRule);
|
|
1571
|
+
const isRuleRecord = ruleClauses.length > 0;
|
|
1572
|
+
const subtitle = record.subtitle ?? (isRuleRecord ? null : ruleSummary) ?? (tone === "missing" ? "Empty \u2014 needs values" : tone === "own" ? "Configured" : "Inherited");
|
|
1480
1573
|
return /* @__PURE__ */ jsxs(
|
|
1481
1574
|
"button",
|
|
1482
1575
|
{
|
|
@@ -1496,7 +1589,22 @@ var DefaultRecordRow = ({ record, ctx, compact = false }) => {
|
|
|
1496
1589
|
) }),
|
|
1497
1590
|
/* @__PURE__ */ jsxs("div", { className: "ra-row-body", children: [
|
|
1498
1591
|
/* @__PURE__ */ jsx("div", { className: "ra-row-title", children: record.label }),
|
|
1499
|
-
!compact && /* @__PURE__ */
|
|
1592
|
+
!compact && isRuleRecord && /* @__PURE__ */ jsxs(
|
|
1593
|
+
"div",
|
|
1594
|
+
{
|
|
1595
|
+
className: "ra-row-rule-chips",
|
|
1596
|
+
title: ruleSummary ?? void 0,
|
|
1597
|
+
"aria-label": ruleSummary ?? void 0,
|
|
1598
|
+
children: [
|
|
1599
|
+
ruleClauses.slice(0, 4).map((clause, i) => /* @__PURE__ */ jsx("span", { className: "ra-rule-chip", children: clause.label }, `${clause.facetKey}-${i}`)),
|
|
1600
|
+
ruleClauses.length > 4 && /* @__PURE__ */ jsxs("span", { className: "ra-rule-chip ra-rule-chip-more", children: [
|
|
1601
|
+
"+",
|
|
1602
|
+
ruleClauses.length - 4
|
|
1603
|
+
] })
|
|
1604
|
+
]
|
|
1605
|
+
}
|
|
1606
|
+
),
|
|
1607
|
+
!compact && !isRuleRecord && /* @__PURE__ */ jsx("div", { className: "ra-row-sub", children: subtitle })
|
|
1500
1608
|
] }),
|
|
1501
1609
|
compact && /* @__PURE__ */ jsx(StatusIcon, { status: record.status, size: "0.85rem" }),
|
|
1502
1610
|
!compact && record.scope.kind && record.scope.kind !== "collection" && /* @__PURE__ */ jsx("span", { className: "ra-row-scope", "aria-hidden": "true", children: /* @__PURE__ */ jsx(ScopeIcon, { className: "w-3 h-3" }) }),
|
|
@@ -1609,6 +1717,104 @@ var ProductList = RecordList;
|
|
|
1609
1717
|
var FacetList = RecordList;
|
|
1610
1718
|
var VariantList = RecordList;
|
|
1611
1719
|
var BatchList = RecordList;
|
|
1720
|
+
var EMPTY_RULE_FILTERS = { facetKeys: [], minClauses: null };
|
|
1721
|
+
var COMPLEXITY_THRESHOLDS = [3, 5, 10];
|
|
1722
|
+
var ruleOf = (r) => r.facetRule ?? null;
|
|
1723
|
+
function RuleFilterChips({ source, value, onChange }) {
|
|
1724
|
+
const facetKeyEntries = useMemo(() => {
|
|
1725
|
+
const counts = /* @__PURE__ */ new Map();
|
|
1726
|
+
for (const r of source) {
|
|
1727
|
+
const rule = ruleOf(r);
|
|
1728
|
+
if (!rule) continue;
|
|
1729
|
+
for (const c of rule.all ?? []) {
|
|
1730
|
+
counts.set(c.facetKey, (counts.get(c.facetKey) ?? 0) + 1);
|
|
1731
|
+
}
|
|
1732
|
+
}
|
|
1733
|
+
return Array.from(counts.entries()).sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]));
|
|
1734
|
+
}, [source]);
|
|
1735
|
+
const maxClauses = useMemo(() => {
|
|
1736
|
+
let max = 0;
|
|
1737
|
+
for (const r of source) {
|
|
1738
|
+
const rule = ruleOf(r);
|
|
1739
|
+
if (!rule) continue;
|
|
1740
|
+
max = Math.max(max, rule.all?.length ?? 0);
|
|
1741
|
+
}
|
|
1742
|
+
return max;
|
|
1743
|
+
}, [source]);
|
|
1744
|
+
if (facetKeyEntries.length === 0 && maxClauses < 2) return null;
|
|
1745
|
+
const toggleKey = (key) => {
|
|
1746
|
+
const has = value.facetKeys.includes(key);
|
|
1747
|
+
const next = has ? value.facetKeys.filter((k) => k !== key) : [...value.facetKeys, key];
|
|
1748
|
+
onChange({ ...value, facetKeys: next });
|
|
1749
|
+
};
|
|
1750
|
+
const setMin = (n) => onChange({ ...value, minClauses: n });
|
|
1751
|
+
const hasAny = value.facetKeys.length > 0 || value.minClauses != null;
|
|
1752
|
+
return /* @__PURE__ */ jsxs("div", { className: "ra-rule-filters", children: [
|
|
1753
|
+
/* @__PURE__ */ jsx("div", { className: "ra-rule-filters-row", role: "group", "aria-label": "Filter rules by facet", children: facetKeyEntries.map(([key, count]) => {
|
|
1754
|
+
const active = value.facetKeys.includes(key);
|
|
1755
|
+
return /* @__PURE__ */ jsxs(
|
|
1756
|
+
"button",
|
|
1757
|
+
{
|
|
1758
|
+
type: "button",
|
|
1759
|
+
onClick: () => toggleKey(key),
|
|
1760
|
+
className: "ra-rule-filter-chip",
|
|
1761
|
+
"data-active": active ? "true" : "false",
|
|
1762
|
+
"aria-pressed": active,
|
|
1763
|
+
title: `Show rules using ${key}`,
|
|
1764
|
+
children: [
|
|
1765
|
+
/* @__PURE__ */ jsx("span", { className: "ra-rule-filter-chip-label", children: key }),
|
|
1766
|
+
/* @__PURE__ */ jsx("span", { className: "ra-rule-filter-chip-count", children: count })
|
|
1767
|
+
]
|
|
1768
|
+
},
|
|
1769
|
+
key
|
|
1770
|
+
);
|
|
1771
|
+
}) }),
|
|
1772
|
+
maxClauses >= 2 && /* @__PURE__ */ jsx("div", { className: "ra-rule-filters-row", role: "group", "aria-label": "Filter by clause count", children: COMPLEXITY_THRESHOLDS.filter((n) => maxClauses >= n).map((n) => {
|
|
1773
|
+
const active = value.minClauses === n;
|
|
1774
|
+
return /* @__PURE__ */ jsxs(
|
|
1775
|
+
"button",
|
|
1776
|
+
{
|
|
1777
|
+
type: "button",
|
|
1778
|
+
onClick: () => setMin(active ? null : n),
|
|
1779
|
+
className: "ra-rule-filter-chip",
|
|
1780
|
+
"data-tone": "complexity",
|
|
1781
|
+
"data-active": active ? "true" : "false",
|
|
1782
|
+
"aria-pressed": active,
|
|
1783
|
+
title: `Only rules with \u2265 ${n} facets`,
|
|
1784
|
+
children: [
|
|
1785
|
+
"\u2265 ",
|
|
1786
|
+
n,
|
|
1787
|
+
" facets"
|
|
1788
|
+
]
|
|
1789
|
+
},
|
|
1790
|
+
n
|
|
1791
|
+
);
|
|
1792
|
+
}) }),
|
|
1793
|
+
hasAny && /* @__PURE__ */ jsx(
|
|
1794
|
+
"button",
|
|
1795
|
+
{
|
|
1796
|
+
type: "button",
|
|
1797
|
+
onClick: () => onChange(EMPTY_RULE_FILTERS),
|
|
1798
|
+
className: "ra-rule-filter-clear",
|
|
1799
|
+
"aria-label": "Clear rule filters",
|
|
1800
|
+
children: "Clear filters"
|
|
1801
|
+
}
|
|
1802
|
+
)
|
|
1803
|
+
] });
|
|
1804
|
+
}
|
|
1805
|
+
function applyRuleFilters(items, filters) {
|
|
1806
|
+
if (filters.facetKeys.length === 0 && filters.minClauses == null) return items;
|
|
1807
|
+
return items.filter((r) => {
|
|
1808
|
+
const rule = ruleOf(r);
|
|
1809
|
+
if (!rule) return false;
|
|
1810
|
+
if (filters.minClauses != null && (rule.all?.length ?? 0) < filters.minClauses) return false;
|
|
1811
|
+
if (filters.facetKeys.length > 0) {
|
|
1812
|
+
const keys = new Set((rule.all ?? []).map((c) => c.facetKey));
|
|
1813
|
+
if (!filters.facetKeys.some((k) => keys.has(k))) return false;
|
|
1814
|
+
}
|
|
1815
|
+
return true;
|
|
1816
|
+
});
|
|
1817
|
+
}
|
|
1612
1818
|
var EmptyState = ({
|
|
1613
1819
|
title,
|
|
1614
1820
|
body,
|
|
@@ -2081,6 +2287,7 @@ function RecordEditor({
|
|
|
2081
2287
|
i18n,
|
|
2082
2288
|
children,
|
|
2083
2289
|
preview,
|
|
2290
|
+
targeting,
|
|
2084
2291
|
bulkActions,
|
|
2085
2292
|
footerExtra,
|
|
2086
2293
|
onBeforeDelete,
|
|
@@ -2164,6 +2371,7 @@ function RecordEditor({
|
|
|
2164
2371
|
}
|
|
2165
2372
|
),
|
|
2166
2373
|
/* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto px-5 py-4", children: [
|
|
2374
|
+
targeting,
|
|
2167
2375
|
children,
|
|
2168
2376
|
preview
|
|
2169
2377
|
] }),
|
|
@@ -2251,7 +2459,8 @@ function RecordEditor({
|
|
|
2251
2459
|
void ctx.save().catch(() => {
|
|
2252
2460
|
});
|
|
2253
2461
|
},
|
|
2254
|
-
disabled: !ctx.isDirty || !!ctx.isSaving,
|
|
2462
|
+
disabled: !ctx.isDirty || !!ctx.isSaving || ctx.canSave === false,
|
|
2463
|
+
title: ctx.canSave === false ? ctx.cannotSaveReason : void 0,
|
|
2255
2464
|
className: "text-xs px-3 py-1.5 rounded-md font-medium transition-opacity disabled:opacity-40 inline-flex items-center gap-1.5",
|
|
2256
2465
|
style: { background: "hsl(var(--ra-accent))", color: "hsl(var(--ra-surface))" },
|
|
2257
2466
|
children: [
|
|
@@ -2265,6 +2474,120 @@ function RecordEditor({
|
|
|
2265
2474
|
)
|
|
2266
2475
|
] });
|
|
2267
2476
|
}
|
|
2477
|
+
function summariseRule(clauses, facets) {
|
|
2478
|
+
let valueCount = 0;
|
|
2479
|
+
const parts = clauses.map((c) => {
|
|
2480
|
+
const facet = facets.find((f) => f.key === c.facetKey);
|
|
2481
|
+
const facetName = facet?.name ?? c.facetKey;
|
|
2482
|
+
const values = c.anyOf.map((v) => facet?.values.find((x) => x.key === v)?.name ?? v);
|
|
2483
|
+
valueCount += values.length;
|
|
2484
|
+
if (values.length === 0) return `${facetName}: (none)`;
|
|
2485
|
+
if (values.length <= 3) return `${facetName}: ${values.join(", ")}`;
|
|
2486
|
+
return `${facetName}: ${values.slice(0, 2).join(", ")} +${values.length - 2}`;
|
|
2487
|
+
});
|
|
2488
|
+
return { text: parts.join(" \xB7 "), clauseCount: clauses.length, valueCount };
|
|
2489
|
+
}
|
|
2490
|
+
function RecordTargeting({ SL, collectionId, appId, ctx }) {
|
|
2491
|
+
const facets = useFacets(collectionId, void 0);
|
|
2492
|
+
const preview = useRulePreview({ SL, collectionId, appId, rule: ctx.facetRule ?? null });
|
|
2493
|
+
const clauses = ctx.facetRule?.all ?? [];
|
|
2494
|
+
const hasAnyClause = clauses.length > 0;
|
|
2495
|
+
const isInvalid = ctx.canSave === false;
|
|
2496
|
+
const shouldAutoOpen = !hasAnyClause || isInvalid;
|
|
2497
|
+
const [open, setOpen] = useState(shouldAutoOpen);
|
|
2498
|
+
useEffect(() => {
|
|
2499
|
+
if (shouldAutoOpen) setOpen(true);
|
|
2500
|
+
}, [shouldAutoOpen]);
|
|
2501
|
+
const summary = useMemo(() => summariseRule(clauses, facets), [clauses, facets]);
|
|
2502
|
+
if (!ctx.onFacetRuleChange) return null;
|
|
2503
|
+
const headerTone = isInvalid ? { color: "hsl(var(--ra-danger, 0 70% 45%))" } : { color: "hsl(var(--ra-muted-text))" };
|
|
2504
|
+
return /* @__PURE__ */ jsxs(
|
|
2505
|
+
"div",
|
|
2506
|
+
{
|
|
2507
|
+
className: "mb-4 rounded-lg border",
|
|
2508
|
+
style: {
|
|
2509
|
+
borderColor: isInvalid ? "hsl(var(--ra-danger, 0 70% 45%) / 0.5)" : "hsl(var(--ra-border))",
|
|
2510
|
+
background: "hsl(var(--ra-muted) / 0.3)"
|
|
2511
|
+
},
|
|
2512
|
+
children: [
|
|
2513
|
+
/* @__PURE__ */ jsxs(
|
|
2514
|
+
"button",
|
|
2515
|
+
{
|
|
2516
|
+
type: "button",
|
|
2517
|
+
onClick: () => setOpen((o) => !o),
|
|
2518
|
+
className: "w-full flex items-center gap-2 px-3 py-2 text-left hover:bg-[hsl(var(--ra-muted)/0.5)] rounded-lg transition-colors",
|
|
2519
|
+
"aria-expanded": open,
|
|
2520
|
+
children: [
|
|
2521
|
+
open ? /* @__PURE__ */ jsx(ChevronDown, { className: "w-3.5 h-3.5 shrink-0", style: headerTone }) : /* @__PURE__ */ jsx(ChevronRight, { className: "w-3.5 h-3.5 shrink-0", style: headerTone }),
|
|
2522
|
+
/* @__PURE__ */ jsx(Target, { className: "w-3.5 h-3.5 shrink-0", style: headerTone }),
|
|
2523
|
+
/* @__PURE__ */ jsx(
|
|
2524
|
+
"span",
|
|
2525
|
+
{
|
|
2526
|
+
className: "text-[11px] font-medium uppercase tracking-wide shrink-0",
|
|
2527
|
+
style: headerTone,
|
|
2528
|
+
children: "Targets"
|
|
2529
|
+
}
|
|
2530
|
+
),
|
|
2531
|
+
/* @__PURE__ */ jsx(
|
|
2532
|
+
"span",
|
|
2533
|
+
{
|
|
2534
|
+
className: "text-xs truncate flex-1 min-w-0",
|
|
2535
|
+
style: { color: "hsl(var(--ra-text))" },
|
|
2536
|
+
title: summary.text || void 0,
|
|
2537
|
+
children: hasAnyClause ? summary.text || `${summary.clauseCount} facet${summary.clauseCount === 1 ? "" : "s"}` : /* @__PURE__ */ jsx("span", { style: { color: "hsl(var(--ra-muted-text))", fontStyle: "italic" }, children: "No rule yet \u2014 pick a facet to begin" })
|
|
2538
|
+
}
|
|
2539
|
+
),
|
|
2540
|
+
isInvalid && hasAnyClause && /* @__PURE__ */ jsxs(
|
|
2541
|
+
"span",
|
|
2542
|
+
{
|
|
2543
|
+
className: "inline-flex items-center gap-1 text-[10px] uppercase tracking-wide shrink-0",
|
|
2544
|
+
style: { color: "hsl(var(--ra-danger, 0 70% 45%))" },
|
|
2545
|
+
children: [
|
|
2546
|
+
/* @__PURE__ */ jsx(AlertCircle, { className: "w-3 h-3" }),
|
|
2547
|
+
"Incomplete"
|
|
2548
|
+
]
|
|
2549
|
+
}
|
|
2550
|
+
),
|
|
2551
|
+
!open && hasAnyClause && !isInvalid && preview.totalMatches != null && /* @__PURE__ */ jsxs(
|
|
2552
|
+
"span",
|
|
2553
|
+
{
|
|
2554
|
+
className: "text-[10px] uppercase tracking-wide shrink-0 px-1.5 py-0.5 rounded-full",
|
|
2555
|
+
style: {
|
|
2556
|
+
color: "hsl(var(--ra-muted-text))",
|
|
2557
|
+
background: "hsl(var(--ra-muted) / 0.6)"
|
|
2558
|
+
},
|
|
2559
|
+
children: [
|
|
2560
|
+
preview.totalMatches,
|
|
2561
|
+
" match",
|
|
2562
|
+
preview.totalMatches === 1 ? "" : "es"
|
|
2563
|
+
]
|
|
2564
|
+
}
|
|
2565
|
+
),
|
|
2566
|
+
/* @__PURE__ */ jsx(Settings2, { className: "w-3.5 h-3.5 shrink-0", style: headerTone })
|
|
2567
|
+
]
|
|
2568
|
+
}
|
|
2569
|
+
),
|
|
2570
|
+
open && /* @__PURE__ */ jsx(
|
|
2571
|
+
"div",
|
|
2572
|
+
{
|
|
2573
|
+
className: "px-3 pb-3 pt-1 border-t",
|
|
2574
|
+
style: { borderColor: "hsl(var(--ra-border) / 0.6)" },
|
|
2575
|
+
children: /* @__PURE__ */ jsx(
|
|
2576
|
+
FacetRuleEditor,
|
|
2577
|
+
{
|
|
2578
|
+
value: ctx.facetRule ?? null,
|
|
2579
|
+
onChange: ctx.onFacetRuleChange,
|
|
2580
|
+
collectionId,
|
|
2581
|
+
preview,
|
|
2582
|
+
description: "Pick one or more facets. The record applies to every product whose facets match."
|
|
2583
|
+
}
|
|
2584
|
+
)
|
|
2585
|
+
}
|
|
2586
|
+
)
|
|
2587
|
+
]
|
|
2588
|
+
}
|
|
2589
|
+
);
|
|
2590
|
+
}
|
|
2268
2591
|
var TAB_META = {
|
|
2269
2592
|
product: { icon: Box, label: "Product" },
|
|
2270
2593
|
variant: { icon: Layers, label: "Variants" },
|
|
@@ -3409,13 +3732,18 @@ var downloadBlob = (blob, filename) => {
|
|
|
3409
3732
|
styleInject(':root {\n --ra-status-own: var(--ra-emerald, 142 71% 45%);\n --ra-status-shared: var(--ra-amber, 38 92% 50%);\n --ra-status-missing: var(--muted-foreground, 220 9% 46%);\n --ra-accent: var(--primary, 222 47% 11%);\n --ra-surface: var(--card, 0 0% 100%);\n --ra-border: var(--border, 220 13% 91%);\n --ra-text: var(--foreground, 222 47% 11%);\n --ra-muted: var(--muted, 220 14% 96%);\n --ra-muted-text: var(--muted-foreground, 220 9% 46%);\n --ra-radius: var(--radius, 0.625rem);\n --ra-dot-size: 0.5rem;\n --ra-page-bg: var(--background, 220 14% 98%);\n --ra-card-shadow: 0 1px 2px hsl(var(--ra-accent) / 0.04), 0 4px 12px hsl(var(--ra-accent) / 0.05);\n --ra-card-shadow-hover: 0 2px 4px hsl(var(--ra-accent) / 0.06), 0 8px 24px hsl(var(--ra-accent) / 0.08);\n --ra-row-hover: hsl(var(--ra-accent) / 0.05);\n --ra-row-active-bg: hsl(var(--ra-accent) / 0.10);\n --ra-row-active-bd: hsl(var(--ra-accent) / 0.45);\n --ra-focus-ring: hsl(var(--ra-accent) / 0.35);\n --ra-font-display: var(--font-display, var(--font-sans, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif));\n --ra-font-ui: var(--font-sans, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif);\n --ra-title-weight: 600;\n --ra-display-weight: 700;\n --ra-info: var(--ra-blue, 214 95% 55%);\n --ra-success: var(--ra-emerald, 142 71% 45%);\n --ra-warning: var(--ra-amber, 38 92% 50%);\n --ra-danger: var(--destructive, 0 72% 51%);\n}\n.ra-status-dot {\n display: inline-block;\n width: var(--ra-dot-size);\n height: var(--ra-dot-size);\n border-radius: 9999px;\n flex-shrink: 0;\n}\n.ra-status-own {\n background: hsl(var(--ra-status-own));\n}\n.ra-status-shared {\n background: hsl(var(--ra-status-shared));\n}\n.ra-status-missing {\n background: hsl(var(--ra-status-missing) / 0.4);\n border: 1px solid hsl(var(--ra-status-missing) / 0.6);\n}\n.ra-row-active {\n background: var(--ra-row-active-bg);\n border-color: var(--ra-row-active-bd) !important;\n}\n');
|
|
3410
3733
|
|
|
3411
3734
|
// src/components/RecordsAdmin/shell/shell.css
|
|
3412
|
-
styleInject(".ra-shell {\n color: hsl(var(--ra-text));\n background: hsl(var(--ra-page-bg));\n font-family: var(--ra-font-ui);\n}\n.ra-shell *,\n.ra-shell *::before,\n.ra-shell *::after {\n box-sizing: border-box;\n}\n.ra-shell .ra-card {\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n border-radius: var(--ra-radius);\n box-shadow: var(--ra-card-shadow);\n}\n.ra-shell .ra-card-hover {\n transition:\n box-shadow .18s ease,\n transform .18s ease,\n border-color .18s ease;\n}\n.ra-shell .ra-card-hover:hover {\n box-shadow: var(--ra-card-shadow-hover);\n}\n.ra-shell .ra-display {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n letter-spacing: -0.01em;\n}\n.ra-shell .ra-title {\n font-weight: var(--ra-title-weight);\n}\n.ra-shell :where(button, [role=button], input, select, textarea, a):focus-visible {\n outline: none;\n box-shadow: 0 0 0 3px var(--ra-focus-ring);\n border-radius: calc(var(--ra-radius) * 0.6);\n}\n.ra-shell .ra-header {\n position: relative;\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.65rem 0.9rem;\n border-radius: var(--ra-radius);\n border: 1px solid hsl(var(--ra-accent) / 0.12);\n background:\n linear-gradient(\n 135deg,\n hsl(var(--ra-accent) / 0.08),\n hsl(var(--ra-accent) / 0.02) 60%,\n hsl(var(--ra-surface)) 100%);\n box-shadow: var(--ra-card-shadow);\n}\n.ra-shell .ra-header__main {\n flex: 1;\n min-width: 0;\n display: flex;\n align-items: center;\n gap: 0.625rem;\n}\n.ra-shell .ra-header-aside {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n flex-shrink: 0;\n}\n.ra-shell .ra-header-icon {\n flex-shrink: 0;\n width: 2rem;\n height: 2rem;\n border-radius: calc(var(--ra-radius) * 0.9);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: hsl(var(--ra-accent) / 0.12);\n color: hsl(var(--ra-accent));\n border: 1px solid hsl(var(--ra-accent) / 0.18);\n}\n.ra-shell .ra-header-text {\n flex: 1;\n min-width: 0;\n}\n.ra-shell .ra-header-title {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n font-size: 1rem;\n line-height: 1.2;\n color: hsl(var(--ra-text));\n letter-spacing: -0.01em;\n margin: 0;\n}\n.ra-shell .ra-header-subtitle {\n font-size: 0.75rem;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.125rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-header-stats {\n display: flex;\n align-items: stretch;\n gap: 0.15rem;\n padding: 0.15rem 0.4rem;\n border-radius: calc(var(--ra-radius) * 0.75);\n background: hsl(var(--ra-surface) / 0.7);\n border: 1px solid hsl(var(--ra-border));\n}\n.ra-shell .ra-header-stats--titled {\n flex-direction: column;\n align-items: stretch;\n padding: 0.4rem 0.55rem;\n gap: 0.3rem;\n}\n.ra-shell .ra-header-stats .ra-stats-items {\n display: flex;\n align-items: stretch;\n gap: 0.15rem;\n}\n.ra-shell .ra-header-stats .ra-stats-heading {\n display: flex;\n align-items: center;\n gap: 0.35rem;\n color: hsl(var(--ra-muted-text));\n font-size: 0.65rem;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n}\n.ra-shell .ra-header-stats .ra-stats-heading-icon {\n display: inline-flex;\n align-items: center;\n color: hsl(var(--ra-text));\n opacity: 0.75;\n}\n.ra-shell .ra-header-stats .ra-stats-heading-icon > svg {\n width: 0.85rem;\n height: 0.85rem;\n}\n.ra-shell .ra-stat {\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 0.15rem 0.45rem;\n min-width: 2.5rem;\n}\n.ra-shell .ra-stat-value {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n font-size: 0.85rem;\n color: hsl(var(--ra-text));\n line-height: 1;\n}\n.ra-shell .ra-stat-label {\n font-size: 0.6rem;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.15rem;\n}\n.ra-shell .ra-stat-divider {\n width: 1px;\n background: hsl(var(--ra-border));\n margin: 0.25rem 0;\n}\n.ra-shell .ra-header-actions {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n.ra-shell .ra-tabs {\n display: flex;\n gap: 0.25rem;\n padding: 0.25rem;\n background: hsl(var(--ra-muted));\n border-radius: calc(var(--ra-radius) * 0.85);\n border: 1px solid hsl(var(--ra-border));\n}\n.ra-shell .ra-tab {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n padding: 0.4rem 0.7rem;\n border-radius: calc(var(--ra-radius) * 0.65);\n font-size: 0.78rem;\n font-weight: 500;\n color: hsl(var(--ra-muted-text));\n background: transparent;\n border: 0;\n cursor: pointer;\n transition:\n background .15s ease,\n color .15s ease,\n transform .15s ease;\n white-space: nowrap;\n}\n.ra-shell .ra-tab:hover {\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-tab[aria-selected=true] {\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-text));\n box-shadow: var(--ra-card-shadow);\n font-weight: var(--ra-title-weight);\n}\n.ra-shell .ra-tab[aria-selected=true] .ra-tab-icon {\n color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-tab[disabled] {\n opacity: .5;\n cursor: not-allowed;\n}\n.ra-shell .ra-tab-count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 1.25rem;\n padding: 0 0.35rem;\n height: 1.1rem;\n border-radius: 999px;\n background: hsl(var(--ra-accent) / 0.12);\n color: hsl(var(--ra-accent));\n font-size: 0.625rem;\n font-weight: 600;\n line-height: 1;\n}\n.ra-shell .ra-tab[aria-selected=false] .ra-tab-count {\n background: hsl(var(--ra-muted-text) / 0.15);\n color: hsl(var(--ra-muted-text));\n}\n.ra-shell[data-density=compact] .ra-row {\n padding-block: 0.4rem;\n}\n.ra-shell[data-density=compact] .ra-header {\n padding: 0.75rem 1rem;\n}\n.ra-shell[data-density=compact] .ra-header-icon {\n width: 2.25rem;\n height: 2.25rem;\n}\n.ra-shell .ra-row {\n display: flex;\n align-items: center;\n gap: 0.55rem;\n width: 100%;\n text-align: left;\n padding: 0.45rem 0.75rem;\n border-left: 3px solid transparent;\n background: transparent;\n border-bottom: 1px solid transparent;\n transition: background .12s ease, border-color .12s ease;\n cursor: pointer;\n color: hsl(var(--ra-text));\n font-family: inherit;\n}\n.ra-shell .ra-row + .ra-row {\n border-top: 1px solid hsl(var(--ra-border) / 0.6);\n}\n.ra-shell .ra-row:hover {\n background: var(--ra-row-hover);\n}\n.ra-shell .ra-row[data-selected=true] {\n background: var(--ra-row-active-bg);\n border-left-color: var(--ra-row-active-bd);\n}\n.ra-shell .ra-row-compact {\n padding-block: 0.3rem;\n}\n.ra-shell .ra-row-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.5rem;\n height: 1.5rem;\n border-radius: calc(var(--ra-radius) * 0.6);\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n flex-shrink: 0;\n}\n.ra-shell .ra-row[data-selected=true] .ra-row-icon {\n background: hsl(var(--ra-accent) / 0.15);\n color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-row-body {\n flex: 1;\n min-width: 0;\n}\n.ra-shell .ra-row-title {\n font-weight: var(--ra-title-weight);\n font-size: 0.8125rem;\n line-height: 1.2;\n color: hsl(var(--ra-text));\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-row-sub {\n font-size: 0.6875rem;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.05rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell[data-density=compact] .ra-row {\n padding-block: 0.3rem;\n gap: 0.45rem;\n}\n.ra-shell[data-density=compact] .ra-row-title {\n font-size: 0.78125rem;\n}\n.ra-shell .ra-row-actions {\n display: inline-flex;\n align-items: center;\n gap: 0.15rem;\n margin-left: auto;\n opacity: 0;\n transition: opacity .15s ease;\n}\n.ra-shell .ra-row:hover .ra-row-actions,\n.ra-shell .ra-row:focus-within .ra-row-actions {\n opacity: 1;\n}\n.ra-shell .ra-row-action {\n width: 1.6rem;\n height: 1.6rem;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border-radius: 999px;\n background: transparent;\n color: hsl(var(--ra-muted-text));\n border: 0;\n cursor: pointer;\n transition: background .15s ease, color .15s ease;\n}\n.ra-shell .ra-row-action:hover {\n background: hsl(var(--ra-accent) / 0.10);\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-row-action[data-tone=danger]:hover {\n background: hsl(var(--ra-danger) / 0.12);\n color: hsl(var(--ra-danger));\n}\n.ra-shell .ra-chip {\n display: inline-flex;\n align-items: center;\n gap: 0.3rem;\n padding: 0.15rem 0.5rem;\n border-radius: 999px;\n font-size: 0.6875rem;\n font-weight: 500;\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n border: 1px solid hsl(var(--ra-border));\n white-space: nowrap;\n max-width: 14rem;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-chip[data-tone=success] {\n background: hsl(var(--ra-success) / 0.12);\n color: hsl(var(--ra-success));\n border-color: hsl(var(--ra-success) / 0.30);\n}\n.ra-shell .ra-chip[data-tone=warning] {\n background: hsl(var(--ra-warning) / 0.14);\n color: hsl(var(--ra-warning));\n border-color: hsl(var(--ra-warning) / 0.35);\n}\n.ra-shell .ra-chip[data-tone=info] {\n background: hsl(var(--ra-info) / 0.10);\n color: hsl(var(--ra-info));\n border-color: hsl(var(--ra-info) / 0.30);\n}\n.ra-shell .ra-chip[data-tone=danger] {\n background: hsl(var(--ra-danger) / 0.10);\n color: hsl(var(--ra-danger));\n border-color: hsl(var(--ra-danger) / 0.30);\n}\n.ra-shell .ra-chip[data-tone=muted] {\n background: transparent;\n color: hsl(var(--ra-muted-text));\n border-style: dashed;\n}\n.ra-shell .ra-group {\n border-bottom: 1px solid hsl(var(--ra-border));\n}\n.ra-shell .ra-group:last-child {\n border-bottom: 0;\n}\n.ra-shell .ra-group-summary {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n width: 100%;\n padding: 0.5rem 0.85rem;\n background: hsl(var(--ra-muted) / 0.6);\n font-size: 0.7rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: hsl(var(--ra-muted-text));\n border: 0;\n cursor: pointer;\n transition: background .12s ease;\n}\n.ra-shell .ra-group-summary:hover {\n background: hsl(var(--ra-muted));\n}\n.ra-shell .ra-group-summary .ra-group-chevron {\n transition: transform .15s ease;\n}\n.ra-shell .ra-group[data-open=false] .ra-group-chevron {\n transform: rotate(-90deg);\n}\n.ra-shell .ra-group-name {\n flex: 1;\n text-align: left;\n}\n.ra-shell .ra-group-count {\n font-size: 0.65rem;\n font-weight: 600;\n color: hsl(var(--ra-muted-text));\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n border-radius: 999px;\n padding: 0.05rem 0.4rem;\n}\n.ra-shell .ra-group[data-open=false] .ra-group-body {\n display: none;\n}\n.ra-shell .ra-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n text-align: center;\n padding: 2.5rem 1.5rem;\n gap: 0.75rem;\n}\n.ra-shell .ra-empty-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 3.25rem;\n height: 3.25rem;\n border-radius: 999px;\n background: hsl(var(--ra-accent) / 0.08);\n color: hsl(var(--ra-accent));\n margin-bottom: 0.25rem;\n}\n.ra-shell .ra-empty-title {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n font-size: 1rem;\n color: hsl(var(--ra-text));\n margin: 0;\n letter-spacing: -0.01em;\n}\n.ra-shell .ra-empty-body {\n font-size: 0.8125rem;\n color: hsl(var(--ra-muted-text));\n max-width: 22rem;\n line-height: 1.45;\n}\n.ra-shell .ra-empty-actions {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n margin-top: 0.25rem;\n flex-wrap: wrap;\n justify-content: center;\n}\n.ra-shell .ra-btn {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n padding: 0.45rem 0.85rem;\n border-radius: calc(var(--ra-radius) * 0.7);\n font-size: 0.8125rem;\n font-weight: 500;\n border: 1px solid hsl(var(--ra-border));\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-text));\n cursor: pointer;\n transition:\n background .15s ease,\n border-color .15s ease,\n box-shadow .15s ease,\n transform .1s ease;\n}\n.ra-shell .ra-btn:hover {\n background: hsl(var(--ra-muted));\n box-shadow: var(--ra-card-shadow);\n}\n.ra-shell .ra-btn:active {\n transform: translateY(1px);\n}\n.ra-shell .ra-btn[data-variant=primary] {\n background: hsl(var(--ra-accent));\n color: hsl(var(--ra-surface));\n border-color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-btn[data-variant=primary]:hover {\n background: hsl(var(--ra-accent) / 0.92);\n}\n.ra-shell .ra-btn[data-variant=ghost] {\n background: transparent;\n border-color: transparent;\n color: hsl(var(--ra-muted-text));\n}\n.ra-shell .ra-btn[data-variant=ghost]:hover {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-btn[data-variant=danger] {\n color: hsl(var(--ra-danger));\n}\n.ra-shell .ra-btn[data-variant=danger]:hover {\n background: hsl(var(--ra-danger) / 0.10);\n border-color: hsl(var(--ra-danger) / 0.40);\n}\n.ra-shell .ra-intro {\n position: relative;\n display: flex;\n gap: 0.85rem;\n padding: 0.9rem 1rem;\n border-radius: var(--ra-radius);\n border: 1px solid hsl(var(--ra-info) / 0.30);\n background: hsl(var(--ra-info) / 0.08);\n margin-bottom: 1rem;\n}\n.ra-shell .ra-intro[data-tone=success] {\n border-color: hsl(var(--ra-success) / 0.30);\n background: hsl(var(--ra-success) / 0.08);\n}\n.ra-shell .ra-intro[data-tone=warning] {\n border-color: hsl(var(--ra-warning) / 0.35);\n background: hsl(var(--ra-warning) / 0.10);\n}\n.ra-shell .ra-intro-icon {\n flex-shrink: 0;\n width: 2rem;\n height: 2rem;\n border-radius: 999px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: hsl(var(--ra-info) / 0.18);\n color: hsl(var(--ra-info));\n}\n.ra-shell .ra-intro[data-tone=success] .ra-intro-icon {\n background: hsl(var(--ra-success) / 0.18);\n color: hsl(var(--ra-success));\n}\n.ra-shell .ra-intro[data-tone=warning] .ra-intro-icon {\n background: hsl(var(--ra-warning) / 0.20);\n color: hsl(var(--ra-warning));\n}\n.ra-shell .ra-intro-body {\n flex: 1;\n min-width: 0;\n}\n.ra-shell .ra-intro-title {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-title-weight);\n font-size: 0.875rem;\n color: hsl(var(--ra-text));\n margin: 0 0 0.2rem 0;\n}\n.ra-shell .ra-intro-text {\n font-size: 0.8125rem;\n color: hsl(var(--ra-text) / 0.85);\n line-height: 1.45;\n}\n.ra-shell .ra-intro-dismiss {\n position: absolute;\n top: 0.5rem;\n right: 0.5rem;\n width: 1.6rem;\n height: 1.6rem;\n border-radius: 999px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: 0;\n color: hsl(var(--ra-muted-text));\n cursor: pointer;\n}\n.ra-shell .ra-intro-dismiss:hover {\n background: hsl(var(--ra-text) / 0.06);\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-bulk-menu {\n min-width: 12rem;\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n border-radius: calc(var(--ra-radius) * 0.85);\n box-shadow: var(--ra-card-shadow-hover);\n padding: 0.3rem;\n z-index: 60;\n}\n.ra-shell .ra-bulk-item {\n display: flex;\n align-items: center;\n gap: 0.55rem;\n width: 100%;\n padding: 0.45rem 0.6rem;\n border-radius: calc(var(--ra-radius) * 0.6);\n font-size: 0.8125rem;\n color: hsl(var(--ra-text));\n background: transparent;\n border: 0;\n cursor: pointer;\n text-align: left;\n transition: background .12s ease, color .12s ease;\n}\n.ra-shell .ra-bulk-item:hover {\n background: hsl(var(--ra-muted));\n}\n.ra-shell .ra-bulk-item[data-tone=danger] {\n color: hsl(var(--ra-danger));\n}\n.ra-shell .ra-bulk-item[data-tone=danger]:hover {\n background: hsl(var(--ra-danger) / 0.10);\n}\n.ra-shell .ra-bulk-divider {\n height: 1px;\n background: hsl(var(--ra-border));\n margin: 0.25rem 0;\n}\n.ra-shell .ra-preview-rail {\n background: hsl(var(--ra-surface));\n border-left: 1px solid hsl(var(--ra-border));\n box-shadow: -4px 0 16px hsl(var(--ra-accent) / 0.04);\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n}\n.ra-shell .ra-preview-rail-header {\n position: sticky;\n top: 0;\n z-index: 1;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.75rem 1rem;\n background:\n linear-gradient(\n 180deg,\n hsl(var(--ra-surface)) 0%,\n hsl(var(--ra-surface) / 0.92) 100%);\n border-bottom: 1px solid hsl(var(--ra-border));\n backdrop-filter: blur(6px);\n}\n.ra-shell .ra-preview-rail-title {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n font-size: 0.7rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: hsl(var(--ra-muted-text));\n}\n.ra-shell .ra-preview-rail-body {\n flex: 1;\n overflow-y: auto;\n padding: 1rem;\n}\n.ra-confirm-root {\n position: fixed;\n inset: 0;\n z-index: 2147483000;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 1rem;\n}\n.ra-confirm-root .ra-confirm-backdrop {\n position: absolute;\n inset: 0;\n background: hsl(0 0% 0% / 0.45);\n backdrop-filter: blur(2px);\n animation: ra-confirm-fade .12s ease-out;\n}\n.ra-confirm-root .ra-confirm-card {\n position: relative;\n width: min(440px, 100%);\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-text));\n border: 1px solid hsl(var(--ra-border));\n border-radius: var(--ra-radius);\n box-shadow: 0 1px 2px hsl(0 0% 0% / 0.08), 0 24px 48px -12px hsl(0 0% 0% / 0.32);\n padding: 1.25rem;\n animation: ra-confirm-pop .14s ease-out;\n}\n.ra-confirm-root .ra-confirm-header {\n display: flex;\n align-items: center;\n gap: 0.6rem;\n margin-bottom: 0.5rem;\n}\n.ra-confirm-root .ra-confirm-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.75rem;\n height: 1.75rem;\n border-radius: 999px;\n background: hsl(var(--ra-warning, 38 92% 50%) / 0.12);\n color: hsl(var(--ra-warning, 38 92% 50%));\n}\n.ra-confirm-root .ra-confirm-title {\n font-family: var(--ra-font-display);\n font-weight: 600;\n font-size: 1rem;\n margin: 0;\n}\n.ra-confirm-root .ra-confirm-body {\n font-size: 0.875rem;\n color: hsl(var(--ra-muted-text));\n margin: 0 0 1.1rem;\n line-height: 1.45;\n}\n.ra-confirm-root .ra-confirm-actions {\n display: flex;\n justify-content: flex-end;\n gap: 0.5rem;\n flex-wrap: wrap;\n}\n.ra-confirm-root .ra-confirm-btn {\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n border: 1px solid transparent;\n border-radius: calc(var(--ra-radius) - 2px);\n padding: 0.45rem 0.85rem;\n font-size: 0.8125rem;\n font-weight: 500;\n cursor: pointer;\n transition:\n background-color .12s ease,\n border-color .12s ease,\n color .12s ease;\n}\n.ra-confirm-root .ra-confirm-btn:focus-visible {\n outline: none;\n box-shadow: 0 0 0 3px var(--ra-focus-ring);\n}\n.ra-confirm-root .ra-confirm-btn-ghost {\n background: transparent;\n color: hsl(var(--ra-muted-text));\n border-color: hsl(var(--ra-border));\n}\n.ra-confirm-root .ra-confirm-btn-ghost:hover {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-confirm-root .ra-confirm-btn-danger {\n background: transparent;\n color: hsl(var(--ra-danger, 0 72% 51%));\n border-color: hsl(var(--ra-danger, 0 72% 51%) / 0.45);\n}\n.ra-confirm-root .ra-confirm-btn-danger:hover {\n background: hsl(var(--ra-danger, 0 72% 51%) / 0.08);\n border-color: hsl(var(--ra-danger, 0 72% 51%));\n}\n.ra-confirm-root .ra-confirm-btn-primary {\n background: hsl(var(--ra-accent));\n color: hsl(var(--ra-accent-fg, 0 0% 100%));\n border-color: hsl(var(--ra-accent));\n}\n.ra-confirm-root .ra-confirm-btn-primary:hover {\n filter: brightness(0.95);\n}\n@keyframes ra-confirm-fade {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n@keyframes ra-confirm-pop {\n from {\n opacity: 0;\n transform: translateY(4px) scale(.98);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n}\n.ra-shell .ra-unsaved-banner {\n display: flex;\n align-items: center;\n gap: 0.6rem;\n padding: 0.5rem 0.75rem;\n border: 1px solid hsl(var(--ra-warning, 38 92% 50%) / 0.35);\n background: hsl(var(--ra-warning, 38 92% 50%) / 0.08);\n border-radius: var(--ra-radius);\n font-size: 0.8125rem;\n color: hsl(var(--ra-text));\n animation: ra-unsaved-slide .14s ease-out;\n}\n.ra-shell .ra-unsaved-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n color: hsl(var(--ra-warning, 38 92% 50%));\n flex-shrink: 0;\n}\n.ra-shell .ra-unsaved-text {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.ra-shell .ra-unsaved-context {\n color: hsl(var(--ra-muted-text));\n font-weight: 400;\n}\n.ra-shell .ra-unsaved-error {\n color: hsl(var(--ra-danger, 0 72% 51%));\n font-size: 0.75rem;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n font-weight: 500;\n}\n.ra-shell .ra-unsaved-actions {\n display: inline-flex;\n gap: 0.4rem;\n flex-shrink: 0;\n}\n.ra-shell .ra-unsaved-btn {\n display: inline-flex;\n align-items: center;\n gap: 0.3rem;\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n border: 1px solid transparent;\n border-radius: calc(var(--ra-radius) - 2px);\n padding: 0.3rem 0.6rem;\n font-size: 0.75rem;\n font-weight: 500;\n cursor: pointer;\n transition:\n background-color .12s ease,\n border-color .12s ease,\n color .12s ease,\n opacity .12s ease;\n}\n.ra-shell .ra-unsaved-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.ra-shell .ra-unsaved-btn:focus-visible {\n outline: none;\n box-shadow: 0 0 0 3px var(--ra-focus-ring);\n}\n.ra-shell .ra-unsaved-btn-ghost {\n background: transparent;\n color: hsl(var(--ra-muted-text));\n border-color: hsl(var(--ra-border));\n}\n.ra-shell .ra-unsaved-btn-ghost:hover:not(:disabled) {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-unsaved-btn-primary {\n background: hsl(var(--ra-accent));\n color: hsl(var(--ra-accent-fg, 0 0% 100%));\n border-color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-unsaved-btn-primary:hover:not(:disabled) {\n filter: brightness(0.95);\n}\n@keyframes ra-unsaved-slide {\n from {\n opacity: 0;\n transform: translateY(-3px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n.ra-shell .ra-clipboard-toast {\n position: fixed;\n bottom: 1.25rem;\n left: 50%;\n transform: translateX(-50%);\n z-index: 90;\n display: inline-flex;\n align-items: center;\n gap: 0.5rem;\n max-width: min(28rem, calc(100vw - 2rem));\n padding: 0.55rem 0.85rem;\n border-radius: 999px;\n background: hsl(var(--ra-text));\n color: hsl(var(--ra-surface));\n font-size: 0.75rem;\n line-height: 1;\n box-shadow: 0 8px 24px -10px hsl(0 0% 0% / 0.45);\n animation: ra-clipboard-pop 0.18s ease-out both;\n pointer-events: none;\n}\n@keyframes ra-clipboard-pop {\n from {\n opacity: 0;\n transform: translate(-50%, 6px);\n }\n to {\n opacity: 1;\n transform: translate(-50%, 0);\n }\n}\n.ra-shell .ra-row-menu-wrap {\n display: inline-flex;\n align-items: center;\n margin-left: 0.25rem;\n}\n.ra-shell .ra-row-menu-trigger {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.5rem;\n height: 1.5rem;\n border-radius: 0.35rem;\n background: transparent;\n color: hsl(var(--ra-muted-text));\n opacity: 0;\n transition:\n opacity .15s ease,\n background .15s ease,\n color .15s ease;\n border: 1px solid transparent;\n}\n.ra-shell .ra-row:hover .ra-row-menu-trigger,\n.ra-shell .ra-card-hover:hover .ra-row-menu-trigger,\n.ra-shell .ra-row-menu-trigger:focus-visible,\n.ra-shell .ra-row-menu-trigger[aria-expanded=true] {\n opacity: 1;\n}\n.ra-shell .ra-row-menu-trigger:hover {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-row-menu {\n position: absolute;\n right: 0;\n top: calc(100% + 4px);\n z-index: 50;\n min-width: 11rem;\n padding: 0.25rem;\n border-radius: 0.5rem;\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n box-shadow: 0 12px 28px -10px hsl(0 0% 0% / 0.25);\n display: flex;\n flex-direction: column;\n gap: 0.125rem;\n}\n.ra-shell .ra-row-menu-item {\n display: inline-flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.4rem 0.55rem;\n border-radius: 0.35rem;\n font-size: 0.75rem;\n color: hsl(var(--ra-text));\n background: transparent;\n border: 0;\n text-align: left;\n width: 100%;\n cursor: pointer;\n}\n.ra-shell .ra-row-menu-item:hover:not(:disabled) {\n background: hsl(var(--ra-muted));\n}\n.ra-shell .ra-row-menu-item:disabled {\n opacity: 0.45;\n cursor: not-allowed;\n}\n.ra-shell .ra-item-list {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n}\n.ra-shell .ra-item-list-body {\n flex: 1;\n min-height: 0;\n overflow: auto;\n padding: 1rem 1.25rem 1.5rem;\n}\n.ra-shell .ra-item-toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.75rem;\n padding: 0.75rem 1.25rem;\n border-bottom: 1px solid hsl(var(--ra-border));\n background: hsl(var(--ra-surface));\n}\n.ra-shell .ra-item-toolbar-title {\n display: flex;\n align-items: baseline;\n gap: 0.5rem;\n min-width: 0;\n}\n.ra-shell .ra-item-toolbar-count {\n font-size: 0.7rem;\n font-weight: 600;\n color: hsl(var(--ra-muted-text));\n background: hsl(var(--ra-muted));\n border: 1px solid hsl(var(--ra-border));\n border-radius: 999px;\n padding: 0.05rem 0.45rem;\n}\n.ra-shell .ra-item-toolbar-actions {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n flex-shrink: 0;\n}\n.ra-shell .ra-item-table-wrap {\n border: 1px solid hsl(var(--ra-border));\n border-radius: var(--ra-radius);\n background: hsl(var(--ra-surface));\n overflow: hidden;\n box-shadow: var(--ra-card-shadow);\n}\n.ra-shell .ra-item-table {\n width: 100%;\n border-collapse: collapse;\n font-size: 0.85rem;\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-item-table thead th {\n text-align: left;\n font-size: 0.7rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: hsl(var(--ra-muted-text));\n padding: 0.65rem 0.85rem;\n background: hsl(var(--ra-muted) / 0.55);\n border-bottom: 1px solid hsl(var(--ra-border));\n}\n.ra-shell .ra-item-table tbody td {\n padding: 0.65rem 0.85rem;\n border-bottom: 1px solid hsl(var(--ra-border) / 0.7);\n vertical-align: middle;\n}\n.ra-shell .ra-item-table tbody tr:last-child td {\n border-bottom: 0;\n}\n.ra-shell .ra-item-row {\n cursor: pointer;\n transition: background .12s ease;\n}\n.ra-shell .ra-item-row:hover {\n background: var(--ra-row-hover);\n}\n.ra-shell .ra-item-row[data-selected=true] {\n background: var(--ra-row-active-bg);\n}\n.ra-shell .ra-item-row-title {\n font-weight: var(--ra-title-weight);\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-item-row-sub {\n font-size: 0.75rem;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.15rem;\n}\n.ra-shell .ra-item-row-meta {\n font-size: 0.78rem;\n color: hsl(var(--ra-muted-text));\n}\n.ra-shell .ra-item-row-actions {\n text-align: right;\n white-space: nowrap;\n}\n.ra-shell .ra-item-row-actions .ra-row-action + .ra-row-action {\n margin-left: 0.15rem;\n}\n.ra-shell .ra-item-cards {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));\n gap: 0.85rem;\n}\n.ra-shell .ra-item-gallery {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));\n gap: 1rem;\n}\n.ra-shell .ra-item-card {\n position: relative;\n display: flex;\n flex-direction: column;\n align-items: stretch;\n text-align: left;\n padding: 0;\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n border-radius: var(--ra-radius);\n overflow: hidden;\n cursor: pointer;\n transition:\n box-shadow .18s ease,\n transform .12s ease,\n border-color .15s ease;\n box-shadow: var(--ra-card-shadow);\n font-family: inherit;\n color: inherit;\n}\n.ra-shell .ra-item-card:hover {\n box-shadow: var(--ra-card-shadow-hover);\n border-color: hsl(var(--ra-accent) / 0.30);\n}\n.ra-shell .ra-item-card[data-selected=true] {\n border-color: hsl(var(--ra-accent) / 0.55);\n box-shadow: var(--ra-card-shadow-hover);\n}\n.ra-shell .ra-item-card-thumb {\n width: 100%;\n aspect-ratio: 1 / 1;\n background:\n linear-gradient(\n 135deg,\n hsl(var(--ra-accent) / 0.12),\n hsl(var(--ra-accent) / 0.04));\n display: flex;\n align-items: center;\n justify-content: center;\n color: hsl(var(--ra-accent));\n overflow: hidden;\n}\n.ra-shell .ra-item-card-thumb--gallery {\n aspect-ratio: 16 / 9;\n}\n.ra-shell .ra-item-card-thumb img {\n width: 100%;\n height: 100%;\n -o-object-fit: cover;\n object-fit: cover;\n}\n.ra-shell .ra-item-card-initials {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n font-size: 1.5rem;\n letter-spacing: 0.02em;\n}\n.ra-shell .ra-item-card-body {\n padding: 0.65rem 0.8rem 0.85rem;\n min-width: 0;\n}\n.ra-shell .ra-item-card-title {\n font-weight: var(--ra-title-weight);\n font-size: 0.85rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-item-card-sub {\n font-size: 0.75rem;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.15rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-item-card-delete {\n position: absolute;\n top: 0.4rem;\n right: 0.4rem;\n background: hsl(var(--ra-surface) / 0.85);\n backdrop-filter: blur(4px);\n opacity: 0;\n transition: opacity .15s ease;\n}\n.ra-shell .ra-item-card:hover .ra-item-card-delete,\n.ra-shell .ra-item-card:focus-within .ra-item-card-delete {\n opacity: 1;\n}\n.ra-shell .ra-item-nav {\n display: flex;\n align-items: center;\n gap: 0.6rem;\n padding: 0.5rem 1.25rem;\n border-bottom: 1px solid hsl(var(--ra-border));\n background: hsl(var(--ra-surface));\n}\n.ra-shell .ra-item-nav-position {\n font-size: 0.72rem;\n color: hsl(var(--ra-muted-text));\n font-variant-numeric: tabular-nums;\n}\n.ra-shell .ra-item-nav-arrows {\n margin-left: auto;\n display: inline-flex;\n align-items: center;\n gap: 0.15rem;\n}\n.ra-shell .ra-item-nav-arrows .ra-row-action[disabled] {\n opacity: 0.35;\n cursor: not-allowed;\n}\n.ra-shell .ra-sibling-rail {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n}\n.ra-shell .ra-sibling-back {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n padding: 0.6rem 0.85rem;\n font-size: 0.75rem;\n font-weight: 500;\n color: hsl(var(--ra-muted-text));\n background: hsl(var(--ra-muted) / 0.5);\n border: 0;\n border-bottom: 1px solid hsl(var(--ra-border));\n cursor: pointer;\n text-align: left;\n transition: background .12s ease, color .12s ease;\n}\n.ra-shell .ra-sibling-back:hover {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-sibling-heading {\n padding: 0.6rem 0.85rem 0.4rem;\n font-size: 0.65rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: hsl(var(--ra-muted-text));\n}\n.ra-shell .ra-sibling-body {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n}\n.ra-shell .ra-sibling-list {\n list-style: none;\n margin: 0;\n padding: 0;\n}\n.ra-shell .ra-status-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n border-radius: 9999px;\n}\n.ra-shell .ra-status-icon > svg {\n width: 100%;\n height: 100%;\n display: block;\n}\n.ra-shell .ra-status-icon--own {\n color: hsl(var(--ra-status-own));\n}\n.ra-shell .ra-status-icon--shared {\n color: hsl(var(--ra-status-shared));\n}\n.ra-shell .ra-status-icon--missing {\n color: hsl(var(--ra-status-missing) / 0.7);\n}\n.ra-shell .ra-row-status {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.5rem;\n height: 1.5rem;\n flex-shrink: 0;\n}\n.ra-shell .ra-row-scope {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.25rem;\n height: 1.25rem;\n border-radius: calc(var(--ra-radius) * 0.5);\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n flex-shrink: 0;\n margin-left: auto;\n opacity: 0.55;\n transition:\n opacity .12s ease,\n color .12s ease,\n background .12s ease;\n}\n.ra-shell .ra-row:hover .ra-row-scope {\n opacity: 0.85;\n}\n.ra-shell .ra-row[data-selected=true] .ra-row-scope {\n opacity: 1;\n background: hsl(var(--ra-accent) / 0.12);\n color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-row[data-tone=own] .ra-row-sub {\n color: hsl(var(--ra-status-own));\n}\n.ra-shell .ra-row[data-tone=shared] .ra-row-sub {\n color: hsl(var(--ra-status-shared));\n}\n.ra-shell .ra-row[data-selected=true] {\n background:\n linear-gradient(\n 90deg,\n hsl(var(--ra-accent) / 0.10) 0%,\n hsl(var(--ra-accent) / 0.04) 100%);\n border-left-width: 3px;\n border-left-color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-dirty-pip {\n display: inline-block;\n width: 0.45rem;\n height: 0.45rem;\n border-radius: 9999px;\n background: hsl(var(--ra-warning));\n box-shadow: 0 0 0 2px hsl(var(--ra-warning) / 0.18);\n flex-shrink: 0;\n}\n.ra-shell .ra-group-summary {\n background: transparent;\n}\n.ra-shell {\n position: relative;\n}\n.ra-shell .ra-help-float {\n position: absolute;\n top: 0.65rem;\n right: 0.85rem;\n z-index: 5;\n display: inline-flex;\n align-items: center;\n gap: 0.35rem;\n padding: 0.3rem 0.6rem;\n font-size: 0.7rem;\n font-weight: 500;\n color: hsl(var(--ra-muted-text));\n background: hsl(var(--ra-surface) / 0.85);\n backdrop-filter: blur(6px);\n border: 1px solid hsl(var(--ra-border));\n border-radius: 999px;\n cursor: pointer;\n transition:\n color .12s ease,\n background .12s ease,\n border-color .12s ease;\n}\n.ra-shell .ra-help-float:hover {\n color: hsl(var(--ra-accent));\n border-color: hsl(var(--ra-accent) / 0.4);\n background: hsl(var(--ra-surface));\n}\n.ra-shell .ra-help-float svg {\n width: 0.85rem;\n height: 0.85rem;\n}\n.ra-shell .ra-preview-reopen {\n position: absolute;\n top: 50%;\n right: 0;\n transform: translateY(-50%);\n z-index: 4;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.4rem;\n padding: 0.65rem 0.45rem;\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-muted-text));\n border: 1px solid hsl(var(--ra-border));\n border-right: 0;\n border-radius: calc(var(--ra-radius) * 0.85) 0 0 calc(var(--ra-radius) * 0.85);\n box-shadow: var(--ra-card-shadow);\n cursor: pointer;\n transition:\n color .12s ease,\n background .12s ease,\n padding-right .15s ease;\n writing-mode: vertical-rl;\n font-size: 0.7rem;\n font-weight: 600;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n}\n.ra-shell .ra-preview-reopen:hover {\n color: hsl(var(--ra-accent));\n background: hsl(var(--ra-accent) / 0.04);\n padding-right: 0.6rem;\n}\n.ra-shell .ra-preview-reopen svg {\n width: 0.85rem;\n height: 0.85rem;\n writing-mode: horizontal-tb;\n}\n");
|
|
3735
|
+
styleInject(".ra-shell {\n color: hsl(var(--ra-text));\n background: hsl(var(--ra-page-bg));\n font-family: var(--ra-font-ui);\n}\n.ra-shell *,\n.ra-shell *::before,\n.ra-shell *::after {\n box-sizing: border-box;\n}\n.ra-shell .ra-card {\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n border-radius: var(--ra-radius);\n box-shadow: var(--ra-card-shadow);\n}\n.ra-shell .ra-card-hover {\n transition:\n box-shadow .18s ease,\n transform .18s ease,\n border-color .18s ease;\n}\n.ra-shell .ra-card-hover:hover {\n box-shadow: var(--ra-card-shadow-hover);\n}\n.ra-shell .ra-display {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n letter-spacing: -0.01em;\n}\n.ra-shell .ra-title {\n font-weight: var(--ra-title-weight);\n}\n.ra-shell :where(button, [role=button], input, select, textarea, a):focus-visible {\n outline: none;\n box-shadow: 0 0 0 3px var(--ra-focus-ring);\n border-radius: calc(var(--ra-radius) * 0.6);\n}\n.ra-shell .ra-header {\n position: relative;\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.65rem 0.9rem;\n border-radius: var(--ra-radius);\n border: 1px solid hsl(var(--ra-accent) / 0.12);\n background:\n linear-gradient(\n 135deg,\n hsl(var(--ra-accent) / 0.08),\n hsl(var(--ra-accent) / 0.02) 60%,\n hsl(var(--ra-surface)) 100%);\n box-shadow: var(--ra-card-shadow);\n}\n.ra-shell .ra-header__main {\n flex: 1;\n min-width: 0;\n display: flex;\n align-items: center;\n gap: 0.625rem;\n}\n.ra-shell .ra-header-aside {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n flex-shrink: 0;\n}\n.ra-shell .ra-header-icon {\n flex-shrink: 0;\n width: 2rem;\n height: 2rem;\n border-radius: calc(var(--ra-radius) * 0.9);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: hsl(var(--ra-accent) / 0.12);\n color: hsl(var(--ra-accent));\n border: 1px solid hsl(var(--ra-accent) / 0.18);\n}\n.ra-shell .ra-header-text {\n flex: 1;\n min-width: 0;\n}\n.ra-shell .ra-header-title {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n font-size: 1rem;\n line-height: 1.2;\n color: hsl(var(--ra-text));\n letter-spacing: -0.01em;\n margin: 0;\n}\n.ra-shell .ra-header-subtitle {\n font-size: 0.75rem;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.125rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-header-stats {\n display: flex;\n align-items: stretch;\n gap: 0.15rem;\n padding: 0.15rem 0.4rem;\n border-radius: calc(var(--ra-radius) * 0.75);\n background: hsl(var(--ra-surface) / 0.7);\n border: 1px solid hsl(var(--ra-border));\n}\n.ra-shell .ra-header-stats--titled {\n flex-direction: column;\n align-items: stretch;\n padding: 0.4rem 0.55rem;\n gap: 0.3rem;\n}\n.ra-shell .ra-header-stats .ra-stats-items {\n display: flex;\n align-items: stretch;\n gap: 0.15rem;\n}\n.ra-shell .ra-header-stats .ra-stats-heading {\n display: flex;\n align-items: center;\n gap: 0.35rem;\n color: hsl(var(--ra-muted-text));\n font-size: 0.65rem;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n}\n.ra-shell .ra-header-stats .ra-stats-heading-icon {\n display: inline-flex;\n align-items: center;\n color: hsl(var(--ra-text));\n opacity: 0.75;\n}\n.ra-shell .ra-header-stats .ra-stats-heading-icon > svg {\n width: 0.85rem;\n height: 0.85rem;\n}\n.ra-shell .ra-stat {\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 0.15rem 0.45rem;\n min-width: 2.5rem;\n}\n.ra-shell .ra-stat-value {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n font-size: 0.85rem;\n color: hsl(var(--ra-text));\n line-height: 1;\n}\n.ra-shell .ra-stat-label {\n font-size: 0.6rem;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.15rem;\n}\n.ra-shell .ra-stat-divider {\n width: 1px;\n background: hsl(var(--ra-border));\n margin: 0.25rem 0;\n}\n.ra-shell .ra-header-actions {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n.ra-shell .ra-tabs {\n display: flex;\n gap: 0.25rem;\n padding: 0.25rem;\n background: hsl(var(--ra-muted));\n border-radius: calc(var(--ra-radius) * 0.85);\n border: 1px solid hsl(var(--ra-border));\n}\n.ra-shell .ra-tab {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n padding: 0.4rem 0.7rem;\n border-radius: calc(var(--ra-radius) * 0.65);\n font-size: 0.78rem;\n font-weight: 500;\n color: hsl(var(--ra-muted-text));\n background: transparent;\n border: 0;\n cursor: pointer;\n transition:\n background .15s ease,\n color .15s ease,\n transform .15s ease;\n white-space: nowrap;\n}\n.ra-shell .ra-tab:hover {\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-tab[aria-selected=true] {\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-text));\n box-shadow: var(--ra-card-shadow);\n font-weight: var(--ra-title-weight);\n}\n.ra-shell .ra-tab[aria-selected=true] .ra-tab-icon {\n color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-tab[disabled] {\n opacity: .5;\n cursor: not-allowed;\n}\n.ra-shell .ra-tab-count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 1.25rem;\n padding: 0 0.35rem;\n height: 1.1rem;\n border-radius: 999px;\n background: hsl(var(--ra-accent) / 0.12);\n color: hsl(var(--ra-accent));\n font-size: 0.625rem;\n font-weight: 600;\n line-height: 1;\n}\n.ra-shell .ra-tab[aria-selected=false] .ra-tab-count {\n background: hsl(var(--ra-muted-text) / 0.15);\n color: hsl(var(--ra-muted-text));\n}\n.ra-shell[data-density=compact] .ra-row {\n padding-block: 0.4rem;\n}\n.ra-shell[data-density=compact] .ra-header {\n padding: 0.75rem 1rem;\n}\n.ra-shell[data-density=compact] .ra-header-icon {\n width: 2.25rem;\n height: 2.25rem;\n}\n.ra-shell .ra-row {\n display: flex;\n align-items: center;\n gap: 0.55rem;\n width: 100%;\n text-align: left;\n padding: 0.45rem 0.75rem;\n border-left: 3px solid transparent;\n background: transparent;\n border-bottom: 1px solid transparent;\n transition: background .12s ease, border-color .12s ease;\n cursor: pointer;\n color: hsl(var(--ra-text));\n font-family: inherit;\n}\n.ra-shell .ra-row + .ra-row {\n border-top: 1px solid hsl(var(--ra-border) / 0.6);\n}\n.ra-shell .ra-row:hover {\n background: var(--ra-row-hover);\n}\n.ra-shell .ra-row[data-selected=true] {\n background: var(--ra-row-active-bg);\n border-left-color: var(--ra-row-active-bd);\n}\n.ra-shell .ra-row-compact {\n padding-block: 0.3rem;\n}\n.ra-shell .ra-row-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.5rem;\n height: 1.5rem;\n border-radius: calc(var(--ra-radius) * 0.6);\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n flex-shrink: 0;\n}\n.ra-shell .ra-row[data-selected=true] .ra-row-icon {\n background: hsl(var(--ra-accent) / 0.15);\n color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-row-body {\n flex: 1;\n min-width: 0;\n}\n.ra-shell .ra-row-title {\n font-weight: var(--ra-title-weight);\n font-size: 0.8125rem;\n line-height: 1.2;\n color: hsl(var(--ra-text));\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-row-sub {\n font-size: 0.6875rem;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.05rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-row-rule-chips {\n display: flex;\n flex-wrap: wrap;\n gap: 0.2rem;\n margin-top: 0.2rem;\n}\n.ra-shell .ra-rule-chip {\n display: inline-flex;\n align-items: center;\n max-width: 100%;\n padding: 0.05rem 0.4rem;\n border-radius: 999px;\n font-size: 0.625rem;\n font-weight: 500;\n line-height: 1.4;\n background: hsl(var(--ra-accent) / 0.10);\n color: hsl(var(--ra-accent));\n border: 1px solid hsl(var(--ra-accent) / 0.20);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-rule-chip-more {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n border-color: hsl(var(--ra-border));\n}\n.ra-shell[data-density=compact] .ra-row-rule-chips {\n margin-top: 0.15rem;\n gap: 0.15rem;\n}\n.ra-shell[data-density=compact] .ra-rule-chip {\n font-size: 0.6rem;\n padding: 0.02rem 0.35rem;\n}\n.ra-shell .ra-rule-filters {\n display: flex;\n flex-direction: column;\n gap: 0.3rem;\n}\n.ra-shell .ra-rule-filters-row {\n display: flex;\n flex-wrap: wrap;\n gap: 0.25rem;\n}\n.ra-shell .ra-rule-filter-chip {\n display: inline-flex;\n align-items: center;\n gap: 0.3rem;\n padding: 0.15rem 0.5rem;\n border-radius: 999px;\n font-size: 0.65rem;\n font-weight: 500;\n line-height: 1.4;\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n border: 1px solid hsl(var(--ra-border));\n cursor: pointer;\n transition:\n background .12s ease,\n color .12s ease,\n border-color .12s ease;\n max-width: 100%;\n}\n.ra-shell .ra-rule-filter-chip:hover {\n background: hsl(var(--ra-accent) / 0.10);\n color: hsl(var(--ra-text));\n border-color: hsl(var(--ra-accent) / 0.25);\n}\n.ra-shell .ra-rule-filter-chip[data-active=true] {\n background: hsl(var(--ra-accent) / 0.15);\n color: hsl(var(--ra-accent));\n border-color: hsl(var(--ra-accent) / 0.40);\n}\n.ra-shell .ra-rule-filter-chip[data-tone=complexity][data-active=true] {\n background: hsl(var(--ra-info) / 0.15);\n color: hsl(var(--ra-info));\n border-color: hsl(var(--ra-info) / 0.40);\n}\n.ra-shell .ra-rule-filter-chip-label {\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 9rem;\n}\n.ra-shell .ra-rule-filter-chip-count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 1.1rem;\n height: 1rem;\n padding: 0 0.3rem;\n border-radius: 999px;\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-muted-text));\n font-size: 0.6rem;\n font-weight: 600;\n}\n.ra-shell .ra-rule-filter-chip[data-active=true] .ra-rule-filter-chip-count {\n background: hsl(var(--ra-accent) / 0.18);\n color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-rule-filter-clear {\n align-self: flex-start;\n background: transparent;\n border: 0;\n padding: 0;\n color: hsl(var(--ra-muted-text));\n font-size: 0.65rem;\n cursor: pointer;\n text-decoration: underline;\n text-decoration-style: dotted;\n}\n.ra-shell .ra-rule-filter-clear:hover {\n color: hsl(var(--ra-text));\n}\n.ra-shell[data-density=compact] .ra-row {\n padding-block: 0.3rem;\n gap: 0.45rem;\n}\n.ra-shell[data-density=compact] .ra-row-title {\n font-size: 0.78125rem;\n}\n.ra-shell .ra-row-actions {\n display: inline-flex;\n align-items: center;\n gap: 0.15rem;\n margin-left: auto;\n opacity: 0;\n transition: opacity .15s ease;\n}\n.ra-shell .ra-row:hover .ra-row-actions,\n.ra-shell .ra-row:focus-within .ra-row-actions {\n opacity: 1;\n}\n.ra-shell .ra-row-action {\n width: 1.6rem;\n height: 1.6rem;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border-radius: 999px;\n background: transparent;\n color: hsl(var(--ra-muted-text));\n border: 0;\n cursor: pointer;\n transition: background .15s ease, color .15s ease;\n}\n.ra-shell .ra-row-action:hover {\n background: hsl(var(--ra-accent) / 0.10);\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-row-action[data-tone=danger]:hover {\n background: hsl(var(--ra-danger) / 0.12);\n color: hsl(var(--ra-danger));\n}\n.ra-shell .ra-chip {\n display: inline-flex;\n align-items: center;\n gap: 0.3rem;\n padding: 0.15rem 0.5rem;\n border-radius: 999px;\n font-size: 0.6875rem;\n font-weight: 500;\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n border: 1px solid hsl(var(--ra-border));\n white-space: nowrap;\n max-width: 14rem;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-chip[data-tone=success] {\n background: hsl(var(--ra-success) / 0.12);\n color: hsl(var(--ra-success));\n border-color: hsl(var(--ra-success) / 0.30);\n}\n.ra-shell .ra-chip[data-tone=warning] {\n background: hsl(var(--ra-warning) / 0.14);\n color: hsl(var(--ra-warning));\n border-color: hsl(var(--ra-warning) / 0.35);\n}\n.ra-shell .ra-chip[data-tone=info] {\n background: hsl(var(--ra-info) / 0.10);\n color: hsl(var(--ra-info));\n border-color: hsl(var(--ra-info) / 0.30);\n}\n.ra-shell .ra-chip[data-tone=danger] {\n background: hsl(var(--ra-danger) / 0.10);\n color: hsl(var(--ra-danger));\n border-color: hsl(var(--ra-danger) / 0.30);\n}\n.ra-shell .ra-chip[data-tone=muted] {\n background: transparent;\n color: hsl(var(--ra-muted-text));\n border-style: dashed;\n}\n.ra-shell .ra-group {\n border-bottom: 1px solid hsl(var(--ra-border));\n}\n.ra-shell .ra-group:last-child {\n border-bottom: 0;\n}\n.ra-shell .ra-group-summary {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n width: 100%;\n padding: 0.5rem 0.85rem;\n background: hsl(var(--ra-muted) / 0.6);\n font-size: 0.7rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: hsl(var(--ra-muted-text));\n border: 0;\n cursor: pointer;\n transition: background .12s ease;\n}\n.ra-shell .ra-group-summary:hover {\n background: hsl(var(--ra-muted));\n}\n.ra-shell .ra-group-summary .ra-group-chevron {\n transition: transform .15s ease;\n}\n.ra-shell .ra-group[data-open=false] .ra-group-chevron {\n transform: rotate(-90deg);\n}\n.ra-shell .ra-group-name {\n flex: 1;\n text-align: left;\n}\n.ra-shell .ra-group-count {\n font-size: 0.65rem;\n font-weight: 600;\n color: hsl(var(--ra-muted-text));\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n border-radius: 999px;\n padding: 0.05rem 0.4rem;\n}\n.ra-shell .ra-group[data-open=false] .ra-group-body {\n display: none;\n}\n.ra-shell .ra-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n text-align: center;\n padding: 2.5rem 1.5rem;\n gap: 0.75rem;\n}\n.ra-shell .ra-empty-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 3.25rem;\n height: 3.25rem;\n border-radius: 999px;\n background: hsl(var(--ra-accent) / 0.08);\n color: hsl(var(--ra-accent));\n margin-bottom: 0.25rem;\n}\n.ra-shell .ra-empty-title {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n font-size: 1rem;\n color: hsl(var(--ra-text));\n margin: 0;\n letter-spacing: -0.01em;\n}\n.ra-shell .ra-empty-body {\n font-size: 0.8125rem;\n color: hsl(var(--ra-muted-text));\n max-width: 22rem;\n line-height: 1.45;\n}\n.ra-shell .ra-empty-actions {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n margin-top: 0.25rem;\n flex-wrap: wrap;\n justify-content: center;\n}\n.ra-shell .ra-btn {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n padding: 0.45rem 0.85rem;\n border-radius: calc(var(--ra-radius) * 0.7);\n font-size: 0.8125rem;\n font-weight: 500;\n border: 1px solid hsl(var(--ra-border));\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-text));\n cursor: pointer;\n transition:\n background .15s ease,\n border-color .15s ease,\n box-shadow .15s ease,\n transform .1s ease;\n}\n.ra-shell .ra-btn:hover {\n background: hsl(var(--ra-muted));\n box-shadow: var(--ra-card-shadow);\n}\n.ra-shell .ra-btn:active {\n transform: translateY(1px);\n}\n.ra-shell .ra-btn[data-variant=primary] {\n background: hsl(var(--ra-accent));\n color: hsl(var(--ra-surface));\n border-color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-btn[data-variant=primary]:hover {\n background: hsl(var(--ra-accent) / 0.92);\n}\n.ra-shell .ra-btn[data-variant=ghost] {\n background: transparent;\n border-color: transparent;\n color: hsl(var(--ra-muted-text));\n}\n.ra-shell .ra-btn[data-variant=ghost]:hover {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-btn[data-variant=danger] {\n color: hsl(var(--ra-danger));\n}\n.ra-shell .ra-btn[data-variant=danger]:hover {\n background: hsl(var(--ra-danger) / 0.10);\n border-color: hsl(var(--ra-danger) / 0.40);\n}\n.ra-shell .ra-intro {\n position: relative;\n display: flex;\n gap: 0.85rem;\n padding: 0.9rem 1rem;\n border-radius: var(--ra-radius);\n border: 1px solid hsl(var(--ra-info) / 0.30);\n background: hsl(var(--ra-info) / 0.08);\n margin-bottom: 1rem;\n}\n.ra-shell .ra-intro[data-tone=success] {\n border-color: hsl(var(--ra-success) / 0.30);\n background: hsl(var(--ra-success) / 0.08);\n}\n.ra-shell .ra-intro[data-tone=warning] {\n border-color: hsl(var(--ra-warning) / 0.35);\n background: hsl(var(--ra-warning) / 0.10);\n}\n.ra-shell .ra-intro-icon {\n flex-shrink: 0;\n width: 2rem;\n height: 2rem;\n border-radius: 999px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: hsl(var(--ra-info) / 0.18);\n color: hsl(var(--ra-info));\n}\n.ra-shell .ra-intro[data-tone=success] .ra-intro-icon {\n background: hsl(var(--ra-success) / 0.18);\n color: hsl(var(--ra-success));\n}\n.ra-shell .ra-intro[data-tone=warning] .ra-intro-icon {\n background: hsl(var(--ra-warning) / 0.20);\n color: hsl(var(--ra-warning));\n}\n.ra-shell .ra-intro-body {\n flex: 1;\n min-width: 0;\n}\n.ra-shell .ra-intro-title {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-title-weight);\n font-size: 0.875rem;\n color: hsl(var(--ra-text));\n margin: 0 0 0.2rem 0;\n}\n.ra-shell .ra-intro-text {\n font-size: 0.8125rem;\n color: hsl(var(--ra-text) / 0.85);\n line-height: 1.45;\n}\n.ra-shell .ra-intro-dismiss {\n position: absolute;\n top: 0.5rem;\n right: 0.5rem;\n width: 1.6rem;\n height: 1.6rem;\n border-radius: 999px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: 0;\n color: hsl(var(--ra-muted-text));\n cursor: pointer;\n}\n.ra-shell .ra-intro-dismiss:hover {\n background: hsl(var(--ra-text) / 0.06);\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-bulk-menu {\n min-width: 12rem;\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n border-radius: calc(var(--ra-radius) * 0.85);\n box-shadow: var(--ra-card-shadow-hover);\n padding: 0.3rem;\n z-index: 60;\n}\n.ra-shell .ra-bulk-item {\n display: flex;\n align-items: center;\n gap: 0.55rem;\n width: 100%;\n padding: 0.45rem 0.6rem;\n border-radius: calc(var(--ra-radius) * 0.6);\n font-size: 0.8125rem;\n color: hsl(var(--ra-text));\n background: transparent;\n border: 0;\n cursor: pointer;\n text-align: left;\n transition: background .12s ease, color .12s ease;\n}\n.ra-shell .ra-bulk-item:hover {\n background: hsl(var(--ra-muted));\n}\n.ra-shell .ra-bulk-item[data-tone=danger] {\n color: hsl(var(--ra-danger));\n}\n.ra-shell .ra-bulk-item[data-tone=danger]:hover {\n background: hsl(var(--ra-danger) / 0.10);\n}\n.ra-shell .ra-bulk-divider {\n height: 1px;\n background: hsl(var(--ra-border));\n margin: 0.25rem 0;\n}\n.ra-shell .ra-preview-rail {\n background: hsl(var(--ra-surface));\n border-left: 1px solid hsl(var(--ra-border));\n box-shadow: -4px 0 16px hsl(var(--ra-accent) / 0.04);\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n}\n.ra-shell .ra-preview-rail-header {\n position: sticky;\n top: 0;\n z-index: 1;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.75rem 1rem;\n background:\n linear-gradient(\n 180deg,\n hsl(var(--ra-surface)) 0%,\n hsl(var(--ra-surface) / 0.92) 100%);\n border-bottom: 1px solid hsl(var(--ra-border));\n backdrop-filter: blur(6px);\n}\n.ra-shell .ra-preview-rail-title {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n font-size: 0.7rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: hsl(var(--ra-muted-text));\n}\n.ra-shell .ra-preview-rail-body {\n flex: 1;\n overflow-y: auto;\n padding: 1rem;\n}\n.ra-confirm-root {\n position: fixed;\n inset: 0;\n z-index: 2147483000;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 1rem;\n}\n.ra-confirm-root .ra-confirm-backdrop {\n position: absolute;\n inset: 0;\n background: hsl(0 0% 0% / 0.45);\n backdrop-filter: blur(2px);\n animation: ra-confirm-fade .12s ease-out;\n}\n.ra-confirm-root .ra-confirm-card {\n position: relative;\n width: min(440px, 100%);\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-text));\n border: 1px solid hsl(var(--ra-border));\n border-radius: var(--ra-radius);\n box-shadow: 0 1px 2px hsl(0 0% 0% / 0.08), 0 24px 48px -12px hsl(0 0% 0% / 0.32);\n padding: 1.25rem;\n animation: ra-confirm-pop .14s ease-out;\n}\n.ra-confirm-root .ra-confirm-header {\n display: flex;\n align-items: center;\n gap: 0.6rem;\n margin-bottom: 0.5rem;\n}\n.ra-confirm-root .ra-confirm-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.75rem;\n height: 1.75rem;\n border-radius: 999px;\n background: hsl(var(--ra-warning, 38 92% 50%) / 0.12);\n color: hsl(var(--ra-warning, 38 92% 50%));\n}\n.ra-confirm-root .ra-confirm-title {\n font-family: var(--ra-font-display);\n font-weight: 600;\n font-size: 1rem;\n margin: 0;\n}\n.ra-confirm-root .ra-confirm-body {\n font-size: 0.875rem;\n color: hsl(var(--ra-muted-text));\n margin: 0 0 1.1rem;\n line-height: 1.45;\n}\n.ra-confirm-root .ra-confirm-actions {\n display: flex;\n justify-content: flex-end;\n gap: 0.5rem;\n flex-wrap: wrap;\n}\n.ra-confirm-root .ra-confirm-btn {\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n border: 1px solid transparent;\n border-radius: calc(var(--ra-radius) - 2px);\n padding: 0.45rem 0.85rem;\n font-size: 0.8125rem;\n font-weight: 500;\n cursor: pointer;\n transition:\n background-color .12s ease,\n border-color .12s ease,\n color .12s ease;\n}\n.ra-confirm-root .ra-confirm-btn:focus-visible {\n outline: none;\n box-shadow: 0 0 0 3px var(--ra-focus-ring);\n}\n.ra-confirm-root .ra-confirm-btn-ghost {\n background: transparent;\n color: hsl(var(--ra-muted-text));\n border-color: hsl(var(--ra-border));\n}\n.ra-confirm-root .ra-confirm-btn-ghost:hover {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-confirm-root .ra-confirm-btn-danger {\n background: transparent;\n color: hsl(var(--ra-danger, 0 72% 51%));\n border-color: hsl(var(--ra-danger, 0 72% 51%) / 0.45);\n}\n.ra-confirm-root .ra-confirm-btn-danger:hover {\n background: hsl(var(--ra-danger, 0 72% 51%) / 0.08);\n border-color: hsl(var(--ra-danger, 0 72% 51%));\n}\n.ra-confirm-root .ra-confirm-btn-primary {\n background: hsl(var(--ra-accent));\n color: hsl(var(--ra-accent-fg, 0 0% 100%));\n border-color: hsl(var(--ra-accent));\n}\n.ra-confirm-root .ra-confirm-btn-primary:hover {\n filter: brightness(0.95);\n}\n@keyframes ra-confirm-fade {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n@keyframes ra-confirm-pop {\n from {\n opacity: 0;\n transform: translateY(4px) scale(.98);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n}\n.ra-shell .ra-unsaved-banner {\n display: flex;\n align-items: center;\n gap: 0.6rem;\n padding: 0.5rem 0.75rem;\n border: 1px solid hsl(var(--ra-warning, 38 92% 50%) / 0.35);\n background: hsl(var(--ra-warning, 38 92% 50%) / 0.08);\n border-radius: var(--ra-radius);\n font-size: 0.8125rem;\n color: hsl(var(--ra-text));\n animation: ra-unsaved-slide .14s ease-out;\n}\n.ra-shell .ra-unsaved-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n color: hsl(var(--ra-warning, 38 92% 50%));\n flex-shrink: 0;\n}\n.ra-shell .ra-unsaved-text {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.ra-shell .ra-unsaved-context {\n color: hsl(var(--ra-muted-text));\n font-weight: 400;\n}\n.ra-shell .ra-unsaved-error {\n color: hsl(var(--ra-danger, 0 72% 51%));\n font-size: 0.75rem;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n font-weight: 500;\n}\n.ra-shell .ra-unsaved-actions {\n display: inline-flex;\n gap: 0.4rem;\n flex-shrink: 0;\n}\n.ra-shell .ra-unsaved-btn {\n display: inline-flex;\n align-items: center;\n gap: 0.3rem;\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n border: 1px solid transparent;\n border-radius: calc(var(--ra-radius) - 2px);\n padding: 0.3rem 0.6rem;\n font-size: 0.75rem;\n font-weight: 500;\n cursor: pointer;\n transition:\n background-color .12s ease,\n border-color .12s ease,\n color .12s ease,\n opacity .12s ease;\n}\n.ra-shell .ra-unsaved-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.ra-shell .ra-unsaved-btn:focus-visible {\n outline: none;\n box-shadow: 0 0 0 3px var(--ra-focus-ring);\n}\n.ra-shell .ra-unsaved-btn-ghost {\n background: transparent;\n color: hsl(var(--ra-muted-text));\n border-color: hsl(var(--ra-border));\n}\n.ra-shell .ra-unsaved-btn-ghost:hover:not(:disabled) {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-unsaved-btn-primary {\n background: hsl(var(--ra-accent));\n color: hsl(var(--ra-accent-fg, 0 0% 100%));\n border-color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-unsaved-btn-primary:hover:not(:disabled) {\n filter: brightness(0.95);\n}\n@keyframes ra-unsaved-slide {\n from {\n opacity: 0;\n transform: translateY(-3px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n.ra-shell .ra-clipboard-toast {\n position: fixed;\n bottom: 1.25rem;\n left: 50%;\n transform: translateX(-50%);\n z-index: 90;\n display: inline-flex;\n align-items: center;\n gap: 0.5rem;\n max-width: min(28rem, calc(100vw - 2rem));\n padding: 0.55rem 0.85rem;\n border-radius: 999px;\n background: hsl(var(--ra-text));\n color: hsl(var(--ra-surface));\n font-size: 0.75rem;\n line-height: 1;\n box-shadow: 0 8px 24px -10px hsl(0 0% 0% / 0.45);\n animation: ra-clipboard-pop 0.18s ease-out both;\n pointer-events: none;\n}\n@keyframes ra-clipboard-pop {\n from {\n opacity: 0;\n transform: translate(-50%, 6px);\n }\n to {\n opacity: 1;\n transform: translate(-50%, 0);\n }\n}\n.ra-shell .ra-row-menu-wrap {\n display: inline-flex;\n align-items: center;\n margin-left: 0.25rem;\n}\n.ra-shell .ra-row-menu-trigger {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.5rem;\n height: 1.5rem;\n border-radius: 0.35rem;\n background: transparent;\n color: hsl(var(--ra-muted-text));\n opacity: 0;\n transition:\n opacity .15s ease,\n background .15s ease,\n color .15s ease;\n border: 1px solid transparent;\n}\n.ra-shell .ra-row:hover .ra-row-menu-trigger,\n.ra-shell .ra-card-hover:hover .ra-row-menu-trigger,\n.ra-shell .ra-row-menu-trigger:focus-visible,\n.ra-shell .ra-row-menu-trigger[aria-expanded=true] {\n opacity: 1;\n}\n.ra-shell .ra-row-menu-trigger:hover {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-row-menu {\n position: absolute;\n right: 0;\n top: calc(100% + 4px);\n z-index: 50;\n min-width: 11rem;\n padding: 0.25rem;\n border-radius: 0.5rem;\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n box-shadow: 0 12px 28px -10px hsl(0 0% 0% / 0.25);\n display: flex;\n flex-direction: column;\n gap: 0.125rem;\n}\n.ra-shell .ra-row-menu-item {\n display: inline-flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.4rem 0.55rem;\n border-radius: 0.35rem;\n font-size: 0.75rem;\n color: hsl(var(--ra-text));\n background: transparent;\n border: 0;\n text-align: left;\n width: 100%;\n cursor: pointer;\n}\n.ra-shell .ra-row-menu-item:hover:not(:disabled) {\n background: hsl(var(--ra-muted));\n}\n.ra-shell .ra-row-menu-item:disabled {\n opacity: 0.45;\n cursor: not-allowed;\n}\n.ra-shell .ra-item-list {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n}\n.ra-shell .ra-item-list-body {\n flex: 1;\n min-height: 0;\n overflow: auto;\n padding: 1rem 1.25rem 1.5rem;\n}\n.ra-shell .ra-item-toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.75rem;\n padding: 0.75rem 1.25rem;\n border-bottom: 1px solid hsl(var(--ra-border));\n background: hsl(var(--ra-surface));\n}\n.ra-shell .ra-item-toolbar-title {\n display: flex;\n align-items: baseline;\n gap: 0.5rem;\n min-width: 0;\n}\n.ra-shell .ra-item-toolbar-count {\n font-size: 0.7rem;\n font-weight: 600;\n color: hsl(var(--ra-muted-text));\n background: hsl(var(--ra-muted));\n border: 1px solid hsl(var(--ra-border));\n border-radius: 999px;\n padding: 0.05rem 0.45rem;\n}\n.ra-shell .ra-item-toolbar-actions {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n flex-shrink: 0;\n}\n.ra-shell .ra-item-table-wrap {\n border: 1px solid hsl(var(--ra-border));\n border-radius: var(--ra-radius);\n background: hsl(var(--ra-surface));\n overflow: hidden;\n box-shadow: var(--ra-card-shadow);\n}\n.ra-shell .ra-item-table {\n width: 100%;\n border-collapse: collapse;\n font-size: 0.85rem;\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-item-table thead th {\n text-align: left;\n font-size: 0.7rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: hsl(var(--ra-muted-text));\n padding: 0.65rem 0.85rem;\n background: hsl(var(--ra-muted) / 0.55);\n border-bottom: 1px solid hsl(var(--ra-border));\n}\n.ra-shell .ra-item-table tbody td {\n padding: 0.65rem 0.85rem;\n border-bottom: 1px solid hsl(var(--ra-border) / 0.7);\n vertical-align: middle;\n}\n.ra-shell .ra-item-table tbody tr:last-child td {\n border-bottom: 0;\n}\n.ra-shell .ra-item-row {\n cursor: pointer;\n transition: background .12s ease;\n}\n.ra-shell .ra-item-row:hover {\n background: var(--ra-row-hover);\n}\n.ra-shell .ra-item-row[data-selected=true] {\n background: var(--ra-row-active-bg);\n}\n.ra-shell .ra-item-row-title {\n font-weight: var(--ra-title-weight);\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-item-row-sub {\n font-size: 0.75rem;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.15rem;\n}\n.ra-shell .ra-item-row-meta {\n font-size: 0.78rem;\n color: hsl(var(--ra-muted-text));\n}\n.ra-shell .ra-item-row-actions {\n text-align: right;\n white-space: nowrap;\n}\n.ra-shell .ra-item-row-actions .ra-row-action + .ra-row-action {\n margin-left: 0.15rem;\n}\n.ra-shell .ra-item-cards {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));\n gap: 0.85rem;\n}\n.ra-shell .ra-item-gallery {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));\n gap: 1rem;\n}\n.ra-shell .ra-item-card {\n position: relative;\n display: flex;\n flex-direction: column;\n align-items: stretch;\n text-align: left;\n padding: 0;\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n border-radius: var(--ra-radius);\n overflow: hidden;\n cursor: pointer;\n transition:\n box-shadow .18s ease,\n transform .12s ease,\n border-color .15s ease;\n box-shadow: var(--ra-card-shadow);\n font-family: inherit;\n color: inherit;\n}\n.ra-shell .ra-item-card:hover {\n box-shadow: var(--ra-card-shadow-hover);\n border-color: hsl(var(--ra-accent) / 0.30);\n}\n.ra-shell .ra-item-card[data-selected=true] {\n border-color: hsl(var(--ra-accent) / 0.55);\n box-shadow: var(--ra-card-shadow-hover);\n}\n.ra-shell .ra-item-card-thumb {\n width: 100%;\n aspect-ratio: 1 / 1;\n background:\n linear-gradient(\n 135deg,\n hsl(var(--ra-accent) / 0.12),\n hsl(var(--ra-accent) / 0.04));\n display: flex;\n align-items: center;\n justify-content: center;\n color: hsl(var(--ra-accent));\n overflow: hidden;\n}\n.ra-shell .ra-item-card-thumb--gallery {\n aspect-ratio: 16 / 9;\n}\n.ra-shell .ra-item-card-thumb img {\n width: 100%;\n height: 100%;\n -o-object-fit: cover;\n object-fit: cover;\n}\n.ra-shell .ra-item-card-initials {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n font-size: 1.5rem;\n letter-spacing: 0.02em;\n}\n.ra-shell .ra-item-card-body {\n padding: 0.65rem 0.8rem 0.85rem;\n min-width: 0;\n}\n.ra-shell .ra-item-card-title {\n font-weight: var(--ra-title-weight);\n font-size: 0.85rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-item-card-sub {\n font-size: 0.75rem;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.15rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-item-card-delete {\n position: absolute;\n top: 0.4rem;\n right: 0.4rem;\n background: hsl(var(--ra-surface) / 0.85);\n backdrop-filter: blur(4px);\n opacity: 0;\n transition: opacity .15s ease;\n}\n.ra-shell .ra-item-card:hover .ra-item-card-delete,\n.ra-shell .ra-item-card:focus-within .ra-item-card-delete {\n opacity: 1;\n}\n.ra-shell .ra-item-nav {\n display: flex;\n align-items: center;\n gap: 0.6rem;\n padding: 0.5rem 1.25rem;\n border-bottom: 1px solid hsl(var(--ra-border));\n background: hsl(var(--ra-surface));\n}\n.ra-shell .ra-item-nav-position {\n font-size: 0.72rem;\n color: hsl(var(--ra-muted-text));\n font-variant-numeric: tabular-nums;\n}\n.ra-shell .ra-item-nav-arrows {\n margin-left: auto;\n display: inline-flex;\n align-items: center;\n gap: 0.15rem;\n}\n.ra-shell .ra-item-nav-arrows .ra-row-action[disabled] {\n opacity: 0.35;\n cursor: not-allowed;\n}\n.ra-shell .ra-sibling-rail {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n}\n.ra-shell .ra-sibling-back {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n padding: 0.6rem 0.85rem;\n font-size: 0.75rem;\n font-weight: 500;\n color: hsl(var(--ra-muted-text));\n background: hsl(var(--ra-muted) / 0.5);\n border: 0;\n border-bottom: 1px solid hsl(var(--ra-border));\n cursor: pointer;\n text-align: left;\n transition: background .12s ease, color .12s ease;\n}\n.ra-shell .ra-sibling-back:hover {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-sibling-heading {\n padding: 0.6rem 0.85rem 0.4rem;\n font-size: 0.65rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: hsl(var(--ra-muted-text));\n}\n.ra-shell .ra-sibling-body {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n}\n.ra-shell .ra-sibling-list {\n list-style: none;\n margin: 0;\n padding: 0;\n}\n.ra-shell .ra-status-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n border-radius: 9999px;\n}\n.ra-shell .ra-status-icon > svg {\n width: 100%;\n height: 100%;\n display: block;\n}\n.ra-shell .ra-status-icon--own {\n color: hsl(var(--ra-status-own));\n}\n.ra-shell .ra-status-icon--shared {\n color: hsl(var(--ra-status-shared));\n}\n.ra-shell .ra-status-icon--missing {\n color: hsl(var(--ra-status-missing) / 0.7);\n}\n.ra-shell .ra-row-status {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.5rem;\n height: 1.5rem;\n flex-shrink: 0;\n}\n.ra-shell .ra-row-scope {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.25rem;\n height: 1.25rem;\n border-radius: calc(var(--ra-radius) * 0.5);\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n flex-shrink: 0;\n margin-left: auto;\n opacity: 0.55;\n transition:\n opacity .12s ease,\n color .12s ease,\n background .12s ease;\n}\n.ra-shell .ra-row:hover .ra-row-scope {\n opacity: 0.85;\n}\n.ra-shell .ra-row[data-selected=true] .ra-row-scope {\n opacity: 1;\n background: hsl(var(--ra-accent) / 0.12);\n color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-row[data-tone=own] .ra-row-sub {\n color: hsl(var(--ra-status-own));\n}\n.ra-shell .ra-row[data-tone=shared] .ra-row-sub {\n color: hsl(var(--ra-status-shared));\n}\n.ra-shell .ra-row[data-selected=true] {\n background:\n linear-gradient(\n 90deg,\n hsl(var(--ra-accent) / 0.10) 0%,\n hsl(var(--ra-accent) / 0.04) 100%);\n border-left-width: 3px;\n border-left-color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-dirty-pip {\n display: inline-block;\n width: 0.45rem;\n height: 0.45rem;\n border-radius: 9999px;\n background: hsl(var(--ra-warning));\n box-shadow: 0 0 0 2px hsl(var(--ra-warning) / 0.18);\n flex-shrink: 0;\n}\n.ra-shell .ra-group-summary {\n background: transparent;\n}\n.ra-shell {\n position: relative;\n}\n.ra-shell .ra-help-float {\n position: absolute;\n top: 0.65rem;\n right: 0.85rem;\n z-index: 5;\n display: inline-flex;\n align-items: center;\n gap: 0.35rem;\n padding: 0.3rem 0.6rem;\n font-size: 0.7rem;\n font-weight: 500;\n color: hsl(var(--ra-muted-text));\n background: hsl(var(--ra-surface) / 0.85);\n backdrop-filter: blur(6px);\n border: 1px solid hsl(var(--ra-border));\n border-radius: 999px;\n cursor: pointer;\n transition:\n color .12s ease,\n background .12s ease,\n border-color .12s ease;\n}\n.ra-shell .ra-help-float:hover {\n color: hsl(var(--ra-accent));\n border-color: hsl(var(--ra-accent) / 0.4);\n background: hsl(var(--ra-surface));\n}\n.ra-shell .ra-help-float svg {\n width: 0.85rem;\n height: 0.85rem;\n}\n.ra-shell .ra-preview-reopen {\n position: absolute;\n top: 50%;\n right: 0;\n transform: translateY(-50%);\n z-index: 4;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.4rem;\n padding: 0.65rem 0.45rem;\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-muted-text));\n border: 1px solid hsl(var(--ra-border));\n border-right: 0;\n border-radius: calc(var(--ra-radius) * 0.85) 0 0 calc(var(--ra-radius) * 0.85);\n box-shadow: var(--ra-card-shadow);\n cursor: pointer;\n transition:\n color .12s ease,\n background .12s ease,\n padding-right .15s ease;\n writing-mode: vertical-rl;\n font-size: 0.7rem;\n font-weight: 600;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n}\n.ra-shell .ra-preview-reopen:hover {\n color: hsl(var(--ra-accent));\n background: hsl(var(--ra-accent) / 0.04);\n padding-right: 0.6rem;\n}\n.ra-shell .ra-preview-reopen svg {\n width: 0.85rem;\n height: 0.85rem;\n writing-mode: horizontal-tb;\n}\n");
|
|
3413
3736
|
var TOP_LEVEL_SCOPES = ["rule", "collection", "product", "facet"];
|
|
3414
3737
|
var defaultItemId = () => {
|
|
3415
3738
|
const time = Date.now().toString(36);
|
|
3416
3739
|
const rand = Math.random().toString(36).slice(2, 8);
|
|
3417
3740
|
return `${time}${rand}`;
|
|
3418
3741
|
};
|
|
3742
|
+
var newRuleId = () => {
|
|
3743
|
+
const time = Date.now().toString(36);
|
|
3744
|
+
const rand = Math.random().toString(36).slice(2, 10);
|
|
3745
|
+
return `${time}${rand}`;
|
|
3746
|
+
};
|
|
3419
3747
|
var productItemToSummary = (p) => {
|
|
3420
3748
|
const ref = buildRef({ productId: p.id });
|
|
3421
3749
|
return {
|
|
@@ -3563,6 +3891,7 @@ function RecordsAdminShell(props) {
|
|
|
3563
3891
|
}, [initialScope]);
|
|
3564
3892
|
const [search, setSearch] = useState("");
|
|
3565
3893
|
const [filter, setFilter] = useState("all");
|
|
3894
|
+
const [ruleFilters, setRuleFilters] = useState(EMPTY_RULE_FILTERS);
|
|
3566
3895
|
const [selectedFacetRef, setSelectedFacetRef] = useState();
|
|
3567
3896
|
const [selectedProductId, setSelectedProductId] = useState(
|
|
3568
3897
|
contextScope?.productId
|
|
@@ -3649,13 +3978,26 @@ function RecordsAdminShell(props) {
|
|
|
3649
3978
|
const first = facetBrowse.items[0];
|
|
3650
3979
|
if (first) setSelectedFacetRef(first.ref);
|
|
3651
3980
|
}, [activeScope, selectedFacetRef, facetBrowse.items]);
|
|
3981
|
+
useEffect(() => {
|
|
3982
|
+
if (activeScope !== "rule" && activeScope !== "collection") return;
|
|
3983
|
+
if (selectedFacetRef !== void 0) return;
|
|
3984
|
+
if (activeScope === "collection" && cardinality === "collection") {
|
|
3985
|
+
setSelectedFacetRef("");
|
|
3986
|
+
return;
|
|
3987
|
+
}
|
|
3988
|
+
const first = recordList.items[0];
|
|
3989
|
+
if (first) setSelectedFacetRef(first.ref);
|
|
3990
|
+
}, [activeScope, selectedFacetRef, recordList.items, cardinality]);
|
|
3652
3991
|
useEffect(() => {
|
|
3653
3992
|
setSearch("");
|
|
3654
3993
|
setFilter("all");
|
|
3994
|
+
setRuleFilters(EMPTY_RULE_FILTERS);
|
|
3995
|
+
setSelectedFacetRef(void 0);
|
|
3655
3996
|
}, [activeScope]);
|
|
3656
3997
|
const editingScope = useMemo(() => {
|
|
3657
|
-
if (activeScope === "facet") {
|
|
3658
|
-
|
|
3998
|
+
if (activeScope === "facet" || activeScope === "rule" || activeScope === "collection") {
|
|
3999
|
+
if (selectedFacetRef === void 0) return null;
|
|
4000
|
+
return parseRef(selectedFacetRef);
|
|
3659
4001
|
}
|
|
3660
4002
|
if (!selectedProductId) return null;
|
|
3661
4003
|
if (drillTab === "variant") {
|
|
@@ -3742,6 +4084,7 @@ function RecordsAdminShell(props) {
|
|
|
3742
4084
|
batchId: editingTargetScope?.batchId,
|
|
3743
4085
|
facetId: editingTargetScope?.facetId,
|
|
3744
4086
|
facetValue: editingTargetScope?.facetValue,
|
|
4087
|
+
ref: editingTargetScope?.raw,
|
|
3745
4088
|
supportedScopes: supportedForResolution,
|
|
3746
4089
|
enabled: !!editingTargetScope
|
|
3747
4090
|
});
|
|
@@ -3756,9 +4099,14 @@ function RecordsAdminShell(props) {
|
|
|
3756
4099
|
const editorCtx = useRecordEditor({
|
|
3757
4100
|
ctx,
|
|
3758
4101
|
scope: editingTargetScope ?? parseRef(""),
|
|
3759
|
-
resolved: { data: resolved.data, source: resolved.source, sourceRef: resolved.sourceRef, parentValue: resolved.parentValue },
|
|
4102
|
+
resolved: { data: resolved.data, source: resolved.source, sourceRef: resolved.sourceRef, parentValue: resolved.parentValue, facetRule: resolved.facetRule },
|
|
3760
4103
|
defaultData,
|
|
3761
4104
|
reseed: dirtyStrategy === "keep" ? "preserve-dirty" : "always",
|
|
4105
|
+
// Seed an empty rule for freshly-minted `rule:{id}` refs so the Targeting
|
|
4106
|
+
// section can render its empty-state picker. For existing rule records
|
|
4107
|
+
// pull the saved rule off the resolved record. Pinned scopes get `null`
|
|
4108
|
+
// and the Targeting section stays hidden.
|
|
4109
|
+
initialFacetRule: editingTargetScope?.kind === "rule" ? resolved.facetRule ?? { all: [] } : null,
|
|
3762
4110
|
onSaved: () => {
|
|
3763
4111
|
onTelemetry?.({ type: "record.save", recordType, ref: editingTargetScope?.raw ?? "", isCreate: resolved.source !== "self" });
|
|
3764
4112
|
refetchAll();
|
|
@@ -4054,7 +4402,7 @@ function RecordsAdminShell(props) {
|
|
|
4054
4402
|
if (!ok) return;
|
|
4055
4403
|
}
|
|
4056
4404
|
try {
|
|
4057
|
-
const { deleteRecord: deleteRecord2 } = await import('../../records-
|
|
4405
|
+
const { deleteRecord: deleteRecord2 } = await import('../../records-AUJWCB7Q.js');
|
|
4058
4406
|
await deleteRecord2(ctx, ref);
|
|
4059
4407
|
onTelemetry?.({ type: "item.delete", recordType, scopeRef: baseScopeRef, itemId });
|
|
4060
4408
|
if (selectedItemId === itemId) setSelectedItemId(null);
|
|
@@ -4151,6 +4499,15 @@ function RecordsAdminShell(props) {
|
|
|
4151
4499
|
bulkActions: { ...csvBulk, i18n },
|
|
4152
4500
|
preview: inlinePreviewBody,
|
|
4153
4501
|
footerExtra: extraFooter,
|
|
4502
|
+
targeting: editingTargetScope.kind === "rule" ? /* @__PURE__ */ jsx(
|
|
4503
|
+
RecordTargeting,
|
|
4504
|
+
{
|
|
4505
|
+
SL,
|
|
4506
|
+
collectionId,
|
|
4507
|
+
appId,
|
|
4508
|
+
ctx: editorCtx
|
|
4509
|
+
}
|
|
4510
|
+
) : void 0,
|
|
4154
4511
|
onBeforeDelete: onBeforeDelete && editingTargetScope ? () => onBeforeDelete(editingTargetScope) : void 0,
|
|
4155
4512
|
headerLabel: editorHeaderLabel,
|
|
4156
4513
|
headerSubtitle: editorHeaderSubtitle,
|
|
@@ -4271,7 +4628,34 @@ function RecordsAdminShell(props) {
|
|
|
4271
4628
|
const isRuleTab = activeScope === "rule";
|
|
4272
4629
|
const isGlobalTab = activeScope === "collection";
|
|
4273
4630
|
const isRecordsTab = isRuleTab || isGlobalTab;
|
|
4274
|
-
const
|
|
4631
|
+
const onCreateRule = useCallback(() => {
|
|
4632
|
+
void runWithGuard(() => {
|
|
4633
|
+
const id = newRuleId();
|
|
4634
|
+
const ref = `rule:${id}`;
|
|
4635
|
+
if (activeScope !== "rule") setActiveScope("rule");
|
|
4636
|
+
setSelectedFacetRef(ref);
|
|
4637
|
+
});
|
|
4638
|
+
}, [runWithGuard, activeScope]);
|
|
4639
|
+
const hasGlobalRecord = useMemo(
|
|
4640
|
+
() => recordList.items.some((it) => !it.scope.productId && !it.scope.facetId && !it.scope.variantId && !it.scope.batchId && !it.scope.proofId && !it.scope.itemId && !it.ref.startsWith("item:") && !it.ref.includes("/item:")),
|
|
4641
|
+
[recordList.items]
|
|
4642
|
+
);
|
|
4643
|
+
const showCreateGlobal = isGlobalTab && (isCollection || !hasGlobalRecord);
|
|
4644
|
+
const onCreateGlobal = useCallback(() => {
|
|
4645
|
+
void runWithGuard(() => {
|
|
4646
|
+
if (activeScope !== "collection") setActiveScope("collection");
|
|
4647
|
+
setSelectedFacetRef("");
|
|
4648
|
+
});
|
|
4649
|
+
}, [runWithGuard, activeScope]);
|
|
4650
|
+
const filteredRuleItems = useMemo(
|
|
4651
|
+
() => isRuleTab ? applyRuleFilters(recordList.items, ruleFilters) : recordList.items,
|
|
4652
|
+
[isRuleTab, recordList.items, ruleFilters]
|
|
4653
|
+
);
|
|
4654
|
+
const stripItemRecords = useCallback(
|
|
4655
|
+
(items) => items.filter((it) => !it.scope.itemId && !it.ref.startsWith("item:") && !it.ref.includes("/item:")),
|
|
4656
|
+
[]
|
|
4657
|
+
);
|
|
4658
|
+
const leftItems = isProductTab ? productListItems : isRuleTab ? isCollection ? stripItemRecords(filteredRuleItems) : filteredRuleItems : isRecordsTab ? isCollection ? stripItemRecords(recordList.items) : recordList.items : facetBrowse.items;
|
|
4275
4659
|
const leftLoading = isProductTab ? !productPinned && productBrowse.isLoading : isRecordsTab ? recordList.isLoading || probe.isLoading : facetBrowse.isLoading || recordList.isLoading || probe.isLoading;
|
|
4276
4660
|
const leftError = isProductTab ? productBrowse.error : isRecordsTab ? recordList.error : facetBrowse.error ?? recordList.error;
|
|
4277
4661
|
const leftSelectedRef = isProductTab ? selectedProductId ? buildRef({ productId: selectedProductId }) : void 0 : selectedFacetRef;
|
|
@@ -4442,6 +4826,34 @@ function RecordsAdminShell(props) {
|
|
|
4442
4826
|
}
|
|
4443
4827
|
) }),
|
|
4444
4828
|
/* @__PURE__ */ jsxs("div", { className: "p-3 space-y-2.5 border-b", style: { borderColor: "hsl(var(--ra-border))" }, children: [
|
|
4829
|
+
isRuleTab && /* @__PURE__ */ jsxs(
|
|
4830
|
+
"button",
|
|
4831
|
+
{
|
|
4832
|
+
type: "button",
|
|
4833
|
+
onClick: onCreateRule,
|
|
4834
|
+
className: "ra-btn w-full",
|
|
4835
|
+
"data-variant": "primary",
|
|
4836
|
+
"aria-label": "New rule",
|
|
4837
|
+
children: [
|
|
4838
|
+
/* @__PURE__ */ jsx(Plus, { className: "w-3.5 h-3.5", "aria-hidden": "true" }),
|
|
4839
|
+
/* @__PURE__ */ jsx("span", { children: "New rule" })
|
|
4840
|
+
]
|
|
4841
|
+
}
|
|
4842
|
+
),
|
|
4843
|
+
showCreateGlobal && /* @__PURE__ */ jsxs(
|
|
4844
|
+
"button",
|
|
4845
|
+
{
|
|
4846
|
+
type: "button",
|
|
4847
|
+
onClick: onCreateGlobal,
|
|
4848
|
+
className: "ra-btn w-full",
|
|
4849
|
+
"data-variant": "primary",
|
|
4850
|
+
"aria-label": "New global default",
|
|
4851
|
+
children: [
|
|
4852
|
+
/* @__PURE__ */ jsx(Plus, { className: "w-3.5 h-3.5", "aria-hidden": "true" }),
|
|
4853
|
+
/* @__PURE__ */ jsx("span", { children: "New global default" })
|
|
4854
|
+
]
|
|
4855
|
+
}
|
|
4856
|
+
),
|
|
4445
4857
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
4446
4858
|
/* @__PURE__ */ jsxs("div", { className: "relative flex-1 min-w-0", children: [
|
|
4447
4859
|
/* @__PURE__ */ jsx(Search, { className: "absolute left-2.5 top-1/2 -translate-y-1/2 w-3.5 h-3.5 opacity-50" }),
|
|
@@ -4476,6 +4888,14 @@ function RecordsAdminShell(props) {
|
|
|
4476
4888
|
hideZero: ["partial"],
|
|
4477
4889
|
i18n
|
|
4478
4890
|
}
|
|
4891
|
+
),
|
|
4892
|
+
isRuleTab && /* @__PURE__ */ jsx(
|
|
4893
|
+
RuleFilterChips,
|
|
4894
|
+
{
|
|
4895
|
+
source: recordList.items,
|
|
4896
|
+
value: ruleFilters,
|
|
4897
|
+
onChange: setRuleFilters
|
|
4898
|
+
}
|
|
4479
4899
|
)
|
|
4480
4900
|
] }),
|
|
4481
4901
|
/* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto", children: [
|
|
@@ -4837,49 +5257,6 @@ function useResolveAllRecords(args) {
|
|
|
4837
5257
|
}
|
|
4838
5258
|
};
|
|
4839
5259
|
}
|
|
4840
|
-
var isRuleValid = (rule) => {
|
|
4841
|
-
if (!rule || !Array.isArray(rule.all) || rule.all.length === 0) return false;
|
|
4842
|
-
return rule.all.every(
|
|
4843
|
-
(c) => !!c.facetKey && Array.isArray(c.anyOf) && c.anyOf.length > 0
|
|
4844
|
-
);
|
|
4845
|
-
};
|
|
4846
|
-
function useRulePreview(args) {
|
|
4847
|
-
const {
|
|
4848
|
-
SL,
|
|
4849
|
-
collectionId,
|
|
4850
|
-
appId,
|
|
4851
|
-
rule,
|
|
4852
|
-
limit = 20,
|
|
4853
|
-
debounceMs = 350,
|
|
4854
|
-
enabled = true
|
|
4855
|
-
} = args;
|
|
4856
|
-
const [debouncedRule, setDebouncedRule] = useState(rule);
|
|
4857
|
-
const timer = useRef(null);
|
|
4858
|
-
useEffect(() => {
|
|
4859
|
-
if (timer.current) clearTimeout(timer.current);
|
|
4860
|
-
timer.current = setTimeout(() => setDebouncedRule(rule), debounceMs);
|
|
4861
|
-
return () => {
|
|
4862
|
-
if (timer.current) clearTimeout(timer.current);
|
|
4863
|
-
};
|
|
4864
|
-
}, [rule, debounceMs]);
|
|
4865
|
-
const valid = isRuleValid(debouncedRule);
|
|
4866
|
-
const query = useQuery({
|
|
4867
|
-
queryKey: ["records-admin", "preview-rule", collectionId, appId, debouncedRule, limit],
|
|
4868
|
-
enabled: enabled && !!collectionId && !!appId && valid,
|
|
4869
|
-
staleTime: 3e4,
|
|
4870
|
-
queryFn: () => SL.app.records.previewRule(collectionId, appId, {
|
|
4871
|
-
facetRule: debouncedRule,
|
|
4872
|
-
limit
|
|
4873
|
-
})
|
|
4874
|
-
});
|
|
4875
|
-
return {
|
|
4876
|
-
totalMatches: query.data?.totalMatches ?? null,
|
|
4877
|
-
sampleProductIds: query.data?.sampleProductIds ?? [],
|
|
4878
|
-
isLoading: query.isFetching,
|
|
4879
|
-
isStale: rule !== debouncedRule,
|
|
4880
|
-
error: query.error ?? null
|
|
4881
|
-
};
|
|
4882
|
-
}
|
|
4883
5260
|
var DEFAULT_SCOPES2 = ["batch", "variant", "product", "facet"];
|
|
4884
5261
|
var readField = (data, path) => {
|
|
4885
5262
|
if (data == null || typeof data !== "object") return void 0;
|