@proveanything/smartlinks-utils-ui 0.11.10 → 0.12.1

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.
@@ -67,7 +67,22 @@ interface RecordSummary<TData = unknown> {
67
67
  ref: string;
68
68
  scope: ParsedRef;
69
69
  data: TData | null;
70
+ /**
71
+ * Data-completeness status (NOT lifecycle). One of `'configured' |
72
+ * 'partial' | 'empty'`. Driven by `classify` and used by the rail's
73
+ * status-pill filter and default subtitle. For lifecycle (active /
74
+ * archived / draft), see {@link RecordSummary.lifecycleStatus}.
75
+ */
70
76
  status: RecordStatus;
77
+ /**
78
+ * Raw lifecycle status string from the SDK (`AppRecord.status`).
79
+ * Free-form by SDK contract; the shell treats values in
80
+ * `RecordsAdminShellProps.activeStatuses` (default `['active']`) plus
81
+ * `null` / `undefined` as "active". Anything else is history (archived,
82
+ * draft, etc.) and gets collapsed behind the rail's history disclosure.
83
+ * Distinct from {@link RecordSummary.status} which is data-completeness.
84
+ */
85
+ lifecycleStatus?: string;
71
86
  /** Display label for the list row. */
72
87
  label: string;
73
88
  /** Optional subtitle (e.g. SKU, GTIN). */
@@ -318,6 +333,14 @@ type TelemetryEvent = {
318
333
  recordType?: string;
319
334
  key: string;
320
335
  ref: string;
336
+ }
337
+ /** Lifecycle status flipped from the footer / header status menu. */
338
+ | {
339
+ type: 'lifecycle.change';
340
+ recordType?: string;
341
+ ref: string;
342
+ from: string | undefined;
343
+ to: string;
321
344
  };
322
345
 
323
346
  interface RecordsAdminI18n {
@@ -479,6 +502,33 @@ interface RecordsAdminI18n {
479
502
  hookAfterSaveFailed: string;
480
503
  hookBeforeDeleteFailed: string;
481
504
  hookAfterDeleteFailed: string;
505
+ /**
506
+ * History disclosure (per-slot collapsed footer for non-active records).
507
+ * `{n}` is replaced with the count.
508
+ */
509
+ historyDisclosureShow: string;
510
+ historyDisclosureHide: string;
511
+ /** Lifecycle controls (editor header dropdown + row menu). */
512
+ lifecycleStatusLabel: string;
513
+ lifecycleStatusActive: string;
514
+ lifecycleStatusArchived: string;
515
+ lifecycleStatusDraft: string;
516
+ /** Tooltip on the editor's status control. */
517
+ lifecycleStatusHint: string;
518
+ actionArchive: string;
519
+ actionRestore: string;
520
+ /** Footer / header status menu. */
521
+ lifecycleMenuLabel: string;
522
+ lifecycleChangeTo: string;
523
+ lifecycleCurrentBadge: string;
524
+ /** Singleton-slot conflict banner. */
525
+ conflictBannerTitle: string;
526
+ conflictBannerBodyOne: string;
527
+ conflictBannerBodyMany: string;
528
+ conflictArchiveDuplicates: string;
529
+ conflictDeleteDuplicates: string;
530
+ conflictDeleteConfirm: string;
531
+ conflictResolveLabel: string;
482
532
  }
483
533
  declare const DEFAULT_I18N: RecordsAdminI18n;
484
534
 
@@ -934,6 +984,36 @@ interface RecordsAdminShellProps<TData = unknown> {
934
984
  i18n?: Partial<RecordsAdminI18n>;
935
985
  onTelemetry?: (event: TelemetryEvent) => void;
936
986
  className?: string;
987
+ /**
988
+ * Lifecycle values treated as "active" by the rail and the singleton
989
+ * conflict detector. Defaults to `['active']`. Records with a missing
990
+ * `status` are always treated as active for back-compat. Set this only
991
+ * if your data uses a different vocabulary (e.g. `['active', 'live']`).
992
+ *
993
+ * @deprecated Prefer `lifecycle.statuses` (mark each def with `isActive`).
994
+ * This prop continues to work as a back-compat shortcut and is merged
995
+ * into the resolved active set.
996
+ */
997
+ activeStatuses?: readonly string[];
998
+ /**
999
+ * Lifecycle config — controls how the shell treats record status as a
1000
+ * primary surface. See {@link LifecycleConfig}. When omitted the
1001
+ * built-in trio (Draft / Active / Archived) is used and a single-button
1002
+ * status menu is rendered in the editor footer next to Delete.
1003
+ */
1004
+ lifecycle?: LifecycleConfig;
1005
+ /**
1006
+ * Singleton-slot conflict resolution actions. The shell always *detects*
1007
+ * duplicates (multiple active records sharing the same slot) and surfaces
1008
+ * the banner; this prop only controls which bulk-resolution buttons the
1009
+ * banner offers.
1010
+ *
1011
+ * Defaults: both `archiveDuplicates` and `deleteDuplicates` are enabled.
1012
+ * Set either to `false` to hide that button. If both are disabled the
1013
+ * banner falls back to detection-only with the legacy "Resolve" CTA that
1014
+ * jumps to the first duplicate.
1015
+ */
1016
+ conflicts?: ConflictsConfig;
937
1017
  }
938
1018
  interface HeaderStatsConfig {
939
1019
  /** Show a counts strip in the header. */
@@ -1173,6 +1253,96 @@ interface ActionsConfig {
1173
1253
  /** Optional icon component rendered before each action label. */
1174
1254
  icons?: Partial<Record<RecordsAdminActionKey, RecordsAdminActionIcon>>;
1175
1255
  }
1256
+ /**
1257
+ * Bulk-resolution affordances offered in the singleton conflict banner.
1258
+ * Detection is always on; this only gates the action buttons.
1259
+ */
1260
+ interface ConflictsConfig {
1261
+ /** Show the "Archive duplicates" button. Default `true`. */
1262
+ archiveDuplicates?: boolean;
1263
+ /** Show the "Delete duplicates" button. Default `true`. */
1264
+ deleteDuplicates?: boolean;
1265
+ /** Lifecycle status string written when archiving. Default `'archived'`. */
1266
+ archivedStatus?: string;
1267
+ }
1268
+ /**
1269
+ * One row in the host-configurable lifecycle vocabulary. The shell uses
1270
+ * these to populate the footer status menu, drive the rail's auto-grouping
1271
+ * tones, and decide which records are considered "active" by the resolver
1272
+ * and the singleton conflict detector.
1273
+ *
1274
+ * Built-in defaults live in `data/lifecycleStatuses.ts` —
1275
+ * `[draft (warning), active (success, isActive), archived (muted)]`.
1276
+ */
1277
+ interface LifecycleStatusDef {
1278
+ /** The literal status string written to `AppRecord.status`. */
1279
+ value: string;
1280
+ /** Visible label in menus / group headers. */
1281
+ label: string;
1282
+ /** Semantic tone — drives the dot colour and the rail bucket tone. */
1283
+ tone: 'success' | 'warning' | 'muted' | 'danger' | 'default';
1284
+ /**
1285
+ * Mark this status as part of the "live" set. Active records are the
1286
+ * ones the resolver / public consumer sees and the only ones flagged in
1287
+ * singleton-slot conflict detection. Default `false`.
1288
+ */
1289
+ isActive?: boolean;
1290
+ /** Optional Lucide-style icon rendered before the label. */
1291
+ icon?: ComponentType<{
1292
+ className?: string;
1293
+ }>;
1294
+ }
1295
+ /**
1296
+ * Context passed to `lifecycle.beforeChange`. Return `false` to veto the
1297
+ * status flip (the menu re-opens with the change rejected; nothing is
1298
+ * written to the SDK). Throwing has the same effect.
1299
+ */
1300
+ interface LifecycleChangeCtx {
1301
+ recordId: string;
1302
+ from: string | undefined;
1303
+ to: string;
1304
+ scope: ParsedRef;
1305
+ }
1306
+ /**
1307
+ * Lifecycle configuration. All fields optional — omit the prop entirely
1308
+ * to get the built-in trio + footer menu + conditional auto-grouping.
1309
+ */
1310
+ interface LifecycleConfig {
1311
+ /**
1312
+ * Replace or extend the built-in vocabulary. The first `isActive: true`
1313
+ * status is treated as the canonical "live" value. Hosts typically
1314
+ * spread `DEFAULT_LIFECYCLE_STATUSES` here when adding extra values
1315
+ * (e.g. `'scheduled'`, `'under-review'`).
1316
+ */
1317
+ statuses?: readonly LifecycleStatusDef[];
1318
+ /**
1319
+ * Status assigned to brand-new records on first save. Default
1320
+ * `'active'`. Apps that publish in two steps (CMS, FAQ, votes, etc.)
1321
+ * typically set this to `'draft'`.
1322
+ */
1323
+ defaultStatus?: string;
1324
+ /**
1325
+ * Where the status switcher appears.
1326
+ * - `'footer'` *(default)* — single button next to Delete in the footer.
1327
+ * - `'header'` — legacy header dropdown (compact, less discoverable).
1328
+ * - `'both'` — render in both places.
1329
+ * - `'off'` — host opts out entirely (e.g. status managed elsewhere).
1330
+ */
1331
+ surface?: 'footer' | 'header' | 'both' | 'off';
1332
+ /**
1333
+ * Whether the rail automatically groups records by lifecycle bucket
1334
+ * when the data contains non-active statuses AND the host hasn't
1335
+ * supplied its own `rail.groupBy`. Default `true`. Setting to `false`
1336
+ * keeps the flat list regardless of mixed data.
1337
+ */
1338
+ autoGroup?: boolean;
1339
+ /**
1340
+ * Veto hook fired before every status flip. Return `false` (or throw)
1341
+ * to abort. Use this for app-side validation — e.g. "can't publish
1342
+ * without a question text", "can't archive while a vote is running".
1343
+ */
1344
+ beforeChange?: (ctx: LifecycleChangeCtx) => boolean | Promise<boolean>;
1345
+ }
1176
1346
  /**
1177
1347
  * Controls the small tab strip that appears above the editor body inside the
1178
1348
  * product drill-down.
@@ -1219,7 +1389,7 @@ interface RecordBrowserProps {
1219
1389
  }
1220
1390
  declare const RecordBrowser: ({ scopes, activeScope, onActiveScopeChange, selectedId, onSelectRef, items, counts, isLoading, error, filter, onFilterChange, search, onSearchChange, hasNextPage, isFetchingNextPage, onLoadMore, scopesLoading, i18n, }: RecordBrowserProps) => react_jsx_runtime.JSX.Element;
1221
1391
 
1222
- interface Props$h {
1392
+ interface Props$i {
1223
1393
  scopes: ScopeKind[];
1224
1394
  active: ScopeKind;
1225
1395
  onChange: (s: ScopeKind) => void;
@@ -1237,20 +1407,20 @@ interface Props$h {
1237
1407
  /** Override icons used per scope. Falls back to DEFAULT_ICONS.scope. */
1238
1408
  icons?: RecordsAdminIcons['scope'];
1239
1409
  }
1240
- declare const ScopeTabs: ({ scopes, active, onChange, loading, counts, tooltips, icons, }: Props$h) => react_jsx_runtime.JSX.Element;
1410
+ declare const ScopeTabs: ({ scopes, active, onChange, loading, counts, tooltips, icons, }: Props$i) => react_jsx_runtime.JSX.Element;
1241
1411
 
1242
- interface Props$g {
1412
+ interface Props$h {
1243
1413
  source?: RecordSource;
1244
1414
  status?: RecordStatus;
1245
1415
  className?: string;
1246
1416
  }
1247
1417
  /** Emerald = own data, amber = inherited, muted = empty */
1248
- declare const StatusDot: ({ source, status, className }: Props$g) => react_jsx_runtime.JSX.Element;
1418
+ declare const StatusDot: ({ source, status, className }: Props$h) => react_jsx_runtime.JSX.Element;
1249
1419
 
1250
1420
  type StatusTone = 'own' | 'shared' | 'missing';
1251
1421
  /** Semantic tones used by host-driven iconography (e.g. lifecycle buckets). */
1252
1422
  type SemanticTone = 'success' | 'warning' | 'danger' | 'muted' | 'info' | 'default';
1253
- interface Props$f {
1423
+ interface Props$g {
1254
1424
  source?: RecordSource;
1255
1425
  status?: RecordStatus;
1256
1426
  className?: string;
@@ -1272,11 +1442,11 @@ interface Props$f {
1272
1442
  */
1273
1443
  semanticTone?: SemanticTone;
1274
1444
  }
1275
- declare const StatusIcon: ({ source, status, className, size, label, iconHint, semanticTone, }: Props$f) => react_jsx_runtime.JSX.Element;
1445
+ declare const StatusIcon: ({ source, status, className, size, label, iconHint, semanticTone, }: Props$g) => react_jsx_runtime.JSX.Element;
1276
1446
  /** Short label rendered next to / under the row title. */
1277
1447
  declare const statusToneLabel: (tone: StatusTone) => string;
1278
1448
 
1279
- interface Props$e {
1449
+ interface Props$f {
1280
1450
  value: 'all' | RecordStatus;
1281
1451
  onChange: (v: 'all' | RecordStatus) => void;
1282
1452
  counts: {
@@ -1291,9 +1461,9 @@ interface Props$e {
1291
1461
  * active filter is always rendered so users never lose context. */
1292
1462
  hideZero?: Array<'all' | RecordStatus>;
1293
1463
  }
1294
- declare const StatusFilterPills: ({ value, onChange, counts, i18n, hideZero }: Props$e) => react_jsx_runtime.JSX.Element;
1464
+ declare const StatusFilterPills: ({ value, onChange, counts, i18n, hideZero }: Props$f) => react_jsx_runtime.JSX.Element;
1295
1465
 
1296
- interface Props$d {
1466
+ interface Props$e {
1297
1467
  items: RecordSummary[];
1298
1468
  /**
1299
1469
  * UUID of the currently-selected row. Matches `RecordSummary.id`. Records
@@ -1364,12 +1534,20 @@ interface Props$d {
1364
1534
  rowActions?: (record: RecordSummary) => RecordAction[] | null | undefined;
1365
1535
  /** Resolved i18n strings — used by default row/card renderers. */
1366
1536
  i18n?: RecordsAdminI18n;
1537
+ /**
1538
+ * Optional map of non-active records keyed by `slotKey`. When provided,
1539
+ * each rendered active row that has a matching bucket gets a disclosure
1540
+ * footer (`Show N archived`) appended. Expanded buckets render the
1541
+ * history records inline beneath the active row, dimmed and badged with
1542
+ * their lifecycle status. Pass `undefined` (default) to opt out.
1543
+ */
1544
+ historyBySlot?: ReadonlyMap<string, readonly RecordSummary[]>;
1367
1545
  }
1368
- declare const RecordList: ({ items, selectedId, selectedAnchorKey, onSelect, dirtyId, dirtyAnchorKey, dirtyKeys, errorKeys, presentation, renderListRow, groupBy, renderGroupActions, rowClipboard, rowActions, i18n, }: Props$d) => react_jsx_runtime.JSX.Element;
1369
- declare const ProductList: ({ items, selectedId, selectedAnchorKey, onSelect, dirtyId, dirtyAnchorKey, dirtyKeys, errorKeys, presentation, renderListRow, groupBy, renderGroupActions, rowClipboard, rowActions, i18n, }: Props$d) => react_jsx_runtime.JSX.Element;
1370
- declare const FacetList: ({ items, selectedId, selectedAnchorKey, onSelect, dirtyId, dirtyAnchorKey, dirtyKeys, errorKeys, presentation, renderListRow, groupBy, renderGroupActions, rowClipboard, rowActions, i18n, }: Props$d) => react_jsx_runtime.JSX.Element;
1371
- declare const VariantList: ({ items, selectedId, selectedAnchorKey, onSelect, dirtyId, dirtyAnchorKey, dirtyKeys, errorKeys, presentation, renderListRow, groupBy, renderGroupActions, rowClipboard, rowActions, i18n, }: Props$d) => react_jsx_runtime.JSX.Element;
1372
- declare const BatchList: ({ items, selectedId, selectedAnchorKey, onSelect, dirtyId, dirtyAnchorKey, dirtyKeys, errorKeys, presentation, renderListRow, groupBy, renderGroupActions, rowClipboard, rowActions, i18n, }: Props$d) => react_jsx_runtime.JSX.Element;
1546
+ declare const RecordList: ({ items, selectedId, selectedAnchorKey, onSelect, dirtyId, dirtyAnchorKey, dirtyKeys, errorKeys, presentation, renderListRow, groupBy, renderGroupActions, rowClipboard, rowActions, i18n, historyBySlot, }: Props$e) => react_jsx_runtime.JSX.Element;
1547
+ declare const ProductList: ({ items, selectedId, selectedAnchorKey, onSelect, dirtyId, dirtyAnchorKey, dirtyKeys, errorKeys, presentation, renderListRow, groupBy, renderGroupActions, rowClipboard, rowActions, i18n, historyBySlot, }: Props$e) => react_jsx_runtime.JSX.Element;
1548
+ declare const FacetList: ({ items, selectedId, selectedAnchorKey, onSelect, dirtyId, dirtyAnchorKey, dirtyKeys, errorKeys, presentation, renderListRow, groupBy, renderGroupActions, rowClipboard, rowActions, i18n, historyBySlot, }: Props$e) => react_jsx_runtime.JSX.Element;
1549
+ declare const VariantList: ({ items, selectedId, selectedAnchorKey, onSelect, dirtyId, dirtyAnchorKey, dirtyKeys, errorKeys, presentation, renderListRow, groupBy, renderGroupActions, rowClipboard, rowActions, i18n, historyBySlot, }: Props$e) => react_jsx_runtime.JSX.Element;
1550
+ declare const BatchList: ({ items, selectedId, selectedAnchorKey, onSelect, dirtyId, dirtyAnchorKey, dirtyKeys, errorKeys, presentation, renderListRow, groupBy, renderGroupActions, rowClipboard, rowActions, i18n, historyBySlot, }: Props$e) => react_jsx_runtime.JSX.Element;
1373
1551
 
1374
1552
  interface DefaultRecordRowProps {
1375
1553
  record: RecordSummary;
@@ -1411,7 +1589,7 @@ declare const ErrorState: ({ error }: {
1411
1589
  error: Error;
1412
1590
  }) => react_jsx_runtime.JSX.Element;
1413
1591
 
1414
- interface Props$c {
1592
+ interface Props$d {
1415
1593
  i18n: RecordsAdminI18n;
1416
1594
  onApplyToMany?: () => void;
1417
1595
  onCopyFrom?: () => void;
@@ -1419,9 +1597,9 @@ interface Props$c {
1419
1597
  onImportCsv?: () => void;
1420
1598
  onExportCsv?: () => void;
1421
1599
  }
1422
- declare const BulkActionsMenu: ({ i18n, onApplyToMany, onCopyFrom, onClearMany, onImportCsv, onExportCsv, }: Props$c) => react_jsx_runtime.JSX.Element | null;
1600
+ declare const BulkActionsMenu: ({ i18n, onApplyToMany, onCopyFrom, onClearMany, onImportCsv, onExportCsv, }: Props$d) => react_jsx_runtime.JSX.Element | null;
1423
1601
 
1424
- interface Props$b<T> {
1602
+ interface Props$c<T> {
1425
1603
  ctx: EditorContext<T>;
1426
1604
  i18n: RecordsAdminI18n;
1427
1605
  children: ReactNode;
@@ -1440,6 +1618,21 @@ interface Props$b<T> {
1440
1618
  * the editor header without scrolling to the Targeting section.
1441
1619
  */
1442
1620
  targetingControl?: ReactNode;
1621
+ /**
1622
+ * Optional small control rendered in the header's right cluster for
1623
+ * lifecycle status (Active / Archived / Draft). The shell wires this
1624
+ * for records that already exist on the server (no point until first
1625
+ * save). Independent of dirty draft state — flipping status saves
1626
+ * immediately via `records.update`.
1627
+ */
1628
+ lifecycleControl?: ReactNode;
1629
+ /**
1630
+ * Optional lifecycle status switcher rendered in the footer's left
1631
+ * cluster, between Delete and the clipboard buttons. This is the
1632
+ * primary surface for status (`LifecycleStatusMenu`); the header
1633
+ * `lifecycleControl` slot is the legacy / opt-in alternative.
1634
+ */
1635
+ lifecycleControlFooter?: ReactNode;
1443
1636
  bulkActions?: React.ComponentProps<typeof BulkActionsMenu>;
1444
1637
  /** Extra slot rendered in the footer between the danger actions and Save. */
1445
1638
  footerExtra?: ReactNode;
@@ -1468,6 +1661,13 @@ interface Props$b<T> {
1468
1661
  * without it competing with the friendly name as a subtitle.
1469
1662
  */
1470
1663
  headerMeta?: string;
1664
+ /**
1665
+ * Optional inline notice rendered at the top of the editor body, above
1666
+ * `targeting`. Used by the shell to surface singleton-slot conflict
1667
+ * warnings ("This is 1 of 4 records sharing this slot…") so the admin
1668
+ * sees the problem while editing the record.
1669
+ */
1670
+ headerNotice?: ReactNode;
1471
1671
  /**
1472
1672
  * Clipboard footer actions. The shell wires these when `enableClipboard`
1473
1673
  * is on. Copy is always offered when there's an editing scope; Paste is
@@ -1495,7 +1695,7 @@ interface Props$b<T> {
1495
1695
  /** Host-provided icons rendered before save / discard / delete labels. */
1496
1696
  actionIcons?: Partial<Record<RecordsAdminActionKey, RecordsAdminActionIcon>>;
1497
1697
  }
1498
- declare function RecordEditor<T>({ ctx, i18n, children, preview, targeting, targetingControl, bulkActions, footerExtra, onBeforeDelete, headerLabel, headerSubtitle, headerMeta, headerLeading, clipboard, actionLabels, actionIcons, }: Props$b<T>): react_jsx_runtime.JSX.Element;
1698
+ declare function RecordEditor<T>({ ctx, i18n, children, preview, targeting, targetingControl, lifecycleControl, lifecycleControlFooter, bulkActions, footerExtra, onBeforeDelete, headerLabel, headerSubtitle, headerMeta, headerLeading, headerNotice, clipboard, actionLabels, actionIcons, }: Props$c<T>): react_jsx_runtime.JSX.Element;
1499
1699
 
1500
1700
  interface InheritanceCtx {
1501
1701
  parentValue?: Record<string, unknown> | null;
@@ -1513,10 +1713,10 @@ interface MarkerProps {
1513
1713
  }
1514
1714
  declare const InheritanceMarker: ({ field, inheritedValue, value, children }: MarkerProps) => react_jsx_runtime.JSX.Element;
1515
1715
 
1516
- interface Props$a {
1716
+ interface Props$b {
1517
1717
  children: ReactNode;
1518
1718
  }
1519
- declare const ResolvedPreview: ({ children }: Props$a) => react_jsx_runtime.JSX.Element;
1719
+ declare const ResolvedPreview: ({ children }: Props$b) => react_jsx_runtime.JSX.Element;
1520
1720
 
1521
1721
  interface ProductChildItem {
1522
1722
  /** Variant or batch id (the `<id>` part of `variant:<id>` / `batch:<id>`). */
@@ -1547,7 +1747,7 @@ declare const useProductChildren: (args: UseProductChildrenArgs) => {
1547
1747
  };
1548
1748
 
1549
1749
  type DrillTab = 'product' | 'variant' | 'batch';
1550
- interface Props$9 {
1750
+ interface Props$a {
1551
1751
  productLabel: string;
1552
1752
  /** Which child types are available on the collection. */
1553
1753
  showVariants: boolean;
@@ -1572,7 +1772,7 @@ interface Props$9 {
1572
1772
  */
1573
1773
  hideSingleTab?: boolean;
1574
1774
  }
1575
- declare const ProductDrillDown: ({ productLabel, showVariants, showBatches, active, onChange, selectedChildId, onSelectChild, variants, batches, variantsLoading, batchesLoading, children, hideSingleTab, }: Props$9) => react_jsx_runtime.JSX.Element;
1775
+ declare const ProductDrillDown: ({ productLabel, showVariants, showBatches, active, onChange, selectedChildId, onSelectChild, variants, batches, variantsLoading, batchesLoading, children, hideSingleTab, }: Props$a) => react_jsx_runtime.JSX.Element;
1576
1776
 
1577
1777
  type PreviewMode = 'inline' | 'side' | 'tab' | 'drawer';
1578
1778
  interface CommonProps {
@@ -1640,7 +1840,7 @@ interface PreviewScopePickerProps {
1640
1840
  }
1641
1841
  declare const PreviewScopePicker: ({ SL, collectionId, editingScope, value, onChange, showVariants, showBatches, activeScope, i18n, }: PreviewScopePickerProps) => react_jsx_runtime.JSX.Element | null;
1642
1842
 
1643
- interface Props$8 {
1843
+ interface Props$9 {
1644
1844
  /** Element whose right edge the pill should anchor to. */
1645
1845
  anchorRef: React.RefObject<HTMLElement>;
1646
1846
  onClick: () => void;
@@ -1648,14 +1848,14 @@ interface Props$8 {
1648
1848
  title: string;
1649
1849
  children: ReactNode;
1650
1850
  }
1651
- declare function PreviewReopenPill({ anchorRef, onClick, ariaLabel, title, children }: Props$8): React$1.ReactPortal | null;
1851
+ declare function PreviewReopenPill({ anchorRef, onClick, ariaLabel, title, children }: Props$9): React$1.ReactPortal | null;
1652
1852
 
1653
1853
  declare const ScopeBreadcrumb: ({ scope }: {
1654
1854
  scope: ParsedRef;
1655
1855
  }) => react_jsx_runtime.JSX.Element | null;
1656
1856
 
1657
1857
  type IntroTone = 'info' | 'success' | 'warning';
1658
- interface Props$7 {
1858
+ interface Props$8 {
1659
1859
  title: string;
1660
1860
  body: ReactNode;
1661
1861
  onDismiss: () => void;
@@ -1664,16 +1864,16 @@ interface Props$7 {
1664
1864
  /** Optional "Learn more" link or button rendered inline after the body. */
1665
1865
  action?: ReactNode;
1666
1866
  }
1667
- declare const IntroCard: ({ title, body, onDismiss, tone, action }: Props$7) => react_jsx_runtime.JSX.Element;
1867
+ declare const IntroCard: ({ title, body, onDismiss, tone, action }: Props$8) => react_jsx_runtime.JSX.Element;
1668
1868
 
1669
- interface Props$6 {
1869
+ interface Props$7 {
1670
1870
  label: string;
1671
1871
  /** Optional override for the button label. When set, takes precedence over `label`. */
1672
1872
  customLabel?: string;
1673
1873
  introHidden: boolean;
1674
1874
  onShowIntro?: () => void;
1675
1875
  }
1676
- declare const UtilityRow: ({ label, customLabel, introHidden, onShowIntro }: Props$6) => react_jsx_runtime.JSX.Element | null;
1876
+ declare const UtilityRow: ({ label, customLabel, introHidden, onShowIntro }: Props$7) => react_jsx_runtime.JSX.Element | null;
1677
1877
 
1678
1878
  /** Flat anchor shape — matches `UpsertRecordInput` / `BulkUpsertItem`. */
1679
1879
  interface RecordAnchors {
@@ -1831,10 +2031,20 @@ interface UseRecordListArgs {
1831
2031
  };
1832
2032
  /** Page size requested from the SDK (default 100). */
1833
2033
  pageSize?: number;
2034
+ /**
2035
+ * Lifecycle values treated as "active". Defaults to `['active']`. Records
2036
+ * with a missing/empty `status` are always treated as active (legacy
2037
+ * back-compat). Hosts override this if their vocabulary differs (e.g.
2038
+ * `['active', 'live']`).
2039
+ */
2040
+ activeStatuses?: readonly string[];
1834
2041
  }
1835
2042
  declare const useRecordList: (args: UseRecordListArgs) => {
1836
2043
  allItems: RecordSummary<unknown>[];
1837
2044
  items: RecordSummary<unknown>[];
2045
+ activeItems: RecordSummary<unknown>[];
2046
+ historyItems: RecordSummary<unknown>[];
2047
+ historyBySlot: Map<string, RecordSummary<unknown>[]>;
1838
2048
  total: number;
1839
2049
  counts: {
1840
2050
  all: number;
@@ -2504,7 +2714,7 @@ declare function useItemViewPref(args: {
2504
2714
  defaultValue: ItemView;
2505
2715
  }): [ItemView, (next: ItemView) => void];
2506
2716
 
2507
- interface Props$5<T> {
2717
+ interface Props$6<T> {
2508
2718
  items: RecordSummary<T>[];
2509
2719
  isLoading: boolean;
2510
2720
  error: Error | null;
@@ -2555,22 +2765,22 @@ interface Props$5<T> {
2555
2765
  onLoadMore?: () => void;
2556
2766
  i18n: RecordsAdminI18n;
2557
2767
  }
2558
- declare function ItemListView<T>({ items, isLoading, error, ctx, itemNoun, ruleSummary, view, views, onViewChange, renderItemList, renderItemCard, renderItemEmpty, itemColumns, cardSize, rowActions, rowClipboard, searchableFields, searchable, total, hasNextPage, isFetchingNextPage, onLoadMore, i18n, }: Props$5<T>): react_jsx_runtime.JSX.Element;
2768
+ declare function ItemListView<T>({ items, isLoading, error, ctx, itemNoun, ruleSummary, view, views, onViewChange, renderItemList, renderItemCard, renderItemEmpty, itemColumns, cardSize, rowActions, rowClipboard, searchableFields, searchable, total, hasNextPage, isFetchingNextPage, onLoadMore, i18n, }: Props$6<T>): react_jsx_runtime.JSX.Element;
2559
2769
 
2560
- interface Props$4 {
2770
+ interface Props$5 {
2561
2771
  options: ItemView[];
2562
2772
  value: ItemView;
2563
2773
  onChange: (next: ItemView) => void;
2564
2774
  i18n: Pick<RecordsAdminI18n, 'itemViewTable' | 'itemViewCards' | 'itemViewGallery'>;
2565
2775
  }
2566
- declare const ItemViewSwitcher: ({ options, value, onChange, i18n }: Props$4) => react_jsx_runtime.JSX.Element | null;
2776
+ declare const ItemViewSwitcher: ({ options, value, onChange, i18n }: Props$5) => react_jsx_runtime.JSX.Element | null;
2567
2777
 
2568
2778
  type SortDir = 'asc' | 'desc' | null;
2569
2779
  interface SortState {
2570
2780
  key: string | null;
2571
2781
  dir: SortDir;
2572
2782
  }
2573
- interface Props$3<T> {
2783
+ interface Props$4<T> {
2574
2784
  items: RecordSummary<T>[];
2575
2785
  columns?: ItemColumn<T>[];
2576
2786
  selectedId?: string;
@@ -2592,9 +2802,9 @@ interface Props$3<T> {
2592
2802
  } | null;
2593
2803
  i18n: Pick<RecordsAdminI18n, 'itemColumnLabel' | 'itemColumnUpdated' | 'itemActions' | 'delete'>;
2594
2804
  }
2595
- declare function DefaultItemTable<T>({ items, columns, selectedId, onOpen, onDelete, sort, onToggleSort, rowActions, rowClipboard, i18n, }: Props$3<T>): react_jsx_runtime.JSX.Element;
2805
+ declare function DefaultItemTable<T>({ items, columns, selectedId, onOpen, onDelete, sort, onToggleSort, rowActions, rowClipboard, i18n, }: Props$4<T>): react_jsx_runtime.JSX.Element;
2596
2806
 
2597
- interface Props$2<T> {
2807
+ interface Props$3<T> {
2598
2808
  items: RecordSummary<T>[];
2599
2809
  variant: 'cards' | 'gallery';
2600
2810
  selectedId?: string;
@@ -2611,9 +2821,9 @@ interface Props$2<T> {
2611
2821
  } | null;
2612
2822
  i18n: Pick<RecordsAdminI18n, 'delete'>;
2613
2823
  }
2614
- declare function DefaultItemCards<T>({ items, variant, selectedId, ctx, renderCard, cardSize, rowActions, rowClipboard, i18n, }: Props$2<T>): react_jsx_runtime.JSX.Element;
2824
+ declare function DefaultItemCards<T>({ items, variant, selectedId, ctx, renderCard, cardSize, rowActions, rowClipboard, i18n, }: Props$3<T>): react_jsx_runtime.JSX.Element;
2615
2825
 
2616
- interface Props$1 {
2826
+ interface Props$2 {
2617
2827
  /** Friendly name of the item being edited (mostly for screen readers). */
2618
2828
  label?: string;
2619
2829
  /** 1-based position within the current sibling list. */
@@ -2633,9 +2843,9 @@ interface Props$1 {
2633
2843
  */
2634
2844
  embedded?: boolean;
2635
2845
  }
2636
- declare const EditorItemNav: ({ label, position, total, onBack, onPrev, onNext, canPrev, canNext, i18n, embedded, }: Props$1) => react_jsx_runtime.JSX.Element;
2846
+ declare const EditorItemNav: ({ label, position, total, onBack, onPrev, onNext, canPrev, canNext, i18n, embedded, }: Props$2) => react_jsx_runtime.JSX.Element;
2637
2847
 
2638
- interface Props<T> {
2848
+ interface Props$1<T> {
2639
2849
  items: RecordSummary<T>[];
2640
2850
  selectedItemId?: string;
2641
2851
  isLoading: boolean;
@@ -2677,7 +2887,7 @@ interface Props<T> {
2677
2887
  onLoadMore?: () => void;
2678
2888
  i18n: Pick<RecordsAdminI18n, 'backToScopes' | 'siblingsHeading' | 'noItemsTitle' | 'noItemsBody' | 'backToList' | 'newItem'>;
2679
2889
  }
2680
- declare function SiblingRail<T>({ items, selectedItemId, isLoading, error, onBack, onSelect, contextKind, contextSummary, onCreate, itemNoun, dirtyKeys, errorKeys, i18n, total, hasNextPage, isFetchingNextPage, onLoadMore, }: Props<T>): react_jsx_runtime.JSX.Element;
2890
+ declare function SiblingRail<T>({ items, selectedItemId, isLoading, error, onBack, onSelect, contextKind, contextSummary, onCreate, itemNoun, dirtyKeys, errorKeys, i18n, total, hasNextPage, isFetchingNextPage, onLoadMore, }: Props$1<T>): react_jsx_runtime.JSX.Element;
2681
2891
 
2682
2892
  interface ClipboardEntry<T = unknown> {
2683
2893
  value: T;
@@ -2750,6 +2960,65 @@ interface DeleteButtonProps {
2750
2960
  }
2751
2961
  declare const DeleteButton: ({ onConfirm, onBeforeDelete, label, confirmLabel, revertMs, disabled, icon, }: DeleteButtonProps) => react_jsx_runtime.JSX.Element;
2752
2962
 
2963
+ interface Props {
2964
+ SL: SmartLinksSDK;
2965
+ collectionId: string;
2966
+ appId: string;
2967
+ recordId: string;
2968
+ scope: ParsedRef;
2969
+ /** Current lifecycle value on the record (may be undefined for legacy data). */
2970
+ current: string | undefined;
2971
+ /** Available statuses (defaults are passed by the shell). */
2972
+ statuses: readonly LifecycleStatusDef[];
2973
+ i18n: RecordsAdminI18n;
2974
+ /** Optional veto hook — return false / throw to abort the change. */
2975
+ beforeChange?: (ctx: LifecycleChangeCtx) => boolean | Promise<boolean>;
2976
+ /** Fires after a successful flip with the new value. */
2977
+ onChanged?: (next: string) => void;
2978
+ /** Telemetry hook — receives `{ from, to }`. */
2979
+ onTelemetry?: (event: {
2980
+ from: string | undefined;
2981
+ to: string;
2982
+ }) => void;
2983
+ /**
2984
+ * Visual size — `'sm'` matches the editor footer button height; `'xs'`
2985
+ * matches the legacy header pill. Defaults to `'sm'`.
2986
+ */
2987
+ size?: 'sm' | 'xs';
2988
+ }
2989
+ declare const LifecycleStatusMenu: ({ SL, collectionId, appId, recordId, scope, current, statuses, i18n, beforeChange, onChanged, onTelemetry, size, }: Props) => react_jsx_runtime.JSX.Element;
2990
+
2991
+ /**
2992
+ * Canonical built-in trio. `active` is the only status flagged
2993
+ * `isActive: true` — drafts and archived records are excluded from the
2994
+ * "live" set used by the rail and the singleton conflict detector.
2995
+ *
2996
+ * Hosts can extend this set (e.g. add `'scheduled'`) by passing a custom
2997
+ * `lifecycle.statuses` array — typically `[...DEFAULT_LIFECYCLE_STATUSES, …]`.
2998
+ */
2999
+ declare const DEFAULT_LIFECYCLE_STATUSES: readonly LifecycleStatusDef[];
3000
+ /** Resolve the host-configured status list, falling back to the trio. */
3001
+ declare const getLifecycleStatuses: (config?: LifecycleConfig) => readonly LifecycleStatusDef[];
3002
+ /**
3003
+ * Lifecycle values treated as "live" by the rail and the resolver.
3004
+ * Records with a missing/empty `status` are ALWAYS treated as active for
3005
+ * back-compat with legacy data — that rule lives in `singletonConflicts.isActive`
3006
+ * and is preserved by callers; this helper only enumerates the explicit set.
3007
+ *
3008
+ * Back-compat: when the host passes the legacy `activeStatuses` prop, the
3009
+ * shell merges it on top so old call sites keep working.
3010
+ */
3011
+ declare const getActiveStatusValues: (config?: LifecycleConfig, legacyActiveStatuses?: readonly string[]) => readonly string[];
3012
+ /**
3013
+ * Look up the def that matches a record's current `lifecycleStatus`.
3014
+ * Falls back to the `'active'` def when the record has no status set
3015
+ * (legacy back-compat — missing status counts as active).
3016
+ */
3017
+ declare const resolveLifecycleStatus: (record: Pick<RecordSummary, "lifecycleStatus">, config?: LifecycleConfig) => LifecycleStatusDef;
3018
+ /** True when at least one record uses a non-active lifecycle status. */
3019
+ declare const hasMixedLifecycle: (records: readonly RecordSummary[], activeValues: readonly string[]) => boolean;
3020
+ declare const compareLifecycleBuckets: (a: string, b: string) => number;
3021
+
2753
3022
  declare const parseRef: (raw: string) => ParsedRef;
2754
3023
  interface BuildRefArgs {
2755
3024
  collectionId?: string;
@@ -2834,4 +3103,4 @@ declare const exportCsv: <T>(records: RecordSummary<T>[], schema: CsvSchema<T>)
2834
3103
  declare const importCsv: <T>(file: File, schema: CsvSchema<T>, ctx: RecordsCtx) => Promise<ImportReport>;
2835
3104
  declare const downloadBlob: (blob: Blob, filename: string) => void;
2836
3105
 
2837
- 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 DirtyDraft, DirtyDraftProvider, type DirtyDraftStatus, type DirtyDraftStore, 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 NormalisedRule, type ParsedRef, type PasteCompatibility, type PasteCompatibilityResult, PresentationSwitcher, type PreviewMode, PreviewReopenPill, PreviewScopePicker, PreviewToggleButton, type ProductBrowseItem, type ProductChildItem, ProductDrillDown, ProductList, type RecordAction, type RecordBadge, RecordBrowser, type RecordCardinality, RecordEditor, RecordList, type RecordPresentation, type RecordSlotContext, type RecordSource, type RecordStatus, type RecordSummary, type RecordsAdminActionIcon, type RecordsAdminActionKey, type RecordsAdminI18n, type RecordsAdminIcons, RecordsAdminShell, type RecordsAdminShellProps, type ResolvedDeepLinkParamNames, ResolvedPreview, type ResolvedRecord, type RouterParamsGetter, type RouterParamsSetter, ScopeBreadcrumb, type ScopeCounts, 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, type UseScopeCountsArgs, type UseScopeCountsResult, UtilityRow, VariantList, buildDraftKey, buildRef, bulkDelete, bulkUpsert, checkPasteCompatibility, cloneValue, createDefaultDeepLinkAdapter, createPostMessageDeepLinkAdapter, createRecord, createRouterDeepLinkAdapter, downloadBlob, exportCsv, getRecordById, importCsv, isInSmartLinksIframe, listRecords, matchRecords, mergeIcons, normaliseRule, parseRef, parsedRefToScope, parsedRefToTarget, pickHeaderIcon, removeRecord, resolutionChain, resolveRecord, restoreRecord, ruleHash, rulesEqual, scopeCountsQueryKey, scopesEqual, statusToneLabel, summariseRule, upsertRecord, useCollectedRecords, useCollectionItems, useDeepLinkState, useDirtyDraft, useDirtyDraftActions, useDirtyDraftStore, useDirtyDrafts, useDirtyNavigation, useFacetBrowse, useIntroDismissed, useItemViewPref, useMergedRecord, usePresentationPref, useProductBrowse, useProductChildren, useRecordClipboard, useRecordEditor, useRecordList, useResolveAllRecords, useResolvedRecord, useRulePreview, useScopeCounts, useScopeProbe, useUnsavedGuard };
3106
+ export { ALL_ITEM_VIEWS, ALL_PRESENTATIONS, BatchList, BulkActionsMenu, type ClipboardEntry, type CollectedRecord, type CollectedSort, type CollectionRailMode, type ConflictsConfig, type CsvSchema, type CsvSchemaColumn, DEFAULT_DEEP_LINK_PARAM_NAMES, DEFAULT_I18N, DEFAULT_ICONS, DEFAULT_LIFECYCLE_STATUSES, type DeepLinkAdapter, type DeepLinkChangeKind, type DeepLinkHistoryMode, type DeepLinkOptions, type DeepLinkParamNames, type DeepLinkState, DefaultItemCards, DefaultItemTable, DefaultRecordCard, DefaultRecordRow, DeleteButton, type DirtyDraft, DirtyDraftProvider, type DirtyDraftStatus, type DirtyDraftStore, type DirtyStrategy, DrawerPreview, type EditorContext, EditorItemNav, EmptyState, ErrorState, FacetList, InheritanceMarker, InheritanceProvider, InlinePreview, IntroCard, type ItemColumn, ItemListView, type ItemSlotContext, type ItemView, type ItemViewContext, ItemViewSwitcher, type LifecycleChangeCtx, type LifecycleConfig, type LifecycleStatusDef, LifecycleStatusMenu, LoadingState, type MergeStrategy, type MergedRecord, type NavConfirmI18n, type NormalisedRule, type ParsedRef, type PasteCompatibility, type PasteCompatibilityResult, PresentationSwitcher, type PreviewMode, PreviewReopenPill, PreviewScopePicker, PreviewToggleButton, type ProductBrowseItem, type ProductChildItem, ProductDrillDown, ProductList, type RecordAction, type RecordBadge, RecordBrowser, type RecordCardinality, RecordEditor, RecordList, type RecordPresentation, type RecordSlotContext, type RecordSource, type RecordStatus, type RecordSummary, type RecordsAdminActionIcon, type RecordsAdminActionKey, type RecordsAdminI18n, type RecordsAdminIcons, RecordsAdminShell, type RecordsAdminShellProps, type ResolvedDeepLinkParamNames, ResolvedPreview, type ResolvedRecord, type RouterParamsGetter, type RouterParamsSetter, ScopeBreadcrumb, type ScopeCounts, 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, type UseScopeCountsArgs, type UseScopeCountsResult, UtilityRow, VariantList, buildDraftKey, buildRef, bulkDelete, bulkUpsert, checkPasteCompatibility, cloneValue, compareLifecycleBuckets, createDefaultDeepLinkAdapter, createPostMessageDeepLinkAdapter, createRecord, createRouterDeepLinkAdapter, downloadBlob, exportCsv, getActiveStatusValues, getLifecycleStatuses, getRecordById, hasMixedLifecycle, importCsv, isInSmartLinksIframe, listRecords, matchRecords, mergeIcons, normaliseRule, parseRef, parsedRefToScope, parsedRefToTarget, pickHeaderIcon, removeRecord, resolutionChain, resolveLifecycleStatus, resolveRecord, restoreRecord, ruleHash, rulesEqual, scopeCountsQueryKey, scopesEqual, statusToneLabel, summariseRule, upsertRecord, useCollectedRecords, useCollectionItems, useDeepLinkState, useDirtyDraft, useDirtyDraftActions, useDirtyDraftStore, useDirtyDrafts, useDirtyNavigation, useFacetBrowse, useIntroDismissed, useItemViewPref, useMergedRecord, usePresentationPref, useProductBrowse, useProductChildren, useRecordClipboard, useRecordEditor, useRecordList, useResolveAllRecords, useResolvedRecord, useRulePreview, useScopeCounts, useScopeProbe, useUnsavedGuard };