@bacano/sdk 1.2.2 → 1.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTENT_TYPE_MANAGEMENT.md +42 -2
- package/FLOWS.md +114 -0
- package/README.md +89 -18
- package/STOREFRONT_FORMS.md +50 -0
- package/STOREFRONT_PAYMENTS.md +231 -0
- package/client.d.ts +9 -1
- package/content-management-types.d.ts +44 -1
- package/content-management.cjs +26 -0
- package/content-management.js +26 -0
- package/flows.d.ts +109 -0
- package/form-conditions.d.ts +6 -0
- package/index.cjs +142 -3
- package/index.d.ts +3 -0
- package/index.js +142 -3
- package/modules/checkout.d.ts +1 -1
- package/modules/content.d.ts +1 -0
- package/package.json +1 -1
- package/react/flow-form.d.ts +9 -0
- package/react/form-scale-control.d.ts +9 -0
- package/react/forms.cjs +260 -65
- package/react/forms.d.ts +1 -0
- package/react/forms.js +254 -59
- package/react.cjs +106 -2
- package/react.js +106 -2
- package/skills/bacano-web/SKILL.md +2 -0
- package/skills/bacano-web/references/storefront.md +2 -0
- package/transport/documents.d.ts +2 -1
- package/types.d.ts +14 -1
package/react.js
CHANGED
|
@@ -1065,6 +1065,35 @@ var WEBSITE_GET_PRODUCT_CONTENT = (
|
|
|
1065
1065
|
}
|
|
1066
1066
|
`
|
|
1067
1067
|
);
|
|
1068
|
+
var WEBSITE_GET_PRODUCT_CONTENT_BATCH = (
|
|
1069
|
+
/* GraphQL */
|
|
1070
|
+
`
|
|
1071
|
+
mutation WebsiteGetProductContentBatch(
|
|
1072
|
+
$websiteId: uuid!
|
|
1073
|
+
$productIds: [uuid!]!
|
|
1074
|
+
$locale: String
|
|
1075
|
+
) {
|
|
1076
|
+
result: websiteGetProductContentBatch(
|
|
1077
|
+
website_id: $websiteId
|
|
1078
|
+
product_ids: $productIds
|
|
1079
|
+
locale: $locale
|
|
1080
|
+
) {
|
|
1081
|
+
success
|
|
1082
|
+
errors
|
|
1083
|
+
blocks {
|
|
1084
|
+
id
|
|
1085
|
+
product_id
|
|
1086
|
+
locale
|
|
1087
|
+
content_json
|
|
1088
|
+
resolved_fields
|
|
1089
|
+
sort_order
|
|
1090
|
+
updated_at
|
|
1091
|
+
content_type { id key name kind }
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
`
|
|
1096
|
+
);
|
|
1068
1097
|
var CHECK_AVAILABILITY = (
|
|
1069
1098
|
/* GraphQL */
|
|
1070
1099
|
`
|
|
@@ -1941,7 +1970,7 @@ var RECONCILE_PAYMENT_SESSION = (
|
|
|
1941
1970
|
$orderId: uuid!
|
|
1942
1971
|
$publicOrderToken: String!
|
|
1943
1972
|
$paymentSessionId: uuid!
|
|
1944
|
-
$gatewayTransactionId: String
|
|
1973
|
+
$gatewayTransactionId: String
|
|
1945
1974
|
) {
|
|
1946
1975
|
websiteReconcilePaymentSession(
|
|
1947
1976
|
order_id: $orderId
|
|
@@ -5405,6 +5434,52 @@ function BacanoMarketingProvider({
|
|
|
5405
5434
|
// libs/sdk/src/react/provider.tsx
|
|
5406
5435
|
import { useEffect as useEffect3, useRef as useRef3, useState as useState3 } from "react";
|
|
5407
5436
|
|
|
5437
|
+
// libs/sdk/src/flows.ts
|
|
5438
|
+
function createFlowsClient(config) {
|
|
5439
|
+
const base = config.apiUrl.replace(/\/+$/, "") + "/api/v1/website/flows";
|
|
5440
|
+
async function request(path, body, binary = false) {
|
|
5441
|
+
const token = await config.getAccessToken?.();
|
|
5442
|
+
const response = await fetch(base + path, {
|
|
5443
|
+
method: body === void 0 ? "GET" : "POST",
|
|
5444
|
+
cache: "no-store",
|
|
5445
|
+
headers: {
|
|
5446
|
+
...token ? { Authorization: `Bearer ${token}` } : {},
|
|
5447
|
+
...body !== void 0 ? { "Content-Type": "application/json" } : {},
|
|
5448
|
+
...config.websiteSlug ? { "x-bacano-website-slug": config.websiteSlug } : {}
|
|
5449
|
+
},
|
|
5450
|
+
...body !== void 0 ? { body: JSON.stringify(body) } : {}
|
|
5451
|
+
});
|
|
5452
|
+
if (!response.ok) {
|
|
5453
|
+
const result = await response.json().catch(() => ({ error: "FLOW_REQUEST_FAILED" }));
|
|
5454
|
+
throw new WebsiteError(
|
|
5455
|
+
result.error ?? "FLOW_REQUEST_FAILED",
|
|
5456
|
+
result.error ?? "FLOW_REQUEST_FAILED"
|
|
5457
|
+
);
|
|
5458
|
+
}
|
|
5459
|
+
return binary ? await response.blob() : await response.json();
|
|
5460
|
+
}
|
|
5461
|
+
const stepPath = (caseId, stepId) => `/cases/${encodeURIComponent(caseId)}/steps/${encodeURIComponent(stepId)}`;
|
|
5462
|
+
return {
|
|
5463
|
+
/** Only the explicitly enabled local demo gateway accepts these credentials. */
|
|
5464
|
+
localDemoLogin: (email, password) => request("/local-session", { email, password }),
|
|
5465
|
+
logout: () => request("/logout", {}),
|
|
5466
|
+
listCases: () => request("/cases"),
|
|
5467
|
+
getJourney: (caseId) => request(`/cases/${encodeURIComponent(caseId)}`),
|
|
5468
|
+
getContent: (caseId, stepId) => request(stepPath(caseId, stepId) + "/content"),
|
|
5469
|
+
getForm: (caseId, stepId) => request(stepPath(caseId, stepId) + "/form"),
|
|
5470
|
+
getResponse: (caseId, stepId) => request(stepPath(caseId, stepId) + "/response"),
|
|
5471
|
+
getFile: (caseId, stepId, fileId) => request(
|
|
5472
|
+
stepPath(caseId, stepId) + `/files/${encodeURIComponent(fileId)}`,
|
|
5473
|
+
void 0,
|
|
5474
|
+
true
|
|
5475
|
+
),
|
|
5476
|
+
act: (caseId, command) => request(
|
|
5477
|
+
`/cases/${encodeURIComponent(caseId)}/actions`,
|
|
5478
|
+
command
|
|
5479
|
+
)
|
|
5480
|
+
};
|
|
5481
|
+
}
|
|
5482
|
+
|
|
5408
5483
|
// libs/sdk/src/modules/auth.ts
|
|
5409
5484
|
function createAuthHeaders(accessToken) {
|
|
5410
5485
|
return accessToken ? { Authorization: `Bearer ${accessToken}` } : {};
|
|
@@ -6715,6 +6790,33 @@ function createContentModule(graphqlUrl, getHeaders, getContext, storageUrl) {
|
|
|
6715
6790
|
return (data.result.blocks ?? []).map(
|
|
6716
6791
|
(block) => mapProductContentBlock(block, storageUrl)
|
|
6717
6792
|
);
|
|
6793
|
+
},
|
|
6794
|
+
async getForProducts(productIds, opts) {
|
|
6795
|
+
const uniqueIds = [...new Set(productIds.map((id) => id.toLowerCase()))];
|
|
6796
|
+
const blocksByProduct = Object.fromEntries(uniqueIds.map((id) => [id, []]));
|
|
6797
|
+
if (uniqueIds.length === 0) return blocksByProduct;
|
|
6798
|
+
const ctx = getContext();
|
|
6799
|
+
for (let start = 0; start < uniqueIds.length; start += 50) {
|
|
6800
|
+
const batch = uniqueIds.slice(start, start + 50);
|
|
6801
|
+
const data = await executeGraphQL(
|
|
6802
|
+
graphqlUrl,
|
|
6803
|
+
WEBSITE_GET_PRODUCT_CONTENT_BATCH,
|
|
6804
|
+
{
|
|
6805
|
+
websiteId: ctx.websiteId,
|
|
6806
|
+
productIds: batch,
|
|
6807
|
+
locale: opts?.locale ?? DEFAULT_LOCALE
|
|
6808
|
+
},
|
|
6809
|
+
getHeaders
|
|
6810
|
+
);
|
|
6811
|
+
if (!data.result?.success) continue;
|
|
6812
|
+
for (const block of data.result.blocks ?? []) {
|
|
6813
|
+
const id = block.product_id.toLowerCase();
|
|
6814
|
+
if (Object.prototype.hasOwnProperty.call(blocksByProduct, id)) {
|
|
6815
|
+
blocksByProduct[id].push(mapProductContentBlock(block, storageUrl));
|
|
6816
|
+
}
|
|
6817
|
+
}
|
|
6818
|
+
}
|
|
6819
|
+
return blocksByProduct;
|
|
6718
6820
|
}
|
|
6719
6821
|
};
|
|
6720
6822
|
}
|
|
@@ -7429,6 +7531,7 @@ function createBacanoClient(config) {
|
|
|
7429
7531
|
await initialization;
|
|
7430
7532
|
},
|
|
7431
7533
|
getContext,
|
|
7534
|
+
flows: createFlowsClient(config),
|
|
7432
7535
|
auth: {
|
|
7433
7536
|
async getAccessToken() {
|
|
7434
7537
|
return config.getAccessToken ? await config.getAccessToken() : null;
|
|
@@ -7461,7 +7564,8 @@ function createBacanoClient(config) {
|
|
|
7461
7564
|
getByKey: contentModule.getByKey.bind(contentModule),
|
|
7462
7565
|
getByCategory: contentModule.getByCategory.bind(contentModule),
|
|
7463
7566
|
getByTag: contentModule.getByTag.bind(contentModule),
|
|
7464
|
-
getForProduct: contentModule.getForProduct.bind(contentModule)
|
|
7567
|
+
getForProduct: contentModule.getForProduct.bind(contentModule),
|
|
7568
|
+
getForProducts: contentModule.getForProducts.bind(contentModule)
|
|
7465
7569
|
},
|
|
7466
7570
|
forms: {
|
|
7467
7571
|
getDefinition: formsModule.getDefinition.bind(formsModule),
|
|
@@ -52,6 +52,8 @@ aplicar obligatoriamente `STOREFRONT_CONTENT_LOCATOR.md`; añadir
|
|
|
52
52
|
`AUTHENTICATION.md`, `STOREFRONT_LEADS.md`, `STOREFRONT_CLARITY.md` y
|
|
53
53
|
otros contratos únicamente cuando esas capacidades existan. Leer
|
|
54
54
|
`STOREFRONT_CONSTRUCTION.md` cuando el website permita ocultarse temporalmente.
|
|
55
|
+
Si la tienda acepta pagos, leer obligatoriamente `STOREFRONT_PAYMENTS.md` antes
|
|
56
|
+
de implementar, depurar o auditar checkout, retorno, reintentos o webhooks.
|
|
55
57
|
Si existen formularios administrados desde Bacano, leer obligatoriamente
|
|
56
58
|
`STOREFRONT_FORMS.md` y
|
|
57
59
|
[references/forms.md](references/forms.md) antes de auditarlos o modificarlos.
|
|
@@ -54,6 +54,8 @@ Aplicar además de los controles comunes.
|
|
|
54
54
|
|
|
55
55
|
## Pagos y pedidos
|
|
56
56
|
|
|
57
|
+
- Leer y aplicar `STOREFRONT_PAYMENTS.md`; no reconstruir en la tienda URLs,
|
|
58
|
+
credenciales ni payloads privados de Wompi, Mercado Pago o Addi.
|
|
57
59
|
- Ejecutar al menos un happy path real o sandbox por cada método crítico
|
|
58
60
|
publicado. Probar pago inmediato, transferencia, Wompi y contraentrega solo
|
|
59
61
|
si están activos; los estados alternos de cada proveedor quedan en su matriz
|
package/transport/documents.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ export declare const WEBSITE_GET_PRODUCT_SPECIFICATIONS = "\n mutation WebsiteG
|
|
|
13
13
|
export declare const GET_BRANDS = "\n query GetBrands($companyId: uuid!, $chainId: uuid!) {\n brands(\n where: {\n company_id: { _eq: $companyId }\n products: {\n chain_products: {\n chain_id: { _eq: $chainId }\n is_enabled: { _eq: true }\n status: { _eq: active }\n }\n }\n }\n order_by: { name: asc }\n ) {\n id\n name\n }\n }\n";
|
|
14
14
|
export declare const WEBSITE_GET_CONTENT = "\n mutation WebsiteGetContent(\n $websiteId: uuid!\n $key: String\n $categoryKey: String\n $tag: String\n $locale: String\n ) {\n result: websiteGetContent(\n website_id: $websiteId\n key: $key\n category_key: $categoryKey\n tag: $tag\n locale: $locale\n ) {\n success\n errors\n entries {\n \n id\n key\n category_key\n name\n locale\n status\n tags\n content_json\n resolved_fields\n published_at\n updated_at\n content_type {\n id\n key\n name\n kind\n }\n\n }\n }\n }\n";
|
|
15
15
|
export declare const WEBSITE_GET_PRODUCT_CONTENT = "\n mutation WebsiteGetProductContent(\n $websiteId: uuid!\n $productId: uuid!\n $locale: String\n ) {\n result: websiteGetProductContent(\n website_id: $websiteId\n product_id: $productId\n locale: $locale\n ) {\n success\n errors\n blocks {\n id\n product_id\n locale\n content_json\n resolved_fields\n sort_order\n updated_at\n content_type {\n id\n key\n name\n kind\n }\n }\n }\n }\n";
|
|
16
|
+
export declare const WEBSITE_GET_PRODUCT_CONTENT_BATCH = "\n mutation WebsiteGetProductContentBatch(\n $websiteId: uuid!\n $productIds: [uuid!]!\n $locale: String\n ) {\n result: websiteGetProductContentBatch(\n website_id: $websiteId\n product_ids: $productIds\n locale: $locale\n ) {\n success\n errors\n blocks {\n id\n product_id\n locale\n content_json\n resolved_fields\n sort_order\n updated_at\n content_type { id key name kind }\n }\n }\n }\n";
|
|
16
17
|
export declare const CHECK_AVAILABILITY = "\n query CheckAvailability(\n $variantIds: [uuid!]!\n $chainId: uuid!\n $websiteId: uuid\n ) {\n websiteProductAvailability(\n product_variant_ids: $variantIds\n chain_id: $chainId\n website_id: $websiteId\n ) {\n product_variant_id\n in_stock\n label\n max_purchasable_quantity\n }\n }\n";
|
|
17
18
|
export declare const GET_PRODUCT_LIVE_STATE = "\n query GetProductLiveState(\n $variantIds: [uuid!]!\n $companyId: uuid!\n $chainId: uuid!\n $websiteId: uuid!\n ) {\n product_variants(\n where: {\n id: { _in: $variantIds }\n is_disabled: { _eq: false }\n product: {\n company_id: { _eq: $companyId }\n product_website_publications: {\n website_id: { _eq: $websiteId }\n is_visible: { _eq: true }\n }\n chain_products: {\n chain_id: { _eq: $chainId }\n is_enabled: { _eq: true }\n status: { _eq: active }\n }\n }\n }\n ) {\n id\n product_variant_prices(\n where: {\n price_type: { _in: [CLIENT, SALE, WHOLESALE, WHOLESALE_2] }\n _or: [\n { chain_id: { _eq: $chainId } }\n { chain_id: { _is_null: true } }\n ]\n }\n ) {\n id\n price\n price_type\n chain_id\n }\n }\n websiteProductAvailability(\n product_variant_ids: $variantIds\n chain_id: $chainId\n website_id: $websiteId\n ) {\n product_variant_id\n in_stock\n label\n max_purchasable_quantity\n }\n }\n";
|
|
18
19
|
export declare const CREATE_CART = "\n mutation CreateCart(\n $websiteId: uuid!\n $cartToken: String\n $contact: WebsiteGuestContactInput\n $fulfillmentFamily: String\n ) {\n websiteCreateCart(\n website_id: $websiteId\n cart_token: $cartToken\n contact: $contact\n fulfillment_family: $fulfillmentFamily\n ) {\n success\n order_id\n cart_token\n cart {\n id\n status\n discount\n tax\n total_without_tax\n total_with_tax\n total_with_discount\n created_at\n updated_at\n volume_pricing {\n enabled\n eligibleQuantity\n appliedPriceType\n appliedMinQuantity\n nextPriceType\n nextMinQuantity\n remainingQuantity\n totalSavings\n }\n items {\n id\n product_variant_id\n quantity\n unit_price\n line_total\n base_unit_price\n unit_savings\n line_savings\n volume_pricing_eligible\n resolved_price_type\n volume_pricing_min_quantity\n product_variant {\n id\n sku\n product {\n id\n name\n }\n prices {\n id\n price\n price_type\n chain_id\n }\n }\n }\n }\n errors\n }\n }\n";
|
|
@@ -33,7 +34,7 @@ export declare const VALIDATE_COUPON = "\n mutation ValidateCoupon(\n $order
|
|
|
33
34
|
export declare const APPLY_COUPON = "\n mutation ApplyCoupon($orderId: uuid!, $cartToken: String!, $code: String!) {\n websiteApplyCoupon(\n order_id: $orderId\n cart_token: $cartToken\n code: $code\n ) {\n success\n order_id\n coupon_id\n code\n name\n coupon_type\n discount_amount\n eligible_subtotal\n message\n cart {\n id\n status\n discount\n total_without_tax\n tax\n total_with_tax\n total_with_discount\n created_at\n updated_at\n items {\n id\n product_variant_id\n quantity\n product_variant {\n id\n sku\n product {\n id\n name\n }\n prices {\n id\n price\n price_type\n chain_id\n }\n }\n }\n }\n errors\n }\n }\n";
|
|
34
35
|
export declare const REMOVE_COUPON = "\n mutation RemoveCoupon(\n $orderId: uuid!\n $cartToken: String!\n $couponId: uuid!\n ) {\n websiteRemoveCoupon(\n order_id: $orderId\n cart_token: $cartToken\n coupon_id: $couponId\n ) {\n success\n order_id\n coupon_id\n code\n name\n coupon_type\n discount_amount\n eligible_subtotal\n message\n cart {\n id\n status\n discount\n total_without_tax\n tax\n total_with_tax\n total_with_discount\n created_at\n updated_at\n items {\n id\n product_variant_id\n quantity\n product_variant {\n id\n sku\n product {\n id\n name\n }\n prices {\n id\n price\n price_type\n chain_id\n }\n }\n }\n }\n errors\n }\n }\n";
|
|
35
36
|
export declare const CREATE_PAYMENT_SESSION = "\n mutation CreatePaymentSession(\n $orderId: uuid!\n $cartToken: String\n $publicOrderToken: String\n $paymentMethodId: uuid!\n $returnUrl: String!\n ) {\n websiteCreatePaymentSession(\n order_id: $orderId\n cart_token: $cartToken\n public_order_token: $publicOrderToken\n payment_method_id: $paymentMethodId\n return_url: $returnUrl\n ) {\n success\n order_id\n payment_method_id\n payment_session_id\n gateway_code\n integration_mode\n status\n redirect_url\n public_payload\n errors\n }\n }\n";
|
|
36
|
-
export declare const RECONCILE_PAYMENT_SESSION = "\n mutation ReconcilePaymentSession(\n $orderId: uuid!\n $publicOrderToken: String!\n $paymentSessionId: uuid!\n $gatewayTransactionId: String
|
|
37
|
+
export declare const RECONCILE_PAYMENT_SESSION = "\n mutation ReconcilePaymentSession(\n $orderId: uuid!\n $publicOrderToken: String!\n $paymentSessionId: uuid!\n $gatewayTransactionId: String\n ) {\n websiteReconcilePaymentSession(\n order_id: $orderId\n public_order_token: $publicOrderToken\n payment_session_id: $paymentSessionId\n gateway_transaction_id: $gatewayTransactionId\n ) {\n success\n order_id\n payment_method_id\n payment_session_id\n gateway_code\n integration_mode\n status\n redirect_url\n public_payload\n errors\n }\n }\n";
|
|
37
38
|
export declare const GET_ORDERS = "\n query GetOrders($limit: Int = 20, $offset: Int = 0) {\n orders(\n where: { order_number: { _is_null: false } }\n order_by: { created_at: desc }\n limit: $limit\n offset: $offset\n ) {\n id\n order_number\n status\n fulfillment_family\n discount\n tax\n total_without_tax\n total_with_tax\n total_with_discount\n created_at\n updated_at\n order_product_variants {\n id\n product_variant_id\n quantity\n product_variant {\n sku\n product {\n id\n name\n }\n }\n }\n }\n }\n";
|
|
38
39
|
export declare const GET_ORDER_BY_PK = "\n query GetOrderByPk($orderId: uuid!) {\n orders(where: { id: { _eq: $orderId } }) {\n id\n order_number\n status\n fulfillment_family\n discount\n tax\n total_without_tax\n total_with_tax\n total_with_discount\n created_at\n updated_at\n order_product_variants {\n id\n product_variant_id\n quantity\n product_variant {\n sku\n product {\n id\n name\n }\n }\n }\n }\n }\n";
|
|
39
40
|
export declare const GET_PUBLIC_ORDER = "\n mutation GetPublicOrder($websiteId: uuid!, $orderId: uuid!, $token: String!) {\n websiteGetPublicOrder(\n website_id: $websiteId\n order_id: $orderId\n token: $token\n ) {\n success\n order {\n order_id\n order_number\n status\n payment_status\n fulfillment_family\n delivery {\n fulfillment_family\n shipping {\n label\n amount\n method_type\n collection_mode\n total_policy\n address\n }\n pickup {\n label\n }\n }\n payment {\n mode\n label\n method {\n id\n label\n payment_method_type\n gateway_code\n requires_payment_session\n }\n initial_payment {\n amount\n payment_method_id\n method_label\n payment_method_type\n gateway_code\n requires_payment_session\n }\n requires_payment_session\n next_action\n session {\n id\n gateway_code\n integration_mode\n status\n reference\n amount\n currency\n gateway_transaction_id\n error_message\n expires_at\n created_at\n updated_at\n }\n }\n totals {\n subtotal\n tax\n discount\n total\n total_with_discount\n }\n items {\n id\n product_variant_id\n sku\n name\n image_file_id\n quantity\n unit_price\n line_total\n }\n next_steps\n created_at\n updated_at\n }\n errors\n }\n }\n";
|
package/types.d.ts
CHANGED
|
@@ -151,7 +151,7 @@ export interface WebsiteCampaignCaptureResult {
|
|
|
151
151
|
}
|
|
152
152
|
export type WebsiteFormAction = "STORE_RESPONSE" | "CAPTURE_LEAD";
|
|
153
153
|
export type WebsiteFormStatus = "ACTIVE" | "PAUSED";
|
|
154
|
-
export type WebsiteFormFieldType = "text" | "textarea" | "email" | "phone" | "number" | "date" | "select" | "radio" | "multi_select" | "checkbox";
|
|
154
|
+
export type WebsiteFormFieldType = "text" | "textarea" | "email" | "phone" | "number" | "scale" | "date" | "select" | "radio" | "multi_select" | "checkbox";
|
|
155
155
|
export interface WebsiteFormOption {
|
|
156
156
|
value: string;
|
|
157
157
|
label: string;
|
|
@@ -164,10 +164,23 @@ export type WebsiteFormOptionSource = {
|
|
|
164
164
|
listKey: string;
|
|
165
165
|
};
|
|
166
166
|
export interface WebsiteFormField {
|
|
167
|
+
/** A single-choice question may reveal one branch, recursively. */
|
|
168
|
+
branches?: Array<{
|
|
169
|
+
value: string;
|
|
170
|
+
fields: WebsiteFormField[];
|
|
171
|
+
}>;
|
|
167
172
|
key: string;
|
|
168
173
|
label: string;
|
|
169
174
|
type: WebsiteFormFieldType;
|
|
170
175
|
required: boolean;
|
|
176
|
+
/** Discrete integer scale; submitted as a string, stored as a number. */
|
|
177
|
+
scale?: {
|
|
178
|
+
min: number;
|
|
179
|
+
max: number;
|
|
180
|
+
display: "numbers" | "stars";
|
|
181
|
+
minLabel?: string;
|
|
182
|
+
maxLabel?: string;
|
|
183
|
+
};
|
|
171
184
|
placeholder?: string | null;
|
|
172
185
|
helpText?: string | null;
|
|
173
186
|
optionSource?: WebsiteFormOptionSource | null;
|