@usgb/forms 0.1.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +255 -72
- package/dist/forms-manifest.json +249 -0
- package/dist/index.js +1032 -31
- package/dist/src/contract/collectContext.d.ts +9 -0
- package/dist/src/contract/collectContext.d.ts.map +1 -0
- package/dist/src/contract/createStubAdapter.d.ts +9 -0
- package/dist/src/contract/createStubAdapter.d.ts.map +1 -0
- package/dist/src/contract/types.d.ts +90 -0
- package/dist/src/contract/types.d.ts.map +1 -0
- package/dist/src/definitions/consents.d.ts +37 -0
- package/dist/src/definitions/consents.d.ts.map +1 -0
- package/dist/src/definitions/fields.d.ts +19 -0
- package/dist/src/definitions/fields.d.ts.map +1 -0
- package/dist/src/definitions/index.d.ts +7 -0
- package/dist/src/definitions/index.d.ts.map +1 -0
- package/dist/src/definitions/manifest.d.ts +8 -0
- package/dist/src/definitions/manifest.d.ts.map +1 -0
- package/dist/src/definitions/types.d.ts +77 -0
- package/dist/src/definitions/types.d.ts.map +1 -0
- package/dist/src/form/FormShell.d.ts +10 -0
- package/dist/src/form/FormShell.d.ts.map +1 -0
- package/dist/src/form/RegisteredTextField.d.ts +14 -0
- package/dist/src/form/RegisteredTextField.d.ts.map +1 -0
- package/dist/src/form/UsgbForm.d.ts +25 -0
- package/dist/src/form/UsgbForm.d.ts.map +1 -0
- package/dist/src/form/chunkFields.d.ts +17 -0
- package/dist/src/form/chunkFields.d.ts.map +1 -0
- package/dist/src/form/kinds/LeadKindForm.d.ts +4 -0
- package/dist/src/form/kinds/LeadKindForm.d.ts.map +1 -0
- package/dist/src/form/kinds/NewsletterKindForm.d.ts +4 -0
- package/dist/src/form/kinds/NewsletterKindForm.d.ts.map +1 -0
- package/dist/src/form/kinds/index.d.ts +6 -0
- package/dist/src/form/kinds/index.d.ts.map +1 -0
- package/dist/src/form/kinds/types.d.ts +11 -0
- package/dist/src/form/kinds/types.d.ts.map +1 -0
- package/dist/src/form/useUsgbFormSession.d.ts +41 -0
- package/dist/src/form/useUsgbFormSession.d.ts.map +1 -0
- package/dist/src/index.d.ts +14 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/ui/Button.d.ts +7 -0
- package/dist/src/ui/Button.d.ts.map +1 -0
- package/dist/src/ui/ConsentField.d.ts +9 -0
- package/dist/src/ui/ConsentField.d.ts.map +1 -0
- package/dist/src/ui/FieldError.d.ts +8 -0
- package/dist/src/ui/FieldError.d.ts.map +1 -0
- package/dist/src/ui/FieldLabel.d.ts +9 -0
- package/dist/src/ui/FieldLabel.d.ts.map +1 -0
- package/dist/src/ui/TextField.d.ts +19 -0
- package/dist/src/ui/TextField.d.ts.map +1 -0
- package/dist/src/ui/icons.d.ts +4 -0
- package/dist/src/ui/icons.d.ts.map +1 -0
- package/dist/usgb-forms.1.0.0.js +44 -0
- package/dist/usgb-forms.css +574 -0
- package/dist/usgb-forms.js +44 -0
- package/forms-manifest.json +249 -0
- package/package.json +51 -46
- package/dist/index.cjs +0 -64
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -15
- package/dist/index.d.ts +0 -15
- package/dist/index.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,112 +1,295 @@
|
|
|
1
1
|
# @usgb/forms
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Shared lead and newsletter forms for the **PWA** (React) and **WordPress** (Web Component) hosts.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
You pick a predefined `formId`. The package owns fields, validation, consent copy, tracking keys, and layout. You own the submit endpoint, legal-document URLs, heading/CTA copy, and thank-you behavior.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- Dual ESM/CJS build output in `dist/`
|
|
9
|
-
- CI on pull requests
|
|
10
|
-
- Publish to npm on every push to `main` via OIDC (no git tags)
|
|
7
|
+
## What you get
|
|
11
8
|
|
|
12
|
-
|
|
9
|
+
| Artifact | Path / export | Who uses it |
|
|
10
|
+
| ------------- | --------------------------------------------------------------- | ----------------------------------- |
|
|
11
|
+
| React package | `@usgb/forms` → `dist/index.js` | PWA / any React host |
|
|
12
|
+
| Stylesheet | `@usgb/forms/usgb-forms.css` | **Required** for React hosts |
|
|
13
|
+
| Web Component | `dist/usgb-forms.js` (also versioned `usgb-forms.<version>.js`) | WordPress and other non-React hosts |
|
|
14
|
+
| Catalog | `@usgb/forms/manifest` → `forms-manifest.json` | CMS pickers, docs, tooling |
|
|
15
|
+
|
|
16
|
+
The Web Component script injects the same CSS once on load. React hosts must import the stylesheet themselves.
|
|
17
|
+
|
|
18
|
+
## Mental model
|
|
19
|
+
|
|
20
|
+
| You pass | Package already decided |
|
|
21
|
+
| -------------------------------- | ------------------------------------------------------------------------------------- |
|
|
22
|
+
| `formId` | Fields, required/optional rules, consent bundle, tracking set, layout family (`kind`) |
|
|
23
|
+
| `adapter.submit` | Where the payload goes (never an attribute or hardcoded URL) |
|
|
24
|
+
| `legalUrls` / `*-url` | Hrefs for package-owned consent copy |
|
|
25
|
+
| `heading`, `body`, `ctaLabel` | Marketing copy around the form |
|
|
26
|
+
| `successMessage` or `successUrl` | Thank-you UX after accept |
|
|
27
|
+
|
|
28
|
+
Hosts **must not** invent field lists, consent wording, or tracking keys. New forms are new catalog entries in this package, not host-built schemas.
|
|
29
|
+
|
|
30
|
+
Use `listFormDefinitions()` (or the manifest) when a CMS needs a picker of available `formId`s. Deeper catalog rules: [`src/definitions/context.md`](src/definitions/context.md).
|
|
31
|
+
|
|
32
|
+
## Available forms
|
|
33
|
+
|
|
34
|
+
| `formId` | Kind | Fields | Consent | Variants |
|
|
35
|
+
| -------------------- | ------------ | --------------------------------------------------------- | ------------------------------ | ------------------------------------------------------- |
|
|
36
|
+
| `main-investors-kit` | `lead` | First name, last name, email (required); phone (optional) | TCPA checkbox (`lead-tcpa` v1) | `dense`, `large`, `sidebar`, plus optional `two-column` |
|
|
37
|
+
| `newsletter` | `newsletter` | Email only | None | None — omit `variants` / `variant` |
|
|
38
|
+
|
|
39
|
+
Appearances for both: `light` | `navy`.
|
|
40
|
+
|
|
41
|
+
`kind` is the layout family (lead grid vs inline newsletter row). The root exposes `data-kind` for CSS. Several catalog forms can share one kind (e.g. another lead kit that reuses the lead layout).
|
|
42
|
+
|
|
43
|
+
## Install
|
|
44
|
+
|
|
45
|
+
Registry package name, scope, and CDN base URL are **TBD** — examples below use the working package name `@usgb/forms` and a placeholder CDN host. Replace them when publishing is finalized.
|
|
46
|
+
|
|
47
|
+
### npm (React / PWA)
|
|
13
48
|
|
|
14
49
|
```bash
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
npm
|
|
50
|
+
yarn add @usgb/forms
|
|
51
|
+
# or
|
|
52
|
+
npm install @usgb/forms
|
|
18
53
|
```
|
|
19
54
|
|
|
20
|
-
|
|
55
|
+
Then import the component and stylesheet:
|
|
21
56
|
|
|
22
|
-
|
|
57
|
+
```ts
|
|
58
|
+
import { UsgbForm } from '@usgb/forms'
|
|
59
|
+
import '@usgb/forms/usgb-forms.css'
|
|
60
|
+
```
|
|
23
61
|
|
|
24
|
-
|
|
62
|
+
Peer dependency: `react` and `react-dom` `^18` or `^19`.
|
|
25
63
|
|
|
26
|
-
|
|
64
|
+
### CDN (Web Component / WordPress)
|
|
27
65
|
|
|
28
|
-
|
|
29
|
-
- npm 11.5.1+
|
|
30
|
-
- GitHub-hosted runners (self-hosted runners are not supported)
|
|
31
|
-
- A public GitHub repository if you want automatic provenance attestations
|
|
66
|
+
Load the built IIFE (styles inject themselves):
|
|
32
67
|
|
|
33
|
-
|
|
68
|
+
```html
|
|
69
|
+
<script src="https://cdn.example.com/usgb-forms/usgb-forms.1.0.0.js"></script>
|
|
70
|
+
```
|
|
34
71
|
|
|
35
|
-
|
|
72
|
+
Exact CDN hostname, path, and versioning scheme are **TBD**. Prefer a versioned filename (`usgb-forms.<version>.js`) so hosts can pin releases.
|
|
73
|
+
|
|
74
|
+
Until the package is published, you can still develop against a local checkout (`yarn add file:../usgb-forms` or `yarn link`).
|
|
75
|
+
|
|
76
|
+
## React (PWA)
|
|
77
|
+
|
|
78
|
+
```tsx
|
|
79
|
+
import { UsgbForm, createStubAdapter, PWA_LEGAL_URLS } from '@usgb/forms'
|
|
80
|
+
import '@usgb/forms/usgb-forms.css'
|
|
81
|
+
;<UsgbForm
|
|
82
|
+
formId="main-investors-kit"
|
|
83
|
+
appearance="navy"
|
|
84
|
+
variants={['large', 'two-column']}
|
|
85
|
+
heading="Get My Free Guide"
|
|
86
|
+
body="Enter your details to receive the Main Investors Kit."
|
|
87
|
+
ctaLabel="GET MY FREE GUIDE"
|
|
88
|
+
source="cms-home"
|
|
89
|
+
campaign="spring-kit"
|
|
90
|
+
legalUrls={PWA_LEGAL_URLS}
|
|
91
|
+
successMessage="Thanks — we will send your kit shortly."
|
|
92
|
+
adapter={yourHostAdapter}
|
|
93
|
+
onAccepted={(payload) => {
|
|
94
|
+
/* analytics bridge */
|
|
95
|
+
}}
|
|
96
|
+
onFailed={(payload, message) => {
|
|
97
|
+
/* error bridge */
|
|
98
|
+
}}
|
|
99
|
+
/>
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Newsletter (no consent, no variants):
|
|
103
|
+
|
|
104
|
+
```tsx
|
|
105
|
+
<UsgbForm
|
|
106
|
+
formId="newsletter"
|
|
107
|
+
appearance="light"
|
|
108
|
+
heading="Subscribe"
|
|
109
|
+
ctaLabel="SUBSCRIBE"
|
|
110
|
+
adapter={yourHostAdapter}
|
|
111
|
+
/>
|
|
112
|
+
```
|
|
36
113
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
114
|
+
### React props
|
|
115
|
+
|
|
116
|
+
| Prop | Required | Role |
|
|
117
|
+
| ------------------------- | -------------------------- | --------------------------------------------------------------------------------------------------- |
|
|
118
|
+
| `formId` | yes | Catalog key (`main-investors-kit`, `newsletter`, …) |
|
|
119
|
+
| `adapter` | yes | `HostAdapter` with `host`, `getTrackingHints()`, `submit()` |
|
|
120
|
+
| `appearance` | no | `light` (default) or `navy` |
|
|
121
|
+
| `variants` | no | Lead only. Default `['dense']`. One of `dense` \| `large` \| `sidebar`, optionally add `two-column` |
|
|
122
|
+
| `heading` / `body` | no | Title and supporting copy |
|
|
123
|
+
| `ctaLabel` | no | Submit button label |
|
|
124
|
+
| `source` / `campaign` | no | Placement / campaign context in the payload |
|
|
125
|
+
| `legalUrls` | when consent requires them | Host CMS paths for legal links in consent copy |
|
|
126
|
+
| `successMessage` | no | Inline thank-you when `successUrl` is omitted |
|
|
127
|
+
| `successUrl` | no | Redirect after accept (analytics / `onAccepted` are invoked first; see Success behavior) |
|
|
128
|
+
| `analytics` | no | `(event) => void` for view / validation / submit / success / failure |
|
|
129
|
+
| `className` | no | Extra class on `.usgb-form` |
|
|
130
|
+
| `onAccepted` / `onFailed` | no | Callbacks with the submission payload |
|
|
131
|
+
|
|
132
|
+
## Web Component (WordPress)
|
|
133
|
+
|
|
134
|
+
Load one script. Styles are injected automatically.
|
|
135
|
+
|
|
136
|
+
````html
|
|
137
|
+
<script src="https://cdn.example.com/usgb-forms/usgb-forms.1.0.0.js"></script>
|
|
138
|
+
<usgb-form
|
|
139
|
+
```
|
|
140
|
+
form-id="main-investors-kit"
|
|
141
|
+
appearance="navy"
|
|
142
|
+
variant="large two-column"
|
|
143
|
+
heading="Get My Free Guide"
|
|
144
|
+
cta="GET MY FREE GUIDE"
|
|
145
|
+
source="cms-home"
|
|
146
|
+
client-agreement-url="/client-agreement/"
|
|
147
|
+
privacy-policy-url="/privacy-policy/"
|
|
148
|
+
success-message="Thanks — we will send your kit shortly."
|
|
149
|
+
></usgb-form>
|
|
150
|
+
````
|
|
151
|
+
|
|
152
|
+
Submit is **not** an attribute. Markup alone uses a stub adapter. Assign a real `HostAdapter` in script:
|
|
153
|
+
|
|
154
|
+
```html
|
|
155
|
+
<script>
|
|
156
|
+
const el = document.querySelector('usgb-form')
|
|
157
|
+
el.adapter = {
|
|
158
|
+
host: 'wordpress',
|
|
159
|
+
getTrackingHints() {
|
|
160
|
+
// Cookies, UTMs, click ids — keys must match the package tracking registry
|
|
161
|
+
return {}
|
|
162
|
+
},
|
|
163
|
+
async submit(payload) {
|
|
164
|
+
const res = await fetch('/your-form-submit', {
|
|
165
|
+
method: 'POST',
|
|
166
|
+
headers: { 'Content-Type': 'application/json' },
|
|
167
|
+
body: JSON.stringify(payload)
|
|
168
|
+
})
|
|
169
|
+
if (!res.ok) return { status: 'failed', message: res.statusText }
|
|
170
|
+
return { status: 'accepted' }
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
el.addEventListener('usgb-form:success', (e) => {
|
|
175
|
+
/* e.detail is SubmissionPayload */
|
|
176
|
+
})
|
|
177
|
+
el.addEventListener('usgb-form:failure', (e) => {
|
|
178
|
+
/* e.detail = { payload, message } */
|
|
179
|
+
})
|
|
180
|
+
</script>
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Attribute map
|
|
184
|
+
|
|
185
|
+
| Attribute | React prop |
|
|
186
|
+
| ----------------------------------------------- | ------------------------------------------------------------- |
|
|
187
|
+
| `form-id` | `formId` |
|
|
188
|
+
| `appearance` | `appearance` |
|
|
189
|
+
| `variant` | `variants` (space-separated) |
|
|
190
|
+
| `heading` / `body` | `heading` / `body` |
|
|
191
|
+
| `cta` | `ctaLabel` |
|
|
192
|
+
| `source` / `campaign` | `source` / `campaign` |
|
|
193
|
+
| `success-message` / `success-url` | `successMessage` / `successUrl` |
|
|
194
|
+
| `client-agreement-url`, `privacy-policy-url`, … | `legalUrls.*` |
|
|
195
|
+
| `host` | Used only for the stub adapter before you assign `el.adapter` |
|
|
196
|
+
|
|
197
|
+
## Host adapter
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
interface HostAdapter {
|
|
201
|
+
host: 'pwa' | 'wordpress'
|
|
202
|
+
getTrackingHints(): Partial<Record<TrackingKey, string | undefined>>
|
|
203
|
+
submit(payload: SubmissionPayload): Promise<SubmitResult>
|
|
44
204
|
}
|
|
45
205
|
```
|
|
46
206
|
|
|
47
|
-
|
|
207
|
+
- `submit` must return `{ status: 'accepted' }` or `{ status: 'failed', message?: string }`.
|
|
208
|
+
- The package never embeds Workato, Magento, or WordPress endpoints.
|
|
209
|
+
- `createStubAdapter('pwa' | 'wordpress')` accepts every payload (playground / markup-only WC).
|
|
210
|
+
- Tracking keys and destination names live in `forms-manifest.json`. Hosts may supply values for registered keys; they must not invent new ones.
|
|
48
211
|
|
|
49
|
-
|
|
212
|
+
### Payload shape (summary)
|
|
50
213
|
|
|
51
|
-
|
|
214
|
+
Successful submits send a nested envelope: `formId`, `definitionVersion`, `submissionContractVersion`, `idempotencyKey`, `data` (field values), optional `consent`, and `context` (`host`, `source`, `campaign`, `page`, `tracking`). Exact field and tracking sets come from the form’s catalog entry.
|
|
52
215
|
|
|
53
|
-
|
|
216
|
+
## Consent and legal URLs
|
|
54
217
|
|
|
55
|
-
|
|
56
|
-
| --- | --- |
|
|
57
|
-
| Organization or user | `OWNER` |
|
|
58
|
-
| Repository | `REPO` |
|
|
59
|
-
| Workflow filename | `publish.yml` |
|
|
60
|
-
| Environment name | `npm-publish` |
|
|
61
|
-
| Allowed actions | `npm publish` |
|
|
218
|
+
Consent bundles are versioned and package-owned (checkboxes and/or clickwrap notices). Hosts only supply document **hrefs**.
|
|
62
219
|
|
|
63
|
-
|
|
220
|
+
- `main-investors-kit` uses `lead-tcpa` v1 and requires `clientAgreement` and `privacyPolicy`.
|
|
221
|
+
- PWA Magento defaults: `PWA_LEGAL_URLS` → `/content/client-agreement`, `/content/privacy-policy`.
|
|
222
|
+
- WordPress must pass every URL required by the selected consent. A consent form with a missing required URL **does not render**.
|
|
223
|
+
- Checkbox values land in `consent.values` (and mirrored in `data`). Notices have no boolean field; the payload still records consent definition id/version.
|
|
224
|
+
- Distinct legal wording requires a new consent id/version in this package — not freeform copy from the host.
|
|
64
225
|
|
|
65
|
-
|
|
226
|
+
`LEAD_CLICKWRAP_V1` (“By clicking the button…”) is in the catalog and needs five legal URLs (`privacyPolicy`, `userAgreement`, `marketLossPolicy`, `electronicDisclaimer`, `termsOfSale`). It is not attached to a `formId` until that recipe is chosen.
|
|
66
227
|
|
|
67
|
-
|
|
228
|
+
## Success behavior
|
|
68
229
|
|
|
69
|
-
|
|
230
|
+
1. Adapter returns `accepted`.
|
|
231
|
+
2. `analytics({ type: 'success' })` and `onAccepted` / `usgb-form:success` run synchronously. The package does not `await` them.
|
|
232
|
+
3. If `successUrl` / `success-url` is set, the page calls `window.location.assign` immediately after those callbacks return.
|
|
233
|
+
4. Otherwise the form shows `successMessage` / `success-message`, or a package default thank-you line.
|
|
70
234
|
|
|
71
|
-
|
|
235
|
+
### Redirect vs analytics
|
|
72
236
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
git commit -m "Release 0.1.1"
|
|
77
|
-
git push origin main
|
|
78
|
-
```
|
|
237
|
+
Invocation order is fixed (hooks first, then navigate). Delivery is not. `location.assign` starts unload in the same turn, so a typical GTM / `gtag` / `dataLayer.push` / image pixel started in `analytics` or `onAccepted` can be cancelled before the beacon leaves — especially on Safari and slow networks. Same for async work inside a `usgb-form:success` listener: the CustomEvent is dispatched synchronously, but anything it schedules after return can die with the document.
|
|
238
|
+
|
|
239
|
+
This package does **not** wait on a returned Promise, add a flush timeout, or call `sendBeacon` on the host’s behalf. A hung analytics callback must not trap the user on the submit screen.
|
|
79
240
|
|
|
80
|
-
|
|
241
|
+
What is reliable today:
|
|
81
242
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
243
|
+
- Inline thank-you (`successMessage` only) — no navigation, so tags usually complete.
|
|
244
|
+
- Same-document hash redirects (`#thank-you`) — no unload.
|
|
245
|
+
- Host `analytics` that uses `navigator.sendBeacon` or `fetch(..., { keepalive: true })`.
|
|
246
|
+
- Conversion measured on the thank-you page itself, not on this `success` event.
|
|
86
247
|
|
|
87
|
-
|
|
248
|
+
`submit_attempt` is safer than `success` because it fires before `adapter.submit` and has the round-trip to flush. Prefer the thank-you page (or a beacon) when `successUrl` is a full navigation.
|
|
88
249
|
|
|
89
|
-
|
|
250
|
+
## Styling
|
|
90
251
|
|
|
91
|
-
|
|
252
|
+
Light DOM with stable `usgb-` class names (not CSS-in-JS). Isolation comes from the prefix and from styling `.usgb-field-control` / `.usgb-btn` instead of bare `input` / `button`. Host theme rules can still win; load host CSS **after** this package’s stylesheet and override under `.usgb-form`.
|
|
92
253
|
|
|
93
|
-
|
|
254
|
+
| Host | How styles load |
|
|
255
|
+
| ------------- | ---------------------------------------------- |
|
|
256
|
+
| React | `import '@usgb/forms/usgb-forms.css'` |
|
|
257
|
+
| Web Component | Injected as `<style id="usgb-forms-css">` once |
|
|
94
258
|
|
|
95
|
-
|
|
259
|
+
Prefer **custom properties** on `.usgb-form` for color, type, and spacing:
|
|
96
260
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
-
|
|
100
|
-
-
|
|
101
|
-
|
|
261
|
+
```css
|
|
262
|
+
.usgb-form {
|
|
263
|
+
--usgb-button-background: #123456;
|
|
264
|
+
--usgb-field-border: #cccccc;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
.usgb-form[data-appearance='navy'] {
|
|
268
|
+
--usgb-button-background: #f4e08e;
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
Use class selectors when a token does not exist (`.usgb-form .usgb-btn { border-radius: 0; }`).
|
|
273
|
+
|
|
274
|
+
Stable hooks: `.usgb-form` (`data-appearance`, `data-variant`, `data-kind`), `.usgb-form-heading`, `.usgb-form-body`, `.usgb-form-grid`, `.usgb-form-inline`, `.usgb-field-control`, `.usgb-field-error`, `.usgb-consent-*`, `.usgb-btn`, `.usgb-form-status-*`.
|
|
275
|
+
|
|
276
|
+
Semantic tokens (`--usgb-form-surface`, `--usgb-field-*`, `--usgb-button-*`, `--usgb-newsletter-underline`, …) are the first place to retheme. Palette vars (`--usgb-blue-1`, …) are a PWA snapshot. Error and checkbox glyphs are inline SVGs that use `currentColor` — override `--usgb-alert-danger` or `--usgb-checkbox-mark` to recolor them.
|
|
277
|
+
|
|
278
|
+
Visual styles are a ported snapshot of the PWA form kit. When PWA form styles change, update this package and bump the version.
|
|
279
|
+
|
|
280
|
+
## Develop (package maintainers)
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
yarn install
|
|
284
|
+
yarn dev # Vite playground (tries :5174)
|
|
285
|
+
yarn build
|
|
286
|
+
yarn typecheck
|
|
287
|
+
yarn lint
|
|
288
|
+
yarn format
|
|
289
|
+
```
|
|
102
290
|
|
|
103
|
-
|
|
291
|
+
Prettier and ESLint match magento-frontend (4-space indent, single quotes, no semicolons, print width 80).
|
|
104
292
|
|
|
105
|
-
|
|
106
|
-
| --- | --- |
|
|
107
|
-
| `ENEEDAUTH` / unable to authenticate | Workflow filename, repo, or environment does not match the trusted publisher |
|
|
108
|
-
| 404 during OIDC exchange | Trusted publisher is missing, or npm CLI is older than 11.5.1 |
|
|
109
|
-
| Provenance missing | Repository or package is private |
|
|
110
|
-
| `npm ci` fails on private deps | Need a read-only install token; OIDC does not apply to install |
|
|
293
|
+
## Git
|
|
111
294
|
|
|
112
|
-
|
|
295
|
+
Local repo only. Connect a GitHub remote later when ready to publish.
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "1.0.0",
|
|
3
|
+
"package": {
|
|
4
|
+
"name": "@usgb/forms",
|
|
5
|
+
"compatiblePackageVersions": "^1.0.0"
|
|
6
|
+
},
|
|
7
|
+
"submissionContract": {
|
|
8
|
+
"version": "1.0.0",
|
|
9
|
+
"transport": "server-proxy",
|
|
10
|
+
"payloadShape": "data-and-context"
|
|
11
|
+
},
|
|
12
|
+
"trackingRegistry": {
|
|
13
|
+
"page_url": {
|
|
14
|
+
"destination": "form_submission_url",
|
|
15
|
+
"category": "page",
|
|
16
|
+
"collection": "server",
|
|
17
|
+
"required": true,
|
|
18
|
+
"states": ["collected", "unavailable"],
|
|
19
|
+
"description": "Canonical landing-page URL at submission time"
|
|
20
|
+
},
|
|
21
|
+
"page_title": {
|
|
22
|
+
"destination": "pageName",
|
|
23
|
+
"category": "page",
|
|
24
|
+
"collection": "server",
|
|
25
|
+
"required": false,
|
|
26
|
+
"states": ["collected", "unavailable"]
|
|
27
|
+
},
|
|
28
|
+
"referrer": {
|
|
29
|
+
"destination": "referrer",
|
|
30
|
+
"category": "page",
|
|
31
|
+
"collection": "browser",
|
|
32
|
+
"required": false,
|
|
33
|
+
"states": ["collected", "unavailable"]
|
|
34
|
+
},
|
|
35
|
+
"first_touch_url": {
|
|
36
|
+
"destination": "crossDomain_landing_url",
|
|
37
|
+
"category": "attribution",
|
|
38
|
+
"collection": "host-adapter",
|
|
39
|
+
"required": false,
|
|
40
|
+
"states": ["collected", "unavailable"]
|
|
41
|
+
},
|
|
42
|
+
"utm_source": {
|
|
43
|
+
"destination": "utm_source",
|
|
44
|
+
"category": "attribution",
|
|
45
|
+
"collection": "host-adapter",
|
|
46
|
+
"required": false,
|
|
47
|
+
"states": ["collected", "unavailable"]
|
|
48
|
+
},
|
|
49
|
+
"utm_medium": {
|
|
50
|
+
"destination": "utm_medium",
|
|
51
|
+
"category": "attribution",
|
|
52
|
+
"collection": "host-adapter",
|
|
53
|
+
"required": false,
|
|
54
|
+
"states": ["collected", "unavailable"]
|
|
55
|
+
},
|
|
56
|
+
"utm_campaign": {
|
|
57
|
+
"destination": "utm_campaign",
|
|
58
|
+
"category": "attribution",
|
|
59
|
+
"collection": "host-adapter",
|
|
60
|
+
"required": false,
|
|
61
|
+
"states": ["collected", "unavailable"]
|
|
62
|
+
},
|
|
63
|
+
"utm_term": {
|
|
64
|
+
"destination": "utm_term",
|
|
65
|
+
"category": "attribution",
|
|
66
|
+
"collection": "host-adapter",
|
|
67
|
+
"required": false,
|
|
68
|
+
"states": ["collected", "unavailable"]
|
|
69
|
+
},
|
|
70
|
+
"utm_content": {
|
|
71
|
+
"destination": "utm_content",
|
|
72
|
+
"category": "attribution",
|
|
73
|
+
"collection": "host-adapter",
|
|
74
|
+
"required": false,
|
|
75
|
+
"states": ["collected", "unavailable"]
|
|
76
|
+
},
|
|
77
|
+
"gclid": {
|
|
78
|
+
"destination": "gclid",
|
|
79
|
+
"category": "click-id",
|
|
80
|
+
"collection": "host-adapter",
|
|
81
|
+
"required": false,
|
|
82
|
+
"states": ["collected", "unavailable"]
|
|
83
|
+
},
|
|
84
|
+
"msclkid": {
|
|
85
|
+
"destination": "msclkid",
|
|
86
|
+
"category": "click-id",
|
|
87
|
+
"collection": "host-adapter",
|
|
88
|
+
"required": false,
|
|
89
|
+
"states": ["collected", "unavailable"]
|
|
90
|
+
},
|
|
91
|
+
"gbraid": {
|
|
92
|
+
"destination": "gbraid",
|
|
93
|
+
"category": "click-id",
|
|
94
|
+
"collection": "host-adapter",
|
|
95
|
+
"required": false,
|
|
96
|
+
"states": ["collected", "unavailable"]
|
|
97
|
+
},
|
|
98
|
+
"wbraid": {
|
|
99
|
+
"destination": "wbraid",
|
|
100
|
+
"category": "click-id",
|
|
101
|
+
"collection": "host-adapter",
|
|
102
|
+
"required": false,
|
|
103
|
+
"states": ["collected", "unavailable"]
|
|
104
|
+
},
|
|
105
|
+
"hubspot_utk": {
|
|
106
|
+
"destination": "hubspot_utk",
|
|
107
|
+
"category": "identity",
|
|
108
|
+
"collection": "host-adapter",
|
|
109
|
+
"required": false,
|
|
110
|
+
"states": ["collected", "unavailable", "consent-withheld"]
|
|
111
|
+
},
|
|
112
|
+
"ga_client_id": {
|
|
113
|
+
"destination": "ga_client_id",
|
|
114
|
+
"category": "analytics",
|
|
115
|
+
"collection": "host-adapter",
|
|
116
|
+
"required": false,
|
|
117
|
+
"states": ["collected", "unavailable", "consent-withheld"]
|
|
118
|
+
},
|
|
119
|
+
"ga_session_id": {
|
|
120
|
+
"destination": "session_id_start",
|
|
121
|
+
"category": "analytics",
|
|
122
|
+
"collection": "host-adapter",
|
|
123
|
+
"required": false,
|
|
124
|
+
"states": ["collected", "unavailable", "consent-withheld"]
|
|
125
|
+
},
|
|
126
|
+
"snowplow_id": {
|
|
127
|
+
"destination": "snowplow_id",
|
|
128
|
+
"category": "analytics",
|
|
129
|
+
"collection": "host-adapter",
|
|
130
|
+
"required": false,
|
|
131
|
+
"states": ["collected", "unavailable", "consent-withheld"]
|
|
132
|
+
},
|
|
133
|
+
"vwo_uuid": {
|
|
134
|
+
"destination": "vwo_uuid",
|
|
135
|
+
"category": "experiment",
|
|
136
|
+
"collection": "host-adapter",
|
|
137
|
+
"required": false,
|
|
138
|
+
"states": ["collected", "unavailable", "consent-withheld"]
|
|
139
|
+
},
|
|
140
|
+
"user_agent": {
|
|
141
|
+
"destination": "header_http_client_details",
|
|
142
|
+
"category": "technical",
|
|
143
|
+
"collection": "server",
|
|
144
|
+
"required": false,
|
|
145
|
+
"states": ["collected", "unavailable"]
|
|
146
|
+
},
|
|
147
|
+
"ip_address": {
|
|
148
|
+
"destination": "ipAddress",
|
|
149
|
+
"category": "technical",
|
|
150
|
+
"collection": "server",
|
|
151
|
+
"required": false,
|
|
152
|
+
"states": ["collected", "unavailable"]
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
"forms": {
|
|
156
|
+
"main-investors-kit": {
|
|
157
|
+
"definitionVersion": "1",
|
|
158
|
+
"kind": "lead",
|
|
159
|
+
"flow": { "type": "single" },
|
|
160
|
+
"supportedHosts": ["pwa", "wordpress"],
|
|
161
|
+
"fields": [
|
|
162
|
+
{ "name": "firstname", "required": true, "group": "name" },
|
|
163
|
+
{ "name": "lastname", "required": true, "group": "name" },
|
|
164
|
+
{ "name": "email", "required": true },
|
|
165
|
+
{ "name": "phone", "required": false }
|
|
166
|
+
],
|
|
167
|
+
"trackingFields": [
|
|
168
|
+
"page_url",
|
|
169
|
+
"page_title",
|
|
170
|
+
"referrer",
|
|
171
|
+
"first_touch_url",
|
|
172
|
+
"utm_source",
|
|
173
|
+
"utm_medium",
|
|
174
|
+
"utm_campaign",
|
|
175
|
+
"utm_term",
|
|
176
|
+
"utm_content",
|
|
177
|
+
"gclid",
|
|
178
|
+
"msclkid",
|
|
179
|
+
"gbraid",
|
|
180
|
+
"wbraid",
|
|
181
|
+
"hubspot_utk",
|
|
182
|
+
"ga_client_id",
|
|
183
|
+
"ga_session_id",
|
|
184
|
+
"snowplow_id",
|
|
185
|
+
"vwo_uuid",
|
|
186
|
+
"user_agent",
|
|
187
|
+
"ip_address"
|
|
188
|
+
],
|
|
189
|
+
"consent": {
|
|
190
|
+
"definitionId": "lead-tcpa",
|
|
191
|
+
"definitionVersion": "1",
|
|
192
|
+
"required": true,
|
|
193
|
+
"submitFields": [
|
|
194
|
+
"tcpa_form_consent_granted",
|
|
195
|
+
"tcpa_form_opt_in_date"
|
|
196
|
+
]
|
|
197
|
+
},
|
|
198
|
+
"editor": {
|
|
199
|
+
"label": "Main Investors Kit",
|
|
200
|
+
"description": "Standard lead form: name, email, phone, TCPA consent. Use on full-width landing pages and PWA kit/sidebar placements.",
|
|
201
|
+
"whenToUse": "Default kit request. Do not use for affiliate landers or IRA-specific leads.",
|
|
202
|
+
"whenNotToUse": "Affiliate pages (separate definition). IRA kit (separate definition when added).",
|
|
203
|
+
"supportedAppearances": ["light", "navy"],
|
|
204
|
+
"supportedVariants": ["dense", "large", "sidebar", "two-column"]
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
"newsletter": {
|
|
208
|
+
"definitionVersion": "1",
|
|
209
|
+
"kind": "newsletter",
|
|
210
|
+
"flow": { "type": "single" },
|
|
211
|
+
"supportedHosts": ["pwa"],
|
|
212
|
+
"fields": [{ "name": "email", "required": true }],
|
|
213
|
+
"trackingFields": [
|
|
214
|
+
"page_url",
|
|
215
|
+
"page_title",
|
|
216
|
+
"referrer",
|
|
217
|
+
"utm_source",
|
|
218
|
+
"utm_medium",
|
|
219
|
+
"utm_campaign",
|
|
220
|
+
"utm_term",
|
|
221
|
+
"utm_content"
|
|
222
|
+
],
|
|
223
|
+
"editor": {
|
|
224
|
+
"label": "Newsletter",
|
|
225
|
+
"description": "Email-only newsletter signup. No TCPA consent.",
|
|
226
|
+
"whenToUse": "Footer or landing newsletter capture where only an email is required.",
|
|
227
|
+
"whenNotToUse": "Lead kits that need name, phone, or TCPA consent.",
|
|
228
|
+
"supportedAppearances": ["light", "navy"],
|
|
229
|
+
"supportedVariants": []
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
"hostAdapterContract": {
|
|
234
|
+
"hosts": ["pwa", "wordpress"],
|
|
235
|
+
"mayProvide": [
|
|
236
|
+
"browser cookies",
|
|
237
|
+
"URL parameters",
|
|
238
|
+
"page and placement context",
|
|
239
|
+
"host/store identity"
|
|
240
|
+
],
|
|
241
|
+
"mustNotDefine": [
|
|
242
|
+
"new tracking keys",
|
|
243
|
+
"destination property names",
|
|
244
|
+
"consent definitions",
|
|
245
|
+
"form fields",
|
|
246
|
+
"submission endpoints"
|
|
247
|
+
]
|
|
248
|
+
}
|
|
249
|
+
}
|