@eifi1/ui-kit 0.32.2 → 0.33.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/README.md +17 -9
- package/dist/account/delete-account-setting.d.ts +11 -10
- package/dist/account/delete-account-setting.js +2 -1
- package/dist/account/delete-account-setting.js.map +1 -1
- package/dist/account/email-change-setting.d.ts +5 -0
- package/dist/account/email-change-setting.js +4 -3
- package/dist/account/email-change-setting.js.map +1 -1
- package/dist/account/sessions-setting.d.ts +4 -0
- package/dist/account/sessions-setting.js +3 -2
- package/dist/account/sessions-setting.js.map +1 -1
- package/dist/admin/admin-action-confirm.d.ts +11 -10
- package/dist/admin/admin-action-confirm.js.map +1 -1
- package/dist/admin/invitations-panel.d.ts +11 -10
- package/dist/admin/invitations-panel.js +4 -3
- package/dist/admin/invitations-panel.js.map +1 -1
- package/dist/admin/plan-change.d.ts +101 -0
- package/dist/admin/plan-change.js +210 -0
- package/dist/admin/plan-change.js.map +1 -0
- package/dist/admin/reviewer-scope-editor.d.ts +11 -10
- package/dist/admin/reviewer-scope-editor.js.map +1 -1
- package/dist/admin/role-select.d.ts +8 -7
- package/dist/admin/role-select.js.map +1 -1
- package/dist/admin/transfer-ownership-dialog.d.ts +11 -10
- package/dist/admin/user-roster.d.ts +8 -7
- package/dist/admin/user-roster.js +2 -2
- package/dist/admin/user-roster.js.map +1 -1
- package/dist/auth/auth-errors.d.ts +13 -2
- package/dist/auth/auth-errors.js +5 -1
- package/dist/auth/auth-errors.js.map +1 -1
- package/dist/auth/complete-name-dialog.d.ts +4 -1
- package/dist/auth/complete-name-dialog.js +2 -1
- package/dist/auth/complete-name-dialog.js.map +1 -1
- package/dist/auth/register-form.d.ts +11 -10
- package/dist/billing/billing-banner.d.ts +14 -11
- package/dist/billing/billing-banner.js.map +1 -1
- package/dist/billing/billing-labels.d.ts +11 -10
- package/dist/billing/billing-labels.js +10 -1
- package/dist/billing/billing-labels.js.map +1 -1
- package/dist/billing/billing-lock.d.ts +40 -12
- package/dist/billing/billing-lock.js +9 -3
- package/dist/billing/billing-lock.js.map +1 -1
- package/dist/billing/billing-overview.d.ts +155 -0
- package/dist/billing/billing-overview.js +2 -0
- package/dist/billing/billing-overview.js.map +1 -0
- package/dist/billing/billing-standing.d.ts +11 -10
- package/dist/billing/checkout-processing.d.ts +218 -0
- package/dist/billing/checkout-processing.js +198 -0
- package/dist/billing/checkout-processing.js.map +1 -0
- package/dist/billing/checkout-return.d.ts +51 -0
- package/dist/billing/checkout-return.js +43 -0
- package/dist/billing/checkout-return.js.map +1 -0
- package/dist/billing/pay-page.d.ts +215 -0
- package/dist/billing/pay-page.js +113 -0
- package/dist/billing/pay-page.js.map +1 -0
- package/dist/billing/plan-card.d.ts +11 -10
- package/dist/billing/plan-limit-notice.d.ts +11 -10
- package/dist/billing/plan-limit-toast.d.ts +144 -0
- package/dist/billing/plan-limit-toast.js +40 -0
- package/dist/billing/plan-limit-toast.js.map +1 -0
- package/dist/billing/subscription-actions.d.ts +39 -15
- package/dist/billing/subscription-actions.js +9 -2
- package/dist/billing/subscription-actions.js.map +1 -1
- package/dist/billing/subscription-status-chip.d.ts +10 -9
- package/dist/bin/eifi1-pay-page.mjs +166 -0
- package/dist/chart.d.ts +11 -10
- package/dist/components/account-chips.d.ts +6 -1
- package/dist/components/account-settings.d.ts +4 -1
- package/dist/components/account-settings.js +2 -1
- package/dist/components/account-settings.js.map +1 -1
- package/dist/components/amount-input.d.ts +11 -10
- package/dist/components/autocomplete.d.ts +2 -1
- package/dist/components/autocomplete.js +5 -3
- package/dist/components/autocomplete.js.map +1 -1
- package/dist/components/button-group.d.ts +11 -10
- package/dist/components/button-group.js +1 -1
- package/dist/components/button-group.js.map +1 -1
- package/dist/components/calculator.d.ts +11 -10
- package/dist/components/calculator.js +3 -3
- package/dist/components/calculator.js.map +1 -1
- package/dist/components/checkbox-group.d.ts +2 -1
- package/dist/components/checkbox-group.js.map +1 -1
- package/dist/components/checkbox.d.ts +2 -1
- package/dist/components/checkbox.js.map +1 -1
- package/dist/components/chip.d.ts +2 -1
- package/dist/components/chip.js +19 -17
- package/dist/components/chip.js.map +1 -1
- package/dist/components/choice-card.d.ts +3 -1
- package/dist/components/choice-card.js +1 -1
- package/dist/components/choice-card.js.map +1 -1
- package/dist/components/combobox-core.js +2 -1
- package/dist/components/combobox-core.js.map +1 -1
- package/dist/components/combobox.d.ts +4 -3
- package/dist/components/combobox.js +2 -2
- package/dist/components/combobox.js.map +1 -1
- package/dist/components/confirm-dialog.d.ts +11 -10
- package/dist/components/confirm-dialog.js +6 -3
- package/dist/components/confirm-dialog.js.map +1 -1
- package/dist/components/copy-button.d.ts +12 -11
- package/dist/components/country-select.d.ts +2 -1
- package/dist/components/country-select.js.map +1 -1
- package/dist/components/danger-confirm.d.ts +11 -10
- package/dist/components/danger-confirm.js.map +1 -1
- package/dist/components/data-table-cells.d.ts +12 -1
- package/dist/components/data-table-filter-popover.d.ts +12 -1
- package/dist/components/data-table-filters.d.ts +12 -1
- package/dist/components/data-table-labels.d.ts +12 -1
- package/dist/components/data-table-pagination.d.ts +12 -1
- package/dist/components/data-table.d.ts +12 -1
- package/dist/components/data-table.js +3 -3
- package/dist/components/data-table.js.map +1 -1
- package/dist/components/date-picker.js +6 -4
- package/dist/components/date-picker.js.map +1 -1
- package/dist/components/dropdown.js +9 -1
- package/dist/components/dropdown.js.map +1 -1
- package/dist/components/entity-combobox.d.ts +3 -2
- package/dist/components/entity-combobox.js.map +1 -1
- package/dist/components/facing-pair.d.ts +11 -10
- package/dist/components/field-parts.d.ts +32 -4
- package/dist/components/field-parts.js +54 -19
- package/dist/components/field-parts.js.map +1 -1
- package/dist/components/file-button.d.ts +11 -10
- package/dist/components/file-button.js +3 -2
- package/dist/components/file-button.js.map +1 -1
- package/dist/components/file-dropzone.d.ts +12 -11
- package/dist/components/file-dropzone.js.map +1 -1
- package/dist/components/floating-panel.js +5 -5
- package/dist/components/floating-panel.js.map +1 -1
- package/dist/components/form-actions.d.ts +10 -9
- package/dist/components/form-actions.js +3 -3
- package/dist/components/form-actions.js.map +1 -1
- package/dist/components/full-bleed-dialog.js.map +1 -1
- package/dist/components/iban-input.d.ts +11 -10
- package/dist/components/inline-edit-field.d.ts +2 -1
- package/dist/components/inline-edit-field.js +6 -6
- package/dist/components/inline-edit-field.js.map +1 -1
- package/dist/components/language-select.d.ts +11 -10
- package/dist/components/legal-page.d.ts +11 -10
- package/dist/components/legal.d.ts +11 -10
- package/dist/components/list.d.ts +2 -1
- package/dist/components/list.js +4 -5
- package/dist/components/list.js.map +1 -1
- package/dist/components/modal.js.map +1 -1
- package/dist/components/money-field.d.ts +11 -10
- package/dist/components/month-picker.js +54 -44
- package/dist/components/month-picker.js.map +1 -1
- package/dist/components/multi-entity-combobox.d.ts +3 -2
- package/dist/components/multi-entity-combobox.js.map +1 -1
- package/dist/components/number-field.d.ts +18 -10
- package/dist/components/number-field.js.map +1 -1
- package/dist/components/number-input.d.ts +37 -10
- package/dist/components/number-input.js +27 -12
- package/dist/components/number-input.js.map +1 -1
- package/dist/components/numpad-sheet.d.ts +11 -10
- package/dist/components/numpad-sheet.js +2 -2
- package/dist/components/numpad-sheet.js.map +1 -1
- package/dist/components/phone-input.d.ts +11 -10
- package/dist/components/popover.js +6 -2
- package/dist/components/popover.js.map +1 -1
- package/dist/components/row-actions.d.ts +6 -5
- package/dist/components/row-actions.js +130 -32
- package/dist/components/row-actions.js.map +1 -1
- package/dist/components/series-chart.d.ts +11 -10
- package/dist/components/settings-fields.d.ts +11 -10
- package/dist/components/share-card.d.ts +8 -7
- package/dist/components/share-card.js +26 -10
- package/dist/components/share-card.js.map +1 -1
- package/dist/components/skeleton.d.ts +10 -2
- package/dist/components/skeleton.js.map +1 -1
- package/dist/components/status-dot.d.ts +1 -0
- package/dist/components/status-dot.js +2 -2
- package/dist/components/status-dot.js.map +1 -1
- package/dist/components/swatch-picker.d.ts +2 -1
- package/dist/components/swatch-picker.js.map +1 -1
- package/dist/components/swipeable-row.d.ts +88 -17
- package/dist/components/swipeable-row.js +46 -9
- package/dist/components/swipeable-row.js.map +1 -1
- package/dist/components/switch.d.ts +2 -1
- package/dist/components/switch.js.map +1 -1
- package/dist/components/table.d.ts +2 -1
- package/dist/components/table.js +6 -0
- package/dist/components/table.js.map +1 -1
- package/dist/components/text-link.d.ts +10 -9
- package/dist/components/time-input.d.ts +11 -10
- package/dist/components/toggle-group.d.ts +2 -1
- package/dist/components/toggle-group.js +1 -1
- package/dist/components/toggle-group.js.map +1 -1
- package/dist/components/translation-review-editor.d.ts +4 -0
- package/dist/components/translation-review-editor.js +4 -3
- package/dist/components/translation-review-editor.js.map +1 -1
- package/dist/components/translation-review-parts.d.ts +1 -0
- package/dist/components/translation-review.d.ts +1 -0
- package/dist/components/translation-review.js +15 -18
- package/dist/components/translation-review.js.map +1 -1
- package/dist/components/ui.d.ts +10 -9
- package/dist/components/ui.js +47 -27
- package/dist/components/ui.js.map +1 -1
- package/dist/components/use-table-state.d.ts +12 -1
- package/dist/components/user-avatar.d.ts +1 -0
- package/dist/components/write-lock.d.ts +101 -13
- package/dist/components/write-lock.js +37 -13
- package/dist/components/write-lock.js.map +1 -1
- package/dist/{data-table-labels-kpAAVi6g.d.ts → data-table-labels-BJ5JE_X2.d.ts} +17 -0
- package/dist/data-table.d.ts +12 -1
- package/dist/{delete-account-setting-Dy4kJgUm.d.ts → delete-account-setting-DAgGBrbn.d.ts} +393 -42
- package/dist/feedback/feedback-attachment.d.ts +11 -10
- package/dist/feedback/feedback-attachment.js +7 -7
- package/dist/feedback/feedback-attachment.js.map +1 -1
- package/dist/feedback/feedback-context.d.ts +11 -10
- package/dist/feedback/feedback-crash.d.ts +11 -10
- package/dist/feedback/feedback-dialog.d.ts +11 -10
- package/dist/feedback/feedback-inbox.d.ts +10 -9
- package/dist/feedback/feedback-inbox.js +7 -3
- package/dist/feedback/feedback-inbox.js.map +1 -1
- package/dist/feedback/feedback-labels.d.ts +11 -10
- package/dist/feedback/feedback-menu.d.ts +4 -3
- package/dist/feedback/feedback-record.d.ts +11 -10
- package/dist/feedback/feedback-row-detail.d.ts +11 -10
- package/dist/feedback/feedback-row-detail.js.map +1 -1
- package/dist/feedback/feedback-status-undo.d.ts +11 -10
- package/dist/feedback/feedback-submit.d.ts +11 -10
- package/dist/feedback/feedback-swipe.d.ts +11 -10
- package/dist/feedback/feedback-swipe.js +3 -6
- package/dist/feedback/feedback-swipe.js.map +1 -1
- package/dist/feedback/feedback-table.d.ts +11 -10
- package/dist/feedback/feedback-table.js.map +1 -1
- package/dist/feedback/feedback-thread.d.ts +11 -10
- package/dist/feedback/feedback-thread.js +5 -1
- package/dist/feedback/feedback-thread.js.map +1 -1
- package/dist/feedback.d.ts +11 -10
- package/dist/hooks/use-anchored-panel.d.ts +37 -7
- package/dist/hooks/use-anchored-panel.js +6 -7
- package/dist/hooks/use-anchored-panel.js.map +1 -1
- package/dist/hooks/use-file-drop.d.ts +11 -10
- package/dist/hooks/use-focus-trap.d.ts +8 -0
- package/dist/hooks/use-focus-trap.js +17 -11
- package/dist/hooks/use-focus-trap.js.map +1 -1
- package/dist/i18n/defaults.d.ts +11 -10
- package/dist/i18n/defaults.js +2 -0
- package/dist/i18n/defaults.js.map +1 -1
- package/dist/i18n/german.d.ts +11 -10
- package/dist/i18n/german.js +37 -1
- package/dist/i18n/german.js.map +1 -1
- package/dist/i18n/kit-labels.d.ts +5 -4
- package/dist/i18n/kit-labels.js.map +1 -1
- package/dist/i18n/languages.d.ts +11 -10
- package/dist/i18n/locales/de-CH.d.ts +11 -10
- package/dist/i18n/locales/en.d.ts +11 -10
- package/dist/i18n/locales/es.d.ts +11 -10
- package/dist/i18n/locales/es.js +35 -1
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.d.ts +11 -10
- package/dist/i18n/locales/fr.js +37 -1
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hu.d.ts +11 -10
- package/dist/i18n/locales/hu.js +38 -1
- package/dist/i18n/locales/hu.js.map +1 -1
- package/dist/i18n/locales/it.d.ts +11 -10
- package/dist/i18n/locales/it.js +35 -1
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/zh.d.ts +11 -10
- package/dist/i18n/locales/zh.js +35 -1
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/i18n/plurals.d.ts +20 -1
- package/dist/i18n/plurals.js +11 -0
- package/dist/i18n/plurals.js.map +1 -1
- package/dist/i18n/review.d.ts +11 -10
- package/dist/i18n/review.js +8 -1
- package/dist/i18n/review.js.map +1 -1
- package/dist/index.d.ts +11 -6
- package/dist/index.js +40 -2
- package/dist/index.js.map +1 -1
- package/dist/landing/landing-actions.d.ts +11 -10
- package/dist/landing/landing-sections.d.ts +11 -10
- package/dist/landing/public-header.d.ts +11 -10
- package/dist/landing/routing.d.ts +11 -10
- package/dist/pay/.well-known/apple-developer-merchantid-domain-association +1 -0
- package/dist/pay/index.html +30 -0
- package/dist/pay/pay.css +126 -0
- package/dist/pay/pay.js +198 -0
- package/dist/rhf/fields.d.ts +11 -10
- package/dist/rhf/form.d.ts +11 -10
- package/dist/rhf.d.ts +11 -10
- package/dist/settings/settings-section.d.ts +11 -10
- package/dist/shell/app-shell.d.ts +10 -9
- package/dist/shell/top-bar-brand.d.ts +11 -10
- package/dist/shell/topbar-action-menu.d.ts +1 -0
- package/dist/shell.d.ts +11 -10
- package/dist/testing/css-variables.d.ts +74 -0
- package/dist/testing/css-variables.generated.d.ts +7 -0
- package/dist/testing/css-variables.generated.js +8 -0
- package/dist/testing/css-variables.generated.js.map +1 -0
- package/dist/testing/css-variables.js +93 -0
- package/dist/testing/css-variables.js.map +1 -0
- package/dist/testing/index.d.ts +1 -0
- package/dist/testing/index.js +12 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/theme/contrast-tokens.d.ts +44 -1
- package/dist/theme/contrast-tokens.js +21 -0
- package/dist/theme/contrast-tokens.js.map +1 -1
- package/dist/theme/contrast.d.ts +2 -2
- package/dist/theme/palette-derive.js +60 -11
- package/dist/theme/palette-derive.js.map +1 -1
- package/dist/theme/palette-presets.js +45 -43
- package/dist/theme/palette-presets.js.map +1 -1
- package/dist/wizard/stepper-nav.d.ts +12 -11
- package/dist/wizard/stepper-nav.js.map +1 -1
- package/dist/wizard.d.ts +11 -10
- package/package.json +10 -2
- package/src/account/delete-account-setting.tsx +6 -1
- package/src/account/email-change-setting.tsx +9 -3
- package/src/account/sessions-setting.tsx +7 -2
- package/src/admin/admin-action-confirm.tsx +2 -1
- package/src/admin/invitations-panel.tsx +9 -3
- package/src/admin/plan-change.tsx +487 -0
- package/src/admin/reviewer-scope-editor.tsx +2 -1
- package/src/admin/role-select.tsx +2 -1
- package/src/admin/user-roster.tsx +5 -3
- package/src/auth/auth-errors.ts +25 -2
- package/src/auth/complete-name-dialog.tsx +6 -2
- package/src/billing/billing-banner.tsx +3 -1
- package/src/billing/billing-labels.ts +45 -0
- package/src/billing/billing-lock.ts +36 -3
- package/src/billing/billing-overview.ts +58 -0
- package/src/billing/checkout-processing.ts +391 -0
- package/src/billing/checkout-return.ts +90 -0
- package/src/billing/pay-page.ts +246 -0
- package/src/billing/plan-limit-toast.tsx +91 -0
- package/src/billing/subscription-actions.tsx +41 -8
- package/src/components/account-settings.tsx +6 -2
- package/src/components/autocomplete.tsx +10 -4
- package/src/components/button-group.tsx +4 -1
- package/src/components/calculator.tsx +10 -6
- package/src/components/checkbox-group.tsx +2 -2
- package/src/components/checkbox.tsx +2 -1
- package/src/components/chip.tsx +37 -32
- package/src/components/choice-card.tsx +4 -2
- package/src/components/combobox-core.tsx +5 -2
- package/src/components/combobox.tsx +8 -6
- package/src/components/confirm-dialog.tsx +13 -6
- package/src/components/country-select.tsx +2 -2
- package/src/components/danger-confirm.tsx +2 -2
- package/src/components/data-table.tsx +20 -9
- package/src/components/date-picker.tsx +10 -7
- package/src/components/dropdown.tsx +12 -2
- package/src/components/entity-combobox.tsx +3 -3
- package/src/components/field-parts.tsx +61 -14
- package/src/components/file-button.tsx +5 -4
- package/src/components/file-dropzone.tsx +2 -2
- package/src/components/floating-panel.tsx +7 -5
- package/src/components/form-actions.tsx +12 -5
- package/src/components/full-bleed-dialog.tsx +6 -0
- package/src/components/inline-edit-field.tsx +13 -13
- package/src/components/list.tsx +10 -9
- package/src/components/modal.tsx +5 -0
- package/src/components/month-picker.tsx +8 -2
- package/src/components/multi-entity-combobox.tsx +3 -3
- package/src/components/number-field.tsx +7 -0
- package/src/components/number-input.tsx +71 -11
- package/src/components/numpad-sheet.tsx +8 -4
- package/src/components/popover.tsx +6 -2
- package/src/components/row-actions.tsx +208 -58
- package/src/components/share-card.tsx +67 -13
- package/src/components/skeleton.tsx +10 -2
- package/src/components/status-dot.tsx +7 -7
- package/src/components/swatch-picker.tsx +2 -2
- package/src/components/swipeable-row.tsx +138 -27
- package/src/components/switch.tsx +2 -1
- package/src/components/table.tsx +8 -1
- package/src/components/toggle-group.tsx +5 -3
- package/src/components/translation-review-editor.tsx +8 -3
- package/src/components/translation-review.tsx +18 -22
- package/src/components/ui.tsx +92 -43
- package/src/components/write-lock.tsx +150 -24
- package/src/feedback/feedback-attachment.tsx +13 -9
- package/src/feedback/feedback-inbox.tsx +10 -6
- package/src/feedback/feedback-row-detail.tsx +3 -2
- package/src/feedback/feedback-swipe.tsx +6 -11
- package/src/feedback/feedback-table.tsx +2 -1
- package/src/feedback/feedback-thread.tsx +20 -1
- package/src/hooks/use-anchored-panel.ts +60 -14
- package/src/hooks/use-focus-trap.ts +55 -12
- package/src/i18n/defaults.ts +2 -0
- package/src/i18n/german.ts +41 -0
- package/src/i18n/kit-labels.tsx +4 -0
- package/src/i18n/locales/es.ts +35 -0
- package/src/i18n/locales/fr.ts +41 -0
- package/src/i18n/locales/hu.ts +39 -0
- package/src/i18n/locales/it.ts +36 -0
- package/src/i18n/locales/zh.ts +34 -0
- package/src/i18n/plurals.ts +29 -0
- package/src/i18n/review.ts +7 -0
- package/src/index.ts +51 -5
- package/src/testing/css-variables.generated.ts +112 -0
- package/src/testing/css-variables.ts +191 -0
- package/src/testing/index.ts +13 -0
- package/src/theme/contrast-tokens.ts +53 -2
- package/src/theme/palette-derive.ts +87 -10
- package/src/theme/palette-presets.ts +45 -43
- package/src/wizard/stepper-nav.tsx +2 -1
- package/tokens.css +324 -46
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
type DisabledReasonDisplay,
|
|
13
13
|
} from "./field-parts";
|
|
14
14
|
import { FOCUS_RING } from "./focus-ring";
|
|
15
|
+
import type { CommitScope } from "./write-lock";
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* A checkbox that is still `<input type="checkbox">`.
|
|
@@ -134,7 +135,7 @@ export interface CheckboxProps extends Omit<InputHTMLAttributes<HTMLInputElement
|
|
|
134
135
|
* locked the `disabledReason` way with the lock's reason (which wins over its own).
|
|
135
136
|
* No provider, or an unlocked one: no effect. Button's `commit`, for keksdose K3.
|
|
136
137
|
*/
|
|
137
|
-
commit?:
|
|
138
|
+
commit?: CommitScope;
|
|
138
139
|
}
|
|
139
140
|
|
|
140
141
|
/**
|
package/src/components/chip.tsx
CHANGED
|
@@ -10,7 +10,7 @@ import { DisabledReasonLine, useDisabledReasonLine, type DisabledReasonDisplay }
|
|
|
10
10
|
import { DEFAULT_COMMON_LABELS, useKitLabels, useKitLink, useKitLocale } from "../i18n/kit-labels";
|
|
11
11
|
import { pickLinkRenderer } from "./text-link";
|
|
12
12
|
import { Tooltip } from "./tooltip";
|
|
13
|
-
import { useCommitReason } from "./write-lock";
|
|
13
|
+
import { useCommitReason, type CommitScope } from "./write-lock";
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* A chip: a compact pill carrying one value.
|
|
@@ -137,7 +137,9 @@ const TONE: Record<ChipTone, { idle: string; selected: string }> = {
|
|
|
137
137
|
// outline toggle that stays an outline when on has no visible state.
|
|
138
138
|
const OUTLINE: Record<ChipTone, string> = {
|
|
139
139
|
neutral: "border-[var(--border-strong)] bg-transparent text-[var(--text-secondary)]",
|
|
140
|
-
brand
|
|
140
|
+
// The brand AS TEXT is `--brand-muted` (0.33): `--brand` itself is solved to 3:1, a
|
|
141
|
+
// fill's boundary, and as text it fell to 3.0:1 in the derived dark presets.
|
|
142
|
+
brand: "border-[var(--brand)] bg-transparent text-brand-muted",
|
|
141
143
|
danger: "border-[var(--danger-border)] bg-transparent text-[var(--danger)]",
|
|
142
144
|
warning: "border-[var(--warning-border)] bg-transparent text-[var(--warning)]",
|
|
143
145
|
success: "border-[var(--success-border)] bg-transparent text-[var(--success)]",
|
|
@@ -151,25 +153,27 @@ const OUTLINE: Record<ChipTone, string> = {
|
|
|
151
153
|
orange: "border-[var(--hue-orange-border)] bg-transparent text-[var(--hue-orange)]",
|
|
152
154
|
};
|
|
153
155
|
|
|
154
|
-
// `solid`: the fill under its contrast
|
|
155
|
-
//
|
|
156
|
-
//
|
|
157
|
-
//
|
|
158
|
-
//
|
|
156
|
+
// `solid`: the fill under its own foreground, `<fill>-contrast` (0.33, colour-roles
|
|
157
|
+
// §5.1): white in light, the tone's 950 (the page, for money) on the dark theme's
|
|
158
|
+
// pastels. Until 0.33 only brand and danger had one and the rest borrowed
|
|
159
|
+
// `--text-inverse`, the surface colour — which left light warning at 4.24:1 and orange
|
|
160
|
+
// at 4.38:1. Neutral keeps the inverse pair: a count pill, louder than the neutral
|
|
161
|
+
// fill. The border goes transparent rather than away, so a solid chip is exactly as
|
|
162
|
+
// tall as a soft one.
|
|
159
163
|
const SOLID: Record<ChipTone, string> = {
|
|
160
|
-
neutral: "border-transparent bg-
|
|
161
|
-
brand: "border-transparent bg-
|
|
162
|
-
danger: "border-transparent bg-
|
|
163
|
-
warning: "border-transparent bg-
|
|
164
|
-
success: "border-transparent bg-
|
|
165
|
-
info: "border-transparent bg-
|
|
166
|
-
income: "border-transparent bg-
|
|
167
|
-
expense: "border-transparent bg-
|
|
168
|
-
blue: "border-transparent bg-
|
|
169
|
-
indigo: "border-transparent bg-
|
|
170
|
-
purple: "border-transparent bg-
|
|
171
|
-
teal: "border-transparent bg-
|
|
172
|
-
orange: "border-transparent bg-
|
|
164
|
+
neutral: "border-transparent bg-inverse text-inverse",
|
|
165
|
+
brand: "border-transparent bg-brand text-brand-contrast",
|
|
166
|
+
danger: "border-transparent bg-danger text-danger-contrast",
|
|
167
|
+
warning: "border-transparent bg-warning text-warning-contrast",
|
|
168
|
+
success: "border-transparent bg-success text-success-contrast",
|
|
169
|
+
info: "border-transparent bg-info text-info-contrast",
|
|
170
|
+
income: "border-transparent bg-money-pos text-money-income-contrast",
|
|
171
|
+
expense: "border-transparent bg-money-neg text-money-expense-contrast",
|
|
172
|
+
blue: "border-transparent bg-hue-blue text-hue-blue-contrast",
|
|
173
|
+
indigo: "border-transparent bg-hue-indigo text-hue-indigo-contrast",
|
|
174
|
+
purple: "border-transparent bg-hue-purple text-hue-purple-contrast",
|
|
175
|
+
teal: "border-transparent bg-hue-teal text-hue-teal-contrast",
|
|
176
|
+
orange: "border-transparent bg-hue-orange text-hue-orange-contrast",
|
|
173
177
|
};
|
|
174
178
|
|
|
175
179
|
/** `dot`: the fill of the dot itself — the tone's strongest colour, which is the one
|
|
@@ -380,7 +384,8 @@ export function refreshChipEdges(): void {
|
|
|
380
384
|
for (let pass = 0; pass <= n && pending.length; pass++) {
|
|
381
385
|
const reads = pending.map((el) => {
|
|
382
386
|
const r = el.getBoundingClientRect();
|
|
383
|
-
|
|
387
|
+
// The text label (CHIP_LABEL_TRUNCATE; `.truncate` before 0.33).
|
|
388
|
+
const label = el.querySelector<HTMLElement>(".truncate-until-large");
|
|
384
389
|
// Not laid out (a hidden ancestor, jsdom), or truncated at its container's edge,
|
|
385
390
|
// where a wider chip would overflow: leave it alone. So too a label wrapped onto
|
|
386
391
|
// a second line at Large (0.32.1): the chip is already as wide as its row lets it
|
|
@@ -511,16 +516,16 @@ const CHIP_BASE = `${CHIP_PILL} ${CHIP_RING}`;
|
|
|
511
516
|
* "…". keksdose's "Zur Prüfung zurücklegen" read "Zur Prüfung zu…" on a phone at Extra
|
|
512
517
|
* large, which is a different instruction. No size has a fixed height (padding and
|
|
513
518
|
* `min-h-*` only), so the pill grows with its lines; the mark before the text stays
|
|
514
|
-
* centred on them, as in a pill. A `large:`
|
|
519
|
+
* centred on them, as in a pill. A `large:` rule, so Normal keeps its one-line chip.
|
|
515
520
|
*
|
|
516
|
-
*
|
|
517
|
-
*
|
|
518
|
-
*
|
|
519
|
-
*
|
|
520
|
-
*
|
|
521
|
-
* the
|
|
521
|
+
* 0.33 (§10.17): the kit's one `truncate-until-large` (tokens.css) in place of this
|
|
522
|
+
* file's own `truncate` + `large:whitespace-normal large:break-words`, as StatusDot's
|
|
523
|
+
* label took it. The utility breaks with `overflow-wrap: anywhere`, which lowers the
|
|
524
|
+
* label's min-content width to one letter: a status chip in an auto-sized table column
|
|
525
|
+
* wants the column given a width at Large, or it is squeezed to a letter per line
|
|
526
|
+
* (StatusDot's label was, in the showcase's tone table at 360 px, Extra large).
|
|
522
527
|
*/
|
|
523
|
-
const
|
|
528
|
+
const CHIP_LABEL_TRUNCATE = "truncate-until-large";
|
|
524
529
|
|
|
525
530
|
/**
|
|
526
531
|
* An interactive chip's touch target at Large and Extra large (docs/text-size-harmonization.md
|
|
@@ -720,7 +725,7 @@ export type ChipProps = ChipBaseProps &
|
|
|
720
725
|
/** This chip COMMITS — pressing it saves. Under a locked
|
|
721
726
|
* {@link WriteLockProvider} it takes the `disabledReason` path with the lock's
|
|
722
727
|
* reason, as {@link Button}'s `commit` does. */
|
|
723
|
-
commit?:
|
|
728
|
+
commit?: CommitScope;
|
|
724
729
|
}
|
|
725
730
|
);
|
|
726
731
|
|
|
@@ -841,7 +846,7 @@ export const Chip = forwardRef<HTMLElement, ChipProps>(function Chip(
|
|
|
841
846
|
) : (
|
|
842
847
|
<Icon className={cn(s.icon, "shrink-0")} aria-hidden />
|
|
843
848
|
))}
|
|
844
|
-
{/* Text truncates at Normal and wraps at Large (
|
|
849
|
+
{/* Text truncates at Normal and wraps at Large (CHIP_LABEL_TRUNCATE). Mixed
|
|
845
850
|
children (an icon and a word) sit in a row instead: as a plain span, the svg —
|
|
846
851
|
a block under Tailwind's preflight — stacked above the text (keksdose live
|
|
847
852
|
#358). */}
|
|
@@ -849,7 +854,7 @@ export const Chip = forwardRef<HTMLElement, ChipProps>(function Chip(
|
|
|
849
854
|
className={cn(
|
|
850
855
|
"min-w-0",
|
|
851
856
|
typeof children === "string" || typeof children === "number"
|
|
852
|
-
?
|
|
857
|
+
? CHIP_LABEL_TRUNCATE
|
|
853
858
|
: "inline-flex items-center gap-1 [&>svg]:size-[1em] [&>svg]:shrink-0",
|
|
854
859
|
)}
|
|
855
860
|
>
|
|
@@ -247,13 +247,15 @@ const META_TONE: Record<ActionCardMetaTone, string> = {
|
|
|
247
247
|
};
|
|
248
248
|
|
|
249
249
|
/** The colour of {@link ActionCardProps.icon}. `default` is the secondary text colour
|
|
250
|
-
* the icon has always had; `brand` tints it (keksdose's privacy enrolment)
|
|
250
|
+
* the icon has always had; `brand` tints it (keksdose's privacy enrolment) with the
|
|
251
|
+
* brand as text, `--brand-muted` (0.33, docs/colour-roles-harmonization.md §5.5):
|
|
252
|
+
* `--brand` read 3.03:1 on the card's hover in the derived dark presets. */
|
|
251
253
|
export type ActionCardIconTone = "default" | "muted" | "brand" | "warning" | "danger" | "info" | "success";
|
|
252
254
|
|
|
253
255
|
const ICON_TONE: Record<ActionCardIconTone, string> = {
|
|
254
256
|
default: "text-[var(--text-secondary)]",
|
|
255
257
|
...META_TONE,
|
|
256
|
-
brand: "text-
|
|
258
|
+
brand: "text-brand-muted",
|
|
257
259
|
};
|
|
258
260
|
|
|
259
261
|
/** What {@link ActionCardProps.renderLink} (and the provider's `linkComponent`) is
|
|
@@ -899,11 +899,14 @@ export function ComboboxPanel<V extends string | number>({
|
|
|
899
899
|
onKeyDown={onKeyDown}
|
|
900
900
|
// `placement` keeps the panel inside the region actually on screen: on a phone
|
|
901
901
|
// the search box below pulls up the keyboard, and a panel pinned under a
|
|
902
|
-
// low trigger would otherwise sit entirely behind it (feedback #135).
|
|
902
|
+
// low trigger would otherwise sit entirely behind it (feedback #135). Flipped
|
|
903
|
+
// above, it hangs from its bottom edge, so a list shorter than its cap still meets
|
|
904
|
+
// the trigger (keksdose K1); the edge not in use is cleared, a caller's included.
|
|
903
905
|
style={{
|
|
904
906
|
...style,
|
|
905
907
|
position: "fixed",
|
|
906
|
-
top: placement.top,
|
|
908
|
+
top: placement.above ? undefined : placement.top,
|
|
909
|
+
bottom: placement.above ? placement.bottom : undefined,
|
|
907
910
|
...inline,
|
|
908
911
|
width: rect.width,
|
|
909
912
|
// 220 px at Normal, in rem so the panel's text keeps its room at Large (§3.2).
|
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
useLockReason,
|
|
35
35
|
} from "./field-parts";
|
|
36
36
|
import { hasMessage, mergeDescribedBy } from "./choice-parts";
|
|
37
|
-
import { useCommitReason } from "./write-lock";
|
|
37
|
+
import { useCommitReason, type CommitScope } from "./write-lock";
|
|
38
38
|
|
|
39
39
|
// One look for both combobox flavors below — the suggestion list and its rows
|
|
40
40
|
// must stay pixel-identical between the free-text and the id-keyed variant (and
|
|
@@ -112,7 +112,7 @@ function SuggestionList({
|
|
|
112
112
|
panelRef: RefObject<HTMLDivElement | null>;
|
|
113
113
|
children: ReactNode;
|
|
114
114
|
}) {
|
|
115
|
-
const { rect, top, maxHeight } = useAnchoredPanel(anchorRef, true, { preferredHeight: 256 });
|
|
115
|
+
const { rect, top, bottom, maxHeight, above } = useAnchoredPanel(anchorRef, true, { preferredHeight: 256 });
|
|
116
116
|
const dir = useAnchorDir(anchorRef, true);
|
|
117
117
|
if (!rect) return null;
|
|
118
118
|
return createPortal(
|
|
@@ -124,7 +124,9 @@ function SuggestionList({
|
|
|
124
124
|
// Portalled out of the form's `dir`; the field's is put back. The list is
|
|
125
125
|
// exactly the field's width, so `left` places it in either direction.
|
|
126
126
|
dir={dir}
|
|
127
|
-
|
|
127
|
+
// Flipped above, the list hangs from its bottom edge: it filters as the user
|
|
128
|
+
// types, and a short one placed by `top` floated above the field (keksdose K1).
|
|
129
|
+
style={{ ...(above ? { bottom } : { top }), left: rect.left, width: rect.width }}
|
|
128
130
|
>
|
|
129
131
|
<ul id={id} role="listbox" data-clips="" className={LIST_CLASS} style={{ maxHeight }}>
|
|
130
132
|
{children}
|
|
@@ -207,7 +209,7 @@ export interface ComboboxProps
|
|
|
207
209
|
/** This field COMMITS. Under a locked {@link WriteLockProvider} it is locked the
|
|
208
210
|
* `disabledReason` way with the lock's reason; inside a form with its own Save, leave
|
|
209
211
|
* it off and put `commit` on the Save. No provider, or an unlocked one: no effect. */
|
|
210
|
-
commit?:
|
|
212
|
+
commit?: CommitScope;
|
|
211
213
|
/** Heading an option belongs under. Supplying it makes this list read exactly
|
|
212
214
|
* like {@link InlineEntityCombobox}'s — one heading per group with its rows
|
|
213
215
|
* indented beneath — instead of a flat list (feedback #136 rework: the payee
|
|
@@ -849,7 +851,7 @@ export interface InlineEntityComboboxProps<V extends string | number, C extends
|
|
|
849
851
|
* A picker inside a form with its own Save stays editable under the lock — leave this
|
|
850
852
|
* off there and put `commit` on the Save. No provider, or an unlocked one: no effect.
|
|
851
853
|
*/
|
|
852
|
-
commit?:
|
|
854
|
+
commit?: CommitScope;
|
|
853
855
|
/**
|
|
854
856
|
* A last row that makes a new record from what was typed — keksdose G9, whose "Create
|
|
855
857
|
* cash account" had to become a separate button because this picker had no such row.
|
|
@@ -894,7 +896,7 @@ export interface InlineEntityComboboxProps<V extends string | number, C extends
|
|
|
894
896
|
* one explanation a phone cannot show), and `onCreate` is not called. Not needed with
|
|
895
897
|
* `commit`: a locked field opens no list at all.
|
|
896
898
|
*/
|
|
897
|
-
createCommit?:
|
|
899
|
+
createCommit?: CommitScope;
|
|
898
900
|
/**
|
|
899
901
|
* The `<input>` — the focusable control, the one a reader types in — as a React 19
|
|
900
902
|
* ref prop (0.24, kastlan). Its account picker is this component inside an
|
|
@@ -6,7 +6,7 @@ import { TypedConfirmField, typedMatches } from "./danger-confirm";
|
|
|
6
6
|
import type { TypedMatch } from "./danger-confirm";
|
|
7
7
|
import { DialogFrame } from "./dialog-frame";
|
|
8
8
|
import { Button } from "./ui";
|
|
9
|
-
import { useWriteLock } from "./write-lock";
|
|
9
|
+
import { useWriteLock, writeLockFor, type CommitScope } from "./write-lock";
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* The `confirmDialog` namespace of `<UiKitProvider labels>`: the two buttons' fallback
|
|
@@ -83,8 +83,12 @@ export interface ConfirmOptions {
|
|
|
83
83
|
* host sits — it is `aria-disabled` with the lock's reason, so a read-only page (a
|
|
84
84
|
* demo, a viewer's budget) can't confirm a delete through a dialog. One prop for the
|
|
85
85
|
* many confirm sites an app has (kastlan's 0.31 adoption counted ~23).
|
|
86
|
+
*
|
|
87
|
+
* 0.33: a {@link CommitScope} — `confirm({ commit: COMMIT_EXCEPT_BILLING })` for a
|
|
88
|
+
* confirm a lapsed plan still allows (removing access, the account's own settings;
|
|
89
|
+
* docs/billing-harmonization.md §12.36).
|
|
86
90
|
*/
|
|
87
|
-
commit?:
|
|
91
|
+
commit?: CommitScope;
|
|
88
92
|
}
|
|
89
93
|
|
|
90
94
|
export type ConfirmFn = (options: ConfirmOptions) => Promise<boolean>;
|
|
@@ -107,12 +111,15 @@ export function useConfirm(): ConfirmFn {
|
|
|
107
111
|
throw new Error("useConfirm() must be called below a <ConfirmProvider>.");
|
|
108
112
|
}
|
|
109
113
|
// The lock of the CALLER's place: the dialog host usually sits above the app's
|
|
110
|
-
// `WriteLockProvider`, so it could not read the lock itself.
|
|
114
|
+
// `WriteLockProvider`, so it could not read the lock itself. Each call's own `commit`
|
|
115
|
+
// scope is applied to it when the call runs (`writeLockFor`, §12.36).
|
|
111
116
|
const lock = useWriteLock();
|
|
112
117
|
return useCallback(
|
|
113
|
-
(options: ConfirmOptions) =>
|
|
114
|
-
|
|
115
|
-
|
|
118
|
+
(options: ConfirmOptions) => {
|
|
119
|
+
const scoped = writeLockFor(lock, options.commit);
|
|
120
|
+
return confirm(scoped.locked ? ({ ...options, lockReason: scoped.reason } as ConfirmOptions) : options);
|
|
121
|
+
},
|
|
122
|
+
[confirm, lock],
|
|
116
123
|
);
|
|
117
124
|
}
|
|
118
125
|
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
type ComboOption,
|
|
14
14
|
} from "./combobox-core";
|
|
15
15
|
import { assignRef, hasMessage, mergeDescribedBy } from "./choice-parts";
|
|
16
|
-
import { useCommitReason } from "./write-lock";
|
|
16
|
+
import { useCommitReason, type CommitScope } from "./write-lock";
|
|
17
17
|
import {
|
|
18
18
|
DEFAULT_COMBOBOX_LABELS,
|
|
19
19
|
DEFAULT_COMMON_LABELS,
|
|
@@ -147,7 +147,7 @@ export interface CountrySelectProps<Clearable extends boolean = false>
|
|
|
147
147
|
* reason. A country field inside a form that has its own Save stays editable under
|
|
148
148
|
* the lock — leave this off there, and put `commit` on the Save.
|
|
149
149
|
*/
|
|
150
|
-
commit?:
|
|
150
|
+
commit?: CommitScope;
|
|
151
151
|
/** The language the names are in. Default: the `<UiKitProvider locale>`, else
|
|
152
152
|
* English (see {@link countryName}). */
|
|
153
153
|
locale?: string;
|
|
@@ -6,7 +6,7 @@ import { Button, Input, Label, Spinner } from "./ui";
|
|
|
6
6
|
import type { ButtonVariant, InputProps } from "./ui";
|
|
7
7
|
import { Checkbox } from "./checkbox";
|
|
8
8
|
import { Tooltip } from "./tooltip";
|
|
9
|
-
import { useCommitReason } from "./write-lock";
|
|
9
|
+
import { useCommitReason, type CommitScope } from "./write-lock";
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* How typed text is compared with the text it has to repeat — shared by
|
|
@@ -567,7 +567,7 @@ export interface DangerConfirmProps extends Omit<ComponentPropsWithoutRef<"div">
|
|
|
567
567
|
* provider no longer threads `lockedReason={lock.locked ? lock.reason : undefined}`
|
|
568
568
|
* into every tile. No provider, or an unlocked one: no effect.
|
|
569
569
|
*/
|
|
570
|
-
commit?:
|
|
570
|
+
commit?: CommitScope;
|
|
571
571
|
/** Controlled armed state. The parent can then collapse the tile from a mutation's
|
|
572
572
|
* own `onSuccess` without returning a promise. */
|
|
573
573
|
armed?: boolean;
|
|
@@ -246,6 +246,23 @@ export interface DataTableProps<T> {
|
|
|
246
246
|
rowHref?: (row: T) => string | undefined;
|
|
247
247
|
expandedRow?: (row: T) => ReactNode | null;
|
|
248
248
|
isExpanded?: (row: T) => boolean;
|
|
249
|
+
/**
|
|
250
|
+
* Extra classes for a row — the `<tr>` on desktop, the card on mobile. Merged last,
|
|
251
|
+
* so a `hover:` fill here replaces the row's own `hover:bg-[var(--bg-hover)]`.
|
|
252
|
+
*
|
|
253
|
+
* **A row you paint has to pick its own hover** (0.33, docs/colour-roles-harmonization.md
|
|
254
|
+
* §12.2): the kit cannot see your rest colour, and `--bg-hover` is mixed against the
|
|
255
|
+
* card. The rule: a hover differs from its rest by 1.08:1 or more, and every text role
|
|
256
|
+
* on it keeps 4.5:1.
|
|
257
|
+
* - A row that rests on the well (`bg-surface-2`) hovers to the CARD,
|
|
258
|
+
* `hover:bg-surface`: in light the well is the page, and `--bg-hover` sits 1.04:1
|
|
259
|
+
* from it.
|
|
260
|
+
* - A row whose well MARKS A STATE (selected) keeps its fill and draws a 1 px inside
|
|
261
|
+
* line instead, since the card would read as "not selected":
|
|
262
|
+
* `bg-surface-2 hover:bg-surface-2 hover:outline hover:-outline-offset-1 hover:outline-strong`.
|
|
263
|
+
* An outline, not a shadow: a shadow on a `<tr>` is not painted by every engine.
|
|
264
|
+
* - Not `--bg-active` for a selected row: its muted and money text fall to 3.8–4.7:1.
|
|
265
|
+
*/
|
|
249
266
|
rowClassName?: (row: T) => string | undefined;
|
|
250
267
|
/**
|
|
251
268
|
* Extra DOM attributes for a row's container — the `<tr>` on desktop, the
|
|
@@ -1199,15 +1216,9 @@ export function DataTable<T>({
|
|
|
1199
1216
|
label: a.label,
|
|
1200
1217
|
icon: a.icon,
|
|
1201
1218
|
onCommit: () => void runRowAction(a.action, row),
|
|
1202
|
-
//
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
? "bg-[var(--danger)] text-[var(--danger-contrast)]"
|
|
1206
|
-
: "bg-[var(--brand)] text-[var(--brand-contrast)]",
|
|
1207
|
-
armedClassName:
|
|
1208
|
-
a.tone === "danger"
|
|
1209
|
-
? "bg-[var(--danger-hover)] text-[var(--danger-contrast)]"
|
|
1210
|
-
: "bg-[var(--brand-hover)] text-[var(--brand-contrast)]",
|
|
1219
|
+
// The row action's tone, painted by SwipeableRow: its soft wash idle, its fill
|
|
1220
|
+
// and that fill's foreground armed (0.33).
|
|
1221
|
+
tone: a.tone === "danger" ? "danger" : "brand",
|
|
1211
1222
|
});
|
|
1212
1223
|
return {
|
|
1213
1224
|
start: swipes.filter((a) => a.swipe === "start").map(toSwipe),
|
|
@@ -17,7 +17,7 @@ import { splitTriggerAria } from "./trigger-aria";
|
|
|
17
17
|
import type { TriggerAria } from "./trigger-aria";
|
|
18
18
|
import { Button, FIELD_BASE, FIELD_TRIGGER, FIELD_FLOATING_PAD, FIELD_INVALID } from "./ui";
|
|
19
19
|
import { FOCUS_RING_WIDTH } from "./focus-ring";
|
|
20
|
-
import { FieldBox, FieldLabelLine, useFieldMessages } from "./field-parts";
|
|
20
|
+
import { FieldBox, FieldLabelLine, LABEL_ABOVE_BOX, useFieldMessages } from "./field-parts";
|
|
21
21
|
import { FullBleedDialog } from "./full-bleed-dialog";
|
|
22
22
|
import { usePhoneLayout, type RemLength } from "../hooks/use-breakpoint";
|
|
23
23
|
import { DEFAULT_MINI_CALENDAR_LABELS, MiniCalendar, type MiniCalendarProps } from "./mini-calendar";
|
|
@@ -210,11 +210,12 @@ function CustomTrigger({
|
|
|
210
210
|
* The trigger's value wraps instead of truncating at Large and Extra large (0.32.1, the
|
|
211
211
|
* 360 px Extra-large sweep; docs/text-size-harmonization.md §4 "nothing truncates"). A
|
|
212
212
|
* range ("01/09/2026 – 30/09/2026") is 312 px at 150 %, and on a 360 px phone it read
|
|
213
|
-
* "01/09/2026 – 30/…" — its end, the half a reader needs, was the half cut off.
|
|
214
|
-
*
|
|
215
|
-
*
|
|
213
|
+
* "01/09/2026 – 30/…" — its end, the half a reader needs, was the half cut off. A
|
|
214
|
+
* `large:` class, so Normal keeps its one-line field: since 0.33 (§10.17) the kit's one
|
|
215
|
+
* `truncate-until-large` (tokens.css) in place of this file's own `truncate` +
|
|
216
|
+
* `large:whitespace-normal large:break-words`.
|
|
216
217
|
*/
|
|
217
|
-
const
|
|
218
|
+
const VALUE_TRUNCATE = "truncate-until-large";
|
|
218
219
|
|
|
219
220
|
/**
|
|
220
221
|
* The field-shaped button that opens the calendar.
|
|
@@ -330,7 +331,7 @@ function DateFieldTrigger({
|
|
|
330
331
|
|
|
331
332
|
return (
|
|
332
333
|
<button {...attrs}>
|
|
333
|
-
<span id={valueId} className={cn(
|
|
334
|
+
<span id={valueId} className={cn(VALUE_TRUNCATE, !hasValue && "text-[var(--text-placeholder)]")}>
|
|
334
335
|
{/* `|| " "` (a NON-BREAKING space) — triggerText is "" when there is no value and no
|
|
335
336
|
placeholder was passed. An empty span has no line box, so the
|
|
336
337
|
trigger collapses to its padding and sits shorter than every
|
|
@@ -515,7 +516,9 @@ function DateField({
|
|
|
515
516
|
return (
|
|
516
517
|
// The caller's attributes land here, on the field's own box — the trigger inside is
|
|
517
518
|
// named by `aria-labelledby` and must keep the id pair it is given.
|
|
518
|
-
|
|
519
|
+
// At Large a labelled box is a grid: the label above, the calendar glyph and the
|
|
520
|
+
// clear × measured against the trigger's row (LABEL_ABOVE_BOX, 0.33 §10.17).
|
|
521
|
+
<div {...wrapperRest} ref={rootRef} className={cn("relative", label !== undefined && LABEL_ABOVE_BOX, className)}>
|
|
519
522
|
{label !== undefined && <FieldLabelLine label={label} hint={labelHint} />}
|
|
520
523
|
{/* The visible FieldLabel is a plain span, not a `<label htmlFor>`, so it names
|
|
521
524
|
nothing on its own — this hidden twin is what the trigger is named by.
|
|
@@ -341,8 +341,18 @@ export function DropdownPanel({
|
|
|
341
341
|
dir={dir}
|
|
342
342
|
// The caller's `style` is kept underneath, but the placement is measured rather
|
|
343
343
|
// than chosen (dev#548: an `overflow` ancestor clipped a third of this panel
|
|
344
|
-
// away), so
|
|
345
|
-
|
|
344
|
+
// away), so these values are the panel's own. Flipped above, it hangs from its
|
|
345
|
+
// bottom edge, so a list shorter than its cap still meets the trigger (keksdose
|
|
346
|
+
// K1); the edge not in use is cleared, a caller's included.
|
|
347
|
+
style={{
|
|
348
|
+
...style,
|
|
349
|
+
position: "fixed",
|
|
350
|
+
top: anchored.above ? undefined : anchored.top,
|
|
351
|
+
bottom: anchored.above ? anchored.bottom : undefined,
|
|
352
|
+
left,
|
|
353
|
+
width,
|
|
354
|
+
maxHeight: anchored.maxHeight,
|
|
355
|
+
}}
|
|
346
356
|
className={cn(
|
|
347
357
|
"z-50 flex flex-col overflow-hidden rounded-md border border-[var(--border)] bg-[var(--bg-surface)] shadow-lg",
|
|
348
358
|
// The list, not the panel, is what scrolls: the search header has to stay put
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
useLockReason,
|
|
24
24
|
} from "./field-parts";
|
|
25
25
|
import { assignRef, mergeDescribedBy } from "./choice-parts";
|
|
26
|
-
import { useCommitReason } from "./write-lock";
|
|
26
|
+
import { useCommitReason, type CommitScope } from "./write-lock";
|
|
27
27
|
|
|
28
28
|
export type { ComboClearValue, ComboOption } from "./combobox-core";
|
|
29
29
|
|
|
@@ -89,7 +89,7 @@ export interface EntityComboboxProps<V extends string | number, C extends ComboC
|
|
|
89
89
|
* A picker inside a form with its own Save stays editable under the lock: leave this
|
|
90
90
|
* off there and put `commit` on the Save. No provider, or an unlocked one: no effect.
|
|
91
91
|
*/
|
|
92
|
-
commit?:
|
|
92
|
+
commit?: CommitScope;
|
|
93
93
|
/** When set, a "create" row appears for a non-empty query with no exact match. */
|
|
94
94
|
onCreate?: (query: string) => void;
|
|
95
95
|
createLabel?: (query: string) => string;
|
|
@@ -106,7 +106,7 @@ export interface EntityComboboxProps<V extends string | number, C extends ComboC
|
|
|
106
106
|
* taken, with the lock's reason as its second line — the picker itself stays live.
|
|
107
107
|
* keksdose dev#496: on the read-only demo choosing is draft state, minting is not.
|
|
108
108
|
*/
|
|
109
|
-
createCommit?:
|
|
109
|
+
createCommit?: CommitScope;
|
|
110
110
|
/** Required and unanswered — {@link FIELD_INVALID}. See {@link Input}'s `invalid`. */
|
|
111
111
|
invalid?: boolean;
|
|
112
112
|
/** What is wrong with the value, as {@link Input}'s `error`: rendered under the
|
|
@@ -5,7 +5,7 @@ import { cn } from "../lib/cn";
|
|
|
5
5
|
import { useInlineFacts } from "../hooks/use-large-text";
|
|
6
6
|
import { FOCUS_RING } from "./focus-ring";
|
|
7
7
|
import { Tooltip, type TooltipSide } from "./tooltip";
|
|
8
|
-
import { useCommitReason } from "./write-lock";
|
|
8
|
+
import { useCommitReason, type CommitScope } from "./write-lock";
|
|
9
9
|
import { hasMessage, mergeDescribedBy } from "./choice-parts";
|
|
10
10
|
|
|
11
11
|
/**
|
|
@@ -34,12 +34,45 @@ import { hasMessage, mergeDescribedBy } from "./choice-parts";
|
|
|
34
34
|
export const STATIC_LABEL_TYPE =
|
|
35
35
|
"text-caption leading-tight text-[var(--text-muted)] peer-disabled:opacity-50";
|
|
36
36
|
|
|
37
|
+
/**
|
|
38
|
+
* A field's label at Large and Extra large (0.33, docs/text-size-harmonization.md
|
|
39
|
+
* §10.17): a static label ABOVE the field — the phone card's "label above value" (§4) —
|
|
40
|
+
* not a label squeezed into the field's top strip, where a long one ended in "…". It
|
|
41
|
+
* stops being absolute, so it wraps like any text (`truncate-until-large` beside it); it
|
|
42
|
+
* takes the pointer, since nothing of the field lies under it any more; and the field
|
|
43
|
+
* no longer reserves the strip for it (`FIELD_FLOATING_PAD`). In the first row of a box
|
|
44
|
+
* that is a grid at Large ({@link LABEL_ABOVE_BOX}), wherever it sits in the DOM — a
|
|
45
|
+
* floating label FOLLOWS its input, for `peer-*`. `large:` classes, so it costs no
|
|
46
|
+
* render and is right on the first paint; Normal keeps the floating label.
|
|
47
|
+
*
|
|
48
|
+
* The placement only: a label element adds `large:block` (a `<span>` or `<label>` in
|
|
49
|
+
* flow), a label ROW keeps its `flex`.
|
|
50
|
+
*/
|
|
51
|
+
export const LABEL_ABOVE_AT_LARGE =
|
|
52
|
+
"large:static large:row-start-1 large:mb-1 large:max-w-none large:pointer-events-auto";
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* The box a field's label is positioned in — {@link FloatingField}'s `relative` wrapper,
|
|
56
|
+
* a date or month picker's root — at Large, while it holds a label above
|
|
57
|
+
* ({@link LABEL_ABOVE_AT_LARGE}): one column, the label's row over the field's. The
|
|
58
|
+
* field's own absolute parts in the box (a chevron, a clear ×, a reveal toggle, a
|
|
59
|
+
* calculator) are placed in the second row, so their `top-1/2` and `inset-y-*` still
|
|
60
|
+
* measure the FIELD and not label and field together; the label's own elements carry
|
|
61
|
+
* `data-field-label` and stay in the first. Only on a box with a visible label: without
|
|
62
|
+
* one the second row would be empty.
|
|
63
|
+
*/
|
|
64
|
+
export const LABEL_ABOVE_BOX =
|
|
65
|
+
"large:grid large:grid-cols-[minmax(0,1fr)] large:[&>.absolute:not([data-field-label])]:row-start-2";
|
|
66
|
+
|
|
37
67
|
// A field that always has a value (select / dropdown trigger) keeps the label
|
|
38
|
-
// permanently in the floated position — small, in the top strip, value below.
|
|
68
|
+
// permanently in the floated position — small, in the top strip, value below. At Large,
|
|
69
|
+
// a label above the field (LABEL_ABOVE_AT_LARGE).
|
|
39
70
|
export const FLOATING_LABEL_STATIC = cn(
|
|
40
71
|
"pointer-events-none absolute start-3 top-1",
|
|
41
72
|
STATIC_LABEL_TYPE,
|
|
42
|
-
"max-w-[calc(100%-1.5rem)] truncate",
|
|
73
|
+
"max-w-[calc(100%-1.5rem)] truncate-until-large",
|
|
74
|
+
LABEL_ABOVE_AT_LARGE,
|
|
75
|
+
"large:block",
|
|
43
76
|
);
|
|
44
77
|
|
|
45
78
|
/**
|
|
@@ -53,7 +86,9 @@ export interface FieldLabelProps extends ComponentPropsWithoutRef<"span"> {
|
|
|
53
86
|
|
|
54
87
|
export function FieldLabel({ children, className, ...rest }: FieldLabelProps) {
|
|
55
88
|
return (
|
|
56
|
-
|
|
89
|
+
// `data-field-label`: a label of the box it stands in, kept in the first row at Large
|
|
90
|
+
// (LABEL_ABOVE_BOX).
|
|
91
|
+
<span data-field-label="" {...rest} className={cn(FLOATING_LABEL_STATIC, "z-10", className)}>
|
|
57
92
|
{children}
|
|
58
93
|
</span>
|
|
59
94
|
);
|
|
@@ -207,9 +242,10 @@ export function FieldCaption({ parts, className }: { parts: FieldHintParts; clas
|
|
|
207
242
|
* Classes that take a static floating label (`FLOATING_LABEL_STATIC`: `FieldLabel`,
|
|
208
243
|
* `ComboboxFieldLabel`) out of its own absolute slot and into a {@link StaticLabelRow}.
|
|
209
244
|
* `static` wins over `absolute` through `cn`'s merge; `min-w-0` lets it truncate in
|
|
210
|
-
* the row.
|
|
245
|
+
* the row. At Large the ROW stands above the field, so the label inside it drops the
|
|
246
|
+
* margin a label above takes alone (`large:mb-0`), and stays level with its "?".
|
|
211
247
|
*/
|
|
212
|
-
export const LABEL_IN_ROW = "static min-w-0";
|
|
248
|
+
export const LABEL_IN_ROW = "static min-w-0 large:mb-0";
|
|
213
249
|
|
|
214
250
|
/**
|
|
215
251
|
* A static label and its "?" on one line, in the top strip of a field that lays out its
|
|
@@ -222,7 +258,10 @@ export const LABEL_IN_ROW = "static min-w-0";
|
|
|
222
258
|
*/
|
|
223
259
|
export function StaticLabelRow({ hint, children }: { hint: ReactNode; children: ReactNode }) {
|
|
224
260
|
return (
|
|
225
|
-
<div
|
|
261
|
+
<div
|
|
262
|
+
data-field-label=""
|
|
263
|
+
className={cn("pointer-events-none absolute start-3 end-9 top-1 z-10 flex items-center gap-1", LABEL_ABOVE_AT_LARGE)}
|
|
264
|
+
>
|
|
226
265
|
{children}
|
|
227
266
|
<span className="pointer-events-auto flex shrink-0 items-center">{hint}</span>
|
|
228
267
|
</div>
|
|
@@ -270,7 +309,7 @@ export interface LockReason {
|
|
|
270
309
|
* switch, a checkbox or a select that saves on change, a list row whose click writes.
|
|
271
310
|
* The lock's reason wins over the control's own (`useCommitReason`).
|
|
272
311
|
*/
|
|
273
|
-
export function useLockReason(commit:
|
|
312
|
+
export function useLockReason(commit: CommitScope | undefined, disabledReason: ReactNode): LockReason {
|
|
274
313
|
const reason = useCommitReason(commit, disabledReason);
|
|
275
314
|
const reasonId = useId();
|
|
276
315
|
return { reason, locked: hasMessage(reason), reasonId };
|
|
@@ -510,9 +549,12 @@ export function FieldLabelLine({ label, hint }: { label: ReactNode; hint?: React
|
|
|
510
549
|
if (!hasContent(hint)) return <FieldLabel>{label}</FieldLabel>;
|
|
511
550
|
return (
|
|
512
551
|
// `z-10` as FieldLabel has it: the trigger after it is `relative` and would paint
|
|
513
|
-
// over the row (and take the "?"'s hover) otherwise.
|
|
514
|
-
<div
|
|
515
|
-
|
|
552
|
+
// over the row (and take the "?"'s hover) otherwise. Above the field at Large.
|
|
553
|
+
<div
|
|
554
|
+
data-field-label=""
|
|
555
|
+
className={cn("pointer-events-none absolute start-3 end-9 top-1 z-10 flex items-center gap-1", LABEL_ABOVE_AT_LARGE)}
|
|
556
|
+
>
|
|
557
|
+
<FieldLabel className={cn(LABEL_IN_ROW, "max-w-full")}>{label}</FieldLabel>
|
|
516
558
|
<span className="pointer-events-auto flex shrink-0 items-center">{hint}</span>
|
|
517
559
|
</div>
|
|
518
560
|
);
|
|
@@ -570,12 +612,17 @@ export function LabelStrip({
|
|
|
570
612
|
children: ReactNode;
|
|
571
613
|
}) {
|
|
572
614
|
return (
|
|
573
|
-
|
|
574
|
-
|
|
615
|
+
// At Large the row is a label above the group, in flow (0.33, §10.17), and the
|
|
616
|
+
// strip's padding goes: nothing lies under it any more.
|
|
617
|
+
<div {...rest} className={cn("relative min-w-0", LABEL_STRIP_PAD[pad], "large:pt-0", className)}>
|
|
618
|
+
<div
|
|
619
|
+
data-field-label=""
|
|
620
|
+
className={cn("pointer-events-none absolute inset-x-3 top-1 flex items-center gap-1", LABEL_ABOVE_AT_LARGE)}
|
|
621
|
+
>
|
|
575
622
|
{/* `static`: FieldLabel positions itself absolutely; here the ROW is
|
|
576
623
|
positioned, so the label and its "?" are centred on one line by the flex
|
|
577
624
|
layout (dev#468). */}
|
|
578
|
-
<FieldLabel id={labelId} className={cn("
|
|
625
|
+
<FieldLabel id={labelId} className={cn(LABEL_IN_ROW, "max-w-full", disabled && "opacity-50")}>
|
|
579
626
|
{label}
|
|
580
627
|
</FieldLabel>
|
|
581
628
|
{hasContent(hint) && <span className="pointer-events-auto flex shrink-0 items-center">{hint}</span>}
|