@cohiva/support-widget 1.1.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -39,6 +39,7 @@ module.exports = __toCommonJS(index_exports);
39
39
 
40
40
  // src/components/SupportWidget.tsx
41
41
  var import_react2 = require("react");
42
+ var import_lucide_react = require("lucide-react");
42
43
 
43
44
  // src/adapters/centralApi.ts
44
45
  function createCentralFeedbackClient(options) {
@@ -724,7 +725,7 @@ function buildFeedbackDescription(formData, diagnostics) {
724
725
  }
725
726
 
726
727
  // src/components/SupportWidget.tsx
727
- var import_widget = require("./widget-TTYCIVNC.css");
728
+ var import_widget = require("./widget-E4MWTWY5.css");
728
729
 
729
730
  // src/utils/classNames.ts
730
731
  function classNames(...items) {
@@ -733,6 +734,12 @@ function classNames(...items) {
733
734
 
734
735
  // src/components/SupportWidget.tsx
735
736
  var import_jsx_runtime = require("react/jsx-runtime");
737
+ var typeIconMap = {
738
+ bug: { icon: import_lucide_react.Bug, color: "#ef4444" },
739
+ feature: { icon: import_lucide_react.Lightbulb, color: "#f59e0b" },
740
+ feedback: { icon: import_lucide_react.MessageCircle, color: "#3b82f6" },
741
+ improvement: { icon: import_lucide_react.Wrench, color: "#8b5cf6" }
742
+ };
736
743
  function labelForType(type) {
737
744
  return feedbackTypes.find((item) => item.value === type)?.label || type;
738
745
  }
@@ -881,7 +888,7 @@ function SupportWidget({ config, isVisible = true, onSuccess, onError, onSubmit
881
888
  ]
882
889
  }
883
890
  ),
884
- isOpen ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "sw-overlay", onClick: handleClose, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "sw-modal-wrapper", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
891
+ isOpen ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "sw-overlay", onClick: handleClose, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
885
892
  "div",
886
893
  {
887
894
  "aria-describedby": "support-widget-description",
@@ -892,7 +899,8 @@ function SupportWidget({ config, isVisible = true, onSuccess, onError, onSubmit
892
899
  children: [
893
900
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { "aria-label": "Close", className: "sw-close", onClick: handleClose, type: "button", children: "x" }),
894
901
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "sw-sr-only", id: "support-widget-description", children: "Support ticket dialog" }),
895
- isSubmitted ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "sw-success", "data-testid": "feedback-success-screen", children: [
902
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "sw-modal-body", children: isSubmitted ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "sw-success", "data-testid": "feedback-success-screen", children: [
903
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.CheckCircle, { "aria-hidden": "true", className: "sw-success-icon", color: "#0f766e", size: 48 }),
896
904
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { children: "Thank You!" }),
897
905
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: "Your feedback helps us improve the product." }),
898
906
  submitResult?.issue_number || submitResult?.issue_url ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { "data-testid": "feedback-success-issue-link", children: [
@@ -904,23 +912,31 @@ function SupportWidget({ config, isVisible = true, onSuccess, onError, onSubmit
904
912
  ] }) : null
905
913
  ] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
906
914
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("header", { className: "sw-header", children: [
907
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { children: step === 1 ? "Send Feedback" : selectedTypeConfig?.label || "Support Ticket" }),
908
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: step === 1 ? "What kind of support ticket would you like to submit?" : selectedTypeConfig?.description })
915
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { children: step === 1 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
916
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.MessageSquarePlus, { "aria-hidden": "true", className: "sw-header-icon", size: 22 }),
917
+ " Send Feedback"
918
+ ] }) : selectedTypeConfig?.label || "Support Ticket" }),
919
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: step === 1 ? "Help us improve Cohiva by sharing your experience" : selectedTypeConfig?.description })
909
920
  ] }),
910
- step === 1 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "sw-type-grid", children: feedbackTypes.map((typeConfig) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
911
- "button",
912
- {
913
- className: "sw-type-card",
914
- "data-testid": `feedback-type-${typeConfig.value}`,
915
- onClick: () => handleTypeSelect(typeConfig.value),
916
- type: "button",
917
- children: [
918
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: typeConfig.label }),
919
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: typeConfig.description })
920
- ]
921
- },
922
- typeConfig.value
923
- )) }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("form", { className: "sw-form", onSubmit: handleSubmit, children: [
921
+ step === 1 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "sw-type-grid", children: feedbackTypes.map((typeConfig) => {
922
+ const entry = typeIconMap[typeConfig.value];
923
+ const Icon = entry?.icon;
924
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
925
+ "button",
926
+ {
927
+ className: "sw-type-card",
928
+ "data-testid": `feedback-type-${typeConfig.value}`,
929
+ onClick: () => handleTypeSelect(typeConfig.value),
930
+ type: "button",
931
+ children: [
932
+ Icon ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { "aria-hidden": "true", className: "sw-type-card-icon", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { color: entry.color, size: 36, strokeWidth: 1.5 }) }) : null,
933
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: typeConfig.label }),
934
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: typeConfig.description })
935
+ ]
936
+ },
937
+ typeConfig.value
938
+ );
939
+ }) }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("form", { className: "sw-form", onSubmit: handleSubmit, children: [
924
940
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { htmlFor: "support-title", children: "Title *" }),
925
941
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
926
942
  "input",
@@ -1020,13 +1036,16 @@ function SupportWidget({ config, isVisible = true, onSuccess, onError, onSubmit
1020
1036
  !validation.valid ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "sw-error", children: validation.description }) : null,
1021
1037
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "sw-actions", children: [
1022
1038
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { onClick: () => setStep(1), type: "button", children: "Back" }),
1023
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { disabled: isSubmitting || !validation.valid, type: "submit", children: isSubmitting ? "Submitting..." : "Submit" })
1039
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { disabled: isSubmitting || !validation.valid, type: "submit", children: isSubmitting ? "Submitting..." : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
1040
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Send, { "aria-hidden": "true", size: 14, style: { marginRight: "0.35rem", verticalAlign: "middle" } }),
1041
+ "Submit"
1042
+ ] }) })
1024
1043
  ] })
1025
1044
  ] })
1026
- ] })
1045
+ ] }) })
1027
1046
  ]
1028
1047
  }
1029
- ) }) }) : null
1048
+ ) }) : null
1030
1049
  ] });
1031
1050
  }
1032
1051
  // Annotate the CommonJS export names for ESM import in node:
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  // src/components/SupportWidget.tsx
2
2
  import { useCallback, useEffect as useEffect2, useMemo, useState } from "react";
3
+ import { Bug, CheckCircle, Lightbulb, MessageCircle, MessageSquarePlus, Send, Wrench } from "lucide-react";
3
4
 
4
5
  // src/adapters/centralApi.ts
5
6
  function createCentralFeedbackClient(options) {
@@ -685,7 +686,7 @@ function buildFeedbackDescription(formData, diagnostics) {
685
686
  }
686
687
 
687
688
  // src/components/SupportWidget.tsx
688
- import "./widget-TTYCIVNC.css";
689
+ import "./widget-E4MWTWY5.css";
689
690
 
690
691
  // src/utils/classNames.ts
691
692
  function classNames(...items) {
@@ -694,6 +695,12 @@ function classNames(...items) {
694
695
 
695
696
  // src/components/SupportWidget.tsx
696
697
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
698
+ var typeIconMap = {
699
+ bug: { icon: Bug, color: "#ef4444" },
700
+ feature: { icon: Lightbulb, color: "#f59e0b" },
701
+ feedback: { icon: MessageCircle, color: "#3b82f6" },
702
+ improvement: { icon: Wrench, color: "#8b5cf6" }
703
+ };
697
704
  function labelForType(type) {
698
705
  return feedbackTypes.find((item) => item.value === type)?.label || type;
699
706
  }
@@ -842,7 +849,7 @@ function SupportWidget({ config, isVisible = true, onSuccess, onError, onSubmit
842
849
  ]
843
850
  }
844
851
  ),
845
- isOpen ? /* @__PURE__ */ jsx("div", { className: "sw-overlay", onClick: handleClose, children: /* @__PURE__ */ jsx("div", { className: "sw-modal-wrapper", children: /* @__PURE__ */ jsxs(
852
+ isOpen ? /* @__PURE__ */ jsx("div", { className: "sw-overlay", onClick: handleClose, children: /* @__PURE__ */ jsxs(
846
853
  "div",
847
854
  {
848
855
  "aria-describedby": "support-widget-description",
@@ -853,7 +860,8 @@ function SupportWidget({ config, isVisible = true, onSuccess, onError, onSubmit
853
860
  children: [
854
861
  /* @__PURE__ */ jsx("button", { "aria-label": "Close", className: "sw-close", onClick: handleClose, type: "button", children: "x" }),
855
862
  /* @__PURE__ */ jsx("p", { className: "sw-sr-only", id: "support-widget-description", children: "Support ticket dialog" }),
856
- isSubmitted ? /* @__PURE__ */ jsxs("div", { className: "sw-success", "data-testid": "feedback-success-screen", children: [
863
+ /* @__PURE__ */ jsx("div", { className: "sw-modal-body", children: isSubmitted ? /* @__PURE__ */ jsxs("div", { className: "sw-success", "data-testid": "feedback-success-screen", children: [
864
+ /* @__PURE__ */ jsx(CheckCircle, { "aria-hidden": "true", className: "sw-success-icon", color: "#0f766e", size: 48 }),
857
865
  /* @__PURE__ */ jsx("h2", { children: "Thank You!" }),
858
866
  /* @__PURE__ */ jsx("p", { children: "Your feedback helps us improve the product." }),
859
867
  submitResult?.issue_number || submitResult?.issue_url ? /* @__PURE__ */ jsxs("p", { "data-testid": "feedback-success-issue-link", children: [
@@ -865,23 +873,31 @@ function SupportWidget({ config, isVisible = true, onSuccess, onError, onSubmit
865
873
  ] }) : null
866
874
  ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
867
875
  /* @__PURE__ */ jsxs("header", { className: "sw-header", children: [
868
- /* @__PURE__ */ jsx("h2", { children: step === 1 ? "Send Feedback" : selectedTypeConfig?.label || "Support Ticket" }),
869
- /* @__PURE__ */ jsx("p", { children: step === 1 ? "What kind of support ticket would you like to submit?" : selectedTypeConfig?.description })
876
+ /* @__PURE__ */ jsx("h2", { children: step === 1 ? /* @__PURE__ */ jsxs(Fragment, { children: [
877
+ /* @__PURE__ */ jsx(MessageSquarePlus, { "aria-hidden": "true", className: "sw-header-icon", size: 22 }),
878
+ " Send Feedback"
879
+ ] }) : selectedTypeConfig?.label || "Support Ticket" }),
880
+ /* @__PURE__ */ jsx("p", { children: step === 1 ? "Help us improve Cohiva by sharing your experience" : selectedTypeConfig?.description })
870
881
  ] }),
871
- step === 1 ? /* @__PURE__ */ jsx("div", { className: "sw-type-grid", children: feedbackTypes.map((typeConfig) => /* @__PURE__ */ jsxs(
872
- "button",
873
- {
874
- className: "sw-type-card",
875
- "data-testid": `feedback-type-${typeConfig.value}`,
876
- onClick: () => handleTypeSelect(typeConfig.value),
877
- type: "button",
878
- children: [
879
- /* @__PURE__ */ jsx("strong", { children: typeConfig.label }),
880
- /* @__PURE__ */ jsx("span", { children: typeConfig.description })
881
- ]
882
- },
883
- typeConfig.value
884
- )) }) : /* @__PURE__ */ jsxs("form", { className: "sw-form", onSubmit: handleSubmit, children: [
882
+ step === 1 ? /* @__PURE__ */ jsx("div", { className: "sw-type-grid", children: feedbackTypes.map((typeConfig) => {
883
+ const entry = typeIconMap[typeConfig.value];
884
+ const Icon = entry?.icon;
885
+ return /* @__PURE__ */ jsxs(
886
+ "button",
887
+ {
888
+ className: "sw-type-card",
889
+ "data-testid": `feedback-type-${typeConfig.value}`,
890
+ onClick: () => handleTypeSelect(typeConfig.value),
891
+ type: "button",
892
+ children: [
893
+ Icon ? /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "sw-type-card-icon", children: /* @__PURE__ */ jsx(Icon, { color: entry.color, size: 36, strokeWidth: 1.5 }) }) : null,
894
+ /* @__PURE__ */ jsx("strong", { children: typeConfig.label }),
895
+ /* @__PURE__ */ jsx("span", { children: typeConfig.description })
896
+ ]
897
+ },
898
+ typeConfig.value
899
+ );
900
+ }) }) : /* @__PURE__ */ jsxs("form", { className: "sw-form", onSubmit: handleSubmit, children: [
885
901
  /* @__PURE__ */ jsx("label", { htmlFor: "support-title", children: "Title *" }),
886
902
  /* @__PURE__ */ jsx(
887
903
  "input",
@@ -981,13 +997,16 @@ function SupportWidget({ config, isVisible = true, onSuccess, onError, onSubmit
981
997
  !validation.valid ? /* @__PURE__ */ jsx("p", { className: "sw-error", children: validation.description }) : null,
982
998
  /* @__PURE__ */ jsxs("div", { className: "sw-actions", children: [
983
999
  /* @__PURE__ */ jsx("button", { onClick: () => setStep(1), type: "button", children: "Back" }),
984
- /* @__PURE__ */ jsx("button", { disabled: isSubmitting || !validation.valid, type: "submit", children: isSubmitting ? "Submitting..." : "Submit" })
1000
+ /* @__PURE__ */ jsx("button", { disabled: isSubmitting || !validation.valid, type: "submit", children: isSubmitting ? "Submitting..." : /* @__PURE__ */ jsxs(Fragment, { children: [
1001
+ /* @__PURE__ */ jsx(Send, { "aria-hidden": "true", size: 14, style: { marginRight: "0.35rem", verticalAlign: "middle" } }),
1002
+ "Submit"
1003
+ ] }) })
985
1004
  ] })
986
1005
  ] })
987
- ] })
1006
+ ] }) })
988
1007
  ]
989
1008
  }
990
- ) }) }) : null
1009
+ ) }) : null
991
1010
  ] });
992
1011
  }
993
1012
  export {
package/dist/styles.css CHANGED
@@ -61,12 +61,7 @@
61
61
  inset: 0;
62
62
  z-index: 1100;
63
63
  background: rgba(2, 6, 23, 0.7);
64
- overflow-y: auto;
65
- }
66
-
67
- .sw-modal-wrapper {
68
64
  display: flex;
69
- min-height: 100%;
70
65
  align-items: center;
71
66
  justify-content: center;
72
67
  padding: 1rem;
@@ -74,15 +69,25 @@
74
69
 
75
70
  .sw-modal {
76
71
  width: min(100%, 56rem);
72
+ max-height: calc(100dvh - 2rem);
73
+ display: flex;
74
+ flex-direction: column;
75
+ overflow: hidden;
77
76
  position: relative;
78
77
  border-radius: 1rem;
79
78
  border: 1px solid var(--sw-color-border);
80
79
  background: var(--sw-color-surface);
81
80
  color: var(--sw-color-text);
82
- padding: 1.25rem;
83
81
  box-shadow: var(--sw-shadow-elevated);
84
82
  }
85
83
 
84
+ .sw-modal-body {
85
+ flex: 1;
86
+ overflow-y: auto;
87
+ overscroll-behavior: contain;
88
+ padding: 1.25rem;
89
+ }
90
+
86
91
  .sw-close {
87
92
  position: absolute;
88
93
  right: 0.75rem;
@@ -97,6 +102,13 @@
97
102
  .sw-header h2 {
98
103
  margin: 0;
99
104
  font-size: 1.25rem;
105
+ display: flex;
106
+ align-items: center;
107
+ gap: 0.4rem;
108
+ }
109
+
110
+ .sw-header-icon {
111
+ flex-shrink: 0;
100
112
  }
101
113
 
102
114
  .sw-header p {
@@ -115,12 +127,22 @@
115
127
  border: 2px solid var(--sw-color-border);
116
128
  border-radius: 0.75rem;
117
129
  background: #ffffff;
118
- padding: 0.85rem;
119
- display: grid;
120
- gap: 0.4rem;
130
+ padding: 1.25rem 1rem;
131
+ display: flex;
132
+ flex-direction: column;
133
+ align-items: center;
134
+ text-align: center;
135
+ gap: 0.5rem;
121
136
  transition: border-color 150ms ease, background 150ms ease;
122
137
  }
123
138
 
139
+ .sw-type-card-icon {
140
+ display: flex;
141
+ align-items: center;
142
+ justify-content: center;
143
+ margin-bottom: 0.25rem;
144
+ }
145
+
124
146
  .sw-type-card:hover {
125
147
  border-color: var(--sw-color-primary);
126
148
  background: var(--sw-color-surface-muted);
@@ -232,6 +254,14 @@
232
254
  .sw-success {
233
255
  text-align: center;
234
256
  padding: 3rem 1rem;
257
+ display: flex;
258
+ flex-direction: column;
259
+ align-items: center;
260
+ gap: 0.5rem;
261
+ }
262
+
263
+ .sw-success-icon {
264
+ margin-bottom: 0.5rem;
235
265
  }
236
266
 
237
267
  @media (max-width: 640px) {
@@ -0,0 +1,277 @@
1
+ :root {
2
+ --sw-color-launcher-bg: #6d28d9;
3
+ --sw-color-launcher-bg-hover: #5b21b6;
4
+ --sw-color-launcher-border: #8b5cf6;
5
+ --sw-color-surface: #ffffff;
6
+ --sw-color-surface-muted: #f8fafc;
7
+ --sw-color-text: #0f172a;
8
+ --sw-color-text-muted: #475569;
9
+ --sw-color-border: #cbd5e1;
10
+ --sw-color-primary: #0f766e;
11
+ --sw-color-primary-hover: #115e59;
12
+ --sw-color-danger: #b91c1c;
13
+ --sw-shadow-elevated: 0 20px 35px rgba(15, 23, 42, 0.25);
14
+ }
15
+
16
+ .sw-sr-only {
17
+ border: 0;
18
+ clip: rect(0, 0, 0, 0);
19
+ height: 1px;
20
+ margin: -1px;
21
+ overflow: hidden;
22
+ padding: 0;
23
+ position: absolute;
24
+ width: 1px;
25
+ }
26
+
27
+ .sw-launcher {
28
+ position: fixed;
29
+ right: 1.5rem;
30
+ bottom: 1.5rem;
31
+ z-index: 1000;
32
+ display: inline-flex;
33
+ align-items: center;
34
+ gap: 0.5rem;
35
+ border-radius: 999px;
36
+ border: 2px solid var(--sw-color-launcher-border);
37
+ background: var(--sw-color-launcher-bg);
38
+ color: #ffffff;
39
+ font-size: 0.875rem;
40
+ font-weight: 700;
41
+ padding: 0.625rem 1rem;
42
+ box-shadow: 0 10px 24px rgba(76, 29, 149, 0.38);
43
+ transition: transform 150ms ease, background 150ms ease;
44
+ }
45
+
46
+ .sw-launcher:hover {
47
+ transform: scale(1.05);
48
+ background: var(--sw-color-launcher-bg-hover);
49
+ }
50
+
51
+ .sw-launcher-icon {
52
+ width: 1.25rem;
53
+ height: 1.25rem;
54
+ display: inline-flex;
55
+ align-items: center;
56
+ justify-content: center;
57
+ }
58
+
59
+ .sw-overlay {
60
+ position: fixed;
61
+ inset: 0;
62
+ z-index: 1100;
63
+ background: rgba(2, 6, 23, 0.7);
64
+ display: flex;
65
+ align-items: center;
66
+ justify-content: center;
67
+ padding: 1rem;
68
+ }
69
+
70
+ .sw-modal {
71
+ width: min(100%, 56rem);
72
+ max-height: calc(100dvh - 2rem);
73
+ display: flex;
74
+ flex-direction: column;
75
+ overflow: hidden;
76
+ position: relative;
77
+ border-radius: 1rem;
78
+ border: 1px solid var(--sw-color-border);
79
+ background: var(--sw-color-surface);
80
+ color: var(--sw-color-text);
81
+ box-shadow: var(--sw-shadow-elevated);
82
+ }
83
+
84
+ .sw-modal-body {
85
+ flex: 1;
86
+ overflow-y: auto;
87
+ overscroll-behavior: contain;
88
+ padding: 1.25rem;
89
+ }
90
+
91
+ .sw-close {
92
+ position: absolute;
93
+ right: 0.75rem;
94
+ top: 0.75rem;
95
+ width: 2rem;
96
+ height: 2rem;
97
+ border-radius: 0.5rem;
98
+ border: 1px solid var(--sw-color-border);
99
+ background: transparent;
100
+ }
101
+
102
+ .sw-header h2 {
103
+ margin: 0;
104
+ font-size: 1.25rem;
105
+ display: flex;
106
+ align-items: center;
107
+ gap: 0.4rem;
108
+ }
109
+
110
+ .sw-header-icon {
111
+ flex-shrink: 0;
112
+ }
113
+
114
+ .sw-header p {
115
+ margin: 0.3rem 0 1rem;
116
+ color: var(--sw-color-text-muted);
117
+ }
118
+
119
+ .sw-type-grid {
120
+ display: grid;
121
+ grid-template-columns: repeat(2, minmax(0, 1fr));
122
+ gap: 0.75rem;
123
+ }
124
+
125
+ .sw-type-card {
126
+ text-align: left;
127
+ border: 2px solid var(--sw-color-border);
128
+ border-radius: 0.75rem;
129
+ background: #ffffff;
130
+ padding: 1.25rem 1rem;
131
+ display: flex;
132
+ flex-direction: column;
133
+ align-items: center;
134
+ text-align: center;
135
+ gap: 0.5rem;
136
+ transition: border-color 150ms ease, background 150ms ease;
137
+ }
138
+
139
+ .sw-type-card-icon {
140
+ display: flex;
141
+ align-items: center;
142
+ justify-content: center;
143
+ margin-bottom: 0.25rem;
144
+ }
145
+
146
+ .sw-type-card:hover {
147
+ border-color: var(--sw-color-primary);
148
+ background: var(--sw-color-surface-muted);
149
+ }
150
+
151
+ .sw-type-card span {
152
+ color: var(--sw-color-text-muted);
153
+ font-size: 0.85rem;
154
+ }
155
+
156
+ .sw-form {
157
+ display: grid;
158
+ gap: 0.8rem;
159
+ }
160
+
161
+ .sw-field {
162
+ display: grid;
163
+ gap: 0.35rem;
164
+ }
165
+
166
+ .sw-field textarea,
167
+ .sw-form input,
168
+ .sw-form select {
169
+ border: 1px solid var(--sw-color-border);
170
+ border-radius: 0.5rem;
171
+ padding: 0.6rem;
172
+ font: inherit;
173
+ }
174
+
175
+ .sw-row {
176
+ display: grid;
177
+ grid-template-columns: repeat(2, minmax(0, 1fr));
178
+ gap: 0.75rem;
179
+ }
180
+
181
+ .sw-section {
182
+ border: 1px solid var(--sw-color-border);
183
+ border-radius: 0.75rem;
184
+ background: var(--sw-color-surface-muted);
185
+ padding: 0.8rem;
186
+ }
187
+
188
+ .sw-section h3 {
189
+ margin-top: 0;
190
+ margin-bottom: 0.6rem;
191
+ font-size: 1rem;
192
+ }
193
+
194
+ .sw-rating {
195
+ display: grid;
196
+ gap: 0.45rem;
197
+ }
198
+
199
+ .sw-rating-button {
200
+ border: 1px solid var(--sw-color-border);
201
+ border-radius: 0.3rem;
202
+ background: transparent;
203
+ color: #94a3b8;
204
+ margin-right: 0.35rem;
205
+ }
206
+
207
+ .sw-rating-button.is-active {
208
+ color: #f59e0b;
209
+ border-color: #f59e0b;
210
+ }
211
+
212
+ .sw-diagnostics-note {
213
+ border: 1px dashed var(--sw-color-border);
214
+ border-radius: 0.55rem;
215
+ font-size: 0.8rem;
216
+ color: var(--sw-color-text-muted);
217
+ padding: 0.65rem;
218
+ }
219
+
220
+ .sw-error {
221
+ color: var(--sw-color-danger);
222
+ margin: 0;
223
+ }
224
+
225
+ .sw-actions {
226
+ display: flex;
227
+ gap: 0.75rem;
228
+ }
229
+
230
+ .sw-actions button {
231
+ flex: 1;
232
+ border: 1px solid var(--sw-color-border);
233
+ border-radius: 0.5rem;
234
+ padding: 0.6rem;
235
+ font: inherit;
236
+ background: #ffffff;
237
+ }
238
+
239
+ .sw-actions button[type='submit'] {
240
+ color: #ffffff;
241
+ background: var(--sw-color-primary);
242
+ border-color: var(--sw-color-primary);
243
+ }
244
+
245
+ .sw-actions button[type='submit']:hover {
246
+ background: var(--sw-color-primary-hover);
247
+ }
248
+
249
+ .sw-actions button:disabled {
250
+ opacity: 0.5;
251
+ cursor: not-allowed;
252
+ }
253
+
254
+ .sw-success {
255
+ text-align: center;
256
+ padding: 3rem 1rem;
257
+ display: flex;
258
+ flex-direction: column;
259
+ align-items: center;
260
+ gap: 0.5rem;
261
+ }
262
+
263
+ .sw-success-icon {
264
+ margin-bottom: 0.5rem;
265
+ }
266
+
267
+ @media (max-width: 640px) {
268
+ .sw-type-grid,
269
+ .sw-row {
270
+ grid-template-columns: 1fr;
271
+ }
272
+
273
+ .sw-launcher {
274
+ right: 1rem;
275
+ bottom: 1rem;
276
+ }
277
+ }
@@ -0,0 +1,252 @@
1
+ :root {
2
+ --sw-color-launcher-bg: #6d28d9;
3
+ --sw-color-launcher-bg-hover: #5b21b6;
4
+ --sw-color-launcher-border: #8b5cf6;
5
+ --sw-color-surface: #ffffff;
6
+ --sw-color-surface-muted: #f8fafc;
7
+ --sw-color-text: #0f172a;
8
+ --sw-color-text-muted: #475569;
9
+ --sw-color-border: #cbd5e1;
10
+ --sw-color-primary: #0f766e;
11
+ --sw-color-primary-hover: #115e59;
12
+ --sw-color-danger: #b91c1c;
13
+ --sw-shadow-elevated: 0 20px 35px rgba(15, 23, 42, 0.25);
14
+ }
15
+
16
+ .sw-sr-only {
17
+ border: 0;
18
+ clip: rect(0, 0, 0, 0);
19
+ height: 1px;
20
+ margin: -1px;
21
+ overflow: hidden;
22
+ padding: 0;
23
+ position: absolute;
24
+ width: 1px;
25
+ }
26
+
27
+ .sw-launcher {
28
+ position: fixed;
29
+ right: 1.5rem;
30
+ bottom: 1.5rem;
31
+ z-index: 1000;
32
+ display: inline-flex;
33
+ align-items: center;
34
+ gap: 0.5rem;
35
+ border-radius: 999px;
36
+ border: 2px solid var(--sw-color-launcher-border);
37
+ background: var(--sw-color-launcher-bg);
38
+ color: #ffffff;
39
+ font-size: 0.875rem;
40
+ font-weight: 700;
41
+ padding: 0.625rem 1rem;
42
+ box-shadow: 0 10px 24px rgba(76, 29, 149, 0.38);
43
+ transition: transform 150ms ease, background 150ms ease;
44
+ }
45
+
46
+ .sw-launcher:hover {
47
+ transform: scale(1.05);
48
+ background: var(--sw-color-launcher-bg-hover);
49
+ }
50
+
51
+ .sw-launcher-icon {
52
+ width: 1.25rem;
53
+ height: 1.25rem;
54
+ display: inline-flex;
55
+ align-items: center;
56
+ justify-content: center;
57
+ }
58
+
59
+ .sw-overlay {
60
+ position: fixed;
61
+ inset: 0;
62
+ z-index: 1100;
63
+ background: rgba(2, 6, 23, 0.7);
64
+ display: flex;
65
+ align-items: center;
66
+ justify-content: center;
67
+ padding: 1rem;
68
+ }
69
+
70
+ .sw-modal {
71
+ width: min(100%, 56rem);
72
+ max-height: calc(100dvh - 2rem);
73
+ display: flex;
74
+ flex-direction: column;
75
+ overflow: hidden;
76
+ position: relative;
77
+ border-radius: 1rem;
78
+ border: 1px solid var(--sw-color-border);
79
+ background: var(--sw-color-surface);
80
+ color: var(--sw-color-text);
81
+ box-shadow: var(--sw-shadow-elevated);
82
+ }
83
+
84
+ .sw-modal-body {
85
+ flex: 1;
86
+ overflow-y: auto;
87
+ overscroll-behavior: contain;
88
+ padding: 1.25rem;
89
+ }
90
+
91
+ .sw-close {
92
+ position: absolute;
93
+ right: 0.75rem;
94
+ top: 0.75rem;
95
+ width: 2rem;
96
+ height: 2rem;
97
+ border-radius: 0.5rem;
98
+ border: 1px solid var(--sw-color-border);
99
+ background: transparent;
100
+ }
101
+
102
+ .sw-header h2 {
103
+ margin: 0;
104
+ font-size: 1.25rem;
105
+ }
106
+
107
+ .sw-header p {
108
+ margin: 0.3rem 0 1rem;
109
+ color: var(--sw-color-text-muted);
110
+ }
111
+
112
+ .sw-type-grid {
113
+ display: grid;
114
+ grid-template-columns: repeat(2, minmax(0, 1fr));
115
+ gap: 0.75rem;
116
+ }
117
+
118
+ .sw-type-card {
119
+ text-align: left;
120
+ border: 2px solid var(--sw-color-border);
121
+ border-radius: 0.75rem;
122
+ background: #ffffff;
123
+ padding: 0.85rem;
124
+ display: grid;
125
+ gap: 0.4rem;
126
+ transition: border-color 150ms ease, background 150ms ease;
127
+ }
128
+
129
+ .sw-type-card:hover {
130
+ border-color: var(--sw-color-primary);
131
+ background: var(--sw-color-surface-muted);
132
+ }
133
+
134
+ .sw-type-card span {
135
+ color: var(--sw-color-text-muted);
136
+ font-size: 0.85rem;
137
+ }
138
+
139
+ .sw-form {
140
+ display: grid;
141
+ gap: 0.8rem;
142
+ }
143
+
144
+ .sw-field {
145
+ display: grid;
146
+ gap: 0.35rem;
147
+ }
148
+
149
+ .sw-field textarea,
150
+ .sw-form input,
151
+ .sw-form select {
152
+ border: 1px solid var(--sw-color-border);
153
+ border-radius: 0.5rem;
154
+ padding: 0.6rem;
155
+ font: inherit;
156
+ }
157
+
158
+ .sw-row {
159
+ display: grid;
160
+ grid-template-columns: repeat(2, minmax(0, 1fr));
161
+ gap: 0.75rem;
162
+ }
163
+
164
+ .sw-section {
165
+ border: 1px solid var(--sw-color-border);
166
+ border-radius: 0.75rem;
167
+ background: var(--sw-color-surface-muted);
168
+ padding: 0.8rem;
169
+ }
170
+
171
+ .sw-section h3 {
172
+ margin-top: 0;
173
+ margin-bottom: 0.6rem;
174
+ font-size: 1rem;
175
+ }
176
+
177
+ .sw-rating {
178
+ display: grid;
179
+ gap: 0.45rem;
180
+ }
181
+
182
+ .sw-rating-button {
183
+ border: 1px solid var(--sw-color-border);
184
+ border-radius: 0.3rem;
185
+ background: transparent;
186
+ color: #94a3b8;
187
+ margin-right: 0.35rem;
188
+ }
189
+
190
+ .sw-rating-button.is-active {
191
+ color: #f59e0b;
192
+ border-color: #f59e0b;
193
+ }
194
+
195
+ .sw-diagnostics-note {
196
+ border: 1px dashed var(--sw-color-border);
197
+ border-radius: 0.55rem;
198
+ font-size: 0.8rem;
199
+ color: var(--sw-color-text-muted);
200
+ padding: 0.65rem;
201
+ }
202
+
203
+ .sw-error {
204
+ color: var(--sw-color-danger);
205
+ margin: 0;
206
+ }
207
+
208
+ .sw-actions {
209
+ display: flex;
210
+ gap: 0.75rem;
211
+ }
212
+
213
+ .sw-actions button {
214
+ flex: 1;
215
+ border: 1px solid var(--sw-color-border);
216
+ border-radius: 0.5rem;
217
+ padding: 0.6rem;
218
+ font: inherit;
219
+ background: #ffffff;
220
+ }
221
+
222
+ .sw-actions button[type='submit'] {
223
+ color: #ffffff;
224
+ background: var(--sw-color-primary);
225
+ border-color: var(--sw-color-primary);
226
+ }
227
+
228
+ .sw-actions button[type='submit']:hover {
229
+ background: var(--sw-color-primary-hover);
230
+ }
231
+
232
+ .sw-actions button:disabled {
233
+ opacity: 0.5;
234
+ cursor: not-allowed;
235
+ }
236
+
237
+ .sw-success {
238
+ text-align: center;
239
+ padding: 3rem 1rem;
240
+ }
241
+
242
+ @media (max-width: 640px) {
243
+ .sw-type-grid,
244
+ .sw-row {
245
+ grid-template-columns: 1fr;
246
+ }
247
+
248
+ .sw-launcher {
249
+ right: 1rem;
250
+ bottom: 1rem;
251
+ }
252
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cohiva/support-widget",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "description": "Reusable Support Ticket widget with diagnostics capture and typed payload generation",
5
5
  "license": "MIT",
6
6
  "engines": {
@@ -63,6 +63,7 @@
63
63
  "react-dom": ">=18"
64
64
  },
65
65
  "dependencies": {
66
+ "lucide-react": "^1.7.0",
66
67
  "zod": "^3.24.1"
67
68
  },
68
69
  "devDependencies": {