@proveanything/smartlinks-utils-ui 0.9.7 → 0.9.9
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/components/AssetPicker/index.css +18 -0
- package/dist/components/AssetPicker/index.css.map +1 -1
- package/dist/components/ConditionsEditor/index.css +18 -0
- package/dist/components/ConditionsEditor/index.css.map +1 -1
- package/dist/components/FontPicker/index.css +18 -0
- package/dist/components/FontPicker/index.css.map +1 -1
- package/dist/components/IconPicker/index.css +18 -0
- package/dist/components/IconPicker/index.css.map +1 -1
- package/dist/components/RecordsAdmin/index.css +18 -0
- package/dist/components/RecordsAdmin/index.css.map +1 -1
- package/dist/components/RecordsAdmin/index.d.ts +27 -2
- package/dist/components/RecordsAdmin/index.js +108 -58
- package/dist/components/RecordsAdmin/index.js.map +1 -1
- package/dist/index.css +18 -0
- package/dist/index.css.map +1 -1
- package/package.json +1 -1
|
@@ -1235,6 +1235,14 @@ interface Props$a<T> {
|
|
|
1235
1235
|
headerLabel?: string;
|
|
1236
1236
|
/** Optional subtitle shown beneath `headerLabel` (e.g. facet name). */
|
|
1237
1237
|
headerSubtitle?: string;
|
|
1238
|
+
/**
|
|
1239
|
+
* Optional content rendered at the very start of the header's left
|
|
1240
|
+
* cluster, before the title/breadcrumb. Used by the shell to embed the
|
|
1241
|
+
* collection-mode `EditorItemNav` (Back / position / arrows) inline so
|
|
1242
|
+
* it shares the row with the Global / scope chip instead of consuming
|
|
1243
|
+
* its own strip above the editor.
|
|
1244
|
+
*/
|
|
1245
|
+
headerLeading?: ReactNode;
|
|
1238
1246
|
/**
|
|
1239
1247
|
* Optional technical reference (e.g. productId / SKU) shown as a tiny muted
|
|
1240
1248
|
* caption pinned to the top-right of the header. Power users can scan it
|
|
@@ -1259,7 +1267,7 @@ interface Props$a<T> {
|
|
|
1259
1267
|
/** Host-provided icons rendered before save / discard / delete labels. */
|
|
1260
1268
|
actionIcons?: Partial<Record<RecordsAdminActionKey, RecordsAdminActionIcon>>;
|
|
1261
1269
|
}
|
|
1262
|
-
declare function RecordEditor<T>({ ctx, i18n, children, preview, targeting, targetingControl, bulkActions, footerExtra, onBeforeDelete, headerLabel, headerSubtitle, headerMeta, clipboard, actionLabels, actionIcons, }: Props$a<T>): react_jsx_runtime.JSX.Element;
|
|
1270
|
+
declare function RecordEditor<T>({ ctx, i18n, children, preview, targeting, targetingControl, bulkActions, footerExtra, onBeforeDelete, headerLabel, headerSubtitle, headerMeta, headerLeading, clipboard, actionLabels, actionIcons, }: Props$a<T>): react_jsx_runtime.JSX.Element;
|
|
1263
1271
|
|
|
1264
1272
|
interface InheritanceCtx {
|
|
1265
1273
|
parentValue?: Record<string, unknown> | null;
|
|
@@ -1897,6 +1905,16 @@ interface UseScopeCountsResult {
|
|
|
1897
1905
|
error: Error | null;
|
|
1898
1906
|
/** True when we hit `maxRecords` and stopped paginating. */
|
|
1899
1907
|
truncated: boolean;
|
|
1908
|
+
/**
|
|
1909
|
+
* Set of distinct `productId`s observed across the scanned records.
|
|
1910
|
+
* Used by the rail to:
|
|
1911
|
+
* • surface "X products configured" as the Products tab badge
|
|
1912
|
+
* (consistent with Global/Rules counts — never catalogue size);
|
|
1913
|
+
* • sort configured products to the top of the browse rail;
|
|
1914
|
+
* • back the Configured/Not-configured filter pills.
|
|
1915
|
+
* Lower bound when `truncated` is true.
|
|
1916
|
+
*/
|
|
1917
|
+
productIds: ReadonlySet<string>;
|
|
1900
1918
|
}
|
|
1901
1919
|
declare const useScopeCounts: (args: UseScopeCountsArgs) => UseScopeCountsResult;
|
|
1902
1920
|
/** React Query key factory for cache invalidation from save/delete sites. */
|
|
@@ -2283,8 +2301,15 @@ interface Props$1 {
|
|
|
2283
2301
|
canPrev: boolean;
|
|
2284
2302
|
canNext: boolean;
|
|
2285
2303
|
i18n: Pick<RecordsAdminI18n, 'backToList' | 'prevItem' | 'nextItem'>;
|
|
2304
|
+
/**
|
|
2305
|
+
* When true, render without the row-level border/background/padding so
|
|
2306
|
+
* the nav can sit inline inside another header strip (the shell embeds
|
|
2307
|
+
* it in `RecordEditor`'s header to avoid a dedicated row of whitespace
|
|
2308
|
+
* above the editor).
|
|
2309
|
+
*/
|
|
2310
|
+
embedded?: boolean;
|
|
2286
2311
|
}
|
|
2287
|
-
declare const EditorItemNav: ({ label, position, total, onBack, onPrev, onNext, canPrev, canNext, i18n, }: Props$1) => react_jsx_runtime.JSX.Element;
|
|
2312
|
+
declare const EditorItemNav: ({ label, position, total, onBack, onPrev, onNext, canPrev, canNext, i18n, embedded, }: Props$1) => react_jsx_runtime.JSX.Element;
|
|
2288
2313
|
|
|
2289
2314
|
interface Props<T> {
|
|
2290
2315
|
items: RecordSummary<T>[];
|
|
@@ -531,14 +531,20 @@ var useScopeCounts = (args) => {
|
|
|
531
531
|
rule: 0,
|
|
532
532
|
all: 0
|
|
533
533
|
};
|
|
534
|
-
|
|
534
|
+
const productIds = /* @__PURE__ */ new Set();
|
|
535
|
+
for (const rec of records) {
|
|
536
|
+
counts[classify(rec)] += 1;
|
|
537
|
+
const pid = rec.productId ?? void 0;
|
|
538
|
+
if (pid) productIds.add(pid);
|
|
539
|
+
}
|
|
535
540
|
counts.all = records.length;
|
|
536
541
|
return {
|
|
537
542
|
counts,
|
|
538
543
|
total: records.length,
|
|
539
544
|
isLoading: query.isLoading,
|
|
540
545
|
error: query.error ?? null,
|
|
541
|
-
truncated
|
|
546
|
+
truncated,
|
|
547
|
+
productIds
|
|
542
548
|
};
|
|
543
549
|
}, [query.data, query.isLoading, query.error]);
|
|
544
550
|
return result;
|
|
@@ -731,26 +737,15 @@ var useFacetBrowse = ({
|
|
|
731
737
|
enabled: queryEnabled,
|
|
732
738
|
staleTime: 3e4,
|
|
733
739
|
queryFn: async () => {
|
|
734
|
-
const t0 = performance.now();
|
|
735
740
|
try {
|
|
736
741
|
if (SL?.facets?.list) {
|
|
737
|
-
console.info(`${LOG} \u2192 SL.facets.list("${collectionId}", { includeValues: true })`);
|
|
738
742
|
const res = await SL.facets.list(collectionId, { includeValues: true });
|
|
739
743
|
const items = res?.items ?? [];
|
|
740
|
-
console.info(
|
|
741
|
-
`${LOG} \u2190 SL.facets.list ok in ${Math.round(performance.now() - t0)}ms \u2014 ${items.length} facet(s)`,
|
|
742
|
-
items
|
|
743
|
-
);
|
|
744
744
|
return items;
|
|
745
745
|
}
|
|
746
746
|
if (SL?.facets?.publicList) {
|
|
747
|
-
console.info(`${LOG} \u2192 SL.facets.publicList("${collectionId}", { includeValues: true })`);
|
|
748
747
|
const res = await SL.facets.publicList(collectionId, { includeValues: true });
|
|
749
748
|
const items = res?.items ?? [];
|
|
750
|
-
console.info(
|
|
751
|
-
`${LOG} \u2190 SL.facets.publicList ok in ${Math.round(performance.now() - t0)}ms \u2014 ${items.length} facet(s)`,
|
|
752
|
-
items
|
|
753
|
-
);
|
|
754
749
|
return items;
|
|
755
750
|
}
|
|
756
751
|
console.warn(`${LOG} queryFn ran but no facets API is available on SL`);
|
|
@@ -767,7 +762,6 @@ var useFacetBrowse = ({
|
|
|
767
762
|
if (signature === lastLoggedRef.current) return;
|
|
768
763
|
lastLoggedRef.current = signature;
|
|
769
764
|
if (!enabled) {
|
|
770
|
-
console.info(`${LOG} skipped \u2014 enabled=false (shell not on facet tab yet)`);
|
|
771
765
|
return;
|
|
772
766
|
}
|
|
773
767
|
if (!collectionId) {
|
|
@@ -781,9 +775,6 @@ var useFacetBrowse = ({
|
|
|
781
775
|
);
|
|
782
776
|
return;
|
|
783
777
|
}
|
|
784
|
-
console.info(
|
|
785
|
-
`${LOG} will fetch facets for collection "${collectionId}" via ${hasAdminList ? "SL.facets.list (admin)" : "SL.facets.publicList (fallback)"}`
|
|
786
|
-
);
|
|
787
778
|
}, [enabled, collectionId, hasAdminList, hasPublicList, hasAnyList, SL]);
|
|
788
779
|
const mergedItems = useMemo(() => {
|
|
789
780
|
const existingByAnchor = new Map(
|
|
@@ -2158,6 +2149,13 @@ var useShellDeepLink = (args) => {
|
|
|
2158
2149
|
}
|
|
2159
2150
|
setPendingDeepLinkRecordId(recordId ?? null);
|
|
2160
2151
|
if (recordId) preserveInitialRecordIdRef.current = true;
|
|
2152
|
+
if (recordId) {
|
|
2153
|
+
console.info("[RecordsAdminShell] deep-link restore \u2014 pending recordId set", {
|
|
2154
|
+
recordId,
|
|
2155
|
+
scope: scope ?? null,
|
|
2156
|
+
view: view ?? null
|
|
2157
|
+
});
|
|
2158
|
+
}
|
|
2161
2159
|
if (!recordId && selectedItemId !== null) {
|
|
2162
2160
|
console.info("[RecordsAdminShell] preserving selected item during restore without recordId", {
|
|
2163
2161
|
selectedItemId,
|
|
@@ -2183,7 +2181,9 @@ var useShellDeepLink = (args) => {
|
|
|
2183
2181
|
warnedMissingRef.current.add(pending);
|
|
2184
2182
|
console.warn("[RecordsAdminShell] deep-linked recordId not found in collection items \u2014 clearing pending selection", {
|
|
2185
2183
|
recordId: pending,
|
|
2186
|
-
scope: editingScope?.raw ?? null
|
|
2184
|
+
scope: editingScope?.raw ?? null,
|
|
2185
|
+
collectionItemsCount: collectionItems.items.length,
|
|
2186
|
+
sampleIds: collectionItems.items.slice(0, 5).map((it) => ({ id: it.id, itemId: it.itemId }))
|
|
2187
2187
|
});
|
|
2188
2188
|
}
|
|
2189
2189
|
preserveInitialRecordIdRef.current = false;
|
|
@@ -2203,7 +2203,10 @@ var useShellDeepLink = (args) => {
|
|
|
2203
2203
|
warnedMissingRef.current.add(pending);
|
|
2204
2204
|
console.warn("[RecordsAdminShell] deep-linked recordId not found in records list \u2014 clearing pending selection", {
|
|
2205
2205
|
recordId: pending,
|
|
2206
|
-
scope: editingScope?.raw ?? null
|
|
2206
|
+
scope: editingScope?.raw ?? null,
|
|
2207
|
+
recordListCount: recordListItems.length,
|
|
2208
|
+
sampleIds: recordListItems.slice(0, 5).map((it) => it.id),
|
|
2209
|
+
activeScopeHint: "check that the shell tab matches the record's scope"
|
|
2207
2210
|
});
|
|
2208
2211
|
}
|
|
2209
2212
|
preserveInitialRecordIdRef.current = false;
|
|
@@ -4245,6 +4248,7 @@ function RecordEditor({
|
|
|
4245
4248
|
headerLabel,
|
|
4246
4249
|
headerSubtitle,
|
|
4247
4250
|
headerMeta,
|
|
4251
|
+
headerLeading,
|
|
4248
4252
|
clipboard,
|
|
4249
4253
|
actionLabels,
|
|
4250
4254
|
actionIcons
|
|
@@ -4261,7 +4265,7 @@ function RecordEditor({
|
|
|
4261
4265
|
const s = ctx.scope;
|
|
4262
4266
|
return Boolean(s?.facetId || s?.productId || s?.variantId || s?.batchId);
|
|
4263
4267
|
})();
|
|
4264
|
-
const hasLeftContent = Boolean(headerLabel) || hasBreadcrumb;
|
|
4268
|
+
const hasLeftContent = Boolean(headerLabel) || hasBreadcrumb || Boolean(headerLeading);
|
|
4265
4269
|
const hasRightContent = showInherited || showEmpty || Boolean(headerMeta) || Boolean(bulkActions) || Boolean(targetingControl);
|
|
4266
4270
|
const showHeader = hasLeftContent || hasRightContent;
|
|
4267
4271
|
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full", children: [
|
|
@@ -4271,26 +4275,29 @@ function RecordEditor({
|
|
|
4271
4275
|
className: "sticky top-0 z-40 px-5 py-3 border-b flex items-start justify-between gap-3",
|
|
4272
4276
|
style: { borderColor: "hsl(var(--ra-border))", background: "hsl(var(--ra-surface))" },
|
|
4273
4277
|
children: [
|
|
4274
|
-
/* @__PURE__ */
|
|
4275
|
-
/* @__PURE__ */ jsx(
|
|
4276
|
-
|
|
4277
|
-
|
|
4278
|
-
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
|
|
4278
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 flex items-center gap-3", children: [
|
|
4279
|
+
headerLeading && /* @__PURE__ */ jsx("div", { className: "shrink-0", children: headerLeading }),
|
|
4280
|
+
headerLabel ? /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
4281
|
+
/* @__PURE__ */ jsx(
|
|
4282
|
+
"div",
|
|
4283
|
+
{
|
|
4284
|
+
className: "text-sm font-medium truncate",
|
|
4285
|
+
style: { color: "hsl(var(--ra-text))" },
|
|
4286
|
+
title: headerLabel,
|
|
4287
|
+
children: headerLabel
|
|
4288
|
+
}
|
|
4289
|
+
),
|
|
4290
|
+
headerSubtitle && /* @__PURE__ */ jsx(
|
|
4291
|
+
"div",
|
|
4292
|
+
{
|
|
4293
|
+
className: "text-xs truncate",
|
|
4294
|
+
style: { color: "hsl(var(--ra-muted-text))" },
|
|
4295
|
+
title: headerSubtitle,
|
|
4296
|
+
children: headerSubtitle
|
|
4297
|
+
}
|
|
4298
|
+
)
|
|
4299
|
+
] }) : /* @__PURE__ */ jsx(ScopeBreadcrumb, { scope: ctx.scope })
|
|
4300
|
+
] }),
|
|
4294
4301
|
/* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2 shrink-0", children: [
|
|
4295
4302
|
showInherited && /* @__PURE__ */ jsxs(
|
|
4296
4303
|
"span",
|
|
@@ -5759,8 +5766,9 @@ var EditorItemNav = ({
|
|
|
5759
5766
|
onNext,
|
|
5760
5767
|
canPrev,
|
|
5761
5768
|
canNext,
|
|
5762
|
-
i18n
|
|
5763
|
-
|
|
5769
|
+
i18n,
|
|
5770
|
+
embedded
|
|
5771
|
+
}) => /* @__PURE__ */ jsxs("div", { className: "ra-item-nav", "data-embedded": embedded ? "true" : void 0, children: [
|
|
5764
5772
|
/* @__PURE__ */ jsxs(
|
|
5765
5773
|
"button",
|
|
5766
5774
|
{
|
|
@@ -5774,12 +5782,7 @@ var EditorItemNav = ({
|
|
|
5774
5782
|
]
|
|
5775
5783
|
}
|
|
5776
5784
|
),
|
|
5777
|
-
|
|
5778
|
-
position,
|
|
5779
|
-
" / ",
|
|
5780
|
-
total
|
|
5781
|
-
] }),
|
|
5782
|
-
/* @__PURE__ */ jsxs("div", { className: "ra-item-nav-arrows", children: [
|
|
5785
|
+
/* @__PURE__ */ jsxs("div", { className: "ra-item-nav-cluster", children: [
|
|
5783
5786
|
/* @__PURE__ */ jsx(
|
|
5784
5787
|
"button",
|
|
5785
5788
|
{
|
|
@@ -5792,6 +5795,11 @@ var EditorItemNav = ({
|
|
|
5792
5795
|
children: /* @__PURE__ */ jsx(ChevronLeft, { className: "w-4 h-4" })
|
|
5793
5796
|
}
|
|
5794
5797
|
),
|
|
5798
|
+
typeof position === "number" && typeof total === "number" && total > 0 && /* @__PURE__ */ jsxs("span", { className: "ra-item-nav-position", "aria-label": label, children: [
|
|
5799
|
+
position,
|
|
5800
|
+
" / ",
|
|
5801
|
+
total
|
|
5802
|
+
] }),
|
|
5795
5803
|
/* @__PURE__ */ jsx(
|
|
5796
5804
|
"button",
|
|
5797
5805
|
{
|
|
@@ -7665,6 +7673,7 @@ function RecordsAdminShellInner(props) {
|
|
|
7665
7673
|
const itemNav = isCollection && selectedItemId && itemPosition && ruleWizardStep === null ? /* @__PURE__ */ jsx(
|
|
7666
7674
|
EditorItemNav,
|
|
7667
7675
|
{
|
|
7676
|
+
embedded: true,
|
|
7668
7677
|
label: editorHeaderLabel,
|
|
7669
7678
|
position: itemPosition.index + 1,
|
|
7670
7679
|
total: itemPosition.total,
|
|
@@ -7717,6 +7726,7 @@ function RecordsAdminShellInner(props) {
|
|
|
7717
7726
|
headerLabel: editorHeaderLabel,
|
|
7718
7727
|
headerSubtitle: editorHeaderSubtitle,
|
|
7719
7728
|
headerMeta: editorHeaderMeta,
|
|
7729
|
+
headerLeading: itemNav,
|
|
7720
7730
|
clipboard: editorClipboard,
|
|
7721
7731
|
actionLabels,
|
|
7722
7732
|
actionIcons,
|
|
@@ -7735,10 +7745,7 @@ function RecordsAdminShellInner(props) {
|
|
|
7735
7745
|
)
|
|
7736
7746
|
}
|
|
7737
7747
|
);
|
|
7738
|
-
const withNav = (node) =>
|
|
7739
|
-
itemNav,
|
|
7740
|
-
/* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0 overflow-hidden", children: node })
|
|
7741
|
-
] }) : node;
|
|
7748
|
+
const withNav = (node) => node;
|
|
7742
7749
|
if (!previewBody) return withNav(baseEditor());
|
|
7743
7750
|
if (previewMode === "inline") {
|
|
7744
7751
|
return withNav(baseEditor(
|
|
@@ -7841,8 +7848,26 @@ function RecordsAdminShellInner(props) {
|
|
|
7841
7848
|
subtitle: pinnedProduct.item?.sku ?? void 0
|
|
7842
7849
|
}];
|
|
7843
7850
|
}
|
|
7844
|
-
|
|
7845
|
-
|
|
7851
|
+
const configured = scopeCounts.productIds;
|
|
7852
|
+
const all = productBrowse.items.map(productItemToSummary);
|
|
7853
|
+
const isConfigured = (s) => {
|
|
7854
|
+
const pid = s.scope.productId;
|
|
7855
|
+
return !!pid && configured.has(pid);
|
|
7856
|
+
};
|
|
7857
|
+
if (filter === "configured") return all.filter(isConfigured);
|
|
7858
|
+
if (filter === "empty") return all.filter((s) => !isConfigured(s));
|
|
7859
|
+
const yes = [];
|
|
7860
|
+
const no = [];
|
|
7861
|
+
for (const s of all) (isConfigured(s) ? yes : no).push(s);
|
|
7862
|
+
return [...yes, ...no];
|
|
7863
|
+
}, [
|
|
7864
|
+
productPinned,
|
|
7865
|
+
contextScope,
|
|
7866
|
+
productBrowse.items,
|
|
7867
|
+
pinnedProduct.item,
|
|
7868
|
+
scopeCounts.productIds,
|
|
7869
|
+
filter
|
|
7870
|
+
]);
|
|
7846
7871
|
const isRuleTab = activeScope === "rule";
|
|
7847
7872
|
const isGlobalTab = activeScope === "collection";
|
|
7848
7873
|
const isAllTab = activeScope === "all";
|
|
@@ -8281,10 +8306,14 @@ function RecordsAdminShellInner(props) {
|
|
|
8281
8306
|
},
|
|
8282
8307
|
loading: probe.isLoading,
|
|
8283
8308
|
counts: {
|
|
8284
|
-
//
|
|
8285
|
-
//
|
|
8286
|
-
//
|
|
8287
|
-
|
|
8309
|
+
// Products badge counts DISTINCT products that have at
|
|
8310
|
+
// least one custom record — same semantics as Global /
|
|
8311
|
+
// Rules. Catalogue size (which can be 1k–10k+) was
|
|
8312
|
+
// misleading: "Products: 247" implied 247 customised
|
|
8313
|
+
// products when in fact zero might be configured. Falls
|
|
8314
|
+
// back to a lower bound when scope-counts truncated at
|
|
8315
|
+
// the hard cap.
|
|
8316
|
+
product: scopeCounts.productIds.size,
|
|
8288
8317
|
// The remaining tabs show actual record counts so hidden
|
|
8289
8318
|
// state (e.g. a rule-scoped competition) is visible from
|
|
8290
8319
|
// any tab. `useScopeCounts` returns 0 while loading, which
|
|
@@ -8365,6 +8394,27 @@ function RecordsAdminShellInner(props) {
|
|
|
8365
8394
|
i18n
|
|
8366
8395
|
}
|
|
8367
8396
|
),
|
|
8397
|
+
isProductTab && !productPinned && (() => {
|
|
8398
|
+
const cfg = scopeCounts.productIds;
|
|
8399
|
+
let configured = 0;
|
|
8400
|
+
for (const p of productBrowse.items) if (cfg.has(p.id)) configured += 1;
|
|
8401
|
+
const total = productBrowse.items.length;
|
|
8402
|
+
return /* @__PURE__ */ jsx(
|
|
8403
|
+
StatusFilterPills,
|
|
8404
|
+
{
|
|
8405
|
+
value: filter,
|
|
8406
|
+
onChange: setFilter,
|
|
8407
|
+
counts: {
|
|
8408
|
+
all: total,
|
|
8409
|
+
configured,
|
|
8410
|
+
partial: 0,
|
|
8411
|
+
empty: total - configured
|
|
8412
|
+
},
|
|
8413
|
+
hideZero: ["partial"],
|
|
8414
|
+
i18n
|
|
8415
|
+
}
|
|
8416
|
+
);
|
|
8417
|
+
})(),
|
|
8368
8418
|
isRuleTab && /* @__PURE__ */ jsx(
|
|
8369
8419
|
RuleFilterChips,
|
|
8370
8420
|
{
|