@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
|
@@ -7,8 +7,9 @@ import { useLargeText } from "../hooks/use-large-text";
|
|
|
7
7
|
import { useKitLabels } from "../i18n/kit-labels";
|
|
8
8
|
import { Popover } from "./popover";
|
|
9
9
|
import { Button, CompactControls, IconButton } from "./ui";
|
|
10
|
-
import { useCommitReason } from "./write-lock";
|
|
11
|
-
import type { IconButtonSize } from "./ui";
|
|
10
|
+
import { useCommitReason, type CommitScope } from "./write-lock";
|
|
11
|
+
import type { IconButtonGlyphSize, IconButtonSize } from "./ui";
|
|
12
|
+
import type { TooltipSide } from "./tooltip";
|
|
12
13
|
import type { DataTableColumn } from "./data-table";
|
|
13
14
|
|
|
14
15
|
/**
|
|
@@ -24,8 +25,17 @@ import type { DataTableColumn } from "./data-table";
|
|
|
24
25
|
*
|
|
25
26
|
* The data is the roster's `UserRowActionList`, generalised: entries, and `false` /
|
|
26
27
|
* `null` for the ones a condition left out (`row.locked || {…}`).
|
|
28
|
+
*
|
|
29
|
+
* 0.33 (§10.16): an action carries its state at both sizes — a toggle (`pressed`), a
|
|
30
|
+
* disclosure (`expanded`, `controls`), a tone, a tour anchor (`dataTour`) — so a row
|
|
31
|
+
* with an "on" share button or a tour step no longer keeps hand-rolled IconButtons at
|
|
32
|
+
* Normal and this only at Large (keksdose k15).
|
|
27
33
|
*/
|
|
28
34
|
|
|
35
|
+
/** An action's colour: IconButton's tone inline; in the menu the glyph takes it and the
|
|
36
|
+
* words keep the text colour, except `danger`, whose words are the danger text. */
|
|
37
|
+
export type RowActionTone = "default" | "muted" | "info" | "warning" | "danger";
|
|
38
|
+
|
|
29
39
|
/** One action of a row. */
|
|
30
40
|
export interface RowAction {
|
|
31
41
|
/** React key. Default: the label. */
|
|
@@ -57,9 +67,15 @@ export interface RowAction {
|
|
|
57
67
|
* without one is a small text button; in the menu it is the words alone.
|
|
58
68
|
*/
|
|
59
69
|
icon?: LucideIcon | ReactElement;
|
|
60
|
-
/**
|
|
61
|
-
*
|
|
62
|
-
|
|
70
|
+
/**
|
|
71
|
+
* `danger` for delete, revoke, erase: the quiet red of IconButton's `tone="danger"`
|
|
72
|
+
* inline, the danger text tone in the menu. `muted` (an open or add that should not
|
|
73
|
+
* compete), `info` (a notice-worthy, harmless action: keksdose's reconcile) and
|
|
74
|
+
* `warning` (a flag that wants attention): IconButton's tone inline; in the menu the
|
|
75
|
+
* glyph takes it and the words keep the text colour, so `muted` looks like `default`
|
|
76
|
+
* there (0.33).
|
|
77
|
+
*/
|
|
78
|
+
tone?: RowActionTone;
|
|
63
79
|
/** Why it is not available for this row. It stays listed, focusable, and says so — an
|
|
64
80
|
* action that silently vanished would leave the reader looking for it. */
|
|
65
81
|
disabledReason?: ReactNode;
|
|
@@ -68,7 +84,7 @@ export interface RowAction {
|
|
|
68
84
|
* {@link WriteLockProvider} it is refused with the lock's reason, as {@link Button}'s
|
|
69
85
|
* `commit` is, inline and in the menu alike. No provider, or an unlocked one: no effect.
|
|
70
86
|
*/
|
|
71
|
-
commit?:
|
|
87
|
+
commit?: CommitScope;
|
|
72
88
|
/**
|
|
73
89
|
* In flight — the request it started has not answered. Inline, the icon turns into
|
|
74
90
|
* IconButton's spinner (`pending`); collapsed, the "⋯" button does, since the menu
|
|
@@ -84,6 +100,33 @@ export interface RowAction {
|
|
|
84
100
|
disabled?: boolean;
|
|
85
101
|
/** Leave it out for this row. */
|
|
86
102
|
hidden?: boolean;
|
|
103
|
+
/**
|
|
104
|
+
* A toggle (0.33): `aria-pressed` and IconButton's "on" look inline, `aria-pressed` on
|
|
105
|
+
* the menu entry. Keep the label the same in both states ("Share budget"): the pressed
|
|
106
|
+
* state already says whether it is on. Not on an `href` action — a link is not a
|
|
107
|
+
* toggle — nor with `expanded`.
|
|
108
|
+
*/
|
|
109
|
+
pressed?: boolean;
|
|
110
|
+
/**
|
|
111
|
+
* Opens or closes something IN THE PAGE (0.33) — a share card under the row, an
|
|
112
|
+
* add-category row: `aria-expanded`, inline and on the menu entry. Not with `pressed`:
|
|
113
|
+
* a disclosure says open, not on. Not on an `href` action.
|
|
114
|
+
*/
|
|
115
|
+
expanded?: boolean;
|
|
116
|
+
/** The `id` of what `expanded` opens: `aria-controls`, inline and on the menu entry. */
|
|
117
|
+
controls?: string;
|
|
118
|
+
/**
|
|
119
|
+
* A tour anchor (0.33, §10.18): `data-tour` on ONE element per action at a time.
|
|
120
|
+
* Inline, on the action's own control (the IconButton, the small text button, the
|
|
121
|
+
* link). Collapsed, on an `aria-hidden` box laid over the "⋯" button — `[data-tour=x]`
|
|
122
|
+
* resolves to a box the size of the "⋯", whose `data-slot="row-actions"` box holds the
|
|
123
|
+
* button, two anchored actions in one row don't fight over one attribute, and a tap
|
|
124
|
+
* still reaches the button. Never on the entry in the open menu: the kit's tour takes
|
|
125
|
+
* the first visible match and the menu is portalled after the row, so a copy there
|
|
126
|
+
* would never be found, only make the selector match twice. The kit's name for it, as
|
|
127
|
+
* `AppShellNavItem.dataTour`.
|
|
128
|
+
*/
|
|
129
|
+
dataTour?: string;
|
|
87
130
|
}
|
|
88
131
|
|
|
89
132
|
/** What a row's actions may be: entries, and `false` / `null` / `undefined` for the ones
|
|
@@ -130,8 +173,14 @@ export interface RowActionsProps {
|
|
|
130
173
|
size?: RowActionsSize;
|
|
131
174
|
/** The menu's width. Default `"15rem"`, in rem so it grows with the words (§3.2). */
|
|
132
175
|
menuWidth?: `${number}rem`;
|
|
133
|
-
/** On the wrapper: the inline strip, or the "⋯" button
|
|
176
|
+
/** On the wrapper: the inline strip, or the box round the "⋯" button. */
|
|
134
177
|
className?: string;
|
|
178
|
+
/** The inline glyphs' size, IconButton's `glyphSize` — e.g. 14 in a dense header strip
|
|
179
|
+
* (keksdose's category group header). The "⋯" button keeps its box's own. */
|
|
180
|
+
glyphSize?: IconButtonGlyphSize;
|
|
181
|
+
/** The inline tooltips' side, IconButton's `tooltipSide` — `"start"` for a table's last
|
|
182
|
+
* column, so a bubble does not run off the row's end. Per row: every inline action. */
|
|
183
|
+
tooltipSide?: TooltipSide;
|
|
135
184
|
labels?: Partial<RowActionsLabels>;
|
|
136
185
|
}
|
|
137
186
|
|
|
@@ -147,6 +196,30 @@ function glyphOf(icon: RowAction["icon"]): ReactNode {
|
|
|
147
196
|
return <Icon />;
|
|
148
197
|
}
|
|
149
198
|
|
|
199
|
+
/** The menu glyph's tint per tone (0.33): the words keep the text colour, so the glyph
|
|
200
|
+
* carries `info` and `warning` — IconButton's toned colours. `danger` colours the words
|
|
201
|
+
* through Button's tone, and `muted` is the default look in a menu. */
|
|
202
|
+
const MENU_GLYPH_TONE: Partial<Record<RowActionTone, string>> = {
|
|
203
|
+
info: "text-info",
|
|
204
|
+
warning: "text-warning",
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
/** The state an action's control says, inline and in the menu alike: `aria-expanded` and
|
|
208
|
+
* `aria-controls` for a disclosure (a toggle's `aria-pressed` goes through the button's
|
|
209
|
+
* own `pressed`, which also draws the "on" look). */
|
|
210
|
+
function stateAttrs(action: RowAction) {
|
|
211
|
+
return {
|
|
212
|
+
"aria-expanded": action.expanded,
|
|
213
|
+
"aria-controls": action.expanded === undefined ? undefined : action.controls,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/** An action's tone on its inline control, for a caller's CSS and a test: `data-tone`,
|
|
218
|
+
* left off for the default look. */
|
|
219
|
+
function toneAttr(tone: RowActionTone | undefined) {
|
|
220
|
+
return { "data-tone": tone === undefined || tone === "default" ? undefined : tone };
|
|
221
|
+
}
|
|
222
|
+
|
|
150
223
|
/**
|
|
151
224
|
* A row's actions, inline or as a "⋯" menu — see {@link RowActionsCollapse}. Every
|
|
152
225
|
* control stops its click (and the Enter/Space it stands for) from reaching the row, so
|
|
@@ -170,6 +243,8 @@ export function RowActions({
|
|
|
170
243
|
size = "xs",
|
|
171
244
|
menuWidth = "15rem",
|
|
172
245
|
className,
|
|
246
|
+
glyphSize,
|
|
247
|
+
tooltipSide,
|
|
173
248
|
labels: labelsProp,
|
|
174
249
|
}: RowActionsProps) {
|
|
175
250
|
const labels = useKitLabels("rowActions", DEFAULT_ROW_ACTIONS_LABELS, labelsProp);
|
|
@@ -181,7 +256,13 @@ export function RowActions({
|
|
|
181
256
|
const strip = (
|
|
182
257
|
<div data-slot="row-actions" className={cn("inline-flex items-center gap-0.5", className)}>
|
|
183
258
|
{entries.map((action) => (
|
|
184
|
-
<InlineAction
|
|
259
|
+
<InlineAction
|
|
260
|
+
key={action.key ?? action.label}
|
|
261
|
+
action={action}
|
|
262
|
+
size={size}
|
|
263
|
+
glyphSize={glyphSize}
|
|
264
|
+
tooltipSide={tooltipSide}
|
|
265
|
+
/>
|
|
185
266
|
))}
|
|
186
267
|
</div>
|
|
187
268
|
);
|
|
@@ -192,48 +273,62 @@ export function RowActions({
|
|
|
192
273
|
const title = name ? labels.actionsFor(name) : labels.actions;
|
|
193
274
|
// The menu closed when the action was chosen, so what is in flight shows on "⋯".
|
|
194
275
|
const busy = entries.some((action) => action.pending);
|
|
276
|
+
const anchored = entries.filter((action) => action.dataTour);
|
|
195
277
|
return (
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
278
|
+
// The "⋯" in a box of its own, the inline strip's slot: the tour anchors of the
|
|
279
|
+
// collapsed actions lie over the button in it (see `dataTour`), and `className`
|
|
280
|
+
// places the box as it places the strip.
|
|
281
|
+
<div data-slot="row-actions" className={cn("relative inline-flex", className)}>
|
|
282
|
+
<Popover
|
|
283
|
+
width={menuWidth}
|
|
284
|
+
aria-label={title}
|
|
285
|
+
className="p-1"
|
|
286
|
+
trigger={({ open, toggle, ref }) => (
|
|
287
|
+
<IconButton
|
|
288
|
+
ref={ref}
|
|
289
|
+
size={size}
|
|
290
|
+
label={title}
|
|
291
|
+
// "⋯" is read by everyone as "more actions"; the menu it opens is the words.
|
|
292
|
+
labelVisible={false}
|
|
293
|
+
aria-haspopup="dialog"
|
|
294
|
+
aria-expanded={open}
|
|
295
|
+
pending={busy}
|
|
296
|
+
stopPropagation
|
|
297
|
+
onClick={toggle}
|
|
298
|
+
>
|
|
299
|
+
<MoreHorizontal />
|
|
300
|
+
</IconButton>
|
|
301
|
+
)}
|
|
302
|
+
// React carries an event out of a portal along the COMPONENT tree, so a click in
|
|
303
|
+
// the menu reached a clickable row or a DataTable `onRowClick` the menu was opened
|
|
304
|
+
// from, though the panel is nowhere near it in the page — only the "⋯" trigger
|
|
305
|
+
// stopped its own (keksdose's 0.32 report). Stopped on the PANEL itself, its padding
|
|
306
|
+
// and border included (0.32.2: 0.32.1 stopped it on an inner box, and a click on
|
|
307
|
+
// the panel's `p-1` still went through): clicks, and the Enter / Space a row also
|
|
308
|
+
// listens for. Escape goes on, to the popover's own handler that closes it.
|
|
309
|
+
onClick={stopClick}
|
|
310
|
+
onKeyDown={stopActivationKeys}
|
|
311
|
+
>
|
|
312
|
+
{(close) => (
|
|
313
|
+
<ul data-slot="row-actions-menu" className="space-y-0.5">
|
|
314
|
+
{entries.map((action) => (
|
|
315
|
+
<li key={action.key ?? action.label}>
|
|
316
|
+
<MenuAction action={action} close={close} />
|
|
317
|
+
</li>
|
|
318
|
+
))}
|
|
319
|
+
</ul>
|
|
320
|
+
)}
|
|
321
|
+
</Popover>
|
|
322
|
+
{anchored.map((action) => (
|
|
323
|
+
// The More cell's TourAnchor: decoration over the button, which keeps every tap.
|
|
324
|
+
<span
|
|
325
|
+
key={action.key ?? action.label}
|
|
326
|
+
aria-hidden
|
|
327
|
+
data-tour={action.dataTour}
|
|
328
|
+
className="pointer-events-none absolute inset-0"
|
|
329
|
+
/>
|
|
330
|
+
))}
|
|
331
|
+
</div>
|
|
237
332
|
);
|
|
238
333
|
}
|
|
239
334
|
|
|
@@ -261,10 +356,15 @@ function useActionHref(action: RowAction): string | undefined {
|
|
|
261
356
|
function MenuAction({ action, close }: { action: RowAction; close: () => void }) {
|
|
262
357
|
const href = useActionHref(action);
|
|
263
358
|
const glyph = glyphOf(action.icon);
|
|
359
|
+
const glyphTone = action.tone === undefined ? undefined : MENU_GLYPH_TONE[action.tone];
|
|
264
360
|
const words = (
|
|
265
361
|
<>
|
|
266
362
|
{glyph && (
|
|
267
|
-
<span
|
|
363
|
+
<span
|
|
364
|
+
aria-hidden
|
|
365
|
+
data-tone={glyphTone ? action.tone : undefined}
|
|
366
|
+
className={cn("flex shrink-0 [&_svg]:size-4", glyphTone)}
|
|
367
|
+
>
|
|
268
368
|
{glyph}
|
|
269
369
|
</span>
|
|
270
370
|
)}
|
|
@@ -295,11 +395,13 @@ function MenuAction({ action, close }: { action: RowAction; close: () => void })
|
|
|
295
395
|
}
|
|
296
396
|
return (
|
|
297
397
|
<Button
|
|
398
|
+
{...stateAttrs(action)}
|
|
298
399
|
type="button"
|
|
299
400
|
variant="ghost"
|
|
300
401
|
size="sm"
|
|
301
402
|
stretch
|
|
302
403
|
tone={tone}
|
|
404
|
+
pressed={action.pressed}
|
|
303
405
|
disabledReason={action.disabledReason}
|
|
304
406
|
commit={action.commit}
|
|
305
407
|
pending={action.pending}
|
|
@@ -313,20 +415,37 @@ function MenuAction({ action, close }: { action: RowAction; close: () => void })
|
|
|
313
415
|
}
|
|
314
416
|
|
|
315
417
|
/** One inline action: an IconButton with its icon, else a small text button — each a
|
|
316
|
-
* link for an `href` (see {@link useActionHref}).
|
|
317
|
-
|
|
418
|
+
* link for an `href` (see {@link useActionHref}). The control carries the action's
|
|
419
|
+
* state, its tone and its tour anchor. */
|
|
420
|
+
function InlineAction({
|
|
421
|
+
action,
|
|
422
|
+
size,
|
|
423
|
+
glyphSize,
|
|
424
|
+
tooltipSide,
|
|
425
|
+
}: {
|
|
426
|
+
action: RowAction;
|
|
427
|
+
size: RowActionsSize;
|
|
428
|
+
glyphSize?: IconButtonGlyphSize;
|
|
429
|
+
tooltipSide?: TooltipSide;
|
|
430
|
+
}) {
|
|
318
431
|
const href = useActionHref(action);
|
|
319
432
|
const glyph = glyphOf(action.icon);
|
|
320
|
-
const
|
|
433
|
+
const iconTone = action.tone === "default" ? undefined : action.tone;
|
|
434
|
+
// A text button has Button's two tones; `info` and `warning` are a glyph's colours.
|
|
435
|
+
const textTone = action.tone === "danger" || action.tone === "muted" ? action.tone : undefined;
|
|
436
|
+
const marks = { "data-tour": action.dataTour, ...toneAttr(action.tone) };
|
|
321
437
|
if (glyph) {
|
|
322
438
|
if (href !== undefined) {
|
|
323
439
|
return (
|
|
324
440
|
<IconButton
|
|
441
|
+
{...marks}
|
|
325
442
|
href={href}
|
|
326
443
|
external={action.external}
|
|
327
444
|
size={size}
|
|
445
|
+
glyphSize={glyphSize}
|
|
328
446
|
label={action.label}
|
|
329
|
-
|
|
447
|
+
tooltipSide={tooltipSide}
|
|
448
|
+
tone={iconTone}
|
|
330
449
|
disabled={action.disabled}
|
|
331
450
|
stopPropagation
|
|
332
451
|
onClick={() => action.onSelect?.()}
|
|
@@ -337,9 +456,14 @@ function InlineAction({ action, size }: { action: RowAction; size: RowActionsSiz
|
|
|
337
456
|
}
|
|
338
457
|
return (
|
|
339
458
|
<IconButton
|
|
459
|
+
{...marks}
|
|
460
|
+
{...stateAttrs(action)}
|
|
340
461
|
size={size}
|
|
462
|
+
glyphSize={glyphSize}
|
|
341
463
|
label={action.label}
|
|
342
|
-
|
|
464
|
+
tooltipSide={tooltipSide}
|
|
465
|
+
tone={iconTone}
|
|
466
|
+
pressed={action.pressed}
|
|
343
467
|
disabledReason={action.disabledReason}
|
|
344
468
|
commit={action.commit}
|
|
345
469
|
pending={action.pending}
|
|
@@ -363,17 +487,29 @@ function InlineAction({ action, size }: { action: RowAction; size: RowActionsSiz
|
|
|
363
487
|
};
|
|
364
488
|
if (href !== undefined) {
|
|
365
489
|
return (
|
|
366
|
-
<Button
|
|
490
|
+
<Button
|
|
491
|
+
{...marks}
|
|
492
|
+
href={href}
|
|
493
|
+
external={action.external}
|
|
494
|
+
variant="ghost"
|
|
495
|
+
size="sm"
|
|
496
|
+
tone={textTone}
|
|
497
|
+
disabled={action.disabled}
|
|
498
|
+
{...stop}
|
|
499
|
+
>
|
|
367
500
|
{action.label}
|
|
368
501
|
</Button>
|
|
369
502
|
);
|
|
370
503
|
}
|
|
371
504
|
return (
|
|
372
505
|
<Button
|
|
506
|
+
{...marks}
|
|
507
|
+
{...stateAttrs(action)}
|
|
373
508
|
type="button"
|
|
374
509
|
variant="ghost"
|
|
375
510
|
size="sm"
|
|
376
|
-
tone={
|
|
511
|
+
tone={textTone}
|
|
512
|
+
pressed={action.pressed}
|
|
377
513
|
disabledReason={action.disabledReason}
|
|
378
514
|
commit={action.commit}
|
|
379
515
|
pending={action.pending}
|
|
@@ -402,6 +538,10 @@ export interface RowActionsColumnOptions<T> {
|
|
|
402
538
|
collapse?: RowActionsCollapse;
|
|
403
539
|
/** Default `xs`. */
|
|
404
540
|
size?: RowActionsSize;
|
|
541
|
+
/** See {@link RowActionsProps.glyphSize}. */
|
|
542
|
+
glyphSize?: IconButtonGlyphSize;
|
|
543
|
+
/** See {@link RowActionsProps.tooltipSide} — `"start"` in a table's last column. */
|
|
544
|
+
tooltipSide?: TooltipSide;
|
|
405
545
|
/**
|
|
406
546
|
* The column's name as plain text — the column-settings checklist and the phone
|
|
407
547
|
* card's label read it (`DataTableColumn.headerText`). Pass the app's own word; left
|
|
@@ -432,6 +572,8 @@ export function rowActionsColumn<T>({
|
|
|
432
572
|
name,
|
|
433
573
|
collapse,
|
|
434
574
|
size,
|
|
575
|
+
glyphSize,
|
|
576
|
+
tooltipSide,
|
|
435
577
|
headerText,
|
|
436
578
|
labels,
|
|
437
579
|
column,
|
|
@@ -441,7 +583,15 @@ export function rowActionsColumn<T>({
|
|
|
441
583
|
header: <RowActionsHeader text={headerText} labels={labels} />,
|
|
442
584
|
headerText,
|
|
443
585
|
cell: (row) => (
|
|
444
|
-
<RowActions
|
|
586
|
+
<RowActions
|
|
587
|
+
actions={actions(row)}
|
|
588
|
+
name={name?.(row)}
|
|
589
|
+
collapse={collapse}
|
|
590
|
+
size={size}
|
|
591
|
+
glyphSize={glyphSize}
|
|
592
|
+
tooltipSide={tooltipSide}
|
|
593
|
+
labels={labels}
|
|
594
|
+
/>
|
|
445
595
|
),
|
|
446
596
|
className: "w-px whitespace-nowrap text-end",
|
|
447
597
|
headClassName: "w-px",
|
|
@@ -18,7 +18,8 @@ import { Caption, SectionLabel } from "./text";
|
|
|
18
18
|
import { ToggleGroup } from "./toggle-group";
|
|
19
19
|
import { Tooltip } from "./tooltip";
|
|
20
20
|
import { Button, Card, IconButton, Spinner } from "./ui";
|
|
21
|
-
import { useWriteLock } from "./write-lock";
|
|
21
|
+
import { COMMIT_EXCEPT_BILLING, useWriteLock } from "./write-lock";
|
|
22
|
+
import type { WriteLock } from "./write-lock";
|
|
22
23
|
import type { CardProps } from "./ui";
|
|
23
24
|
import type { DisabledReasonDisplay } from "./field-parts";
|
|
24
25
|
|
|
@@ -174,8 +175,11 @@ type MaybePromise = void | Promise<unknown>;
|
|
|
174
175
|
|
|
175
176
|
export interface SharePanelProps {
|
|
176
177
|
grantees: ShareGrantee[];
|
|
177
|
-
/** The role vocabulary, in display order
|
|
178
|
-
* row shows its
|
|
178
|
+
/** The role vocabulary, in display order, NARROWEST FIRST — viewer, then editor, as
|
|
179
|
+
* Kurvenschmiede lists them. One role: no choice is offered and each row shows its
|
|
180
|
+
* chip. The order is what tells a lowering from a raise under a write lock: a lapsed
|
|
181
|
+
* plan lets a grantee's role be lowered, which removes access, and never raised
|
|
182
|
+
* (docs/billing-harmonization.md decision 26 as amended, §12.36). */
|
|
179
183
|
roles: ShareRole[];
|
|
180
184
|
pending?: SharePendingGrant[];
|
|
181
185
|
/** Completions for the field. Left out: the field is a plain address field. */
|
|
@@ -244,6 +248,40 @@ function LockedRoleChoice({ reason, children }: { reason: ReactNode; children: R
|
|
|
244
248
|
return reason === undefined ? children : <Tooltip label={reason}>{children}</Tooltip>;
|
|
245
249
|
}
|
|
246
250
|
|
|
251
|
+
/** What a grantee's role choice may do under the write lock: `group` locks the whole
|
|
252
|
+
* choice with that reason; `raise` leaves it live for a lowering and refuses a raise
|
|
253
|
+
* with that reason. Neither: the choice is free. */
|
|
254
|
+
interface RoleChoiceLock {
|
|
255
|
+
group?: ReactNode;
|
|
256
|
+
raise?: ReactNode;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* A grantee's role choice under the write lock (decision 26 as amended,
|
|
261
|
+
* docs/billing-harmonization.md §12.36). `roles` is read narrowest first, so an option
|
|
262
|
+
* before the grantee's role LOWERS it: that removes access, which a lapsed plan allows
|
|
263
|
+
* (§12.13), so it sees the lock as `COMMIT_EXCEPT_BILLING` does (`removal`). An option
|
|
264
|
+
* after it RAISES it — a role grant, which every lock refuses (`every`), billing's with
|
|
265
|
+
* its own reason. Kurvenschmiede's server refuses exactly that: a widening while lapsed,
|
|
266
|
+
* not a narrowing (`shares_router.py:229-234`).
|
|
267
|
+
*
|
|
268
|
+
* A segmented choice is locked as a whole, so per grantee: under a demo's lock nothing
|
|
269
|
+
* moves; under billing's, a grantee at the narrowest role has only raises (locked), one
|
|
270
|
+
* at the widest only lowerings (live), and one in between keeps its lowerings while its
|
|
271
|
+
* raises are dimmed and refused. A role the vocabulary does not list cannot be told
|
|
272
|
+
* either way and stays locked.
|
|
273
|
+
*/
|
|
274
|
+
function roleChoiceLock(index: number, count: number, every: WriteLock, removal: WriteLock): RoleChoiceLock {
|
|
275
|
+
if (removal.locked) return { group: removal.reason };
|
|
276
|
+
if (!every.locked) return {};
|
|
277
|
+
if (index <= 0) return { group: every.reason };
|
|
278
|
+
return index < count - 1 ? { raise: every.reason } : {};
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/** The look of a raise refused while the lowerings beside it stay live — the dimmed
|
|
282
|
+
* segment of a locked group (ToggleGroup's `dimmed`), on that segment alone. */
|
|
283
|
+
const RAISE_REFUSED = "cursor-not-allowed opacity-50 hover:bg-transparent dark:hover:bg-transparent";
|
|
284
|
+
|
|
247
285
|
/**
|
|
248
286
|
* The body both forms share: the add form, then the list. Exported for an app that
|
|
249
287
|
* frames it itself (a settings section, a sheet).
|
|
@@ -272,8 +310,12 @@ export function SharePanel({
|
|
|
272
310
|
const labels = useKitLabels("shareCard", DEFAULT_SHARE_CARD_LABELS, labelsProp);
|
|
273
311
|
const confirm = useConfirm();
|
|
274
312
|
// Every commit below opts into the surrounding WriteLockProvider with `commit`; the
|
|
275
|
-
// role choices save on change, cannot take it, and read the lock themselves.
|
|
313
|
+
// role choices save on change, cannot take it, and read the lock themselves. Adding
|
|
314
|
+
// and raising a role see every lock (`lock`); removing access, withdrawing an
|
|
315
|
+
// invitation and lowering a role see it as a lapsed plan's lock allows them
|
|
316
|
+
// (`removal`, COMMIT_EXCEPT_BILLING; docs/billing-harmonization.md §12.13, §12.36).
|
|
276
317
|
const lock = useWriteLock();
|
|
318
|
+
const removal = useWriteLock(COMMIT_EXCEPT_BILLING);
|
|
277
319
|
const [email, setEmail] = useState("");
|
|
278
320
|
// A candidate taken from the completion. Typing again lets it go: the field then
|
|
279
321
|
// names an address again, and a chosen team beside free text would be two answers
|
|
@@ -454,6 +496,8 @@ export function SharePanel({
|
|
|
454
496
|
const editable = !readOnly && !g.locked;
|
|
455
497
|
const changeable = editable && onRoleChange !== undefined && choosable;
|
|
456
498
|
const key = `grantee:${g.id}`;
|
|
499
|
+
const rank = roles.findIndex((r) => r.key === g.role);
|
|
500
|
+
const roleLock = roleChoiceLock(rank, roles.length, lock, removal);
|
|
457
501
|
return (
|
|
458
502
|
<li key={key} className="space-y-1.5 py-2 first:pt-0 last:pb-0">
|
|
459
503
|
{/* Wraps rather than squeezes: on a phone the controls drop under
|
|
@@ -462,13 +506,13 @@ export function SharePanel({
|
|
|
462
506
|
<div className="min-w-0 flex-1 basis-40">
|
|
463
507
|
<div className="flex min-w-0 items-center gap-1.5 text-sm font-medium text-[var(--text-primary)]">
|
|
464
508
|
{g.kind === "team" && <UsersRound className="size-4 shrink-0" aria-hidden />}
|
|
465
|
-
<span data-private className="truncate">
|
|
509
|
+
<span data-private className="truncate-until-large">
|
|
466
510
|
{g.name}
|
|
467
511
|
</span>
|
|
468
512
|
{!changeable && <ShareRoleChip role={roleOf(g.role)} />}
|
|
469
513
|
</div>
|
|
470
514
|
{(g.kind === "team" || g.email) && (
|
|
471
|
-
<div data-private className="truncate text-xs text-[var(--text-muted)]">
|
|
515
|
+
<div data-private className="truncate-until-large text-xs text-[var(--text-muted)]">
|
|
472
516
|
{g.kind === "team" ? labels.team : g.email}
|
|
473
517
|
</div>
|
|
474
518
|
)}
|
|
@@ -476,15 +520,23 @@ export function SharePanel({
|
|
|
476
520
|
{(changeable || (editable && onRemove)) && (
|
|
477
521
|
<div className={ROW_CONTROLS}>
|
|
478
522
|
{changeable && (
|
|
479
|
-
<LockedRoleChoice reason={
|
|
523
|
+
<LockedRoleChoice reason={roleLock.group ?? roleLock.raise}>
|
|
480
524
|
<ToggleGroup<string>
|
|
481
525
|
size="sm"
|
|
482
526
|
aria-label={labels.roleOf(g.name)}
|
|
483
|
-
options={roles.map((r) => ({
|
|
527
|
+
options={roles.map((r, i) => ({
|
|
528
|
+
value: r.key,
|
|
529
|
+
label: r.label,
|
|
530
|
+
className: roleLock.raise !== undefined && i > rank ? RAISE_REFUSED : undefined,
|
|
531
|
+
}))}
|
|
484
532
|
value={g.role}
|
|
485
|
-
disabled={busy !== null ||
|
|
533
|
+
disabled={busy !== null || roleLock.group !== undefined}
|
|
486
534
|
onChange={(next) => {
|
|
487
|
-
if (next
|
|
535
|
+
if (next === g.role) return;
|
|
536
|
+
// A raise under a lock that allows only lowerings: refused,
|
|
537
|
+
// and the tooltip round the choice says why.
|
|
538
|
+
if (roleLock.raise !== undefined && roles.findIndex((r) => r.key === next) > rank) return;
|
|
539
|
+
void run(`role:${g.id}`, () => onRoleChange(g, next));
|
|
488
540
|
}}
|
|
489
541
|
/>
|
|
490
542
|
</LockedRoleChoice>
|
|
@@ -493,7 +545,8 @@ export function SharePanel({
|
|
|
493
545
|
<IconButton
|
|
494
546
|
tone="danger"
|
|
495
547
|
size="xs"
|
|
496
|
-
|
|
548
|
+
// Removing access: a lapsed plan allows it (§12.13).
|
|
549
|
+
commit={COMMIT_EXCEPT_BILLING}
|
|
497
550
|
label={labels.remove}
|
|
498
551
|
// The icon alone at every text size (§10.8): the row's one
|
|
499
552
|
// control beside its role toggle, where "Remove access" as
|
|
@@ -533,7 +586,7 @@ export function SharePanel({
|
|
|
533
586
|
<div
|
|
534
587
|
data-private={p.email ? true : undefined}
|
|
535
588
|
className={cn(
|
|
536
|
-
"truncate text-sm",
|
|
589
|
+
"truncate-until-large text-sm",
|
|
537
590
|
p.email ? "text-[var(--text-primary)]" : "text-[var(--text-muted)]",
|
|
538
591
|
)}
|
|
539
592
|
>
|
|
@@ -553,7 +606,8 @@ export function SharePanel({
|
|
|
553
606
|
<IconButton
|
|
554
607
|
tone="danger"
|
|
555
608
|
size="xs"
|
|
556
|
-
|
|
609
|
+
// Withdrawing an invitation removes access too (§12.13).
|
|
610
|
+
commit={COMMIT_EXCEPT_BILLING}
|
|
557
611
|
label={labels.revokePending}
|
|
558
612
|
// As the grantee's remove above: one action beside the
|
|
559
613
|
// copy icon (which is an icon at every size), and the
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ComponentPropsWithRef } from "react";
|
|
2
2
|
import { cn } from "../lib/cn";
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -14,7 +14,15 @@ export const SKELETON_CLASS = "animate-pulse rounded bg-[var(--bg-active)] motio
|
|
|
14
14
|
|
|
15
15
|
export type SkeletonShape = "line" | "block" | "circle";
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
/**
|
|
18
|
+
* A `div`'s props, `ref` included (0.33.1, keksdose): they were spread onto the
|
|
19
|
+
* placeholder all along, but `ComponentPropsWithoutRef` kept `ref` out of the type, so an
|
|
20
|
+
* app could not hold the element (to measure it, or scroll it into view) without a
|
|
21
|
+
* wrapper. The ref is the placeholder's — with `lines`, the box round the lines; with
|
|
22
|
+
* `label`, still the placeholder, not the `role="status"` region round it — where
|
|
23
|
+
* `className` goes too.
|
|
24
|
+
*/
|
|
25
|
+
export interface SkeletonProps extends Omit<ComponentPropsWithRef<"div">, "children"> {
|
|
18
26
|
/** `line` (default): a bar the height of a line of small text. `block`: an area
|
|
19
27
|
* (an image, a chart, a card body). `circle`: an avatar. Size any of them with
|
|
20
28
|
* `className` (`w-32`, `h-40`, `size-8`). */
|
|
@@ -75,13 +75,13 @@ const SIZE: Record<StatusDotSize, string> = { sm: "size-2", md: "size-2.5", lg:
|
|
|
75
75
|
* (`1lh`, the label's own line height, which the dot inherits) leaves around it.
|
|
76
76
|
* `large:` classes, so Normal keeps its one centred line.
|
|
77
77
|
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
78
|
+
* 0.33 (§10.17): the kit's one `truncate-until-large` (tokens.css) in place of this
|
|
79
|
+
* file's own `truncate` + `large:whitespace-normal large:break-words`. The utility breaks
|
|
80
|
+
* with `overflow-wrap: anywhere`, which lowers the label's min-content width: a legend in
|
|
81
|
+
* an auto-sized table column (the showcase's tone table at 360 px, Extra large) wants the
|
|
82
|
+
* column given a width, or it is squeezed to a letter per line.
|
|
83
83
|
*/
|
|
84
|
-
const
|
|
84
|
+
const LABEL_TRUNCATE = "truncate-until-large";
|
|
85
85
|
const DOT_ON_FIRST_LINE: Record<StatusDotSize, string> = {
|
|
86
86
|
sm: "large:mt-[calc((1lh_-_0.5rem)/2)]",
|
|
87
87
|
md: "large:mt-[calc((1lh_-_0.625rem)/2)]",
|
|
@@ -155,7 +155,7 @@ export function StatusDot({
|
|
|
155
155
|
// span is one ARIA forbids and screen readers ignore.
|
|
156
156
|
<span {...rest} className={cn("inline-flex min-w-0 items-center gap-1.5 text-sm large:items-start", className)}>
|
|
157
157
|
{dot}
|
|
158
|
-
<span className={cn("min-w-0
|
|
158
|
+
<span className={cn("min-w-0", LABEL_TRUNCATE)}>{label}</span>
|
|
159
159
|
</span>
|
|
160
160
|
);
|
|
161
161
|
}
|
|
@@ -5,7 +5,7 @@ import { useKitLabels } from "../i18n/kit-labels";
|
|
|
5
5
|
import { TILE_SIZE, TileRadioGroup } from "./tile-radio";
|
|
6
6
|
import type { TileItem, TileSize } from "./tile-radio";
|
|
7
7
|
import { Tooltip } from "./tooltip";
|
|
8
|
-
import { useCommitReason } from "./write-lock";
|
|
8
|
+
import { useCommitReason, type CommitScope } from "./write-lock";
|
|
9
9
|
import { hasContent, LabelStrip } from "./field-parts";
|
|
10
10
|
|
|
11
11
|
export interface SwatchPickerLabels {
|
|
@@ -115,7 +115,7 @@ export interface SwatchPickerProps<T extends string>
|
|
|
115
115
|
/** This picker COMMITS — choosing a colour saves it. Under a locked
|
|
116
116
|
* {@link WriteLockProvider} it takes the `disabledReason` path with the lock's
|
|
117
117
|
* reason, as {@link Button}'s `commit` does. */
|
|
118
|
-
commit?:
|
|
118
|
+
commit?: CommitScope;
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
/**
|