@jotul/jotul-widgets 0.0.3 → 0.0.4

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.
@@ -0,0 +1,253 @@
1
+ .jwi-root {
2
+ width: 100%;
3
+ color: #111111;
4
+ font-family:
5
+ Inter,
6
+ ui-sans-serif,
7
+ system-ui,
8
+ -apple-system,
9
+ BlinkMacSystemFont,
10
+ "Segoe UI",
11
+ sans-serif;
12
+ }
13
+
14
+ .jwi-shell {
15
+ width: 100%;
16
+ border: 1px solid #e9e5dc;
17
+ border-radius: 32px;
18
+ background: #f8f6f2;
19
+ padding: 16px;
20
+ box-shadow: 0 6px 20px rgba(17, 17, 17, 0.04);
21
+ }
22
+
23
+ .jwi-searchBox {
24
+ overflow: hidden;
25
+ border: 1px solid #d8d2c7;
26
+ border-radius: 24px;
27
+ background: #ffffff;
28
+ }
29
+
30
+ .jwi-searchRow {
31
+ display: flex;
32
+ flex-direction: column;
33
+ }
34
+
35
+ .jwi-inputWrap {
36
+ display: flex;
37
+ min-width: 0;
38
+ flex: 1;
39
+ align-items: center;
40
+ gap: 12px;
41
+ padding: 16px 20px;
42
+ }
43
+
44
+ .jwi-pin {
45
+ display: inline-flex;
46
+ flex-shrink: 0;
47
+ color: #000000;
48
+ }
49
+
50
+ .jwi-input {
51
+ width: 100%;
52
+ border: 0;
53
+ background: transparent;
54
+ color: #111111;
55
+ font-size: 16px;
56
+ line-height: 1.4;
57
+ outline: none;
58
+ }
59
+
60
+ .jwi-input::placeholder {
61
+ color: #767676;
62
+ }
63
+
64
+ .jwi-findButton {
65
+ min-height: 64px;
66
+ border: 0;
67
+ background: #000000;
68
+ padding: 0 32px;
69
+ color: #ffffff;
70
+ font-size: 16px;
71
+ font-weight: 500;
72
+ cursor: pointer;
73
+ }
74
+
75
+ .jwi-findButton:hover {
76
+ background: #1f1f1f;
77
+ }
78
+
79
+ .jwi-findButton:disabled {
80
+ cursor: not-allowed;
81
+ background: #444444;
82
+ }
83
+
84
+ .jwi-error {
85
+ margin-top: 16px;
86
+ border: 1px solid #f0c7c2;
87
+ border-radius: 16px;
88
+ background: #fff3f1;
89
+ padding: 12px 16px;
90
+ color: #8f2d21;
91
+ font-size: 14px;
92
+ line-height: 1.4;
93
+ }
94
+
95
+ .jwi-results {
96
+ margin-top: 20px;
97
+ }
98
+
99
+ .jwi-resultsHeader {
100
+ border-bottom: 1px solid #e6e1d7;
101
+ padding-bottom: 16px;
102
+ color: #111111;
103
+ font-size: 16px;
104
+ font-weight: 500;
105
+ }
106
+
107
+ .jwi-resultsList {
108
+ margin-top: 20px;
109
+ display: flex;
110
+ max-height: 700px;
111
+ flex-direction: column;
112
+ gap: 16px;
113
+ overflow-y: auto;
114
+ padding-right: 4px;
115
+ }
116
+
117
+ .jwi-card {
118
+ border: 1px solid #e6e1d7;
119
+ border-radius: 24px;
120
+ background: #ffffff;
121
+ padding: 20px;
122
+ box-shadow: 0 1px 2px rgba(17, 17, 17, 0.03);
123
+ }
124
+
125
+ .jwi-cardTop {
126
+ display: flex;
127
+ align-items: flex-start;
128
+ justify-content: space-between;
129
+ gap: 16px;
130
+ }
131
+
132
+ .jwi-cardTitleWrap {
133
+ max-width: 70%;
134
+ }
135
+
136
+ .jwi-cardTitle {
137
+ margin: 0;
138
+ color: #111111;
139
+ font-size: 22px;
140
+ font-weight: 600;
141
+ line-height: 1.15;
142
+ }
143
+
144
+ .jwi-distance {
145
+ border-radius: 9999px;
146
+ background: #fbf3db;
147
+ padding: 8px 16px;
148
+ color: #111111;
149
+ font-size: 20px;
150
+ font-weight: 500;
151
+ line-height: 1;
152
+ white-space: nowrap;
153
+ }
154
+
155
+ .jwi-address {
156
+ margin-top: 20px;
157
+ display: flex;
158
+ flex-direction: column;
159
+ gap: 4px;
160
+ color: #111111;
161
+ font-size: 18px;
162
+ line-height: 1.15;
163
+ }
164
+
165
+ .jwi-cardActions {
166
+ margin-top: 24px;
167
+ display: flex;
168
+ flex-direction: column;
169
+ gap: 16px;
170
+ }
171
+
172
+ .jwi-cta {
173
+ display: inline-flex;
174
+ min-height: 70px;
175
+ width: 100%;
176
+ align-items: center;
177
+ justify-content: space-between;
178
+ border: 0;
179
+ border-radius: 16px;
180
+ background: #ef2b18;
181
+ padding: 0 28px;
182
+ color: #ffffff;
183
+ font-size: 18px;
184
+ font-weight: 500;
185
+ cursor: pointer;
186
+ }
187
+
188
+ .jwi-cta:hover {
189
+ background: #d92817;
190
+ }
191
+
192
+ .jwi-phoneLink {
193
+ display: inline-flex;
194
+ align-items: center;
195
+ gap: 12px;
196
+ color: #111111;
197
+ font-size: 18px;
198
+ font-weight: 500;
199
+ text-decoration: none;
200
+ }
201
+
202
+ .jwi-phoneLink:hover {
203
+ text-decoration: underline;
204
+ }
205
+
206
+ .jwi-icon16 {
207
+ width: 16px;
208
+ height: 16px;
209
+ flex-shrink: 0;
210
+ }
211
+
212
+ .jwi-icon22 {
213
+ width: 22px;
214
+ height: 22px;
215
+ flex-shrink: 0;
216
+ }
217
+
218
+ .jwi-loading,
219
+ .jwi-message {
220
+ color: #111111;
221
+ font-family:
222
+ Inter,
223
+ ui-sans-serif,
224
+ system-ui,
225
+ -apple-system,
226
+ BlinkMacSystemFont,
227
+ "Segoe UI",
228
+ sans-serif;
229
+ }
230
+
231
+ @media (min-width: 768px) {
232
+ .jwi-shell {
233
+ padding: 24px;
234
+ }
235
+
236
+ .jwi-searchRow {
237
+ flex-direction: row;
238
+ }
239
+
240
+ .jwi-inputWrap {
241
+ padding: 16px 24px;
242
+ }
243
+
244
+ .jwi-cardActions {
245
+ flex-direction: row;
246
+ align-items: center;
247
+ justify-content: space-between;
248
+ }
249
+
250
+ .jwi-cta {
251
+ width: 390px;
252
+ }
253
+ }
@@ -1,3 +1,4 @@
1
+ import './JotulWidget.css';
1
2
  export type JotulWidgetType = 'productPage' | 'dealerFinder' | 'warrantyForm';
2
3
  export type WidgetAuthClientResponse = {
3
4
  apiVersion?: string;
@@ -1,5 +1,6 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import './JotulWidget.css';
3
4
  import { useEffect, useMemo, useState } from 'react';
4
5
  const VALID_WIDGET_TYPES = [
5
6
  'productPage',
@@ -7,13 +8,13 @@ const VALID_WIDGET_TYPES = [
7
8
  'warrantyForm',
8
9
  ];
9
10
  function PinIcon() {
10
- return (_jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", className: "h-4 w-4 shrink-0", children: _jsx("path", { fillRule: "evenodd", clipRule: "evenodd", d: "M2.70895 0.833313H5.20957C5.41781 0.833313 5.60425 0.962386 5.67756 1.15731L6.64785 3.73723C6.68 3.82263 6.68813 3.91519 6.6714 4.00488L6.1852 6.61285C6.7828 8.01818 7.76987 8.96258 9.40693 9.80971L11.9836 9.31045C12.0751 9.29271 12.1697 9.30091 12.2567 9.33411L14.8446 10.3202C15.0385 10.3941 15.1665 10.58 15.1665 10.7874V13.177C15.1665 14.2606 14.2117 15.14 13.0949 14.897C11.0592 14.454 7.28767 13.3282 4.64633 10.6868C2.11624 8.15678 1.26855 4.66166 0.983187 2.77244C0.820367 1.69446 1.6849 0.833313 2.70895 0.833313Z", fill: "currentColor" }) }));
11
+ return (_jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", className: "jwi-icon16", children: _jsx("path", { fillRule: "evenodd", clipRule: "evenodd", d: "M2.70895 0.833313H5.20957C5.41781 0.833313 5.60425 0.962386 5.67756 1.15731L6.64785 3.73723C6.68 3.82263 6.68813 3.91519 6.6714 4.00488L6.1852 6.61285C6.7828 8.01818 7.76987 8.96258 9.40693 9.80971L11.9836 9.31045C12.0751 9.29271 12.1697 9.30091 12.2567 9.33411L14.8446 10.3202C15.0385 10.3941 15.1665 10.58 15.1665 10.7874V13.177C15.1665 14.2606 14.2117 15.14 13.0949 14.897C11.0592 14.454 7.28767 13.3282 4.64633 10.6868C2.11624 8.15678 1.26855 4.66166 0.983187 2.77244C0.820367 1.69446 1.6849 0.833313 2.70895 0.833313Z", fill: "currentColor" }) }));
11
12
  }
12
13
  function ArrowRightIcon() {
13
- return (_jsx("svg", { width: "22", height: "22", viewBox: "0 0 22 22", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", className: "h-5 w-5 shrink-0", children: _jsx("path", { d: "M2.75 11L19.25 11M19.25 11L11.4583 3.20836M19.25 11L11.4583 18.7917", stroke: "currentColor", strokeWidth: "2.08333", strokeLinecap: "round", strokeLinejoin: "round" }) }));
14
+ return (_jsx("svg", { width: "22", height: "22", viewBox: "0 0 22 22", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", className: "jwi-icon22", children: _jsx("path", { d: "M2.75 11L19.25 11M19.25 11L11.4583 3.20836M19.25 11L11.4583 18.7917", stroke: "currentColor", strokeWidth: "2.08333", strokeLinecap: "round", strokeLinejoin: "round" }) }));
14
15
  }
15
16
  function TelephoneIcon() {
16
- return (_jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", className: "h-4 w-4 shrink-0", children: _jsx("path", { fillRule: "evenodd", clipRule: "evenodd", d: "M2.70895 0.833313H5.20957C5.41781 0.833313 5.60425 0.962386 5.67756 1.15731L6.64785 3.73723C6.68 3.82263 6.68813 3.91519 6.6714 4.00488L6.1852 6.61285C6.7828 8.01818 7.76987 8.96258 9.40693 9.80971L11.9836 9.31045C12.0751 9.29271 12.1697 9.30091 12.2567 9.33411L14.8446 10.3202C15.0385 10.3941 15.1665 10.58 15.1665 10.7874V13.177C15.1665 14.2606 14.2117 15.14 13.0949 14.897C11.0592 14.454 7.28767 13.3282 4.64633 10.6868C2.11624 8.15678 1.26855 4.66166 0.983187 2.77244C0.820367 1.69446 1.6849 0.833313 2.70895 0.833313Z", fill: "currentColor" }) }));
17
+ return (_jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", className: "jwi-icon16", children: _jsx("path", { fillRule: "evenodd", clipRule: "evenodd", d: "M2.70895 0.833313H5.20957C5.41781 0.833313 5.60425 0.962386 5.67756 1.15731L6.64785 3.73723C6.68 3.82263 6.68813 3.91519 6.6714 4.00488L6.1852 6.61285C6.7828 8.01818 7.76987 8.96258 9.40693 9.80971L11.9836 9.31045C12.0751 9.29271 12.1697 9.30091 12.2567 9.33411L14.8446 10.3202C15.0385 10.3941 15.1665 10.58 15.1665 10.7874V13.177C15.1665 14.2606 14.2117 15.14 13.0949 14.897C11.0592 14.454 7.28767 13.3282 4.64633 10.6868C2.11624 8.15678 1.26855 4.66166 0.983187 2.77244C0.820367 1.69446 1.6849 0.833313 2.70895 0.833313Z", fill: "currentColor" }) }));
17
18
  }
18
19
  function asText(value) {
19
20
  return typeof value === 'string' && value.trim() ? value.trim() : null;
@@ -144,35 +145,35 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, }
144
145
  return 'typeReady';
145
146
  }, [type]);
146
147
  if (isLoading) {
147
- return _jsx("div", { className: className, children: "Loading JotulWidget\u2026" });
148
+ return _jsx("div", { className: className ? `jwi-loading ${className}` : 'jwi-loading', children: "Loading JotulWidget\u2026" });
148
149
  }
149
150
  if (!auth?.ok || !auth.authorized) {
150
- return (_jsxs("div", { className: className, children: ["JotulWidget auth failed: ", auth?.error ?? 'Unknown authorization error'] }));
151
+ return (_jsxs("div", { className: className ? `jwi-message ${className}` : 'jwi-message', children: ["JotulWidget auth failed: ", auth?.error ?? 'Unknown authorization error'] }));
151
152
  }
152
153
  if (typeState === 'typeMissing') {
153
- return _jsx("div", { className: className, children: "JotulWidget type missing" });
154
+ return _jsx("div", { className: className ? `jwi-message ${className}` : 'jwi-message', children: "JotulWidget type missing" });
154
155
  }
155
156
  if (typeState === 'typeInvalid') {
156
- return _jsx("div", { className: className, children: "Invalid widget type" });
157
+ return _jsx("div", { className: className ? `jwi-message ${className}` : 'jwi-message', children: "Invalid widget type" });
157
158
  }
158
159
  if (type === 'productPage') {
159
160
  const dealers = (searchResult?.dealers ?? []);
160
161
  const canSearch = postalCode.trim().length > 0;
161
162
  const total = searchResult?.total ?? dealers.length;
162
- return (_jsx("div", { className: className, children: _jsxs("div", { className: "w-full rounded-[32px] border border-[#e9e5dc] bg-[#f8f6f2] p-4 text-[#111111] shadow-[0_6px_20px_rgba(17,17,17,0.04)] md:p-6", children: [_jsx("div", { className: "overflow-hidden rounded-[24px] border border-[#d8d2c7] bg-white", children: _jsxs("div", { className: "flex flex-col md:flex-row", children: [_jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-3 px-5 py-4 md:px-6", children: [_jsx("span", { className: "text-black", children: _jsx(PinIcon, {}) }), _jsx("input", { type: "text", inputMode: "numeric", autoComplete: "postal-code", pattern: "[0-9]*", maxLength: 10, value: postalCode, onChange: (event) => {
163
+ return (_jsx("div", { className: className ? `jwi-root ${className}` : 'jwi-root', children: _jsxs("div", { className: "jwi-shell", children: [_jsx("div", { className: "jwi-searchBox", children: _jsxs("div", { className: "jwi-searchRow", children: [_jsxs("div", { className: "jwi-inputWrap", children: [_jsx("span", { className: "jwi-pin", children: _jsx(PinIcon, {}) }), _jsx("input", { type: "text", inputMode: "numeric", autoComplete: "postal-code", pattern: "[0-9]*", maxLength: 10, value: postalCode, onChange: (event) => {
163
164
  const next = event.target.value.replace(/\D+/g, '');
164
165
  setPostalCode(next);
165
- }, placeholder: "Enter postcode", className: "w-full border-0 bg-transparent text-base text-[#111111] outline-none placeholder:text-[#767676]" })] }), _jsx("button", { type: "button", disabled: isSearching || !canSearch, onClick: async () => {
166
+ }, placeholder: "Enter postcode", className: "jwi-input" })] }), _jsx("button", { type: "button", disabled: isSearching || !canSearch, onClick: async () => {
166
167
  setIsSearching(true);
167
168
  const result = await searchDealersByPostalCode(postalCode, { endpoint });
168
169
  setSearchResult(result);
169
170
  setIsSearching(false);
170
- }, className: "min-h-[64px] bg-black px-8 text-base font-medium text-white transition hover:bg-[#1f1f1f] disabled:cursor-not-allowed disabled:bg-[#444444]", children: isSearching ? 'Finding...' : 'Find' })] }) }), searchResult?.ok === false && (_jsx("div", { className: "mt-4 rounded-2xl border border-[#f0c7c2] bg-[#fff3f1] px-4 py-3 text-sm text-[#8f2d21]", children: searchResult.error ?? 'Unknown widget error' })), searchResult?.ok && (_jsxs("div", { className: "mt-5", children: [_jsxs("div", { className: "border-b border-[#e6e1d7] pb-4 text-base font-medium text-[#111111]", children: [total, " dealers near you"] }), _jsx("div", { className: "mt-5 max-h-[700px] space-y-4 overflow-y-auto pr-1", children: dealers.map((dealer, index) => {
171
+ }, className: "jwi-findButton", children: isSearching ? 'Finding...' : 'Find' })] }) }), searchResult?.ok === false && (_jsx("div", { className: "jwi-error", children: searchResult.error ?? 'Unknown widget error' })), searchResult?.ok && (_jsxs("div", { className: "jwi-results", children: [_jsxs("div", { className: "jwi-resultsHeader", children: [total, " dealers near you"] }), _jsx("div", { className: "jwi-resultsList", children: dealers.map((dealer, index) => {
171
172
  const addressLines = getDealerAddressLines(dealer);
172
173
  const phone = asText(dealer.phone);
173
174
  const distance = formatDistance(dealer);
174
- return (_jsxs("div", { className: "rounded-[24px] border border-[#e6e1d7] bg-white p-5 shadow-[0_1px_2px_rgba(17,17,17,0.03)]", children: [_jsxs("div", { className: "flex items-start justify-between gap-4", children: [_jsx("div", { className: "max-w-[70%]", children: _jsx("h3", { className: "text-[22px] font-semibold leading-[1.15] text-[#111111]", children: getDealerName(dealer) }) }), distance && (_jsx("div", { className: "rounded-full bg-[#fbf3db] px-4 py-2 text-xl font-medium leading-none text-[#111111]", children: distance }))] }), addressLines.length > 0 && (_jsx("div", { className: "mt-5 space-y-1 text-[18px] leading-[1.15] text-[#111111]", children: addressLines.map((line) => (_jsx("div", { children: line }, line))) })), _jsxs("div", { className: "mt-6 flex flex-col gap-4 md:flex-row md:items-center md:justify-between", children: [_jsxs("button", { type: "button", className: "inline-flex min-h-[70px] w-full items-center justify-between rounded-[16px] bg-[#ef2b18] px-7 text-[18px] font-medium text-white transition hover:bg-[#d92817] md:w-[390px]", children: [_jsx("span", { children: "Send foresporsel" }), _jsx(ArrowRightIcon, {})] }), phone && (_jsxs("a", { href: `tel:${phone.replace(/\s+/g, '')}`, className: "inline-flex items-center gap-3 text-[18px] font-medium text-[#111111] hover:underline", children: [_jsx(TelephoneIcon, {}), _jsx("span", { children: phone })] }))] })] }, getDealerKey(dealer, index)));
175
+ return (_jsxs("div", { className: "jwi-card", children: [_jsxs("div", { className: "jwi-cardTop", children: [_jsx("div", { className: "jwi-cardTitleWrap", children: _jsx("h3", { className: "jwi-cardTitle", children: getDealerName(dealer) }) }), distance && (_jsx("div", { className: "jwi-distance", children: distance }))] }), addressLines.length > 0 && (_jsx("div", { className: "jwi-address", children: addressLines.map((line) => (_jsx("div", { children: line }, line))) })), _jsxs("div", { className: "jwi-cardActions", children: [_jsxs("button", { type: "button", className: "jwi-cta", children: [_jsx("span", { children: "Send foresporsel" }), _jsx(ArrowRightIcon, {})] }), phone && (_jsxs("a", { href: `tel:${phone.replace(/\s+/g, '')}`, className: "jwi-phoneLink", children: [_jsx(TelephoneIcon, {}), _jsx("span", { children: phone })] }))] })] }, getDealerKey(dealer, index)));
175
176
  }) })] }))] }) }));
176
177
  }
177
- return _jsx("div", { className: className, children: renderReadyState(type) });
178
+ return _jsx("div", { className: className ? `jwi-message ${className}` : 'jwi-message', children: renderReadyState(type) });
178
179
  }
package/package.json CHANGED
@@ -1,9 +1,11 @@
1
1
  {
2
2
  "name": "@jotul/jotul-widgets",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "type": "module",
5
5
  "license": "UNLICENSED",
6
- "sideEffects": false,
6
+ "sideEffects": [
7
+ "**/*.css"
8
+ ],
7
9
  "files": [
8
10
  "dist",
9
11
  "README.md"
@@ -17,7 +19,7 @@
17
19
  }
18
20
  },
19
21
  "scripts": {
20
- "build": "tsc -p tsconfig.build.json",
22
+ "build": "tsc -p tsconfig.build.json && cp src/JotulWidget.css dist/JotulWidget.css",
21
23
  "clean": "rm -rf dist",
22
24
  "prepublishOnly": "npm run clean && npm run build"
23
25
  },