@proveanything/smartlinks-utils-ui 0.3.11 → 0.3.13

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.
@@ -70,17 +70,26 @@ var getRecordByRef = async (ctx, ref) => {
70
70
  };
71
71
  var upsertRecord = async (ctx, write) => {
72
72
  const ref = write.ref ?? deriveRefFromScope(write.scope);
73
- const res = await ctx.SL.app.records.upsert(ctx.collectionId, ctx.appId, {
73
+ const payload = {
74
74
  ref,
75
75
  ...ctx.recordType ? { recordType: ctx.recordType } : {},
76
- scope: write.scope,
77
76
  data: write.data,
78
77
  status: write.status,
79
78
  startsAt: write.startsAt,
80
79
  expiresAt: write.expiresAt,
81
80
  customId: write.customId,
82
81
  sourceSystem: write.sourceSystem
83
- });
82
+ };
83
+ if (write.facetRule && write.facetRule.all && write.facetRule.all.length > 0) {
84
+ payload.facetRule = write.facetRule;
85
+ } else {
86
+ payload.scope = write.scope;
87
+ }
88
+ const res = await ctx.SL.app.records.upsert(
89
+ ctx.collectionId,
90
+ ctx.appId,
91
+ payload
92
+ );
84
93
  return { record: res, isCreate: !!res?.created };
85
94
  };
86
95
  var upsertRecordForScope = async (ctx, scope, data, extra = {}) => upsertRecord(ctx, {
@@ -168,5 +177,5 @@ var deriveRefFromScope = (scope) => {
168
177
  };
169
178
 
170
179
  export { bulkDelete, bulkUpsert, deleteRecord, getRecordByRef, listRecords, matchRecords, parsedRefToScope, parsedRefToTarget, restoreRecord, scopesEqual, upsertRecord, upsertRecordForScope };
171
- //# sourceMappingURL=chunk-TY2UIZ24.js.map
172
- //# sourceMappingURL=chunk-TY2UIZ24.js.map
180
+ //# sourceMappingURL=chunk-76Y4UTYQ.js.map
181
+ //# sourceMappingURL=chunk-76Y4UTYQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/RecordsAdmin/data/scopeBridge.ts","../src/components/RecordsAdmin/data/records.ts"],"names":[],"mappings":"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","file":"chunk-76Y4UTYQ.js","sourcesContent":["// =============================================================================\r\n// scopeBridge — Convert between our UI `ParsedRef` and the SDK `RecordScope`.\r\n//\r\n// Our `ParsedRef` is a UI-friendly flat object that round-trips with the\r\n// `kind:id/kind:id` URL refs. The SDK's `RecordScope` is the structured\r\n// canonical form used for server-side specificity & `match()`. Use these\r\n// helpers at every boundary so we never write a record without `scope`.\r\n// =============================================================================\r\nimport type { RecordScope, RecordTarget } from './sdkTypes';\r\nimport type { ParsedRef } from '../types';\r\n\r\nexport const parsedRefToScope = (ref: ParsedRef): RecordScope => {\r\n const scope: RecordScope = {};\r\n if (ref.productId) scope.productId = ref.productId;\r\n if (ref.variantId) scope.variantId = ref.variantId;\r\n if (ref.batchId) scope.batchId = ref.batchId;\r\n if (ref.proofId) scope.proofId = ref.proofId;\r\n if (ref.facetId) {\r\n scope.facets = [{\r\n key: ref.facetId,\r\n valueKeys: ref.facetValue ? [ref.facetValue] : [],\r\n }];\r\n }\r\n return scope;\r\n};\r\n\r\nexport const parsedRefToTarget = (ref: ParsedRef): RecordTarget => {\r\n const target: RecordTarget = {};\r\n if (ref.productId) target.productId = ref.productId;\r\n if (ref.variantId) target.variantId = ref.variantId;\r\n if (ref.batchId) target.batchId = ref.batchId;\r\n if (ref.proofId) target.proofId = ref.proofId;\r\n if (ref.facetId && ref.facetValue) {\r\n target.facets = { [ref.facetId]: [ref.facetValue] };\r\n }\r\n return target;\r\n};\r\n\r\n/**\r\n * Compare a winning record's scope against the editing scope.\r\n * Returns true when they refer to the same node — used to decide\r\n * \"self\" vs \"inherited\" when consuming `match()` results.\r\n */\r\nexport const scopesEqual = (a: RecordScope, b: RecordScope): boolean => {\r\n if ((a.productId ?? null) !== (b.productId ?? null)) return false;\r\n if ((a.variantId ?? null) !== (b.variantId ?? null)) return false;\r\n if ((a.batchId ?? null) !== (b.batchId ?? null)) return false;\r\n if ((a.proofId ?? null) !== (b.proofId ?? null)) return false;\r\n const af = a.facets ?? [];\r\n const bf = b.facets ?? [];\r\n if (af.length !== bf.length) return false;\r\n const norm = (xs: typeof af) => xs\r\n .map((f) => `${f.key}:${[...f.valueKeys].sort().join(',')}`)\r\n .sort()\r\n .join('|');\r\n return norm(af) === norm(bf);\r\n};","// =============================================================================\r\n// Thin wrappers over SL.app.records.* — always admin: true here.\r\n//\r\n// As of `@proveanything/smartlinks` 1.9.0 the records surface ships a proper\r\n// `upsert()`, server-side `match()`, and atomic `bulkUpsert` / `bulkDelete`.\r\n// We delegate to those rather than rolling our own list+update sequences,\r\n// which were racy and ignored facet AND-of-OR semantics.\r\n// =============================================================================\r\nimport type {\r\n AppRecord, RecordScope, RecordTarget, BulkUpsertItem, BulkDeleteResult,\r\n MatchResult, FacetRule,\r\n} from './sdkTypes';\r\nimport type { ParsedRef, SmartLinksSDK } from '../types';\r\nimport { parsedRefToScope } from './scopeBridge';\r\n\r\nexport interface RecordsCtx {\r\n SL: SmartLinksSDK;\r\n collectionId: string;\r\n appId: string;\r\n /** Optional — when omitted, records are stored against the app id alone\r\n * (no type qualifier). Set this only when an app uses multiple record types\r\n * and needs to query/scope by type. */\r\n recordType?: string;\r\n}\r\n\r\n/** Shape of a single record write — uses the SDK's structured `scope`. */\r\nexport interface RecordWrite<T = unknown> {\r\n /** Logical key. The server canonicalises this from `scope` if omitted. */\r\n ref?: string;\r\n /** Structured scope; required for specificity / `match()` to work. */\r\n scope: RecordScope;\r\n data: T;\r\n visibility?: 'public' | 'owner' | 'admin';\r\n productId?: string;\r\n status?: string;\r\n startsAt?: string | null;\r\n expiresAt?: string | null;\r\n customId?: string;\r\n sourceSystem?: string;\r\n /**\r\n * Optional facet rule. When set, the record is targeted via this rule and\r\n * `scope` should be empty (the SDK enforces mutual exclusion). Used by\r\n * the rule editor / Targeting section.\r\n */\r\n facetRule?: FacetRule | null;\r\n}\r\n\r\nexport const listRecords = async (\r\n ctx: RecordsCtx,\r\n params: { ref?: string; refPrefix?: string; q?: string; limit?: number; offset?: number; sort?: string } = {},\r\n): Promise<{ data: AppRecord[]; total: number; hasMore: boolean }> => {\r\n const { limit = 100, offset, ref, refPrefix, q, sort } = params;\r\n const res = await ctx.SL.app.records.list(\r\n ctx.collectionId,\r\n ctx.appId,\r\n {\r\n ...(ctx.recordType ? { recordType: ctx.recordType } : {}),\r\n limit, offset, ref, refPrefix, q, sort,\r\n },\r\n true,\r\n );\r\n return {\r\n data: res?.data ?? [],\r\n total: res?.pagination?.total ?? (res?.data?.length ?? 0),\r\n hasMore: res?.pagination?.hasMore ?? false,\r\n };\r\n};\r\n\r\n/** Look up a single record by its canonical ref. */\r\nexport const getRecordByRef = async (\r\n ctx: RecordsCtx,\r\n ref: string,\r\n): Promise<AppRecord | null> => {\r\n const res = await ctx.SL.app.records.list(\r\n ctx.collectionId,\r\n ctx.appId,\r\n { ...(ctx.recordType ? { recordType: ctx.recordType } : {}), ref, limit: 1 },\r\n true,\r\n );\r\n return res?.data?.[0] ?? null;\r\n};\r\n\r\n/**\r\n * Atomic upsert via the SDK. Always sends `scope` so the server can compute\r\n * `specificity` and derive `ref` deterministically.\r\n */\r\nexport const upsertRecord = async <T,>(\r\n ctx: RecordsCtx,\r\n write: RecordWrite<T>,\r\n): Promise<{ record: AppRecord; isCreate: boolean }> => {\r\n const ref = write.ref ?? deriveRefFromScope(write.scope);\r\n const payload: Record<string, unknown> = {\r\n ref,\r\n ...(ctx.recordType ? { recordType: ctx.recordType } : {}),\r\n data: write.data as Record<string, unknown>,\r\n status: write.status,\r\n startsAt: write.startsAt,\r\n expiresAt: write.expiresAt,\r\n customId: write.customId,\r\n sourceSystem: write.sourceSystem,\r\n };\r\n // SDK 1.10 enforces mutual exclusion between `scope` and `facetRule`. Send\r\n // exactly one. When a rule is supplied the server resolves matches against\r\n // it; otherwise the structured scope drives specificity.\r\n if (write.facetRule && write.facetRule.all && write.facetRule.all.length > 0) {\r\n payload.facetRule = write.facetRule;\r\n } else {\r\n payload.scope = write.scope;\r\n }\r\n const res = await ctx.SL.app.records.upsert(\r\n ctx.collectionId, ctx.appId, payload as Parameters<typeof ctx.SL.app.records.upsert>[2],\r\n );\r\n return { record: res, isCreate: !!res?.created };\r\n};\r\n\r\n/**\r\n * Convenience wrapper for callers that only have a `ParsedRef` and a payload —\r\n * matches the previous (`ref`, `data`) call shape used by the editor hook.\r\n */\r\nexport const upsertRecordForScope = async <T,>(\r\n ctx: RecordsCtx,\r\n scope: ParsedRef,\r\n data: T,\r\n extra: { visibility?: 'public' | 'owner' | 'admin' } = {},\r\n) => upsertRecord<T>(ctx, {\r\n ref: scope.raw || undefined,\r\n scope: parsedRefToScope(scope),\r\n data,\r\n visibility: extra.visibility,\r\n});\r\n\r\nexport const deleteRecord = async (\r\n ctx: RecordsCtx,\r\n ref: string,\r\n): Promise<boolean> => {\r\n const existing = await getRecordByRef(ctx, ref).catch(() => null);\r\n if (!existing) return false;\r\n await ctx.SL.app.records.remove(ctx.collectionId, ctx.appId, existing.id, true);\r\n return true;\r\n};\r\n\r\n/** Restore a soft-deleted record by ID (admin only). */\r\nexport const restoreRecord = async (\r\n ctx: RecordsCtx,\r\n recordId: string,\r\n): Promise<AppRecord> => ctx.SL.app.records.restore(ctx.collectionId, ctx.appId, recordId);\r\n\r\n/**\r\n * Server-side match — single round trip that returns every record whose\r\n * `scope` is satisfied by `target`, ordered by descending `specificity`.\r\n * Replaces the per-scope N+1 chain walk we used pre-1.9.\r\n */\r\nexport const matchRecords = async (\r\n ctx: RecordsCtx,\r\n target: RecordTarget,\r\n opts: {\r\n strategy?: 'all' | 'best';\r\n at?: string;\r\n includeScheduled?: boolean;\r\n includeExpired?: boolean;\r\n limit?: number;\r\n } = {},\r\n): Promise<MatchResult> => ctx.SL.app.records.match(\r\n ctx.collectionId,\r\n ctx.appId,\r\n {\r\n target,\r\n ...(ctx.recordType ? { recordType: ctx.recordType } : {}),\r\n strategy: opts.strategy ?? 'all',\r\n at: opts.at,\r\n includeScheduled: opts.includeScheduled,\r\n includeExpired: opts.includeExpired,\r\n limit: opts.limit,\r\n },\r\n true,\r\n);\r\n\r\n/**\r\n * Server-side bulk upsert. Up to 500 rows per call; any leftover is chunked.\r\n * Each row is error-isolated by the server.\r\n */\r\nexport const bulkUpsert = async <T,>(\r\n ctx: RecordsCtx,\r\n entries: Array<{ ref?: string; scope: RecordScope; data: T; status?: string }>,\r\n): Promise<{ saved: number; failed: number }> => {\r\n const CHUNK = 500;\r\n let saved = 0;\r\n let failed = 0;\r\n for (let i = 0; i < entries.length; i += CHUNK) {\r\n const slice = entries.slice(i, i + CHUNK);\r\n const items: BulkUpsertItem[] = slice.map((e) => ({\r\n ref: e.ref ?? deriveRefFromScope(e.scope),\r\n ...(ctx.recordType ? { recordType: ctx.recordType } : {}),\r\n scope: e.scope,\r\n data: e.data as Record<string, unknown>,\r\n status: e.status,\r\n }));\r\n const res = await ctx.SL.app.records.bulkUpsert(ctx.collectionId, ctx.appId, items)\r\n .catch((): { saved: number; failed: number } => ({ saved: 0, failed: items.length }));\r\n saved += res.saved ?? 0;\r\n failed += res.failed ?? 0;\r\n }\r\n return { saved, failed };\r\n};\r\n\r\n/**\r\n * Server-side bulk delete. Accepts an explicit ref list (max 1000 per call,\r\n * chunked here) or a scope anchor (single call).\r\n */\r\nexport const bulkDelete = async (\r\n ctx: RecordsCtx,\r\n input: { refs: string[] } | { scope: Omit<RecordScope, 'facets'> },\r\n): Promise<{ removed: number }> => {\r\n if ('scope' in input) {\r\n const res: BulkDeleteResult = await ctx.SL.app.records.bulkDelete(\r\n ctx.collectionId, ctx.appId,\r\n { scope: input.scope, ...(ctx.recordType ? { recordType: ctx.recordType } : {}) },\r\n );\r\n return { removed: res.deleted ?? 0 };\r\n }\r\n\r\n const CHUNK = 1000;\r\n let removed = 0;\r\n for (let i = 0; i < input.refs.length; i += CHUNK) {\r\n const slice = input.refs.slice(i, i + CHUNK);\r\n const res: BulkDeleteResult = await ctx.SL.app.records.bulkDelete(\r\n ctx.collectionId, ctx.appId,\r\n { refs: slice, ...(ctx.recordType ? { recordType: ctx.recordType } : {}) },\r\n );\r\n removed += res.deleted ?? 0;\r\n }\r\n return { removed };\r\n};\r\n\r\n// ---------------------------------------------------------------------------\r\n// Internal — derive a stable ref string from a structured scope. The server\r\n// re-derives this canonically on write; we send our best guess so callers\r\n// (and our own list/lookup helpers) can find the record by ref afterwards.\r\n// ---------------------------------------------------------------------------\r\nconst deriveRefFromScope = (scope: RecordScope): string => {\r\n const parts: string[] = [];\r\n if (scope.facets && scope.facets.length > 0) {\r\n // Sort for determinism.\r\n const sorted = [...scope.facets].sort((a, b) => a.key.localeCompare(b.key));\r\n for (const f of sorted) {\r\n const vals = [...f.valueKeys].sort().join(',');\r\n parts.push(vals ? `facet:${f.key}=${vals}` : `facet:${f.key}`);\r\n }\r\n }\r\n if (scope.productId) parts.push(`product:${scope.productId}`);\r\n if (scope.variantId) parts.push(`variant:${scope.variantId}`);\r\n if (scope.batchId) parts.push(`batch:${scope.batchId}`);\r\n if (scope.proofId) parts.push(`proof:${scope.proofId}`);\r\n return parts.join('/');\r\n};"]}
@@ -243,5 +243,5 @@ var FacetRuleEditor = ({
243
243
  };
244
244
 
245
245
  export { FacetRuleEditor };
246
- //# sourceMappingURL=chunk-MZ6JSCXO.js.map
247
- //# sourceMappingURL=chunk-MZ6JSCXO.js.map
246
+ //# sourceMappingURL=chunk-JMCV6FOW.js.map
247
+ //# sourceMappingURL=chunk-JMCV6FOW.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/FacetRuleEditor/FacetRuleEditor.tsx"],"names":[],"mappings":"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","file":"chunk-MZ6JSCXO.js","sourcesContent":["// =============================================================================\r\n// FacetRuleEditor — Friendly AND-of-OR rule builder for facet-targeted records.\r\n//\r\n// Model: `{ all: [{ facetKey, anyOf: [valueKey, ...] }, ...] }`.\r\n// - Each clause picks ONE facet key and one or more values (OR within).\r\n// - Multiple clauses are ANDed.\r\n// - Facet keys cannot repeat across clauses (server enforces; we hide already-\r\n// chosen keys from the picker).\r\n// - No NOTs, no nesting, no free-text — by design. This is the public-side\r\n// rule shape; richer logic belongs in `ConditionsEditor` (client-side only).\r\n//\r\n// UX notes:\r\n// - Empty state: a single inviting \"Pick a facet to start\" card.\r\n// - Each clause renders as a labelled row of value chips that toggle on click.\r\n// - Bottom bar shows live \"matches N products\" feedback when `preview` is set.\r\n// =============================================================================\r\nimport React, { useMemo } from 'react';\r\nimport { Plus, X, Trash2, Loader2, Check, AlertCircle } from 'lucide-react';\r\nimport { cn } from '../../utils/cn';\r\nimport { useFacets } from '../ConditionsEditor/useFacets';\r\nimport type { FacetRuleEditorProps, FacetRule, FacetRuleClause, FacetOption } from './types';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Helpers\r\n// ---------------------------------------------------------------------------\r\nconst cloneRule = (rule: FacetRule | null): FacetRule => ({\r\n all: (rule?.all ?? []).map((c: FacetRuleClause) => ({ facetKey: c.facetKey, anyOf: [...c.anyOf] })),\r\n});\r\n\r\nconst updateClause = (\r\n rule: FacetRule | null,\r\n index: number,\r\n next: FacetRuleClause | null,\r\n): FacetRule | null => {\r\n const draft = cloneRule(rule);\r\n if (next === null) draft.all.splice(index, 1);\r\n else draft.all[index] = next;\r\n return draft.all.length === 0 ? null : draft;\r\n};\r\n\r\nconst findFacet = (facets: FacetOption[], key: string) =>\r\n facets.find((f) => f.key === key);\r\n\r\n// ---------------------------------------------------------------------------\r\n// Single-clause editor: facet header + chip-grid of values.\r\n// ---------------------------------------------------------------------------\r\ninterface ClauseEditorProps {\r\n clause: FacetRuleClause;\r\n facet: FacetOption | undefined;\r\n onChange: (next: FacetRuleClause | null) => void;\r\n readOnly?: boolean;\r\n}\r\n\r\nconst ClauseEditor: React.FC<ClauseEditorProps> = ({ clause, facet, onChange, readOnly }) => {\r\n const selected = useMemo(() => new Set(clause.anyOf), [clause.anyOf]);\r\n const toggle = (valueKey: string) => {\r\n if (readOnly) return;\r\n const next = new Set(selected);\r\n if (next.has(valueKey)) next.delete(valueKey);\r\n else next.add(valueKey);\r\n onChange({ facetKey: clause.facetKey, anyOf: Array.from(next) });\r\n };\r\n\r\n const facetName = facet?.name ?? clause.facetKey;\r\n const values = facet?.values ?? [];\r\n\r\n return (\r\n <div className=\"rounded-xl border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 overflow-hidden\">\r\n {/* Header */}\r\n <div className=\"flex items-center gap-2 px-4 py-2.5 bg-gray-50 dark:bg-gray-800/50 border-b border-gray-200 dark:border-gray-700\">\r\n <div className=\"flex flex-col flex-1 min-w-0\">\r\n <span className=\"text-[11px] font-medium uppercase tracking-wide text-gray-500 dark:text-gray-400\">\r\n Where\r\n </span>\r\n <span className=\"text-sm font-semibold text-gray-900 dark:text-gray-100 truncate\">\r\n {facetName}\r\n </span>\r\n </div>\r\n <span className=\"text-xs text-gray-500 dark:text-gray-400 px-2 py-0.5 rounded-full bg-gray-100 dark:bg-gray-700\">\r\n {clause.anyOf.length} selected\r\n </span>\r\n {!readOnly && (\r\n <button\r\n type=\"button\"\r\n onClick={() => onChange(null)}\r\n className=\"p-1.5 rounded-md text-gray-400 hover:text-red-600 hover:bg-red-50 dark:hover:bg-red-900/20 transition-colors\"\r\n aria-label={`Remove ${facetName} clause`}\r\n >\r\n <Trash2 className=\"w-3.5 h-3.5\" />\r\n </button>\r\n )}\r\n </div>\r\n\r\n {/* Body */}\r\n <div className=\"p-3\">\r\n {!facet ? (\r\n <div className=\"flex items-center gap-2 text-xs text-amber-600 dark:text-amber-400 px-2 py-1.5\">\r\n <AlertCircle className=\"w-3.5 h-3.5\" />\r\n <span>Facet \"{clause.facetKey}\" no longer exists in this collection.</span>\r\n </div>\r\n ) : values.length === 0 ? (\r\n <div className=\"text-xs text-gray-500 dark:text-gray-400 px-2 py-1.5\">\r\n No values defined for this facet yet.\r\n </div>\r\n ) : (\r\n <div className=\"flex flex-wrap gap-1.5\">\r\n {values.map((v) => {\r\n const isSel = selected.has(v.key);\r\n return (\r\n <button\r\n key={v.key}\r\n type=\"button\"\r\n disabled={readOnly}\r\n onClick={() => toggle(v.key)}\r\n className={cn(\r\n 'inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium transition-all',\r\n 'border',\r\n isSel\r\n ? 'bg-blue-600 text-white border-blue-600 hover:bg-blue-700'\r\n : 'bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-300 border-gray-200 dark:border-gray-700 hover:border-blue-400 hover:text-blue-600 dark:hover:text-blue-400',\r\n readOnly && 'cursor-not-allowed opacity-60'\r\n )}\r\n aria-pressed={isSel}\r\n >\r\n {v.color && (\r\n <span\r\n className=\"inline-block w-2 h-2 rounded-full\"\r\n style={{ backgroundColor: v.color }}\r\n />\r\n )}\r\n {v.name}\r\n {isSel && <Check className=\"w-3 h-3\" />}\r\n </button>\r\n );\r\n })}\r\n </div>\r\n )}\r\n {clause.anyOf.length > 1 && (\r\n <p className=\"mt-2 text-[11px] text-gray-500 dark:text-gray-400 px-1\">\r\n Matches when any of the selected values is present.\r\n </p>\r\n )}\r\n </div>\r\n </div>\r\n );\r\n};\r\n\r\n// ---------------------------------------------------------------------------\r\n// \"Add facet\" picker — lists facets not already used by another clause.\r\n// ---------------------------------------------------------------------------\r\ninterface AddFacetPickerProps {\r\n available: FacetOption[];\r\n onPick: (facetKey: string) => void;\r\n isFirst: boolean;\r\n}\r\n\r\nconst AddFacetPicker: React.FC<AddFacetPickerProps> = ({ available, onPick, isFirst }) => {\r\n const [open, setOpen] = React.useState(false);\r\n\r\n if (available.length === 0 && !isFirst) {\r\n return (\r\n <p className=\"text-xs text-gray-500 dark:text-gray-400 px-2 py-1\">\r\n All available facets are in use.\r\n </p>\r\n );\r\n }\r\n\r\n if (isFirst) {\r\n // Empty state — friendly inviting card\r\n return (\r\n <div className=\"rounded-xl border-2 border-dashed border-gray-300 dark:border-gray-700 p-6 text-center\">\r\n <p className=\"text-sm font-medium text-gray-700 dark:text-gray-200 mb-1\">\r\n Pick a facet to target\r\n </p>\r\n <p className=\"text-xs text-gray-500 dark:text-gray-400 mb-4\">\r\n Records matching this rule will be applied to every product whose facets satisfy it.\r\n </p>\r\n <div className=\"flex flex-wrap gap-1.5 justify-center\">\r\n {available.map((f) => (\r\n <button\r\n key={f.key}\r\n type=\"button\"\r\n onClick={() => onPick(f.key)}\r\n className=\"inline-flex items-center gap-1 px-3 py-1.5 rounded-full text-xs font-medium bg-blue-50 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300 hover:bg-blue-100 dark:hover:bg-blue-900/50 transition-colors\"\r\n >\r\n <Plus className=\"w-3 h-3\" />\r\n {f.name}\r\n </button>\r\n ))}\r\n {available.length === 0 && (\r\n <span className=\"text-xs text-gray-500 dark:text-gray-400\">\r\n No facets defined for this collection yet.\r\n </span>\r\n )}\r\n </div>\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className=\"relative\">\r\n <button\r\n type=\"button\"\r\n onClick={() => setOpen((o) => !o)}\r\n className=\"inline-flex items-center gap-1.5 px-3 py-1.5 rounded-full text-xs font-medium bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors\"\r\n >\r\n <Plus className=\"w-3.5 h-3.5\" />\r\n AND another facet\r\n </button>\r\n {open && (\r\n <>\r\n <div className=\"fixed inset-0 z-40\" onClick={() => setOpen(false)} />\r\n <div className=\"absolute z-50 mt-1 left-0 min-w-[200px] rounded-lg border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 shadow-lg overflow-hidden\">\r\n {available.map((f) => (\r\n <button\r\n key={f.key}\r\n type=\"button\"\r\n onClick={() => { onPick(f.key); setOpen(false); }}\r\n className=\"w-full text-left px-3 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors\"\r\n >\r\n {f.name}\r\n </button>\r\n ))}\r\n </div>\r\n </>\r\n )}\r\n </div>\r\n );\r\n};\r\n\r\n// ---------------------------------------------------------------------------\r\n// Live preview chip — wired through the optional `preview` prop.\r\n// ---------------------------------------------------------------------------\r\nconst PreviewChip: React.FC<{ preview: NonNullable<FacetRuleEditorProps['preview']> }> = ({ preview }) => {\r\n const { totalMatches, isLoading, isStale, error } = preview;\r\n\r\n if (error) {\r\n return (\r\n <div className=\"inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium bg-red-50 dark:bg-red-900/30 text-red-700 dark:text-red-300\">\r\n <AlertCircle className=\"w-3 h-3\" />\r\n Preview failed\r\n </div>\r\n );\r\n }\r\n\r\n if (isLoading || isStale || totalMatches === null) {\r\n return (\r\n <div className=\"inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium bg-gray-100 dark:bg-gray-800 text-gray-500 dark:text-gray-400\">\r\n <Loader2 className=\"w-3 h-3 animate-spin\" />\r\n Counting…\r\n </div>\r\n );\r\n }\r\n\r\n const tone = totalMatches === 0\r\n ? 'bg-amber-50 dark:bg-amber-900/30 text-amber-700 dark:text-amber-300'\r\n : 'bg-emerald-50 dark:bg-emerald-900/30 text-emerald-700 dark:text-emerald-300';\r\n\r\n return (\r\n <div className={cn('inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium', tone)}>\r\n <Check className=\"w-3 h-3\" />\r\n {totalMatches === 0\r\n ? 'Matches no products yet'\r\n : `Matches ${totalMatches} product${totalMatches === 1 ? '' : 's'}`}\r\n </div>\r\n );\r\n};\r\n\r\n// ---------------------------------------------------------------------------\r\n// Top-level component\r\n// ---------------------------------------------------------------------------\r\nexport const FacetRuleEditor: React.FC<FacetRuleEditorProps> = ({\r\n value, onChange,\r\n facets: providedFacets, collectionId, getFacets,\r\n preview, readOnly,\r\n onClear,\r\n title,\r\n description,\r\n className,\r\n}) => {\r\n const facets = useFacets(collectionId, providedFacets, getFacets);\r\n\r\n const usedKeys = useMemo(\r\n () => new Set((value?.all ?? []).map((c: FacetRuleClause) => c.facetKey)),\r\n [value],\r\n );\r\n const availableFacets = useMemo(\r\n () => facets.filter((f) => !usedKeys.has(f.key)),\r\n [facets, usedKeys],\r\n );\r\n\r\n const addClause = (facetKey: string) => {\r\n const next: FacetRule = cloneRule(value);\r\n next.all.push({ facetKey, anyOf: [] });\r\n onChange(next);\r\n };\r\n\r\n const updateAt = (i: number, next: FacetRuleClause | null) => {\r\n onChange(updateClause(value, i, next));\r\n };\r\n\r\n const hasClauses = (value?.all?.length ?? 0) > 0;\r\n\r\n return (\r\n <div className={cn('smartlinks-ui-facet-rule-editor space-y-3', className)}>\r\n {(title || description || (hasClauses && onClear) || preview) && (\r\n <div className=\"flex items-start gap-2\">\r\n <div className=\"flex-1 min-w-0\">\r\n {title && (\r\n <h3 className=\"text-sm font-semibold text-gray-900 dark:text-gray-100\">{title}</h3>\r\n )}\r\n {description && (\r\n <p className=\"mt-0.5 text-xs text-gray-500 dark:text-gray-400\">{description}</p>\r\n )}\r\n </div>\r\n {preview && hasClauses && <PreviewChip preview={preview} />}\r\n {onClear && hasClauses && !readOnly && (\r\n <button\r\n type=\"button\"\r\n onClick={onClear}\r\n className=\"inline-flex items-center gap-1 px-2 py-1 rounded-md text-xs text-gray-500 hover:text-red-600 hover:bg-red-50 dark:hover:bg-red-900/20 transition-colors\"\r\n >\r\n <X className=\"w-3 h-3\" />\r\n Remove rule\r\n </button>\r\n )}\r\n </div>\r\n )}\r\n\r\n {!hasClauses ? (\r\n <AddFacetPicker available={facets} onPick={addClause} isFirst />\r\n ) : (\r\n <>\r\n {value!.all.map((clause: FacetRuleClause, i: number) => (\r\n <React.Fragment key={`${clause.facetKey}-${i}`}>\r\n {i > 0 && (\r\n <div className=\"flex items-center justify-center\">\r\n <span className=\"px-2 py-0.5 rounded-full text-[10px] font-bold uppercase tracking-wider bg-gray-100 dark:bg-gray-800 text-gray-500 dark:text-gray-400\">\r\n AND\r\n </span>\r\n </div>\r\n )}\r\n <ClauseEditor\r\n clause={clause}\r\n facet={findFacet(facets, clause.facetKey)}\r\n onChange={(next) => updateAt(i, next)}\r\n readOnly={readOnly}\r\n />\r\n </React.Fragment>\r\n ))}\r\n {!readOnly && (\r\n <div className=\"pt-1\">\r\n <AddFacetPicker\r\n available={availableFacets}\r\n onPick={addClause}\r\n isFirst={false}\r\n />\r\n </div>\r\n )}\r\n </>\r\n )}\r\n </div>\r\n );\r\n};"]}
1
+ {"version":3,"sources":["../src/components/FacetRuleEditor/FacetRuleEditor.tsx"],"names":[],"mappings":"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","file":"chunk-JMCV6FOW.js","sourcesContent":["// =============================================================================\r\n// FacetRuleEditor — Friendly AND-of-OR rule builder for facet-targeted records.\r\n//\r\n// Model: `{ all: [{ facetKey, anyOf: [valueKey, ...] }, ...] }`.\r\n// - Each clause picks ONE facet key and one or more values (OR within).\r\n// - Multiple clauses are ANDed.\r\n// - Facet keys cannot repeat across clauses (server enforces; we hide already-\r\n// chosen keys from the picker).\r\n// - No NOTs, no nesting, no free-text — by design. This is the public-side\r\n// rule shape; richer logic belongs in `ConditionsEditor` (client-side only).\r\n//\r\n// UX notes:\r\n// - Empty state: a single inviting \"Pick a facet to start\" card.\r\n// - Each clause renders as a labelled row of value chips that toggle on click.\r\n// - Bottom bar shows live \"matches N products\" feedback when `preview` is set.\r\n// =============================================================================\r\nimport React, { useMemo } from 'react';\r\nimport { Plus, X, Trash2, Loader2, Check, AlertCircle } from 'lucide-react';\r\nimport { cn } from '../../utils/cn';\r\nimport { useFacets } from '../ConditionsEditor/useFacets';\r\nimport type { FacetRuleEditorProps, FacetRule, FacetRuleClause, FacetOption } from './types';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Helpers\r\n// ---------------------------------------------------------------------------\r\nconst cloneRule = (rule: FacetRule | null): FacetRule => ({\r\n all: (rule?.all ?? []).map((c: FacetRuleClause) => ({ facetKey: c.facetKey, anyOf: [...c.anyOf] })),\r\n});\r\n\r\nconst updateClause = (\r\n rule: FacetRule | null,\r\n index: number,\r\n next: FacetRuleClause | null,\r\n): FacetRule | null => {\r\n const draft = cloneRule(rule);\r\n if (next === null) draft.all.splice(index, 1);\r\n else draft.all[index] = next;\r\n return draft.all.length === 0 ? null : draft;\r\n};\r\n\r\nconst findFacet = (facets: FacetOption[], key: string) =>\r\n facets.find((f) => f.key === key);\r\n\r\n// ---------------------------------------------------------------------------\r\n// Single-clause editor: facet header + chip-grid of values.\r\n// ---------------------------------------------------------------------------\r\ninterface ClauseEditorProps {\r\n clause: FacetRuleClause;\r\n facet: FacetOption | undefined;\r\n onChange: (next: FacetRuleClause | null) => void;\r\n readOnly?: boolean;\r\n}\r\n\r\nconst ClauseEditor: React.FC<ClauseEditorProps> = ({ clause, facet, onChange, readOnly }) => {\r\n const selected = useMemo(() => new Set(clause.anyOf), [clause.anyOf]);\r\n const toggle = (valueKey: string) => {\r\n if (readOnly) return;\r\n const next = new Set(selected);\r\n if (next.has(valueKey)) next.delete(valueKey);\r\n else next.add(valueKey);\r\n onChange({ facetKey: clause.facetKey, anyOf: Array.from(next) });\r\n };\r\n\r\n const facetName = facet?.name ?? clause.facetKey;\r\n const values = facet?.values ?? [];\r\n\r\n return (\r\n <div className=\"rounded-xl border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 overflow-hidden\">\r\n {/* Header */}\r\n <div className=\"flex items-center gap-2 px-4 py-2.5 bg-gray-50 dark:bg-gray-800/50 border-b border-gray-200 dark:border-gray-700\">\r\n <div className=\"flex flex-col flex-1 min-w-0\">\r\n <span className=\"text-[11px] font-medium uppercase tracking-wide text-gray-500 dark:text-gray-400\">\r\n Where\r\n </span>\r\n <span className=\"text-sm font-semibold text-gray-900 dark:text-gray-100 truncate\">\r\n {facetName}\r\n </span>\r\n </div>\r\n <span className=\"text-xs text-gray-500 dark:text-gray-400 px-2 py-0.5 rounded-full bg-gray-100 dark:bg-gray-700\">\r\n {clause.anyOf.length} selected\r\n </span>\r\n {!readOnly && (\r\n <button\r\n type=\"button\"\r\n onClick={() => onChange(null)}\r\n className=\"p-1.5 rounded-md text-gray-400 hover:text-red-600 hover:bg-red-50 dark:hover:bg-red-900/20 transition-colors\"\r\n aria-label={`Remove ${facetName} clause`}\r\n >\r\n <Trash2 className=\"w-3.5 h-3.5\" />\r\n </button>\r\n )}\r\n </div>\r\n\r\n {/* Body */}\r\n <div className=\"p-3\">\r\n {!facet ? (\r\n <div className=\"flex items-center gap-2 text-xs text-amber-600 dark:text-amber-400 px-2 py-1.5\">\r\n <AlertCircle className=\"w-3.5 h-3.5\" />\r\n <span>Facet \"{clause.facetKey}\" no longer exists in this collection.</span>\r\n </div>\r\n ) : values.length === 0 ? (\r\n <div className=\"text-xs text-gray-500 dark:text-gray-400 px-2 py-1.5\">\r\n No values defined for this facet yet.\r\n </div>\r\n ) : (\r\n <div className=\"flex flex-wrap gap-1.5\">\r\n {values.map((v) => {\r\n const isSel = selected.has(v.key);\r\n return (\r\n <button\r\n key={v.key}\r\n type=\"button\"\r\n disabled={readOnly}\r\n onClick={() => toggle(v.key)}\r\n className={cn(\r\n 'inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium transition-all',\r\n 'border',\r\n isSel\r\n ? 'bg-blue-600 text-white border-blue-600 hover:bg-blue-700'\r\n : 'bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-300 border-gray-200 dark:border-gray-700 hover:border-blue-400 hover:text-blue-600 dark:hover:text-blue-400',\r\n readOnly && 'cursor-not-allowed opacity-60'\r\n )}\r\n aria-pressed={isSel}\r\n >\r\n {v.color && (\r\n <span\r\n className=\"inline-block w-2 h-2 rounded-full\"\r\n style={{ backgroundColor: v.color }}\r\n />\r\n )}\r\n {v.name}\r\n {isSel && <Check className=\"w-3 h-3\" />}\r\n </button>\r\n );\r\n })}\r\n </div>\r\n )}\r\n {clause.anyOf.length > 1 && (\r\n <p className=\"mt-2 text-[11px] text-gray-500 dark:text-gray-400 px-1\">\r\n Matches when any of the selected values is present.\r\n </p>\r\n )}\r\n </div>\r\n </div>\r\n );\r\n};\r\n\r\n// ---------------------------------------------------------------------------\r\n// \"Add facet\" picker — lists facets not already used by another clause.\r\n// ---------------------------------------------------------------------------\r\ninterface AddFacetPickerProps {\r\n available: FacetOption[];\r\n onPick: (facetKey: string) => void;\r\n isFirst: boolean;\r\n}\r\n\r\nconst AddFacetPicker: React.FC<AddFacetPickerProps> = ({ available, onPick, isFirst }) => {\r\n const [open, setOpen] = React.useState(false);\r\n\r\n if (available.length === 0 && !isFirst) {\r\n return (\r\n <p className=\"text-xs text-gray-500 dark:text-gray-400 px-2 py-1\">\r\n All available facets are in use.\r\n </p>\r\n );\r\n }\r\n\r\n if (isFirst) {\r\n // Empty state — friendly inviting card\r\n return (\r\n <div className=\"rounded-xl border-2 border-dashed border-gray-300 dark:border-gray-700 p-6 text-center\">\r\n <p className=\"text-sm font-medium text-gray-700 dark:text-gray-200 mb-1\">\r\n Pick a facet to target\r\n </p>\r\n <p className=\"text-xs text-gray-500 dark:text-gray-400 mb-4\">\r\n Records matching this rule will be applied to every product whose facets satisfy it.\r\n </p>\r\n <div className=\"flex flex-wrap gap-1.5 justify-center\">\r\n {available.map((f) => (\r\n <button\r\n key={f.key}\r\n type=\"button\"\r\n onClick={() => onPick(f.key)}\r\n className=\"inline-flex items-center gap-1 px-3 py-1.5 rounded-full text-xs font-medium bg-blue-50 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300 hover:bg-blue-100 dark:hover:bg-blue-900/50 transition-colors\"\r\n >\r\n <Plus className=\"w-3 h-3\" />\r\n {f.name}\r\n </button>\r\n ))}\r\n {available.length === 0 && (\r\n <span className=\"text-xs text-gray-500 dark:text-gray-400\">\r\n No facets defined for this collection yet.\r\n </span>\r\n )}\r\n </div>\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className=\"relative\">\r\n <button\r\n type=\"button\"\r\n onClick={() => setOpen((o) => !o)}\r\n className=\"inline-flex items-center gap-1.5 px-3 py-1.5 rounded-full text-xs font-medium bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors\"\r\n >\r\n <Plus className=\"w-3.5 h-3.5\" />\r\n AND another facet\r\n </button>\r\n {open && (\r\n <>\r\n <div className=\"fixed inset-0 z-40\" onClick={() => setOpen(false)} />\r\n <div className=\"absolute z-50 mt-1 left-0 min-w-[200px] rounded-lg border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 shadow-lg overflow-hidden\">\r\n {available.map((f) => (\r\n <button\r\n key={f.key}\r\n type=\"button\"\r\n onClick={() => { onPick(f.key); setOpen(false); }}\r\n className=\"w-full text-left px-3 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors\"\r\n >\r\n {f.name}\r\n </button>\r\n ))}\r\n </div>\r\n </>\r\n )}\r\n </div>\r\n );\r\n};\r\n\r\n// ---------------------------------------------------------------------------\r\n// Live preview chip — wired through the optional `preview` prop.\r\n// ---------------------------------------------------------------------------\r\nconst PreviewChip: React.FC<{ preview: NonNullable<FacetRuleEditorProps['preview']> }> = ({ preview }) => {\r\n const { totalMatches, isLoading, isStale, error } = preview;\r\n\r\n if (error) {\r\n return (\r\n <div className=\"inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium bg-red-50 dark:bg-red-900/30 text-red-700 dark:text-red-300\">\r\n <AlertCircle className=\"w-3 h-3\" />\r\n Preview failed\r\n </div>\r\n );\r\n }\r\n\r\n if (isLoading || isStale || totalMatches === null) {\r\n return (\r\n <div className=\"inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium bg-gray-100 dark:bg-gray-800 text-gray-500 dark:text-gray-400\">\r\n <Loader2 className=\"w-3 h-3 animate-spin\" />\r\n Counting…\r\n </div>\r\n );\r\n }\r\n\r\n const tone = totalMatches === 0\r\n ? 'bg-amber-50 dark:bg-amber-900/30 text-amber-700 dark:text-amber-300'\r\n : 'bg-emerald-50 dark:bg-emerald-900/30 text-emerald-700 dark:text-emerald-300';\r\n\r\n return (\r\n <div className={cn('inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium', tone)}>\r\n <Check className=\"w-3 h-3\" />\r\n {totalMatches === 0\r\n ? 'Matches no products yet'\r\n : `Matches ${totalMatches} product${totalMatches === 1 ? '' : 's'}`}\r\n </div>\r\n );\r\n};\r\n\r\n// ---------------------------------------------------------------------------\r\n// Top-level component\r\n// ---------------------------------------------------------------------------\r\nexport const FacetRuleEditor: React.FC<FacetRuleEditorProps> = ({\r\n value, onChange,\r\n facets: providedFacets, collectionId, getFacets,\r\n preview, readOnly,\r\n onClear,\r\n title,\r\n description,\r\n className,\r\n}) => {\r\n const facets = useFacets(collectionId, providedFacets, getFacets);\r\n\r\n const usedKeys = useMemo(\r\n () => new Set((value?.all ?? []).map((c: FacetRuleClause) => c.facetKey)),\r\n [value],\r\n );\r\n const availableFacets = useMemo(\r\n () => facets.filter((f) => !usedKeys.has(f.key)),\r\n [facets, usedKeys],\r\n );\r\n\r\n const addClause = (facetKey: string) => {\r\n const next: FacetRule = cloneRule(value);\r\n next.all.push({ facetKey, anyOf: [] });\r\n onChange(next);\r\n };\r\n\r\n const updateAt = (i: number, next: FacetRuleClause | null) => {\r\n onChange(updateClause(value, i, next));\r\n };\r\n\r\n const hasClauses = (value?.all?.length ?? 0) > 0;\r\n\r\n return (\r\n <div className={cn('smartlinks-ui-facet-rule-editor space-y-3', className)}>\r\n {(title || description || (hasClauses && onClear) || preview) && (\r\n <div className=\"flex items-start gap-2\">\r\n <div className=\"flex-1 min-w-0\">\r\n {title && (\r\n <h3 className=\"text-sm font-semibold text-gray-900 dark:text-gray-100\">{title}</h3>\r\n )}\r\n {description && (\r\n <p className=\"mt-0.5 text-xs text-gray-500 dark:text-gray-400\">{description}</p>\r\n )}\r\n </div>\r\n {preview && hasClauses && <PreviewChip preview={preview} />}\r\n {onClear && hasClauses && !readOnly && (\r\n <button\r\n type=\"button\"\r\n onClick={onClear}\r\n className=\"inline-flex items-center gap-1 px-2 py-1 rounded-md text-xs text-gray-500 hover:text-red-600 hover:bg-red-50 dark:hover:bg-red-900/20 transition-colors\"\r\n >\r\n <X className=\"w-3 h-3\" />\r\n Remove rule\r\n </button>\r\n )}\r\n </div>\r\n )}\r\n\r\n {!hasClauses ? (\r\n <AddFacetPicker available={facets} onPick={addClause} isFirst />\r\n ) : (\r\n <>\r\n {value!.all.map((clause: FacetRuleClause, i: number) => (\r\n <React.Fragment key={`${clause.facetKey}-${i}`}>\r\n {i > 0 && (\r\n <div className=\"flex items-center justify-center\">\r\n <span className=\"px-2 py-0.5 rounded-full text-[10px] font-bold uppercase tracking-wider bg-gray-100 dark:bg-gray-800 text-gray-500 dark:text-gray-400\">\r\n AND\r\n </span>\r\n </div>\r\n )}\r\n <ClauseEditor\r\n clause={clause}\r\n facet={findFacet(facets, clause.facetKey)}\r\n onChange={(next) => updateAt(i, next)}\r\n readOnly={readOnly}\r\n />\r\n </React.Fragment>\r\n ))}\r\n {!readOnly && (\r\n <div className=\"pt-1\">\r\n <AddFacetPicker\r\n available={availableFacets}\r\n onPick={addClause}\r\n isFirst={false}\r\n />\r\n </div>\r\n )}\r\n </>\r\n )}\r\n </div>\r\n );\r\n};"]}
@@ -0,0 +1,3 @@
1
+
2
+ //# sourceMappingURL=chunk-S27GIYV7.js.map
3
+ //# sourceMappingURL=chunk-S27GIYV7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-S27GIYV7.js"}
@@ -1,4 +1,5 @@
1
- export { FacetRuleEditor } from '../../chunk-MZ6JSCXO.js';
1
+ import '../../chunk-S27GIYV7.js';
2
+ export { FacetRuleEditor } from '../../chunk-JMCV6FOW.js';
2
3
  import '../../chunk-4LHF5JB7.js';
3
4
  import '../../chunk-L7FQ52F5.js';
4
5
  //# sourceMappingURL=index.js.map
@@ -1,9 +1,9 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode, ComponentType } from 'react';
3
- import * as _proveanything_smartlinks_dist_types_appObjects from '@proveanything/smartlinks/dist/types/appObjects';
4
- import { MatchedAt, FacetRule, RecordScope, AppRecord, RecordTarget, MatchResult, MatchEntry } from '@proveanything/smartlinks/dist/types/appObjects';
3
+ import { FacetRule, MatchedAt, RecordScope, AppRecord, RecordTarget, MatchResult, MatchEntry } from '@proveanything/smartlinks/dist/types/appObjects';
5
4
  import { LucideIcon } from 'lucide-react';
6
5
  import * as _tanstack_query_core from '@tanstack/query-core';
6
+ import * as _proveanything_smartlinks from '@proveanything/smartlinks';
7
7
  import { InfiniteData } from '@tanstack/react-query';
8
8
 
9
9
  /**
@@ -16,8 +16,11 @@ import { InfiniteData } from '@tanstack/react-query';
16
16
  * - `product` — anchored to a product.
17
17
  * - `variant` — anchored to a product variant.
18
18
  * - `batch` — anchored to a product batch.
19
+ * - `rule` — synthetic UI scope: records that target via a `facetRule`
20
+ * (AND-of-OR over facets) rather than being pinned to a
21
+ * specific node in the chain. Their refs start with `rule:`.
19
22
  */
20
- type ScopeKind = 'collection' | 'product' | 'facet' | 'variant' | 'batch';
23
+ type ScopeKind = 'collection' | 'product' | 'facet' | 'variant' | 'batch' | 'rule';
21
24
  /** Parsed `ref` string — see `data/refs.ts`. Format: `kind:id` or chain. */
22
25
  interface ParsedRef {
23
26
  /** Most-specific scope this ref points at. */
@@ -31,6 +34,12 @@ interface ParsedRef {
31
34
  variantId?: string;
32
35
  batchId?: string;
33
36
  proofId?: string;
37
+ /**
38
+ * Opaque id of a rule-targeted record (ref starts with `rule:`). Set when
39
+ * `kind === 'rule'`. The actual rule lives on the record's `facetRule`
40
+ * field — this is just the addressing handle used by the URL/refs layer.
41
+ */
42
+ ruleId?: string;
34
43
  /**
35
44
  * For `collection` cardinality records: the per-item identifier within the
36
45
  * scope. Singleton records leave this undefined. The full ref is
@@ -72,6 +81,13 @@ interface RecordSummary<TData = unknown> {
72
81
  * leave this undefined.
73
82
  */
74
83
  itemId?: string;
84
+ /**
85
+ * For rule-targeted records (ref begins `rule:`). The AND-of-OR clauses
86
+ * the server uses to match this record against a product's facets.
87
+ * `null` for non-rule records. The browser uses this to render a friendly
88
+ * rule summary as the row subtitle.
89
+ */
90
+ facetRule?: FacetRule | null;
75
91
  }
76
92
  interface ResolvedRecord<TData = unknown> {
77
93
  data: TData | null;
@@ -88,6 +104,13 @@ interface ResolvedRecord<TData = unknown> {
88
104
  matchedAt?: MatchedAt;
89
105
  /** The rule that fired. Present only when `matchedAt === 'rule'`. */
90
106
  matchedRule?: FacetRule;
107
+ /**
108
+ * The `facetRule` attached to the winning record itself, if any. Distinct
109
+ * from `matchedRule` (which is set when the resolver classified the match
110
+ * as rule-based). For rule-targeted records (`source: 'self'` on a
111
+ * `rule:{id}` ref) this is the rule the editor authors against.
112
+ */
113
+ facetRule?: FacetRule | null;
91
114
  }
92
115
 
93
116
  interface EditorContext<TData = unknown> {
@@ -108,6 +131,15 @@ interface EditorContext<TData = unknown> {
108
131
  isSaving?: boolean;
109
132
  /** Last save error, if any. Cleared when the next save attempt starts. */
110
133
  saveError?: unknown | null;
134
+ /**
135
+ * Current facet rule attached to this record, if any. Always defined for
136
+ * rule-targeted scopes (`scope.kind === 'rule'`) — starts as `{ all: [] }`
137
+ * for a freshly created rule and is updated via `onFacetRuleChange`.
138
+ * Mutually exclusive with the structured `scope` on save.
139
+ */
140
+ facetRule?: FacetRule | null;
141
+ /** Update the in-progress facet rule. Marks the editor dirty. */
142
+ onFacetRuleChange?: (next: FacetRule | null) => void;
111
143
  }
112
144
 
113
145
  interface CsvSchemaColumn<TData> {
@@ -886,7 +918,7 @@ interface RecordBrowserProps {
886
918
  }
887
919
  declare const RecordBrowser: ({ scopes, activeScope, onActiveScopeChange, selectedRef, onSelectRef, items, counts, isLoading, error, filter, onFilterChange, search, onSearchChange, hasNextPage, isFetchingNextPage, onLoadMore, scopesLoading, i18n, }: RecordBrowserProps) => react_jsx_runtime.JSX.Element;
888
920
 
889
- interface Props$f {
921
+ interface Props$g {
890
922
  scopes: ScopeKind[];
891
923
  active: ScopeKind;
892
924
  onChange: (s: ScopeKind) => void;
@@ -897,15 +929,29 @@ interface Props$f {
897
929
  /** Override icons used per scope. Falls back to DEFAULT_ICONS.scope. */
898
930
  icons?: RecordsAdminIcons['scope'];
899
931
  }
900
- declare const ScopeTabs: ({ scopes, active, onChange, loading, counts, icons, }: Props$f) => react_jsx_runtime.JSX.Element;
932
+ declare const ScopeTabs: ({ scopes, active, onChange, loading, counts, icons, }: Props$g) => react_jsx_runtime.JSX.Element;
901
933
 
902
- interface Props$e {
934
+ interface Props$f {
903
935
  source?: RecordSource;
904
936
  status?: RecordStatus;
905
937
  className?: string;
906
938
  }
907
939
  /** Emerald = own data, amber = inherited, muted = empty */
908
- declare const StatusDot: ({ source, status, className }: Props$e) => react_jsx_runtime.JSX.Element;
940
+ declare const StatusDot: ({ source, status, className }: Props$f) => react_jsx_runtime.JSX.Element;
941
+
942
+ type StatusTone = 'own' | 'shared' | 'missing';
943
+ interface Props$e {
944
+ source?: RecordSource;
945
+ status?: RecordStatus;
946
+ className?: string;
947
+ /** Override icon size (default 1.05rem). */
948
+ size?: string;
949
+ /** Optional accessible label — defaults to the tone name. */
950
+ label?: string;
951
+ }
952
+ declare const StatusIcon: ({ source, status, className, size, label }: Props$e) => react_jsx_runtime.JSX.Element;
953
+ /** Short label rendered next to / under the row title. */
954
+ declare const statusToneLabel: (tone: StatusTone) => string;
909
955
 
910
956
  interface Props$d {
911
957
  value: 'all' | RecordStatus;
@@ -1014,6 +1060,13 @@ interface Props$a<T> {
1014
1060
  i18n: RecordsAdminI18n;
1015
1061
  children: ReactNode;
1016
1062
  preview?: ReactNode;
1063
+ /**
1064
+ * Optional Targeting section rendered above `children`. The shell mounts
1065
+ * this for rule-targeted records (`scope.kind === 'rule'`) so admins can
1066
+ * author the facet rule alongside the record's data. Plain record types
1067
+ * leave it `undefined` and nothing renders.
1068
+ */
1069
+ targeting?: ReactNode;
1017
1070
  bulkActions?: React.ComponentProps<typeof BulkActionsMenu>;
1018
1071
  /** Extra slot rendered in the footer between the danger actions and Save. */
1019
1072
  footerExtra?: ReactNode;
@@ -1052,7 +1105,7 @@ interface Props$a<T> {
1052
1105
  /** Host-provided icons rendered before save / discard / delete labels. */
1053
1106
  actionIcons?: Partial<Record<RecordsAdminActionKey, RecordsAdminActionIcon>>;
1054
1107
  }
1055
- declare function RecordEditor<T>({ ctx, i18n, children, preview, bulkActions, footerExtra, onBeforeDelete, headerLabel, headerSubtitle, headerMeta, clipboard, actionLabels, actionIcons, }: Props$a<T>): react_jsx_runtime.JSX.Element;
1108
+ declare function RecordEditor<T>({ ctx, i18n, children, preview, targeting, bulkActions, footerExtra, onBeforeDelete, headerLabel, headerSubtitle, headerMeta, clipboard, actionLabels, actionIcons, }: Props$a<T>): react_jsx_runtime.JSX.Element;
1056
1109
 
1057
1110
  interface InheritanceCtx {
1058
1111
  parentValue?: Record<string, unknown> | null;
@@ -1239,6 +1292,12 @@ interface RecordWrite<T = unknown> {
1239
1292
  expiresAt?: string | null;
1240
1293
  customId?: string;
1241
1294
  sourceSystem?: string;
1295
+ /**
1296
+ * Optional facet rule. When set, the record is targeted via this rule and
1297
+ * `scope` should be empty (the SDK enforces mutual exclusion). Used by
1298
+ * the rule editor / Targeting section.
1299
+ */
1300
+ facetRule?: FacetRule | null;
1242
1301
  }
1243
1302
  declare const listRecords: (ctx: RecordsCtx, params?: {
1244
1303
  ref?: string;
@@ -1361,6 +1420,13 @@ interface UseRecordEditorArgs<T> {
1361
1420
  * (used by the shell when `dirtyStrategy === 'keep'`).
1362
1421
  */
1363
1422
  reseed?: 'always' | 'preserve-dirty';
1423
+ /**
1424
+ * Initial facet rule for the record. Required for rule-targeted scopes —
1425
+ * pass `null` (or `{ all: [] }`) for a freshly minted `rule:{id}` ref so
1426
+ * the Targeting section has somewhere to author into. Ignored for pinned
1427
+ * scopes unless the host explicitly opts a record into rule targeting.
1428
+ */
1429
+ initialFacetRule?: FacetRule | null;
1364
1430
  }
1365
1431
  declare function useRecordEditor<T>(args: UseRecordEditorArgs<T>): EditorContext<T>;
1366
1432
 
@@ -1376,6 +1442,13 @@ interface UseResolvedRecordArgs {
1376
1442
  facetId?: string;
1377
1443
  facetValue?: string;
1378
1444
  proofId?: string;
1445
+ /**
1446
+ * Optional raw ref. Required for rule-targeted records (`rule:{id}`) so the
1447
+ * resolver can look them up by ref instead of running an inheritance chain.
1448
+ * For pinned scopes this can be left empty — the structured scope ids are
1449
+ * sufficient.
1450
+ */
1451
+ ref?: string;
1379
1452
  supportedScopes?: ScopeKind[];
1380
1453
  enabled?: boolean;
1381
1454
  withParent?: boolean;
@@ -1387,8 +1460,9 @@ declare function useResolvedRecord<T = unknown>(args: UseResolvedRecordArgs): {
1387
1460
  source: RecordSource;
1388
1461
  sourceRef?: string;
1389
1462
  parentValue?: T | null | undefined;
1390
- matchedAt?: _proveanything_smartlinks_dist_types_appObjects.MatchedAt;
1391
- matchedRule?: _proveanything_smartlinks_dist_types_appObjects.FacetRule;
1463
+ matchedAt?: _proveanything_smartlinks.MatchedAt;
1464
+ matchedRule?: _proveanything_smartlinks.FacetRule;
1465
+ facetRule?: _proveanything_smartlinks.FacetRule | null;
1392
1466
  };
1393
1467
 
1394
1468
  interface UseCollectionItemsArgs {
@@ -1976,4 +2050,4 @@ declare const exportCsv: <T>(records: RecordSummary<T>[], schema: CsvSchema<T>)
1976
2050
  declare const importCsv: <T>(file: File, schema: CsvSchema<T>, ctx: RecordsCtx) => Promise<ImportReport>;
1977
2051
  declare const downloadBlob: (blob: Blob, filename: string) => void;
1978
2052
 
1979
- export { ALL_ITEM_VIEWS, ALL_PRESENTATIONS, BatchList, BulkActionsMenu, type ClipboardEntry, type CollectedRecord, type CollectedSort, type CollectionRailMode, type CsvSchema, type CsvSchemaColumn, DEFAULT_DEEP_LINK_PARAM_NAMES, DEFAULT_I18N, DEFAULT_ICONS, type DeepLinkAdapter, type DeepLinkChangeKind, type DeepLinkHistoryMode, type DeepLinkOptions, type DeepLinkParamNames, type DeepLinkState, DefaultItemCards, DefaultItemTable, DefaultRecordCard, DefaultRecordRow, DeleteButton, type DirtyStrategy, DrawerPreview, type EditorContext, EditorItemNav, EmptyState, ErrorState, FacetList, InheritanceMarker, InheritanceProvider, InlinePreview, IntroCard, type ItemColumn, ItemListView, type ItemSlotContext, type ItemView, type ItemViewContext, ItemViewSwitcher, LoadingState, type MergeStrategy, type MergedRecord, type NavConfirmI18n, type ParsedRef, type PasteCompatibility, type PasteCompatibilityResult, PresentationSwitcher, type PreviewMode, PreviewScopePicker, PreviewToggleButton, type ProductBrowseItem, type ProductChildItem, ProductDrillDown, ProductList, type RecordBadge, RecordBrowser, type RecordCardinality, RecordEditor, RecordList, type RecordPresentation, type RecordSlotContext, type RecordSource, type RecordStatus, type RecordSummary, type RecordsAdminI18n, type RecordsAdminIcons, RecordsAdminShell, type RecordsAdminShellProps, type ResolvedDeepLinkParamNames, ResolvedPreview, type ResolvedRecord, ScopeBreadcrumb, type ScopeKind, ScopeTabs, SiblingRail, SidePreview, type SmartLinksSDK, StatusDot, StatusFilterPills, TabbedPreview, type TelemetryEvent, type UseCollectionItemsArgs, type UseRecordClipboardArgs, type UseRecordClipboardReturn, type UseResolveAllRecordsArgs, type UseResolveAllResult, type UseRulePreviewArgs, type UseRulePreviewResult, UtilityRow, VariantList, buildItemRef, buildRef, bulkDelete, bulkUpsert, checkPasteCompatibility, cloneValue, createDefaultDeepLinkAdapter, deleteRecord, downloadBlob, exportCsv, getRecordByRef, importCsv, listRecords, matchRecords, mergeIcons, parseRef, parsedRefToScope, parsedRefToTarget, pickHeaderIcon, resolutionChain, resolveRecord, restoreRecord, scopesEqual, splitItemRef, upsertRecord, useCollectedRecords, useCollectionItems, useDeepLinkState, useDirtyNavigation, useFacetBrowse, useIntroDismissed, useItemViewPref, useMergedRecord, usePresentationPref, useProductBrowse, useProductChildren, useRecordClipboard, useRecordEditor, useRecordList, useResolveAllRecords, useResolvedRecord, useRulePreview, useScopeProbe, useUnsavedGuard };
2053
+ export { ALL_ITEM_VIEWS, ALL_PRESENTATIONS, BatchList, BulkActionsMenu, type ClipboardEntry, type CollectedRecord, type CollectedSort, type CollectionRailMode, type CsvSchema, type CsvSchemaColumn, DEFAULT_DEEP_LINK_PARAM_NAMES, DEFAULT_I18N, DEFAULT_ICONS, type DeepLinkAdapter, type DeepLinkChangeKind, type DeepLinkHistoryMode, type DeepLinkOptions, type DeepLinkParamNames, type DeepLinkState, DefaultItemCards, DefaultItemTable, DefaultRecordCard, DefaultRecordRow, DeleteButton, type DirtyStrategy, DrawerPreview, type EditorContext, EditorItemNav, EmptyState, ErrorState, FacetList, InheritanceMarker, InheritanceProvider, InlinePreview, IntroCard, type ItemColumn, ItemListView, type ItemSlotContext, type ItemView, type ItemViewContext, ItemViewSwitcher, LoadingState, type MergeStrategy, type MergedRecord, type NavConfirmI18n, type ParsedRef, type PasteCompatibility, type PasteCompatibilityResult, PresentationSwitcher, type PreviewMode, PreviewScopePicker, PreviewToggleButton, type ProductBrowseItem, type ProductChildItem, ProductDrillDown, ProductList, type RecordBadge, RecordBrowser, type RecordCardinality, RecordEditor, RecordList, type RecordPresentation, type RecordSlotContext, type RecordSource, type RecordStatus, type RecordSummary, type RecordsAdminI18n, type RecordsAdminIcons, RecordsAdminShell, type RecordsAdminShellProps, type ResolvedDeepLinkParamNames, ResolvedPreview, type ResolvedRecord, ScopeBreadcrumb, type ScopeKind, ScopeTabs, SiblingRail, SidePreview, type SmartLinksSDK, StatusDot, StatusFilterPills, StatusIcon, type StatusTone, TabbedPreview, type TelemetryEvent, type UseCollectionItemsArgs, type UseRecordClipboardArgs, type UseRecordClipboardReturn, type UseResolveAllRecordsArgs, type UseResolveAllResult, type UseRulePreviewArgs, type UseRulePreviewResult, UtilityRow, VariantList, buildItemRef, buildRef, bulkDelete, bulkUpsert, checkPasteCompatibility, cloneValue, createDefaultDeepLinkAdapter, deleteRecord, downloadBlob, exportCsv, getRecordByRef, importCsv, listRecords, matchRecords, mergeIcons, parseRef, parsedRefToScope, parsedRefToTarget, pickHeaderIcon, resolutionChain, resolveRecord, restoreRecord, scopesEqual, splitItemRef, statusToneLabel, upsertRecord, useCollectedRecords, useCollectionItems, useDeepLinkState, useDirtyNavigation, useFacetBrowse, useIntroDismissed, useItemViewPref, useMergedRecord, usePresentationPref, useProductBrowse, useProductChildren, useRecordClipboard, useRecordEditor, useRecordList, useResolveAllRecords, useResolvedRecord, useRulePreview, useScopeProbe, useUnsavedGuard };