@mt-gloss/ui 0.0.23 → 0.0.25

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.
@@ -14,7 +14,7 @@ export type { MetricCardProps, CardShellProps } from '../primitives/dashboard/Me
14
14
  export type { StackedGroupCardProps, StackedValueEntry } from '../primitives/dashboard/MetricCard/StackedGroupCard';
15
15
  export type { CardBackProps } from '../primitives/dashboard/MetricCard/CardBack';
16
16
  export { ActionStrip, buildDefaultOverflow } from '../primitives/overlays/ActionStrip';
17
- export type { ActionStripProps, PrimaryAction, OverflowAction, ActionStripContext, ActionStripVariant, ActionStripMenuDirection, DefaultHandlers, } from '../primitives/overlays/ActionStrip';
17
+ export type { ActionStripProps, PrimaryAction, OverflowAction, ActionStripContext, ActionStripMenuDirection, DefaultHandlers, } from '../primitives/overlays/ActionStrip';
18
18
  export { SparklineBg } from '../primitives/dashboard/MetricCard';
19
19
  export { BarsBg } from '../primitives/dashboard/MetricCard';
20
20
  export { DonutChart } from '../primitives/dashboard/MetricCard';
@@ -1,9 +1,22 @@
1
1
  import { TrendData } from './types';
2
+ import { PrimaryAction, OverflowAction } from '../../overlays/ActionStrip/types';
2
3
  export interface StackedValueEntry {
3
4
  timeframe: string;
4
5
  value: number | null;
5
6
  trend?: TrendData | null;
6
7
  }
8
+ /**
9
+ * Phase 18 plan 18-01 — per-slot ActionStrip config shape returned by
10
+ * `slotToActionStripConfig(slotIdx)`. Composed from Phase 16 ActionStrip
11
+ * `PrimaryAction` + `OverflowAction` types so consumers import a single
12
+ * contract. Collapses CONTEXT §Per-slot API shape onto the two-array API.
13
+ */
14
+ export interface SlotActionStripConfig {
15
+ primary: PrimaryAction[];
16
+ overflow: OverflowAction[];
17
+ }
18
+ /** Selector mapping slot index → ActionStrip config for that slot. */
19
+ export type SlotToActionStripConfig = (slotIdx: number) => SlotActionStripConfig;
7
20
  export interface StackedGroupCardProps {
8
21
  title: string;
9
22
  prefix?: string;
@@ -44,6 +57,38 @@ export interface StackedGroupCardProps {
44
57
  * padding so trend text on the right does not collide with the stroke.
45
58
  */
46
59
  sparklineInset?: 'padded' | 'bleed';
60
+ /**
61
+ * Phase 18 plan 18-01 — per-slot ActionStrip config selector. Called with
62
+ * the currently-hovered slot index; returns the `{primary, overflow}`
63
+ * arrays that ActionStrip will render while that slot is hovered.
64
+ *
65
+ * When omitted (back-compat), the existing Cluster D `onSlotHoverStart/End`
66
+ * surface is preserved byte-for-byte — no new callbacks fire, no new DOM
67
+ * attributes appear, parent ActionStrip falls back to card-default config.
68
+ *
69
+ * When supplied, the selector runs on each slot `pointerenter` AFTER
70
+ * `onSlotHoverStart`. The resolved config is forwarded to the parent via
71
+ * `onSlotActionStripConfigChange`. The selector is invoked inside a
72
+ * try/catch; throws produce `console.error` + a `(idx, null)` change
73
+ * callback so the parent can fall back to card-default.
74
+ *
75
+ * AP-12 (Phase 18 new anti-pattern guard): When this prop co-occurs with
76
+ * a legacy global-action prop (detected at mount as `onTableAction` in
77
+ * props), the component emits `console.warn('[StackedGroupCard AP-12] …')`
78
+ * exactly once per mount. Mixing per-slot + global dispatch is ambiguous;
79
+ * remove the legacy global prop.
80
+ */
81
+ slotToActionStripConfig?: SlotToActionStripConfig;
82
+ /**
83
+ * Phase 18 plan 18-01 — fires whenever the resolved per-slot config
84
+ * changes. `(slotIdx, config)` on enter; `(null, null)` when pointer
85
+ * leaves the card (NOT fired when leaving to a sibling slot; the
86
+ * existing Cluster E `relatedTarget` guard keeps the bridge active).
87
+ *
88
+ * Parent owns the ActionStrip render + `anchorX` wiring; this callback
89
+ * is the bridge between per-slot hover and parent-level config state.
90
+ */
91
+ onSlotActionStripConfigChange?: (slotIdx: number | null, config: SlotActionStripConfig | null) => void;
47
92
  }
48
93
  /**
49
94
  * StackedGroupCard -- Renders 3 mini metric values horizontally within a 2-col card.
@@ -66,6 +111,6 @@ export interface StackedGroupCardProps {
66
111
  * ```
67
112
  */
68
113
  export declare const StackedGroupCard: {
69
- ({ title, prefix, suffix, values, timeframes, sparklineData, accentColor, pinnedTimeframe, onPinTimeframe, isStale, colSpan, onSlotHoverStart, onSlotHoverEnd, sparklineInset, }: StackedGroupCardProps): import("react/jsx-runtime").JSX.Element;
114
+ (props: StackedGroupCardProps): import("react/jsx-runtime").JSX.Element;
70
115
  displayName: string;
71
116
  };
@@ -0,0 +1,38 @@
1
+ import { computeGutterAnchorX as ComputeGutterAnchorXFn } from '../utils/computeGutterAnchorX';
2
+ export interface NyquistHarness {
3
+ /** Reference to the promoted math helper (assertion invariants call through it). */
4
+ computeGutterAnchorX: typeof ComputeGutterAnchorXFn;
5
+ }
6
+ export interface BehaviorDef {
7
+ /** 1-indexed for human readability in test output. */
8
+ id: number;
9
+ /** Short, greppable label. */
10
+ label: string;
11
+ /**
12
+ * The contract invariant this row pins. Either an assert-lambda that the
13
+ * runner invokes inside `it.each`, or `null` when the row is documented as
14
+ * covered by a sibling test file (runner skips but keeps the row in the
15
+ * matrix count pin).
16
+ */
17
+ assert: ((harness: NyquistHarness) => void | Promise<void>) | null;
18
+ /**
19
+ * When present, the runner skips the row with the returned reason string
20
+ * instead of calling `assert`. Used to document rows whose contract is
21
+ * pinned by a dedicated sibling test file (cross-reference maintained in
22
+ * 18-VALIDATION.md).
23
+ */
24
+ skipFor?: () => string | undefined;
25
+ }
26
+ /**
27
+ * The 9 NYQUIST-11 behaviors. Each row's `assert` OR `skipFor` is evaluated
28
+ * by the runner. Rows without an inline assert are documented in
29
+ * 18-VALIDATION.md as covered by sibling test files — they remain in the
30
+ * matrix so the row-count pin (9) catches silent drops.
31
+ */
32
+ export declare const BEHAVIORS: BehaviorDef[];
33
+ /**
34
+ * Row-count pin — NYQUIST-11 runner asserts exactly this number of rows.
35
+ * Changing the behavior set requires updating this constant and adding a
36
+ * line in 18-VALIDATION.md §NYQUIST-11 behavior matrix.
37
+ */
38
+ export declare const BEHAVIOR_ROW_COUNT = 9;
@@ -36,6 +36,13 @@ export interface FlipAndStageInternalState {
36
36
  activeCardId: string | null;
37
37
  activeDimensionId: string | null;
38
38
  dirtyState: Record<string, unknown>;
39
+ /**
40
+ * Phase 17: which dimension section the overlay should render.
41
+ * `null` means no section is open. Independent of `state` — the overlay
42
+ * is only shown after an explicit setOpenSection() call; `cancelConfig()`
43
+ * and `commitConfig()` MUST null this out (per 17-UI-SPEC §Sequencing).
44
+ */
45
+ openSection: string | null;
39
46
  }
40
47
  /**
41
48
  * The full value exposed by useFlipAndStage and FlipAndStageContext.
@@ -48,6 +55,8 @@ export interface FlipAndStageInternalState {
48
55
  * - `commitConfig` — persist edits and return to idle; optional patch merged into dirty
49
56
  * - `cancelConfig` — discard edits and return to idle
50
57
  * - `setDirty` — merge additional edits into dirtyState
58
+ * - `openSection` — (Phase 17) which dimension section the overlay should render
59
+ * - `setOpenSection` — (Phase 17) mutate openSection; cancel/commit auto-null it
51
60
  */
52
61
  export interface FlipAndStageValue {
53
62
  activeCardId: string | null;
@@ -70,6 +79,17 @@ export interface FlipAndStageValue {
70
79
  cancelConfig: () => void;
71
80
  /** Merge additional dirty fields. Successive calls accumulate (not replace). */
72
81
  setDirty: (patch: Record<string, unknown>) => void;
82
+ /**
83
+ * Phase 17: which dimension section the overlay should render.
84
+ * `null` = no section open. Independent of `state` — the overlay is only
85
+ * rendered once a consumer explicitly calls `setOpenSection(id)`.
86
+ */
87
+ openSection: string | null;
88
+ /**
89
+ * Phase 17: mutate openSection. `cancelConfig()` and `commitConfig()` MUST
90
+ * null this out as part of their state reset (per 17-UI-SPEC §Sequencing).
91
+ */
92
+ setOpenSection: (id: string | null) => void;
73
93
  }
74
94
  /**
75
95
  * Options for useFlipAndStage.
@@ -13,7 +13,7 @@ export { useEdgeHoverResize } from './useEdgeHoverResize';
13
13
  export * from './flipAndStage';
14
14
  export * from './types';
15
15
  export type { CardBackProps } from './CardBack';
16
- export type { StackedGroupCardProps, StackedValueEntry } from './StackedGroupCard';
16
+ export type { StackedGroupCardProps, StackedValueEntry, SlotActionStripConfig, SlotToActionStripConfig, } from './StackedGroupCard';
17
17
  export type { SlideOutRevealConfig, SlideOutRevealReturn } from './useSlideOutReveal';
18
18
  export type { ResizeState, ResizeDirection, ResizeMode, ResizeCommit, UseEdgeHoverResizeArgs, UseEdgeHoverResizeReturn, } from './useEdgeHoverResize';
19
19
  export type { EdgeHoverHandleProps } from './EdgeHoverHandle';
@@ -24,6 +24,8 @@ export { DonutChart } from './visualizations/DonutChart';
24
24
  export { ObjectArrow } from './visualizations/ObjectArrow';
25
25
  export { formatValue } from './utils/formatValue';
26
26
  export { formatTrend } from './utils/formatTrend';
27
+ export { computeGutterAnchorX } from './utils/computeGutterAnchorX';
28
+ export type { GutterAnchorInput } from './utils/computeGutterAnchorX';
27
29
  export { allVariantFixtures } from './fixtures/allVariants';
28
30
  export { loadingFixture, errorFixture, emptyFixture, staleFixture, staleSparklineFixture, staleDonutFixture, allStateFixtures, } from './fixtures/states';
29
31
  export { sparklineFixture, sparklineUpFixture } from './fixtures/sparklineCard';
@@ -0,0 +1,48 @@
1
+ /**
2
+ * computeGutterAnchorX — Pure math for per-slot gutter-actions anchor (AP-13).
3
+ *
4
+ * AP-13 invariant (Phase 18): The gutter pill's horizontal `anchorX` MUST be
5
+ * derived via this helper — never hardcoded pixel offsets. Consumers include
6
+ * reptime's `MetricCardGrid` stacked-group branch (via plan 18-02 swap) and
7
+ * gloss-side tests; source-grep guard in plan 18-05 enforces that no other
8
+ * `anchorX = <number>` computation exists outside this module.
9
+ *
10
+ * Stack cards host N equally-distributed metric slots along their width.
11
+ * When the pointer hovers a slot, the ActionStrip pill must slide to that
12
+ * slot's horizontal midpoint (or pill-left offset, if `pillWidthPx` is
13
+ * supplied) so metric-scoped actions visually hang off the hovered metric.
14
+ *
15
+ * Formula (slot-center, default):
16
+ * anchorX = (activeSlotIdx + 0.5) * (cardWidthPx / slotCount)
17
+ *
18
+ * Formula (pill-left-offset, when `pillWidthPx` present and > 0 and finite):
19
+ * anchorX = (activeSlotIdx + 0.5) * (cardWidthPx / slotCount) - pillWidthPx / 2
20
+ * (so the pill's visual CENTER sits at slot-center — per UI-SPEC §Spacing)
21
+ *
22
+ * Returns `undefined` when any input is invalid so the caller can skip the
23
+ * transition entirely and leave the pill at its current position.
24
+ *
25
+ * This utility is zero-dep by design — promoted to @mt-gloss/ui so every
26
+ * consumer shares the same formula without copy-paste. Plan 18-01 (this plan)
27
+ * publishes; plan 18-02 swaps reptime's local gutterAnchor.ts helper to
28
+ * import from here (byte-for-byte behavior parity when `pillWidthPx` absent).
29
+ */
30
+ export interface GutterAnchorInput {
31
+ /** Measured width of the stack card, in CSS pixels. MUST be > 0 and finite. */
32
+ cardWidthPx: number;
33
+ /** Number of slots in the stack card (typically 3 or 5). MUST be > 0 and finite. */
34
+ slotCount: number;
35
+ /**
36
+ * Index of the currently-hovered slot (0-based). `null` returns `undefined`
37
+ * so the caller can unset the anchor and let the pill return to default.
38
+ */
39
+ activeSlotIdx: number | null;
40
+ /**
41
+ * Optional pill width. When present and finite and > 0, the returned value
42
+ * is the pill-LEFT offset so the pill's CENTER sits at slot center. When
43
+ * absent, zero, negative, or non-finite, the returned value is the raw
44
+ * slot-center pixel (matches reptime's original helper byte-for-byte).
45
+ */
46
+ pillWidthPx?: number;
47
+ }
48
+ export declare function computeGutterAnchorX(input: GutterAnchorInput): number | undefined;
@@ -0,0 +1,13 @@
1
+ import { default as React } from 'react';
2
+ import { ReconfigBacksideButtonsProps, ReconfigDimension } from './types';
3
+ /**
4
+ * Verbatim button labels per 17-UI-SPEC §Copywriting Contract.
5
+ * Exported as a const to make future localization extraction a single edit.
6
+ */
7
+ declare const LABELS: Record<ReconfigDimension, string>;
8
+ /**
9
+ * ReconfigBacksideButtons — renders the type-picker button strip on a
10
+ * metric-card backside. See module doc for parent wiring contract.
11
+ */
12
+ export declare const ReconfigBacksideButtons: React.FC<ReconfigBacksideButtonsProps>;
13
+ export { LABELS as RECONFIG_BACKSIDE_LABELS };
@@ -0,0 +1,19 @@
1
+ import { ReconfigDimension } from '../../types';
2
+ export type Nyquist10Archetype = 'standard' | 'stacked-group' | 'order-status-stack';
3
+ export interface Nyquist10MatrixRow {
4
+ /** cardType the matrix row describes. */
5
+ cardType: Nyquist10Archetype;
6
+ /** Dimension under test (the backside button to click). */
7
+ dimension: ReconfigDimension;
8
+ /** All dimensions expected on the backside for this cardType. */
9
+ expectedBacksideDimensions: ReadonlyArray<ReconfigDimension>;
10
+ /** data-section-id that MUST be the sole rendered section post-click. */
11
+ expectedOverlaySectionId: string;
12
+ }
13
+ export declare const NYQUIST_10_MATRIX: ReadonlyArray<Nyquist10MatrixRow>;
14
+ /** Row count pin consumed by the contract runner. */
15
+ export declare const NYQUIST_10_ROW_COUNT: number;
16
+ /** The 3 archetypes enumerated (stable order, useful for grouped describes). */
17
+ export declare const NYQUIST_10_ARCHETYPES: ReadonlyArray<Nyquist10Archetype>;
18
+ /** Matrix lookup — parity check against reptime's CARD_TYPE_DIMENSION_MATRIX. */
19
+ export declare const NYQUIST_10_DIMENSIONS_BY_CARD_TYPE: Readonly<Record<Nyquist10Archetype, ReadonlyArray<ReconfigDimension>>>;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Phase 17, Plan 01 — ReconfigBacksideButtons barrel.
3
+ */
4
+ export { ReconfigBacksideButtons, RECONFIG_BACKSIDE_LABELS } from './ReconfigBacksideButtons';
5
+ export type { ReconfigBacksideButtonsProps, ReconfigDimension } from './types';
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Phase 17, Plan 01: ReconfigBacksideButtons primitive — public type contracts.
3
+ *
4
+ * Renders the card-back type-picker strip (one button per configurable
5
+ * dimension). Buttons only — NO dropdowns, NO popovers. See 17-UI-SPEC
6
+ * §Backside type-picker button labels for the full spec.
7
+ *
8
+ * @module primitives/dashboard/ReconfigBacksideButtons/types
9
+ */
10
+ /**
11
+ * The six configurable dimensions exposable on any metric card backside.
12
+ * Per-card-type matrix lives downstream in reptime (`CARD_TYPE_DIMENSION_MATRIX`).
13
+ */
14
+ export type ReconfigDimension = 'timeframe' | 'threshold' | 'slots' | 'size' | 'color' | 'pinned';
15
+ /**
16
+ * Public props for ReconfigBacksideButtons.
17
+ *
18
+ * Minimal by design — no optional prop beyond these four. Parent wires
19
+ * onDimensionSelect to `flipAndStage.setOpenSection(dim)` + `flipToFace()`.
20
+ */
21
+ export interface ReconfigBacksideButtonsProps {
22
+ /**
23
+ * Dimensions to render (order is preserved; empty array → component
24
+ * returns null — parent should avoid rendering at all for excluded types).
25
+ */
26
+ dimensions: ReadonlyArray<ReconfigDimension>;
27
+ /**
28
+ * Fired on button click. Parent wires:
29
+ * flipAndStage.setOpenSection(dimension)
30
+ * flipAndStage.flipToFace()
31
+ * in that order.
32
+ */
33
+ onDimensionSelect: (dimension: ReconfigDimension) => void;
34
+ /**
35
+ * Highlights the active dimension with aria-current="true" + persisted
36
+ * hover tint. Used when re-entering the backside with a previously-
37
+ * launched overlay still in memory.
38
+ */
39
+ activeDimension?: ReconfigDimension | null;
40
+ /**
41
+ * Screen-reader label substitution — rendered as
42
+ * `aria-label="Configure {ariaCardTypeLabel}: choose a dimension"` on root.
43
+ */
44
+ ariaCardTypeLabel?: string;
45
+ /** Optional consumer-provided class appended to the BEM root class. */
46
+ className?: string;
47
+ }
@@ -7,6 +7,7 @@ export * from './UnifiedBreakdownTable';
7
7
  export * from './ChartControlBar';
8
8
  export * from './UnifiedContextMenu';
9
9
  export * from './TimeFrame';
10
+ export * from './ReconfigBacksideButtons';
10
11
  export * from './MetricCardGrid';
11
12
  export * from './TabbedDataView';
12
13
  export * from './MetricGroupContainer';
@@ -0,0 +1,18 @@
1
+ export type FlipDir = 'up' | 'down';
2
+ export type Variant = 'default' | 'config';
3
+ export interface ParityHarness {
4
+ row: ParityRow;
5
+ }
6
+ export interface ParityRow {
7
+ behaviorId: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
8
+ behaviorLabel: string;
9
+ flip: FlipDir;
10
+ variant: Variant;
11
+ /** Skip reason (row still emits as `test.skip` so it is visible in vitest output). */
12
+ skip?: string;
13
+ /** Concrete assertion executed by `it.each` runner. */
14
+ assert: (harness: ParityHarness) => Promise<void> | void;
15
+ }
16
+ export declare const PARITY_MATRIX: ParityRow[];
17
+ /** Row count = 9 × 2 × 2 = 36. Exposed for assertion convenience in the runner. */
18
+ export declare const MATRIX_ROW_COUNT: number;
@@ -1,5 +1,5 @@
1
1
  export { ActionStrip } from './ActionStrip';
2
- export type { PrimaryAction, OverflowAction, ActionStripProps, ActionStripContext, ActionStripVariant, ActionStripMenuDirection, } from './types';
2
+ export type { PrimaryAction, OverflowAction, ActionStripProps, ActionStripContext, ActionStripMenuDirection, } from './types';
3
3
  export { subscribe, getActive, setActive, resetForTests, } from './overflowMenuRegistry';
4
4
  export { useSlideOutReveal } from './useSlideOutReveal';
5
5
  export type { SlideOutRevealConfig, SlideOutRevealReturn, SlideOutRevealStyle, } from './useSlideOutReveal';
@@ -71,12 +71,16 @@ export interface OverflowAction {
71
71
  visibleWhen?: (ctx: ActionStripContext) => boolean;
72
72
  }
73
73
  /**
74
- * `'default'` is the standard pill + menu. `'config'` is a transitional variant
75
- * that replaces the More trigger with Save/Cancel pills during reconfig flow;
76
- * Phase 17 retires this variant entirely.
74
+ * Menu-flip direction. Omit to let floating-ui's flip() middleware decide.
75
+ *
76
+ * AP-13 the reconfig-surface pass-through variant was retired in Phase 17
77
+ * (plan 17-04): its type alias and Save / Cancel pass-through props were
78
+ * removed along with the render branch. Cancel / close now live in the
79
+ * Phase 17 overlay header, not inside ActionStrip. Only lingering references
80
+ * allowed in source: skip-marker strings in NYQUIST-09 parity-matrix fixtures
81
+ * under `__tests__/fixtures/`. Any resurrection in source is a regression and
82
+ * is blocked by `nyquist-10-ap-guards.test.ts` (AP-13 source-grep).
77
83
  */
78
- export type ActionStripVariant = 'default' | 'config';
79
- /** Menu-flip direction. Omit to let floating-ui's flip() middleware decide. */
80
84
  export type ActionStripMenuDirection = 'up' | 'down';
81
85
  /**
82
86
  * Public ActionStrip prop contract. Stable across Phase 16 plans 16-01..05.
@@ -92,8 +96,6 @@ export interface ActionStripProps {
92
96
  expanded: boolean;
93
97
  /** Called to toggle `expanded`. */
94
98
  onExpandedChange: (open: boolean) => void;
95
- /** Defaults to 'default'. Phase 17 retires 'config'. */
96
- variant?: ActionStripVariant;
97
99
  /** CardBack collapse-to-Undo. Preserved behavior #5. */
98
100
  isFlipped?: boolean;
99
101
  /** Called when the Undo button is clicked while isFlipped. */
@@ -110,8 +112,4 @@ export interface ActionStripProps {
110
112
  graphLabel?: string;
111
113
  /** Consumer-overridable tooltip for the Details pinned button. */
112
114
  detailsLabel?: string;
113
- /** Config variant Save handler. Retired in Phase 17 — pass-through only this phase. */
114
- onConfigSave?: () => void;
115
- /** Config variant Cancel handler. Retired in Phase 17 — pass-through only this phase. */
116
- onConfigCancel?: () => void;
117
115
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mt-gloss/ui",
3
- "version": "0.0.23",
3
+ "version": "0.0.25",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "restricted"