@oatfi/ui 0.5.0 → 0.7.0

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.
package/dist/index.cjs.js CHANGED
@@ -2102,6 +2102,17 @@ const MethodCard = styled.div`
2102
2102
  transition:
2103
2103
  border-color 0.15s ease,
2104
2104
  background 0.15s ease;
2105
+
2106
+ /**
2107
+ * The unsaved-edit bar. It thickens the left border rather than adding one, so
2108
+ * the padding gives back the 2px it takes and the card's contents do not shift
2109
+ * when it appears mid-keystroke. Declared last so it wins over the shorthand
2110
+ * above, including on a $default card that already has an accent border.
2111
+ */
2112
+ ${({ theme, $edited }) => $edited && styled.css`
2113
+ border-left: 3px solid ${theme.colors.accent};
2114
+ padding-left: 14px;
2115
+ `}
2105
2116
  `;
2106
2117
  const MethodBody = styled.div`
2107
2118
  flex: 1;
@@ -2166,6 +2177,10 @@ const FooterActions = styled.div`
2166
2177
  button {
2167
2178
  margin-top: 0;
2168
2179
  }
2180
+
2181
+ > :only-child {
2182
+ margin-left: auto;
2183
+ }
2169
2184
  `;
2170
2185
  const FooterRight = styled.div`
2171
2186
  display: flex;
@@ -2216,6 +2231,7 @@ function ManualMethodCard({
2216
2231
  index,
2217
2232
  value,
2218
2233
  isDefault = false,
2234
+ status,
2219
2235
  trashDisabled = false,
2220
2236
  disabled = false,
2221
2237
  accountError,
@@ -2227,7 +2243,7 @@ function ManualMethodCard({
2227
2243
  name = "default-method"
2228
2244
  }) {
2229
2245
  const radioId = `default-${value.id}`;
2230
- return /* @__PURE__ */ jsxRuntime.jsxs(MethodCard, { $default: isDefault, children: [
2246
+ return /* @__PURE__ */ jsxRuntime.jsxs(MethodCard, { $default: isDefault, $edited: status === "edited", children: [
2231
2247
  /* @__PURE__ */ jsxRuntime.jsx(
2232
2248
  RadioInput,
2233
2249
  {
@@ -2246,7 +2262,8 @@ function ManualMethodCard({
2246
2262
  "Account ",
2247
2263
  index + 1
2248
2264
  ] }),
2249
- isDefault && /* @__PURE__ */ jsxRuntime.jsx(Badge, { $variant: "filled", children: "Default" })
2265
+ isDefault && /* @__PURE__ */ jsxRuntime.jsx(Badge, { $variant: "filled", children: "Default" }),
2266
+ status === "edited" && /* @__PURE__ */ jsxRuntime.jsx(Badge, { $variant: "info", children: "Unsaved" })
2250
2267
  ] }),
2251
2268
  /* @__PURE__ */ jsxRuntime.jsx(
2252
2269
  IconButton,
@@ -2350,6 +2367,167 @@ function AchVerificationConsent({
2350
2367
  ] });
2351
2368
  }
2352
2369
 
2370
+ const AMBER = "#F59E0B";
2371
+ const CYAN = "#22D3EE";
2372
+ const GREY = "#9CA3AF";
2373
+ const GREEN = "#22C55E";
2374
+ const WHITE = "#FFFFFF";
2375
+ const INK = "#141312";
2376
+ const RED = "#DC2626";
2377
+ const ENVIRONMENT_MISMATCH_BORDER = RED;
2378
+ const ENVIRONMENT_TAGS = Object.freeze({
2379
+ production: Object.freeze({ label: "PROD", name: "Production", fill: WHITE, ink: INK }),
2380
+ staging: Object.freeze({ label: "STG", name: "Staging", fill: AMBER, ink: INK }),
2381
+ qa: Object.freeze({ label: "QA", name: "QA", fill: CYAN, ink: INK }),
2382
+ development: Object.freeze({ label: "DEV", name: "Development", fill: GREY, ink: INK }),
2383
+ local: Object.freeze({ label: "LOCAL", name: "Local", fill: GREEN, ink: INK })
2384
+ });
2385
+ const UNKNOWN_ENVIRONMENT_TAG = Object.freeze({
2386
+ label: "?",
2387
+ name: "Unknown",
2388
+ fill: WHITE,
2389
+ ink: INK
2390
+ });
2391
+ const INVALID_API_TAG = Object.freeze({
2392
+ label: "?",
2393
+ name: "Unknown",
2394
+ fill: RED,
2395
+ ink: WHITE
2396
+ });
2397
+ const ALIASES = /* @__PURE__ */ new Map([
2398
+ ["production", "production"],
2399
+ ["prod", "production"],
2400
+ ["staging", "staging"],
2401
+ ["stg", "staging"],
2402
+ ["qa", "qa"],
2403
+ ["development", "development"],
2404
+ ["dev", "development"],
2405
+ ["local", "local"]
2406
+ ]);
2407
+ const normalizeEnvironment = (value) => {
2408
+ const key = value?.trim().toLowerCase();
2409
+ return key && ALIASES.get(key) || null;
2410
+ };
2411
+ const resolveComponentEnvTag = ({
2412
+ bundleEnv,
2413
+ apiEnv
2414
+ }) => {
2415
+ const apiValue = apiEnv?.trim();
2416
+ if (!apiValue) return null;
2417
+ const api = normalizeEnvironment(apiValue);
2418
+ if (!api) return { kind: "invalid-api", apiEnv: apiValue };
2419
+ const bundleValue = bundleEnv?.trim();
2420
+ const bundle = normalizeEnvironment(bundleValue);
2421
+ const apiTag = ENVIRONMENT_TAGS[api];
2422
+ if (bundleValue && !bundle) {
2423
+ return { kind: "split", bundleEnv: null, bundle: UNKNOWN_ENVIRONMENT_TAG, api: apiTag };
2424
+ }
2425
+ if (bundle === "local" && api !== "local" && api !== "production") {
2426
+ return { kind: "local", api: apiTag };
2427
+ }
2428
+ if (bundle && bundle !== api) {
2429
+ return { kind: "split", bundleEnv: bundle, bundle: ENVIRONMENT_TAGS[bundle], api: apiTag };
2430
+ }
2431
+ if (api === "production") return null;
2432
+ return { kind: "single", tag: apiTag };
2433
+ };
2434
+ const environmentDebug = (value) => {
2435
+ const env = normalizeEnvironment(value);
2436
+ if (env) return env;
2437
+ const raw = value?.trim();
2438
+ return raw ? `unrecognised:${raw}` : "unknown";
2439
+ };
2440
+ const describeComponentEnv = ({ bundleEnv, apiEnv, ref, sha }) => [
2441
+ `bundle=${environmentDebug(bundleEnv)}`,
2442
+ `api=${environmentDebug(apiEnv)}`,
2443
+ `ref=${ref || "unknown"}`,
2444
+ `sha=${sha || "unknown"}`
2445
+ ].join(" ");
2446
+ const environmentTitle = (value) => {
2447
+ const env = normalizeEnvironment(value);
2448
+ if (env) return ENVIRONMENT_TAGS[env].name;
2449
+ const raw = value?.trim();
2450
+ return raw ? `Unrecognised "${raw}"` : "Unknown";
2451
+ };
2452
+ const describeComponentEnvTitle = ({
2453
+ bundleEnv,
2454
+ apiEnv,
2455
+ ref,
2456
+ sha
2457
+ }) => {
2458
+ const build = [ref, sha].filter(Boolean).join(", ");
2459
+ return `Bundle: ${environmentTitle(bundleEnv)}${build ? ` (${build})` : ""} \xB7 API: ${environmentTitle(apiEnv)}`;
2460
+ };
2461
+
2462
+ const FONT_SIZE = { small: 9, medium: 11 };
2463
+ const PADDING_X = { small: 6, medium: 8 };
2464
+ const FONT_FAMILY = 'Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif';
2465
+ const BORDER_WIDTH = 1.5;
2466
+ const base = (size) => ({
2467
+ display: "inline-flex",
2468
+ alignItems: "stretch",
2469
+ boxSizing: "border-box",
2470
+ fontFamily: FONT_FAMILY,
2471
+ fontSize: FONT_SIZE[size],
2472
+ fontWeight: 800,
2473
+ letterSpacing: "0.1em",
2474
+ lineHeight: 1.4,
2475
+ whiteSpace: "nowrap",
2476
+ borderRadius: 0
2477
+ });
2478
+ const half = (tag, label, size) => /* @__PURE__ */ jsxRuntime.jsx("span", { style: { padding: `2px ${PADDING_X[size]}px`, background: tag.fill, color: tag.ink }, children: label });
2479
+ const EnvironmentTag = ({
2480
+ bundleEnv,
2481
+ apiEnv,
2482
+ buildRef,
2483
+ buildSha,
2484
+ size = "small",
2485
+ testId = "oatfi-env-tag"
2486
+ }) => {
2487
+ const result = resolveComponentEnvTag({ bundleEnv, apiEnv });
2488
+ if (!result) return null;
2489
+ const title = describeComponentEnvTitle({ bundleEnv, apiEnv, ref: buildRef, sha: buildSha });
2490
+ const chip = (border, children) => /* @__PURE__ */ jsxRuntime.jsx(
2491
+ "span",
2492
+ {
2493
+ role: "note",
2494
+ "aria-label": `Environment: ${title}`,
2495
+ "data-testid": testId,
2496
+ "data-env-kind": result.kind,
2497
+ title,
2498
+ style: { ...base(size), border: `${BORDER_WIDTH}px solid ${border}` },
2499
+ children
2500
+ }
2501
+ );
2502
+ switch (result.kind) {
2503
+ case "single":
2504
+ return chip(result.tag.fill, half(result.tag, result.tag.label, size));
2505
+ case "local":
2506
+ return chip(
2507
+ ENVIRONMENT_TAGS.local.fill,
2508
+ /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2509
+ half(ENVIRONMENT_TAGS.local, ENVIRONMENT_TAGS.local.label, size),
2510
+ half(result.api, `API ${result.api.label}`, size)
2511
+ ] })
2512
+ );
2513
+ case "invalid-api":
2514
+ return chip(
2515
+ INVALID_API_TAG.fill,
2516
+ half(INVALID_API_TAG, `API ${INVALID_API_TAG.label}`, size)
2517
+ );
2518
+ case "split": {
2519
+ const bundleLabel = result.bundleEnv === "local" ? "LOCAL" : `BUNDLE ${result.bundle.label}`;
2520
+ return chip(
2521
+ ENVIRONMENT_MISMATCH_BORDER,
2522
+ /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2523
+ half(result.bundle, bundleLabel, size),
2524
+ half(result.api, `API ${result.api.label}`, size)
2525
+ ] })
2526
+ );
2527
+ }
2528
+ }
2529
+ };
2530
+
2353
2531
  const PreviewCard = styled.div`
2354
2532
  display: flex;
2355
2533
  gap: 2rem;
@@ -2448,6 +2626,7 @@ exports.DropdownContainer = DropdownContainer;
2448
2626
  exports.DropdownItem = DropdownItem;
2449
2627
  exports.DropdownList = DropdownList;
2450
2628
  exports.EmailInput = EmailInput;
2629
+ exports.EnvironmentTag = EnvironmentTag;
2451
2630
  exports.FieldsGrid = FieldsGrid;
2452
2631
  exports.FileInput = FileInput;
2453
2632
  exports.FlexColumnWrapper = FlexColumnWrapper;
@@ -2496,6 +2675,9 @@ exports.UnderwritingStatus = UnderwritingStatus;
2496
2675
  exports.UploadZone = UploadZone;
2497
2676
  exports.buildMuiTheme = buildMuiTheme;
2498
2677
  exports.defaultTheme = defaultTheme;
2678
+ exports.describeComponentEnv = describeComponentEnv;
2679
+ exports.describeComponentEnvTitle = describeComponentEnvTitle;
2499
2680
  exports.mergeBranding = mergeBranding;
2681
+ exports.resolveComponentEnvTag = resolveComponentEnvTag;
2500
2682
  exports.useTheme = useTheme;
2501
2683
  //# sourceMappingURL=index.cjs.js.map