@proveanything/smartlinks-utils-ui 0.11.1 → 0.11.3

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.
@@ -3003,7 +3003,7 @@ function useEditorBridge(args) {
3003
3003
  parentValue: resolved.parentValue ?? null,
3004
3004
  recordId: resolved.recordId
3005
3005
  },
3006
- defaultValue: defaultData?.() ?? {}
3006
+ defaultValue: target?.initialData ?? defaultData?.() ?? {}
3007
3007
  });
3008
3008
  editorIdRef.current = id;
3009
3009
  }, [target?.scope.raw, target?.recordId, target?.createMode, target?.draftKey]);
@@ -3090,6 +3090,8 @@ function useShellEditorTarget(args) {
3090
3090
  activeScope,
3091
3091
  draftKind,
3092
3092
  ruleWizardStep,
3093
+ ruleWizardDraftKey,
3094
+ ruleWizardInitialData,
3093
3095
  ruleWizardRule,
3094
3096
  resolved,
3095
3097
  defaultData,
@@ -3103,9 +3105,9 @@ function useShellEditorTarget(args) {
3103
3105
  const label = deriveDraftLabel ? deriveDraftLabel(resolved.data, editingTargetScope) : void 0;
3104
3106
  const rawScope = editingTargetScope.raw ?? "";
3105
3107
  const isDraftScope = rawScope.includes("__draft__") || rawScope.includes("item:draft:");
3106
- const draftKey = isDraftScope ? isCollection && selectedItemId && isDraftId2(selectedItemId) ? `item:${selectedItemId}` : `${activeScope}:${draftKind ?? "wizard"}` : void 0;
3108
+ const draftKey = isDraftScope ? isCollection && selectedItemId && isDraftId2(selectedItemId) ? `item:${selectedItemId}` : ruleWizardDraftKey ?? `${activeScope}:${draftKind ?? "wizard"}` : void 0;
3107
3109
  const itemDraftCreate = isCollection && !!selectedItemId && isDraftId2(selectedItemId);
3108
- const createMode = itemDraftCreate || isCollection && !!selectedItemId && !resolved.recordId;
3110
+ const createMode = itemDraftCreate || isDraftScope || isCollection && !!selectedItemId && !resolved.recordId;
3109
3111
  return {
3110
3112
  scope: editingTargetScope,
3111
3113
  // Item drafts must NOT inherit the parent rule's resolved recordId —
@@ -3125,7 +3127,8 @@ function useShellEditorTarget(args) {
3125
3127
  initialFacetRule,
3126
3128
  label,
3127
3129
  draftKey,
3128
- isDraftScope
3130
+ isDraftScope,
3131
+ initialData: createMode ? ruleWizardInitialData : void 0
3129
3132
  };
3130
3133
  }, [
3131
3134
  editingTargetScope?.raw,
@@ -3137,6 +3140,8 @@ function useShellEditorTarget(args) {
3137
3140
  activeScope,
3138
3141
  draftKind,
3139
3142
  ruleWizardStep,
3143
+ ruleWizardDraftKey,
3144
+ ruleWizardInitialData,
3140
3145
  ruleWizardRule
3141
3146
  ]);
3142
3147
  const editorCtx = useEditorBridge({
@@ -3165,6 +3170,8 @@ var useShellSelection = (args) => {
3165
3170
  const [draftKind, setDraftKind] = useState(null);
3166
3171
  const [ruleWizardStep, setRuleWizardStep] = useState(null);
3167
3172
  const [ruleWizardRule, setRuleWizardRule] = useState(null);
3173
+ const [ruleWizardSeedMode, setRuleWizardSeedMode] = useState(null);
3174
+ const [ruleWizardDraftKey, setRuleWizardDraftKey] = useState(null);
3168
3175
  const [selectedProductId, setSelectedProductId] = useState(
3169
3176
  contextScope?.productId
3170
3177
  );
@@ -3211,6 +3218,10 @@ var useShellSelection = (args) => {
3211
3218
  setRuleWizardStep,
3212
3219
  ruleWizardRule,
3213
3220
  setRuleWizardRule,
3221
+ ruleWizardSeedMode,
3222
+ setRuleWizardSeedMode,
3223
+ ruleWizardDraftKey,
3224
+ setRuleWizardDraftKey,
3214
3225
  selectedProductId,
3215
3226
  setSelectedProductId,
3216
3227
  drillTab,
@@ -6663,6 +6674,10 @@ function NewRuleWizard({
6663
6674
  onCancel,
6664
6675
  onNext,
6665
6676
  onBack,
6677
+ canChooseSeed = false,
6678
+ seedMode = null,
6679
+ onSeedModeChange,
6680
+ facets,
6666
6681
  children,
6667
6682
  itemNoun = "record"
6668
6683
  }) {
@@ -6680,16 +6695,57 @@ function NewRuleWizard({
6680
6695
  onCancel
6681
6696
  }
6682
6697
  ),
6683
- /* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0 overflow-auto px-5 py-4", children: /* @__PURE__ */ jsx(
6684
- FacetRuleEditor,
6685
- {
6686
- value: rule,
6687
- onChange: onRuleChange,
6688
- collectionId,
6689
- preview,
6690
- description: "The new rule will apply to every product whose facets match every clause below."
6691
- }
6692
- ) }),
6698
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-h-0 overflow-auto px-5 py-4", children: [
6699
+ /* @__PURE__ */ jsx(
6700
+ FacetRuleEditor,
6701
+ {
6702
+ value: rule,
6703
+ onChange: onRuleChange,
6704
+ facets,
6705
+ collectionId,
6706
+ preview,
6707
+ description: "The new rule will apply to every product whose facets match every clause below."
6708
+ }
6709
+ ),
6710
+ canChooseSeed && /* @__PURE__ */ jsxs(
6711
+ "div",
6712
+ {
6713
+ className: "mt-4 rounded-lg border p-3",
6714
+ style: {
6715
+ borderColor: "hsl(var(--ra-border))",
6716
+ background: "hsl(var(--ra-surface))"
6717
+ },
6718
+ children: [
6719
+ /* @__PURE__ */ jsxs("div", { className: "mb-2", children: [
6720
+ /* @__PURE__ */ jsx("div", { className: "text-sm font-semibold", style: { color: "hsl(var(--ra-text))" }, children: "Start from" }),
6721
+ /* @__PURE__ */ jsx("div", { className: "text-xs", style: { color: "hsl(var(--ra-muted-text))" }, children: "Choose whether the new rule starts empty or copies the current global record." })
6722
+ ] }),
6723
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
6724
+ /* @__PURE__ */ jsx(
6725
+ "button",
6726
+ {
6727
+ type: "button",
6728
+ className: "ra-btn",
6729
+ "data-variant": seedMode !== "global" ? "primary" : "ghost",
6730
+ onClick: () => onSeedModeChange?.("blank"),
6731
+ children: "Start blank"
6732
+ }
6733
+ ),
6734
+ /* @__PURE__ */ jsx(
6735
+ "button",
6736
+ {
6737
+ type: "button",
6738
+ className: "ra-btn",
6739
+ "data-variant": seedMode === "global" ? "primary" : "ghost",
6740
+ onClick: () => onSeedModeChange?.("global"),
6741
+ children: "Copy from global"
6742
+ }
6743
+ )
6744
+ ] })
6745
+ ]
6746
+ }
6747
+ )
6748
+ ] }),
6693
6749
  /* @__PURE__ */ jsx(
6694
6750
  WizardFooter,
6695
6751
  {
@@ -7930,6 +7986,10 @@ function RecordsAdminShellInner(props) {
7930
7986
  setRuleWizardStep,
7931
7987
  ruleWizardRule,
7932
7988
  setRuleWizardRule,
7989
+ ruleWizardSeedMode,
7990
+ setRuleWizardSeedMode,
7991
+ ruleWizardDraftKey,
7992
+ setRuleWizardDraftKey,
7933
7993
  selectedProductId,
7934
7994
  setSelectedProductId,
7935
7995
  drillTab,
@@ -7946,6 +8006,10 @@ function RecordsAdminShellInner(props) {
7946
8006
  } = selection;
7947
8007
  const [isReconcilingRecordSelection, setIsReconcilingRecordSelection] = useState(false);
7948
8008
  const { dismissed, dismiss, undismiss } = useIntroDismissed(SL, collectionId, appId, recordType);
8009
+ const mintRuleWizardDraftKey = useCallback(
8010
+ () => `rule-wizard:${typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`}`,
8011
+ []
8012
+ );
7949
8013
  const headerWillRender = useMemo(() => {
7950
8014
  const headerCustomised = !!title || !!subtitle || !!headerIcon || !!headerActions || showStats || !!statsItems || !!statsTitle || !!statsIcon || !!helpUrl;
7951
8015
  return showHeader === true || showHeader !== false && headerCustomised;
@@ -8146,6 +8210,22 @@ function RecordsAdminShellInner(props) {
8146
8210
  supportedScopes: supportedForResolution,
8147
8211
  enabled: !!editingTargetScope
8148
8212
  });
8213
+ const globalSourceRecord = useMemo(
8214
+ () => recordList.items.find((it) => !it.scope.productId && !it.scope.facetId && !it.scope.variantId && !it.scope.batchId && !it.scope.proofId && !it.facetRule),
8215
+ [recordList.items]
8216
+ );
8217
+ const ruleWizardInitialData = useMemo(() => {
8218
+ if (ruleWizardSeedMode !== "global") return void 0;
8219
+ if (!globalSourceRecord?.data) return defaultData?.();
8220
+ if (onCopyOverride) {
8221
+ return onCopyOverride({ value: globalSourceRecord.data, scope: globalSourceRecord.scope });
8222
+ }
8223
+ try {
8224
+ return structuredClone(globalSourceRecord.data);
8225
+ } catch {
8226
+ return JSON.parse(JSON.stringify(globalSourceRecord.data));
8227
+ }
8228
+ }, [ruleWizardSeedMode, globalSourceRecord, onCopyOverride, defaultData]);
8149
8229
  const refetchAll = useCallback(async () => {
8150
8230
  await Promise.all([
8151
8231
  recordList.refetch(),
@@ -8162,6 +8242,8 @@ function RecordsAdminShellInner(props) {
8162
8242
  activeScope,
8163
8243
  draftKind,
8164
8244
  ruleWizardStep,
8245
+ ruleWizardDraftKey,
8246
+ ruleWizardInitialData,
8165
8247
  ruleWizardRule,
8166
8248
  resolved: {
8167
8249
  data: resolved.data,
@@ -8175,12 +8257,15 @@ function RecordsAdminShellInner(props) {
8175
8257
  deriveDraftLabel,
8176
8258
  onSaved: async (isCreate, savedRecordId) => {
8177
8259
  onTelemetry?.({ type: "record.save", recordType, ref: editingTargetScope?.raw ?? "", isCreate });
8178
- if (ruleWizardStep !== null) {
8260
+ const savedFromRuleWizard = ruleWizardStep !== null;
8261
+ if (savedFromRuleWizard) {
8179
8262
  setRuleWizardStep(null);
8180
8263
  setRuleWizardRule(null);
8264
+ setRuleWizardSeedMode(null);
8265
+ setRuleWizardDraftKey(null);
8181
8266
  setDraftKind(null);
8182
8267
  }
8183
- if (isCreate && selectedRecordId === DRAFT_ID3) {
8268
+ if (isCreate && selectedRecordId === DRAFT_ID3 && !(savedFromRuleWizard && !isCollection && savedRecordId)) {
8184
8269
  setIsReconcilingRecordSelection(true);
8185
8270
  setSelectedRecordId(null);
8186
8271
  setDraftKind(null);
@@ -8188,6 +8273,9 @@ function RecordsAdminShellInner(props) {
8188
8273
  if (isCreate && isCollection && savedRecordId && isDraftId3(selectedItemId)) {
8189
8274
  setSelectedItemId(savedRecordId);
8190
8275
  }
8276
+ if (savedFromRuleWizard && !isCollection && savedRecordId) {
8277
+ setSelectedRecordId(savedRecordId);
8278
+ }
8191
8279
  if (!isCollection && isCreate && activeScope === "collection") {
8192
8280
  setSelectedRecordId(savedRecordId ?? null);
8193
8281
  }
@@ -8700,30 +8788,36 @@ function RecordsAdminShellInner(props) {
8700
8788
  setSelectedRecordId(null);
8701
8789
  setSelectedItemId(null);
8702
8790
  setDraftKind("rule");
8791
+ setRuleWizardSeedMode("blank");
8792
+ setRuleWizardDraftKey(null);
8703
8793
  setRuleWizardRule({ all: [] });
8704
8794
  setRuleWizardStep(1);
8705
8795
  });
8706
- }, [runWithGuard, activeScope]);
8796
+ }, [runWithGuard, activeScope, setRuleWizardSeedMode, setRuleWizardDraftKey]);
8707
8797
  const onCancelRuleWizard = useCallback(() => {
8708
8798
  setRuleWizardStep(null);
8709
8799
  setRuleWizardRule(null);
8800
+ setRuleWizardSeedMode(null);
8801
+ setRuleWizardDraftKey(null);
8710
8802
  setSelectedRecordId(null);
8711
8803
  setSelectedItemId(null);
8712
8804
  setDraftKind(null);
8713
- }, []);
8805
+ }, [setRuleWizardSeedMode, setRuleWizardDraftKey]);
8714
8806
  const onRuleWizardNext = useCallback(() => {
8715
8807
  if (cardinality === "collection") {
8716
8808
  setRuleWizardStep(2);
8717
8809
  } else {
8718
8810
  setRuleWizardStep(2);
8811
+ setRuleWizardDraftKey(mintRuleWizardDraftKey());
8719
8812
  setSelectedRecordId(DRAFT_ID3);
8720
8813
  }
8721
- }, [cardinality]);
8814
+ }, [cardinality, mintRuleWizardDraftKey]);
8722
8815
  const onRuleWizardBack = useCallback(() => {
8723
8816
  setRuleWizardStep(1);
8817
+ setRuleWizardDraftKey(null);
8724
8818
  setSelectedRecordId(null);
8725
8819
  setSelectedItemId(null);
8726
- }, []);
8820
+ }, [setRuleWizardDraftKey]);
8727
8821
  const onRuleWizardCreateItem = useCallback(() => {
8728
8822
  if (!isCollection) return;
8729
8823
  const id = coerceDraftItemId2(generateItemId);
@@ -8795,15 +8889,27 @@ function RecordsAdminShellInner(props) {
8795
8889
  const vocab = facetBrowse.vocabulary ?? [];
8796
8890
  if (!vocab.length) return [];
8797
8891
  const out = [];
8892
+ const seen = /* @__PURE__ */ new Set();
8798
8893
  for (const facet of vocab) {
8799
8894
  const key = facet.key;
8800
8895
  if (!key) continue;
8801
- const values = (facet.values ?? []).filter((v) => !!v.key).map((v) => ({ key: v.key, label: v.name ?? v.key }));
8896
+ const dedupeKey = key.trim().toLowerCase();
8897
+ if (seen.has(dedupeKey)) continue;
8898
+ seen.add(dedupeKey);
8899
+ const values = (facet.values ?? []).filter((v) => !!v.key).map((v) => ({
8900
+ key: v.key,
8901
+ label: v.name ?? ruleLabelLookup.valueLabel?.(key, v.key) ?? v.key
8902
+ }));
8802
8903
  if (!values.length) continue;
8803
- out.push({ key, label: facet.name ?? key, values });
8904
+ out.push({ key, label: facet.name ?? ruleLabelLookup.facetLabel?.(key) ?? key, values });
8804
8905
  }
8805
8906
  return out;
8806
- }, [facetBrowse.vocabulary]);
8907
+ }, [facetBrowse.vocabulary, ruleLabelLookup]);
8908
+ const ruleWizardFacets = useMemo(() => facetBrowseFacets.map((facet) => ({
8909
+ key: facet.key,
8910
+ name: facet.label ?? facet.key,
8911
+ values: facet.values.map((value) => ({ key: value.key, name: value.label ?? value.key }))
8912
+ })), [facetBrowseFacets]);
8807
8913
  const collectionGlobalAllRow = useMemo(
8808
8914
  () => ({
8809
8915
  id: null,
@@ -8922,6 +9028,8 @@ function RecordsAdminShellInner(props) {
8922
9028
  if (ruleWizardStep !== null) {
8923
9029
  setRuleWizardStep(null);
8924
9030
  setRuleWizardRule(null);
9031
+ setRuleWizardSeedMode(null);
9032
+ setRuleWizardDraftKey(null);
8925
9033
  }
8926
9034
  }
8927
9035
  });
@@ -9320,6 +9428,10 @@ function RecordsAdminShellInner(props) {
9320
9428
  onCancel: onCancelRuleWizard,
9321
9429
  onNext: onRuleWizardNext,
9322
9430
  onBack: onRuleWizardBack,
9431
+ canChooseSeed: !isCollection && !!globalSourceRecord,
9432
+ seedMode: ruleWizardSeedMode,
9433
+ onSeedModeChange: setRuleWizardSeedMode,
9434
+ facets: ruleWizardFacets,
9323
9435
  itemNoun,
9324
9436
  children: [
9325
9437
  ruleWizardStep === 2 && !isCollection && editingTargetScope && renderEditorWithPreview(),