@cellarnode/ui 0.191.0 → 0.192.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.
@@ -12,5 +12,13 @@ export interface CountryFlagProps {
12
12
  */
13
13
  decorative?: boolean;
14
14
  }
15
+ /** Test seam: forget the memoised flag set. */
16
+ export declare function __resetCountryFlagCacheForTests(): void;
17
+ /**
18
+ * CEL-2135 — renders real SVG flags (country-flag-icons, 3x2) rather than regional-indicator
19
+ * emoji, which Windows shows as two letters. The flag set is one lazy chunk (~49 KB gzip, fetched on first
20
+ * render); until it arrives the box is neutral, if it fails or the code is unknown the Globe shows,
21
+ * never letters.
22
+ */
15
23
  export declare function CountryFlag({ code, className, label, decorative }: CountryFlagProps): import("react/jsx-runtime").JSX.Element;
16
24
  //# sourceMappingURL=country-flag.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"country-flag.d.ts","sourceRoot":"","sources":["../../src/components/country-flag.tsx"],"names":[],"mappings":"AAKA,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAyBD,wBAAgB,WAAW,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,gBAAgB,2CAwBnF"}
1
+ {"version":3,"file":"country-flag.d.ts","sourceRoot":"","sources":["../../src/components/country-flag.tsx"],"names":[],"mappings":"AAKA,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAmED,+CAA+C;AAC/C,wBAAgB,+BAA+B,IAAI,IAAI,CAGtD;AAYD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,gBAAgB,2CA6BnF"}
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
+ import * as React from "react";
2
3
  import { Globe } from "lucide-react";
3
4
  import { COUNTRY_NAMES } from "../lib/country-registry.js";
4
5
  import { cn } from "../lib/utils.js";
@@ -13,22 +14,74 @@ function countryName(code) {
13
14
  const canonical = COUNTRY_ALIASES[code] ?? code;
14
15
  return COUNTRY_NAMES[canonical];
15
16
  }
16
- function codeToFlagChar(code) {
17
- const up = code.toUpperCase();
18
- if (up.length !== 2)
19
- return "";
20
- const A = 0x1f1e6;
21
- return (String.fromCodePoint(A + (up.charCodeAt(0) - 65)) +
22
- String.fromCodePoint(A + (up.charCodeAt(1) - 65)));
17
+ /**
18
+ * The 3x2 flag set loads as ONE lazy chunk (the per-flag entry points all re-export the shared
19
+ * module, so splitting per flag would still download the whole set on the first flag). It is
20
+ * fetched only when a flag first renders and memoised so it is fetched once. A rejected load
21
+ * clears the memo so the next mount retries.
22
+ */
23
+ let flagSet;
24
+ let flagSetPromise;
25
+ function loadFlagSet() {
26
+ flagSetPromise ??= import("country-flag-icons/react/3x2").then((m) => (flagSet = m), (error) => {
27
+ flagSetPromise = undefined;
28
+ throw error;
29
+ });
30
+ return flagSetPromise;
31
+ }
32
+ function useFlagStatus(code) {
33
+ const [failed, setFailed] = React.useState(false);
34
+ const [, rerender] = React.useReducer((n) => n + 1, 0);
35
+ const needsLoad = Boolean(code) && flagSet === undefined;
36
+ React.useEffect(() => {
37
+ if (!needsLoad)
38
+ return;
39
+ let live = true;
40
+ loadFlagSet().then(() => {
41
+ if (live)
42
+ rerender();
43
+ }, () => {
44
+ if (live)
45
+ setFailed(true); // chunk failed: show the Globe, never letters
46
+ });
47
+ return () => {
48
+ live = false;
49
+ };
50
+ }, [needsLoad]);
51
+ if (code && flagSet?.[code])
52
+ return "ready";
53
+ return failed || flagSet ? "failed" : "pending";
54
+ }
55
+ /** Test seam: forget the memoised flag set. */
56
+ export function __resetCountryFlagCacheForTests() {
57
+ flagSet = undefined;
58
+ flagSetPromise = undefined;
23
59
  }
60
+ function renderFlag(code, className) {
61
+ const Flag = flagSet?.[code];
62
+ return Flag
63
+ ? React.createElement(Flag, { "aria-hidden": true, focusable: false, className })
64
+ : null;
65
+ }
66
+ /** Same footprint the emoji had: one em tall, inline with the text, 3:2 like the SVG flags. */
67
+ const FLAG_BOX = "inline-block h-[1em] w-[1.5em] shrink-0 align-[-0.125em] rounded-xs";
68
+ /**
69
+ * CEL-2135 — renders real SVG flags (country-flag-icons, 3x2) rather than regional-indicator
70
+ * emoji, which Windows shows as two letters. The flag set is one lazy chunk (~49 KB gzip, fetched on first
71
+ * render); until it arrives the box is neutral, if it fails or the code is unknown the Globe shows,
72
+ * never letters.
73
+ */
24
74
  export function CountryFlag({ code, className, label, decorative }) {
25
75
  const up = code?.toUpperCase() ?? "";
26
76
  const name = countryName(up);
27
- if (!name) {
77
+ const canonical = name ? (COUNTRY_ALIASES[up] ?? up) : undefined;
78
+ const status = useFlagStatus(canonical);
79
+ if (!name || status === "failed") {
28
80
  return (_jsx("span", { ...(decorative
29
81
  ? { "aria-hidden": true }
30
- : { role: "img", "aria-label": label ?? "Unknown country" }), className: cn("inline-flex items-center text-muted-foreground", className), children: _jsx(Globe, { "aria-hidden": true, className: "size-4" }) }));
82
+ : { role: "img", "aria-label": label ?? name ?? "Unknown country" }), className: cn("inline-flex items-center text-muted-foreground", className), children: _jsx(Globe, { "aria-hidden": true, className: "size-4" }) }));
31
83
  }
32
- return (_jsx("span", { ...(decorative ? { "aria-hidden": true } : { role: "img", "aria-label": label ?? name }), className: cn("inline-block", className), children: codeToFlagChar(COUNTRY_ALIASES[up] ?? up) }));
84
+ return (_jsx("span", { ...(decorative ? { "aria-hidden": true } : { role: "img", "aria-label": label ?? name }), className: cn("inline-block", className), children: (canonical &&
85
+ renderFlag(canonical, cn(FLAG_BOX, "ring-1 ring-foreground/10 ring-inset"))) || (_jsx("span", { "aria-hidden": true, className: cn(FLAG_BOX, "bg-muted") })) }));
33
86
  }
34
87
  //# sourceMappingURL=country-flag.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"country-flag.js","sourceRoot":"","sources":["../../src/components/country-flag.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAiBlC;;;;;GAKG;AACH,MAAM,eAAe,GAA2B,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;AAE7D,SAAS,WAAW,CAAC,IAAY;IAC/B,MAAM,SAAS,GAAG,eAAe,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC;IAChD,OAAQ,aAAkD,CAAC,SAAS,CAAC,CAAC;AACxE,CAAC;AAED,SAAS,cAAc,CAAC,IAAY;IAClC,MAAM,EAAE,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IAC9B,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAC/B,MAAM,CAAC,GAAG,OAAO,CAAC;IAClB,OAAO,CACL,MAAM,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;QACjD,MAAM,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAClD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAoB;IAClF,MAAM,EAAE,GAAG,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;IACrC,MAAM,IAAI,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC;IAE7B,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,CACL,kBACM,CAAC,UAAU;gBACb,CAAC,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE;gBACzB,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,IAAI,iBAAiB,EAAE,CAAC,EAC9D,SAAS,EAAE,EAAE,CAAC,gDAAgD,EAAE,SAAS,CAAC,YAE1E,KAAC,KAAK,yBAAa,SAAS,EAAC,QAAQ,GAAG,GACnC,CACR,CAAC;IACJ,CAAC;IACD,OAAO,CACL,kBACM,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,IAAI,IAAI,EAAE,CAAC,EACzF,SAAS,EAAE,EAAE,CAAC,cAAc,EAAE,SAAS,CAAC,YAEvC,cAAc,CAAC,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,GACrC,CACR,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"country-flag.js","sourceRoot":"","sources":["../../src/components/country-flag.tsx"],"names":[],"mappings":"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"}
@@ -3,6 +3,13 @@ import type { OpportunityTab } from "./types.js";
3
3
  export interface OpportunityDetailPanelProps {
4
4
  tabs: OpportunityTab[];
5
5
  defaultTabId?: string;
6
+ /**
7
+ * Controlled active tab (CEL-2129). When set, the panel follows it and
8
+ * reports user switches through `onTabChange`; `defaultTabId` is then
9
+ * ignored. Leave unset for the original uncontrolled behaviour.
10
+ */
11
+ tabId?: string;
12
+ onTabChange?: (tabId: string) => void;
6
13
  className?: string;
7
14
  }
8
15
  declare const OpportunityDetailPanelWithSkeleton: React.FC<OpportunityDetailPanelProps> & {
@@ -1 +1 @@
1
- {"version":3,"file":"opportunity-detail-panel.d.ts","sourceRoot":"","sources":["../../src/opportunities/opportunity-detail-panel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,MAAM,WAAW,2BAA2B;IAC1C,IAAI,EAAE,cAAc,EAAE,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAiLD,QAAA,MAAM,kCAAkC,EACZ,KAAK,CAAC,EAAE,CAAC,2BAA2B,CAAC,GAAG;IAChE,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC;CACpB,CAAC;AAGJ,OAAO,EAAE,kCAAkC,IAAI,sBAAsB,EAAE,CAAC;AACxE,YAAY,EAAE,2BAA2B,IAAI,oCAAoC,EAAE,CAAC"}
1
+ {"version":3,"file":"opportunity-detail-panel.d.ts","sourceRoot":"","sources":["../../src/opportunities/opportunity-detail-panel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,MAAM,WAAW,2BAA2B;IAC1C,IAAI,EAAE,cAAc,EAAE,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAyLD,QAAA,MAAM,kCAAkC,EACZ,KAAK,CAAC,EAAE,CAAC,2BAA2B,CAAC,GAAG;IAChE,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC;CACpB,CAAC;AAGJ,OAAO,EAAE,kCAAkC,IAAI,sBAAsB,EAAE,CAAC;AACxE,YAAY,EAAE,2BAA2B,IAAI,oCAAoC,EAAE,CAAC"}
@@ -38,7 +38,7 @@ function useMeasuredHeight() {
38
38
  }, []);
39
39
  return [ref, height];
40
40
  }
41
- function OpportunityDetailPanel({ tabs, defaultTabId, className }) {
41
+ function OpportunityDetailPanel({ tabs, defaultTabId, tabId, onTabChange, className, }) {
42
42
  const prefersReducedMotion = useReducedMotion();
43
43
  const [measureRef, height] = useMeasuredHeight();
44
44
  const visible = tabs.filter((t) => !t.hidden);
@@ -57,7 +57,7 @@ function OpportunityDetailPanel({ tabs, defaultTabId, className }) {
57
57
  return (_jsx("div", { className: cn("flex min-w-0 flex-col gap-4", className), children: _jsx(motion.div, { className: "min-w-0 overflow-hidden", animate: prefersReducedMotion ? undefined : { height: height ?? "auto" }, style: prefersReducedMotion ? { height: height ?? "auto" } : undefined, transition: { type: "spring", stiffness: 380, damping: 32 }, children: _jsx("div", { ref: measureRef, className: "min-w-0", children: _jsx("div", { className: "grid min-w-0", "data-panel-id": only.id, children: only.content }) }) }) }));
58
58
  }
59
59
  const initial = defaultTabId && visible.some((t) => t.id === defaultTabId) ? defaultTabId : visible[0].id;
60
- return (_jsxs(Tabs.Root, { defaultValue: initial, activationMode: "manual", className: cn("flex min-w-0 flex-col gap-4", className), children: [_jsx(Tabs.List, { "aria-label": "Opportunity detail sections", className: "flex flex-wrap gap-1 border-b border-border", children: visible.map((t) => (_jsx(Tabs.Trigger, { value: t.id, className: cn(
60
+ return (_jsxs(Tabs.Root, { defaultValue: initial, value: tabId, onValueChange: onTabChange, activationMode: "manual", className: cn("flex min-w-0 flex-col gap-4", className), children: [_jsx(Tabs.List, { "aria-label": "Opportunity detail sections", className: "flex flex-wrap gap-1 border-b border-border", children: visible.map((t) => (_jsx(Tabs.Trigger, { value: t.id, className: cn(
61
61
  // min-h-11: 44px WCAG 2.5.5 touch target (py-2 alone is ~36px).
62
62
  "relative inline-flex min-h-11 items-center rounded-t-md px-3 py-2 text-sm font-medium text-muted-foreground ring-inset", "transition-colors duration-[var(--duration-micro)] ease-[var(--ease-emphasized)]", "hover:text-foreground",
63
63
  // Active state: stronger weight + accent fill, plus a brand
@@ -1 +1 @@
1
- {"version":3,"file":"opportunity-detail-panel.js","sourceRoot":"","sources":["../../src/opportunities/opportunity-detail-panel.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"opportunity-detail-panel.js","sourceRoot":"","sources":["../../src/opportunities/opportunity-detail-panel.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ import type { TranslateFn } from "./types.js";
2
+ /**
3
+ * Why the delivery terms are locked. A closed union: the consumer passes the
4
+ * code, the sheet renders the matching copy from `editLabels.locked.reasons`,
5
+ * and an unknown code falls back to the generic copy. A raw code never renders.
6
+ */
7
+ export type OpportunityTermsLockedReason = "live_offers";
8
+ /** Sections of an `OpportunityFactSheet` that can switch to an in-place edit mode (CEL-2129). */
9
+ export type OpportunityEditableSectionId = "product-requirements" | "delivery-terms";
10
+ /**
11
+ * Copy for the in-place edit mode of `OpportunityFactSheet` (CEL-2129). Every
12
+ * string is overridable: pass a partial `editLabels` or build the whole object
13
+ * through `defaultOpportunityFactEditLabels(t)` with an i18next-shaped `t`.
14
+ * English defaults only; none of them contains an em dash.
15
+ */
16
+ export interface OpportunityFactEditLabels {
17
+ /** Visible text of the section Edit button. */
18
+ readonly edit: string;
19
+ /** Accessible name of the Edit button, e.g. "Edit product requirements". */
20
+ readonly editSection: (section: string) => string;
21
+ /** Row action for a missing value, e.g. "Add vintage". */
22
+ readonly add: (fact: string) => string;
23
+ /** Save button text, named after what it saves, e.g. "Save product requirements". */
24
+ readonly saveSection: (section: string) => string;
25
+ /** Note under the footer when other tabs hold unsaved changes of the same draft; `tabs` is a comma separated list of tab names. */
26
+ readonly saveAlsoOn: (tabs: string) => string;
27
+ readonly saving: string;
28
+ readonly cancel: string;
29
+ /** Polite announcement after a successful save (the edit mode has closed by then). */
30
+ readonly saved: string;
31
+ /** Used when `onSave` rejects with an error that carries no message. */
32
+ readonly saveFailed: string;
33
+ readonly unsaved: {
34
+ readonly title: string;
35
+ readonly body: string;
36
+ readonly keepEditing: string;
37
+ readonly discard: string;
38
+ };
39
+ /** Lower-case noun phrase used inside sentences ("Edit delivery terms"). */
40
+ readonly section: Readonly<Record<OpportunityEditableSectionId, string>>;
41
+ /** Heading of the delivery-terms card on the Commercial tab. */
42
+ readonly deliveryTermsHeading: string;
43
+ readonly locked: {
44
+ readonly title: string;
45
+ /** Generic reason: used when no reason, or an unknown one, is passed. */
46
+ readonly reason: string;
47
+ /** Copy per `termsLockedReason` code. */
48
+ readonly reasons: Readonly<Record<OpportunityTermsLockedReason, string>>;
49
+ /** Announced when the lock lands while the section was being edited. */
50
+ readonly arrivedWhileEditing: string;
51
+ readonly sentOffersNote: string;
52
+ readonly reviewOffers: string;
53
+ };
54
+ }
55
+ export declare function defaultOpportunityFactEditLabels(t?: TranslateFn): OpportunityFactEditLabels;
56
+ //# sourceMappingURL=edit-labels.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edit-labels.d.ts","sourceRoot":"","sources":["../../src/opportunity-facts/edit-labels.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3C;;;;GAIG;AACH,MAAM,MAAM,4BAA4B,GAAG,aAAa,CAAC;AAEzD,iGAAiG;AACjG,MAAM,MAAM,4BAA4B,GAAG,sBAAsB,GAAG,gBAAgB,CAAC;AAErF;;;;;GAKG;AACH,MAAM,WAAW,yBAAyB;IACxC,+CAA+C;IAC/C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,4EAA4E;IAC5E,QAAQ,CAAC,WAAW,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;IAClD,0DAA0D;IAC1D,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACvC,qFAAqF;IACrF,QAAQ,CAAC,WAAW,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;IAClD,mIAAmI;IACnI,QAAQ,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC9C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,sFAAsF;IACtF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,wEAAwE;IACxE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE;QAChB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;KAC1B,CAAC;IACF,4EAA4E;IAC5E,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,4BAA4B,EAAE,MAAM,CAAC,CAAC,CAAC;IACzE,gEAAgE;IAChE,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACtC,QAAQ,CAAC,MAAM,EAAE;QACf,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,yEAAyE;QACzE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,yCAAyC;QACzC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,4BAA4B,EAAE,MAAM,CAAC,CAAC,CAAC;QACzE,wEAAwE;QACxE,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;QACrC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;QAChC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;KAC/B,CAAC;CACH;AAED,wBAAgB,gCAAgC,CAC9C,CAAC,GAAE,WAA0C,GAC5C,yBAAyB,CAiD3B"}
@@ -0,0 +1,37 @@
1
+ import { interpolate } from "../portfolio/interpolate.js";
2
+ export function defaultOpportunityFactEditLabels(t = (_key, fallback) => fallback) {
3
+ const i = (key, fallback, vars) => interpolate(t(key, fallback), vars);
4
+ return {
5
+ edit: t("opportunity.edit.edit", "Edit"),
6
+ editSection: (section) => i("opportunity.edit.editSection", "Edit {{section}}", { section }),
7
+ add: (fact) => i("opportunity.edit.add", "Add {{fact}}", { fact }),
8
+ saveSection: (section) => i("opportunity.edit.saveSection", "Save {{section}}", { section }),
9
+ saveAlsoOn: (tabs) => i("opportunity.edit.saveAlsoOn", "Also saves your changes on {{tabs}}", { tabs }),
10
+ saving: t("opportunity.edit.saving", "Saving"),
11
+ cancel: t("opportunity.edit.cancel", "Cancel"),
12
+ saved: t("opportunity.edit.saved", "Changes saved"),
13
+ saveFailed: t("opportunity.edit.saveFailed", "Couldn't save. Your changes are still here. Try again."),
14
+ unsaved: {
15
+ title: t("opportunity.edit.unsaved.title", "Discard unsaved changes?"),
16
+ body: t("opportunity.edit.unsaved.body", "Your edits to this section have not been saved."),
17
+ keepEditing: t("opportunity.edit.unsaved.keepEditing", "Keep editing"),
18
+ discard: t("opportunity.edit.unsaved.discard", "Discard changes"),
19
+ },
20
+ section: {
21
+ "product-requirements": t("opportunity.edit.section.productRequirements", "product requirements"),
22
+ "delivery-terms": t("opportunity.edit.section.deliveryTerms", "delivery terms"),
23
+ },
24
+ deliveryTermsHeading: t("opportunity.edit.deliveryTermsHeading", "Delivery terms"),
25
+ locked: {
26
+ title: t("opportunity.edit.locked.title", "Delivery terms are locked"),
27
+ reason: t("opportunity.edit.locked.reason", "These delivery terms can no longer be changed."),
28
+ reasons: {
29
+ live_offers: t("opportunity.edit.locked.reasons.liveOffers", "Producers have live offers based on these terms, so they can no longer be changed."),
30
+ },
31
+ arrivedWhileEditing: t("opportunity.edit.locked.arrivedWhileEditing", "Delivery terms were locked while you were editing. Your changes were not saved."),
32
+ sentOffersNote: t("opportunity.edit.locked.sentOffersNote", "Sent offers are never changed."),
33
+ reviewOffers: t("opportunity.edit.locked.reviewOffers", "Review offers"),
34
+ },
35
+ };
36
+ }
37
+ //# sourceMappingURL=edit-labels.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edit-labels.js","sourceRoot":"","sources":["../../src/opportunity-facts/edit-labels.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AA2DvD,MAAM,UAAU,gCAAgC,CAC9C,IAAiB,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC,QAAQ;IAE7C,MAAM,CAAC,GAAG,CAAC,GAAW,EAAE,QAAgB,EAAE,IAAqC,EAAE,EAAE,CACjF,WAAW,CAAC,CAAC,CAAC,GAAG,EAAE,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC;IAEtC,OAAO;QACL,IAAI,EAAE,CAAC,CAAC,uBAAuB,EAAE,MAAM,CAAC;QACxC,WAAW,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,8BAA8B,EAAE,kBAAkB,EAAE,EAAE,OAAO,EAAE,CAAC;QAC5F,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,sBAAsB,EAAE,cAAc,EAAE,EAAE,IAAI,EAAE,CAAC;QAClE,WAAW,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,8BAA8B,EAAE,kBAAkB,EAAE,EAAE,OAAO,EAAE,CAAC;QAC5F,UAAU,EAAE,CAAC,IAAI,EAAE,EAAE,CACnB,CAAC,CAAC,6BAA6B,EAAE,qCAAqC,EAAE,EAAE,IAAI,EAAE,CAAC;QACnF,MAAM,EAAE,CAAC,CAAC,yBAAyB,EAAE,QAAQ,CAAC;QAC9C,MAAM,EAAE,CAAC,CAAC,yBAAyB,EAAE,QAAQ,CAAC;QAC9C,KAAK,EAAE,CAAC,CAAC,wBAAwB,EAAE,eAAe,CAAC;QACnD,UAAU,EAAE,CAAC,CACX,6BAA6B,EAC7B,wDAAwD,CACzD;QACD,OAAO,EAAE;YACP,KAAK,EAAE,CAAC,CAAC,gCAAgC,EAAE,0BAA0B,CAAC;YACtE,IAAI,EAAE,CAAC,CAAC,+BAA+B,EAAE,iDAAiD,CAAC;YAC3F,WAAW,EAAE,CAAC,CAAC,sCAAsC,EAAE,cAAc,CAAC;YACtE,OAAO,EAAE,CAAC,CAAC,kCAAkC,EAAE,iBAAiB,CAAC;SAClE;QACD,OAAO,EAAE;YACP,sBAAsB,EAAE,CAAC,CACvB,8CAA8C,EAC9C,sBAAsB,CACvB;YACD,gBAAgB,EAAE,CAAC,CAAC,wCAAwC,EAAE,gBAAgB,CAAC;SAChF;QACD,oBAAoB,EAAE,CAAC,CAAC,uCAAuC,EAAE,gBAAgB,CAAC;QAClF,MAAM,EAAE;YACN,KAAK,EAAE,CAAC,CAAC,+BAA+B,EAAE,2BAA2B,CAAC;YACtE,MAAM,EAAE,CAAC,CAAC,gCAAgC,EAAE,gDAAgD,CAAC;YAC7F,OAAO,EAAE;gBACP,WAAW,EAAE,CAAC,CACZ,4CAA4C,EAC5C,oFAAoF,CACrF;aACF;YACD,mBAAmB,EAAE,CAAC,CACpB,6CAA6C,EAC7C,iFAAiF,CAClF;YACD,cAAc,EAAE,CAAC,CAAC,wCAAwC,EAAE,gCAAgC,CAAC;YAC7F,YAAY,EAAE,CAAC,CAAC,sCAAsC,EAAE,eAAe,CAAC;SACzE;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,119 @@
1
+ import * as React from "react";
2
+ import type { OpportunityEditableSectionId, OpportunityFactEditLabels, OpportunityTermsLockedReason } from "./edit-labels.js";
3
+ import type { FactKey } from "./types.js";
4
+ /** What a field control needs to wire itself to its row (label, server error). */
5
+ export interface FactFieldContext {
6
+ /** id of the visible row label (`<dt>`); use as `aria-labelledby`. */
7
+ readonly labelId: string;
8
+ /** id of the inline server error for this field, set only while one is shown. */
9
+ readonly errorId: string | undefined;
10
+ /** True while a server error is shown for this field; map to `aria-invalid`. */
11
+ readonly invalid: boolean;
12
+ }
13
+ export type FactFieldNode = React.ReactNode | ((ctx: FactFieldContext) => React.ReactNode);
14
+ export interface OpportunityFactSectionEditing {
15
+ /**
16
+ * Controls keyed by the fact they edit. A control renders in the row of its
17
+ * fact (the label stays, the read-only value is replaced) wherever that fact
18
+ * lives: product facts on Overview, compliance facts on the Compliance tab,
19
+ * and so on. The tab that hosts the fact also shows Save and Cancel, so the
20
+ * decision stays next to the facts. A key with no fact row anywhere renders
21
+ * nothing: fold such a value into the control of the fact that carries it. A key listed here also gets an "Add {fact}" action wherever its
22
+ * fact is shown as missing.
23
+ */
24
+ readonly fields?: Partial<Record<FactKey, FactFieldNode>>;
25
+ /** A free block rendered below the facts while editing (e.g. a picker). */
26
+ readonly editor?: React.ReactNode;
27
+ /** Server errors per field, rendered under the field's control. */
28
+ readonly fieldErrors?: Partial<Record<FactKey, string>>;
29
+ /**
30
+ * Persist the draft. Resolve to close the edit mode; REJECT to keep it open
31
+ * (the error's message is shown inline unless `error` is set). The consumer
32
+ * owns the draft state and the mutation.
33
+ */
34
+ readonly onSave: () => void | Promise<void>;
35
+ /** Discard the draft (Cancel, Escape, or Discard in the unsaved-changes guard). */
36
+ readonly onCancel?: () => void;
37
+ /** Whether the draft differs from the saved value. Drives the guard and the Save button. */
38
+ readonly isDirty?: boolean;
39
+ /** `false` blocks Save (client-side validation). Default `true`. */
40
+ readonly canSave?: boolean;
41
+ /** A section-level error (e.g. mapped from a server response). Overrides a rejection's message. */
42
+ readonly error?: string | null;
43
+ }
44
+ /**
45
+ * The state machine of one editable section, shared by every tab that hosts
46
+ * its controls (the product requirements span Overview and Compliance, so two
47
+ * footers drive one session). Lives in `OpportunityFactSheet`.
48
+ */
49
+ export interface EditSession {
50
+ readonly config: OpportunityFactSectionEditing | undefined;
51
+ readonly saving: boolean;
52
+ readonly error: string | null;
53
+ readonly guardOpen: boolean;
54
+ readonly justSaved: boolean;
55
+ /** Tabs where the user changed a control of this draft since edit mode opened. */
56
+ readonly touchedTabs: readonly string[];
57
+ touch(tabId: string): void;
58
+ readonly dirty: boolean;
59
+ readonly saveBlocked: boolean;
60
+ /** Whether any shell has moved focus on entering edit mode yet. */
61
+ hasFocused(): boolean;
62
+ markFocused(): void;
63
+ readonly failTick: number;
64
+ save(): Promise<void>;
65
+ requestCancel(): void;
66
+ keepEditing(): void;
67
+ discard(): void;
68
+ /** Asks before leaving (e.g. to another tab); runs `proceed` after a discard. */
69
+ requestLeave(proceed: () => void): void;
70
+ }
71
+ export declare function useEditSession({ config, labels, isEditing, onClose, }: {
72
+ config: OpportunityFactSectionEditing | undefined;
73
+ labels: OpportunityFactEditLabels;
74
+ isEditing: boolean;
75
+ onClose: () => void;
76
+ }): EditSession;
77
+ export interface EditableSectionProps {
78
+ readonly id: OpportunityEditableSectionId;
79
+ readonly session: EditSession;
80
+ readonly heading: string;
81
+ readonly headingAs: `h${2 | 3 | 4 | 5 | 6}`;
82
+ readonly labels: OpportunityFactEditLabels;
83
+ readonly isEditing: boolean;
84
+ /** The shell's tab is the visible one; focus work and the guard wait for this. */
85
+ readonly active: boolean;
86
+ /** The tab this shell sits on (its id), to attribute edits to a tab. */
87
+ readonly tabId: string;
88
+ /** Tab names by id, for the "also saves" note. */
89
+ readonly tabLabels: Readonly<Record<string, string>>;
90
+ /**
91
+ * A continuation of a section whose Edit button lives elsewhere (the
92
+ * requirements' compliance facts): no Edit button, no focus return, same
93
+ * Save and Cancel.
94
+ */
95
+ readonly secondary?: boolean;
96
+ /** False hides the Edit button (no editor, or the section is locked). */
97
+ readonly canEdit?: boolean;
98
+ /** True while a different section is being edited: this Edit button is disabled. */
99
+ readonly editBlocked?: boolean;
100
+ readonly focusKey?: FactKey;
101
+ readonly onEdit?: () => void;
102
+ /** Rendered between the heading and the body when the section is locked. */
103
+ readonly lockedPanel?: React.ReactNode;
104
+ /** Moves focus to the locked panel when edit mode ends with no Edit button (the lock arrived); returns whether it did. */
105
+ readonly focusLockedPanel?: () => boolean;
106
+ /** The read-only facts (and, in edit mode, the in-row controls). */
107
+ readonly children: React.ReactNode;
108
+ }
109
+ export declare function EditableSection({ id, session, heading, headingAs, labels, isEditing, active, tabId, tabLabels, secondary, canEdit, editBlocked, focusKey, onEdit, lockedPanel, focusLockedPanel, children, }: EditableSectionProps): import("react/jsx-runtime").JSX.Element;
110
+ export interface LockedTermsPanelProps {
111
+ readonly labels: OpportunityFactEditLabels;
112
+ readonly reason?: OpportunityTermsLockedReason;
113
+ readonly onReviewOffers?: () => void;
114
+ /** Called with the panel element on mount and null on unmount. */
115
+ readonly onMount?: (node: HTMLDivElement | null) => void;
116
+ }
117
+ /** CEL-2167 locked state: explains the lock, never offers a workaround. */
118
+ export declare function LockedTermsPanel({ labels, reason, onReviewOffers, onMount, }: LockedTermsPanelProps): import("react/jsx-runtime").JSX.Element;
119
+ //# sourceMappingURL=editable-section.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"editable-section.d.ts","sourceRoot":"","sources":["../../src/opportunity-facts/editable-section.tsx"],"names":[],"mappings":"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"}