@doneisbetter/gds-core 2.6.7 → 3.0.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.
@@ -7,7 +7,7 @@ import {
7
7
  StateBlock,
8
8
  getSemanticActionLabel,
9
9
  resolveSemanticActionConfig
10
- } from "./chunk-LH2KMMXT.mjs";
10
+ } from "./chunk-P7ICTEEB.mjs";
11
11
 
12
12
  // src/SemanticButton.tsx
13
13
  import { useEffect, useState } from "react";
@@ -189,6 +189,23 @@ var themePresetCatalog = {
189
189
  avoidFor: "Avoid for local style experiments or temporary visual fixes without compliance approval."
190
190
  }
191
191
  };
192
+ var colorSchemeProof = [
193
+ {
194
+ id: "light",
195
+ label: "Light",
196
+ description: "Validates readable default surfaces, controls, badges, and focus states against light backgrounds."
197
+ },
198
+ {
199
+ id: "dark",
200
+ label: "Dark",
201
+ description: "Validates contrast for public, operational, and feedback surfaces when dark mode is active."
202
+ },
203
+ {
204
+ id: "auto",
205
+ label: "Auto",
206
+ description: "Documents the adopter path for OS-controlled schemes while keeping the provider contract unchanged."
207
+ }
208
+ ];
192
209
  function ThemePreviewSurface({
193
210
  preset,
194
211
  colorScheme,
@@ -210,6 +227,10 @@ function ThemePreviewSurface({
210
227
  " ",
211
228
  colorScheme
212
229
  ] }),
230
+ /* @__PURE__ */ jsxs2(Text2, { size: "sm", children: [
231
+ /* @__PURE__ */ jsx4("strong", { children: "Accessibility proof:" }),
232
+ " status uses text, badge label, and placement, not color alone."
233
+ ] }),
213
234
  forcedScheme ? /* @__PURE__ */ jsx4(Text2, { size: "sm", c: "dimmed", children: "This lane always previews in dark mode so the runtime stays inside its sanctioned contrast contract." }) : null
214
235
  ] }),
215
236
  /* @__PURE__ */ jsx4(ThemeToggle, {})
@@ -239,7 +260,8 @@ function ThemePreviewSurface({
239
260
  description: "This preview uses the real shipped design-system runtime rather than a docs-only styling lane.",
240
261
  metadata: [
241
262
  { id: "runtime", label: "Runtime lane", value: preset.themeKey },
242
- { id: "scheme", label: "Color scheme", value: colorScheme }
263
+ { id: "scheme", label: "Color scheme", value: colorScheme },
264
+ { id: "focus", label: "A11y proof", value: "Keyboard + readable states" }
243
265
  ],
244
266
  primaryAction: /* @__PURE__ */ jsx4(Button2, { size: "sm", children: "Inspect route" })
245
267
  }
@@ -356,7 +378,7 @@ function ReferenceThemeExplorer() {
356
378
  ),
357
379
  /* @__PURE__ */ jsx4(Text2, { size: "sm", c: "dimmed", children: "The generator composes shipped helpers instead of creating a second theme authority inside the website." })
358
380
  ] }) }),
359
- /* @__PURE__ */ jsx4(Paper, { withBorder: true, radius: "xl", p: "lg", children: /* @__PURE__ */ jsxs2(Stack, { gap: "md", children: [
381
+ /* @__PURE__ */ jsx4(Paper, { withBorder: true, radius: "xl", p: "lg", children: /* @__PURE__ */ jsxs2(Stack, { gap: "md", role: "status", "aria-live": "polite", children: [
360
382
  /* @__PURE__ */ jsx4(Title, { order: 4, children: "Current selection summary" }),
361
383
  /* @__PURE__ */ jsxs2(Stack, { gap: 6, children: [
362
384
  /* @__PURE__ */ jsx4(Text2, { fw: 700, children: selectionSummary.label }),
@@ -423,6 +445,18 @@ function ReferenceThemeExplorer() {
423
445
  ] }) }, lane.themeKey)) })
424
446
  }
425
447
  ),
448
+ /* @__PURE__ */ jsx4(
449
+ ReferenceSection,
450
+ {
451
+ title: "Light, dark, and auto proof",
452
+ description: "Every official lane must remain usable across explicit light, explicit dark, and OS-controlled auto modes. The dark-public lane is intentionally forced to dark in preview to preserve its contrast contract.",
453
+ children: /* @__PURE__ */ jsx4(SimpleGrid, { cols: { base: 1, md: 3 }, spacing: "md", children: colorSchemeProof.map((item) => /* @__PURE__ */ jsx4(Paper, { withBorder: true, radius: "lg", p: "md", children: /* @__PURE__ */ jsxs2(Stack, { gap: 6, children: [
454
+ /* @__PURE__ */ jsx4(Badge, { variant: "light", color: item.id === "dark" ? "violet" : item.id === "auto" ? "teal" : "blue", w: "fit-content", children: item.label }),
455
+ /* @__PURE__ */ jsx4(Text2, { size: "sm", children: item.description }),
456
+ /* @__PURE__ */ jsx4(Text2, { size: "xs", c: "dimmed", children: "Required proof: semantic text, visible focus, and contrast-safe state treatment." })
457
+ ] }) }, item.id)) })
458
+ }
459
+ ),
426
460
  /* @__PURE__ */ jsx4(
427
461
  ReferenceSection,
428
462
  {
@@ -460,18 +494,34 @@ function ReferenceThemeExplorer() {
460
494
  /* @__PURE__ */ jsx4(
461
495
  ReferenceSection,
462
496
  {
463
- title: "Creator-Authored Experience Boundary",
464
- description: "Creator-authored expression is allowed only through the sanctioned theme helpers and narrow exception process.",
497
+ title: "Unsupported lane boundary",
498
+ description: "Unsupported local theme lanes are blocked by policy and compliance because they create parallel design-system authority.",
465
499
  tone: "supporting",
466
- children: /* @__PURE__ */ jsx4(
467
- StateBlock,
468
- {
469
- variant: "info",
470
- title: "Shipped first, custom second",
471
- description: "The official site uses shipped presets and the public brand generator first. Product-authored overrides must stay reviewable, testable, and scoped.",
472
- compact: true
473
- }
474
- )
500
+ children: /* @__PURE__ */ jsxs2(Stack, { gap: "md", children: [
501
+ /* @__PURE__ */ jsx4(
502
+ StateBlock,
503
+ {
504
+ variant: "permission",
505
+ title: "Do not create local branding-layer helpers",
506
+ description: "If a consumer needs brand expression, use createPublicBrandTheme(...). If a lane is missing, request it for GDS instead of building extendGdsTheme(...), createTheme(...), or mergeMantineTheme(...) ownership locally.",
507
+ compact: true
508
+ }
509
+ ),
510
+ /* @__PURE__ */ jsxs2(SimpleGrid, { cols: { base: 1, md: 2 }, spacing: "md", children: [
511
+ /* @__PURE__ */ jsx4(Paper, { withBorder: true, radius: "lg", p: "md", children: /* @__PURE__ */ jsxs2(Stack, { gap: 6, children: [
512
+ /* @__PURE__ */ jsx4(Text2, { fw: 700, size: "sm", children: "Approved remediation" }),
513
+ /* @__PURE__ */ jsxs2(Code, { block: true, children: [
514
+ "createPublicBrandTheme(",
515
+ `{ flatSurfaces: true, overrides: { primaryColor: 'blue' } }`,
516
+ ")"
517
+ ] })
518
+ ] }) }),
519
+ /* @__PURE__ */ jsx4(Paper, { withBorder: true, radius: "lg", p: "md", children: /* @__PURE__ */ jsxs2(Stack, { gap: 6, children: [
520
+ /* @__PURE__ */ jsx4(Text2, { fw: 700, size: "sm", children: "Prohibited ownership" }),
521
+ /* @__PURE__ */ jsx4(Code, { block: true, children: "extendGdsTheme(...) / createTheme(...) / mergeMantineTheme(...)" })
522
+ ] }) })
523
+ ] })
524
+ ] })
475
525
  }
476
526
  )
477
527
  ] });
@@ -823,22 +873,34 @@ function ShareButtonGroup({
823
873
 
824
874
  // src/UploadDropzone.tsx
825
875
  import { useRef, useState as useState6 } from "react";
826
- import { Box as Box4, Button as Button4, Group as Group7, Stack as Stack6, Text as Text8 } from "@mantine/core";
876
+ import { Badge as Badge2, Box as Box4, Button as Button4, Group as Group7, Stack as Stack6, Text as Text8 } from "@mantine/core";
827
877
  import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
828
878
  function UploadDropzone({
829
879
  title,
830
880
  description,
831
881
  onFilesSelected,
832
882
  accept,
883
+ acceptedTypesLabel,
884
+ maxSizeLabel,
833
885
  multiple = true,
834
886
  actionLabel = "Choose files",
835
- mode = "panel"
887
+ mode = "panel",
888
+ state = "idle",
889
+ selectedFiles = [],
890
+ error,
891
+ policyText,
892
+ retryAction,
893
+ removeAction,
894
+ readonly = false
836
895
  }) {
837
896
  const inputRef = useRef(null);
838
897
  const [dragging, setDragging] = useState6(false);
839
898
  const UploadIcon = GdsIcons.Upload;
899
+ const effectiveState = readonly ? "readonly" : dragging ? "drag-active" : state;
900
+ const isDisabled = readonly || effectiveState === "upload-pending";
901
+ const isError = ["upload-failed", "unsupported-type", "too-large"].includes(effectiveState);
840
902
  const forwardFiles = (files) => {
841
- if (!files?.length || !onFilesSelected) {
903
+ if (isDisabled || !files?.length || !onFilesSelected) {
842
904
  return;
843
905
  }
844
906
  onFilesSelected(Array.from(files));
@@ -848,6 +910,9 @@ function UploadDropzone({
848
910
  {
849
911
  onDragOver: (event) => {
850
912
  event.preventDefault();
913
+ if (isDisabled) {
914
+ return;
915
+ }
851
916
  setDragging(true);
852
917
  },
853
918
  onDragLeave: () => setDragging(false),
@@ -858,10 +923,11 @@ function UploadDropzone({
858
923
  },
859
924
  p: mode === "inline" ? "md" : "xl",
860
925
  style: {
861
- border: `1px dashed var(${dragging ? "--mantine-color-violet-6" : "--mantine-color-default-border"})`,
926
+ border: `1px dashed var(${effectiveState === "drag-active" ? "--mantine-color-violet-6" : isError ? "--mantine-color-red-6" : "--mantine-color-default-border"})`,
862
927
  borderRadius: "var(--mantine-radius-lg)",
863
- background: dragging ? "var(--mantine-color-violet-light)" : "transparent"
928
+ background: effectiveState === "drag-active" ? "var(--mantine-color-violet-light)" : "transparent"
864
929
  },
930
+ "aria-invalid": isError || void 0,
865
931
  children: [
866
932
  /* @__PURE__ */ jsx11(
867
933
  "input",
@@ -871,14 +937,30 @@ function UploadDropzone({
871
937
  hidden: true,
872
938
  accept,
873
939
  multiple,
940
+ disabled: isDisabled,
874
941
  onChange: (event) => forwardFiles(event.currentTarget.files)
875
942
  }
876
943
  ),
877
944
  /* @__PURE__ */ jsxs8(Stack6, { align: mode === "inline" ? "flex-start" : "center", ta: mode === "inline" ? "left" : "center", gap: "sm", children: [
878
945
  /* @__PURE__ */ jsx11(UploadIcon, { size: "1.5rem" }),
946
+ /* @__PURE__ */ jsx11(Badge2, { variant: "light", color: isError ? "red" : effectiveState === "selected" ? "blue" : effectiveState === "upload-pending" ? "violet" : "gray", children: effectiveState.replace("-", " ") }),
879
947
  /* @__PURE__ */ jsx11(Text8, { fw: 600, children: title }),
880
948
  description ? /* @__PURE__ */ jsx11(Text8, { size: "sm", c: "dimmed", children: description }) : null,
881
- /* @__PURE__ */ jsx11(Group7, { children: /* @__PURE__ */ jsx11(Button4, { variant: "light", onClick: () => inputRef.current?.click(), children: actionLabel }) })
949
+ acceptedTypesLabel || maxSizeLabel ? /* @__PURE__ */ jsxs8(Group7, { gap: "xs", justify: mode === "inline" ? "flex-start" : "center", children: [
950
+ acceptedTypesLabel ? /* @__PURE__ */ jsx11(Badge2, { variant: "outline", color: "gray", children: acceptedTypesLabel }) : null,
951
+ maxSizeLabel ? /* @__PURE__ */ jsx11(Badge2, { variant: "outline", color: "gray", children: maxSizeLabel }) : null
952
+ ] }) : null,
953
+ selectedFiles.length ? /* @__PURE__ */ jsxs8(Text8, { size: "sm", children: [
954
+ "Selected: ",
955
+ selectedFiles.join(", ")
956
+ ] }) : null,
957
+ policyText ? /* @__PURE__ */ jsx11(Text8, { size: "sm", c: isError ? "red.7" : "dimmed", children: policyText }) : null,
958
+ error ? /* @__PURE__ */ jsx11(Text8, { size: "sm", c: "red.7", role: "alert", children: error }) : null,
959
+ /* @__PURE__ */ jsxs8(Group7, { children: [
960
+ /* @__PURE__ */ jsx11(Button4, { variant: "light", onClick: () => inputRef.current?.click(), disabled: isDisabled, children: actionLabel }),
961
+ retryAction,
962
+ removeAction
963
+ ] })
882
964
  ] })
883
965
  ]
884
966
  }
@@ -892,6 +974,7 @@ import { jsx as jsx12 } from "react/jsx-runtime";
892
974
  var stateBlockVariantByState = {
893
975
  unauthenticated: "permission",
894
976
  "expired-session": "info",
977
+ timeout: "error",
895
978
  forbidden: "permission",
896
979
  missing: "error",
897
980
  unavailable: "error"
@@ -905,6 +988,10 @@ var defaultCopyByState = {
905
988
  title: "Session expired",
906
989
  description: "Sign in again or retry to continue where you left off."
907
990
  },
991
+ timeout: {
992
+ title: "Request timed out",
993
+ description: "The recovery action took too long. Retry or choose a safe destination."
994
+ },
908
995
  forbidden: {
909
996
  title: "You do not have access",
910
997
  description: "This content is outside your current permissions or scope."
@@ -936,6 +1023,12 @@ function defaultActionsForState(state, {
936
1023
  secondary: retryAction && signInAction ? retryAction : backAction,
937
1024
  tertiary: supportAction ?? null
938
1025
  };
1026
+ case "timeout":
1027
+ return {
1028
+ primary: retryAction ?? backAction,
1029
+ secondary: retryAction && backAction ? backAction : supportAction ?? null,
1030
+ tertiary: retryAction && backAction ? supportAction ?? null : null
1031
+ };
939
1032
  case "forbidden":
940
1033
  return { primary: backAction, secondary: supportAction ?? null, tertiary: null };
941
1034
  case "missing":