@mohasinac/appkit 4.61.0 → 4.62.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.build-stamp.json +3 -3
- package/dist/_internal/client/features/lottery/LotteryAdminEditView.js +19 -3
- package/dist/_internal/client/features/maintenance/views/AnalysisRunnerView.js +1 -1
- package/dist/_internal/client/features/maintenance/views/CloudLogsListView.js +1 -1
- package/dist/_internal/server/features/checkout/actions.d.ts +80 -0
- package/dist/_internal/server/features/checkout/actions.js +542 -26
- package/dist/_internal/server/features/invoicing/allocate.d.ts +63 -0
- package/dist/_internal/server/features/invoicing/allocate.js +162 -0
- package/dist/_internal/server/features/invoicing/credit-note.d.ts +57 -0
- package/dist/_internal/server/features/invoicing/credit-note.js +126 -0
- package/dist/_internal/server/features/invoicing/gstr1.d.ts +74 -0
- package/dist/_internal/server/features/invoicing/gstr1.js +251 -0
- package/dist/_internal/server/features/invoicing/issue.d.ts +96 -0
- package/dist/_internal/server/features/invoicing/issue.js +202 -0
- package/dist/_internal/server/features/orders/actions.d.ts +8 -1
- package/dist/_internal/server/features/orders/actions.js +81 -8
- package/dist/_internal/server/features/orders/adapters.js +33 -0
- package/dist/_internal/server/features/orders/cancellation-refund.d.ts +15 -9
- package/dist/_internal/server/features/orders/cancellation-refund.js +15 -9
- package/dist/_internal/server/features/points/award.js +46 -4
- package/dist/_internal/server/features/refunds/actions.js +26 -0
- package/dist/_internal/server/features/shipping/courier-block.d.ts +69 -0
- package/dist/_internal/server/features/shipping/courier-block.js +239 -0
- package/dist/_internal/server/features/site-settings/adapters.d.ts +1 -1
- package/dist/_internal/server/features/site-settings/adapters.js +15 -0
- package/dist/_internal/server/features/stores/adapters.d.ts +2 -2
- package/dist/_internal/server/features/stores/adapters.js +51 -0
- package/dist/_internal/server/functions/scheduled.js +38 -1
- package/dist/_internal/server/jobs/core/autoPayoutEligibility.js +9 -2
- package/dist/_internal/server/jobs/core/dailyStatusDigest.d.ts +4 -0
- package/dist/_internal/server/jobs/core/dailyStatusDigest.js +19 -2
- package/dist/_internal/server/jobs/core/index.d.ts +2 -1
- package/dist/_internal/server/jobs/core/index.js +2 -1
- package/dist/_internal/server/jobs/core/onJobCreated.d.ts +30 -7
- package/dist/_internal/server/jobs/core/onJobCreated.js +78 -45
- package/dist/_internal/server/jobs/core/onOrderStatusChange.d.ts +7 -0
- package/dist/_internal/server/jobs/core/onOrderStatusChange.js +62 -0
- package/dist/_internal/server/jobs/core/paymentReconcile.js +87 -97
- package/dist/_internal/server/jobs/core/paymentWindowTimeout.js +33 -0
- package/dist/_internal/server/jobs/core/runJobOnce.d.ts +48 -0
- package/dist/_internal/server/jobs/core/runJobOnce.js +195 -0
- package/dist/_internal/server/jobs/core/weeklyPayoutEligibility.js +10 -2
- package/dist/_internal/server/jobs/handlers/onOrderStatusChange.js +17 -0
- package/dist/_internal/server/notifications/channel-health.d.ts +26 -3
- package/dist/_internal/shared/actions/action-registry.js +177 -9
- package/dist/_internal/shared/checkout/coupon-discount.d.ts +43 -1
- package/dist/_internal/shared/checkout/coupon-discount.js +26 -1
- package/dist/_internal/shared/checkout/order-math.d.ts +145 -0
- package/dist/_internal/shared/checkout/order-math.js +173 -0
- package/dist/_internal/shared/checkout/refundable-base.d.ts +25 -0
- package/dist/_internal/shared/checkout/refundable-base.js +13 -1
- package/dist/_internal/shared/checkout/split.d.ts +87 -0
- package/dist/_internal/shared/checkout/split.js +100 -0
- package/dist/_internal/shared/content/disclaimers.d.ts +88 -0
- package/dist/_internal/shared/content/disclaimers.js +217 -0
- package/dist/_internal/shared/content/published-values.d.ts +88 -0
- package/dist/_internal/shared/content/published-values.js +198 -0
- package/dist/_internal/shared/features/admin/integrations.d.ts +109 -0
- package/dist/_internal/shared/features/admin/integrations.js +253 -0
- package/dist/_internal/shared/features/orders/dispute-reasons.d.ts +113 -0
- package/dist/_internal/shared/features/orders/dispute-reasons.js +181 -0
- package/dist/_internal/shared/features/orders/refund-copy.d.ts +1 -1
- package/dist/_internal/shared/features/orders/refund-copy.js +18 -1
- package/dist/_internal/shared/features/points/accepts.d.ts +36 -0
- package/dist/_internal/shared/features/points/accepts.js +43 -0
- package/dist/_internal/shared/features/shipping/shared-purchase.d.ts +91 -0
- package/dist/_internal/shared/features/shipping/shared-purchase.js +108 -0
- package/dist/_internal/shared/features/site-settings/types.d.ts +11 -0
- package/dist/_internal/shared/fees/calculator.d.ts +33 -1
- package/dist/_internal/shared/fees/calculator.js +32 -2
- package/dist/_internal/shared/media/limits.d.ts +10 -0
- package/dist/_internal/shared/media/limits.js +10 -0
- package/dist/_internal/shared/types/action-result.js +15 -1
- package/dist/client/api/surface-error.js +16 -2
- package/dist/client/api/useApiMutation.js +17 -1
- package/dist/client.d.ts +12 -1
- package/dist/client.js +31 -1
- package/dist/constants/api-endpoints.d.ts +45 -0
- package/dist/constants/api-endpoints.js +15 -0
- package/dist/constants/field-names.d.ts +18 -0
- package/dist/constants/field-names.js +28 -0
- package/dist/contracts/index.d.ts +1 -1
- package/dist/contracts/shipping.d.ts +45 -0
- package/dist/contracts/shipping.js +15 -0
- package/dist/core/server-action.js +19 -3
- package/dist/errors/error-mapping.js +26 -1
- package/dist/features/about/components/AboutView.js +1 -1
- package/dist/features/account/components/BuyerAuctionsGuideView.js +4 -1
- package/dist/features/account/components/UserOffersPanel.js +5 -3
- package/dist/features/account/components/UserOrdersView.js +19 -33
- package/dist/features/admin/components/AdminActionIndexView.js +100 -5
- package/dist/features/admin/components/AdminAddressClustersView.js +21 -2
- package/dist/features/admin/components/AdminBlogEditorView.js +8 -8
- package/dist/features/admin/components/AdminCarouselEditorView.js +1 -1
- package/dist/features/admin/components/AdminCarouselView.js +96 -4
- package/dist/features/admin/components/AdminCouponEditorView.js +17 -0
- package/dist/features/admin/components/AdminFulfillmentView.js +3 -2
- package/dist/features/admin/components/AdminInvoicingView.d.ts +2 -0
- package/dist/features/admin/components/AdminInvoicingView.js +65 -0
- package/dist/features/admin/components/AdminMediaView.js +36 -3
- package/dist/features/admin/components/AdminNavigationView.js +4 -1
- package/dist/features/admin/components/AdminOffersView.js +2 -1
- package/dist/features/admin/components/AdminOrderEditorView.d.ts +18 -1
- package/dist/features/admin/components/AdminOrderEditorView.js +11 -2
- package/dist/features/admin/components/AdminOrdersGuideView.js +23 -2
- package/dist/features/admin/components/AdminOrdersView.js +67 -5
- package/dist/features/admin/components/AdminPaymentClustersView.js +19 -2
- package/dist/features/admin/components/AdminProductEditorView.js +2 -2
- package/dist/features/admin/components/AdminSectionsView.d.ts +10 -0
- package/dist/features/admin/components/AdminSectionsView.js +486 -224
- package/dist/features/admin/components/OwnerQuickActions.js +24 -2
- package/dist/features/admin/components/ReferenceRecordEditor.js +1 -1
- package/dist/features/admin/constants/filter-tabs.d.ts +6 -0
- package/dist/features/admin/constants/filter-tabs.js +6 -0
- package/dist/features/admin/constants/site-settings-tabs.d.ts +1 -1
- package/dist/features/admin/hooks/useAdminListingData.js +16 -0
- package/dist/features/admin/hooks/useOptimisticRowFlag.d.ts +33 -0
- package/dist/features/admin/hooks/useOptimisticRowFlag.js +87 -0
- package/dist/features/admin/repository/notification.repository.d.ts +15 -0
- package/dist/features/admin/repository/notification.repository.js +32 -0
- package/dist/features/admin/schemas/action-index-form.d.ts +34 -0
- package/dist/features/admin/schemas/action-index-form.js +115 -0
- package/dist/features/admin/schemas/admin-user-form.d.ts +2 -2
- package/dist/features/admin/schemas/firestore.d.ts +30 -0
- package/dist/features/admin/schemas/firestore.js +5 -0
- package/dist/features/audit-log/schemas/firestore.d.ts +30 -0
- package/dist/features/audit-log/schemas/firestore.js +15 -0
- package/dist/features/auth/components/RegisterForm.js +2 -1
- package/dist/features/auth/permissions/constants.js +13 -0
- package/dist/features/cart/components/CartPriceBreakdown.d.ts +13 -0
- package/dist/features/cart/components/CartPriceBreakdown.js +6 -2
- package/dist/features/cart/components/PointsTenderPicker.d.ts +61 -0
- package/dist/features/cart/components/PointsTenderPicker.js +15 -0
- package/dist/features/cart/components/StoreAddonsPicker.js +2 -1
- package/dist/features/cart/components/index.d.ts +2 -0
- package/dist/features/cart/components/index.js +1 -0
- package/dist/features/cart/repository/cart.repository.d.ts +19 -0
- package/dist/features/cart/repository/cart.repository.js +27 -0
- package/dist/features/cart/schemas/firestore.d.ts +92 -0
- package/dist/features/catalogue/components/CatalogueItemEditorView.js +3 -3
- package/dist/features/contact/email.d.ts +27 -10
- package/dist/features/contact/email.js +20 -3
- package/dist/features/dispute-reasons/repository/dispute-reasons.repository.d.ts +38 -0
- package/dist/features/dispute-reasons/repository/dispute-reasons.repository.js +80 -0
- package/dist/features/dispute-reasons/schemas/firestore.d.ts +64 -0
- package/dist/features/dispute-reasons/schemas/firestore.js +40 -0
- package/dist/features/events/components/AdminEventEditorView.js +8 -6
- package/dist/features/faq/components/FAQAccordion.d.ts +13 -1
- package/dist/features/faq/components/FAQAccordion.js +29 -4
- package/dist/features/invoicing/schemas/firestore.d.ts +112 -0
- package/dist/features/invoicing/schemas/firestore.js +45 -0
- package/dist/features/invoicing/utils/financial-year.d.ts +43 -0
- package/dist/features/invoicing/utils/financial-year.js +53 -0
- package/dist/features/jobs/actions/enqueue-job.js +18 -1
- package/dist/features/jobs/repository/jobs.repository.d.ts +62 -1
- package/dist/features/jobs/repository/jobs.repository.js +84 -1
- package/dist/features/jobs/schemas/firestore.d.ts +80 -0
- package/dist/features/jobs/schemas/firestore.js +37 -0
- package/dist/features/layout/hooks/useFormBottomActions.js +20 -1
- package/dist/features/lottery/schemas/zod.d.ts +6 -6
- package/dist/features/media/MediaImage.js +22 -1
- package/dist/features/media/upload/ImageUpload.js +1 -1
- package/dist/features/obligations/constants/policies.js +24 -1
- package/dist/features/orders/components/EmiInstallmentsPanel.js +25 -7
- package/dist/features/orders/components/OrderPaymentSummary.js +10 -1
- package/dist/features/orders/components/OrderProvenanceCard.d.ts +8 -0
- package/dist/features/orders/components/OrderProvenanceCard.js +185 -0
- package/dist/features/orders/components/RaiseDisputeForm.d.ts +14 -0
- package/dist/features/orders/components/RaiseDisputeForm.js +111 -0
- package/dist/features/orders/components/RefundRequestView.js +22 -4
- package/dist/features/orders/components/index.d.ts +4 -0
- package/dist/features/orders/components/index.js +2 -0
- package/dist/features/orders/constants/order-lane-tabs.d.ts +69 -0
- package/dist/features/orders/constants/order-lane-tabs.js +88 -0
- package/dist/features/orders/repository/orders.repository.d.ts +57 -0
- package/dist/features/orders/repository/orders.repository.js +145 -0
- package/dist/features/orders/schemas/firestore.d.ts +196 -1
- package/dist/features/orders/schemas/index.d.ts +60 -12
- package/dist/features/orders/schemas/index.js +12 -0
- package/dist/features/orders/types/index.d.ts +26 -0
- package/dist/features/orders/utils/courier-block.d.ts +25 -0
- package/dist/features/orders/utils/courier-block.js +23 -0
- package/dist/features/payment-cases/schemas/firestore.d.ts +26 -1
- package/dist/features/payment-cases/schemas/firestore.js +1 -0
- package/dist/features/products/components/GroupMemberPicker.js +4 -1
- package/dist/features/products/components/PrizeDrawDetailPageView.js +2 -2
- package/dist/features/products/components/PrizeDrawEntryActions.js +2 -1
- package/dist/features/products/components/ProductDetailActions.js +2 -1
- package/dist/features/products/components/ProductDetailPageView.d.ts +17 -1
- package/dist/features/products/components/ProductDetailPageView.js +2 -2
- package/dist/features/products/schemas/product-features.validators.d.ts +10 -10
- package/dist/features/promotions/actions/coupon-stacking.d.ts +30 -3
- package/dist/features/promotions/actions/coupon-stacking.js +21 -2
- package/dist/features/promotions/components/CouponCard.js +13 -0
- package/dist/features/promotions/constants/coupon-help.d.ts +2 -2
- package/dist/features/promotions/constants/coupon-help.js +9 -1
- package/dist/features/promotions/schemas/firestore.d.ts +24 -0
- package/dist/features/promotions/schemas/firestore.js +4 -0
- package/dist/features/promotions/types/index.d.ts +19 -1
- package/dist/features/scams/components/ScamProfileView.js +2 -2
- package/dist/features/scams/components/ScamRegistryView.js +2 -2
- package/dist/features/search/action-index/tab-entries.js +1 -1
- package/dist/features/seller/actions/seller-actions.js +33 -3
- package/dist/features/seller/components/FulfillmentView.js +3 -2
- package/dist/features/seller/components/SellerAddressesView.js +32 -4
- package/dist/features/seller/components/SellerAnalyticsAlertsView.js +62 -3
- package/dist/features/seller/components/SellerBundlesView.js +53 -14
- package/dist/features/seller/components/SellerGroupedListingsView.js +23 -3
- package/dist/features/seller/components/SellerListingTypeView.js +56 -10
- package/dist/features/seller/components/SellerOrdersView.js +129 -27
- package/dist/features/seller/components/SellerPayoutMethodsView.js +33 -1
- package/dist/features/seller/components/SellerPayoutSettingsView.js +48 -9
- package/dist/features/seller/components/SellerProductsView.js +5 -1
- package/dist/features/seller/components/SellerShippingConfigsView.js +33 -1
- package/dist/features/seller/components/SellerShippingView.js +2 -1
- package/dist/features/seller/components/SellerStoreCategoriesView.js +33 -1
- package/dist/features/seller/components/SellerSupportView.js +69 -2
- package/dist/features/seller/hooks/useSellerListingData.js +25 -0
- package/dist/features/shell/SectionForm.js +20 -16
- package/dist/features/shell/build-sections.js +14 -1
- package/dist/features/shipments/components/AdminShipmentLotItemsView.js +54 -1
- package/dist/features/shipments/components/AdminShipmentProjectionsView.js +3 -2
- package/dist/features/shipments/schemas/validation.d.ts +4 -4
- package/dist/features/shipping-boxes/repository/shipping-boxes.repository.d.ts +43 -0
- package/dist/features/shipping-boxes/repository/shipping-boxes.repository.js +90 -0
- package/dist/features/shipping-boxes/schemas/firestore.d.ts +82 -0
- package/dist/features/shipping-boxes/schemas/firestore.js +53 -0
- package/dist/features/sticker-trace/components/StickerCommitPanel.js +2 -1
- package/dist/features/sticker-trace/components/StickerPrintPanel.js +2 -1
- package/dist/features/sticker-trace/components/StickerRetryPanel.js +24 -4
- package/dist/features/sticker-trace/components/StickerTraceStudio.js +2 -1
- package/dist/features/store-extensions/schemas/report-create-form.d.ts +2 -2
- package/dist/features/store-extensions/schemas/shipping-config-form.d.ts +2 -2
- package/dist/features/stores/components/StoreOrdersGuideView.js +6 -1
- package/dist/features/stores/schemas/firestore.d.ts +71 -0
- package/dist/features/stores/types/index.d.ts +19 -0
- package/dist/features/support/schemas/index.d.ts +6 -6
- package/dist/features/tester/components/AdminTesterFeedbackIssuesView.js +3 -2
- package/dist/features/wishlist/hooks/useWishlistWithGuest.d.ts +1 -1
- package/dist/index.d.ts +11 -2
- package/dist/index.js +17 -2
- package/dist/next/routing/route-map.d.ts +24 -0
- package/dist/next/routing/route-map.js +19 -0
- package/dist/providers/shipping-shiprocket/index.d.ts +27 -1
- package/dist/providers/shipping-shiprocket/index.js +84 -1
- package/dist/schemas/registry.d.ts +51 -22
- package/dist/schemas/sieve.d.ts +5 -5
- package/dist/server-entry.d.ts +2 -2
- package/dist/server-entry.js +8 -1
- package/dist/server.d.ts +11 -2
- package/dist/server.js +40 -2
- package/dist/styles.css +64 -80
- package/dist/tailwind-utilities.css +1 -1
- package/dist/tokens/themes/default-dark.js +1 -0
- package/dist/tokens/themes/default-light.js +1 -0
- package/dist/tokens/themes/required.d.ts +1 -1
- package/dist/tokens/themes/required.js +1 -0
- package/dist/tokens/tokens.css +15 -0
- package/dist/ui/components/Checkbox.js +10 -2
- package/dist/ui/components/DateInput.js +8 -1
- package/dist/ui/components/Disclaimer.d.ts +19 -0
- package/dist/ui/components/Disclaimer.js +74 -0
- package/dist/ui/components/Input.js +22 -2
- package/dist/ui/components/PaginatedSelect.d.ts +8 -19
- package/dist/ui/components/PaginatedSelect.js +43 -9
- package/dist/ui/components/Radio.js +8 -1
- package/dist/ui/components/Select.js +10 -2
- package/dist/ui/components/TagInput.d.ts +8 -1
- package/dist/ui/components/TagInput.js +4 -3
- package/dist/ui/components/Textarea.js +10 -2
- package/dist/ui/components/tabs-overflow.js +64 -11
- package/dist/ui/forms/FieldCheckbox.js +1 -1
- package/dist/ui/forms/FormErrorList.d.ts +0 -16
- package/dist/ui/forms/FormErrorList.js +34 -1
- package/dist/ui/forms/apply-zod-issues.d.ts +19 -1
- package/dist/ui/forms/apply-zod-issues.js +23 -1
- package/dist/ui/index.d.ts +2 -0
- package/dist/ui/index.js +6 -0
- package/dist/ui/rich-text/RichText.style.css +48 -79
- package/package.json +1 -1
- package/scripts/seed-cli.mjs +1831 -1822
|
@@ -54,6 +54,7 @@ export const DEFAULT_DARK_THEME = {
|
|
|
54
54
|
"appkit-color-text": "#fafafa",
|
|
55
55
|
"appkit-color-text-muted": "#b4b4bd",
|
|
56
56
|
"appkit-color-text-faint": "#8b8b94",
|
|
57
|
+
"appkit-color-link": "#22d3ee",
|
|
57
58
|
"appkit-color-success": "#34d399",
|
|
58
59
|
"appkit-color-success-surface": "rgba(6, 78, 59, 0.25)",
|
|
59
60
|
"appkit-color-warning": "#fbbf24",
|
|
@@ -57,6 +57,7 @@ export const DEFAULT_LIGHT_THEME = {
|
|
|
57
57
|
"appkit-color-text-muted": "#5b5b63",
|
|
58
58
|
"appkit-color-text-faint": "#6f6f78",
|
|
59
59
|
"appkit-color-text-on-primary": "#ffffff",
|
|
60
|
+
"appkit-color-link": "#0f766e",
|
|
60
61
|
"appkit-color-success": "#15803d",
|
|
61
62
|
"appkit-color-success-surface": "#f0fdf4",
|
|
62
63
|
"appkit-color-warning": "#b45309",
|
|
@@ -10,6 +10,6 @@ import type { GradientKey } from "./types";
|
|
|
10
10
|
* unknown keys are rejected; missing keys fall back to the active mode's
|
|
11
11
|
* default theme value (so a theme can override only a subset).
|
|
12
12
|
*/
|
|
13
|
-
export declare const REQUIRED_THEME_TOKENS: readonly ["appkit-color-primary", "appkit-color-primary-50", "appkit-color-primary-100", "appkit-color-primary-200", "appkit-color-primary-300", "appkit-color-primary-400", "appkit-color-primary-500", "appkit-color-primary-600", "appkit-color-primary-700", "appkit-color-primary-800", "appkit-color-primary-900", "appkit-color-primary-950", "appkit-color-secondary", "appkit-color-secondary-50", "appkit-color-secondary-100", "appkit-color-secondary-200", "appkit-color-secondary-300", "appkit-color-secondary-400", "appkit-color-secondary-500", "appkit-color-secondary-600", "appkit-color-secondary-700", "appkit-color-secondary-800", "appkit-color-secondary-900", "appkit-color-secondary-950", "appkit-color-bg", "appkit-color-surface", "appkit-color-surface-elevated", "appkit-color-surface-input", "appkit-color-border", "appkit-color-border-subtle", "appkit-color-text", "appkit-color-text-muted", "appkit-color-text-faint", "appkit-color-text-on-primary", "appkit-color-success", "appkit-color-success-surface", "appkit-color-warning", "appkit-color-warning-surface", "appkit-color-error", "appkit-color-error-surface", "appkit-color-info", "appkit-color-info-surface", "appkit-color-focus-ring", "appkit-shadow-glow", "appkit-shadow-glow-pink", "appkit-font-display", "appkit-font-sans", "appkit-font-editorial", "appkit-font-mono", "appkit-space-0-5", "appkit-space-1", "appkit-space-1-5", "appkit-space-2", "appkit-space-2-5", "appkit-space-3", "appkit-space-3-5", "appkit-space-4", "appkit-space-5", "appkit-space-6", "appkit-space-8", "appkit-space-10", "appkit-space-12", "appkit-space-14", "appkit-space-16", "appkit-space-18", "appkit-space-20", "appkit-space-24", "appkit-text-2xs", "appkit-text-xs", "appkit-text-sm", "appkit-text-base", "appkit-text-lg", "appkit-text-xl", "appkit-text-2xl", "appkit-text-3xl", "appkit-text-4xl", "appkit-text-5xl"];
|
|
13
|
+
export declare const REQUIRED_THEME_TOKENS: readonly ["appkit-color-primary", "appkit-color-primary-50", "appkit-color-primary-100", "appkit-color-primary-200", "appkit-color-primary-300", "appkit-color-primary-400", "appkit-color-primary-500", "appkit-color-primary-600", "appkit-color-primary-700", "appkit-color-primary-800", "appkit-color-primary-900", "appkit-color-primary-950", "appkit-color-secondary", "appkit-color-secondary-50", "appkit-color-secondary-100", "appkit-color-secondary-200", "appkit-color-secondary-300", "appkit-color-secondary-400", "appkit-color-secondary-500", "appkit-color-secondary-600", "appkit-color-secondary-700", "appkit-color-secondary-800", "appkit-color-secondary-900", "appkit-color-secondary-950", "appkit-color-bg", "appkit-color-surface", "appkit-color-surface-elevated", "appkit-color-surface-input", "appkit-color-border", "appkit-color-border-subtle", "appkit-color-text", "appkit-color-text-muted", "appkit-color-text-faint", "appkit-color-text-on-primary", "appkit-color-link", "appkit-color-success", "appkit-color-success-surface", "appkit-color-warning", "appkit-color-warning-surface", "appkit-color-error", "appkit-color-error-surface", "appkit-color-info", "appkit-color-info-surface", "appkit-color-focus-ring", "appkit-shadow-glow", "appkit-shadow-glow-pink", "appkit-font-display", "appkit-font-sans", "appkit-font-editorial", "appkit-font-mono", "appkit-space-0-5", "appkit-space-1", "appkit-space-1-5", "appkit-space-2", "appkit-space-2-5", "appkit-space-3", "appkit-space-3-5", "appkit-space-4", "appkit-space-5", "appkit-space-6", "appkit-space-8", "appkit-space-10", "appkit-space-12", "appkit-space-14", "appkit-space-16", "appkit-space-18", "appkit-space-20", "appkit-space-24", "appkit-text-2xs", "appkit-text-xs", "appkit-text-sm", "appkit-text-base", "appkit-text-lg", "appkit-text-xl", "appkit-text-2xl", "appkit-text-3xl", "appkit-text-4xl", "appkit-text-5xl"];
|
|
14
14
|
export type RequiredThemeToken = (typeof REQUIRED_THEME_TOKENS)[number];
|
|
15
15
|
export declare const REQUIRED_GRADIENT_KEYS: readonly GradientKey[];
|
package/dist/tokens/tokens.css
CHANGED
|
@@ -302,6 +302,15 @@
|
|
|
302
302
|
--appkit-color-text-on-primary: #ffffff;
|
|
303
303
|
--appkit-color-text-on-dark: #ffffff;
|
|
304
304
|
|
|
305
|
+
/* Link ink for long-form prose. A SEPARATE token because the right link
|
|
306
|
+
* colour is not the same ramp in every theme: default-light wants primary
|
|
307
|
+
* (teal), default-dark wants secondary (cyan) because its primary is a RED
|
|
308
|
+
* that reads as danger, and cobalt-night's primary IS blue. Binding prose
|
|
309
|
+
* links to `primary-600` instead would be #dc2626 on the dark theme.
|
|
310
|
+
* primary-700, not -600: #0d9488 is only 3.59:1 on --appkit-color-bg and
|
|
311
|
+
* fails AA for normal text; #0f766e is 5.24:1. */
|
|
312
|
+
--appkit-color-link: #0f766e; /* primary-700 — 5.24:1 on --appkit-color-bg */
|
|
313
|
+
|
|
305
314
|
--appkit-color-success: #15803d; /* green-700 — 4.5:1 AA against success-surface, distinct from the new teal primary */
|
|
306
315
|
--appkit-color-success-surface: #f0fdf4; /* green-50 */
|
|
307
316
|
--appkit-color-warning: #b45309; /* amber-700 — 4.5:1 AA against warning-surface */
|
|
@@ -500,6 +509,8 @@
|
|
|
500
509
|
--appkit-color-text-muted: #b4b4bd; /* lightened from zinc-400 #a1a1aa — ~9:1 on the dark page */
|
|
501
510
|
--appkit-color-text-faint: #8b8b94; /* lightened from zinc-500 #71717a, which was ~3:1 and read as barely present */
|
|
502
511
|
|
|
512
|
+
--appkit-color-link: #22d3ee; /* secondary-400 — 11.16:1 on --appkit-color-bg. NOT primary: this theme's primary is crimson */
|
|
513
|
+
|
|
503
514
|
--appkit-color-success: #34d399; /* emerald-400 */
|
|
504
515
|
--appkit-color-success-surface: rgba(6, 78, 59, 0.25);
|
|
505
516
|
--appkit-color-warning: #fbbf24; /* amber-400 */
|
|
@@ -620,6 +631,8 @@
|
|
|
620
631
|
--appkit-color-text-muted: #bcd4ff; /* primary-200 */
|
|
621
632
|
--appkit-color-text-faint: #8eb9ff; /* primary-300 */
|
|
622
633
|
|
|
634
|
+
--appkit-color-link: #5992ff; /* primary-500 — 5.17:1 on --appkit-color-bg */
|
|
635
|
+
|
|
623
636
|
--appkit-color-success: #4ade80;
|
|
624
637
|
--appkit-color-success-surface: rgba(20, 83, 45, 0.3);
|
|
625
638
|
--appkit-color-warning: #fbbf24;
|
|
@@ -652,6 +665,8 @@
|
|
|
652
665
|
--appkit-color-surface-elevated: #ffffff;
|
|
653
666
|
--appkit-color-surface-input: #fffbeb; /* amber-50 */
|
|
654
667
|
|
|
668
|
+
--appkit-color-link: #b45309; /* amber-700 — 4.73:1 on --appkit-color-bg; primary-600 #d97706 is only 3.0:1 */
|
|
669
|
+
|
|
655
670
|
/* --- Interactive surfaces ------------------------------------------------
|
|
656
671
|
* `-hover` is the neutral chrome hover fill; `-raised` is a resting panel one
|
|
657
672
|
* step off the page surface; `primary-surface` is the brand-tinted hover.
|
|
@@ -19,13 +19,21 @@ export function Checkbox({ label, suffix, error, indeterminate = false, type = "
|
|
|
19
19
|
const generatedId = React.useId();
|
|
20
20
|
const inputId = id ?? generatedId;
|
|
21
21
|
const inputRef = React.useRef(null);
|
|
22
|
+
/*
|
|
23
|
+
* A caller's own `aria-invalid` wins. `{...props}` is spread first, so
|
|
24
|
+
* re-specifying the attribute afterwards used to overwrite an incoming
|
|
25
|
+
* `"true"` with `undefined` — and `FieldCheckbox` sets it itself while
|
|
26
|
+
* withholding `error` (to avoid a double message). See the full writeup in
|
|
27
|
+
* `Input.tsx`; the same bug existed here.
|
|
28
|
+
*/
|
|
29
|
+
const ariaInvalid = props["aria-invalid"] ?? (error ? "true" : undefined);
|
|
22
30
|
React.useEffect(() => {
|
|
23
31
|
if (inputRef.current) {
|
|
24
32
|
inputRef.current.indeterminate = indeterminate;
|
|
25
33
|
}
|
|
26
34
|
}, [indeterminate]);
|
|
27
35
|
if (bare) {
|
|
28
|
-
return (_jsx("input", { ...props, ref: inputRef, id: inputId, type: type, checked: checked, disabled: disabled, "aria-invalid":
|
|
36
|
+
return (_jsx("input", { ...props, ref: inputRef, id: inputId, type: type, checked: checked, disabled: disabled, "aria-invalid": ariaInvalid, className: className }));
|
|
29
37
|
}
|
|
30
38
|
// A checkbox with no label/suffix has no text to lay out beside the box, so
|
|
31
39
|
// the default `width: 100%` on the root serves no purpose and actively harms
|
|
@@ -43,7 +51,7 @@ export function Checkbox({ label, suffix, error, indeterminate = false, type = "
|
|
|
43
51
|
disabled ? UI_CHECKBOX.labelDisabled : "",
|
|
44
52
|
]
|
|
45
53
|
.filter(Boolean)
|
|
46
|
-
.join(" "), children: [_jsxs("span", { className: UI_CHECKBOX.boxWrap, children: [_jsx("input", { ...props, ref: inputRef, id: inputId, type: type, checked: checked, disabled: disabled, "aria-invalid":
|
|
54
|
+
.join(" "), children: [_jsxs("span", { className: UI_CHECKBOX.boxWrap, children: [_jsx("input", { ...props, ref: inputRef, id: inputId, type: type, checked: checked, disabled: disabled, "aria-invalid": ariaInvalid, className: [
|
|
47
55
|
UI_CHECKBOX.input,
|
|
48
56
|
error ? UI_CHECKBOX.inputError : "",
|
|
49
57
|
className,
|
|
@@ -5,7 +5,14 @@ import { Label, Span, Text } from "./Typography.js";
|
|
|
5
5
|
export const DateInput = React.forwardRef(function DateInput({ label, error, helperText, value, onChange, disabled, required, id, className = "", ...props }, ref) {
|
|
6
6
|
const generatedId = React.useId();
|
|
7
7
|
const inputId = id ?? generatedId;
|
|
8
|
-
|
|
8
|
+
/*
|
|
9
|
+
* A caller's own `aria-invalid` wins. `{...props}` is spread first, so
|
|
10
|
+
* re-specifying the attribute afterwards overwrites an incoming "true"
|
|
11
|
+
* with `undefined` — the defect that left every Field*-built form in the
|
|
12
|
+
* app with no aria-invalid at all. See the full writeup in `Input.tsx`.
|
|
13
|
+
*/
|
|
14
|
+
const ariaInvalid = props["aria-invalid"] ?? (error ? "true" : undefined);
|
|
15
|
+
return (_jsxs("div", { className: "w-full", children: [label && (_jsx(Label, { htmlFor: inputId, required: required, className: "appkit-form-field__label mb-1.5", children: label })), _jsx("input", { ...props, ref: ref, id: inputId, type: "date", value: value, disabled: disabled, required: required, "aria-invalid": ariaInvalid, onChange: (e) => onChange?.(e.target.value), className: ["appkit-input", error ? "appkit-input--error" : "", className].filter(Boolean).join(" ") }), error ? (_jsx(Text, { size: "sm", variant: "error", role: "alert", className: "mt-1.5", children: error })) : helperText ? (_jsx(Text, { size: "sm", variant: "secondary", className: "mt-1.5", children: helperText })) : null] }));
|
|
9
16
|
});
|
|
10
17
|
export function DateRangeInput({ label, startLabel = "From", endLabel = "To", startValue, endValue, onStartChange, onEndChange, error, helperText, disabled, required, startMin, startMax, endMin, endMax, }) {
|
|
11
18
|
return (_jsxs("div", { className: "w-full", children: [label && (_jsx(Text, { size: "sm", className: "appkit-form-field__label mb-1.5 block font-medium", children: label })), _jsxs("div", { className: "flex items-end gap-2", children: [_jsx(DateInput, { label: startLabel, value: startValue, onChange: onStartChange, disabled: disabled, required: required, min: startMin, max: startMax ?? endValue }), _jsx(Span, { size: "sm", className: "mb-2.5 shrink-0 text-[var(--appkit-color-text-muted)]", children: "\u2013" }), _jsx(DateInput, { label: endLabel, value: endValue, onChange: onEndChange, disabled: disabled, min: endMin ?? startValue, max: endMax })] }), error ? (_jsx(Text, { size: "sm", variant: "error", role: "alert", className: "mt-1.5", children: error })) : helperText ? (_jsx(Text, { size: "sm", variant: "secondary", className: "mt-1.5", children: helperText })) : null] }));
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { type DisclaimerId } from "../../_internal/shared/content/disclaimers";
|
|
3
|
+
import { type PublishedValues } from "../../_internal/shared/content/published-values";
|
|
4
|
+
export interface DisclaimerProps {
|
|
5
|
+
id: DisclaimerId;
|
|
6
|
+
/** Override the money figures with the admin's current configuration. */
|
|
7
|
+
publishedValues?: PublishedValues;
|
|
8
|
+
/**
|
|
9
|
+
* Render without the surrounding box — for a disclaimer that sits inside a
|
|
10
|
+
* card that already has chrome.
|
|
11
|
+
*
|
|
12
|
+
* 🛑 Does NOT make it smaller or quieter. A `warning`-tone entry keeps its
|
|
13
|
+
* tone inline, because the entries marked `warning` are the ones where
|
|
14
|
+
* ignoring the text has a consequence the reader cannot undo.
|
|
15
|
+
*/
|
|
16
|
+
inline?: boolean;
|
|
17
|
+
className?: string;
|
|
18
|
+
}
|
|
19
|
+
export declare function Disclaimer({ id, publishedValues, inline, className, }: DisclaimerProps): React.JSX.Element | null;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { Div, Stack, Text } from "../index.js";
|
|
4
|
+
import { DISCLAIMERS, } from "../../_internal/shared/content/disclaimers.js";
|
|
5
|
+
import { resolvePublishedCopy, resolvePublishedValues, } from "../../_internal/shared/content/published-values.js";
|
|
6
|
+
/**
|
|
7
|
+
* The one way to render a disclaimer (Phase 12).
|
|
8
|
+
*
|
|
9
|
+
* ## 🛑 `id` only — there is no `text` prop, deliberately
|
|
10
|
+
*
|
|
11
|
+
* A `text` escape hatch would make this a styled box, and then the legally
|
|
12
|
+
* material disclaimers would be written at their call sites again, drift, and
|
|
13
|
+
* end up weakest exactly where they matter most. That is the failure this
|
|
14
|
+
* registry exists to close. If a surface needs a disclaimer that does not
|
|
15
|
+
* exist, the fix is a new registry entry — which is also what gets it
|
|
16
|
+
* reviewed.
|
|
17
|
+
*
|
|
18
|
+
* ## Tokens resolve here
|
|
19
|
+
*
|
|
20
|
+
* The protection entry quotes `{{saleProtectionMaxValue}}` and the claim
|
|
21
|
+
* windows, so the published limits come from the constants that ENFORCE them
|
|
22
|
+
* (Phase 9's mechanism). A change to `SALE_PROTECTION_MAX_VALUE` updates the
|
|
23
|
+
* terms rather than contradicting them.
|
|
24
|
+
*
|
|
25
|
+
* Code-derived values are the default; a caller with settings in hand passes
|
|
26
|
+
* better ones for the money figures.
|
|
27
|
+
*
|
|
28
|
+
* ## Safe in a Server Component
|
|
29
|
+
*
|
|
30
|
+
* No hooks, no state, and the registry is a plain object — so this renders on
|
|
31
|
+
* either side of the boundary. Do not add state here without checking every
|
|
32
|
+
* RSC call site (Root Cause #76).
|
|
33
|
+
*/
|
|
34
|
+
const CODE_DERIVED_VALUES = resolvePublishedValues();
|
|
35
|
+
/**
|
|
36
|
+
* Renders `**bold**` and nothing else.
|
|
37
|
+
*
|
|
38
|
+
* 🛑 A deliberately tiny subset, not a markdown renderer. The emphasis is
|
|
39
|
+
* load-bearing in exactly the places it is used — "**not insurance**" in the
|
|
40
|
+
* protection entry, "**under review**" versus "**verified**" in the scam
|
|
41
|
+
* registry — and those are the phrases a reader skims past without it.
|
|
42
|
+
*
|
|
43
|
+
* 🛑 And it returns ELEMENTS, never HTML. The bodies are our own constants so
|
|
44
|
+
* injection is not the risk; the risk is that a `dangerouslySetInnerHTML`
|
|
45
|
+
* here would invite someone to pass admin-editable text through it later,
|
|
46
|
+
* which is how a disclaimer box becomes a stored-XSS surface.
|
|
47
|
+
*/
|
|
48
|
+
function renderEmphasis(text) {
|
|
49
|
+
return text.split(/(\*\*[^*]+\*\*)/g).map((part, i) => part.startsWith("**") && part.endsWith("**") && part.length > 4 ? (_jsx(Text, { as: "span", weight: "semibold", children: part.slice(2, -2) }, i)) : (_jsx(React.Fragment, { children: part }, i)));
|
|
50
|
+
}
|
|
51
|
+
export function Disclaimer({ id, publishedValues = CODE_DERIVED_VALUES, inline = false, className = "", }) {
|
|
52
|
+
const entry = DISCLAIMERS[id];
|
|
53
|
+
/*
|
|
54
|
+
* A `Record<DisclaimerId, …>` means this cannot happen through the type, but
|
|
55
|
+
* an `as DisclaimerId` cast at a call site could — and rendering nothing is
|
|
56
|
+
* the wrong failure here. A missing disclaimer is invisible, which is the
|
|
57
|
+
* whole problem; so it renders nothing only when the registry genuinely has
|
|
58
|
+
* no entry, and the audit is what catches that case before it ships.
|
|
59
|
+
*/
|
|
60
|
+
if (!entry)
|
|
61
|
+
return null;
|
|
62
|
+
const body = resolvePublishedCopy(entry.body, publishedValues);
|
|
63
|
+
const content = (_jsxs(Stack, { gap: "xs", children: [entry.heading && (_jsx(Text, { size: "xs", weight: "semibold", transform: "uppercase", color: "muted", children: entry.heading })), _jsx(Text, { size: "xs", color: "muted", className: "leading-relaxed", children: renderEmphasis(body) })] }));
|
|
64
|
+
if (inline)
|
|
65
|
+
return _jsx(Div, { className: className, children: content });
|
|
66
|
+
/*
|
|
67
|
+
* 🛑 `surface` + the matching ink, never a status background with literal
|
|
68
|
+
* white text. `-surface` is a near-white tint in light themes and a dark
|
|
69
|
+
* tint in dark ones, so a fixed `text-white` is invisible in exactly one
|
|
70
|
+
* theme — Root Cause #67, which shipped 26 invisible surfaces that way.
|
|
71
|
+
* `Text color="muted"` above pairs correctly with both.
|
|
72
|
+
*/
|
|
73
|
+
return (_jsx(Div, { surface: entry.tone === "warning" ? "warning-surface" : "muted", rounded: "lg", padding: "sm", className: className, children: content }));
|
|
74
|
+
}
|
|
@@ -13,6 +13,26 @@ export const Input = React.forwardRef(function Input({ label, error, helperText,
|
|
|
13
13
|
: variant === "ghost"
|
|
14
14
|
? "border-transparent bg-transparent shadow-none"
|
|
15
15
|
: "";
|
|
16
|
+
/*
|
|
17
|
+
* 🛑 A CALLER'S OWN `aria-invalid` MUST WIN — it did not, and that broke
|
|
18
|
+
* every form in the app.
|
|
19
|
+
*
|
|
20
|
+
* `{...props}` is spread FIRST on both `<input>` elements below, so
|
|
21
|
+
* re-specifying `aria-invalid={error ? "true" : undefined}` afterwards
|
|
22
|
+
* OVERWROTE an incoming `"true"` with `undefined` (JSX: later wins).
|
|
23
|
+
*
|
|
24
|
+
* That is not hypothetical. `FieldInput` sets `aria-invalid` itself and
|
|
25
|
+
* deliberately WITHHOLDS `error` from this component, so the message is not
|
|
26
|
+
* rendered twice — which means `error` here is `undefined` exactly when the
|
|
27
|
+
* field is invalid. Net effect: no `Field*`-built form ever emitted
|
|
28
|
+
* `aria-invalid`, and `SectionForm`'s jump-to-error
|
|
29
|
+
* (`querySelector("[aria-invalid='true']")?.focus()`) silently focused
|
|
30
|
+
* nothing, every time.
|
|
31
|
+
*
|
|
32
|
+
* Same precedence rule as `bareAriaLabel` below: fill the gap, never
|
|
33
|
+
* override an explicit choice.
|
|
34
|
+
*/
|
|
35
|
+
const ariaInvalid = props["aria-invalid"] ?? (error ? "true" : undefined);
|
|
16
36
|
const inputClassName = [
|
|
17
37
|
"appkit-input",
|
|
18
38
|
icon ? "pl-10" : "",
|
|
@@ -45,10 +65,10 @@ export const Input = React.forwardRef(function Input({ label, error, helperText,
|
|
|
45
65
|
* overrides an explicit choice.
|
|
46
66
|
*/
|
|
47
67
|
const bareAriaLabel = props["aria-label"] ?? (typeof label === "string" ? label : undefined);
|
|
48
|
-
return (_jsx("input", { ...props, ref: ref, id: inputId, disabled: disabled, "aria-label": bareAriaLabel, "aria-invalid":
|
|
68
|
+
return (_jsx("input", { ...props, ref: ref, id: inputId, disabled: disabled, "aria-label": bareAriaLabel, "aria-invalid": ariaInvalid, className: inputClassName }));
|
|
49
69
|
}
|
|
50
70
|
const adornment = rightIcon ??
|
|
51
71
|
(success && !error ? (_jsx("svg", { className: CLS_INPUT_SUCCESS_ICON, viewBox: "0 0 20 20", fill: "currentColor", "aria-hidden": "true", children: _jsx("path", { fillRule: "evenodd", d: "M16.704 5.29a1 1 0 010 1.42l-7.2 7.2a1 1 0 01-1.415 0l-3.2-3.2a1 1 0 111.414-1.42l2.493 2.494 6.493-6.494a1 1 0 011.415 0z", clipRule: "evenodd" }) })) : null);
|
|
52
|
-
return (_jsxs("div", { className: "w-full", "data-section": "input-div-527", children: [label && (_jsx(Label, { htmlFor: inputId, required: required, children: label })), _jsxs("div", { className: "relative", "data-section": "input-div-528", children: [icon && (_jsx(Div, { className: "pointer-events-none absolute inset-y-0 left-3 flex items-center text-[var(--appkit-color-text-faint)]", "data-section": "input-div-529", children: icon })), _jsx("input", { ...props, ref: ref, id: inputId, disabled: disabled, "aria-invalid":
|
|
72
|
+
return (_jsxs("div", { className: "w-full", "data-section": "input-div-527", children: [label && (_jsx(Label, { htmlFor: inputId, required: required, children: label })), _jsxs("div", { className: "relative", "data-section": "input-div-528", children: [icon && (_jsx(Div, { className: "pointer-events-none absolute inset-y-0 left-3 flex items-center text-[var(--appkit-color-text-faint)]", "data-section": "input-div-529", children: icon })), _jsx("input", { ...props, ref: ref, id: inputId, disabled: disabled, "aria-invalid": ariaInvalid, className: inputClassName }), adornment && (_jsx(Div, { className: "pointer-events-none absolute inset-y-0 right-3 flex items-center text-[var(--appkit-color-text-faint)]", "data-section": "input-div-530", children: adornment }))] }), error ? (_jsx(Text, { size: "sm", variant: "error", className: "mt-1.5", role: "alert", children: error })) : helperText ? (_jsx(Text, { size: "sm", variant: "secondary", className: "mt-1.5", children: helperText })) : null] }));
|
|
53
73
|
});
|
|
54
74
|
Input.displayName = "Input";
|
|
@@ -20,6 +20,14 @@ interface BaseProps<V> {
|
|
|
20
20
|
disabled?: boolean;
|
|
21
21
|
className?: string;
|
|
22
22
|
ariaLabel?: string;
|
|
23
|
+
/** Field name — resolves this control's error from `FormShellContext`, as `Field*` do. */
|
|
24
|
+
name?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Validation message. Explicit prop wins; else read from context by `name`.
|
|
27
|
+
* Without these two this control had no error affordance at all: a required
|
|
28
|
+
* taxonomy pick could fail and the control showed nothing.
|
|
29
|
+
*/
|
|
30
|
+
error?: React.ReactNode;
|
|
23
31
|
/** "+ Create new …" button. Provide `renderCreateForm` OR (`createFields` + `onCreateSubmit`). */
|
|
24
32
|
createLabel?: string;
|
|
25
33
|
drawerTitle?: string;
|
|
@@ -59,24 +67,5 @@ interface MultiProps<V> extends BaseProps<V> {
|
|
|
59
67
|
maxChipsVisible?: number;
|
|
60
68
|
}
|
|
61
69
|
export type PaginatedSelectProps<V = string> = SingleProps<V> | MultiProps<V>;
|
|
62
|
-
/**
|
|
63
|
-
* PaginatedSelect — searchable, async-paginated select with optional multi-mode
|
|
64
|
-
* and optional inline create-new drawer.
|
|
65
|
-
*
|
|
66
|
-
* @example single-select
|
|
67
|
-
* <PaginatedSelect value={storeId} onChange={setStoreId} loadOptions={loadStores} />
|
|
68
|
-
*
|
|
69
|
-
* @example single-select with inline create
|
|
70
|
-
* <PaginatedSelect
|
|
71
|
-
* value={categoryId}
|
|
72
|
-
* onChange={(v) => setCategoryId(v ?? "")}
|
|
73
|
-
* loadOptions={loadCategories}
|
|
74
|
-
* createLabel="Category"
|
|
75
|
-
* renderCreateForm={({ onCreated, onCancel }) => <CategoryForm ... />}
|
|
76
|
-
* />
|
|
77
|
-
*
|
|
78
|
-
* @example multi-select
|
|
79
|
-
* <PaginatedSelect multiple value={tagIds} onChange={setTagIds} loadOptions={loadTags} />
|
|
80
|
-
*/
|
|
81
70
|
export declare function PaginatedSelect<V = string>(props: PaginatedSelectProps<V>): React.JSX.Element;
|
|
82
71
|
export {};
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
-
import { useCallback, useEffect, useRef, useState } from "react";
|
|
3
|
+
import React, { useCallback, useEffect, useRef, useState } from "react";
|
|
4
4
|
import { Input } from "./Input.js";
|
|
5
|
+
import { toUserMessage } from "../../errors/error-display-map.js";
|
|
6
|
+
import { Text } from "./Typography.js";
|
|
7
|
+
import { FormShellContext } from "../forms/FormShell.js";
|
|
5
8
|
import { SideDrawer } from "./SideDrawer.js";
|
|
6
9
|
import { Button } from "./Button.js";
|
|
7
10
|
import { QuickFormDrawer } from "../../features/shell/QuickFormDrawer.js";
|
|
@@ -87,9 +90,43 @@ function isValueSelected(value, props, isMulti) {
|
|
|
87
90
|
* @example multi-select
|
|
88
91
|
* <PaginatedSelect multiple value={tagIds} onChange={setTagIds} loadOptions={loadTags} />
|
|
89
92
|
*/
|
|
93
|
+
/**
|
|
94
|
+
* Resolve this control's validation message and the id that labels it.
|
|
95
|
+
*
|
|
96
|
+
* A hook rather than four lines in the component body: `PaginatedSelect` is
|
|
97
|
+
* already at `audit-code-quality`'s size limit, and the error affordance is
|
|
98
|
+
* self-contained — explicit prop wins, else `FormShellContext` by `name`,
|
|
99
|
+
* exactly as the `Field*` primitives resolve theirs.
|
|
100
|
+
*/
|
|
101
|
+
function usePaginatedSelectError(name, errorProp) {
|
|
102
|
+
const ctx = React.useContext(FormShellContext);
|
|
103
|
+
const error = errorProp ?? (name ? ctx?.errors[name] : undefined);
|
|
104
|
+
const errorId = `${React.useId()}-error`;
|
|
105
|
+
return { error, errorId };
|
|
106
|
+
}
|
|
107
|
+
/** The message, under the trigger it describes. */
|
|
108
|
+
function PaginatedSelectError({ id, error }) {
|
|
109
|
+
if (!error)
|
|
110
|
+
return null;
|
|
111
|
+
return (_jsx(Text, { id: id, size: "sm", variant: "error", className: "appkit-form-field__error", role: "alert", children: error }));
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* The selected-values row, multi-select only.
|
|
115
|
+
*
|
|
116
|
+
* Its own component because `PaginatedSelect` sits against
|
|
117
|
+
* `audit-code-quality`'s size limit, and this block needs none of the
|
|
118
|
+
* control's twelve state variables — only what it is handed.
|
|
119
|
+
*/
|
|
120
|
+
function PaginatedSelectChips({ chips, labelFor, overflowCount, disabled, onRemove, }) {
|
|
121
|
+
return (_jsxs("div", { className: C.chips, children: [chips.map((v) => (_jsxs("span", { className: C.chip, children: [_jsx("span", { className: C.chipLabel, children: labelFor(v) }), !disabled && (_jsx("button", { type: "button", "aria-label": "Remove", className: C.chipRemove, onClick: (e) => {
|
|
122
|
+
e.stopPropagation();
|
|
123
|
+
onRemove(v);
|
|
124
|
+
}, children: "\u2715" }))] }, String(v)))), overflowCount > 0 && (_jsxs("span", { className: C.overflowChip, children: ["+", overflowCount, " more"] }))] }));
|
|
125
|
+
}
|
|
90
126
|
export function PaginatedSelect(props) {
|
|
91
|
-
const { options, loadOptions, placeholder = "Select...", searchPlaceholder = "Search...", noResultsText = "No results", disabled, className = "", ariaLabel, createLabel, drawerTitle, renderCreateForm, createFields, createSchema, onCreateSubmit, createSubmitLabel, editLabel, editDrawerTitle, renderEditForm, editFields, editSchema, onEditLoad, onEditSubmit, editSubmitLabel, } = props;
|
|
127
|
+
const { options, loadOptions, placeholder = "Select...", searchPlaceholder = "Search...", noResultsText = "No results", disabled, className = "", ariaLabel, name, error: errorProp, createLabel, drawerTitle, renderCreateForm, createFields, createSchema, onCreateSubmit, createSubmitLabel, editLabel, editDrawerTitle, renderEditForm, editFields, editSchema, onEditLoad, onEditSubmit, editSubmitLabel, } = props;
|
|
92
128
|
const isMulti = props.multiple === true;
|
|
129
|
+
const { error, errorId } = usePaginatedSelectError(name, errorProp);
|
|
93
130
|
const maxChipsVisible = isMulti ? props.maxChipsVisible ?? 3 : 0;
|
|
94
131
|
const [query, setQuery] = useState("");
|
|
95
132
|
const [open, setOpen] = useState(false);
|
|
@@ -222,7 +259,7 @@ export function PaginatedSelect(props) {
|
|
|
222
259
|
// Same staleness rule as the success path: a superseded request must
|
|
223
260
|
// not paint its failure over a newer request's results.
|
|
224
261
|
if (requestId === requestIdRef.current) {
|
|
225
|
-
setLoadError(normalized.
|
|
262
|
+
setLoadError(toUserMessage(normalized.code, undefined, { fallback: "Could not load options." }));
|
|
226
263
|
if (reset)
|
|
227
264
|
setAsyncOptions([]);
|
|
228
265
|
}
|
|
@@ -370,12 +407,9 @@ export function PaginatedSelect(props) {
|
|
|
370
407
|
const multiValue = isMulti ? props.value : [];
|
|
371
408
|
const visibleChips = multiValue.slice(0, maxChipsVisible);
|
|
372
409
|
const overflowCount = multiValue.length - maxChipsVisible;
|
|
373
|
-
return (_jsxs(_Fragment, { children: [_jsxs("div", { ref: containerRef, className: [C.root, className].filter(Boolean).join(" "),
|
|
374
|
-
e.stopPropagation();
|
|
375
|
-
removeChip(v);
|
|
376
|
-
}, children: "\u2715" }))] }, String(v)))), overflowCount > 0 && (_jsxs("span", { className: C.overflowChip, children: ["+", overflowCount, " more"] }))] })), _jsxs("button", { type: "button", disabled: disabled, onClick: () => setOpen((prev) => !prev), className: [C.trigger, disabled ? C.triggerDisabled : ""]
|
|
410
|
+
return (_jsxs(_Fragment, { children: [_jsxs("div", { ref: containerRef, className: [C.root, className].filter(Boolean).join(" "), children: [isMulti && multiValue.length > 0 && (_jsx(PaginatedSelectChips, { chips: visibleChips, labelFor: (v) => labelMap.current.get(v) ?? String(v), overflowCount: overflowCount, disabled: disabled, onRemove: removeChip })), _jsxs("button", { type: "button", disabled: disabled, onClick: () => setOpen((prev) => !prev), className: [C.trigger, disabled ? C.triggerDisabled : ""]
|
|
377
411
|
.filter(Boolean)
|
|
378
|
-
.join(" "), "aria-expanded": open, "aria-haspopup": "listbox", children: [_jsx("span", { className: C.triggerLeft, children: _jsx("span", { className: triggerEmpty ? C.placeholder : "", children: triggerLabel }) }), _jsx("span", { "aria-hidden": "true", children: "\u25BE" })] }), hasEdit && !disabled ? (_jsx("button", { type: "button", className: C.editBtn, "aria-label": `Edit ${editLabel}`, title: `Edit ${editLabel}`, onClick: () => {
|
|
412
|
+
.join(" "), "aria-label": ariaLabel, "aria-expanded": open, "aria-haspopup": "listbox", "aria-invalid": error ? "true" : undefined, "aria-describedby": error ? errorId : undefined, children: [_jsx("span", { className: C.triggerLeft, children: _jsx("span", { className: triggerEmpty ? C.placeholder : "", children: triggerLabel }) }), _jsx("span", { "aria-hidden": "true", children: "\u25BE" })] }), hasEdit && !disabled ? (_jsx("button", { type: "button", className: C.editBtn, "aria-label": `Edit ${editLabel}`, title: `Edit ${editLabel}`, onClick: () => {
|
|
379
413
|
setOpen(false);
|
|
380
414
|
setEditOpen(true);
|
|
381
415
|
}, children: "\u270E" })) : null, open && (_jsxs("div", { className: [C.dropdown, opensUp ? C.dropdownUp : ""].filter(Boolean).join(" "), role: "listbox", "aria-multiselectable": isMulti || undefined, children: [_jsx(Input, { autoFocus: true, value: query, onChange: (e) => setQuery(e.target.value), placeholder: searchPlaceholder, className: C.search }), _jsxs("ul", { className: C.list, children: [filtered.map((opt, idx) => {
|
|
@@ -386,7 +420,7 @@ export function PaginatedSelect(props) {
|
|
|
386
420
|
}), loadError && !loading && (_jsxs("li", { className: C.empty, role: "alert", children: [loadError, " ", _jsx(Button, { variant: "ghost", size: "sm", onClick: () => void load(query, 1, true), children: "Try again" })] })), !loadError && filtered.length === 0 && !loading && (_jsx("li", { className: C.empty, children: noResultsText })), loading && _jsx("li", { className: C.loading, children: "Loading\u2026" }), hasMore && !loading && (_jsx("li", { children: _jsx("button", { type: "button", className: C.loadMore, onClick: () => void load(query, page + 1), children: "Load more" }) })), hasCreate && (_jsx("li", { children: _jsxs("button", { type: "button", className: C.createBtn, onClick: () => {
|
|
387
421
|
setOpen(false);
|
|
388
422
|
setDrawerOpen(true);
|
|
389
|
-
}, children: ["+ Create new ", createLabel] }) }, CREATE_SENTINEL))] })] }))] }), hasCreate && renderCreateForm ? (_jsx(SideDrawer, { isOpen: drawerOpen, onClose: () => setDrawerOpen(false), title: drawerTitle ?? `Create ${createLabel}`, mode: "create", footer: _jsx(Button, { variant: "ghost", onClick: () => setDrawerOpen(false), children: "Cancel" }), children: renderCreateForm({
|
|
423
|
+
}, children: ["+ Create new ", createLabel] }) }, CREATE_SENTINEL))] })] })), _jsx(PaginatedSelectError, { id: errorId, error: error })] }), hasCreate && renderCreateForm ? (_jsx(SideDrawer, { isOpen: drawerOpen, onClose: () => setDrawerOpen(false), title: drawerTitle ?? `Create ${createLabel}`, mode: "create", footer: _jsx(Button, { variant: "ghost", onClick: () => setDrawerOpen(false), children: "Cancel" }), children: renderCreateForm({
|
|
390
424
|
onCreated: handleCreated,
|
|
391
425
|
onCancel: () => setDrawerOpen(false),
|
|
392
426
|
}) })) : hasCreate && createFields && onCreateSubmit ? (_jsx(QuickFormDrawer, { isOpen: drawerOpen, onClose: () => setDrawerOpen(false), title: drawerTitle ?? `Create ${createLabel}`, fields: createFields, schema: createSchema, submitLabel: createSubmitLabel ?? `Create ${createLabel}`, onSubmit: async (values) => {
|
|
@@ -66,5 +66,12 @@ export function RadioGroup({ name, options, value, onChange, label, error, orien
|
|
|
66
66
|
export function RadioItem({ label, suffix, error, className = "", checked, disabled, id, ...props }) {
|
|
67
67
|
const generatedId = React.useId();
|
|
68
68
|
const inputId = id ?? generatedId;
|
|
69
|
-
|
|
69
|
+
/*
|
|
70
|
+
* A caller's own `aria-invalid` wins. `{...props}` is spread first, so
|
|
71
|
+
* re-specifying the attribute afterwards overwrites an incoming "true"
|
|
72
|
+
* with `undefined` — the defect that left every Field*-built form in the
|
|
73
|
+
* app with no aria-invalid at all. See the full writeup in `Input.tsx`.
|
|
74
|
+
*/
|
|
75
|
+
const ariaInvalid = props["aria-invalid"] ?? (error ? "true" : undefined);
|
|
76
|
+
return (_jsxs("div", { className: "appkit-radio-item", "data-section": "radio-item-div", children: [_jsxs(Label, { htmlFor: inputId, className: ["appkit-radio-item__label", disabled ? "appkit-radio-item__label--disabled" : ""].filter(Boolean).join(" "), children: [_jsx("span", { className: "appkit-radio-item__box-wrap", children: _jsx("input", { ...props, id: inputId, type: "radio", checked: checked, disabled: disabled, "aria-invalid": ariaInvalid, className: ["appkit-radio-item__input", error ? "appkit-radio-item__input--error" : "", className].filter(Boolean).join(" ") }) }), (label || suffix) && (_jsxs("span", { className: "appkit-radio-item__content", children: [label ? _jsx(Span, { className: "appkit-radio-item__text", children: label }) : _jsx("span", {}), suffix] }))] }), error && (_jsx(Text, { size: "sm", variant: "error", className: "appkit-radio-item__error", role: "alert", children: error }))] }));
|
|
70
77
|
}
|
|
@@ -6,6 +6,14 @@ import { Label, Text } from "./Typography.js";
|
|
|
6
6
|
export function Select({ options, value, onChange, onValueChange, placeholder, label, error, helperText, disabled = false, required, className = "", id, variant = "default", bare = false, wrapperClassName, ...props }) {
|
|
7
7
|
const generatedId = React.useId();
|
|
8
8
|
const inputId = id ?? generatedId;
|
|
9
|
+
/*
|
|
10
|
+
* A caller's own `aria-invalid` wins. `{...props}` is spread first, so
|
|
11
|
+
* re-specifying the attribute afterwards used to overwrite an incoming
|
|
12
|
+
* `"true"` with `undefined` — and `FieldSelect` sets it itself while
|
|
13
|
+
* withholding `error` (to avoid a double message). See the full writeup in
|
|
14
|
+
* `Input.tsx`; the same bug existed here.
|
|
15
|
+
*/
|
|
16
|
+
const ariaInvalid = props["aria-invalid"] ?? (error ? "true" : undefined);
|
|
9
17
|
const handleChange = (event) => {
|
|
10
18
|
onChange?.(event);
|
|
11
19
|
onValueChange?.(event.target.value);
|
|
@@ -28,7 +36,7 @@ export function Select({ options, value, onChange, onValueChange, placeholder, l
|
|
|
28
36
|
.join(" ");
|
|
29
37
|
const optionsMarkup = (_jsxs(_Fragment, { children: [placeholder ? (_jsx("option", { value: "", disabled: true, children: placeholder })) : null, options.map((option) => (_jsx("option", { value: option.value, disabled: option.disabled, children: option.label }, String(option.value))))] }));
|
|
30
38
|
if (bare) {
|
|
31
|
-
return (_jsx("select", { ...props, id: inputId, value: value, onChange: handleChange, disabled: disabled, "aria-invalid":
|
|
39
|
+
return (_jsx("select", { ...props, id: inputId, value: value, onChange: handleChange, disabled: disabled, "aria-invalid": ariaInvalid, className: selectClassName, children: optionsMarkup }));
|
|
32
40
|
}
|
|
33
|
-
return (_jsxs("div", { className: ["appkit-select", wrapperClassName].filter(Boolean).join(" "), "data-section": "select-div-592", children: [label && (_jsx(Label, { htmlFor: inputId, className: "appkit-select__label", required: required, children: label })), _jsxs("div", { className: "relative group", "data-section": "select-div-593", children: [_jsx("select", { ...props, id: inputId, value: value, onChange: handleChange, disabled: disabled, "aria-invalid":
|
|
41
|
+
return (_jsxs("div", { className: ["appkit-select", wrapperClassName].filter(Boolean).join(" "), "data-section": "select-div-592", children: [label && (_jsx(Label, { htmlFor: inputId, className: "appkit-select__label", required: required, children: label })), _jsxs("div", { className: "relative group", "data-section": "select-div-593", children: [_jsx("select", { ...props, id: inputId, value: value, onChange: handleChange, disabled: disabled, "aria-invalid": ariaInvalid, className: selectClassName, children: optionsMarkup }), _jsx(Div, { className: "pointer-events-none absolute inset-y-0 right-3 flex items-center text-[var(--appkit-color-text-faint)]", "data-section": "select-div-594", children: _jsx("svg", { className: "h-4 w-4", viewBox: "0 0 20 20", fill: "currentColor", "aria-hidden": "true", children: _jsx("path", { fillRule: "evenodd", d: "M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z", clipRule: "evenodd" }) }) })] }), error ? (_jsx(Text, { size: "sm", variant: "error", className: "appkit-select__error", role: "alert", children: error })) : helperText ? (_jsx(Text, { size: "sm", variant: "secondary", className: "appkit-select__error", children: helperText })) : null] }));
|
|
34
42
|
}
|
|
@@ -7,5 +7,12 @@ export interface TagInputProps {
|
|
|
7
7
|
placeholder?: string;
|
|
8
8
|
className?: string;
|
|
9
9
|
helperText?: string;
|
|
10
|
+
/**
|
|
11
|
+
* Validation message. This control had no error slot at all, so a schema
|
|
12
|
+
* failure on a tags field could only ever appear in the summary — the field
|
|
13
|
+
* itself showed nothing and was not announced as invalid. Mirrors the
|
|
14
|
+
* contract Input/Select/Textarea/Checkbox already have.
|
|
15
|
+
*/
|
|
16
|
+
error?: React.ReactNode;
|
|
10
17
|
}
|
|
11
|
-
export declare function TagInput({ value, onChange, disabled, label, placeholder, className, helperText, }: TagInputProps): React.JSX.Element;
|
|
18
|
+
export declare function TagInput({ value, onChange, disabled, label, placeholder, className, helperText, error, }: TagInputProps): React.JSX.Element;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useRef, useState } from "react";
|
|
3
|
+
import React, { useRef, useState } from "react";
|
|
4
4
|
import { Label, Span } from "./Typography.js";
|
|
5
|
-
export function TagInput({ value, onChange, disabled = false, label, placeholder = "Add a tag...", className = "", helperText = "Press Enter or comma to add a tag", }) {
|
|
5
|
+
export function TagInput({ value, onChange, disabled = false, label, placeholder = "Add a tag...", className = "", helperText = "Press Enter or comma to add a tag", error, }) {
|
|
6
6
|
const [draft, setDraft] = useState("");
|
|
7
7
|
const inputRef = useRef(null);
|
|
8
|
+
const errorId = React.useId();
|
|
8
9
|
const normalizeTag = (raw) => raw.trim().replace(/,+$/, "").trim();
|
|
9
10
|
const addTag = (raw) => {
|
|
10
11
|
const tag = normalizeTag(raw);
|
|
@@ -69,5 +70,5 @@ export function TagInput({ value, onChange, disabled = false, label, placeholder
|
|
|
69
70
|
disabled ? "appkit-tag-input__text--disabled" : "",
|
|
70
71
|
]
|
|
71
72
|
.filter(Boolean)
|
|
72
|
-
.join(" "), "aria-label": label ?? "Tag input" })] }), helperText
|
|
73
|
+
.join(" "), "aria-label": label ?? "Tag input", "aria-invalid": error ? "true" : undefined, "aria-describedby": error ? errorId : undefined })] }), error ? (_jsx(Span, { id: errorId, size: "xs", className: "appkit-tag-input__helper appkit-form-field__error", role: "alert", children: error })) : helperText ? (_jsx(Span, { size: "xs", className: "appkit-tag-input__helper", children: helperText })) : null] }));
|
|
73
74
|
}
|
|
@@ -15,12 +15,20 @@ export const Textarea = React.forwardRef(function Textarea({ label, error, helpe
|
|
|
15
15
|
: variant === "ghost"
|
|
16
16
|
? "border-transparent bg-transparent shadow-none"
|
|
17
17
|
: "";
|
|
18
|
+
/*
|
|
19
|
+
* A caller's own `aria-invalid` wins. `{...props}` is spread first, so
|
|
20
|
+
* re-specifying the attribute afterwards used to overwrite an incoming
|
|
21
|
+
* `"true"` with `undefined` — and `FieldTextarea` sets it itself while
|
|
22
|
+
* withholding `error` (to avoid a double message). See the full writeup in
|
|
23
|
+
* `Input.tsx`; the same bug existed here.
|
|
24
|
+
*/
|
|
25
|
+
const ariaInvalid = props["aria-invalid"] ?? (error ? "true" : undefined);
|
|
18
26
|
const textareaClassName = ["appkit-textarea", variantClass, className]
|
|
19
27
|
.filter(Boolean)
|
|
20
28
|
.join(" ");
|
|
21
29
|
if (bare) {
|
|
22
|
-
return (_jsx("textarea", { ...props, ref: ref, id: inputId, value: value, defaultValue: defaultValue, maxLength: maxLength, "aria-invalid":
|
|
30
|
+
return (_jsx("textarea", { ...props, ref: ref, id: inputId, value: value, defaultValue: defaultValue, maxLength: maxLength, "aria-invalid": ariaInvalid, className: textareaClassName }));
|
|
23
31
|
}
|
|
24
|
-
return (_jsxs("div", { className: "w-full", "data-section": "textarea-div-620", children: [label && (_jsx(Label, { htmlFor: inputId, required: required, children: label })), _jsx("textarea", { ...props, ref: ref, id: inputId, value: value, defaultValue: defaultValue, maxLength: maxLength, "aria-invalid":
|
|
32
|
+
return (_jsxs("div", { className: "w-full", "data-section": "textarea-div-620", children: [label && (_jsx(Label, { htmlFor: inputId, required: required, children: label })), _jsx("textarea", { ...props, ref: ref, id: inputId, value: value, defaultValue: defaultValue, maxLength: maxLength, "aria-invalid": ariaInvalid, className: textareaClassName }), (error || helperText || (showCharCount && maxLength)) && (_jsxs("div", { className: "mt-1.5 flex items-start justify-between gap-3", "data-section": "textarea-div-621", children: [_jsx("div", { className: "min-w-0 flex-1", "data-section": "textarea-div-622", children: error ? (_jsx(Text, { size: "sm", variant: "error", role: "alert", children: error })) : helperText ? (_jsx(Text, { size: "sm", variant: "secondary", children: helperText })) : null }), showCharCount && maxLength ? (_jsxs(Text, { size: "xs", variant: charCount >= maxLength ? "error" : "muted", className: "shrink-0 tabular-nums", children: [charCount, "/", maxLength] })) : null] }))] }));
|
|
25
33
|
});
|
|
26
34
|
Textarea.displayName = "Textarea";
|