@jotul/jotul-widgets 1.0.0 → 1.0.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/JotulWidget.d.ts +2 -2
- package/dist/JotulWidget.js +8 -5
- package/dist/api.js +1 -1
- package/dist/components/ProductPageWidget.d.ts +3 -2
- package/dist/components/ProductPageWidget.js +3 -3
- package/dist/components/product-page/DealerList.d.ts +3 -2
- package/dist/components/product-page/DealerList.js +6 -2
- package/dist/components/product-page/InquiryForm.d.ts +3 -2
- package/dist/components/product-page/InquiryForm.js +6 -2
- package/dist/index.d.ts +1 -1
- package/dist/types.d.ts +10 -0
- package/dist/utils/widgetPrimaryButtonPresentation.d.ts +14 -0
- package/dist/utils/widgetPrimaryButtonPresentation.js +36 -0
- package/package.json +1 -1
package/dist/JotulWidget.d.ts
CHANGED
|
@@ -4,5 +4,5 @@ import type { JotulWidgetProps } from './types';
|
|
|
4
4
|
export { normalizeWidgetLocale } from './i18n/widgetStrings';
|
|
5
5
|
export type { JotulWidgetLocale } from './i18n/widgetStrings';
|
|
6
6
|
export { checkWidgetAuthorization, searchLocationSuggestions, searchDealersByCoordinates, searchDealersByPostalCode, };
|
|
7
|
-
export type { CheckWidgetAuthorizationOptions, DealerSearchResponse, JotulWidgetProps, JotulWidgetType, WidgetAuthClientResponse, } from './types';
|
|
8
|
-
export declare function JotulWidget({ type, endpoint, className, productName, locale: localeProp, brands, }: JotulWidgetProps): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export type { CheckWidgetAuthorizationOptions, DealerSearchResponse, JotulWidgetButtonStyling, JotulWidgetProps, JotulWidgetStyling, JotulWidgetType, WidgetAuthClientResponse, } from './types';
|
|
8
|
+
export declare function JotulWidget({ type, endpoint, className, productName, locale: localeProp, brands, styling, }: JotulWidgetProps): import("react/jsx-runtime").JSX.Element;
|
package/dist/JotulWidget.js
CHANGED
|
@@ -4,11 +4,11 @@ import './JotulWidget.css';
|
|
|
4
4
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
5
5
|
import { FinderSearchRowSkeleton } from './components/FinderSearchRowSkeleton';
|
|
6
6
|
import { ProductPageWidget } from './widgets/ProductPageWidget';
|
|
7
|
-
import { FIND_DEALER_BUTTON_CLASS } from './constants';
|
|
8
7
|
import { ButtonSpinner } from './icons/ButtonSpinner';
|
|
9
8
|
import { normalizeWidgetLocale, WIDGET_STRINGS } from './i18n/widgetStrings';
|
|
10
9
|
import { checkWidgetAuthorization, searchLocationSuggestions, searchDealersByCoordinates, searchDealersByPostalCode, } from './api';
|
|
11
10
|
import { createInquiryFormValues, getSafeWidgetErrorMessage, isValidEmail, isWidgetType, renderReadyState, } from './utils';
|
|
11
|
+
import { getWidgetPrimaryButtonPresentation } from './utils/widgetPrimaryButtonPresentation';
|
|
12
12
|
export { normalizeWidgetLocale } from './i18n/widgetStrings';
|
|
13
13
|
export { checkWidgetAuthorization, searchLocationSuggestions, searchDealersByCoordinates, searchDealersByPostalCode, };
|
|
14
14
|
const GEO_PERMISSION_DENIED = 1;
|
|
@@ -19,9 +19,12 @@ const GEOLOCATION_OPTIONS = {
|
|
|
19
19
|
timeout: 15000,
|
|
20
20
|
maximumAge: 300000,
|
|
21
21
|
};
|
|
22
|
-
export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, productName, locale: localeProp, brands, }) {
|
|
22
|
+
export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, productName, locale: localeProp, brands, styling, }) {
|
|
23
23
|
const resolvedLocale = useMemo(() => normalizeWidgetLocale(localeProp), [localeProp]);
|
|
24
24
|
const t = WIDGET_STRINGS[resolvedLocale];
|
|
25
|
+
const heroPrimaryButton = useMemo(() => getWidgetPrimaryButtonPresentation(styling?.button, 'hero', {
|
|
26
|
+
disabledWait: true,
|
|
27
|
+
}), [styling?.button]);
|
|
25
28
|
const [auth, setAuth] = useState(null);
|
|
26
29
|
const [isLoading, setIsLoading] = useState(false);
|
|
27
30
|
const [searchResult, setSearchResult] = useState(null);
|
|
@@ -180,11 +183,11 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, p
|
|
|
180
183
|
else {
|
|
181
184
|
setShouldAutoLocateAfterAuth(true);
|
|
182
185
|
}
|
|
183
|
-
}, className:
|
|
186
|
+
}, className: heroPrimaryButton.className, style: heroPrimaryButton.style, children: t.findDealer }) }) }));
|
|
184
187
|
}
|
|
185
188
|
const productPageAuthPending = widgetType === 'productPage' && isOpen && (auth === null || isLoading);
|
|
186
189
|
if (productPageAuthPending) {
|
|
187
|
-
return (_jsx("div", { className: rootClass, children: _jsx("div", { className: "jwi-flex jwi-py-8 jwi-items-center jwi-justify-center", children: _jsx("button", { type: "button", disabled: true, className: `${
|
|
190
|
+
return (_jsx("div", { className: rootClass, children: _jsx("div", { className: "jwi-flex jwi-py-8 jwi-items-center jwi-justify-center", children: _jsx("button", { type: "button", disabled: true, className: `${heroPrimaryButton.className} jwi-opacity-95`, style: heroPrimaryButton.style, children: _jsxs("span", { className: "jwi-inline-flex jwi-items-center jwi-gap-2", children: [_jsx(ButtonSpinner, {}), t.loading] }) }) }) }));
|
|
188
191
|
}
|
|
189
192
|
const waitingForAuth = auth === null && !(widgetType === 'productPage' && !isOpen);
|
|
190
193
|
if ((isLoading || waitingForAuth) && type !== 'productPage') {
|
|
@@ -194,7 +197,7 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, p
|
|
|
194
197
|
return _jsx("div", { className: rootClass, children: getSafeWidgetErrorMessage(auth?.error, t) });
|
|
195
198
|
}
|
|
196
199
|
if (widgetType === 'productPage') {
|
|
197
|
-
return (_jsx("div", { className: rootClass, children: _jsx(ProductPageWidget, { t: t, isSearching: isSearching, locationError: locationError, searchResult: searchResult?.ok === false
|
|
200
|
+
return (_jsx("div", { className: rootClass, children: _jsx(ProductPageWidget, { t: t, buttonStyling: styling?.button, isSearching: isSearching, locationError: locationError, searchResult: searchResult?.ok === false
|
|
198
201
|
? { ...searchResult, error: getSafeWidgetErrorMessage(searchResult.error, t) }
|
|
199
202
|
: searchResult, inquiryValues: inquiryValues, inquiryError: inquiryError, isInquirySubmitted: isInquirySubmitted, selectedDealerName: selectedDealerName, isManualSearchEnabled: isManualLocationSearchEnabled, query: locationQuery, suggestions: locationSuggestions, suggestionsOpen: isSuggestionListOpen, isSuggestionsLoading: isSearchingSuggestions, onQueryChange: (value) => {
|
|
200
203
|
setLocationQuery(value);
|
package/dist/api.js
CHANGED
|
@@ -92,7 +92,7 @@ export async function searchLocationSuggestions(query, options) {
|
|
|
92
92
|
const endpoint = options?.endpoint ?? '/api/jotul/widget';
|
|
93
93
|
const fetcher = options?.fetcher ?? fetch;
|
|
94
94
|
const params = new URLSearchParams({
|
|
95
|
-
|
|
95
|
+
type: 'autocomplete',
|
|
96
96
|
q: query.trim(),
|
|
97
97
|
});
|
|
98
98
|
if (options?.locale != null && options.locale.trim() !== '') {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { WidgetStrings } from '../i18n/widgetStrings';
|
|
2
|
-
import type { DealerSearchResponse, InquiryFormValues, LocationSuggestion } from '../types';
|
|
2
|
+
import type { DealerSearchResponse, InquiryFormValues, JotulWidgetButtonStyling, LocationSuggestion } from '../types';
|
|
3
3
|
type ProductPageWidgetProps = {
|
|
4
4
|
t: WidgetStrings;
|
|
5
|
+
buttonStyling?: JotulWidgetButtonStyling;
|
|
5
6
|
isSearching: boolean;
|
|
6
7
|
locationError: string | null;
|
|
7
8
|
searchResult: DealerSearchResponse | null;
|
|
@@ -22,5 +23,5 @@ type ProductPageWidgetProps = {
|
|
|
22
23
|
onInquiryFieldChange: (key: keyof InquiryFormValues, value: string) => void;
|
|
23
24
|
onStartInquiry: (dealerName: string) => void;
|
|
24
25
|
};
|
|
25
|
-
export declare function ProductPageWidget({ t, isSearching, locationError, searchResult, inquiryValues, inquiryError, isInquirySubmitted, selectedDealerName, isManualSearchEnabled, query, suggestions, suggestionsOpen, isSuggestionsLoading, onQueryChange, onSuggestionSelect, onDismissSuggestions, onInquiryClose, onInquirySubmit, onInquiryFieldChange, onStartInquiry, }: ProductPageWidgetProps): import("react/jsx-runtime").JSX.Element;
|
|
26
|
+
export declare function ProductPageWidget({ t, buttonStyling, isSearching, locationError, searchResult, inquiryValues, inquiryError, isInquirySubmitted, selectedDealerName, isManualSearchEnabled, query, suggestions, suggestionsOpen, isSuggestionsLoading, onQueryChange, onSuggestionSelect, onDismissSuggestions, onInquiryClose, onInquirySubmit, onInquiryFieldChange, onStartInquiry, }: ProductPageWidgetProps): import("react/jsx-runtime").JSX.Element;
|
|
26
27
|
export {};
|
|
@@ -5,12 +5,12 @@ import { InquiryForm } from './product-page/InquiryForm';
|
|
|
5
5
|
import { LocationSearch } from './product-page/LocationSearch';
|
|
6
6
|
import { StatusBanner } from './product-page/StatusBanner';
|
|
7
7
|
import { R10 } from '../constants';
|
|
8
|
-
export function ProductPageWidget({ t, isSearching, locationError, searchResult, inquiryValues, inquiryError, isInquirySubmitted, selectedDealerName, isManualSearchEnabled, query, suggestions, suggestionsOpen, isSuggestionsLoading, onQueryChange, onSuggestionSelect, onDismissSuggestions, onInquiryClose, onInquirySubmit, onInquiryFieldChange, onStartInquiry, }) {
|
|
8
|
+
export function ProductPageWidget({ t, buttonStyling, isSearching, locationError, searchResult, inquiryValues, inquiryError, isInquirySubmitted, selectedDealerName, isManualSearchEnabled, query, suggestions, suggestionsOpen, isSuggestionsLoading, onQueryChange, onSuggestionSelect, onDismissSuggestions, onInquiryClose, onInquirySubmit, onInquiryFieldChange, onStartInquiry, }) {
|
|
9
9
|
const dealers = (searchResult?.dealers ?? []);
|
|
10
10
|
const total = searchResult?.total ?? dealers.length;
|
|
11
11
|
const inquiryFormOpen = inquiryValues != null;
|
|
12
12
|
if (inquiryFormOpen && searchResult?.ok) {
|
|
13
|
-
return (_jsx("div", { className: "jwi-flex jwi-w-full jwi-flex-col jwi-gap-3", children: _jsx(InquiryForm, { t: t, inquiryValues: inquiryValues, inquiryError: inquiryError, onInquiryClose: onInquiryClose, onInquirySubmit: onInquirySubmit, onInquiryFieldChange: onInquiryFieldChange }) }));
|
|
13
|
+
return (_jsx("div", { className: "jwi-flex jwi-w-full jwi-flex-col jwi-gap-3", children: _jsx(InquiryForm, { t: t, buttonStyling: buttonStyling, inquiryValues: inquiryValues, inquiryError: inquiryError, onInquiryClose: onInquiryClose, onInquirySubmit: onInquirySubmit, onInquiryFieldChange: onInquiryFieldChange }) }));
|
|
14
14
|
}
|
|
15
|
-
return (_jsxs("div", { className: `jwi-flex jwi-w-full jwi-flex-col jwi-gap-3 ${R10} jwi-border jwi-border-[#e6e1d7] jwi-bg-white jwi-p-6`, children: [_jsx(LocationSearch, { t: t, isManualSearchEnabled: isManualSearchEnabled, query: query, suggestions: suggestions, suggestionsOpen: suggestionsOpen, isSuggestionsLoading: isSuggestionsLoading, onQueryChange: onQueryChange, onSuggestionSelect: onSuggestionSelect, onDismissSuggestions: onDismissSuggestions }), locationError != null && !isManualSearchEnabled && (_jsx(StatusBanner, { tone: "error", children: locationError })), searchResult?.ok === false && (_jsx(StatusBanner, { tone: "error", children: searchResult.error ?? '' })), isInquirySubmitted && _jsx(StatusBanner, { tone: "success", children: t.inquirySentSuccess }), isSearching && (_jsxs("div", { className: "jwi-flex jwi-flex-col", children: [_jsx("div", { className: "jwi-w-full jwi-flex-shrink-0 jwi-border-b jwi-border-[#e6e1d7] jwi-pb-3", children: _jsx("div", { className: "jwi-h-5 jwi-w-48 jwi-animate-pulse jwi-rounded-full jwi-bg-[#ece8df]" }) }), _jsxs("div", { className: "jwi-mt-3 jwi-mr-[-12px] jwi-flex jwi-max-h-[min(60vh,480px)] jwi-flex-col jwi-gap-4 jwi-overflow-y-auto jwi-pr-[12px]", children: [_jsx(DealerCardSkeleton, {}), _jsx(DealerCardSkeleton, {}), _jsx(DealerCardSkeleton, {})] })] })), searchResult?.ok && !isSearching && (_jsx(DealerList, { dealers: dealers, total: total, selectedDealerName: selectedDealerName, t: t, onStartInquiry: onStartInquiry }))] }));
|
|
15
|
+
return (_jsxs("div", { className: `jwi-flex jwi-w-full jwi-flex-col jwi-gap-3 ${R10} jwi-border jwi-border-[#e6e1d7] jwi-bg-white jwi-p-6`, children: [_jsx(LocationSearch, { t: t, isManualSearchEnabled: isManualSearchEnabled, query: query, suggestions: suggestions, suggestionsOpen: suggestionsOpen, isSuggestionsLoading: isSuggestionsLoading, onQueryChange: onQueryChange, onSuggestionSelect: onSuggestionSelect, onDismissSuggestions: onDismissSuggestions }), locationError != null && !isManualSearchEnabled && (_jsx(StatusBanner, { tone: "error", children: locationError })), searchResult?.ok === false && (_jsx(StatusBanner, { tone: "error", children: searchResult.error ?? '' })), isInquirySubmitted && _jsx(StatusBanner, { tone: "success", children: t.inquirySentSuccess }), isSearching && (_jsxs("div", { className: "jwi-flex jwi-flex-col", children: [_jsx("div", { className: "jwi-w-full jwi-flex-shrink-0 jwi-border-b jwi-border-[#e6e1d7] jwi-pb-3", children: _jsx("div", { className: "jwi-h-5 jwi-w-48 jwi-animate-pulse jwi-rounded-full jwi-bg-[#ece8df]" }) }), _jsxs("div", { className: "jwi-mt-3 jwi-mr-[-12px] jwi-flex jwi-max-h-[min(60vh,480px)] jwi-flex-col jwi-gap-4 jwi-overflow-y-auto jwi-pr-[12px]", children: [_jsx(DealerCardSkeleton, {}), _jsx(DealerCardSkeleton, {}), _jsx(DealerCardSkeleton, {})] })] })), searchResult?.ok && !isSearching && (_jsx(DealerList, { dealers: dealers, total: total, selectedDealerName: selectedDealerName, t: t, buttonStyling: buttonStyling, onStartInquiry: onStartInquiry }))] }));
|
|
16
16
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { WidgetStrings } from '../../i18n/widgetStrings';
|
|
2
|
-
import type { DealerRecord } from '../../types';
|
|
2
|
+
import type { DealerRecord, JotulWidgetButtonStyling } from '../../types';
|
|
3
3
|
type DealerListProps = {
|
|
4
4
|
dealers: DealerRecord[];
|
|
5
5
|
total: number;
|
|
6
6
|
selectedDealerName: string | null;
|
|
7
7
|
t: WidgetStrings;
|
|
8
|
+
buttonStyling?: JotulWidgetButtonStyling;
|
|
8
9
|
onStartInquiry: (dealerName: string) => void;
|
|
9
10
|
};
|
|
10
|
-
export declare function DealerList({ dealers, total, selectedDealerName, t, onStartInquiry, }: DealerListProps): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export declare function DealerList({ dealers, total, selectedDealerName, t, buttonStyling, onStartInquiry, }: DealerListProps): import("react/jsx-runtime").JSX.Element;
|
|
11
12
|
export {};
|
|
@@ -2,14 +2,18 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { R10 } from '../../constants';
|
|
3
3
|
import { ArrowRightIcon } from '../../icons/ArrowRightIcon';
|
|
4
4
|
import { TelephoneIcon } from '../../icons/TelephoneIcon';
|
|
5
|
+
import { getWidgetPrimaryButtonPresentation } from '../../utils/widgetPrimaryButtonPresentation';
|
|
5
6
|
import { asText, formatDistance, getDealerAddressLines, getDealerKey, getDealerName, } from '../../utils';
|
|
6
|
-
export function DealerList({ dealers, total, selectedDealerName, t, onStartInquiry, }) {
|
|
7
|
+
export function DealerList({ dealers, total, selectedDealerName, t, buttonStyling, onStartInquiry, }) {
|
|
8
|
+
const inquiryCta = getWidgetPrimaryButtonPresentation(buttonStyling, 'panel', {
|
|
9
|
+
extraClassName: 'jwi-w-full jwi-max-w-full jwi-shrink-0 jwi-justify-between jwi-gap-2 md:jwi-max-w-[220px]',
|
|
10
|
+
});
|
|
7
11
|
return (_jsxs("div", { className: "jwi-flex jwi-flex-col", children: [_jsx("div", { className: "jwi--mx-6 jwi-w-auto jwi-flex-shrink-0 jwi-border-b jwi-border-[#e6e1d7] jwi-pb-3 jwi-px-6 jwi-text-sm jwi-font-medium jwi-text-[#111111]", children: t.dealersNearYou.replace('{count}', String(total)) }), _jsxs("div", { className: "jwi-relative jwi-mt-4", children: [_jsx("div", { className: "jwi-mr-[-12px] jwi-flex jwi-max-h-[min(60vh,480px)] jwi-flex-col jwi-gap-4 jwi-overflow-y-auto jwi-pr-[12px]", children: dealers.map((dealer, index) => {
|
|
8
12
|
const addressLines = getDealerAddressLines(dealer);
|
|
9
13
|
const phone = asText(dealer.phone);
|
|
10
14
|
const distance = formatDistance(dealer);
|
|
11
15
|
const dealerName = getDealerName(dealer, t.unknownDealer);
|
|
12
16
|
const isSelectedDealer = selectedDealerName === dealerName;
|
|
13
|
-
return (_jsxs("div", { className: `jwi-w-full ${R10} jwi-border jwi-border-[#e6e1d7] jwi-bg-white jwi-p-4 jwi-shadow-[0_1px_2px_rgba(17,17,17,0.03)]`, children: [_jsxs("div", { className: "jwi-flex jwi-items-start jwi-justify-between jwi-gap-3", children: [_jsx("div", { className: "jwi-min-w-0 jwi-max-w-[calc(100%-5rem)] jwi-pr-1", children: _jsx("h3", { className: "jwi-m-0 jwi-text-base jwi-font-semibold jwi-leading-snug jwi-text-[#111111]", children: dealerName }) }), distance && (_jsx("div", { className: `jwi-shrink-0 jwi-whitespace-nowrap ${R10} jwi-bg-[#fbf3db] jwi-px-2.5 jwi-py-1 jwi-text-xs jwi-font-medium jwi-leading-none jwi-text-[#111111]`, children: distance }))] }), addressLines.length > 0 && (_jsx("div", { className: "jwi-mt-3 jwi-flex jwi-flex-col jwi-gap-0.5 jwi-text-sm jwi-leading-snug jwi-text-[#111111]", children: addressLines.map((line) => (_jsx("div", { children: line }, line))) })), _jsxs("div", { className: "jwi-mt-4 jwi-flex jwi-flex-col jwi-gap-3 md:jwi-flex-row md:jwi-items-center md:jwi-justify-between", children: [_jsxs("button", { type: "button", onClick: () => onStartInquiry(dealerName), className:
|
|
17
|
+
return (_jsxs("div", { className: `jwi-w-full ${R10} jwi-border jwi-border-[#e6e1d7] jwi-bg-white jwi-p-4 jwi-shadow-[0_1px_2px_rgba(17,17,17,0.03)]`, children: [_jsxs("div", { className: "jwi-flex jwi-items-start jwi-justify-between jwi-gap-3", children: [_jsx("div", { className: "jwi-min-w-0 jwi-max-w-[calc(100%-5rem)] jwi-pr-1", children: _jsx("h3", { className: "jwi-m-0 jwi-text-base jwi-font-semibold jwi-leading-snug jwi-text-[#111111]", children: dealerName }) }), distance && (_jsx("div", { className: `jwi-shrink-0 jwi-whitespace-nowrap ${R10} jwi-bg-[#fbf3db] jwi-px-2.5 jwi-py-1 jwi-text-xs jwi-font-medium jwi-leading-none jwi-text-[#111111]`, children: distance }))] }), addressLines.length > 0 && (_jsx("div", { className: "jwi-mt-3 jwi-flex jwi-flex-col jwi-gap-0.5 jwi-text-sm jwi-leading-snug jwi-text-[#111111]", children: addressLines.map((line) => (_jsx("div", { children: line }, line))) })), _jsxs("div", { className: "jwi-mt-4 jwi-flex jwi-flex-col jwi-gap-3 md:jwi-flex-row md:jwi-items-center md:jwi-justify-between", children: [_jsxs("button", { type: "button", onClick: () => onStartInquiry(dealerName), className: inquiryCta.className, style: inquiryCta.style, children: [_jsx("span", { children: isSelectedDealer ? t.sendInquiryEditing : t.sendInquiryCta }), _jsx(ArrowRightIcon, { className: "jwi-h-[18px] jwi-w-[18px] jwi-shrink-0" })] }), phone && (_jsxs("a", { href: `tel:${phone.replace(/\s+/g, '')}`, className: "jwi-inline-flex jwi-min-w-0 jwi-items-center jwi-gap-2 jwi-text-sm jwi-font-normal jwi-tabular-nums jwi-text-[#111111] hover:jwi-underline", children: [_jsx(TelephoneIcon, {}), _jsx("span", { className: "jwi-break-all", children: phone })] }))] })] }, getDealerKey(dealer, index)));
|
|
14
18
|
}) }), _jsx("div", { "aria-hidden": true, className: "jwi-pointer-events-none jwi-absolute jwi-bottom-0 jwi-left-0 jwi-right-0 jwi-h-10 jwi-bg-gradient-to-t jwi-from-white jwi-to-transparent" })] })] }));
|
|
15
19
|
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import type { WidgetStrings } from '../../i18n/widgetStrings';
|
|
2
|
-
import type { InquiryFormValues } from '../../types';
|
|
2
|
+
import type { InquiryFormValues, JotulWidgetButtonStyling } from '../../types';
|
|
3
3
|
type InquiryFormProps = {
|
|
4
4
|
t: WidgetStrings;
|
|
5
|
+
buttonStyling?: JotulWidgetButtonStyling;
|
|
5
6
|
inquiryValues: InquiryFormValues;
|
|
6
7
|
inquiryError: string | null;
|
|
7
8
|
onInquiryClose: () => void;
|
|
8
9
|
onInquirySubmit: () => void;
|
|
9
10
|
onInquiryFieldChange: (key: keyof InquiryFormValues, value: string) => void;
|
|
10
11
|
};
|
|
11
|
-
export declare function InquiryForm({ t, inquiryValues, inquiryError, onInquiryClose, onInquirySubmit, onInquiryFieldChange, }: InquiryFormProps): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export declare function InquiryForm({ t, buttonStyling, inquiryValues, inquiryError, onInquiryClose, onInquirySubmit, onInquiryFieldChange, }: InquiryFormProps): import("react/jsx-runtime").JSX.Element;
|
|
12
13
|
export {};
|
|
@@ -2,7 +2,11 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { InquiryField } from '../InquiryField';
|
|
3
3
|
import { R10 } from '../../constants';
|
|
4
4
|
import { ArrowRightIcon } from '../../icons/ArrowRightIcon';
|
|
5
|
-
|
|
5
|
+
import { getWidgetPrimaryButtonPresentation } from '../../utils/widgetPrimaryButtonPresentation';
|
|
6
|
+
export function InquiryForm({ t, buttonStyling, inquiryValues, inquiryError, onInquiryClose, onInquirySubmit, onInquiryFieldChange, }) {
|
|
7
|
+
const submitButton = getWidgetPrimaryButtonPresentation(buttonStyling, 'panel', {
|
|
8
|
+
extraClassName: 'jwi-mt-4 jwi-w-full',
|
|
9
|
+
});
|
|
6
10
|
const trimmedProductName = inquiryValues.productName.trim();
|
|
7
11
|
const title = trimmedProductName !== ''
|
|
8
12
|
? t.sendInquiryTitleWithProduct.replace('{product}', trimmedProductName)
|
|
@@ -10,5 +14,5 @@ export function InquiryForm({ t, inquiryValues, inquiryError, onInquiryClose, on
|
|
|
10
14
|
return (_jsxs("form", { onSubmit: (event) => {
|
|
11
15
|
event.preventDefault();
|
|
12
16
|
onInquirySubmit();
|
|
13
|
-
}, className: `jwi-w-full ${R10} jwi-border jwi-border-[#e6e1d7] jwi-bg-white jwi-p-4 jwi-shadow-[0_1px_2px_rgba(17,17,17,0.03)]`, children: [_jsxs("button", { type: "button", onClick: onInquiryClose, className: "jwi-mb-3 jwi-inline-flex jwi-w-fit jwi-cursor-pointer jwi-items-center jwi-gap-1.5 jwi-border-0 jwi-bg-transparent jwi-p-0 jwi-text-left jwi-text-sm jwi-font-medium jwi-text-[#767676] hover:jwi-text-[#444444]", children: [_jsx("span", { className: "jwi-inline-flex jwi-shrink-0", style: { transform: 'scaleX(-1)' }, "aria-hidden": true, children: _jsx(ArrowRightIcon, { className: "jwi-h-[14px] jwi-w-[14px]" }) }), t.goBack] }), _jsx("input", { type: "hidden", name: "product", value: inquiryValues.productName }), _jsx("input", { type: "hidden", name: "dealer", value: inquiryValues.dealerName }), _jsxs("div", { className: "jwi-min-w-0", children: [_jsx("h3", { className: "jwi-m-0 jwi-text-base jwi-font-semibold jwi-leading-snug jwi-text-[#111111]", children: title }), _jsx("p", { className: "jwi-m-0 jwi-mt-2 jwi-text-sm jwi-leading-[1.4] jwi-text-[#767676]", children: t.dealerWillContact.replace('{dealer}', inquiryValues.dealerName) })] }), _jsxs("div", { className: "jwi-mt-4 jwi-flex jwi-flex-col jwi-gap-3", children: [_jsx(InquiryField, { label: t.fieldName, value: inquiryValues.name, onChange: (value) => onInquiryFieldChange('name', value) }), _jsx(InquiryField, { label: t.fieldEmail, type: "email", value: inquiryValues.email, onChange: (value) => onInquiryFieldChange('email', value) }), _jsx(InquiryField, { label: t.fieldPhone, type: "tel", value: inquiryValues.phone, onChange: (value) => onInquiryFieldChange('phone', value) }), _jsx(InquiryField, { label: t.fieldComment, multiline: true, value: inquiryValues.comment, onChange: (value) => onInquiryFieldChange('comment', value) })] }), inquiryError && (_jsx("div", { className: `jwi-mt-4 ${R10} jwi-border jwi-border-[#f0c7c2] jwi-bg-[#fff3f1] jwi-px-4 jwi-py-3 jwi-text-sm jwi-leading-[1.4] jwi-text-[#8f2d21]`, children: inquiryError })), _jsx("button", { type: "submit", className:
|
|
17
|
+
}, className: `jwi-w-full ${R10} jwi-border jwi-border-[#e6e1d7] jwi-bg-white jwi-p-4 jwi-shadow-[0_1px_2px_rgba(17,17,17,0.03)]`, children: [_jsxs("button", { type: "button", onClick: onInquiryClose, className: "jwi-mb-3 jwi-inline-flex jwi-w-fit jwi-cursor-pointer jwi-items-center jwi-gap-1.5 jwi-border-0 jwi-bg-transparent jwi-p-0 jwi-text-left jwi-text-sm jwi-font-medium jwi-text-[#767676] hover:jwi-text-[#444444]", children: [_jsx("span", { className: "jwi-inline-flex jwi-shrink-0", style: { transform: 'scaleX(-1)' }, "aria-hidden": true, children: _jsx(ArrowRightIcon, { className: "jwi-h-[14px] jwi-w-[14px]" }) }), t.goBack] }), _jsx("input", { type: "hidden", name: "product", value: inquiryValues.productName }), _jsx("input", { type: "hidden", name: "dealer", value: inquiryValues.dealerName }), _jsxs("div", { className: "jwi-min-w-0", children: [_jsx("h3", { className: "jwi-m-0 jwi-text-base jwi-font-semibold jwi-leading-snug jwi-text-[#111111]", children: title }), _jsx("p", { className: "jwi-m-0 jwi-mt-2 jwi-text-sm jwi-leading-[1.4] jwi-text-[#767676]", children: t.dealerWillContact.replace('{dealer}', inquiryValues.dealerName) })] }), _jsxs("div", { className: "jwi-mt-4 jwi-flex jwi-flex-col jwi-gap-3", children: [_jsx(InquiryField, { label: t.fieldName, value: inquiryValues.name, onChange: (value) => onInquiryFieldChange('name', value) }), _jsx(InquiryField, { label: t.fieldEmail, type: "email", value: inquiryValues.email, onChange: (value) => onInquiryFieldChange('email', value) }), _jsx(InquiryField, { label: t.fieldPhone, type: "tel", value: inquiryValues.phone, onChange: (value) => onInquiryFieldChange('phone', value) }), _jsx(InquiryField, { label: t.fieldComment, multiline: true, value: inquiryValues.comment, onChange: (value) => onInquiryFieldChange('comment', value) })] }), inquiryError && (_jsx("div", { className: `jwi-mt-4 ${R10} jwi-border jwi-border-[#f0c7c2] jwi-bg-[#fff3f1] jwi-px-4 jwi-py-3 jwi-text-sm jwi-leading-[1.4] jwi-text-[#8f2d21]`, children: inquiryError })), _jsx("button", { type: "submit", className: submitButton.className, style: submitButton.style, children: t.sendInquiryCta })] }));
|
|
14
18
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { checkWidgetAuthorization, normalizeWidgetLocale, searchDealersByCoordinates, searchDealersByPostalCode, JotulWidget, type CheckWidgetAuthorizationOptions, type DealerSearchResponse, type JotulWidgetLocale, type JotulWidgetProps, type JotulWidgetType, type WidgetAuthClientResponse, } from './JotulWidget';
|
|
1
|
+
export { checkWidgetAuthorization, normalizeWidgetLocale, searchDealersByCoordinates, searchDealersByPostalCode, JotulWidget, type CheckWidgetAuthorizationOptions, type DealerSearchResponse, type JotulWidgetButtonStyling, type JotulWidgetLocale, type JotulWidgetProps, type JotulWidgetStyling, type JotulWidgetType, type WidgetAuthClientResponse, } from './JotulWidget';
|
package/dist/types.d.ts
CHANGED
|
@@ -40,6 +40,15 @@ export type CheckWidgetAuthorizationOptions = {
|
|
|
40
40
|
locale?: string;
|
|
41
41
|
brands?: string[];
|
|
42
42
|
};
|
|
43
|
+
/** CSS values for primary CTA buttons (find dealer, send inquiry, etc.). */
|
|
44
|
+
export type JotulWidgetButtonStyling = {
|
|
45
|
+
borderRadius?: string;
|
|
46
|
+
backgroundColor?: string;
|
|
47
|
+
textColor?: string;
|
|
48
|
+
};
|
|
49
|
+
export type JotulWidgetStyling = {
|
|
50
|
+
button?: JotulWidgetButtonStyling;
|
|
51
|
+
};
|
|
43
52
|
export type JotulWidgetProps = {
|
|
44
53
|
type?: string;
|
|
45
54
|
endpoint?: string;
|
|
@@ -47,6 +56,7 @@ export type JotulWidgetProps = {
|
|
|
47
56
|
productName?: string;
|
|
48
57
|
locale?: string;
|
|
49
58
|
brands?: string[];
|
|
59
|
+
styling?: JotulWidgetStyling;
|
|
50
60
|
};
|
|
51
61
|
export type DealerRecord = Record<string, unknown>;
|
|
52
62
|
export type InquiryFormValues = {
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { CSSProperties } from 'react';
|
|
2
|
+
import type { JotulWidgetButtonStyling } from '../types';
|
|
3
|
+
export type PrimaryButtonVariant = 'hero' | 'panel';
|
|
4
|
+
/**
|
|
5
|
+
* Primary CTA buttons share the same visual tokens; optional `styling.button`
|
|
6
|
+
* overrides border radius, background, and text color (CSS values).
|
|
7
|
+
*/
|
|
8
|
+
export declare function getWidgetPrimaryButtonPresentation(buttonStyling: JotulWidgetButtonStyling | undefined, variant: PrimaryButtonVariant, options?: {
|
|
9
|
+
disabledWait?: boolean;
|
|
10
|
+
extraClassName?: string;
|
|
11
|
+
}): {
|
|
12
|
+
className: string;
|
|
13
|
+
style: CSSProperties;
|
|
14
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
const HERO_LAYOUT = 'jwi-inline-flex jwi-w-full jwi-min-h-[56px] jwi-cursor-pointer jwi-items-center jwi-justify-center jwi-border-0 jwi-px-7 jwi-text-base jwi-font-medium';
|
|
2
|
+
const PANEL_LAYOUT = 'jwi-inline-flex jwi-min-h-[48px] jwi-cursor-pointer jwi-items-center jwi-justify-center jwi-border-0 jwi-px-4 jwi-text-sm jwi-font-medium';
|
|
3
|
+
/**
|
|
4
|
+
* Primary CTA buttons share the same visual tokens; optional `styling.button`
|
|
5
|
+
* overrides border radius, background, and text color (CSS values).
|
|
6
|
+
*/
|
|
7
|
+
export function getWidgetPrimaryButtonPresentation(buttonStyling, variant, options) {
|
|
8
|
+
const b = buttonStyling;
|
|
9
|
+
const style = {};
|
|
10
|
+
if (b?.borderRadius?.trim()) {
|
|
11
|
+
style.borderRadius = b.borderRadius.trim();
|
|
12
|
+
}
|
|
13
|
+
if (b?.backgroundColor?.trim()) {
|
|
14
|
+
style.backgroundColor = b.backgroundColor.trim();
|
|
15
|
+
}
|
|
16
|
+
if (b?.textColor?.trim()) {
|
|
17
|
+
style.color = b.textColor.trim();
|
|
18
|
+
}
|
|
19
|
+
const layout = variant === 'hero' ? HERO_LAYOUT : PANEL_LAYOUT;
|
|
20
|
+
const parts = [layout, options?.extraClassName?.trim()].filter((p) => typeof p === 'string' && p.length > 0);
|
|
21
|
+
if (!b?.borderRadius?.trim()) {
|
|
22
|
+
parts.push('jwi-rounded-[10px]');
|
|
23
|
+
}
|
|
24
|
+
if (!b?.backgroundColor?.trim()) {
|
|
25
|
+
parts.push('jwi-bg-[#ef2b18] hover:jwi-bg-[#d92817]');
|
|
26
|
+
}
|
|
27
|
+
if (!b?.textColor?.trim()) {
|
|
28
|
+
parts.push('jwi-text-white');
|
|
29
|
+
}
|
|
30
|
+
if (options?.disabledWait &&
|
|
31
|
+
variant === 'hero' &&
|
|
32
|
+
!b?.backgroundColor?.trim()) {
|
|
33
|
+
parts.push('disabled:jwi-cursor-wait disabled:hover:jwi-bg-[#ef2b18]');
|
|
34
|
+
}
|
|
35
|
+
return { className: parts.join(' '), style };
|
|
36
|
+
}
|