@squaredr/fieldcraft-pro 1.4.0 → 1.5.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.
@@ -453,6 +453,14 @@ var QUESTION_TYPE_INFO = {
453
453
  icon: "Phone",
454
454
  description: "US phone number input"
455
455
  },
456
+ phone_international: {
457
+ type: "phone_international",
458
+ label: "Intl Phone",
459
+ category: "text",
460
+ icon: "Globe2",
461
+ description: "Phone with country code",
462
+ defaultConfig: { type: "phone_international", defaultCountry: "US" }
463
+ },
456
464
  url: {
457
465
  type: "url",
458
466
  label: "URL",
@@ -546,6 +554,14 @@ var QUESTION_TYPE_INFO = {
546
554
  requiresOptions: true,
547
555
  defaultConfig: { type: "ranking", items: [] }
548
556
  },
557
+ country_select: {
558
+ type: "country_select",
559
+ label: "Country",
560
+ category: "selection",
561
+ icon: "Globe",
562
+ description: "Country dropdown with search",
563
+ defaultConfig: { type: "country_select" }
564
+ },
549
565
  // ── Date/Time ──
550
566
  date: {
551
567
  type: "date",
@@ -597,6 +613,14 @@ var QUESTION_TYPE_INFO = {
597
613
  description: "Canvas signature pad",
598
614
  defaultConfig: { type: "signature" }
599
615
  },
616
+ image_capture: {
617
+ type: "image_capture",
618
+ label: "Camera",
619
+ category: "media",
620
+ icon: "Camera",
621
+ description: "Capture photo from camera",
622
+ defaultConfig: { type: "image_capture", allowGallery: true }
623
+ },
600
624
  date_range: {
601
625
  type: "date_range",
602
626
  label: "Date Range",
@@ -605,6 +629,14 @@ var QUESTION_TYPE_INFO = {
605
629
  description: "Start and end date picker",
606
630
  defaultConfig: { type: "date_range" }
607
631
  },
632
+ appointment: {
633
+ type: "appointment",
634
+ label: "Appointment",
635
+ category: "datetime",
636
+ icon: "CalendarCheck",
637
+ description: "Date & time slot booking",
638
+ defaultConfig: { type: "appointment", duration: 30 }
639
+ },
608
640
  // ── Advanced ──
609
641
  repeater: {
610
642
  type: "repeater",
@@ -676,6 +708,14 @@ var QUESTION_TYPE_INFO = {
676
708
  description: "Hidden value from URL or static",
677
709
  defaultConfig: { type: "hidden", source: "static" }
678
710
  },
711
+ payment: {
712
+ type: "payment",
713
+ label: "Payment",
714
+ category: "advanced",
715
+ icon: "CreditCard",
716
+ description: "Collect payment via Stripe",
717
+ defaultConfig: { type: "payment", provider: "stripe", publicKey: "", currency: "USD" }
718
+ },
679
719
  // ── Structural ──
680
720
  section_header: {
681
721
  type: "section_header",
@@ -780,7 +820,7 @@ var DEFAULT_PALETTE = [
780
820
  {
781
821
  category: "text",
782
822
  label: "Text Input",
783
- types: ["short_text", "long_text", "email", "phone", "url", "legal_name", "address"]
823
+ types: ["short_text", "long_text", "email", "phone", "phone_international", "url", "legal_name", "address"]
784
824
  },
785
825
  {
786
826
  category: "numeric",
@@ -790,17 +830,17 @@ var DEFAULT_PALETTE = [
790
830
  {
791
831
  category: "selection",
792
832
  label: "Selection",
793
- types: ["single_select", "multi_select", "dropdown", "boolean", "ranking"]
833
+ types: ["single_select", "multi_select", "dropdown", "boolean", "ranking", "country_select"]
794
834
  },
795
835
  {
796
836
  category: "datetime",
797
837
  label: "Date & Time",
798
- types: ["date", "time", "date_range"]
838
+ types: ["date", "time", "date_range", "appointment"]
799
839
  },
800
840
  {
801
841
  category: "media",
802
842
  label: "Media",
803
- types: ["file_upload", "signature"]
843
+ types: ["file_upload", "signature", "image_capture"]
804
844
  },
805
845
  {
806
846
  category: "content",
@@ -815,7 +855,7 @@ var DEFAULT_PALETTE = [
815
855
  {
816
856
  category: "advanced",
817
857
  label: "Advanced",
818
- types: ["repeater", "likert", "scoring", "matrix", "calculated", "hidden"]
858
+ types: ["repeater", "likert", "scoring", "matrix", "calculated", "hidden", "payment"]
819
859
  }
820
860
  ];
821
861
 
@@ -1,4 +1,4 @@
1
- export { B as BuilderState, a as BuilderStateHook, D as DEFAULT_PALETTE, b as DEFAULT_SCHEMA, c as DragItem, d as DropTarget, F as FormBuilder, f as FormBuilderProps, h as FormBuilderTheme, i as FormBuilderThemeProvider, M as MutationAction, P as PaletteCategory, j as PropertyPanelTab, Q as QUESTION_TYPE_INFO, k as QuestionTypeCategory, l as QuestionTypeInfo, S as SelectedItem, U as UndoRedoState, m as addOption, n as addQuestion, o as addSection, p as cleanPreset, q as cn, r as duplicateQuestion, s as duplicateSection, t as findQuestion, u as findSection, v as generateId, w as generateOptionId, x as generateQuestionId, y as generateSectionId, z as moveOption, A as moveQuestion, C as moveSection, E as removeOption, G as removeQuestion, H as removeSection, I as squaredrDarkPreset, J as updateOption, K as updateQuestion, L as updateSection, N as useBuilderState, O as useBuilderTheme, R as useDragDrop, T as useUndoRedo } from '../index-nvIvXlmc.mjs';
1
+ export { B as BuilderState, a as BuilderStateHook, D as DEFAULT_PALETTE, b as DEFAULT_SCHEMA, c as DragItem, d as DropTarget, F as FormBuilder, f as FormBuilderProps, h as FormBuilderTheme, i as FormBuilderThemeProvider, M as MutationAction, P as PaletteCategory, j as PropertyPanelTab, Q as QUESTION_TYPE_INFO, k as QuestionTypeCategory, l as QuestionTypeInfo, S as SelectedItem, U as UndoRedoState, m as addOption, n as addQuestion, o as addSection, p as cleanPreset, q as cn, r as duplicateQuestion, s as duplicateSection, t as findQuestion, u as findSection, v as generateId, w as generateOptionId, x as generateQuestionId, y as generateSectionId, z as moveOption, A as moveQuestion, C as moveSection, E as removeOption, G as removeQuestion, H as removeSection, I as squaredrDarkPreset, J as updateOption, K as updateQuestion, L as updateSection, N as useBuilderState, O as useBuilderTheme, R as useDragDrop, T as useUndoRedo } from '../index-BHJ4mqHP.mjs';
2
2
  import 'react';
3
3
  import '@squaredr/fieldcraft-core';
4
4
  import '@squaredr/fieldcraft-react';
@@ -1,4 +1,4 @@
1
- export { B as BuilderState, a as BuilderStateHook, D as DEFAULT_PALETTE, b as DEFAULT_SCHEMA, c as DragItem, d as DropTarget, F as FormBuilder, f as FormBuilderProps, h as FormBuilderTheme, i as FormBuilderThemeProvider, M as MutationAction, P as PaletteCategory, j as PropertyPanelTab, Q as QUESTION_TYPE_INFO, k as QuestionTypeCategory, l as QuestionTypeInfo, S as SelectedItem, U as UndoRedoState, m as addOption, n as addQuestion, o as addSection, p as cleanPreset, q as cn, r as duplicateQuestion, s as duplicateSection, t as findQuestion, u as findSection, v as generateId, w as generateOptionId, x as generateQuestionId, y as generateSectionId, z as moveOption, A as moveQuestion, C as moveSection, E as removeOption, G as removeQuestion, H as removeSection, I as squaredrDarkPreset, J as updateOption, K as updateQuestion, L as updateSection, N as useBuilderState, O as useBuilderTheme, R as useDragDrop, T as useUndoRedo } from '../index-nvIvXlmc.js';
1
+ export { B as BuilderState, a as BuilderStateHook, D as DEFAULT_PALETTE, b as DEFAULT_SCHEMA, c as DragItem, d as DropTarget, F as FormBuilder, f as FormBuilderProps, h as FormBuilderTheme, i as FormBuilderThemeProvider, M as MutationAction, P as PaletteCategory, j as PropertyPanelTab, Q as QUESTION_TYPE_INFO, k as QuestionTypeCategory, l as QuestionTypeInfo, S as SelectedItem, U as UndoRedoState, m as addOption, n as addQuestion, o as addSection, p as cleanPreset, q as cn, r as duplicateQuestion, s as duplicateSection, t as findQuestion, u as findSection, v as generateId, w as generateOptionId, x as generateQuestionId, y as generateSectionId, z as moveOption, A as moveQuestion, C as moveSection, E as removeOption, G as removeQuestion, H as removeSection, I as squaredrDarkPreset, J as updateOption, K as updateQuestion, L as updateSection, N as useBuilderState, O as useBuilderTheme, R as useDragDrop, T as useUndoRedo } from '../index-BHJ4mqHP.js';
2
2
  import 'react';
3
3
  import '@squaredr/fieldcraft-core';
4
4
  import '@squaredr/fieldcraft-react';
@@ -777,6 +777,14 @@ var QUESTION_TYPE_INFO = {
777
777
  icon: "Phone",
778
778
  description: "US phone number input"
779
779
  },
780
+ phone_international: {
781
+ type: "phone_international",
782
+ label: "Intl Phone",
783
+ category: "text",
784
+ icon: "Globe2",
785
+ description: "Phone with country code",
786
+ defaultConfig: { type: "phone_international", defaultCountry: "US" }
787
+ },
780
788
  url: {
781
789
  type: "url",
782
790
  label: "URL",
@@ -870,6 +878,14 @@ var QUESTION_TYPE_INFO = {
870
878
  requiresOptions: true,
871
879
  defaultConfig: { type: "ranking", items: [] }
872
880
  },
881
+ country_select: {
882
+ type: "country_select",
883
+ label: "Country",
884
+ category: "selection",
885
+ icon: "Globe",
886
+ description: "Country dropdown with search",
887
+ defaultConfig: { type: "country_select" }
888
+ },
873
889
  // ── Date/Time ──
874
890
  date: {
875
891
  type: "date",
@@ -921,6 +937,14 @@ var QUESTION_TYPE_INFO = {
921
937
  description: "Canvas signature pad",
922
938
  defaultConfig: { type: "signature" }
923
939
  },
940
+ image_capture: {
941
+ type: "image_capture",
942
+ label: "Camera",
943
+ category: "media",
944
+ icon: "Camera",
945
+ description: "Capture photo from camera",
946
+ defaultConfig: { type: "image_capture", allowGallery: true }
947
+ },
924
948
  date_range: {
925
949
  type: "date_range",
926
950
  label: "Date Range",
@@ -929,6 +953,14 @@ var QUESTION_TYPE_INFO = {
929
953
  description: "Start and end date picker",
930
954
  defaultConfig: { type: "date_range" }
931
955
  },
956
+ appointment: {
957
+ type: "appointment",
958
+ label: "Appointment",
959
+ category: "datetime",
960
+ icon: "CalendarCheck",
961
+ description: "Date & time slot booking",
962
+ defaultConfig: { type: "appointment", duration: 30 }
963
+ },
932
964
  // ── Advanced ──
933
965
  repeater: {
934
966
  type: "repeater",
@@ -1000,6 +1032,14 @@ var QUESTION_TYPE_INFO = {
1000
1032
  description: "Hidden value from URL or static",
1001
1033
  defaultConfig: { type: "hidden", source: "static" }
1002
1034
  },
1035
+ payment: {
1036
+ type: "payment",
1037
+ label: "Payment",
1038
+ category: "advanced",
1039
+ icon: "CreditCard",
1040
+ description: "Collect payment via Stripe",
1041
+ defaultConfig: { type: "payment", provider: "stripe", publicKey: "", currency: "USD" }
1042
+ },
1003
1043
  // ── Structural ──
1004
1044
  section_header: {
1005
1045
  type: "section_header",
@@ -1104,7 +1144,7 @@ var DEFAULT_PALETTE = [
1104
1144
  {
1105
1145
  category: "text",
1106
1146
  label: "Text Input",
1107
- types: ["short_text", "long_text", "email", "phone", "url", "legal_name", "address"]
1147
+ types: ["short_text", "long_text", "email", "phone", "phone_international", "url", "legal_name", "address"]
1108
1148
  },
1109
1149
  {
1110
1150
  category: "numeric",
@@ -1114,17 +1154,17 @@ var DEFAULT_PALETTE = [
1114
1154
  {
1115
1155
  category: "selection",
1116
1156
  label: "Selection",
1117
- types: ["single_select", "multi_select", "dropdown", "boolean", "ranking"]
1157
+ types: ["single_select", "multi_select", "dropdown", "boolean", "ranking", "country_select"]
1118
1158
  },
1119
1159
  {
1120
1160
  category: "datetime",
1121
1161
  label: "Date & Time",
1122
- types: ["date", "time", "date_range"]
1162
+ types: ["date", "time", "date_range", "appointment"]
1123
1163
  },
1124
1164
  {
1125
1165
  category: "media",
1126
1166
  label: "Media",
1127
- types: ["file_upload", "signature"]
1167
+ types: ["file_upload", "signature", "image_capture"]
1128
1168
  },
1129
1169
  {
1130
1170
  category: "content",
@@ -1139,7 +1179,7 @@ var DEFAULT_PALETTE = [
1139
1179
  {
1140
1180
  category: "advanced",
1141
1181
  label: "Advanced",
1142
- types: ["repeater", "likert", "scoring", "matrix", "calculated", "hidden"]
1182
+ types: ["repeater", "likert", "scoring", "matrix", "calculated", "hidden", "payment"]
1143
1183
  }
1144
1184
  ];
1145
1185
 
@@ -1,3 +1,3 @@
1
- export { DEFAULT_PALETTE, DEFAULT_SCHEMA, FormBuilder, FormBuilderThemeProvider, QUESTION_TYPE_INFO, addOption, addQuestion, addSection, cleanPreset, duplicateQuestion, duplicateSection, findQuestion, findSection, generateId, generateOptionId, generateQuestionId, generateSectionId, moveOption, moveQuestion, moveSection, removeOption, removeQuestion, removeSection, squaredrDarkPreset, updateOption, updateQuestion, updateSection, useBuilderState, useBuilderTheme, useDragDrop, useUndoRedo } from '../chunk-BYT2P3I6.mjs';
1
+ export { DEFAULT_PALETTE, DEFAULT_SCHEMA, FormBuilder, FormBuilderThemeProvider, QUESTION_TYPE_INFO, addOption, addQuestion, addSection, cleanPreset, duplicateQuestion, duplicateSection, findQuestion, findSection, generateId, generateOptionId, generateQuestionId, generateSectionId, moveOption, moveQuestion, moveSection, removeOption, removeQuestion, removeSection, squaredrDarkPreset, updateOption, updateQuestion, updateSection, useBuilderState, useBuilderTheme, useDragDrop, useUndoRedo } from '../chunk-6LRUDBC7.mjs';
2
2
  export { cn } from '../chunk-QQ4JZGTD.mjs';
3
3
  import '../chunk-VECQKSWS.mjs';
@@ -243,12 +243,12 @@ declare const cleanPreset: FormBuilderTheme;
243
243
  * Metadata for all question types available in the Pro palette.
244
244
  * Icons are lucide-react component names (imported dynamically via ICON_MAP).
245
245
  *
246
- * 39 field types — general-purpose form building.
246
+ * 44 field types — general-purpose form building.
247
247
  * Telehealth-specific fields (15) are in @squaredr/fieldcraft-pro-telehealth.
248
248
  */
249
249
  declare const QUESTION_TYPE_INFO: Record<string, QuestionTypeInfo>;
250
250
  /**
251
- * Default palette layout with categories (39 Pro field types).
251
+ * Default palette layout with categories (44 Pro field types).
252
252
  * Telehealth fields can be appended via FormBuilder's `palette` prop.
253
253
  */
254
254
  declare const DEFAULT_PALETTE: ({
@@ -243,12 +243,12 @@ declare const cleanPreset: FormBuilderTheme;
243
243
  * Metadata for all question types available in the Pro palette.
244
244
  * Icons are lucide-react component names (imported dynamically via ICON_MAP).
245
245
  *
246
- * 39 field types — general-purpose form building.
246
+ * 44 field types — general-purpose form building.
247
247
  * Telehealth-specific fields (15) are in @squaredr/fieldcraft-pro-telehealth.
248
248
  */
249
249
  declare const QUESTION_TYPE_INFO: Record<string, QuestionTypeInfo>;
250
250
  /**
251
- * Default palette layout with categories (39 Pro field types).
251
+ * Default palette layout with categories (44 Pro field types).
252
252
  * Telehealth fields can be appended via FormBuilder's `palette` prop.
253
253
  */
254
254
  declare const DEFAULT_PALETTE: ({
package/dist/index.d.mts CHANGED
@@ -1,10 +1,10 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode, ComponentType } from 'react';
3
- export { B as BuilderState, a as BuilderStateHook, D as DEFAULT_PALETTE, b as DEFAULT_SCHEMA, c as DragItem, d as DropTarget, F as FormBuilder, e as FormBuilderPreviewProps, f as FormBuilderProps, g as FormBuilderTemplate, h as FormBuilderTheme, i as FormBuilderThemeProvider, M as MutationAction, P as PaletteCategory, j as PropertyPanelTab, Q as QUESTION_TYPE_INFO, k as QuestionTypeCategory, l as QuestionTypeInfo, S as SelectedItem, U as UndoRedoState, m as addOption, n as addQuestion, o as addSection, p as cleanPreset, q as cn, r as duplicateQuestion, s as duplicateSection, t as findQuestion, u as findSection, v as generateId, w as generateOptionId, x as generateQuestionId, y as generateSectionId, z as moveOption, A as moveQuestion, C as moveSection, E as removeOption, G as removeQuestion, H as removeSection, I as squaredrDarkPreset, J as updateOption, K as updateQuestion, L as updateSection, N as useBuilderState, O as useBuilderTheme, R as useDragDrop, T as useUndoRedo } from './index-nvIvXlmc.mjs';
3
+ export { B as BuilderState, a as BuilderStateHook, D as DEFAULT_PALETTE, b as DEFAULT_SCHEMA, c as DragItem, d as DropTarget, F as FormBuilder, e as FormBuilderPreviewProps, f as FormBuilderProps, g as FormBuilderTemplate, h as FormBuilderTheme, i as FormBuilderThemeProvider, M as MutationAction, P as PaletteCategory, j as PropertyPanelTab, Q as QUESTION_TYPE_INFO, k as QuestionTypeCategory, l as QuestionTypeInfo, S as SelectedItem, U as UndoRedoState, m as addOption, n as addQuestion, o as addSection, p as cleanPreset, q as cn, r as duplicateQuestion, s as duplicateSection, t as findQuestion, u as findSection, v as generateId, w as generateOptionId, x as generateQuestionId, y as generateSectionId, z as moveOption, A as moveQuestion, C as moveSection, E as removeOption, G as removeQuestion, H as removeSection, I as squaredrDarkPreset, J as updateOption, K as updateQuestion, L as updateSection, N as useBuilderState, O as useBuilderTheme, R as useDragDrop, T as useUndoRedo } from './index-BHJ4mqHP.mjs';
4
+ import { FieldComponent, FieldProps } from '@squaredr/fieldcraft-react';
4
5
  export { ResponseField, ResponseViewer, ResponseViewerProps, ViewMode } from './response-viewer/index.mjs';
5
6
  export { P as PREVIEW_SCHEMA, T as ThemeEditor, a as ThemeEditorInner, b as ThemeEditorProps } from './preview-schema-DFvV4y6J.mjs';
6
7
  import '@squaredr/fieldcraft-core';
7
- import '@squaredr/fieldcraft-react';
8
8
  import 'clsx';
9
9
  import '@dnd-kit/core';
10
10
 
@@ -56,4 +56,30 @@ declare function UnlicensedOverlay({ featureName, reason, children }: Unlicensed
56
56
  */
57
57
  declare function isProductionEnvironment(): boolean;
58
58
 
59
- export { FieldCraftProProvider, type LicenseContext, type LicenseStatus, UnlicensedOverlay, isProductionEnvironment, requireLicense, useLicense, validateLicense };
59
+ /**
60
+ * Pro Payment Field — full Stripe integration with dual-mode support.
61
+ *
62
+ * Resolution order for getting clientSecret (first match wins):
63
+ * 1. `customProps.clientSecret` — direct mode (simplest)
64
+ * 2. `customProps.onCreatePaymentIntent` callback — Pro dev mode
65
+ * 3. `config.serverUrl` — SaaS mode (POST to create intent)
66
+ * 4. Nothing — show setup message
67
+ *
68
+ * Requires `@squaredr/paykit-react` and `@squaredr/paykit-stripe/client` as peer deps.
69
+ */
70
+ declare function ProPaymentField(props: FieldProps): react_jsx_runtime.JSX.Element;
71
+
72
+ /**
73
+ * PRO_FIELD_OVERRIDES registry — maps field types to Pro-enhanced components.
74
+ * Pass this to FormEngineRenderer's `components` prop to enable Pro payment:
75
+ *
76
+ * ```tsx
77
+ * import { PRO_FIELD_OVERRIDES } from "@squaredr/fieldcraft-pro";
78
+ * <FormEngineRenderer schema={schema} components={PRO_FIELD_OVERRIDES} />
79
+ * ```
80
+ */
81
+ declare const PRO_FIELD_OVERRIDES: {
82
+ readonly payment: FieldComponent;
83
+ };
84
+
85
+ export { FieldCraftProProvider, type LicenseContext, type LicenseStatus, PRO_FIELD_OVERRIDES, ProPaymentField, UnlicensedOverlay, isProductionEnvironment, requireLicense, useLicense, validateLicense };
package/dist/index.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode, ComponentType } from 'react';
3
- export { B as BuilderState, a as BuilderStateHook, D as DEFAULT_PALETTE, b as DEFAULT_SCHEMA, c as DragItem, d as DropTarget, F as FormBuilder, e as FormBuilderPreviewProps, f as FormBuilderProps, g as FormBuilderTemplate, h as FormBuilderTheme, i as FormBuilderThemeProvider, M as MutationAction, P as PaletteCategory, j as PropertyPanelTab, Q as QUESTION_TYPE_INFO, k as QuestionTypeCategory, l as QuestionTypeInfo, S as SelectedItem, U as UndoRedoState, m as addOption, n as addQuestion, o as addSection, p as cleanPreset, q as cn, r as duplicateQuestion, s as duplicateSection, t as findQuestion, u as findSection, v as generateId, w as generateOptionId, x as generateQuestionId, y as generateSectionId, z as moveOption, A as moveQuestion, C as moveSection, E as removeOption, G as removeQuestion, H as removeSection, I as squaredrDarkPreset, J as updateOption, K as updateQuestion, L as updateSection, N as useBuilderState, O as useBuilderTheme, R as useDragDrop, T as useUndoRedo } from './index-nvIvXlmc.js';
3
+ export { B as BuilderState, a as BuilderStateHook, D as DEFAULT_PALETTE, b as DEFAULT_SCHEMA, c as DragItem, d as DropTarget, F as FormBuilder, e as FormBuilderPreviewProps, f as FormBuilderProps, g as FormBuilderTemplate, h as FormBuilderTheme, i as FormBuilderThemeProvider, M as MutationAction, P as PaletteCategory, j as PropertyPanelTab, Q as QUESTION_TYPE_INFO, k as QuestionTypeCategory, l as QuestionTypeInfo, S as SelectedItem, U as UndoRedoState, m as addOption, n as addQuestion, o as addSection, p as cleanPreset, q as cn, r as duplicateQuestion, s as duplicateSection, t as findQuestion, u as findSection, v as generateId, w as generateOptionId, x as generateQuestionId, y as generateSectionId, z as moveOption, A as moveQuestion, C as moveSection, E as removeOption, G as removeQuestion, H as removeSection, I as squaredrDarkPreset, J as updateOption, K as updateQuestion, L as updateSection, N as useBuilderState, O as useBuilderTheme, R as useDragDrop, T as useUndoRedo } from './index-BHJ4mqHP.js';
4
+ import { FieldComponent, FieldProps } from '@squaredr/fieldcraft-react';
4
5
  export { ResponseField, ResponseViewer, ResponseViewerProps, ViewMode } from './response-viewer/index.js';
5
6
  export { P as PREVIEW_SCHEMA, T as ThemeEditor, a as ThemeEditorInner, b as ThemeEditorProps } from './preview-schema-DFvV4y6J.js';
6
7
  import '@squaredr/fieldcraft-core';
7
- import '@squaredr/fieldcraft-react';
8
8
  import 'clsx';
9
9
  import '@dnd-kit/core';
10
10
 
@@ -56,4 +56,30 @@ declare function UnlicensedOverlay({ featureName, reason, children }: Unlicensed
56
56
  */
57
57
  declare function isProductionEnvironment(): boolean;
58
58
 
59
- export { FieldCraftProProvider, type LicenseContext, type LicenseStatus, UnlicensedOverlay, isProductionEnvironment, requireLicense, useLicense, validateLicense };
59
+ /**
60
+ * Pro Payment Field — full Stripe integration with dual-mode support.
61
+ *
62
+ * Resolution order for getting clientSecret (first match wins):
63
+ * 1. `customProps.clientSecret` — direct mode (simplest)
64
+ * 2. `customProps.onCreatePaymentIntent` callback — Pro dev mode
65
+ * 3. `config.serverUrl` — SaaS mode (POST to create intent)
66
+ * 4. Nothing — show setup message
67
+ *
68
+ * Requires `@squaredr/paykit-react` and `@squaredr/paykit-stripe/client` as peer deps.
69
+ */
70
+ declare function ProPaymentField(props: FieldProps): react_jsx_runtime.JSX.Element;
71
+
72
+ /**
73
+ * PRO_FIELD_OVERRIDES registry — maps field types to Pro-enhanced components.
74
+ * Pass this to FormEngineRenderer's `components` prop to enable Pro payment:
75
+ *
76
+ * ```tsx
77
+ * import { PRO_FIELD_OVERRIDES } from "@squaredr/fieldcraft-pro";
78
+ * <FormEngineRenderer schema={schema} components={PRO_FIELD_OVERRIDES} />
79
+ * ```
80
+ */
81
+ declare const PRO_FIELD_OVERRIDES: {
82
+ readonly payment: FieldComponent;
83
+ };
84
+
85
+ export { FieldCraftProProvider, type LicenseContext, type LicenseStatus, PRO_FIELD_OVERRIDES, ProPaymentField, UnlicensedOverlay, isProductionEnvironment, requireLicense, useLicense, validateLicense };
package/dist/index.js CHANGED
@@ -1032,6 +1032,14 @@ var QUESTION_TYPE_INFO = {
1032
1032
  icon: "Phone",
1033
1033
  description: "US phone number input"
1034
1034
  },
1035
+ phone_international: {
1036
+ type: "phone_international",
1037
+ label: "Intl Phone",
1038
+ category: "text",
1039
+ icon: "Globe2",
1040
+ description: "Phone with country code",
1041
+ defaultConfig: { type: "phone_international", defaultCountry: "US" }
1042
+ },
1035
1043
  url: {
1036
1044
  type: "url",
1037
1045
  label: "URL",
@@ -1125,6 +1133,14 @@ var QUESTION_TYPE_INFO = {
1125
1133
  requiresOptions: true,
1126
1134
  defaultConfig: { type: "ranking", items: [] }
1127
1135
  },
1136
+ country_select: {
1137
+ type: "country_select",
1138
+ label: "Country",
1139
+ category: "selection",
1140
+ icon: "Globe",
1141
+ description: "Country dropdown with search",
1142
+ defaultConfig: { type: "country_select" }
1143
+ },
1128
1144
  // ── Date/Time ──
1129
1145
  date: {
1130
1146
  type: "date",
@@ -1176,6 +1192,14 @@ var QUESTION_TYPE_INFO = {
1176
1192
  description: "Canvas signature pad",
1177
1193
  defaultConfig: { type: "signature" }
1178
1194
  },
1195
+ image_capture: {
1196
+ type: "image_capture",
1197
+ label: "Camera",
1198
+ category: "media",
1199
+ icon: "Camera",
1200
+ description: "Capture photo from camera",
1201
+ defaultConfig: { type: "image_capture", allowGallery: true }
1202
+ },
1179
1203
  date_range: {
1180
1204
  type: "date_range",
1181
1205
  label: "Date Range",
@@ -1184,6 +1208,14 @@ var QUESTION_TYPE_INFO = {
1184
1208
  description: "Start and end date picker",
1185
1209
  defaultConfig: { type: "date_range" }
1186
1210
  },
1211
+ appointment: {
1212
+ type: "appointment",
1213
+ label: "Appointment",
1214
+ category: "datetime",
1215
+ icon: "CalendarCheck",
1216
+ description: "Date & time slot booking",
1217
+ defaultConfig: { type: "appointment", duration: 30 }
1218
+ },
1187
1219
  // ── Advanced ──
1188
1220
  repeater: {
1189
1221
  type: "repeater",
@@ -1255,6 +1287,14 @@ var QUESTION_TYPE_INFO = {
1255
1287
  description: "Hidden value from URL or static",
1256
1288
  defaultConfig: { type: "hidden", source: "static" }
1257
1289
  },
1290
+ payment: {
1291
+ type: "payment",
1292
+ label: "Payment",
1293
+ category: "advanced",
1294
+ icon: "CreditCard",
1295
+ description: "Collect payment via Stripe",
1296
+ defaultConfig: { type: "payment", provider: "stripe", publicKey: "", currency: "USD" }
1297
+ },
1258
1298
  // ── Structural ──
1259
1299
  section_header: {
1260
1300
  type: "section_header",
@@ -1359,7 +1399,7 @@ var DEFAULT_PALETTE = [
1359
1399
  {
1360
1400
  category: "text",
1361
1401
  label: "Text Input",
1362
- types: ["short_text", "long_text", "email", "phone", "url", "legal_name", "address"]
1402
+ types: ["short_text", "long_text", "email", "phone", "phone_international", "url", "legal_name", "address"]
1363
1403
  },
1364
1404
  {
1365
1405
  category: "numeric",
@@ -1369,17 +1409,17 @@ var DEFAULT_PALETTE = [
1369
1409
  {
1370
1410
  category: "selection",
1371
1411
  label: "Selection",
1372
- types: ["single_select", "multi_select", "dropdown", "boolean", "ranking"]
1412
+ types: ["single_select", "multi_select", "dropdown", "boolean", "ranking", "country_select"]
1373
1413
  },
1374
1414
  {
1375
1415
  category: "datetime",
1376
1416
  label: "Date & Time",
1377
- types: ["date", "time", "date_range"]
1417
+ types: ["date", "time", "date_range", "appointment"]
1378
1418
  },
1379
1419
  {
1380
1420
  category: "media",
1381
1421
  label: "Media",
1382
- types: ["file_upload", "signature"]
1422
+ types: ["file_upload", "signature", "image_capture"]
1383
1423
  },
1384
1424
  {
1385
1425
  category: "content",
@@ -1394,7 +1434,7 @@ var DEFAULT_PALETTE = [
1394
1434
  {
1395
1435
  category: "advanced",
1396
1436
  label: "Advanced",
1397
- types: ["repeater", "likert", "scoring", "matrix", "calculated", "hidden"]
1437
+ types: ["repeater", "likert", "scoring", "matrix", "calculated", "hidden", "payment"]
1398
1438
  }
1399
1439
  ];
1400
1440
 
@@ -5060,6 +5100,272 @@ var cleanPreset = {
5060
5100
  borderStrong: "#B9D1CF",
5061
5101
  textDim: "#6A7B85"
5062
5102
  };
5103
+ function formatCurrency(amount, currency) {
5104
+ if (amount == null) return "";
5105
+ try {
5106
+ return new Intl.NumberFormat(void 0, {
5107
+ style: "currency",
5108
+ currency: currency ?? "USD"
5109
+ }).format(amount);
5110
+ } catch {
5111
+ return `${currency ?? "USD"} ${amount.toFixed(2)}`;
5112
+ }
5113
+ }
5114
+ function ProPaymentField(props) {
5115
+ const { field, value, error, touched, disabled, readonly, onChange, onBlur, customProps } = props;
5116
+ const config = field.config;
5117
+ const current = value ?? { status: "pending" };
5118
+ const provider = config?.provider ?? "stripe";
5119
+ const publicKey = config?.publicKey;
5120
+ const amount = customProps?.amount ?? config?.amount;
5121
+ const currency = config?.currency ?? "USD";
5122
+ const directSecret = customProps?.clientSecret;
5123
+ const onCreateIntent = customProps?.onCreatePaymentIntent;
5124
+ const onPaymentComplete = customProps?.onPaymentComplete;
5125
+ const serverUrl = config?.serverUrl;
5126
+ const [clientSecret, setClientSecret] = react.useState(directSecret);
5127
+ const [intentLoading, setIntentLoading] = react.useState(false);
5128
+ const [intentError, setIntentError] = react.useState(null);
5129
+ const mode = directSecret ? "direct" : onCreateIntent ? "callback" : serverUrl ? "url" : "setup";
5130
+ react.useEffect(() => {
5131
+ if (directSecret) {
5132
+ setClientSecret(directSecret);
5133
+ return;
5134
+ }
5135
+ if (mode === "setup" || !amount || !publicKey) return;
5136
+ if (clientSecret) return;
5137
+ const fetchIntent = async () => {
5138
+ setIntentLoading(true);
5139
+ setIntentError(null);
5140
+ try {
5141
+ if (mode === "callback" && onCreateIntent) {
5142
+ const result = await onCreateIntent({ amount, currency, provider, metadata: { fieldId: field.id } });
5143
+ setClientSecret(result.clientSecret);
5144
+ } else if (mode === "url" && serverUrl) {
5145
+ const res = await fetch(serverUrl, {
5146
+ method: "POST",
5147
+ headers: { "Content-Type": "application/json" },
5148
+ body: JSON.stringify({ amount, currency, provider, metadata: { fieldId: field.id } })
5149
+ });
5150
+ if (!res.ok) throw new Error(`Server error (${res.status})`);
5151
+ const data = await res.json();
5152
+ setClientSecret(data.clientSecret);
5153
+ }
5154
+ } catch (err) {
5155
+ setIntentError(err instanceof Error ? err.message : "Failed to create payment intent");
5156
+ } finally {
5157
+ setIntentLoading(false);
5158
+ }
5159
+ };
5160
+ fetchIntent();
5161
+ }, [mode, amount, currency, provider, publicKey, directSecret, clientSecret, onCreateIntent, serverUrl, field.id]);
5162
+ const handleSuccess = (chargeId) => {
5163
+ const result = { status: "succeeded", chargeId };
5164
+ onChange(result);
5165
+ onPaymentComplete?.(result);
5166
+ onBlur();
5167
+ };
5168
+ const handleError = (message) => {
5169
+ const result = { status: "failed", error: message };
5170
+ onChange(result);
5171
+ onPaymentComplete?.(result);
5172
+ onBlur();
5173
+ };
5174
+ if (!publicKey) {
5175
+ return /* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.FieldWrapper, { field, error, touched, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg border-2 border-dashed border-input p-4 text-center", children: /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-muted-foreground", children: [
5176
+ "Payment field \u2014 configure a ",
5177
+ /* @__PURE__ */ jsxRuntime.jsx("code", { className: "bg-muted px-1 rounded text-xs", children: "publicKey" }),
5178
+ " in the field properties panel."
5179
+ ] }) }) });
5180
+ }
5181
+ if (provider !== "stripe") {
5182
+ return /* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.FieldWrapper, { field, error, touched, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg border border-input bg-muted/50 p-4", children: /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-muted-foreground", children: [
5183
+ 'Provider "',
5184
+ provider,
5185
+ '" \u2014 coming soon.'
5186
+ ] }) }) });
5187
+ }
5188
+ if (current.status === "succeeded") {
5189
+ return /* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.FieldWrapper, { field, error, touched, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-input p-4", children: [
5190
+ amount != null && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-muted-foreground mb-2", children: [
5191
+ formatCurrency(amount, currency),
5192
+ config?.description && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
5193
+ " \u2014 ",
5194
+ config.description
5195
+ ] })
5196
+ ] }),
5197
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-sm font-medium", style: { color: "var(--success, #22c55e)" }, children: [
5198
+ /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, width: 16, height: 16, children: /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "20 6 9 17 4 12" }) }),
5199
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
5200
+ "Payment successful",
5201
+ current.chargeId ? ` (${current.chargeId})` : ""
5202
+ ] })
5203
+ ] })
5204
+ ] }) });
5205
+ }
5206
+ if (current.status === "failed") {
5207
+ return /* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.FieldWrapper, { field, error, touched, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-destructive/50 p-4", children: [
5208
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-sm text-destructive font-medium", children: [
5209
+ /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, width: 16, height: 16, children: [
5210
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
5211
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
5212
+ ] }),
5213
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
5214
+ "Payment failed",
5215
+ current.error ? `: ${current.error}` : ""
5216
+ ] })
5217
+ ] }),
5218
+ /* @__PURE__ */ jsxRuntime.jsx(
5219
+ "button",
5220
+ {
5221
+ type: "button",
5222
+ className: "mt-2 text-xs text-primary hover:underline",
5223
+ onClick: () => {
5224
+ onChange({ status: "pending" });
5225
+ setClientSecret(void 0);
5226
+ },
5227
+ children: "Retry"
5228
+ }
5229
+ )
5230
+ ] }) });
5231
+ }
5232
+ if (intentLoading || mode !== "setup" && mode !== "direct" && !clientSecret) {
5233
+ return /* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.FieldWrapper, { field, error, touched, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-input p-4", children: [
5234
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-3", children: [
5235
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium", children: "Payment" }),
5236
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs bg-muted px-2 py-0.5 rounded", children: provider })
5237
+ ] }),
5238
+ amount != null && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-muted-foreground mb-3", children: [
5239
+ "Amount: ",
5240
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: formatCurrency(amount, currency) }),
5241
+ config?.description && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
5242
+ " \u2014 ",
5243
+ config.description
5244
+ ] })
5245
+ ] }),
5246
+ intentError ? /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
5247
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", children: intentError }),
5248
+ /* @__PURE__ */ jsxRuntime.jsx(
5249
+ "button",
5250
+ {
5251
+ type: "button",
5252
+ className: "mt-2 text-xs text-primary hover:underline",
5253
+ onClick: () => {
5254
+ setIntentError(null);
5255
+ setClientSecret(void 0);
5256
+ },
5257
+ children: "Retry"
5258
+ }
5259
+ )
5260
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
5261
+ /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "animate-spin size-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "10", strokeDasharray: "60", strokeDashoffset: "20" }) }),
5262
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Preparing payment..." })
5263
+ ] })
5264
+ ] }) });
5265
+ }
5266
+ if (!clientSecret) {
5267
+ const waitingForAmount = config?.amountField && !amount;
5268
+ return /* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.FieldWrapper, { field, error, touched, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-input p-4", children: [
5269
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-3", children: [
5270
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium", children: "Payment" }),
5271
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs bg-muted px-2 py-0.5 rounded", children: provider })
5272
+ ] }),
5273
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: waitingForAmount ? "Select an option above to proceed with payment." : "Provide a clientSecret via customProps, an onCreatePaymentIntent callback, or a serverUrl." })
5274
+ ] }) });
5275
+ }
5276
+ return /* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.FieldWrapper, { field, error, touched, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-input p-4", children: [
5277
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-3", children: [
5278
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium", children: "Payment" }),
5279
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs bg-muted px-2 py-0.5 rounded", children: provider })
5280
+ ] }),
5281
+ amount != null && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-muted-foreground mb-3", children: [
5282
+ "Amount: ",
5283
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: formatCurrency(amount, currency) }),
5284
+ config?.description && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
5285
+ " \u2014 ",
5286
+ config.description
5287
+ ] })
5288
+ ] }),
5289
+ /* @__PURE__ */ jsxRuntime.jsx(
5290
+ react.Suspense,
5291
+ {
5292
+ fallback: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-sm text-muted-foreground py-4", children: [
5293
+ /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "animate-spin size-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "10", strokeDasharray: "60", strokeDashoffset: "20" }) }),
5294
+ "Loading payment form..."
5295
+ ] }),
5296
+ children: /* @__PURE__ */ jsxRuntime.jsx(
5297
+ PayKitCheckout,
5298
+ {
5299
+ publicKey,
5300
+ clientSecret,
5301
+ amount,
5302
+ currency,
5303
+ disabled: disabled || readonly,
5304
+ onSuccess: handleSuccess,
5305
+ onError: handleError
5306
+ }
5307
+ )
5308
+ }
5309
+ )
5310
+ ] }) });
5311
+ }
5312
+ function PayKitCheckout({
5313
+ publicKey,
5314
+ clientSecret,
5315
+ amount,
5316
+ currency,
5317
+ disabled,
5318
+ onSuccess,
5319
+ onError
5320
+ }) {
5321
+ const [PayKit, setPayKit] = react.useState(null);
5322
+ const [loadError, setLoadError] = react.useState(null);
5323
+ react.useEffect(() => {
5324
+ let cancelled = false;
5325
+ Promise.all([
5326
+ // @ts-expect-error — optional peer dep, resolved at runtime
5327
+ import('@squaredr/paykit-react'),
5328
+ // @ts-expect-error — optional peer dep, resolved at runtime
5329
+ import('@squaredr/paykit-stripe/client')
5330
+ ]).then(([paykit, stripe]) => {
5331
+ if (cancelled) return;
5332
+ setPayKit({
5333
+ Provider: paykit.PayKitProvider,
5334
+ Form: paykit.CheckoutForm,
5335
+ adapter: new stripe.StripeClientAdapter(publicKey)
5336
+ });
5337
+ }).catch((err) => {
5338
+ if (cancelled) return;
5339
+ setLoadError(
5340
+ `Failed to load payment SDK. Ensure @squaredr/paykit-react and @squaredr/paykit-stripe are installed. (${err.message})`
5341
+ );
5342
+ });
5343
+ return () => {
5344
+ cancelled = true;
5345
+ };
5346
+ }, [publicKey]);
5347
+ if (loadError) {
5348
+ return /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", children: loadError });
5349
+ }
5350
+ if (!PayKit) {
5351
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-sm text-muted-foreground py-2", children: [
5352
+ /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "animate-spin size-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "10", strokeDasharray: "60", strokeDashoffset: "20" }) }),
5353
+ "Loading Stripe..."
5354
+ ] });
5355
+ }
5356
+ return /* @__PURE__ */ jsxRuntime.jsx(PayKit.Provider, { clientAdapter: PayKit.adapter, children: /* @__PURE__ */ jsxRuntime.jsx(
5357
+ PayKit.Form,
5358
+ {
5359
+ clientSecret,
5360
+ submitLabel: disabled ? "Payment disabled" : `Pay ${formatCurrency(amount, currency)}`,
5361
+ onSuccess: (result) => onSuccess(result.chargeId),
5362
+ onError: (err) => onError(err.message)
5363
+ }
5364
+ ) });
5365
+ }
5366
+ var PRO_FIELD_OVERRIDES = {
5367
+ payment: ProPaymentField
5368
+ };
5063
5369
 
5064
5370
  // src/response-viewer/clinical-display-data.ts
5065
5371
  var BODY_REGION_LABELS = {
@@ -8244,7 +8550,7 @@ var ThemeEditor = requireLicense(ThemeEditorInner, "ThemeEditor");
8244
8550
  // src/index.ts
8245
8551
  if (typeof globalThis !== "undefined" && typeof globalThis.process !== "undefined" && globalThis.process.env?.NODE_ENV !== "production") {
8246
8552
  const _fc_banner = `
8247
- %c FieldCraft Pro %c v1.4.0
8553
+ %c FieldCraft Pro %c v1.5.0
8248
8554
 
8249
8555
  %cForm Builder \xB7 Response Viewer \xB7 Theme Editor
8250
8556
 
@@ -8268,6 +8574,8 @@ exports.FieldCraftProProvider = FieldCraftProProvider;
8268
8574
  exports.FormBuilder = FormBuilder;
8269
8575
  exports.FormBuilderThemeProvider = FormBuilderThemeProvider;
8270
8576
  exports.PREVIEW_SCHEMA = PREVIEW_SCHEMA;
8577
+ exports.PRO_FIELD_OVERRIDES = PRO_FIELD_OVERRIDES;
8578
+ exports.ProPaymentField = ProPaymentField;
8271
8579
  exports.QUESTION_TYPE_INFO = QUESTION_TYPE_INFO;
8272
8580
  exports.ResponseViewer = ResponseViewer;
8273
8581
  exports.ThemeEditor = ThemeEditor;
package/dist/index.mjs CHANGED
@@ -1,13 +1,283 @@
1
- export { DEFAULT_PALETTE, DEFAULT_SCHEMA, FormBuilder, FormBuilderThemeProvider, QUESTION_TYPE_INFO, addOption, addQuestion, addSection, cleanPreset, duplicateQuestion, duplicateSection, findQuestion, findSection, generateId, generateOptionId, generateQuestionId, generateSectionId, moveOption, moveQuestion, moveSection, removeOption, removeQuestion, removeSection, squaredrDarkPreset, updateOption, updateQuestion, updateSection, useBuilderState, useBuilderTheme, useDragDrop, useUndoRedo } from './chunk-BYT2P3I6.mjs';
1
+ export { DEFAULT_PALETTE, DEFAULT_SCHEMA, FormBuilder, FormBuilderThemeProvider, QUESTION_TYPE_INFO, addOption, addQuestion, addSection, cleanPreset, duplicateQuestion, duplicateSection, findQuestion, findSection, generateId, generateOptionId, generateQuestionId, generateSectionId, moveOption, moveQuestion, moveSection, removeOption, removeQuestion, removeSection, squaredrDarkPreset, updateOption, updateQuestion, updateSection, useBuilderState, useBuilderTheme, useDragDrop, useUndoRedo } from './chunk-6LRUDBC7.mjs';
2
2
  export { ResponseViewer } from './chunk-BK4SMEW4.mjs';
3
3
  export { cn } from './chunk-QQ4JZGTD.mjs';
4
4
  export { PREVIEW_SCHEMA, ThemeEditor, ThemeEditorInner } from './chunk-22T5PY6L.mjs';
5
5
  export { FieldCraftProProvider, UnlicensedOverlay, isProductionEnvironment, requireLicense, useLicense, validateLicense } from './chunk-VECQKSWS.mjs';
6
+ import { useState, useEffect, Suspense } from 'react';
7
+ import { FieldWrapper } from '@squaredr/fieldcraft-react';
8
+ import { jsx, jsxs } from 'react/jsx-runtime';
9
+
10
+ function formatCurrency(amount, currency) {
11
+ if (amount == null) return "";
12
+ try {
13
+ return new Intl.NumberFormat(void 0, {
14
+ style: "currency",
15
+ currency: currency ?? "USD"
16
+ }).format(amount);
17
+ } catch {
18
+ return `${currency ?? "USD"} ${amount.toFixed(2)}`;
19
+ }
20
+ }
21
+ function ProPaymentField(props) {
22
+ const { field, value, error, touched, disabled, readonly, onChange, onBlur, customProps } = props;
23
+ const config = field.config;
24
+ const current = value ?? { status: "pending" };
25
+ const provider = config?.provider ?? "stripe";
26
+ const publicKey = config?.publicKey;
27
+ const amount = customProps?.amount ?? config?.amount;
28
+ const currency = config?.currency ?? "USD";
29
+ const directSecret = customProps?.clientSecret;
30
+ const onCreateIntent = customProps?.onCreatePaymentIntent;
31
+ const onPaymentComplete = customProps?.onPaymentComplete;
32
+ const serverUrl = config?.serverUrl;
33
+ const [clientSecret, setClientSecret] = useState(directSecret);
34
+ const [intentLoading, setIntentLoading] = useState(false);
35
+ const [intentError, setIntentError] = useState(null);
36
+ const mode = directSecret ? "direct" : onCreateIntent ? "callback" : serverUrl ? "url" : "setup";
37
+ useEffect(() => {
38
+ if (directSecret) {
39
+ setClientSecret(directSecret);
40
+ return;
41
+ }
42
+ if (mode === "setup" || !amount || !publicKey) return;
43
+ if (clientSecret) return;
44
+ const fetchIntent = async () => {
45
+ setIntentLoading(true);
46
+ setIntentError(null);
47
+ try {
48
+ if (mode === "callback" && onCreateIntent) {
49
+ const result = await onCreateIntent({ amount, currency, provider, metadata: { fieldId: field.id } });
50
+ setClientSecret(result.clientSecret);
51
+ } else if (mode === "url" && serverUrl) {
52
+ const res = await fetch(serverUrl, {
53
+ method: "POST",
54
+ headers: { "Content-Type": "application/json" },
55
+ body: JSON.stringify({ amount, currency, provider, metadata: { fieldId: field.id } })
56
+ });
57
+ if (!res.ok) throw new Error(`Server error (${res.status})`);
58
+ const data = await res.json();
59
+ setClientSecret(data.clientSecret);
60
+ }
61
+ } catch (err) {
62
+ setIntentError(err instanceof Error ? err.message : "Failed to create payment intent");
63
+ } finally {
64
+ setIntentLoading(false);
65
+ }
66
+ };
67
+ fetchIntent();
68
+ }, [mode, amount, currency, provider, publicKey, directSecret, clientSecret, onCreateIntent, serverUrl, field.id]);
69
+ const handleSuccess = (chargeId) => {
70
+ const result = { status: "succeeded", chargeId };
71
+ onChange(result);
72
+ onPaymentComplete?.(result);
73
+ onBlur();
74
+ };
75
+ const handleError = (message) => {
76
+ const result = { status: "failed", error: message };
77
+ onChange(result);
78
+ onPaymentComplete?.(result);
79
+ onBlur();
80
+ };
81
+ if (!publicKey) {
82
+ return /* @__PURE__ */ jsx(FieldWrapper, { field, error, touched, children: /* @__PURE__ */ jsx("div", { className: "rounded-lg border-2 border-dashed border-input p-4 text-center", children: /* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground", children: [
83
+ "Payment field \u2014 configure a ",
84
+ /* @__PURE__ */ jsx("code", { className: "bg-muted px-1 rounded text-xs", children: "publicKey" }),
85
+ " in the field properties panel."
86
+ ] }) }) });
87
+ }
88
+ if (provider !== "stripe") {
89
+ return /* @__PURE__ */ jsx(FieldWrapper, { field, error, touched, children: /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-input bg-muted/50 p-4", children: /* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground", children: [
90
+ 'Provider "',
91
+ provider,
92
+ '" \u2014 coming soon.'
93
+ ] }) }) });
94
+ }
95
+ if (current.status === "succeeded") {
96
+ return /* @__PURE__ */ jsx(FieldWrapper, { field, error, touched, children: /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-input p-4", children: [
97
+ amount != null && /* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground mb-2", children: [
98
+ formatCurrency(amount, currency),
99
+ config?.description && /* @__PURE__ */ jsxs("span", { children: [
100
+ " \u2014 ",
101
+ config.description
102
+ ] })
103
+ ] }),
104
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm font-medium", style: { color: "var(--success, #22c55e)" }, children: [
105
+ /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, width: 16, height: 16, children: /* @__PURE__ */ jsx("polyline", { points: "20 6 9 17 4 12" }) }),
106
+ /* @__PURE__ */ jsxs("span", { children: [
107
+ "Payment successful",
108
+ current.chargeId ? ` (${current.chargeId})` : ""
109
+ ] })
110
+ ] })
111
+ ] }) });
112
+ }
113
+ if (current.status === "failed") {
114
+ return /* @__PURE__ */ jsx(FieldWrapper, { field, error, touched, children: /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-destructive/50 p-4", children: [
115
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm text-destructive font-medium", children: [
116
+ /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, width: 16, height: 16, children: [
117
+ /* @__PURE__ */ jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
118
+ /* @__PURE__ */ jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
119
+ ] }),
120
+ /* @__PURE__ */ jsxs("span", { children: [
121
+ "Payment failed",
122
+ current.error ? `: ${current.error}` : ""
123
+ ] })
124
+ ] }),
125
+ /* @__PURE__ */ jsx(
126
+ "button",
127
+ {
128
+ type: "button",
129
+ className: "mt-2 text-xs text-primary hover:underline",
130
+ onClick: () => {
131
+ onChange({ status: "pending" });
132
+ setClientSecret(void 0);
133
+ },
134
+ children: "Retry"
135
+ }
136
+ )
137
+ ] }) });
138
+ }
139
+ if (intentLoading || mode !== "setup" && mode !== "direct" && !clientSecret) {
140
+ return /* @__PURE__ */ jsx(FieldWrapper, { field, error, touched, children: /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-input p-4", children: [
141
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-3", children: [
142
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: "Payment" }),
143
+ /* @__PURE__ */ jsx("span", { className: "text-xs bg-muted px-2 py-0.5 rounded", children: provider })
144
+ ] }),
145
+ amount != null && /* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground mb-3", children: [
146
+ "Amount: ",
147
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: formatCurrency(amount, currency) }),
148
+ config?.description && /* @__PURE__ */ jsxs("span", { children: [
149
+ " \u2014 ",
150
+ config.description
151
+ ] })
152
+ ] }),
153
+ intentError ? /* @__PURE__ */ jsxs("div", { children: [
154
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: intentError }),
155
+ /* @__PURE__ */ jsx(
156
+ "button",
157
+ {
158
+ type: "button",
159
+ className: "mt-2 text-xs text-primary hover:underline",
160
+ onClick: () => {
161
+ setIntentError(null);
162
+ setClientSecret(void 0);
163
+ },
164
+ children: "Retry"
165
+ }
166
+ )
167
+ ] }) : /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
168
+ /* @__PURE__ */ jsx("svg", { className: "animate-spin size-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10", strokeDasharray: "60", strokeDashoffset: "20" }) }),
169
+ /* @__PURE__ */ jsx("span", { children: "Preparing payment..." })
170
+ ] })
171
+ ] }) });
172
+ }
173
+ if (!clientSecret) {
174
+ const waitingForAmount = config?.amountField && !amount;
175
+ return /* @__PURE__ */ jsx(FieldWrapper, { field, error, touched, children: /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-input p-4", children: [
176
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-3", children: [
177
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: "Payment" }),
178
+ /* @__PURE__ */ jsx("span", { className: "text-xs bg-muted px-2 py-0.5 rounded", children: provider })
179
+ ] }),
180
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: waitingForAmount ? "Select an option above to proceed with payment." : "Provide a clientSecret via customProps, an onCreatePaymentIntent callback, or a serverUrl." })
181
+ ] }) });
182
+ }
183
+ return /* @__PURE__ */ jsx(FieldWrapper, { field, error, touched, children: /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-input p-4", children: [
184
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-3", children: [
185
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: "Payment" }),
186
+ /* @__PURE__ */ jsx("span", { className: "text-xs bg-muted px-2 py-0.5 rounded", children: provider })
187
+ ] }),
188
+ amount != null && /* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground mb-3", children: [
189
+ "Amount: ",
190
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: formatCurrency(amount, currency) }),
191
+ config?.description && /* @__PURE__ */ jsxs("span", { children: [
192
+ " \u2014 ",
193
+ config.description
194
+ ] })
195
+ ] }),
196
+ /* @__PURE__ */ jsx(
197
+ Suspense,
198
+ {
199
+ fallback: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm text-muted-foreground py-4", children: [
200
+ /* @__PURE__ */ jsx("svg", { className: "animate-spin size-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10", strokeDasharray: "60", strokeDashoffset: "20" }) }),
201
+ "Loading payment form..."
202
+ ] }),
203
+ children: /* @__PURE__ */ jsx(
204
+ PayKitCheckout,
205
+ {
206
+ publicKey,
207
+ clientSecret,
208
+ amount,
209
+ currency,
210
+ disabled: disabled || readonly,
211
+ onSuccess: handleSuccess,
212
+ onError: handleError
213
+ }
214
+ )
215
+ }
216
+ )
217
+ ] }) });
218
+ }
219
+ function PayKitCheckout({
220
+ publicKey,
221
+ clientSecret,
222
+ amount,
223
+ currency,
224
+ disabled,
225
+ onSuccess,
226
+ onError
227
+ }) {
228
+ const [PayKit, setPayKit] = useState(null);
229
+ const [loadError, setLoadError] = useState(null);
230
+ useEffect(() => {
231
+ let cancelled = false;
232
+ Promise.all([
233
+ // @ts-expect-error — optional peer dep, resolved at runtime
234
+ import('@squaredr/paykit-react'),
235
+ // @ts-expect-error — optional peer dep, resolved at runtime
236
+ import('@squaredr/paykit-stripe/client')
237
+ ]).then(([paykit, stripe]) => {
238
+ if (cancelled) return;
239
+ setPayKit({
240
+ Provider: paykit.PayKitProvider,
241
+ Form: paykit.CheckoutForm,
242
+ adapter: new stripe.StripeClientAdapter(publicKey)
243
+ });
244
+ }).catch((err) => {
245
+ if (cancelled) return;
246
+ setLoadError(
247
+ `Failed to load payment SDK. Ensure @squaredr/paykit-react and @squaredr/paykit-stripe are installed. (${err.message})`
248
+ );
249
+ });
250
+ return () => {
251
+ cancelled = true;
252
+ };
253
+ }, [publicKey]);
254
+ if (loadError) {
255
+ return /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: loadError });
256
+ }
257
+ if (!PayKit) {
258
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm text-muted-foreground py-2", children: [
259
+ /* @__PURE__ */ jsx("svg", { className: "animate-spin size-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10", strokeDasharray: "60", strokeDashoffset: "20" }) }),
260
+ "Loading Stripe..."
261
+ ] });
262
+ }
263
+ return /* @__PURE__ */ jsx(PayKit.Provider, { clientAdapter: PayKit.adapter, children: /* @__PURE__ */ jsx(
264
+ PayKit.Form,
265
+ {
266
+ clientSecret,
267
+ submitLabel: disabled ? "Payment disabled" : `Pay ${formatCurrency(amount, currency)}`,
268
+ onSuccess: (result) => onSuccess(result.chargeId),
269
+ onError: (err) => onError(err.message)
270
+ }
271
+ ) });
272
+ }
273
+ var PRO_FIELD_OVERRIDES = {
274
+ payment: ProPaymentField
275
+ };
6
276
 
7
277
  // src/index.ts
8
278
  if (typeof globalThis !== "undefined" && typeof globalThis.process !== "undefined" && globalThis.process.env?.NODE_ENV !== "production") {
9
279
  const _fc_banner = `
10
- %c FieldCraft Pro %c v1.4.0
280
+ %c FieldCraft Pro %c v1.5.0
11
281
 
12
282
  %cForm Builder \xB7 Response Viewer \xB7 Theme Editor
13
283
 
@@ -24,3 +294,5 @@ Need a license? \u2192 https://squaredr.tech/products/fieldcraft/admin-pro#prici
24
294
  "color:#6b7280"
25
295
  );
26
296
  }
297
+
298
+ export { PRO_FIELD_OVERRIDES, ProPaymentField };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@squaredr/fieldcraft-pro",
3
- "version": "1.4.0",
3
+ "version": "1.5.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.5.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.5.0",
75
85
  "@tailwindcss/cli": "^4.3.0",
76
86
  "@types/react": "^19.2.14",
77
87
  "@types/react-dom": "^19.2.3",