@squaredr/fieldcraft-pro 1.4.0 → 1.6.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.
@@ -731,7 +731,38 @@ function PaletteGenerator({ theme, onApply, onClose }) {
731
731
  }
732
732
 
733
733
  // src/theme-editor/presets.ts
734
- var draftingTealDarkPreset = {
734
+ var cleanPreset = {
735
+ colors: {
736
+ primary: "#1F6B6E",
737
+ primaryForeground: "#FFFFFF",
738
+ secondary: "#B9D1CF",
739
+ secondaryForeground: "#12222A",
740
+ error: "#B04A3C",
741
+ errorForeground: "#FFFFFF",
742
+ warning: "#C98A2E",
743
+ success: "#2E7D5B",
744
+ surface: "#FFFFFF",
745
+ background: "#F4F7F8",
746
+ text: "#12222A",
747
+ textMuted: "#6A7B85",
748
+ textDisabled: "#B9D1CF",
749
+ border: "#DCE4E8",
750
+ borderFocus: "#1F6B6E",
751
+ inputBackground: "#FFFFFF"
752
+ },
753
+ typography: {
754
+ fontFamily: "Inter, system-ui, sans-serif",
755
+ scale: "comfortable",
756
+ questionSize: "1.125rem",
757
+ labelSize: "0.875rem",
758
+ helpTextSize: "0.8125rem",
759
+ bodySize: "0.9375rem"
760
+ },
761
+ shape: { radius: "none", inputRadius: "0px", buttonRadius: "0px", cardRadius: "0px" },
762
+ spacing: { base: 16, sectionGap: 32, fieldGap: 24, inputPaddingX: 12, inputPaddingY: 10 },
763
+ layout: { maxWidth: "640px", alignment: "left", progressPosition: "top", sectionLayout: "card" }
764
+ };
765
+ var cleanDarkPreset = {
735
766
  colors: {
736
767
  primary: "#63BDB4",
737
768
  primaryForeground: "#0F1A1F",
@@ -740,7 +771,7 @@ var draftingTealDarkPreset = {
740
771
  error: "#E08072",
741
772
  errorForeground: "#0F1A1F",
742
773
  warning: "#E0A94F",
743
- success: "#63BDB4",
774
+ success: "#5DB89A",
744
775
  surface: "#16242A",
745
776
  background: "#0F1A1F",
746
777
  text: "#E8EFF1",
@@ -751,92 +782,281 @@ var draftingTealDarkPreset = {
751
782
  inputBackground: "#16242A"
752
783
  },
753
784
  typography: {
754
- fontFamily: "'Space Grotesk', 'IBM Plex Sans', system-ui, sans-serif",
785
+ fontFamily: "Inter, system-ui, sans-serif",
755
786
  scale: "comfortable",
756
- questionSize: "1.1875rem",
757
- labelSize: "0.8125rem",
787
+ questionSize: "1.125rem",
788
+ labelSize: "0.875rem",
758
789
  helpTextSize: "0.8125rem",
759
790
  bodySize: "0.9375rem"
760
791
  },
761
- shape: {
762
- radius: "none",
763
- inputRadius: "0px",
764
- buttonRadius: "0px",
765
- cardRadius: "0px"
792
+ shape: { radius: "none", inputRadius: "0px", buttonRadius: "0px", cardRadius: "0px" },
793
+ spacing: { base: 16, sectionGap: 32, fieldGap: 24, inputPaddingX: 12, inputPaddingY: 10 },
794
+ layout: { maxWidth: "640px", alignment: "left", progressPosition: "top", sectionLayout: "card" }
795
+ };
796
+ var modernPreset = {
797
+ colors: {
798
+ primary: "#6366F1",
799
+ primaryForeground: "#ffffff",
800
+ secondary: "#8B5CF6",
801
+ secondaryForeground: "#ffffff",
802
+ error: "#F43F5E",
803
+ errorForeground: "#ffffff",
804
+ warning: "#F59E0B",
805
+ success: "#22C55E",
806
+ surface: "#ffffff",
807
+ background: "#FAFAFA",
808
+ text: "#18181B",
809
+ textMuted: "#71717A",
810
+ textDisabled: "#D4D4D8",
811
+ border: "#E4E4E7",
812
+ borderFocus: "#6366F1",
813
+ inputBackground: "#FAFAFA"
766
814
  },
767
- spacing: {
768
- base: 16,
769
- sectionGap: 32,
770
- fieldGap: 24,
771
- inputPaddingX: 12,
772
- inputPaddingY: 10
815
+ typography: {
816
+ fontFamily: "'Plus Jakarta Sans', Inter, system-ui, sans-serif",
817
+ scale: "comfortable",
818
+ questionSize: "1.25rem",
819
+ labelSize: "0.875rem",
820
+ helpTextSize: "0.8125rem",
821
+ bodySize: "1rem"
773
822
  },
774
- layout: {
775
- maxWidth: "640px",
776
- alignment: "left",
777
- progressPosition: "top",
778
- sectionLayout: "flat"
779
- }
823
+ shape: { radius: "lg", inputRadius: "12px", buttonRadius: "12px", cardRadius: "16px" },
824
+ spacing: { base: 16, sectionGap: 40, fieldGap: 28, inputPaddingX: 16, inputPaddingY: 12 },
825
+ layout: { maxWidth: "680px", alignment: "center", progressPosition: "top", sectionLayout: "card" }
780
826
  };
781
- var draftingTealPreset = {
827
+ var modernDarkPreset = {
782
828
  colors: {
783
- primary: "#1F6B6E",
784
- primaryForeground: "#FFFFFF",
785
- secondary: "#B9D1CF",
786
- secondaryForeground: "#12222A",
787
- error: "#B04A3C",
788
- errorForeground: "#FFFFFF",
789
- warning: "#C98A2E",
790
- success: "#2E7D5B",
791
- surface: "#FFFFFF",
792
- background: "#F4F7F8",
793
- text: "#12222A",
794
- textMuted: "#6A7B85",
795
- textDisabled: "#B9D1CF",
796
- border: "#DCE4E8",
797
- borderFocus: "#1F6B6E",
798
- inputBackground: "#FFFFFF"
829
+ primary: "#818CF8",
830
+ primaryForeground: "#1E1B4B",
831
+ secondary: "#A78BFA",
832
+ secondaryForeground: "#1E1B4B",
833
+ error: "#FB7185",
834
+ errorForeground: "#1E1B4B",
835
+ warning: "#FBBF24",
836
+ success: "#4ADE80",
837
+ surface: "#1E1B4B",
838
+ background: "#13111C",
839
+ text: "#E8E6F0",
840
+ textMuted: "#A1A1AA",
841
+ textDisabled: "#3F3F46",
842
+ border: "#2E2B4A",
843
+ borderFocus: "#818CF8",
844
+ inputBackground: "#1E1B4B"
799
845
  },
800
846
  typography: {
801
- fontFamily: "'Space Grotesk', 'IBM Plex Sans', system-ui, sans-serif",
847
+ fontFamily: "'Plus Jakarta Sans', Inter, system-ui, sans-serif",
802
848
  scale: "comfortable",
803
- questionSize: "1.1875rem",
804
- labelSize: "0.8125rem",
849
+ questionSize: "1.25rem",
850
+ labelSize: "0.875rem",
851
+ helpTextSize: "0.8125rem",
852
+ bodySize: "1rem"
853
+ },
854
+ shape: { radius: "lg", inputRadius: "12px", buttonRadius: "12px", cardRadius: "16px" },
855
+ spacing: { base: 16, sectionGap: 40, fieldGap: 28, inputPaddingX: 16, inputPaddingY: 12 },
856
+ layout: { maxWidth: "680px", alignment: "center", progressPosition: "top", sectionLayout: "card" }
857
+ };
858
+ var clinicalPreset = {
859
+ colors: {
860
+ primary: "#0284C7",
861
+ primaryForeground: "#ffffff",
862
+ secondary: "#0891B2",
863
+ secondaryForeground: "#ffffff",
864
+ error: "#DC2626",
865
+ errorForeground: "#ffffff",
866
+ warning: "#D97706",
867
+ success: "#16A34A",
868
+ surface: "#ffffff",
869
+ background: "#F0F9FF",
870
+ text: "#0C4A6E",
871
+ textMuted: "#64748B",
872
+ textDisabled: "#CBD5E1",
873
+ border: "#BAE6FD",
874
+ borderFocus: "#0284C7",
875
+ inputBackground: "#ffffff"
876
+ },
877
+ typography: {
878
+ fontFamily: "'Source Sans 3', 'Segoe UI', system-ui, sans-serif",
879
+ scale: "comfortable",
880
+ questionSize: "1.0625rem",
881
+ labelSize: "0.875rem",
805
882
  helpTextSize: "0.8125rem",
806
883
  bodySize: "0.9375rem"
807
884
  },
808
- shape: {
809
- radius: "none",
810
- inputRadius: "0px",
811
- buttonRadius: "0px",
812
- cardRadius: "0px"
885
+ shape: { radius: "sm", inputRadius: "6px", buttonRadius: "6px", cardRadius: "8px" },
886
+ spacing: { base: 16, sectionGap: 28, fieldGap: 24, inputPaddingX: 12, inputPaddingY: 10 },
887
+ layout: { maxWidth: "680px", alignment: "left", progressPosition: "top", sectionLayout: "bordered" }
888
+ };
889
+ var clinicalDarkPreset = {
890
+ colors: {
891
+ primary: "#38BDF8",
892
+ primaryForeground: "#0C1929",
893
+ secondary: "#22D3EE",
894
+ secondaryForeground: "#0C1929",
895
+ error: "#F87171",
896
+ errorForeground: "#0C1929",
897
+ warning: "#FBBF24",
898
+ success: "#34D399",
899
+ surface: "#0F2438",
900
+ background: "#0C1929",
901
+ text: "#E0F2FE",
902
+ textMuted: "#7DD3FC",
903
+ textDisabled: "#1E3A5F",
904
+ border: "#1E3A5F",
905
+ borderFocus: "#38BDF8",
906
+ inputBackground: "#0F2438"
813
907
  },
814
- spacing: {
815
- base: 16,
816
- sectionGap: 32,
817
- fieldGap: 24,
818
- inputPaddingX: 12,
819
- inputPaddingY: 10
908
+ typography: {
909
+ fontFamily: "'Source Sans 3', 'Segoe UI', system-ui, sans-serif",
910
+ scale: "comfortable",
911
+ questionSize: "1.0625rem",
912
+ labelSize: "0.875rem",
913
+ helpTextSize: "0.8125rem",
914
+ bodySize: "0.9375rem"
820
915
  },
821
- layout: {
822
- maxWidth: "640px",
823
- alignment: "left",
824
- progressPosition: "top",
825
- sectionLayout: "flat"
826
- }
916
+ shape: { radius: "sm", inputRadius: "6px", buttonRadius: "6px", cardRadius: "8px" },
917
+ spacing: { base: 16, sectionGap: 28, fieldGap: 24, inputPaddingX: 12, inputPaddingY: 10 },
918
+ layout: { maxWidth: "680px", alignment: "left", progressPosition: "top", sectionLayout: "bordered" }
827
919
  };
828
- var COMPARISON_PRESETS = {
829
- "drafting-teal": { label: "Drafting Teal", theme: draftingTealPreset },
830
- clean: { label: "Clean", theme: fieldcraftReact.cleanPreset },
831
- dark: { label: "Dark", theme: fieldcraftReact.darkPreset },
832
- modern: { label: "Modern", theme: fieldcraftReact.modernPreset },
833
- "high-contrast": { label: "High Contrast", theme: fieldcraftReact.highContrastPreset },
834
- clinical: { label: "Clinical", theme: fieldcraftReact.clinicalPreset },
835
- playful: { label: "Playful", theme: fieldcraftReact.playfulPreset }
920
+ var playfulPreset = {
921
+ colors: {
922
+ primary: "#EC4899",
923
+ primaryForeground: "#ffffff",
924
+ secondary: "#8B5CF6",
925
+ secondaryForeground: "#ffffff",
926
+ error: "#EF4444",
927
+ errorForeground: "#ffffff",
928
+ warning: "#F59E0B",
929
+ success: "#10B981",
930
+ surface: "#ffffff",
931
+ background: "#FFF7ED",
932
+ text: "#1C1917",
933
+ textMuted: "#78716C",
934
+ textDisabled: "#D6D3D1",
935
+ border: "#FDE68A",
936
+ borderFocus: "#EC4899",
937
+ inputBackground: "#FFFBEB"
938
+ },
939
+ typography: {
940
+ fontFamily: "'Nunito', 'Comic Neue', system-ui, sans-serif",
941
+ scale: "spacious",
942
+ questionSize: "1.25rem",
943
+ labelSize: "0.9375rem",
944
+ helpTextSize: "0.875rem",
945
+ bodySize: "1rem"
946
+ },
947
+ shape: { radius: "full", inputRadius: "9999px", buttonRadius: "9999px", cardRadius: "20px" },
948
+ spacing: { base: 18, sectionGap: 36, fieldGap: 28, inputPaddingX: 18, inputPaddingY: 12 },
949
+ layout: { maxWidth: "600px", alignment: "center", progressPosition: "top", sectionLayout: "card" }
836
950
  };
951
+ var playfulDarkPreset = {
952
+ colors: {
953
+ primary: "#F472B6",
954
+ primaryForeground: "#1A0A14",
955
+ secondary: "#A78BFA",
956
+ secondaryForeground: "#1A0A14",
957
+ error: "#FCA5A5",
958
+ errorForeground: "#1A0A14",
959
+ warning: "#FCD34D",
960
+ success: "#6EE7B7",
961
+ surface: "#2D1F2B",
962
+ background: "#1A0F19",
963
+ text: "#FDF2F8",
964
+ textMuted: "#D4A9C4",
965
+ textDisabled: "#4A3248",
966
+ border: "#5C3D56",
967
+ borderFocus: "#F472B6",
968
+ inputBackground: "#2D1F2B"
969
+ },
970
+ typography: {
971
+ fontFamily: "'Nunito', 'Comic Neue', system-ui, sans-serif",
972
+ scale: "spacious",
973
+ questionSize: "1.25rem",
974
+ labelSize: "0.9375rem",
975
+ helpTextSize: "0.875rem",
976
+ bodySize: "1rem"
977
+ },
978
+ shape: { radius: "full", inputRadius: "9999px", buttonRadius: "9999px", cardRadius: "20px" },
979
+ spacing: { base: 18, sectionGap: 36, fieldGap: 28, inputPaddingX: 18, inputPaddingY: 12 },
980
+ layout: { maxWidth: "600px", alignment: "center", progressPosition: "top", sectionLayout: "card" }
981
+ };
982
+ var highContrastPreset = {
983
+ colors: {
984
+ primary: "#0000EE",
985
+ primaryForeground: "#ffffff",
986
+ secondary: "#6B21A8",
987
+ secondaryForeground: "#ffffff",
988
+ error: "#B91C1C",
989
+ errorForeground: "#ffffff",
990
+ warning: "#92400E",
991
+ success: "#166534",
992
+ surface: "#ffffff",
993
+ background: "#ffffff",
994
+ text: "#000000",
995
+ textMuted: "#374151",
996
+ textDisabled: "#9CA3AF",
997
+ border: "#000000",
998
+ borderFocus: "#0000EE",
999
+ inputBackground: "#ffffff"
1000
+ },
1001
+ typography: {
1002
+ fontFamily: "Arial, Helvetica, sans-serif",
1003
+ scale: "spacious",
1004
+ questionSize: "1.25rem",
1005
+ labelSize: "1rem",
1006
+ helpTextSize: "0.9375rem",
1007
+ bodySize: "1rem"
1008
+ },
1009
+ shape: { radius: "sm", inputRadius: "4px", buttonRadius: "4px", cardRadius: "4px" },
1010
+ spacing: { base: 20, sectionGap: 40, fieldGap: 32, inputPaddingX: 14, inputPaddingY: 12 },
1011
+ layout: { maxWidth: "720px", alignment: "left", progressPosition: "top", sectionLayout: "bordered" }
1012
+ };
1013
+ var highContrastDarkPreset = {
1014
+ colors: {
1015
+ primary: "#93C5FD",
1016
+ primaryForeground: "#000000",
1017
+ secondary: "#C084FC",
1018
+ secondaryForeground: "#000000",
1019
+ error: "#FCA5A5",
1020
+ errorForeground: "#000000",
1021
+ warning: "#FCD34D",
1022
+ success: "#86EFAC",
1023
+ surface: "#000000",
1024
+ background: "#000000",
1025
+ text: "#FFFFFF",
1026
+ textMuted: "#D1D5DB",
1027
+ textDisabled: "#6B7280",
1028
+ border: "#FFFFFF",
1029
+ borderFocus: "#93C5FD",
1030
+ inputBackground: "#000000"
1031
+ },
1032
+ typography: {
1033
+ fontFamily: "Arial, Helvetica, sans-serif",
1034
+ scale: "spacious",
1035
+ questionSize: "1.25rem",
1036
+ labelSize: "1rem",
1037
+ helpTextSize: "0.9375rem",
1038
+ bodySize: "1rem"
1039
+ },
1040
+ shape: { radius: "sm", inputRadius: "4px", buttonRadius: "4px", cardRadius: "4px" },
1041
+ spacing: { base: 20, sectionGap: 40, fieldGap: 32, inputPaddingX: 14, inputPaddingY: 12 },
1042
+ layout: { maxWidth: "720px", alignment: "left", progressPosition: "top", sectionLayout: "bordered" }
1043
+ };
1044
+ var PRESET_FAMILIES = {
1045
+ clean: { light: cleanPreset, dark: cleanDarkPreset, label: "Clean" },
1046
+ modern: { light: modernPreset, dark: modernDarkPreset, label: "Modern" },
1047
+ clinical: { light: clinicalPreset, dark: clinicalDarkPreset, label: "Clinical" },
1048
+ playful: { light: playfulPreset, dark: playfulDarkPreset, label: "Playful" },
1049
+ "high-contrast": { light: highContrastPreset, dark: highContrastDarkPreset, label: "High contrast" }
1050
+ };
1051
+ var COMPARISON_PRESETS = Object.fromEntries(
1052
+ Object.entries(PRESET_FAMILIES).map(([key, family]) => [
1053
+ key,
1054
+ { label: family.label, theme: family.light }
1055
+ ])
1056
+ );
837
1057
  function ThemeComparison({ currentTheme, onClose }) {
838
1058
  const [compareKey, setCompareKey] = react.useState("clean");
839
- const compareTheme = COMPARISON_PRESETS[compareKey]?.theme ?? fieldcraftReact.cleanPreset;
1059
+ const compareTheme = COMPARISON_PRESETS[compareKey]?.theme ?? PRESET_FAMILIES.clean.light;
840
1060
  const diffs = getColorDiffs(currentTheme, compareTheme);
841
1061
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fcte-compare", children: [
842
1062
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fcte-compare__header", children: [
@@ -934,6 +1154,50 @@ function getColorDiffs(a, b) {
934
1154
  }
935
1155
  return diffs;
936
1156
  }
1157
+
1158
+ // src/utils/resolve-theme-from-dom.ts
1159
+ function resolveThemeFromDOM() {
1160
+ if (typeof window === "undefined") return {};
1161
+ const styles = getComputedStyle(document.documentElement);
1162
+ const get = (prop) => {
1163
+ const val = styles.getPropertyValue(prop).trim();
1164
+ return val || void 0;
1165
+ };
1166
+ return {
1167
+ colors: {
1168
+ primary: get("--primary"),
1169
+ primaryForeground: get("--primary-foreground"),
1170
+ secondary: get("--secondary"),
1171
+ secondaryForeground: get("--secondary-foreground"),
1172
+ error: get("--destructive"),
1173
+ errorForeground: get("--destructive-foreground"),
1174
+ warning: get("--fc-color-warning"),
1175
+ success: get("--fc-color-success"),
1176
+ surface: get("--card"),
1177
+ background: get("--background"),
1178
+ text: get("--foreground"),
1179
+ textMuted: get("--muted-foreground"),
1180
+ textDisabled: void 0,
1181
+ border: get("--border"),
1182
+ borderFocus: get("--ring"),
1183
+ inputBackground: get("--input-background") ?? get("--card")
1184
+ },
1185
+ typography: {
1186
+ fontFamily: get("--fc-font-family"),
1187
+ // scale is an enum ("compact" | "comfortable" | "spacious") — not resolvable from CSS
1188
+ questionSize: get("--fc-font-question"),
1189
+ labelSize: get("--fc-font-label"),
1190
+ helpTextSize: get("--fc-font-help"),
1191
+ bodySize: get("--fc-font-body")
1192
+ },
1193
+ shape: {
1194
+ // radius is an enum ("none" | "sm" | "md" | "lg" | "full") — not resolvable from CSS
1195
+ inputRadius: get("--fc-radius-input"),
1196
+ buttonRadius: get("--fc-radius-button"),
1197
+ cardRadius: get("--fc-radius-card")
1198
+ }
1199
+ };
1200
+ }
937
1201
  var ThemeCtx = react.createContext({});
938
1202
  function useEditorTheme() {
939
1203
  return react.useContext(ThemeCtx);
@@ -958,15 +1222,15 @@ function ThemeEditorThemeProvider({ theme, children }) {
958
1222
  const cssVars = react.useMemo(() => themeToCssVars(resolved), [resolved]);
959
1223
  return /* @__PURE__ */ jsxRuntime.jsx(ThemeCtx.Provider, { value: resolved, children: /* @__PURE__ */ jsxRuntime.jsx("div", { "data-fcte-root": "", style: cssVars, className: "fcte-provider-root", children }) });
960
1224
  }
961
- var PRESETS = {
962
- "drafting-teal": draftingTealPreset,
963
- clean: fieldcraftReact.cleanPreset,
964
- dark: fieldcraftReact.darkPreset,
965
- modern: fieldcraftReact.modernPreset,
966
- "high-contrast": fieldcraftReact.highContrastPreset,
967
- clinical: fieldcraftReact.clinicalPreset,
968
- playful: fieldcraftReact.playfulPreset
969
- };
1225
+ function isDarkTheme(theme) {
1226
+ const bg = theme.colors?.background ?? "#FFFFFF";
1227
+ const hex = bg.replace("#", "");
1228
+ if (hex.length < 6) return false;
1229
+ const r = parseInt(hex.slice(0, 2), 16);
1230
+ const g = parseInt(hex.slice(2, 4), 16);
1231
+ const b = parseInt(hex.slice(4, 6), 16);
1232
+ return 0.299 * r + 0.587 * g + 0.114 * b < 128;
1233
+ }
970
1234
  var SECTIONS = [
971
1235
  {
972
1236
  id: "colors",
@@ -1096,9 +1360,17 @@ function ThemeEditorInner({
1096
1360
  toolbarExtra,
1097
1361
  showPreview = true
1098
1362
  }) {
1099
- const [theme, setTheme] = react.useState(initialTheme ?? draftingTealPreset);
1363
+ const resolvedInitial = react.useMemo(
1364
+ () => initialTheme ?? resolveThemeFromDOM(),
1365
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1366
+ []
1367
+ );
1368
+ const [theme, setTheme] = react.useState(resolvedInitial);
1100
1369
  const [activeSection, setActiveSection] = react.useState("colors");
1101
- const [presetKey, setPresetKey] = react.useState(initialTheme ? "custom" : "drafting-teal");
1370
+ const [presetKey, setPresetKey] = react.useState("custom");
1371
+ const [mode, setMode] = react.useState(
1372
+ () => isDarkTheme(resolvedInitial) ? "dark" : "light"
1373
+ );
1102
1374
  const [showPalette, setShowPalette] = react.useState(false);
1103
1375
  const [showComparison, setShowComparison] = react.useState(false);
1104
1376
  const themeRef = react.useRef(theme);
@@ -1128,16 +1400,30 @@ function ThemeEditorInner({
1128
1400
  [onChange]
1129
1401
  );
1130
1402
  const loadPreset = react.useCallback(
1131
- (key) => {
1132
- const preset = PRESETS[key];
1133
- if (preset) {
1403
+ (key, forceMode) => {
1404
+ const family = PRESET_FAMILIES[key];
1405
+ if (family) {
1406
+ const m = forceMode ?? mode;
1407
+ const preset = family[m];
1134
1408
  setTheme(preset);
1135
1409
  setPresetKey(key);
1136
1410
  onChange?.(preset);
1137
1411
  }
1138
1412
  },
1139
- [onChange]
1413
+ [onChange, mode]
1140
1414
  );
1415
+ const toggleMode = react.useCallback(() => {
1416
+ setMode((prev) => {
1417
+ const next = prev === "light" ? "dark" : "light";
1418
+ const family = PRESET_FAMILIES[presetKey];
1419
+ if (family) {
1420
+ const preset = family[next];
1421
+ setTheme(preset);
1422
+ onChange?.(preset);
1423
+ }
1424
+ return next;
1425
+ });
1426
+ }, [presetKey, onChange]);
1141
1427
  const exportJson = react.useCallback(() => {
1142
1428
  const blob = new Blob([JSON.stringify(theme, null, 2)], { type: "application/json" });
1143
1429
  const url = URL.createObjectURL(blob);
@@ -1203,9 +1489,18 @@ function ThemeEditorInner({
1203
1489
  className: "fcte-toolbar__preset",
1204
1490
  children: [
1205
1491
  /* @__PURE__ */ jsxRuntime.jsx("option", { value: "custom", disabled: true, children: "Custom" }),
1206
- Object.keys(PRESETS).map((k) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: k, children: k.charAt(0).toUpperCase() + k.slice(1).replace("-", " ") }, k))
1492
+ Object.entries(PRESET_FAMILIES).map(([k, fam]) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: k, children: fam.label }, k))
1207
1493
  ]
1208
1494
  }
1495
+ ),
1496
+ /* @__PURE__ */ jsxRuntime.jsx(
1497
+ "button",
1498
+ {
1499
+ onClick: toggleMode,
1500
+ className: "fcte-btn fcte-btn--secondary fcte-toolbar__mode",
1501
+ title: mode === "light" ? "Switch to dark mode" : "Switch to light mode",
1502
+ children: mode === "light" ? "\u2600" : "\u263E"
1503
+ }
1209
1504
  )
1210
1505
  ] }),
1211
1506
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fcte-toolbar__right", children: [
@@ -1402,12 +1697,12 @@ var themeEditorDarkPreset = {
1402
1697
  accentForeground: "#0F1A1F"
1403
1698
  };
1404
1699
 
1700
+ exports.PRESET_FAMILIES = PRESET_FAMILIES;
1405
1701
  exports.PREVIEW_SCHEMA = PREVIEW_SCHEMA;
1406
1702
  exports.ThemeEditor = ThemeEditor;
1407
1703
  exports.ThemeEditorInner = ThemeEditorInner;
1408
1704
  exports.ThemeEditorThemeProvider = ThemeEditorThemeProvider;
1409
- exports.draftingTealDarkPreset = draftingTealDarkPreset;
1410
- exports.draftingTealPreset = draftingTealPreset;
1705
+ exports.resolveThemeFromDOM = resolveThemeFromDOM;
1411
1706
  exports.themeEditorDarkPreset = themeEditorDarkPreset;
1412
1707
  exports.themeEditorLightPreset = themeEditorLightPreset;
1413
1708
  exports.useEditorTheme = useEditorTheme;
@@ -1,2 +1,2 @@
1
- export { PREVIEW_SCHEMA, ThemeEditor, ThemeEditorInner, ThemeEditorThemeProvider, draftingTealDarkPreset, draftingTealPreset, themeEditorDarkPreset, themeEditorLightPreset, useEditorTheme } from '../chunk-22T5PY6L.mjs';
1
+ export { PRESET_FAMILIES, PREVIEW_SCHEMA, ThemeEditor, ThemeEditorInner, ThemeEditorThemeProvider, resolveThemeFromDOM, themeEditorDarkPreset, themeEditorLightPreset, useEditorTheme } from '../chunk-IKGS2ZXV.mjs';
2
2
  import '../chunk-VECQKSWS.mjs';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@squaredr/fieldcraft-pro",
3
- "version": "1.4.0",
3
+ "version": "1.6.0",
4
4
  "description": "Pro components for FieldCraft — visual drag-and-drop Form Builder, Response Viewer, and Theme Editor for React",
5
5
  "keywords": [
6
6
  "fieldcraft",
@@ -64,14 +64,24 @@
64
64
  "tailwind-merge": "^3.6.0"
65
65
  },
66
66
  "peerDependencies": {
67
- "@squaredr/fieldcraft-core": "^1.5.0",
68
- "@squaredr/fieldcraft-react": "^1.4.0",
67
+ "@squaredr/fieldcraft-core": "^1.6.0",
68
+ "@squaredr/fieldcraft-react": "^1.6.0",
69
+ "@squaredr/paykit-react": "^1.0.0",
70
+ "@squaredr/paykit-stripe": "^1.0.0",
69
71
  "react": "^18 || ^19",
70
72
  "react-dom": "^18 || ^19"
71
73
  },
74
+ "peerDependenciesMeta": {
75
+ "@squaredr/paykit-react": {
76
+ "optional": true
77
+ },
78
+ "@squaredr/paykit-stripe": {
79
+ "optional": true
80
+ }
81
+ },
72
82
  "devDependencies": {
73
- "@squaredr/fieldcraft-core": "^1.5.0",
74
- "@squaredr/fieldcraft-react": "^1.4.0",
83
+ "@squaredr/fieldcraft-core": "^1.6.0",
84
+ "@squaredr/fieldcraft-react": "^1.6.0",
75
85
  "@tailwindcss/cli": "^4.3.0",
76
86
  "@types/react": "^19.2.14",
77
87
  "@types/react-dom": "^19.2.3",
@@ -1,9 +1,10 @@
1
1
  /* FieldCraft Pro Theme Editor
2
2
  Chrome theming follows the FormBuilder pattern:
3
3
  1. ThemeEditorThemeProvider wraps children in <div data-fcte-root="" style={cssVars}>
4
- 2. [data-fcte-root] defines fallback defaults (Drafting Teal light)
5
- 3. Provider inline styles override these when a theme prop is passed
6
- 4. All editor chrome references var(--fcte-*) fully themeable
4
+ 2. :where([data-fcte-root]) defines zero-specificity fallback defaults
5
+ 3. Host page :root variables naturally cascade through (higher specificity)
6
+ 4. Provider inline styles override everything when a theme prop is passed
7
+ 5. All editor chrome references var(--fcte-*) — fully themeable
7
8
  */
8
9
 
9
10
  /* ─── Provider root ─────────────────────────────────────────────── */
@@ -12,8 +13,12 @@
12
13
  height: 100%;
13
14
  }
14
15
 
15
- /* ─── Default theme variables inherit from host app tokens ────── */
16
- [data-fcte-root] {
16
+ /* ─── Default theme variables (zero specificity) ───────────────── */
17
+ /* :where() gives these zero specificity so host page :root
18
+ variables naturally override them. When no host defines
19
+ these vars, the fallback values apply. Inline styles from
20
+ ThemeEditorThemeProvider override everything. */
21
+ :where([data-fcte-root]) {
17
22
  --fcte-bg: var(--bg, #F4F7F8);
18
23
  --fcte-surface: var(--surface, #FFFFFF);
19
24
  --fcte-surface-hover: var(--wash, #EDF3F2);
@@ -78,6 +83,16 @@
78
83
  cursor: pointer;
79
84
  }
80
85
 
86
+ .fcte-toolbar__mode {
87
+ padding: 4px 8px;
88
+ font-size: 14px;
89
+ line-height: 1;
90
+ min-width: 28px;
91
+ display: flex;
92
+ align-items: center;
93
+ justify-content: center;
94
+ }
95
+
81
96
  /* ─── Buttons ───────────────────────────────────────────────────── */
82
97
  .fcte-btn {
83
98
  padding: 5px 12px;