@burdenoff/website-sdk 2026.520.2 → 2026.520.3
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/components/contact.d.mts +69 -2
- package/dist/components/contact.d.ts +69 -2
- package/dist/components/contact.js +83 -0
- package/dist/components/contact.js.map +1 -1
- package/dist/components/contact.mjs +83 -1
- package/dist/components/contact.mjs.map +1 -1
- package/dist/index.d.mts +5 -2
- package/dist/index.d.ts +5 -2
- package/dist/index.js +84 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +83 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -36,6 +36,39 @@ interface ContactOption {
|
|
|
36
36
|
buttonText: string;
|
|
37
37
|
buttonLink: string;
|
|
38
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* One entry in the contact-form Category dropdown. Each product website
|
|
41
|
+
* supplies its own allow-list via the `categories` prop so the
|
|
42
|
+
* vocabulary stays product-appropriate (e.g. VibeControls uses
|
|
43
|
+
* `plugin-developer`, a manufacturing site uses `dealer`). The backend
|
|
44
|
+
* accepts whatever `value` string is sent and persists it directly.
|
|
45
|
+
*
|
|
46
|
+
* `value` flows to the backend; `label` is what the user sees.
|
|
47
|
+
*/
|
|
48
|
+
interface ContactCategory {
|
|
49
|
+
/** Stored on the server. Short, kebab-case is conventional. */
|
|
50
|
+
value: string;
|
|
51
|
+
/** Human-readable label shown in the dropdown. */
|
|
52
|
+
label: string;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Conservative starter category list — Burdenoff-generic vocabulary
|
|
56
|
+
* (General / Sales / Support / Partnership / Press / Careers / Security).
|
|
57
|
+
*
|
|
58
|
+
* **Not** applied by default: pass it explicitly to opt in:
|
|
59
|
+
*
|
|
60
|
+
* ```tsx
|
|
61
|
+
* <ContactPage
|
|
62
|
+
* …
|
|
63
|
+
* categories={DEFAULT_CONTACT_CATEGORIES}
|
|
64
|
+
* />
|
|
65
|
+
* ```
|
|
66
|
+
*
|
|
67
|
+
* The component default for `categories` is `[]` (no dropdown) so this
|
|
68
|
+
* SDK release is backward-compatible with existing consumers that
|
|
69
|
+
* don't yet know about the field — see the prop docs.
|
|
70
|
+
*/
|
|
71
|
+
declare const DEFAULT_CONTACT_CATEGORIES: ContactCategory[];
|
|
39
72
|
interface ContactPageProps {
|
|
40
73
|
/** Product name. Falls back to SDK config productId if not provided. */
|
|
41
74
|
productName?: string;
|
|
@@ -55,6 +88,40 @@ interface ContactPageProps {
|
|
|
55
88
|
heroDescription?: string;
|
|
56
89
|
/** Additional contact options */
|
|
57
90
|
additionalOptions?: ContactOption[];
|
|
91
|
+
/**
|
|
92
|
+
* Inquiry-type dropdown allow-list. **Defaults to `[]`** — the
|
|
93
|
+
* dropdown does not render unless the consumer explicitly opts in.
|
|
94
|
+
*
|
|
95
|
+
* Two ways to opt in:
|
|
96
|
+
*
|
|
97
|
+
* ```tsx
|
|
98
|
+
* // 1. Provide a product-specific list
|
|
99
|
+
* <ContactPage categories={[{ value: 'sales', label: 'Sales' }, …]} />
|
|
100
|
+
*
|
|
101
|
+
* // 2. Or use the conservative SDK starter list
|
|
102
|
+
* <ContactPage categories={DEFAULT_CONTACT_CATEGORIES} />
|
|
103
|
+
* ```
|
|
104
|
+
*
|
|
105
|
+
* Default is intentionally empty (not `DEFAULT_CONTACT_CATEGORIES`)
|
|
106
|
+
* to keep this SDK release backward-compatible with existing
|
|
107
|
+
* consumers that don't yet wire `categories` — they get zero
|
|
108
|
+
* behavior change.
|
|
109
|
+
*
|
|
110
|
+
* Typed `readonly` because the component never mutates the array;
|
|
111
|
+
* lets product sites pass an `as const`-frozen config without an
|
|
112
|
+
* extra `[...spread]` at the call site.
|
|
113
|
+
*/
|
|
114
|
+
categories?: readonly ContactCategory[];
|
|
115
|
+
/** Label shown above the category dropdown. */
|
|
116
|
+
categoryLabel?: string;
|
|
117
|
+
/** Placeholder text for the unselected state of the dropdown. */
|
|
118
|
+
categoryPlaceholder?: string;
|
|
119
|
+
/**
|
|
120
|
+
* Whether selecting a category is required to submit. Defaults to
|
|
121
|
+
* `true` — the whole point of the dropdown is routing, so users
|
|
122
|
+
* self-triage instead of pushing that work onto support.
|
|
123
|
+
*/
|
|
124
|
+
categoryRequired?: boolean;
|
|
58
125
|
/** SEO metadata */
|
|
59
126
|
seo?: {
|
|
60
127
|
title?: string;
|
|
@@ -64,6 +131,6 @@ interface ContactPageProps {
|
|
|
64
131
|
url?: string;
|
|
65
132
|
};
|
|
66
133
|
}
|
|
67
|
-
declare function ContactPage({ productName, recaptchaSiteKey, contactEmail, contactPhone, officeAddress, responseTime, heroTitle, heroDescription, additionalOptions, seo, }: ContactPageProps): react_jsx_runtime.JSX.Element;
|
|
134
|
+
declare function ContactPage({ productName, recaptchaSiteKey, contactEmail, contactPhone, officeAddress, responseTime, heroTitle, heroDescription, categories, categoryLabel, categoryPlaceholder, categoryRequired, additionalOptions, seo, }: ContactPageProps): react_jsx_runtime.JSX.Element;
|
|
68
135
|
|
|
69
|
-
export { ContactPage, type ContactPageProps };
|
|
136
|
+
export { type ContactCategory, ContactPage, type ContactPageProps, DEFAULT_CONTACT_CATEGORIES };
|
|
@@ -36,6 +36,39 @@ interface ContactOption {
|
|
|
36
36
|
buttonText: string;
|
|
37
37
|
buttonLink: string;
|
|
38
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* One entry in the contact-form Category dropdown. Each product website
|
|
41
|
+
* supplies its own allow-list via the `categories` prop so the
|
|
42
|
+
* vocabulary stays product-appropriate (e.g. VibeControls uses
|
|
43
|
+
* `plugin-developer`, a manufacturing site uses `dealer`). The backend
|
|
44
|
+
* accepts whatever `value` string is sent and persists it directly.
|
|
45
|
+
*
|
|
46
|
+
* `value` flows to the backend; `label` is what the user sees.
|
|
47
|
+
*/
|
|
48
|
+
interface ContactCategory {
|
|
49
|
+
/** Stored on the server. Short, kebab-case is conventional. */
|
|
50
|
+
value: string;
|
|
51
|
+
/** Human-readable label shown in the dropdown. */
|
|
52
|
+
label: string;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Conservative starter category list — Burdenoff-generic vocabulary
|
|
56
|
+
* (General / Sales / Support / Partnership / Press / Careers / Security).
|
|
57
|
+
*
|
|
58
|
+
* **Not** applied by default: pass it explicitly to opt in:
|
|
59
|
+
*
|
|
60
|
+
* ```tsx
|
|
61
|
+
* <ContactPage
|
|
62
|
+
* …
|
|
63
|
+
* categories={DEFAULT_CONTACT_CATEGORIES}
|
|
64
|
+
* />
|
|
65
|
+
* ```
|
|
66
|
+
*
|
|
67
|
+
* The component default for `categories` is `[]` (no dropdown) so this
|
|
68
|
+
* SDK release is backward-compatible with existing consumers that
|
|
69
|
+
* don't yet know about the field — see the prop docs.
|
|
70
|
+
*/
|
|
71
|
+
declare const DEFAULT_CONTACT_CATEGORIES: ContactCategory[];
|
|
39
72
|
interface ContactPageProps {
|
|
40
73
|
/** Product name. Falls back to SDK config productId if not provided. */
|
|
41
74
|
productName?: string;
|
|
@@ -55,6 +88,40 @@ interface ContactPageProps {
|
|
|
55
88
|
heroDescription?: string;
|
|
56
89
|
/** Additional contact options */
|
|
57
90
|
additionalOptions?: ContactOption[];
|
|
91
|
+
/**
|
|
92
|
+
* Inquiry-type dropdown allow-list. **Defaults to `[]`** — the
|
|
93
|
+
* dropdown does not render unless the consumer explicitly opts in.
|
|
94
|
+
*
|
|
95
|
+
* Two ways to opt in:
|
|
96
|
+
*
|
|
97
|
+
* ```tsx
|
|
98
|
+
* // 1. Provide a product-specific list
|
|
99
|
+
* <ContactPage categories={[{ value: 'sales', label: 'Sales' }, …]} />
|
|
100
|
+
*
|
|
101
|
+
* // 2. Or use the conservative SDK starter list
|
|
102
|
+
* <ContactPage categories={DEFAULT_CONTACT_CATEGORIES} />
|
|
103
|
+
* ```
|
|
104
|
+
*
|
|
105
|
+
* Default is intentionally empty (not `DEFAULT_CONTACT_CATEGORIES`)
|
|
106
|
+
* to keep this SDK release backward-compatible with existing
|
|
107
|
+
* consumers that don't yet wire `categories` — they get zero
|
|
108
|
+
* behavior change.
|
|
109
|
+
*
|
|
110
|
+
* Typed `readonly` because the component never mutates the array;
|
|
111
|
+
* lets product sites pass an `as const`-frozen config without an
|
|
112
|
+
* extra `[...spread]` at the call site.
|
|
113
|
+
*/
|
|
114
|
+
categories?: readonly ContactCategory[];
|
|
115
|
+
/** Label shown above the category dropdown. */
|
|
116
|
+
categoryLabel?: string;
|
|
117
|
+
/** Placeholder text for the unselected state of the dropdown. */
|
|
118
|
+
categoryPlaceholder?: string;
|
|
119
|
+
/**
|
|
120
|
+
* Whether selecting a category is required to submit. Defaults to
|
|
121
|
+
* `true` — the whole point of the dropdown is routing, so users
|
|
122
|
+
* self-triage instead of pushing that work onto support.
|
|
123
|
+
*/
|
|
124
|
+
categoryRequired?: boolean;
|
|
58
125
|
/** SEO metadata */
|
|
59
126
|
seo?: {
|
|
60
127
|
title?: string;
|
|
@@ -64,6 +131,6 @@ interface ContactPageProps {
|
|
|
64
131
|
url?: string;
|
|
65
132
|
};
|
|
66
133
|
}
|
|
67
|
-
declare function ContactPage({ productName, recaptchaSiteKey, contactEmail, contactPhone, officeAddress, responseTime, heroTitle, heroDescription, additionalOptions, seo, }: ContactPageProps): react_jsx_runtime.JSX.Element;
|
|
134
|
+
declare function ContactPage({ productName, recaptchaSiteKey, contactEmail, contactPhone, officeAddress, responseTime, heroTitle, heroDescription, categories, categoryLabel, categoryPlaceholder, categoryRequired, additionalOptions, seo, }: ContactPageProps): react_jsx_runtime.JSX.Element;
|
|
68
135
|
|
|
69
|
-
export { ContactPage, type ContactPageProps };
|
|
136
|
+
export { type ContactCategory, ContactPage, type ContactPageProps, DEFAULT_CONTACT_CATEGORIES };
|
|
@@ -322,6 +322,28 @@ var Label = React__namespace.forwardRef(({ className, ...props }, ref) => /* @__
|
|
|
322
322
|
}
|
|
323
323
|
));
|
|
324
324
|
Label.displayName = LabelPrimitive__namespace.Root.displayName;
|
|
325
|
+
var Select = React__namespace.forwardRef(({ className, children, ...props }, ref) => {
|
|
326
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
327
|
+
"select",
|
|
328
|
+
{
|
|
329
|
+
className: cn(
|
|
330
|
+
"flex h-9 w-full appearance-none rounded-md border border-input bg-transparent bg-[length:1rem_1rem] bg-[right_0.75rem_center] bg-no-repeat px-3 py-1 pr-8 text-base shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
|
331
|
+
// Inline SVG chevron: SVG inside a `background-image: url(data:…)`
|
|
332
|
+
// does NOT inherit `currentColor` from the host element (the SVG is
|
|
333
|
+
// its own document with no parent CSS context), so the stroke is
|
|
334
|
+
// hardcoded to a muted slate-400 (#94a3b8). Matches the muted
|
|
335
|
+
// foreground token visually in both light and dark themes well
|
|
336
|
+
// enough for a passive chevron — addresses #9 review feedback.
|
|
337
|
+
`bg-[url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>")]`,
|
|
338
|
+
className
|
|
339
|
+
),
|
|
340
|
+
ref,
|
|
341
|
+
...props,
|
|
342
|
+
children
|
|
343
|
+
}
|
|
344
|
+
);
|
|
345
|
+
});
|
|
346
|
+
Select.displayName = "Select";
|
|
325
347
|
var Textarea = React__namespace.forwardRef(({ className, ...props }, ref) => {
|
|
326
348
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
327
349
|
"textarea",
|
|
@@ -336,6 +358,15 @@ var Textarea = React__namespace.forwardRef(({ className, ...props }, ref) => {
|
|
|
336
358
|
);
|
|
337
359
|
});
|
|
338
360
|
Textarea.displayName = "Textarea";
|
|
361
|
+
var DEFAULT_CONTACT_CATEGORIES = [
|
|
362
|
+
{ value: "general", label: "General enquiry" },
|
|
363
|
+
{ value: "sales", label: "Sales" },
|
|
364
|
+
{ value: "support", label: "Support" },
|
|
365
|
+
{ value: "partnership", label: "Partnership" },
|
|
366
|
+
{ value: "press", label: "Press / media" },
|
|
367
|
+
{ value: "careers", label: "Careers" },
|
|
368
|
+
{ value: "security", label: "Security disclosure" }
|
|
369
|
+
];
|
|
339
370
|
var SUBMIT_CONTACT_INQUIRY_MUTATION = (
|
|
340
371
|
/* GraphQL */
|
|
341
372
|
`
|
|
@@ -357,6 +388,12 @@ async function submitContactForm(client, data, productId) {
|
|
|
357
388
|
subject: data.subject,
|
|
358
389
|
message: data.message,
|
|
359
390
|
productId,
|
|
391
|
+
// Send `category` only when the user actually picked one. Older
|
|
392
|
+
// backend deployments without the `category` field in the
|
|
393
|
+
// `SubmitContactInquiryInput` schema would reject any unknown
|
|
394
|
+
// field; spreading conditionally keeps the SDK forward-
|
|
395
|
+
// compatible.
|
|
396
|
+
...data.category ? { category: data.category } : {},
|
|
360
397
|
...data.recaptchaToken ? { recaptchaToken: data.recaptchaToken } : {}
|
|
361
398
|
}
|
|
362
399
|
});
|
|
@@ -395,6 +432,16 @@ function ContactPage({
|
|
|
395
432
|
responseTime = "We typically respond within 24 hours",
|
|
396
433
|
heroTitle = "Get in Touch",
|
|
397
434
|
heroDescription = "Have questions about {productName}? We're here to help. Reach out to our team and we'll get back to you as soon as possible.",
|
|
435
|
+
// Backward-compatibility: default to `[]` so existing consumers
|
|
436
|
+
// (fluidgrids/burdenoff/algoshred websites) that don't pass
|
|
437
|
+
// `categories` continue to render with NO dropdown — same behavior
|
|
438
|
+
// they had before this SDK version. To opt in, pass an explicit
|
|
439
|
+
// `categories={…}` array (or the exported `DEFAULT_CONTACT_CATEGORIES`
|
|
440
|
+
// constant for the sane Burdenoff-generic vocabulary).
|
|
441
|
+
categories = [],
|
|
442
|
+
categoryLabel = "Category",
|
|
443
|
+
categoryPlaceholder = "Select a category",
|
|
444
|
+
categoryRequired = true,
|
|
398
445
|
additionalOptions = [
|
|
399
446
|
{
|
|
400
447
|
title: "Sales Inquiries",
|
|
@@ -438,11 +485,19 @@ function ContactPage({
|
|
|
438
485
|
const form = e.currentTarget;
|
|
439
486
|
try {
|
|
440
487
|
const formData = new FormData(form);
|
|
488
|
+
const showCategory = categories.length > 0;
|
|
489
|
+
const rawCategory = showCategory ? (formData.get("category") ?? "").trim() : "";
|
|
490
|
+
if (showCategory && categoryRequired && !rawCategory) {
|
|
491
|
+
sonner.toast.error("Please select a category");
|
|
492
|
+
setIsSubmitting(false);
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
441
495
|
const contactData = {
|
|
442
496
|
firstName: formData.get("firstName"),
|
|
443
497
|
lastName: formData.get("lastName"),
|
|
444
498
|
email: formData.get("email"),
|
|
445
499
|
company: formData.get("company"),
|
|
500
|
+
category: rawCategory || void 0,
|
|
446
501
|
subject: formData.get("subject"),
|
|
447
502
|
message: formData.get("message"),
|
|
448
503
|
recaptchaToken
|
|
@@ -611,6 +666,33 @@ function ContactPage({
|
|
|
611
666
|
}
|
|
612
667
|
)
|
|
613
668
|
] }),
|
|
669
|
+
categories.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
670
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
671
|
+
Label,
|
|
672
|
+
{
|
|
673
|
+
htmlFor: "category",
|
|
674
|
+
className: "text-sm sm:text-base",
|
|
675
|
+
children: [
|
|
676
|
+
categoryLabel,
|
|
677
|
+
categoryRequired ? " *" : ""
|
|
678
|
+
]
|
|
679
|
+
}
|
|
680
|
+
),
|
|
681
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
682
|
+
Select,
|
|
683
|
+
{
|
|
684
|
+
id: "category",
|
|
685
|
+
name: "category",
|
|
686
|
+
required: categoryRequired,
|
|
687
|
+
defaultValue: "",
|
|
688
|
+
className: "text-sm sm:text-base",
|
|
689
|
+
children: [
|
|
690
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "", disabled: categoryRequired, children: categoryPlaceholder }),
|
|
691
|
+
categories.map((c) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: c.value, children: c.label }, c.value))
|
|
692
|
+
]
|
|
693
|
+
}
|
|
694
|
+
)
|
|
695
|
+
] }),
|
|
614
696
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
615
697
|
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "subject", className: "text-sm sm:text-base", children: "Subject *" }),
|
|
616
698
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -712,5 +794,6 @@ function ContactPage({
|
|
|
712
794
|
}
|
|
713
795
|
|
|
714
796
|
exports.ContactPage = ContactPage;
|
|
797
|
+
exports.DEFAULT_CONTACT_CATEGORIES = DEFAULT_CONTACT_CATEGORIES;
|
|
715
798
|
//# sourceMappingURL=contact.js.map
|
|
716
799
|
//# sourceMappingURL=contact.js.map
|