@businessdash/sdk 0.9.60
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/LICENSE +21 -0
- package/README.md +899 -0
- package/dist/adapters-revalidate.d.ts +44 -0
- package/dist/adapters-revalidate.d.ts.map +1 -0
- package/dist/adapters-revalidate.js +68 -0
- package/dist/adapters-revalidate.js.map +1 -0
- package/dist/alpha.d.ts +21 -0
- package/dist/alpha.d.ts.map +1 -0
- package/dist/alpha.js +21 -0
- package/dist/alpha.js.map +1 -0
- package/dist/analytics-core.d.ts +34 -0
- package/dist/analytics-core.d.ts.map +1 -0
- package/dist/analytics-core.js +138 -0
- package/dist/analytics-core.js.map +1 -0
- package/dist/analytics-server.d.ts +54 -0
- package/dist/analytics-server.d.ts.map +1 -0
- package/dist/analytics-server.js +78 -0
- package/dist/analytics-server.js.map +1 -0
- package/dist/attribution-logo.d.ts +2 -0
- package/dist/attribution-logo.d.ts.map +1 -0
- package/dist/attribution-logo.js +5 -0
- package/dist/attribution-logo.js.map +1 -0
- package/dist/auth-handler.d.ts +92 -0
- package/dist/auth-handler.d.ts.map +1 -0
- package/dist/auth-handler.js +277 -0
- package/dist/auth-handler.js.map +1 -0
- package/dist/biab-forms.css +484 -0
- package/dist/cli.d.ts +46 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +1824 -0
- package/dist/cli.js.map +1 -0
- package/dist/client.d.ts +1681 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +2845 -0
- package/dist/client.js.map +1 -0
- package/dist/collections.d.ts +13 -0
- package/dist/collections.d.ts.map +1 -0
- package/dist/collections.js +13 -0
- package/dist/collections.js.map +1 -0
- package/dist/contracts.d.ts +14609 -0
- package/dist/contracts.d.ts.map +1 -0
- package/dist/contracts.js +2428 -0
- package/dist/contracts.js.map +1 -0
- package/dist/data-model-schema.d.ts +962 -0
- package/dist/data-model-schema.d.ts.map +1 -0
- package/dist/data-model-schema.js +2295 -0
- package/dist/data-model-schema.js.map +1 -0
- package/dist/distribution.d.ts +38 -0
- package/dist/distribution.d.ts.map +1 -0
- package/dist/distribution.js +61 -0
- package/dist/distribution.js.map +1 -0
- package/dist/element.d.ts +121 -0
- package/dist/element.d.ts.map +1 -0
- package/dist/element.js +276 -0
- package/dist/element.js.map +1 -0
- package/dist/enums.d.ts +25 -0
- package/dist/enums.d.ts.map +1 -0
- package/dist/enums.js +38 -0
- package/dist/enums.js.map +1 -0
- package/dist/errors.d.ts +195 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +188 -0
- package/dist/errors.js.map +1 -0
- package/dist/forms-core/autocomplete.d.ts +37 -0
- package/dist/forms-core/autocomplete.d.ts.map +1 -0
- package/dist/forms-core/autocomplete.js +82 -0
- package/dist/forms-core/autocomplete.js.map +1 -0
- package/dist/forms-core/business-function.d.ts +61 -0
- package/dist/forms-core/business-function.d.ts.map +1 -0
- package/dist/forms-core/business-function.js +149 -0
- package/dist/forms-core/business-function.js.map +1 -0
- package/dist/forms-core/calculation.d.ts +72 -0
- package/dist/forms-core/calculation.d.ts.map +1 -0
- package/dist/forms-core/calculation.js +103 -0
- package/dist/forms-core/calculation.js.map +1 -0
- package/dist/forms-core/controller.d.ts +249 -0
- package/dist/forms-core/controller.d.ts.map +1 -0
- package/dist/forms-core/controller.js +590 -0
- package/dist/forms-core/controller.js.map +1 -0
- package/dist/forms-core/elements.d.ts +44 -0
- package/dist/forms-core/elements.d.ts.map +1 -0
- package/dist/forms-core/elements.js +68 -0
- package/dist/forms-core/elements.js.map +1 -0
- package/dist/forms-core/email-domains.d.ts +10 -0
- package/dist/forms-core/email-domains.d.ts.map +1 -0
- package/dist/forms-core/email-domains.js +69 -0
- package/dist/forms-core/email-domains.js.map +1 -0
- package/dist/forms-core/file-rules.d.ts +51 -0
- package/dist/forms-core/file-rules.d.ts.map +1 -0
- package/dist/forms-core/file-rules.js +105 -0
- package/dist/forms-core/file-rules.js.map +1 -0
- package/dist/forms-core/formula.d.ts +114 -0
- package/dist/forms-core/formula.d.ts.map +1 -0
- package/dist/forms-core/formula.js +1170 -0
- package/dist/forms-core/formula.js.map +1 -0
- package/dist/forms-core/index.d.ts +24 -0
- package/dist/forms-core/index.d.ts.map +1 -0
- package/dist/forms-core/index.js +28 -0
- package/dist/forms-core/index.js.map +1 -0
- package/dist/forms-core/units.d.ts +49 -0
- package/dist/forms-core/units.d.ts.map +1 -0
- package/dist/forms-core/units.js +255 -0
- package/dist/forms-core/units.js.map +1 -0
- package/dist/forms-core/us-states.d.ts +14 -0
- package/dist/forms-core/us-states.d.ts.map +1 -0
- package/dist/forms-core/us-states.js +66 -0
- package/dist/forms-core/us-states.js.map +1 -0
- package/dist/forms-core/validation.d.ts +266 -0
- package/dist/forms-core/validation.d.ts.map +1 -0
- package/dist/forms-core/validation.js +850 -0
- package/dist/forms-core/validation.js.map +1 -0
- package/dist/forms.d.ts +19 -0
- package/dist/forms.d.ts.map +1 -0
- package/dist/forms.js +29 -0
- package/dist/forms.js.map +1 -0
- package/dist/gallery-types.d.ts +32 -0
- package/dist/gallery-types.d.ts.map +1 -0
- package/dist/gallery-types.js +2 -0
- package/dist/gallery-types.js.map +1 -0
- package/dist/graphql.d.ts +97 -0
- package/dist/graphql.d.ts.map +1 -0
- package/dist/graphql.js +212 -0
- package/dist/graphql.js.map +1 -0
- package/dist/index.cjs +19448 -0
- package/dist/index.d.cts +19 -0
- package/dist/index.d.mts +19 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/marketing-schema.d.ts +216 -0
- package/dist/marketing-schema.d.ts.map +1 -0
- package/dist/marketing-schema.js +200 -0
- package/dist/marketing-schema.js.map +1 -0
- package/dist/mcp.d.ts +42 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +87 -0
- package/dist/mcp.js.map +1 -0
- package/dist/native.d.ts +45 -0
- package/dist/native.d.ts.map +1 -0
- package/dist/native.js +43 -0
- package/dist/native.js.map +1 -0
- package/dist/next-revalidate.d.ts +43 -0
- package/dist/next-revalidate.d.ts.map +1 -0
- package/dist/next-revalidate.js +84 -0
- package/dist/next-revalidate.js.map +1 -0
- package/dist/parallel-pages.d.ts +102 -0
- package/dist/parallel-pages.d.ts.map +1 -0
- package/dist/parallel-pages.js +108 -0
- package/dist/parallel-pages.js.map +1 -0
- package/dist/payment-icons.d.ts +66 -0
- package/dist/payment-icons.d.ts.map +1 -0
- package/dist/payment-icons.js +160 -0
- package/dist/payment-icons.js.map +1 -0
- package/dist/proxy.d.ts +67 -0
- package/dist/proxy.d.ts.map +1 -0
- package/dist/proxy.js +97 -0
- package/dist/proxy.js.map +1 -0
- package/dist/react-analytics.d.ts +39 -0
- package/dist/react-analytics.d.ts.map +1 -0
- package/dist/react-analytics.js +59 -0
- package/dist/react-analytics.js.map +1 -0
- package/dist/react-attribution.d.ts +99 -0
- package/dist/react-attribution.d.ts.map +1 -0
- package/dist/react-attribution.js +52 -0
- package/dist/react-attribution.js.map +1 -0
- package/dist/react-marketing.d.ts +181 -0
- package/dist/react-marketing.d.ts.map +1 -0
- package/dist/react-marketing.js +215 -0
- package/dist/react-marketing.js.map +1 -0
- package/dist/react.d.ts +727 -0
- package/dist/react.d.ts.map +1 -0
- package/dist/react.js +2418 -0
- package/dist/react.js.map +1 -0
- package/dist/reserved-paths.d.ts +24 -0
- package/dist/reserved-paths.d.ts.map +1 -0
- package/dist/reserved-paths.js +60 -0
- package/dist/reserved-paths.js.map +1 -0
- package/dist/revalidate-verify.d.ts +30 -0
- package/dist/revalidate-verify.d.ts.map +1 -0
- package/dist/revalidate-verify.js +74 -0
- package/dist/revalidate-verify.js.map +1 -0
- package/dist/sdk.d.ts +678 -0
- package/dist/sdk.d.ts.map +1 -0
- package/dist/sdk.js +801 -0
- package/dist/sdk.js.map +1 -0
- package/dist/seo.d.ts +218 -0
- package/dist/seo.d.ts.map +1 -0
- package/dist/seo.js +309 -0
- package/dist/seo.js.map +1 -0
- package/dist/socials.d.ts +47 -0
- package/dist/socials.d.ts.map +1 -0
- package/dist/socials.js +172 -0
- package/dist/socials.js.map +1 -0
- package/dist/static.d.ts +14 -0
- package/dist/static.d.ts.map +1 -0
- package/dist/static.js +14 -0
- package/dist/static.js.map +1 -0
- package/dist/url-pattern.d.ts +47 -0
- package/dist/url-pattern.d.ts.map +1 -0
- package/dist/url-pattern.js +124 -0
- package/dist/url-pattern.js.map +1 -0
- package/dist/vanilla.d.ts +77 -0
- package/dist/vanilla.d.ts.map +1 -0
- package/dist/vanilla.js +903 -0
- package/dist/vanilla.js.map +1 -0
- package/openapi.json +13779 -0
- package/package.json +204 -0
- package/src/adapters-revalidate.ts +88 -0
- package/src/alpha.ts +89 -0
- package/src/analytics-core.ts +175 -0
- package/src/analytics-server.ts +99 -0
- package/src/angular/biab-form.component.ts +1443 -0
- package/src/angular/index.ts +26 -0
- package/src/attribution-logo.ts +5 -0
- package/src/auth-handler.ts +352 -0
- package/src/cli.ts +2517 -0
- package/src/client.ts +3578 -0
- package/src/collections.ts +101 -0
- package/src/contracts.ts +3390 -0
- package/src/data-model-schema.ts +4042 -0
- package/src/distribution.ts +73 -0
- package/src/element.ts +321 -0
- package/src/enums.ts +65 -0
- package/src/errors.ts +338 -0
- package/src/forms-core/autocomplete.ts +97 -0
- package/src/forms-core/business-function.ts +209 -0
- package/src/forms-core/calculation.ts +167 -0
- package/src/forms-core/controller.ts +922 -0
- package/src/forms-core/elements.ts +86 -0
- package/src/forms-core/email-domains.ts +68 -0
- package/src/forms-core/file-rules.ts +123 -0
- package/src/forms-core/formula.ts +1339 -0
- package/src/forms-core/index.ts +122 -0
- package/src/forms-core/units.ts +308 -0
- package/src/forms-core/us-states.ts +68 -0
- package/src/forms-core/validation.ts +1037 -0
- package/src/forms.ts +63 -0
- package/src/gallery-types.ts +31 -0
- package/src/graphql.ts +295 -0
- package/src/index.ts +505 -0
- package/src/marketing-schema.ts +395 -0
- package/src/mcp.ts +108 -0
- package/src/native.ts +73 -0
- package/src/next-revalidate.ts +124 -0
- package/src/parallel-pages.ts +192 -0
- package/src/payment-icons.ts +205 -0
- package/src/proxy.ts +173 -0
- package/src/qwik.tsx +1234 -0
- package/src/react-analytics.tsx +76 -0
- package/src/react-attribution.tsx +192 -0
- package/src/react-marketing.tsx +338 -0
- package/src/react.tsx +5495 -0
- package/src/reserved-paths.ts +65 -0
- package/src/revalidate-verify.ts +98 -0
- package/src/sdk.ts +1671 -0
- package/src/seo.ts +488 -0
- package/src/socials.ts +230 -0
- package/src/solid.tsx +1466 -0
- package/src/static.ts +21 -0
- package/src/styles/biab-forms.css +484 -0
- package/src/svelte/BiabForm.svelte +1069 -0
- package/src/svelte/context.ts +57 -0
- package/src/svelte/index.ts +79 -0
- package/src/url-pattern.ts +153 -0
- package/src/vanilla.ts +1290 -0
- package/src/vue/BiabForm.vue +1538 -0
- package/src/vue/index.ts +119 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@businessdash/sdk/forms` headless core — framework-agnostic form runtime.
|
|
3
|
+
*
|
|
4
|
+
* Everything a `<BiabForm>` binding needs that ISN'T framework-specific:
|
|
5
|
+
* - `createFormController` — the observable store (values, errors, steps,
|
|
6
|
+
* visibility, submit lifecycle, file uploads).
|
|
7
|
+
* - validation + condition primitives mirrored 1:1 from the BIAB server so the
|
|
8
|
+
* client never disagrees with what the platform enforces.
|
|
9
|
+
*
|
|
10
|
+
* Bindings (React / Vue / Svelte / Solid / Qwik / Angular / web-component /
|
|
11
|
+
* vanilla) import from here, subscribe to `snapshot()`, and render by field
|
|
12
|
+
* `type` using the `biab-*` CSS class convention.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
// Re-export the SDK form types so a binding can import schema/result/field types
|
|
16
|
+
// from the single `/forms` entry without reaching into the root export.
|
|
17
|
+
// `BiabClient` is included because `CreateFormControllerOptions.client` is typed
|
|
18
|
+
// to it — a binding that accepts/injects a client needs the type from here.
|
|
19
|
+
export type {
|
|
20
|
+
BiabClient,
|
|
21
|
+
FormActionPreview,
|
|
22
|
+
FormActionType,
|
|
23
|
+
FormFieldDef,
|
|
24
|
+
FormFileValue,
|
|
25
|
+
FormRenderSettings,
|
|
26
|
+
FormSchema,
|
|
27
|
+
FormSubmissionData,
|
|
28
|
+
FormSubmitFailureReason,
|
|
29
|
+
FormSubmitResult,
|
|
30
|
+
FormsResource,
|
|
31
|
+
FormValidationIssue,
|
|
32
|
+
FormValidationResult,
|
|
33
|
+
} from "../sdk.js";
|
|
34
|
+
export { isFormFileValue, validateFormSubmission } from "../sdk.js";
|
|
35
|
+
|
|
36
|
+
// Calculation / Math element runtime + the formula engine it builds on. A
|
|
37
|
+
// binding uses these to compute `calculation` fields live for non-sensitive
|
|
38
|
+
// formulas/functions (sensitive ones compute server-side on submit).
|
|
39
|
+
export {
|
|
40
|
+
type AutocompleteConfig,
|
|
41
|
+
inferAutocompleteToken,
|
|
42
|
+
resolveFieldAutocomplete,
|
|
43
|
+
} from "./autocomplete.js";
|
|
44
|
+
export {
|
|
45
|
+
type BusinessFunctionDef,
|
|
46
|
+
type FnInput,
|
|
47
|
+
type FnOutput,
|
|
48
|
+
type FnRunResult,
|
|
49
|
+
type FnValueType,
|
|
50
|
+
functionsToEvalOptions,
|
|
51
|
+
runBusinessFunction,
|
|
52
|
+
} from "./business-function.js";
|
|
53
|
+
export {
|
|
54
|
+
type CalcContext,
|
|
55
|
+
type CalcDisplay,
|
|
56
|
+
type CalcInputBinding,
|
|
57
|
+
type CalcResult,
|
|
58
|
+
type CalculationConfig,
|
|
59
|
+
computeCalculation,
|
|
60
|
+
formatCalcValue,
|
|
61
|
+
} from "./calculation.js";
|
|
62
|
+
export {
|
|
63
|
+
type BiabFormsClient,
|
|
64
|
+
type CreateFormControllerOptions,
|
|
65
|
+
concurrentRevealCount,
|
|
66
|
+
createFormController,
|
|
67
|
+
evalCondition,
|
|
68
|
+
type FieldError,
|
|
69
|
+
type FormController,
|
|
70
|
+
type FormSnapshot,
|
|
71
|
+
type FormStatus,
|
|
72
|
+
type FormSubmitOptions,
|
|
73
|
+
findMissingRequired,
|
|
74
|
+
isNodeVisible,
|
|
75
|
+
isPendingFileValue,
|
|
76
|
+
type PendingFileValue,
|
|
77
|
+
type ResolvedFormSettings,
|
|
78
|
+
seedInitialData,
|
|
79
|
+
} from "./controller.js";
|
|
80
|
+
export {
|
|
81
|
+
BIAB_ICON_BASE,
|
|
82
|
+
fetchIconNames,
|
|
83
|
+
filterIconNames,
|
|
84
|
+
ICON_INDEX_URL,
|
|
85
|
+
iconUrl,
|
|
86
|
+
SEARCHABLE_THRESHOLD,
|
|
87
|
+
shouldSearchOptions,
|
|
88
|
+
} from "./elements.js";
|
|
89
|
+
|
|
90
|
+
// File-upload rules — accept-attribute building (incl. iOS HEIC/HEVC), per-file
|
|
91
|
+
// validation, and the form-wide file cap. Shared 1:1 with the BIAB server.
|
|
92
|
+
export {
|
|
93
|
+
buildAcceptAttr,
|
|
94
|
+
expandAllowedTypes,
|
|
95
|
+
type FileLike,
|
|
96
|
+
type FileRule,
|
|
97
|
+
FORM_WIDE_MAX_FILES,
|
|
98
|
+
isFileTypeAllowed,
|
|
99
|
+
validateFile,
|
|
100
|
+
} from "./file-rules.js";
|
|
101
|
+
export {
|
|
102
|
+
type EvalOptions,
|
|
103
|
+
FORMULA_FUNCTIONS,
|
|
104
|
+
type FormulaObject,
|
|
105
|
+
type FormulaResult,
|
|
106
|
+
type FormulaValue,
|
|
107
|
+
type FormulaVars,
|
|
108
|
+
parseFormula,
|
|
109
|
+
runFormula,
|
|
110
|
+
validateFormula,
|
|
111
|
+
} from "./formula.js";
|
|
112
|
+
export {
|
|
113
|
+
type FormConditionClause,
|
|
114
|
+
type FormConditionRule,
|
|
115
|
+
type FormCoreField,
|
|
116
|
+
type FormData,
|
|
117
|
+
flattenValueFields,
|
|
118
|
+
isEmpty,
|
|
119
|
+
type MissingField,
|
|
120
|
+
toSubmissionPayload,
|
|
121
|
+
validateValue,
|
|
122
|
+
} from "./validation.js";
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Units catalog + conversion helpers for the `measurement` form element (SDK
|
|
3
|
+
* copy — mirror of the app's `src/shared/forms/units.ts`; keep in sync).
|
|
4
|
+
*
|
|
5
|
+
* Each linear category defines a `baseUnit` and a `factor` per unit such that
|
|
6
|
+
* `valueInBase = value * factor`. Temperature is affine (offset + scale), so it
|
|
7
|
+
* is special-cased. `<BiabForm/>` uses these to render the unit picker, show a
|
|
8
|
+
* live conversion hint, and compute the value's base — the server recomputes the
|
|
9
|
+
* base authoritatively on submit, so this is convenience only.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export type MeasurementCategory =
|
|
13
|
+
| "length"
|
|
14
|
+
| "mass"
|
|
15
|
+
| "temperature"
|
|
16
|
+
| "storage"
|
|
17
|
+
| "energy"
|
|
18
|
+
| "power"
|
|
19
|
+
| "volume"
|
|
20
|
+
| "area"
|
|
21
|
+
| "speed"
|
|
22
|
+
| "time"
|
|
23
|
+
| "torque"
|
|
24
|
+
| "pressure"
|
|
25
|
+
| "sound";
|
|
26
|
+
|
|
27
|
+
interface UnitDef {
|
|
28
|
+
/** value_in_base = value * factor (ignored for affine categories). */
|
|
29
|
+
factor: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
interface CategoryDef {
|
|
33
|
+
label: string;
|
|
34
|
+
baseUnit: string;
|
|
35
|
+
/** Units in display order (largest-first ordering is derived from factor). */
|
|
36
|
+
units: Record<string, UnitDef>;
|
|
37
|
+
/** Temperature uses offset/scale formulas instead of a single factor. */
|
|
38
|
+
affine?: boolean;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export const UNIT_CATEGORIES: Record<MeasurementCategory, CategoryDef> = {
|
|
42
|
+
length: {
|
|
43
|
+
label: "Length",
|
|
44
|
+
baseUnit: "m",
|
|
45
|
+
units: {
|
|
46
|
+
mm: { factor: 0.001 },
|
|
47
|
+
cm: { factor: 0.01 },
|
|
48
|
+
m: { factor: 1 },
|
|
49
|
+
km: { factor: 1000 },
|
|
50
|
+
in: { factor: 0.0254 },
|
|
51
|
+
ft: { factor: 0.3048 },
|
|
52
|
+
yd: { factor: 0.9144 },
|
|
53
|
+
mi: { factor: 1609.344 },
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
mass: {
|
|
57
|
+
label: "Mass / Weight",
|
|
58
|
+
baseUnit: "g",
|
|
59
|
+
units: {
|
|
60
|
+
mg: { factor: 0.001 },
|
|
61
|
+
g: { factor: 1 },
|
|
62
|
+
kg: { factor: 1000 },
|
|
63
|
+
t: { factor: 1_000_000 },
|
|
64
|
+
oz: { factor: 28.349523125 },
|
|
65
|
+
lb: { factor: 453.59237 },
|
|
66
|
+
st: { factor: 6350.29318 },
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
temperature: {
|
|
70
|
+
label: "Temperature",
|
|
71
|
+
baseUnit: "°C",
|
|
72
|
+
affine: true,
|
|
73
|
+
units: { "°C": { factor: 1 }, "°F": { factor: 1 }, K: { factor: 1 } },
|
|
74
|
+
},
|
|
75
|
+
storage: {
|
|
76
|
+
label: "Data Storage",
|
|
77
|
+
baseUnit: "B",
|
|
78
|
+
units: {
|
|
79
|
+
B: { factor: 1 },
|
|
80
|
+
KB: { factor: 1e3 },
|
|
81
|
+
MB: { factor: 1e6 },
|
|
82
|
+
GB: { factor: 1e9 },
|
|
83
|
+
TB: { factor: 1e12 },
|
|
84
|
+
PB: { factor: 1e15 },
|
|
85
|
+
KiB: { factor: 1024 },
|
|
86
|
+
MiB: { factor: 1024 ** 2 },
|
|
87
|
+
GiB: { factor: 1024 ** 3 },
|
|
88
|
+
TiB: { factor: 1024 ** 4 },
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
energy: {
|
|
92
|
+
label: "Energy",
|
|
93
|
+
baseUnit: "J",
|
|
94
|
+
units: {
|
|
95
|
+
J: { factor: 1 },
|
|
96
|
+
kJ: { factor: 1000 },
|
|
97
|
+
Wh: { factor: 3600 },
|
|
98
|
+
kWh: { factor: 3_600_000 },
|
|
99
|
+
MWh: { factor: 3_600_000_000 },
|
|
100
|
+
cal: { factor: 4.184 },
|
|
101
|
+
kcal: { factor: 4184 },
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
power: {
|
|
105
|
+
label: "Power",
|
|
106
|
+
baseUnit: "W",
|
|
107
|
+
units: {
|
|
108
|
+
W: { factor: 1 },
|
|
109
|
+
kW: { factor: 1000 },
|
|
110
|
+
MW: { factor: 1_000_000 },
|
|
111
|
+
GW: { factor: 1_000_000_000 },
|
|
112
|
+
hp: { factor: 745.699872 },
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
volume: {
|
|
116
|
+
label: "Volume",
|
|
117
|
+
baseUnit: "L",
|
|
118
|
+
units: {
|
|
119
|
+
mL: { factor: 0.001 },
|
|
120
|
+
L: { factor: 1 },
|
|
121
|
+
"m³": { factor: 1000 },
|
|
122
|
+
"fl oz": { factor: 0.0295735 },
|
|
123
|
+
cup: { factor: 0.2365882 },
|
|
124
|
+
pt: { factor: 0.4731765 },
|
|
125
|
+
qt: { factor: 0.9463529 },
|
|
126
|
+
gal: { factor: 3.7854118 },
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
area: {
|
|
130
|
+
label: "Area",
|
|
131
|
+
baseUnit: "m²",
|
|
132
|
+
units: {
|
|
133
|
+
"m²": { factor: 1 },
|
|
134
|
+
"km²": { factor: 1_000_000 },
|
|
135
|
+
"ft²": { factor: 0.09290304 },
|
|
136
|
+
ac: { factor: 4046.8564224 },
|
|
137
|
+
ha: { factor: 10_000 },
|
|
138
|
+
"mi²": { factor: 2_589_988.110336 },
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
speed: {
|
|
142
|
+
label: "Speed",
|
|
143
|
+
baseUnit: "m/s",
|
|
144
|
+
units: {
|
|
145
|
+
"m/s": { factor: 1 },
|
|
146
|
+
"km/h": { factor: 0.2777778 },
|
|
147
|
+
mph: { factor: 0.44704 },
|
|
148
|
+
"ft/s": { factor: 0.3048 },
|
|
149
|
+
kn: { factor: 0.5144444 },
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
time: {
|
|
153
|
+
label: "Duration",
|
|
154
|
+
baseUnit: "s",
|
|
155
|
+
units: {
|
|
156
|
+
ms: { factor: 0.001 },
|
|
157
|
+
s: { factor: 1 },
|
|
158
|
+
min: { factor: 60 },
|
|
159
|
+
h: { factor: 3600 },
|
|
160
|
+
day: { factor: 86_400 },
|
|
161
|
+
wk: { factor: 604_800 },
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
torque: {
|
|
165
|
+
label: "Torque",
|
|
166
|
+
baseUnit: "N·m",
|
|
167
|
+
units: {
|
|
168
|
+
in·lb: { factor: 0.112984829 },
|
|
169
|
+
N·m: { factor: 1 },
|
|
170
|
+
ft·lb: { factor: 1.35581795 },
|
|
171
|
+
kgf·m: { factor: 9.80665 },
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
pressure: {
|
|
175
|
+
label: "Pressure",
|
|
176
|
+
baseUnit: "Pa",
|
|
177
|
+
units: {
|
|
178
|
+
Pa: { factor: 1 },
|
|
179
|
+
kPa: { factor: 1000 },
|
|
180
|
+
bar: { factor: 100_000 },
|
|
181
|
+
psi: { factor: 6894.757 },
|
|
182
|
+
atm: { factor: 101_325 },
|
|
183
|
+
mmHg: { factor: 133.322 },
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
sound: {
|
|
187
|
+
// Audio volume / sound level. Logarithmic → a single dB unit (no cross-unit
|
|
188
|
+
// conversion; dBA/dBC weighting isn't a constant factor).
|
|
189
|
+
label: "Sound level",
|
|
190
|
+
baseUnit: "dB",
|
|
191
|
+
units: {
|
|
192
|
+
dB: { factor: 1 },
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
export const MEASUREMENT_CATEGORIES = Object.keys(
|
|
198
|
+
UNIT_CATEGORIES,
|
|
199
|
+
) as MeasurementCategory[];
|
|
200
|
+
|
|
201
|
+
/** Is `cat` a known measurement category? */
|
|
202
|
+
export function isMeasurementCategory(
|
|
203
|
+
cat: string | undefined,
|
|
204
|
+
): cat is MeasurementCategory {
|
|
205
|
+
return !!cat && cat in UNIT_CATEGORIES;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/** The units available in a category, in catalog order. */
|
|
209
|
+
export function unitsForCategory(cat: MeasurementCategory): string[] {
|
|
210
|
+
return Object.keys(UNIT_CATEGORIES[cat].units);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/** The base unit symbol for a category (e.g. "W" for power). */
|
|
214
|
+
export function baseUnitFor(cat: MeasurementCategory): string {
|
|
215
|
+
return UNIT_CATEGORIES[cat].baseUnit;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/** True when `unit` belongs to `category`. */
|
|
219
|
+
export function isUnitInCategory(
|
|
220
|
+
unit: string,
|
|
221
|
+
cat: MeasurementCategory,
|
|
222
|
+
): boolean {
|
|
223
|
+
return unit in UNIT_CATEGORIES[cat].units;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/** Convert a value to the category's base unit. Returns null when the unit is
|
|
227
|
+
* unknown for the category. Temperature uses affine formulas. */
|
|
228
|
+
export function convertToBase(
|
|
229
|
+
value: number,
|
|
230
|
+
unit: string,
|
|
231
|
+
cat: MeasurementCategory,
|
|
232
|
+
): number | null {
|
|
233
|
+
const def = UNIT_CATEGORIES[cat];
|
|
234
|
+
const u = def.units[unit];
|
|
235
|
+
if (!u) return null;
|
|
236
|
+
if (def.affine) {
|
|
237
|
+
// Base unit is °C.
|
|
238
|
+
if (unit === "°C") return value;
|
|
239
|
+
if (unit === "°F") return (value - 32) * (5 / 9);
|
|
240
|
+
if (unit === "K") return value - 273.15;
|
|
241
|
+
return null;
|
|
242
|
+
}
|
|
243
|
+
return value * u.factor;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/** Convert a base-unit value back into `unit`. Inverse of {@link convertToBase}. */
|
|
247
|
+
export function convertFromBase(
|
|
248
|
+
base: number,
|
|
249
|
+
unit: string,
|
|
250
|
+
cat: MeasurementCategory,
|
|
251
|
+
): number | null {
|
|
252
|
+
const def = UNIT_CATEGORIES[cat];
|
|
253
|
+
const u = def.units[unit];
|
|
254
|
+
if (!u) return null;
|
|
255
|
+
if (def.affine) {
|
|
256
|
+
if (unit === "°C") return base;
|
|
257
|
+
if (unit === "°F") return base * (9 / 5) + 32;
|
|
258
|
+
if (unit === "K") return base + 273.15;
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
return base / u.factor;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/** Convert a value between two units in the same category. */
|
|
265
|
+
export function convertUnit(
|
|
266
|
+
value: number,
|
|
267
|
+
from: string,
|
|
268
|
+
to: string,
|
|
269
|
+
cat: MeasurementCategory,
|
|
270
|
+
): number | null {
|
|
271
|
+
const base = convertToBase(value, from, cat);
|
|
272
|
+
if (base === null) return null;
|
|
273
|
+
return convertFromBase(base, to, cat);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/** Trim float noise to at most `places` decimals without trailing zeros. */
|
|
277
|
+
function tidy(n: number, places = 4): number {
|
|
278
|
+
return Number.parseFloat(n.toFixed(places));
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Auto-promote a value to the most readable unit in its category and format it
|
|
283
|
+
* (e.g. 6300 kW → "6.3 MW", 1500 m → "1.5 km"). Picks the largest non-affine
|
|
284
|
+
* unit where the magnitude is >= 1; affine categories (temperature) keep their
|
|
285
|
+
* unit. Returns "" for an empty value.
|
|
286
|
+
*/
|
|
287
|
+
export function formatMeasurement(
|
|
288
|
+
value: number | null | undefined,
|
|
289
|
+
unit: string,
|
|
290
|
+
cat: MeasurementCategory,
|
|
291
|
+
): string {
|
|
292
|
+
if (value === null || value === undefined || Number.isNaN(value)) return "";
|
|
293
|
+
const def = UNIT_CATEGORIES[cat];
|
|
294
|
+
if (def.affine || !(unit in def.units)) return `${tidy(value)} ${unit}`;
|
|
295
|
+
const base = convertToBase(value, unit, cat);
|
|
296
|
+
if (base === null) return `${tidy(value)} ${unit}`;
|
|
297
|
+
// Units sorted largest-first by factor.
|
|
298
|
+
const ordered = Object.entries(def.units).sort(
|
|
299
|
+
(a, b) => b[1].factor - a[1].factor,
|
|
300
|
+
);
|
|
301
|
+
const abs = Math.abs(base);
|
|
302
|
+
for (const [u, d] of ordered) {
|
|
303
|
+
if (abs >= d.factor || u === ordered[ordered.length - 1]?.[0]) {
|
|
304
|
+
return `${tidy(base / d.factor)} ${u}`;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return `${tidy(value)} ${unit}`;
|
|
308
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* US states (+ DC) for the Address element's State dropdown, and the US ZIP code
|
|
3
|
+
* format. Shared by the server validator, the FormPreview/editor renders, and the
|
|
4
|
+
* SDK (mirrored at `biab-dev/src/forms-core/us-states.ts`). Keep the two in sync.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export const US_STATES: ReadonlyArray<{ name: string; abbr: string }> = [
|
|
8
|
+
{ name: "Alabama", abbr: "AL" },
|
|
9
|
+
{ name: "Alaska", abbr: "AK" },
|
|
10
|
+
{ name: "Arizona", abbr: "AZ" },
|
|
11
|
+
{ name: "Arkansas", abbr: "AR" },
|
|
12
|
+
{ name: "California", abbr: "CA" },
|
|
13
|
+
{ name: "Colorado", abbr: "CO" },
|
|
14
|
+
{ name: "Connecticut", abbr: "CT" },
|
|
15
|
+
{ name: "Delaware", abbr: "DE" },
|
|
16
|
+
{ name: "District of Columbia", abbr: "DC" },
|
|
17
|
+
{ name: "Florida", abbr: "FL" },
|
|
18
|
+
{ name: "Georgia", abbr: "GA" },
|
|
19
|
+
{ name: "Hawaii", abbr: "HI" },
|
|
20
|
+
{ name: "Idaho", abbr: "ID" },
|
|
21
|
+
{ name: "Illinois", abbr: "IL" },
|
|
22
|
+
{ name: "Indiana", abbr: "IN" },
|
|
23
|
+
{ name: "Iowa", abbr: "IA" },
|
|
24
|
+
{ name: "Kansas", abbr: "KS" },
|
|
25
|
+
{ name: "Kentucky", abbr: "KY" },
|
|
26
|
+
{ name: "Louisiana", abbr: "LA" },
|
|
27
|
+
{ name: "Maine", abbr: "ME" },
|
|
28
|
+
{ name: "Maryland", abbr: "MD" },
|
|
29
|
+
{ name: "Massachusetts", abbr: "MA" },
|
|
30
|
+
{ name: "Michigan", abbr: "MI" },
|
|
31
|
+
{ name: "Minnesota", abbr: "MN" },
|
|
32
|
+
{ name: "Mississippi", abbr: "MS" },
|
|
33
|
+
{ name: "Missouri", abbr: "MO" },
|
|
34
|
+
{ name: "Montana", abbr: "MT" },
|
|
35
|
+
{ name: "Nebraska", abbr: "NE" },
|
|
36
|
+
{ name: "Nevada", abbr: "NV" },
|
|
37
|
+
{ name: "New Hampshire", abbr: "NH" },
|
|
38
|
+
{ name: "New Jersey", abbr: "NJ" },
|
|
39
|
+
{ name: "New Mexico", abbr: "NM" },
|
|
40
|
+
{ name: "New York", abbr: "NY" },
|
|
41
|
+
{ name: "North Carolina", abbr: "NC" },
|
|
42
|
+
{ name: "North Dakota", abbr: "ND" },
|
|
43
|
+
{ name: "Ohio", abbr: "OH" },
|
|
44
|
+
{ name: "Oklahoma", abbr: "OK" },
|
|
45
|
+
{ name: "Oregon", abbr: "OR" },
|
|
46
|
+
{ name: "Pennsylvania", abbr: "PA" },
|
|
47
|
+
{ name: "Rhode Island", abbr: "RI" },
|
|
48
|
+
{ name: "South Carolina", abbr: "SC" },
|
|
49
|
+
{ name: "South Dakota", abbr: "SD" },
|
|
50
|
+
{ name: "Tennessee", abbr: "TN" },
|
|
51
|
+
{ name: "Texas", abbr: "TX" },
|
|
52
|
+
{ name: "Utah", abbr: "UT" },
|
|
53
|
+
{ name: "Vermont", abbr: "VT" },
|
|
54
|
+
{ name: "Virginia", abbr: "VA" },
|
|
55
|
+
{ name: "Washington", abbr: "WA" },
|
|
56
|
+
{ name: "West Virginia", abbr: "WV" },
|
|
57
|
+
{ name: "Wisconsin", abbr: "WI" },
|
|
58
|
+
{ name: "Wyoming", abbr: "WY" },
|
|
59
|
+
];
|
|
60
|
+
|
|
61
|
+
/** US ZIP: 5 digits, optionally a 4-digit ZIP+4 suffix. */
|
|
62
|
+
export const US_ZIP_RE = /^\d{5}(-\d{4})?$/;
|
|
63
|
+
|
|
64
|
+
/** True when a ZIP string is empty (caller decides required-ness) or US-valid. */
|
|
65
|
+
export function isValidUsZip(zip: string): boolean {
|
|
66
|
+
const z = zip.trim();
|
|
67
|
+
return z === "" || US_ZIP_RE.test(z);
|
|
68
|
+
}
|