@eifi1/ui-kit 0.53.0 → 0.55.0
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 +96 -82
- package/dist/account/delete-account-setting.d.ts +3 -2
- package/dist/account/delete-account-setting.js.map +1 -1
- package/dist/admin/plan-change.js +2 -2
- package/dist/admin/plan-change.js.map +1 -1
- package/dist/admin/user-roster.d.ts +6 -0
- package/dist/admin/user-roster.js +4 -0
- package/dist/admin/user-roster.js.map +1 -1
- package/dist/auth/auth-errors.d.ts +36 -0
- package/dist/auth/auth-errors.js +20 -0
- package/dist/auth/auth-errors.js.map +1 -1
- package/dist/billing/billing-labels.d.ts +26 -0
- package/dist/billing/billing-labels.js +9 -0
- package/dist/billing/billing-labels.js.map +1 -1
- package/dist/billing/subscription-standing.d.ts +61 -0
- package/dist/billing/subscription-standing.js +51 -0
- package/dist/billing/subscription-standing.js.map +1 -0
- package/dist/billing/usage-meter.d.ts +52 -0
- package/dist/billing/usage-meter.js +52 -0
- package/dist/billing/usage-meter.js.map +1 -0
- package/dist/chart.d.ts +1 -0
- package/dist/chart.js +4 -0
- package/dist/chart.js.map +1 -1
- package/dist/components/alert-banner.js +2 -3
- package/dist/components/alert-banner.js.map +1 -1
- package/dist/components/amount-input.d.ts +2 -1
- package/dist/components/amount-input.js +3 -15
- package/dist/components/amount-input.js.map +1 -1
- package/dist/components/autocomplete.js +2 -2
- package/dist/components/autocomplete.js.map +1 -1
- package/dist/components/bulk-action-bar.js +2 -1
- package/dist/components/bulk-action-bar.js.map +1 -1
- package/dist/components/button.d.ts +35 -1
- package/dist/components/button.js +5 -9
- package/dist/components/button.js.map +1 -1
- package/dist/components/calendar-heatmap.js +6 -4
- package/dist/components/calendar-heatmap.js.map +1 -1
- package/dist/components/camera-button.d.ts +89 -0
- package/dist/components/camera-button.js +122 -0
- package/dist/components/camera-button.js.map +1 -0
- package/dist/components/camera-capture.d.ts +66 -0
- package/dist/components/camera-capture.js +190 -0
- package/dist/components/camera-capture.js.map +1 -0
- package/dist/components/camera-labels.d.ts +20 -0
- package/dist/components/camera-labels.js +15 -0
- package/dist/components/camera-labels.js.map +1 -0
- package/dist/components/chart-edge.d.ts +9 -0
- package/dist/components/chart-edge.js +14 -3
- package/dist/components/chart-edge.js.map +1 -1
- package/dist/components/chart-zoom-core.js +34 -29
- package/dist/components/chart-zoom-core.js.map +1 -1
- package/dist/components/checkbox-group.js +1 -1
- package/dist/components/checkbox-group.js.map +1 -1
- package/dist/components/combobox-core.js +3 -2
- package/dist/components/combobox-core.js.map +1 -1
- package/dist/components/combobox.js +2 -2
- package/dist/components/combobox.js.map +1 -1
- package/dist/components/consent-again-notice-labels.d.ts +25 -0
- package/dist/components/consent-again-notice-labels.js +15 -0
- package/dist/components/consent-again-notice-labels.js.map +1 -0
- package/dist/components/consent-again-notice.d.ts +85 -0
- package/dist/components/consent-again-notice.js +94 -0
- package/dist/components/consent-again-notice.js.map +1 -0
- package/dist/components/country-select.js +2 -7
- package/dist/components/country-select.js.map +1 -1
- package/dist/components/currency-option-list.d.ts +2 -1
- package/dist/components/currency-option-list.js +10 -3
- package/dist/components/currency-option-list.js.map +1 -1
- package/dist/components/currency-select.d.ts +3 -1
- package/dist/components/currency-select.js +2 -2
- package/dist/components/currency-select.js.map +1 -1
- package/dist/components/danger-confirm.d.ts +22 -1
- package/dist/components/danger-confirm.js +52 -30
- package/dist/components/danger-confirm.js.map +1 -1
- package/dist/components/data-table-column-settings.js +2 -2
- package/dist/components/data-table-column-settings.js.map +1 -1
- package/dist/components/data-table-filter-popover.d.ts +2 -1
- package/dist/components/data-table-filter-popover.js +3 -2
- package/dist/components/data-table-filter-popover.js.map +1 -1
- package/dist/components/data-table-filters.d.ts +33 -3
- package/dist/components/data-table-filters.js +6 -4
- package/dist/components/data-table-filters.js.map +1 -1
- package/dist/components/data-table-fit.js.map +1 -1
- package/dist/components/data-table-virtual.js +13 -3
- package/dist/components/data-table-virtual.js.map +1 -1
- package/dist/components/date-field.js +2 -2
- package/dist/components/date-field.js.map +1 -1
- package/dist/components/date-picker.js +2 -2
- package/dist/components/date-picker.js.map +1 -1
- package/dist/components/date-range-picker.js +2 -6
- package/dist/components/date-range-picker.js.map +1 -1
- package/dist/components/dialog-frame.d.ts +5 -1
- package/dist/components/dialog-frame.js +6 -2
- package/dist/components/dialog-frame.js.map +1 -1
- package/dist/components/dropdown.js +7 -3
- package/dist/components/dropdown.js.map +1 -1
- package/dist/components/entity-combobox.js +2 -2
- package/dist/components/entity-combobox.js.map +1 -1
- package/dist/components/field-parts.d.ts +108 -6
- package/dist/components/field-parts.js +59 -6
- package/dist/components/field-parts.js.map +1 -1
- package/dist/components/field-suggestion-labels.d.ts +2 -0
- package/dist/components/field-suggestion-labels.js +10 -0
- package/dist/components/field-suggestion-labels.js.map +1 -0
- package/dist/components/field.js +1 -1
- package/dist/components/field.js.map +1 -1
- package/dist/components/file-button.d.ts +1 -1
- package/dist/components/file-button.js.map +1 -1
- package/dist/components/floating-panel.d.ts +7 -6
- package/dist/components/floating-panel.js +3 -17
- package/dist/components/floating-panel.js.map +1 -1
- package/dist/components/form-actions.d.ts +3 -2
- package/dist/components/form-actions.js.map +1 -1
- package/dist/components/hover-menu.js +3 -2
- package/dist/components/hover-menu.js.map +1 -1
- package/dist/components/icon-button.d.ts +23 -5
- package/dist/components/icon-button.js +6 -8
- package/dist/components/icon-button.js.map +1 -1
- package/dist/components/inline-confirm.js +2 -1
- package/dist/components/inline-confirm.js.map +1 -1
- package/dist/components/inline-entity-combobox.js +2 -2
- package/dist/components/inline-entity-combobox.js.map +1 -1
- package/dist/components/input.js +2 -2
- package/dist/components/input.js.map +1 -1
- package/dist/components/jump-calendar.js +3 -3
- package/dist/components/jump-calendar.js.map +1 -1
- package/dist/components/legal.d.ts +13 -1
- package/dist/components/legal.js +12 -0
- package/dist/components/legal.js.map +1 -1
- package/dist/components/legended-series-chart.d.ts +80 -0
- package/dist/components/legended-series-chart.js +70 -0
- package/dist/components/legended-series-chart.js.map +1 -0
- package/dist/components/lightbox.js +2 -1
- package/dist/components/lightbox.js.map +1 -1
- package/dist/components/mini-calendar.js +16 -7
- package/dist/components/mini-calendar.js.map +1 -1
- package/dist/components/modal.d.ts +48 -0
- package/dist/components/modal.js +26 -6
- package/dist/components/modal.js.map +1 -1
- package/dist/components/month-picker.d.ts +1 -1
- package/dist/components/month-picker.js +6 -6
- package/dist/components/month-picker.js.map +1 -1
- package/dist/components/multi-entity-combobox.js +2 -2
- package/dist/components/multi-entity-combobox.js.map +1 -1
- package/dist/components/multi-select.js +2 -6
- package/dist/components/multi-select.js.map +1 -1
- package/dist/components/number-input.js +2 -2
- package/dist/components/number-input.js.map +1 -1
- package/dist/components/page-header-layout.d.ts +18 -0
- package/dist/components/page-header-layout.js +23 -0
- package/dist/components/page-header-layout.js.map +1 -0
- package/dist/components/page-header-skeleton.d.ts +41 -0
- package/dist/components/page-header-skeleton.js +52 -0
- package/dist/components/page-header-skeleton.js.map +1 -0
- package/dist/components/page-header.js +4 -17
- package/dist/components/page-header.js.map +1 -1
- package/dist/components/popover.js +7 -2
- package/dist/components/popover.js.map +1 -1
- package/dist/components/release-notes-labels.d.ts +16 -0
- package/dist/components/release-notes-labels.js +18 -0
- package/dist/components/release-notes-labels.js.map +1 -0
- package/dist/components/release-notes.d.ts +65 -0
- package/dist/components/release-notes.js +65 -0
- package/dist/components/release-notes.js.map +1 -0
- package/dist/components/select.js +2 -2
- package/dist/components/select.js.map +1 -1
- package/dist/components/series-chart-labels.d.ts +9 -0
- package/dist/components/series-chart-labels.js +3 -1
- package/dist/components/series-chart-labels.js.map +1 -1
- package/dist/components/series-chart.d.ts +5 -0
- package/dist/components/series-chart.js +89 -36
- package/dist/components/series-chart.js.map +1 -1
- package/dist/components/stat-tile.d.ts +21 -2
- package/dist/components/stat-tile.js +4 -2
- package/dist/components/stat-tile.js.map +1 -1
- package/dist/components/toggle-group.js +3 -2
- package/dist/components/toggle-group.js.map +1 -1
- package/dist/components/treemap-layout.js.map +1 -1
- package/dist/components/treemap.d.ts +17 -15
- package/dist/components/treemap.js +167 -85
- package/dist/components/treemap.js.map +1 -1
- package/dist/currencies.d.ts +16 -2
- package/dist/currencies.js +2 -1
- package/dist/currencies.js.map +1 -1
- package/dist/eslint/index.js +1 -1
- package/dist/eslint/role-utilities.d.ts +2 -2
- package/dist/eslint/role-utilities.js.map +1 -1
- package/dist/feedback/feedback-context-labels.js +2 -1
- package/dist/feedback/feedback-context-labels.js.map +1 -1
- package/dist/feedback/feedback-context.d.ts +19 -3
- package/dist/feedback/feedback-context.js +12 -1
- package/dist/feedback/feedback-context.js.map +1 -1
- package/dist/feedback/feedback-diagnostics.d.ts +17 -0
- package/dist/feedback/feedback-diagnostics.js +27 -0
- package/dist/feedback/feedback-diagnostics.js.map +1 -0
- package/dist/feedback/feedback-dialog.d.ts +10 -0
- package/dist/feedback/feedback-dialog.js +6 -4
- package/dist/feedback/feedback-dialog.js.map +1 -1
- package/dist/feedback/feedback-inbox-page.d.ts +260 -0
- package/dist/feedback/feedback-inbox-page.js +207 -0
- package/dist/feedback/feedback-inbox-page.js.map +1 -0
- package/dist/feedback/feedback-record.d.ts +5 -0
- package/dist/feedback/feedback-record.js.map +1 -1
- package/dist/feedback/feedback-row-detail-labels.js +1 -0
- package/dist/feedback/feedback-row-detail-labels.js.map +1 -1
- package/dist/feedback/feedback-row-detail.d.ts +3 -0
- package/dist/feedback/feedback-row-detail.js +3 -0
- package/dist/feedback/feedback-row-detail.js.map +1 -1
- package/dist/feedback/feedback-submit-dialog.d.ts +5 -1
- package/dist/feedback/feedback-submit-dialog.js +15 -3
- package/dist/feedback/feedback-submit-dialog.js.map +1 -1
- package/dist/feedback/feedback-submit.d.ts +30 -2
- package/dist/feedback/feedback-submit.js +5 -2
- package/dist/feedback/feedback-submit.js.map +1 -1
- package/dist/feedback/feedback-vocabulary.js +2 -2
- package/dist/feedback/feedback-vocabulary.js.map +1 -1
- package/dist/feedback.d.ts +1 -0
- package/dist/feedback.js +6 -0
- package/dist/feedback.js.map +1 -1
- package/dist/hooks/use-debounce.d.ts +32 -5
- package/dist/hooks/use-debounce.js +6 -5
- package/dist/hooks/use-debounce.js.map +1 -1
- package/dist/hooks/use-file-picker.d.ts +3 -1
- package/dist/hooks/use-file-picker.js.map +1 -1
- package/dist/hooks/use-focus-trap.d.ts +19 -3
- package/dist/hooks/use-focus-trap.js +15 -5
- package/dist/hooks/use-focus-trap.js.map +1 -1
- package/dist/hooks/use-has-camera.d.ts +36 -0
- package/dist/hooks/use-has-camera.js +53 -0
- package/dist/hooks/use-has-camera.js.map +1 -0
- package/dist/hooks/use-hotkey.js +2 -1
- package/dist/hooks/use-hotkey.js.map +1 -1
- package/dist/hooks/use-overlay-history.d.ts +6 -1
- package/dist/hooks/use-overlay-history.js +10 -2
- package/dist/hooks/use-overlay-history.js.map +1 -1
- package/dist/i18n/defaults.js +11 -1
- package/dist/i18n/defaults.js.map +1 -1
- package/dist/i18n/german.js +78 -4
- package/dist/i18n/german.js.map +1 -1
- package/dist/i18n/kit-labels.d.ts +20 -0
- package/dist/i18n/kit-labels.js.map +1 -1
- package/dist/i18n/locales/en.js +95 -5
- package/dist/i18n/locales/en.js.map +3 -3
- package/dist/i18n/locales/es.js +74 -4
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.js +75 -3
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hu.js +77 -4
- package/dist/i18n/locales/hu.js.map +1 -1
- package/dist/i18n/locales/it.js +77 -4
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/zh.js +74 -4
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/i18n/review.js +22 -1
- package/dist/i18n/review.js.map +1 -1
- package/dist/index.d.ts +27 -8
- package/dist/index.js +41 -2
- package/dist/index.js.map +1 -1
- package/dist/landing/landing-labels.d.ts +8 -0
- package/dist/landing/landing-labels.js +2 -1
- package/dist/landing/landing-labels.js.map +1 -1
- package/dist/lib/changelog.d.ts +130 -0
- package/dist/lib/changelog.js +137 -0
- package/dist/lib/changelog.js.map +1 -0
- package/dist/lib/clipboard-minus.js +2 -2
- package/dist/lib/clipboard-minus.js.map +1 -1
- package/dist/lib/dates.d.ts +36 -4
- package/dist/lib/dates.js +49 -13
- package/dist/lib/dates.js.map +1 -1
- package/dist/lib/editable-content.d.ts +33 -0
- package/dist/lib/editable-content.js +15 -0
- package/dist/lib/editable-content.js.map +1 -0
- package/dist/lib/focus-left.d.ts +47 -1
- package/dist/lib/focus-left.js +11 -2
- package/dist/lib/focus-left.js.map +1 -1
- package/dist/lib/format.d.ts +37 -2
- package/dist/lib/format.js +25 -1
- package/dist/lib/format.js.map +1 -1
- package/dist/lib/intl-cache.d.ts +4 -2
- package/dist/lib/intl-cache.js.map +1 -1
- package/dist/lib/server-wake.d.ts +49 -9
- package/dist/lib/server-wake.js +25 -14
- package/dist/lib/server-wake.js.map +1 -1
- package/dist/lib/session-refresh.d.ts +53 -0
- package/dist/lib/session-refresh.js +27 -1
- package/dist/lib/session-refresh.js.map +1 -1
- package/dist/lib/translation-review.d.ts +26 -0
- package/dist/lib/translation-review.js +14 -0
- package/dist/lib/translation-review.js.map +1 -1
- package/dist/rhf/fields.js +3 -3
- package/dist/rhf/fields.js.map +1 -1
- package/dist/shell/app-shell.d.ts +25 -1
- package/dist/shell/app-shell.js +3 -1
- package/dist/shell/app-shell.js.map +1 -1
- package/dist/shell/dev-menu.d.ts +3 -0
- package/dist/shell/dev-menu.js +4 -2
- package/dist/shell/dev-menu.js.map +1 -1
- package/dist/shell/held-changes-banner-labels.d.ts +23 -0
- package/dist/shell/held-changes-banner-labels.js +14 -0
- package/dist/shell/held-changes-banner-labels.js.map +1 -0
- package/dist/shell/held-changes-banner.d.ts +75 -0
- package/dist/shell/held-changes-banner.js +106 -0
- package/dist/shell/held-changes-banner.js.map +1 -0
- package/dist/shell/sync-status-indicator.d.ts +27 -12
- package/dist/shell/sync-status-indicator.js +13 -4
- package/dist/shell/sync-status-indicator.js.map +1 -1
- package/dist/shell/top-bar-parts-labels.d.ts +5 -0
- package/dist/shell/top-bar-parts-labels.js +3 -1
- package/dist/shell/top-bar-parts-labels.js.map +1 -1
- package/dist/shell.d.ts +2 -0
- package/dist/shell.js +3 -0
- package/dist/shell.js.map +1 -1
- package/dist/sync/engine.d.ts +11 -2
- package/dist/sync/engine.js +13 -5
- package/dist/sync/engine.js.map +1 -1
- package/dist/sync/hooks.d.ts +3 -2
- package/dist/sync/hooks.js +4 -2
- package/dist/sync/hooks.js.map +1 -1
- package/dist/testing/css-variables.generated.d.ts +2 -2
- package/dist/testing/css-variables.generated.js +1 -1
- package/dist/testing/css-variables.generated.js.map +1 -1
- package/dist/theme/chart-palette.d.ts +18 -0
- package/dist/theme/chart-palette.js +17 -1
- package/dist/theme/chart-palette.js.map +1 -1
- package/dist/theme/contrast-tokens.d.ts +3 -3
- package/dist/theme/contrast-tokens.js.map +1 -1
- package/dist/theme/contrast.d.ts +4 -4
- package/dist/theme/contrast.js.map +1 -1
- package/dist/tour/tour-overlay.js +2 -1
- package/dist/tour/tour-overlay.js.map +1 -1
- package/package.json +5 -9
- package/tokens.css +19 -54
- package/src/account/account-parts.ts +0 -47
- package/src/account/account-settings-labels.ts +0 -240
- package/src/account/account-settings.tsx +0 -698
- package/src/account/data-export-setting-labels.ts +0 -20
- package/src/account/data-export-setting.tsx +0 -200
- package/src/account/delete-account-setting-labels.ts +0 -33
- package/src/account/delete-account-setting.tsx +0 -341
- package/src/account/email-change-setting-labels.ts +0 -31
- package/src/account/email-change-setting.tsx +0 -443
- package/src/account/passkeys-setting.tsx +0 -445
- package/src/account/sessions-setting-labels.ts +0 -24
- package/src/account/sessions-setting.tsx +0 -283
- package/src/admin/admin-action-confirm-labels.ts +0 -19
- package/src/admin/admin-action-confirm.tsx +0 -509
- package/src/admin/admin-action-log-labels.ts +0 -83
- package/src/admin/admin-action-log.tsx +0 -464
- package/src/admin/admin-area-labels.ts +0 -114
- package/src/admin/admin-forbidden.tsx +0 -75
- package/src/admin/admin-overview.tsx +0 -258
- package/src/admin/admin-parts.ts +0 -68
- package/src/admin/admin-sections.tsx +0 -208
- package/src/admin/admin-tool-links.tsx +0 -90
- package/src/admin/invitations-panel-labels.ts +0 -31
- package/src/admin/invitations-panel.tsx +0 -516
- package/src/admin/mail-test-card-labels.ts +0 -19
- package/src/admin/mail-test-card.tsx +0 -189
- package/src/admin/plan-change-labels.ts +0 -5
- package/src/admin/plan-change.tsx +0 -474
- package/src/admin/reviewer-scope-editor-labels.ts +0 -16
- package/src/admin/reviewer-scope-editor.tsx +0 -224
- package/src/admin/role-select-labels.ts +0 -16
- package/src/admin/role-select.tsx +0 -282
- package/src/admin/transfer-ownership-dialog-labels.ts +0 -20
- package/src/admin/transfer-ownership-dialog.tsx +0 -162
- package/src/admin/user-roster-labels.ts +0 -17
- package/src/admin/user-roster.tsx +0 -559
- package/src/auth/accept-invitation-labels.ts +0 -21
- package/src/auth/accept-invitation.tsx +0 -210
- package/src/auth/auth-errors-labels.ts +0 -23
- package/src/auth/auth-errors.ts +0 -370
- package/src/auth/complete-name-dialog-labels.ts +0 -16
- package/src/auth/complete-name-dialog.tsx +0 -253
- package/src/auth/email-tag.ts +0 -75
- package/src/auth/forgot-password-form-labels.ts +0 -20
- package/src/auth/forgot-password-form.tsx +0 -221
- package/src/auth/form-rules.ts +0 -40
- package/src/auth/new-password-fields.tsx +0 -85
- package/src/auth/not-found-page-labels.ts +0 -12
- package/src/auth/not-found-page.tsx +0 -95
- package/src/auth/register-form-labels.ts +0 -31
- package/src/auth/register-form.tsx +0 -456
- package/src/auth/reset-password-form-labels.ts +0 -27
- package/src/auth/reset-password-form.tsx +0 -341
- package/src/auth/sign-in-form-labels.ts +0 -44
- package/src/auth/sign-in-form.tsx +0 -858
- package/src/auth/status-parts.tsx +0 -132
- package/src/auth/verify-email-labels.ts +0 -26
- package/src/auth/verify-email.tsx +0 -445
- package/src/billing/billing-banner.tsx +0 -258
- package/src/billing/billing-labels.ts +0 -381
- package/src/billing/billing-lock.ts +0 -108
- package/src/billing/billing-overview.ts +0 -157
- package/src/billing/billing-standing.ts +0 -80
- package/src/billing/cancel-request.ts +0 -97
- package/src/billing/cancel-subscription.tsx +0 -98
- package/src/billing/checkout-processing.ts +0 -394
- package/src/billing/checkout-return.ts +0 -90
- package/src/billing/pay-page.ts +0 -330
- package/src/billing/plan-card.tsx +0 -562
- package/src/billing/plan-change-labels.ts +0 -66
- package/src/billing/plan-limit-notice.tsx +0 -148
- package/src/billing/plan-limit-toast.tsx +0 -90
- package/src/billing/plan-limit.ts +0 -52
- package/src/billing/plan-price.ts +0 -98
- package/src/billing/plan-switch.tsx +0 -216
- package/src/billing/provider-page.ts +0 -84
- package/src/billing/subscription-actions.tsx +0 -247
- package/src/billing/subscription-status-chip.tsx +0 -95
- package/src/chart.ts +0 -103
- package/src/components/account-chips-labels.ts +0 -16
- package/src/components/account-chips.tsx +0 -474
- package/src/components/alert-banner.tsx +0 -670
- package/src/components/amount-input.tsx +0 -815
- package/src/components/appearance-labels.ts +0 -63
- package/src/components/authed-image-labels.ts +0 -11
- package/src/components/authed-image.tsx +0 -209
- package/src/components/autocomplete.tsx +0 -645
- package/src/components/breadcrumbs-labels.ts +0 -10
- package/src/components/breadcrumbs.tsx +0 -205
- package/src/components/bulk-action-bar-labels.ts +0 -11
- package/src/components/bulk-action-bar.tsx +0 -443
- package/src/components/button-group.tsx +0 -223
- package/src/components/button-look.ts +0 -256
- package/src/components/button.tsx +0 -339
- package/src/components/calculator.tsx +0 -341
- package/src/components/calendar-heatmap-labels.ts +0 -15
- package/src/components/calendar-heatmap.tsx +0 -594
- package/src/components/card.tsx +0 -377
- package/src/components/chart-edge.ts +0 -106
- package/src/components/chart-figure.tsx +0 -35
- package/src/components/chart-height.ts +0 -30
- package/src/components/chart-zoom-core.tsx +0 -627
- package/src/components/chart-zoom.tsx +0 -22
- package/src/components/chart.tsx +0 -554
- package/src/components/checkbox-group.tsx +0 -247
- package/src/components/checkbox.tsx +0 -346
- package/src/components/chip-input.tsx +0 -370
- package/src/components/chip-labels.ts +0 -13
- package/src/components/chip.tsx +0 -843
- package/src/components/choice-card.tsx +0 -544
- package/src/components/column-mapper-labels.ts +0 -38
- package/src/components/column-mapper.tsx +0 -655
- package/src/components/combobox-core.tsx +0 -1321
- package/src/components/combobox-suggestions.tsx +0 -131
- package/src/components/combobox.tsx +0 -716
- package/src/components/confirm-context.ts +0 -7
- package/src/components/confirm-dialog-labels.ts +0 -13
- package/src/components/confirm-dialog.tsx +0 -341
- package/src/components/copy-button-labels.ts +0 -13
- package/src/components/copy-button.tsx +0 -192
- package/src/components/country-select-labels.ts +0 -11
- package/src/components/country-select.tsx +0 -539
- package/src/components/currency-option-list.tsx +0 -180
- package/src/components/currency-select.tsx +0 -341
- package/src/components/danger-confirm-labels.ts +0 -20
- package/src/components/danger-confirm.tsx +0 -934
- package/src/components/data-table-cells.tsx +0 -118
- package/src/components/data-table-column-settings.tsx +0 -198
- package/src/components/data-table-filter-popover.tsx +0 -281
- package/src/components/data-table-filters.ts +0 -287
- package/src/components/data-table-fit.ts +0 -301
- package/src/components/data-table-groups.tsx +0 -288
- package/src/components/data-table-head.tsx +0 -280
- package/src/components/data-table-labels.ts +0 -198
- package/src/components/data-table-leading-row.tsx +0 -58
- package/src/components/data-table-mobile.tsx +0 -1117
- package/src/components/data-table-pagination.tsx +0 -202
- package/src/components/data-table-resize.ts +0 -188
- package/src/components/data-table-row-actions.tsx +0 -302
- package/src/components/data-table-row.tsx +0 -496
- package/src/components/data-table-selection.ts +0 -71
- package/src/components/data-table-shared.tsx +0 -287
- package/src/components/data-table-sort.ts +0 -163
- package/src/components/data-table-virtual.ts +0 -576
- package/src/components/data-table.tsx +0 -2598
- package/src/components/date-field.tsx +0 -684
- package/src/components/date-format-setting.tsx +0 -64
- package/src/components/date-picker.tsx +0 -404
- package/src/components/date-range-picker.tsx +0 -518
- package/src/components/description-list-labels.ts +0 -9
- package/src/components/description-list.tsx +0 -386
- package/src/components/dialog-frame-labels.ts +0 -7
- package/src/components/dialog-frame.tsx +0 -276
- package/src/components/disclosure.tsx +0 -476
- package/src/components/dropdown.tsx +0 -461
- package/src/components/empty-state.tsx +0 -136
- package/src/components/entity-combobox.tsx +0 -422
- package/src/components/error-boundary-labels.ts +0 -20
- package/src/components/error-boundary.tsx +0 -675
- package/src/components/facing-pair.ts +0 -93
- package/src/components/field-base-labels.ts +0 -20
- package/src/components/field-base.tsx +0 -656
- package/src/components/field-parts.tsx +0 -825
- package/src/components/field-strip.tsx +0 -129
- package/src/components/field.tsx +0 -206
- package/src/components/file-button.tsx +0 -295
- package/src/components/file-dropzone.tsx +0 -559
- package/src/components/floating-panel-labels.ts +0 -10
- package/src/components/floating-panel.tsx +0 -828
- package/src/components/focus-ring.ts +0 -16
- package/src/components/form-actions-labels.ts +0 -11
- package/src/components/form-actions.tsx +0 -578
- package/src/components/full-bleed-dialog.tsx +0 -294
- package/src/components/grouped-picker.tsx +0 -184
- package/src/components/help-popover.tsx +0 -117
- package/src/components/hover-menu.tsx +0 -343
- package/src/components/iban-input-labels.ts +0 -14
- package/src/components/iban-input.tsx +0 -236
- package/src/components/icon-button.tsx +0 -959
- package/src/components/icon-picker-labels.ts +0 -13
- package/src/components/icon-picker.tsx +0 -232
- package/src/components/image-grid-labels.ts +0 -11
- package/src/components/image-grid.tsx +0 -202
- package/src/components/inline-confirm.tsx +0 -116
- package/src/components/inline-edit-field-labels.ts +0 -11
- package/src/components/inline-edit-field.tsx +0 -552
- package/src/components/inline-entity-combobox.tsx +0 -849
- package/src/components/input.tsx +0 -394
- package/src/components/jump-calendar.tsx +0 -265
- package/src/components/language-select.tsx +0 -93
- package/src/components/legal-labels.ts +0 -105
- package/src/components/legal-page.tsx +0 -711
- package/src/components/legal.tsx +0 -668
- package/src/components/lightbox-labels.ts +0 -18
- package/src/components/lightbox.tsx +0 -399
- package/src/components/line-items-labels.ts +0 -14
- package/src/components/line-items.tsx +0 -602
- package/src/components/list-labels.ts +0 -12
- package/src/components/list.tsx +0 -870
- package/src/components/loading-state.tsx +0 -78
- package/src/components/measured-grid-labels.ts +0 -25
- package/src/components/measured-grid.tsx +0 -837
- package/src/components/menu-item.tsx +0 -241
- package/src/components/mini-calendar-labels.ts +0 -17
- package/src/components/mini-calendar.tsx +0 -789
- package/src/components/modal.tsx +0 -505
- package/src/components/money-draft.ts +0 -83
- package/src/components/money-field.tsx +0 -76
- package/src/components/month-grid.tsx +0 -229
- package/src/components/month-picker-labels.ts +0 -22
- package/src/components/month-picker.tsx +0 -1087
- package/src/components/multi-entity-combobox.tsx +0 -369
- package/src/components/multi-select.tsx +0 -376
- package/src/components/nav-pills.tsx +0 -198
- package/src/components/number-field.tsx +0 -327
- package/src/components/number-input.tsx +0 -558
- package/src/components/numeric-field.ts +0 -169
- package/src/components/numpad-sheet.tsx +0 -285
- package/src/components/one-time-code-input.tsx +0 -270
- package/src/components/page-contents-labels.ts +0 -9
- package/src/components/page-contents.tsx +0 -282
- package/src/components/page-header-context.ts +0 -8
- package/src/components/page-header.tsx +0 -298
- package/src/components/password-strength-labels.ts +0 -22
- package/src/components/password-strength.tsx +0 -241
- package/src/components/phone-input-labels.ts +0 -10
- package/src/components/phone-input.tsx +0 -282
- package/src/components/picker-sheet.tsx +0 -330
- package/src/components/pie-chart-labels.ts +0 -40
- package/src/components/pie-chart.tsx +0 -480
- package/src/components/popover-labels.ts +0 -14
- package/src/components/popover.tsx +0 -268
- package/src/components/progress-bar-labels.ts +0 -10
- package/src/components/progress-bar.tsx +0 -479
- package/src/components/qr-code.tsx +0 -76
- package/src/components/reauth-dialog-labels.ts +0 -13
- package/src/components/reauth-dialog.tsx +0 -265
- package/src/components/row-actions-labels.ts +0 -12
- package/src/components/row-actions.tsx +0 -795
- package/src/components/scroll-area.tsx +0 -123
- package/src/components/search-field.tsx +0 -192
- package/src/components/select.tsx +0 -294
- package/src/components/separator.tsx +0 -33
- package/src/components/series-chart-axes.ts +0 -342
- package/src/components/series-chart-budget.ts +0 -150
- package/src/components/series-chart-labels.ts +0 -33
- package/src/components/series-chart-thin.ts +0 -180
- package/src/components/series-chart-ticks.ts +0 -194
- package/src/components/series-chart.tsx +0 -1906
- package/src/components/server-wake-labels.ts +0 -11
- package/src/components/server-wake.tsx +0 -129
- package/src/components/settings-fields.tsx +0 -237
- package/src/components/share-card-labels.ts +0 -30
- package/src/components/share-card.tsx +0 -675
- package/src/components/signature-pad-labels.ts +0 -24
- package/src/components/signature-pad.tsx +0 -747
- package/src/components/signed-amount-labels.ts +0 -10
- package/src/components/signed-amount.tsx +0 -336
- package/src/components/skeleton.tsx +0 -80
- package/src/components/slider.tsx +0 -338
- package/src/components/sparkline-labels.ts +0 -14
- package/src/components/sparkline.tsx +0 -322
- package/src/components/spinner.tsx +0 -81
- package/src/components/stat-tile-labels.ts +0 -15
- package/src/components/stat-tile.tsx +0 -725
- package/src/components/status-dot.tsx +0 -170
- package/src/components/swatch-picker-labels.ts +0 -10
- package/src/components/swatch-picker.tsx +0 -283
- package/src/components/swipeable-row.tsx +0 -386
- package/src/components/switch.tsx +0 -273
- package/src/components/table-skeleton.tsx +0 -136
- package/src/components/table.tsx +0 -647
- package/src/components/tabs-labels.ts +0 -13
- package/src/components/tabs.tsx +0 -693
- package/src/components/text-link.tsx +0 -359
- package/src/components/text.tsx +0 -150
- package/src/components/textarea.tsx +0 -330
- package/src/components/tile-radio.tsx +0 -332
- package/src/components/time-input.tsx +0 -121
- package/src/components/toast-labels.ts +0 -12
- package/src/components/toast.tsx +0 -519
- package/src/components/toggle-group.tsx +0 -752
- package/src/components/toggle-legend.tsx +0 -394
- package/src/components/tooltip.tsx +0 -1149
- package/src/components/translation-review-editor.tsx +0 -290
- package/src/components/translation-review-labels.ts +0 -181
- package/src/components/translation-review-parts.tsx +0 -272
- package/src/components/translation-review.tsx +0 -1240
- package/src/components/tree-view.tsx +0 -589
- package/src/components/treemap-labels.ts +0 -47
- package/src/components/treemap-layout.ts +0 -210
- package/src/components/treemap.tsx +0 -1184
- package/src/components/trigger-aria.ts +0 -44
- package/src/components/use-anchor-dir.ts +0 -20
- package/src/components/use-mobile-reveal.ts +0 -62
- package/src/components/use-table-state.ts +0 -753
- package/src/components/user-avatar.tsx +0 -116
- package/src/components/wizard-stepper.tsx +0 -42
- package/src/components/write-lock-labels.ts +0 -10
- package/src/components/write-lock.tsx +0 -253
- package/src/currencies.ts +0 -70
- package/src/data-table.ts +0 -42
- package/src/demo/demo-banner.tsx +0 -153
- package/src/demo/demo-countdown.ts +0 -136
- package/src/demo/demo-ended.tsx +0 -90
- package/src/demo/demo-labels.ts +0 -78
- package/src/demo/demo-session.ts +0 -32
- package/src/demo/demo-start.tsx +0 -156
- package/src/eslint/index.ts +0 -161
- package/src/eslint/role-utilities.generated.ts +0 -146
- package/src/eslint/role-utilities.ts +0 -233
- package/src/feedback/feedback-attachment-download.tsx +0 -77
- package/src/feedback/feedback-attachment-labels.ts +0 -37
- package/src/feedback/feedback-attachment.tsx +0 -1239
- package/src/feedback/feedback-capture.ts +0 -287
- package/src/feedback/feedback-comment-thread.tsx +0 -353
- package/src/feedback/feedback-context-labels.ts +0 -10
- package/src/feedback/feedback-context.tsx +0 -213
- package/src/feedback/feedback-crash.ts +0 -547
- package/src/feedback/feedback-dialog-labels.ts +0 -29
- package/src/feedback/feedback-dialog.tsx +0 -440
- package/src/feedback/feedback-entry-file.tsx +0 -150
- package/src/feedback/feedback-inbox.tsx +0 -552
- package/src/feedback/feedback-labels.ts +0 -144
- package/src/feedback/feedback-menu-labels.ts +0 -12
- package/src/feedback/feedback-menu.tsx +0 -177
- package/src/feedback/feedback-mutation.ts +0 -20
- package/src/feedback/feedback-page-link.ts +0 -90
- package/src/feedback/feedback-public-labels.ts +0 -81
- package/src/feedback/feedback-public-list.tsx +0 -524
- package/src/feedback/feedback-public-switch.tsx +0 -102
- package/src/feedback/feedback-public-types.ts +0 -101
- package/src/feedback/feedback-record.ts +0 -423
- package/src/feedback/feedback-replies-context.ts +0 -9
- package/src/feedback/feedback-replies.tsx +0 -343
- package/src/feedback/feedback-rework-entry-chip.tsx +0 -18
- package/src/feedback/feedback-row-detail-labels.ts +0 -30
- package/src/feedback/feedback-row-detail.tsx +0 -858
- package/src/feedback/feedback-status-undo.ts +0 -109
- package/src/feedback/feedback-submit-dialog.tsx +0 -118
- package/src/feedback/feedback-submit.tsx +0 -237
- package/src/feedback/feedback-swipe.tsx +0 -192
- package/src/feedback/feedback-table-labels.ts +0 -27
- package/src/feedback/feedback-table.tsx +0 -912
- package/src/feedback/feedback-thread-labels.ts +0 -22
- package/src/feedback/feedback-thread-parts-labels.ts +0 -41
- package/src/feedback/feedback-thread.tsx +0 -905
- package/src/feedback/feedback-vocabulary.ts +0 -263
- package/src/feedback/feedback-vote-button.tsx +0 -124
- package/src/feedback.ts +0 -116
- package/src/hooks/use-anchored-panel.ts +0 -396
- package/src/hooks/use-anchored-rect.ts +0 -77
- package/src/hooks/use-announce.ts +0 -85
- package/src/hooks/use-authed-src.ts +0 -167
- package/src/hooks/use-body-scroll-lock.ts +0 -119
- package/src/hooks/use-breakpoint.ts +0 -133
- package/src/hooks/use-close-transition.ts +0 -107
- package/src/hooks/use-copy-to-clipboard.ts +0 -122
- package/src/hooks/use-debounce.ts +0 -114
- package/src/hooks/use-dismiss.ts +0 -371
- package/src/hooks/use-document-title.ts +0 -33
- package/src/hooks/use-file-drop.ts +0 -121
- package/src/hooks/use-file-picker-labels.ts +0 -28
- package/src/hooks/use-file-picker.tsx +0 -359
- package/src/hooks/use-focus-trap.ts +0 -199
- package/src/hooks/use-hotkey.ts +0 -189
- package/src/hooks/use-large-text.ts +0 -41
- package/src/hooks/use-long-press.ts +0 -140
- package/src/hooks/use-media-query.ts +0 -39
- package/src/hooks/use-mounted.ts +0 -39
- package/src/hooks/use-noindex.ts +0 -37
- package/src/hooks/use-overlay-history.ts +0 -714
- package/src/hooks/use-row-swipe.ts +0 -207
- package/src/hooks/use-search-param-state.ts +0 -434
- package/src/hooks/use-windowed-rows.ts +0 -225
- package/src/i18n/defaults.ts +0 -267
- package/src/i18n/german.ts +0 -2057
- package/src/i18n/kit-labels.tsx +0 -1003
- package/src/i18n/languages.ts +0 -349
- package/src/i18n/locales/de-CH.ts +0 -24
- package/src/i18n/locales/en.ts +0 -267
- package/src/i18n/locales/es.ts +0 -1997
- package/src/i18n/locales/fr.ts +0 -2035
- package/src/i18n/locales/hu.ts +0 -2002
- package/src/i18n/locales/it.ts +0 -2012
- package/src/i18n/locales/zh.ts +0 -1910
- package/src/i18n/plurals.ts +0 -86
- package/src/i18n/review.ts +0 -475
- package/src/i18n/shared-labels.ts +0 -138
- package/src/i18n/swiss.ts +0 -29
- package/src/index.ts +0 -1179
- package/src/landing/access.ts +0 -93
- package/src/landing/landing-actions.tsx +0 -97
- package/src/landing/landing-labels.ts +0 -59
- package/src/landing/landing-sections.tsx +0 -341
- package/src/landing/page-seo.ts +0 -261
- package/src/landing/public-header.tsx +0 -121
- package/src/landing/public-page.tsx +0 -106
- package/src/landing/routing.tsx +0 -225
- package/src/lib/broadcast.ts +0 -52
- package/src/lib/calc.ts +0 -323
- package/src/lib/chip-edge-snap.ts +0 -212
- package/src/lib/clipboard-minus.ts +0 -107
- package/src/lib/clipping.ts +0 -34
- package/src/lib/cn.ts +0 -28
- package/src/lib/column-mapping.ts +0 -234
- package/src/lib/countries.ts +0 -91
- package/src/lib/data-attributes.ts +0 -14
- package/src/lib/date-format.ts +0 -227
- package/src/lib/dates.ts +0 -266
- package/src/lib/day-format.ts +0 -96
- package/src/lib/decimal-marks.ts +0 -108
- package/src/lib/describe-failure.ts +0 -18
- package/src/lib/device-settings.ts +0 -147
- package/src/lib/direction.ts +0 -74
- package/src/lib/document-navigation.ts +0 -17
- package/src/lib/document-title.ts +0 -41
- package/src/lib/download.ts +0 -172
- package/src/lib/float-clearance.ts +0 -70
- package/src/lib/floating-stack.ts +0 -70
- package/src/lib/focus-left.ts +0 -156
- package/src/lib/format.ts +0 -522
- package/src/lib/http-status.ts +0 -38
- package/src/lib/iban.ts +0 -251
- package/src/lib/ime.ts +0 -24
- package/src/lib/intl-cache.ts +0 -25
- package/src/lib/iso-day.ts +0 -13
- package/src/lib/lazy-with-fallback.ts +0 -82
- package/src/lib/logger.ts +0 -69
- package/src/lib/minus.ts +0 -50
- package/src/lib/path-pattern.ts +0 -55
- package/src/lib/person-name.ts +0 -155
- package/src/lib/phone.ts +0 -208
- package/src/lib/plain-text.ts +0 -22
- package/src/lib/presence.ts +0 -18
- package/src/lib/qr-encode.ts +0 -444
- package/src/lib/quiet-focus.ts +0 -32
- package/src/lib/reduced-motion.ts +0 -22
- package/src/lib/refs.ts +0 -22
- package/src/lib/round.ts +0 -43
- package/src/lib/safe-storage.ts +0 -119
- package/src/lib/server-wake.ts +0 -315
- package/src/lib/session-refresh.ts +0 -472
- package/src/lib/share-format.ts +0 -18
- package/src/lib/status-tone.ts +0 -43
- package/src/lib/strip-fade.ts +0 -287
- package/src/lib/table-text.ts +0 -554
- package/src/lib/text-case.ts +0 -19
- package/src/lib/text-match.ts +0 -169
- package/src/lib/thenable.ts +0 -19
- package/src/lib/translation-review.ts +0 -717
- package/src/notifications/device-zone-report.ts +0 -67
- package/src/notifications/feedback-notification-types-labels.ts +0 -33
- package/src/notifications/feedback-notification-types.ts +0 -71
- package/src/notifications/notification-bell.tsx +0 -119
- package/src/notifications/notification-inbox.tsx +0 -309
- package/src/notifications/notification-parts.tsx +0 -81
- package/src/notifications/notification-types-setting.tsx +0 -406
- package/src/notifications/notification-types.ts +0 -89
- package/src/notifications/notifications-labels.ts +0 -287
- package/src/notifications/push-device-setting.tsx +0 -230
- package/src/notifications/push-devices-setting.tsx +0 -374
- package/src/notifications/push-worker.ts +0 -168
- package/src/notifications/quiet-hours-setting.tsx +0 -238
- package/src/notifications/unsubscribe-panel.tsx +0 -200
- package/src/notifications/use-push-device.ts +0 -448
- package/src/offline/local-first.ts +0 -100
- package/src/offline/pwa-update-prompt-labels.ts +0 -9
- package/src/offline/pwa-update-prompt.tsx +0 -78
- package/src/offline/query-persistence.ts +0 -391
- package/src/offline/service-worker-updates.ts +0 -81
- package/src/offline/shared-computer-labels.ts +0 -8
- package/src/offline/shared-computer.tsx +0 -87
- package/src/offline/sign-out-pending-dialog-labels.ts +0 -21
- package/src/offline/sign-out-pending-dialog.tsx +0 -135
- package/src/offline.ts +0 -37
- package/src/push-worker.ts +0 -25
- package/src/rhf/fields.tsx +0 -2187
- package/src/rhf/form-core.tsx +0 -324
- package/src/rhf/form.tsx +0 -12
- package/src/rhf/line-items.tsx +0 -135
- package/src/rhf/use-rhf-wizard-step.ts +0 -104
- package/src/rhf.ts +0 -21
- package/src/search/command-palette-labels.ts +0 -16
- package/src/search/command-palette.tsx +0 -624
- package/src/search/global-search-labels.ts +0 -13
- package/src/search/global-search.tsx +0 -660
- package/src/search/search-index.ts +0 -283
- package/src/search/use-command-key.ts +0 -23
- package/src/search.ts +0 -14
- package/src/settings/device-reset-setting-labels.ts +0 -20
- package/src/settings/device-reset-setting.tsx +0 -116
- package/src/settings/settings-card-classes.ts +0 -11
- package/src/settings/settings-catalogue.ts +0 -150
- package/src/settings/settings-context.ts +0 -33
- package/src/settings/settings-heading.tsx +0 -67
- package/src/settings/settings-labels.ts +0 -87
- package/src/settings/settings-layout.tsx +0 -471
- package/src/settings/settings-section.tsx +0 -108
- package/src/settings/use-account-appearance.ts +0 -148
- package/src/settings/use-account-language.ts +0 -146
- package/src/settings/use-settings-focus.ts +0 -128
- package/src/settings/use-settings-route.ts +0 -258
- package/src/shell/account-menu-language.tsx +0 -130
- package/src/shell/account-menu-text-size.tsx +0 -80
- package/src/shell/admin-menu.tsx +0 -183
- package/src/shell/app-shell-labels.ts +0 -11
- package/src/shell/app-shell.tsx +0 -1560
- package/src/shell/auth-layout.tsx +0 -186
- package/src/shell/company-switcher-labels.ts +0 -13
- package/src/shell/company-switcher.tsx +0 -136
- package/src/shell/dev-menu.tsx +0 -257
- package/src/shell/fill-height.tsx +0 -45
- package/src/shell/language-code.ts +0 -5
- package/src/shell/option-switcher-menu.tsx +0 -84
- package/src/shell/sync-status-indicator.tsx +0 -303
- package/src/shell/top-bar-actions.tsx +0 -87
- package/src/shell/top-bar-brand.tsx +0 -78
- package/src/shell/top-bar-parts-labels.ts +0 -148
- package/src/shell/top-bar.tsx +0 -40
- package/src/shell/topbar-action-menu.tsx +0 -567
- package/src/shell/topbar-controls.tsx +0 -269
- package/src/shell/tour-menu.tsx +0 -187
- package/src/shell.ts +0 -108
- package/src/sync/db.ts +0 -129
- package/src/sync/engine.ts +0 -1011
- package/src/sync/hooks.ts +0 -98
- package/src/sync/testing.ts +0 -73
- package/src/sync/wire.ts +0 -61
- package/src/sync.ts +0 -37
- package/src/table-text.ts +0 -8
- package/src/testing/css-variables.generated.ts +0 -112
- package/src/testing/css-variables.ts +0 -189
- package/src/testing/index.ts +0 -29
- package/src/testing/react.ts +0 -58
- package/src/testing/tour.ts +0 -41
- package/src/testing/viewport.ts +0 -357
- package/src/theme/chart-palette.ts +0 -232
- package/src/theme/color.ts +0 -272
- package/src/theme/contrast-tokens.ts +0 -268
- package/src/theme/contrast.ts +0 -250
- package/src/theme/palette-derive.ts +0 -825
- package/src/theme/palette-presets.ts +0 -544
- package/src/theme/palette-store.ts +0 -108
- package/src/theme/text-size.ts +0 -289
- package/src/theme/theme-store.ts +0 -157
- package/src/tour/tour-catalogue-labels.ts +0 -75
- package/src/tour/tour-catalogue.tsx +0 -335
- package/src/tour/tour-dock.ts +0 -134
- package/src/tour/tour-engine.ts +0 -37
- package/src/tour/tour-gates.ts +0 -218
- package/src/tour/tour-guide-button.tsx +0 -64
- package/src/tour/tour-guide-labels.ts +0 -15
- package/src/tour/tour-info.ts +0 -144
- package/src/tour/tour-labels.ts +0 -23
- package/src/tour/tour-overlay.tsx +0 -1170
- package/src/tour/tour.tsx +0 -750
- package/src/tour/use-tour-progress.ts +0 -671
- package/src/tour/use-tour-url-sync.ts +0 -266
- package/src/tour.ts +0 -21
- package/src/vite-env.d.ts +0 -23
- package/src/wizard/stepper-nav.tsx +0 -360
- package/src/wizard/types.ts +0 -275
- package/src/wizard/use-wizard.ts +0 -560
- package/src/wizard/validation.ts +0 -39
- package/src/wizard/wizard-context.tsx +0 -74
- package/src/wizard/wizard-labels.ts +0 -29
- package/src/wizard/wizard-step.tsx +0 -76
- package/src/wizard/wizard-summary.tsx +0 -84
- package/src/wizard.ts +0 -15
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import { type DataTableColumn, type DataTableProps } from "../components/data-table.js";
|
|
3
|
+
import type { CommitScope } from "../components/write-lock.js";
|
|
4
|
+
import type { AuthedFetcher } from "../hooks/use-authed-src.js";
|
|
5
|
+
import type { LabelOverride } from "../i18n/kit-labels.js";
|
|
6
|
+
import type { PathPattern } from "../landing/routing.js";
|
|
7
|
+
import type { FeedbackRecord } from "./feedback-record.js";
|
|
8
|
+
import { type FeedbackDetailPatch, type FeedbackRowDetailProps, type FeedbackUpload } from "./feedback-row-detail.js";
|
|
9
|
+
import { type FeedbackStatusChange } from "./feedback-status-undo.js";
|
|
10
|
+
import { type FeedbackSwipeBinding } from "./feedback-swipe.js";
|
|
11
|
+
import { type FeedbackPageLabels, type FeedbackRenderDate } from "./feedback-table.js";
|
|
12
|
+
import type { FeedbackStatus } from "./feedback-vocabulary.js";
|
|
13
|
+
/**
|
|
14
|
+
* The feedback inbox, ASSEMBLED ONCE (0.55; kastlan reuse audit 2026-11-02, proposal 2;
|
|
15
|
+
* docs/feedback-harmonization.md §13).
|
|
16
|
+
*
|
|
17
|
+
* Since 0.27 every part of `/feedback` and `/my-feedback` has been the kit's — the columns,
|
|
18
|
+
* the phone card and its day headers, the detail, the Undo, the swipes, the awaiting toggle
|
|
19
|
+
* (feedback-table.tsx, feedback-row-detail.tsx, feedback-swipe.tsx). What was not the kit's
|
|
20
|
+
* was the WIRING between them, and each app wrote the same ~150 lines of it:
|
|
21
|
+
* kastlan `frontend/src/features/feedback/pages/feedback-page.tsx:40-205`, keksdose
|
|
22
|
+
* `frontend/src/features/feedback/feedback-page.tsx:51-303`, Kurvenschmiede
|
|
23
|
+
* `frontend/src/features/feedback/feedback-page.tsx:88-245`. The open row in `?row=` with
|
|
24
|
+
* its numeric parse and its `rowHref`, `useFeedbackStatusUndo` over the page's PATCH, the
|
|
25
|
+
* `DataTable` with a dozen props, `FeedbackRowDetail` with a dozen more, the phone's
|
|
26
|
+
* grouping, card and swipe plan, the awaiting filter and its toggle. So every rename the
|
|
27
|
+
* parts took (0.52's `mutateAsync`, 0.53's removals) was made three times, and three
|
|
28
|
+
* times reviewed.
|
|
29
|
+
*
|
|
30
|
+
* Here that wiring is the kit's: {@link useFeedbackInbox} holds it and returns what the
|
|
31
|
+
* table, the detail and the phone cards need; {@link FeedbackInbox} draws the page from
|
|
32
|
+
* it. What stays the app's is what differs between the three, each a slot: where the rows
|
|
33
|
+
* come from and the three mutations (its API client, TanStack Query in all three — the kit
|
|
34
|
+
* sends no request), who may triage, the votes, the public switch, the comments (the app's
|
|
35
|
+
* `FeedbackCommentThread` over its own queries), its own columns, its swipe binding, its
|
|
36
|
+
* date writer, the page's header and frame, and whatever else `DataTable` takes.
|
|
37
|
+
*
|
|
38
|
+
* Additive: every part it is built from stays exported and unchanged, for a page that
|
|
39
|
+
* wants its own layout — call the hook and spread `inbox.table` into a `DataTable`.
|
|
40
|
+
*/
|
|
41
|
+
/**
|
|
42
|
+
* One of the page's mutations, as the inbox calls it: **TanStack Query's `useMutation`
|
|
43
|
+
* result, passed as it is** — `update={update}`. The inbox reads `mutateAsync` (whose
|
|
44
|
+
* promise settles for every call, refactor audit 2026-10-30 FLW-3) and `isPending`, and
|
|
45
|
+
* nothing else. Any object with those two fits, so a page on another data layer hands
|
|
46
|
+
* `{ mutateAsync: api.update, isPending }`.
|
|
47
|
+
*
|
|
48
|
+
* Taking the mutation rather than a callback per control is the point of the round: how
|
|
49
|
+
* the parts call it (0.52 moved them from `mutate` to `mutateAsync`) is then the kit's to
|
|
50
|
+
* change, once. Failure is the mutation's own: its `onError` toasts the server's sentence
|
|
51
|
+
* (§4.4), and the inbox catches the rejection.
|
|
52
|
+
*/
|
|
53
|
+
export interface FeedbackInboxMutation<V> {
|
|
54
|
+
mutateAsync: (variables: V) => Promise<unknown>;
|
|
55
|
+
/** In flight: the editors' and the composer's buttons wait for it. */
|
|
56
|
+
isPending?: boolean;
|
|
57
|
+
}
|
|
58
|
+
/** What the reply mutation is sent: `POST /feedback/{id}/replies` (§9.7, §12) — the
|
|
59
|
+
* body, the status picked (absent: "No change") and the uploaded file's URL (absent:
|
|
60
|
+
* none). Keys that carry nothing are left out, so a `mutationFn` may spread them onto
|
|
61
|
+
* the wire. kastlan's `useFeedbackReply` takes exactly this. */
|
|
62
|
+
export interface FeedbackReplyPost {
|
|
63
|
+
id: number;
|
|
64
|
+
body: string;
|
|
65
|
+
status?: FeedbackStatus;
|
|
66
|
+
attachmentUrl?: string;
|
|
67
|
+
}
|
|
68
|
+
/** What the rework mutation is sent: `POST /feedback/{id}/rework` (§10.3) — the author's
|
|
69
|
+
* trimmed note and the uploaded file's URL (absent: none). kastlan's `useFeedbackRework`
|
|
70
|
+
* takes exactly this. */
|
|
71
|
+
export interface FeedbackReworkPost {
|
|
72
|
+
id: number;
|
|
73
|
+
note: string;
|
|
74
|
+
attachmentUrl?: string;
|
|
75
|
+
}
|
|
76
|
+
export interface UseFeedbackInboxOptions<T extends FeedbackRecord> {
|
|
77
|
+
/** The list as the app's query answered it (`GET /feedback`, `GET /feedback/my`) —
|
|
78
|
+
* `list.data ?? []`. Shown newest first and, behind the awaiting toggle, narrowed. */
|
|
79
|
+
rows: readonly T[];
|
|
80
|
+
/** `/my-feedback`: the viewer's own reports — no triage there, for an admin too (§4.3). */
|
|
81
|
+
mine?: boolean;
|
|
82
|
+
/** The viewer may triage: the admin. Only on the inbox — `mine` wins — so `isAdmin`
|
|
83
|
+
* is enough. The status cell, the pills, the reply composer, the swipes, the submitter
|
|
84
|
+
* on the card and the awaiting toggle. */
|
|
85
|
+
canEdit: boolean;
|
|
86
|
+
/** The signed-in user's id: who the AUTHOR is (the description editor, Rework, the
|
|
87
|
+
* public switch's window). */
|
|
88
|
+
viewerId?: number | null;
|
|
89
|
+
/**
|
|
90
|
+
* `PATCH /feedback/{id}` (§3.4): every edit of the report itself — a status change from
|
|
91
|
+
* the cell, the pills or a swipe (with the Undo, `useFeedbackStatusUndo`), the
|
|
92
|
+
* description, the legacy rework append and, with {@link publicSwitch}, the flip. ONE
|
|
93
|
+
* mutation for all of them, the page's, so its observer outlives a row a status filter
|
|
94
|
+
* removes (§4.5).
|
|
95
|
+
*/
|
|
96
|
+
update: FeedbackInboxMutation<FeedbackDetailPatch>;
|
|
97
|
+
/** `POST /feedback/{id}/replies` — the admin's answer (§9.7) with its one file (§12).
|
|
98
|
+
* Without it no composer is drawn. */
|
|
99
|
+
reply?: FeedbackInboxMutation<FeedbackReplyPost>;
|
|
100
|
+
/** `POST /feedback/{id}/rework` — the author's rework entry (§10.3). Without it a rework
|
|
101
|
+
* goes through {@link update} as the legacy body append (§3.4). */
|
|
102
|
+
rework?: FeedbackInboxMutation<FeedbackReworkPost>;
|
|
103
|
+
/**
|
|
104
|
+
* The **Visible to others** switch in the detail (§9.3), its flip sent through
|
|
105
|
+
* {@link update} as `{ id, public }` — as keksdose and Kurvenschmiede send it. Off by
|
|
106
|
+
* default: an app without public parts (kastlan) has no switch.
|
|
107
|
+
*/
|
|
108
|
+
publicSwitch?: boolean;
|
|
109
|
+
/** The **Votes** column and the card's count (§9.6). Off by default (kastlan); keksdose
|
|
110
|
+
* always, Kurvenschmiede for a reader of the public parts. */
|
|
111
|
+
votes?: boolean;
|
|
112
|
+
/**
|
|
113
|
+
* The report's comments, in a section of their own under the replies (§9.8): the app's
|
|
114
|
+
* `FeedbackCommentThread` over its own queries — a component of its own, since its
|
|
115
|
+
* queries are hooks. Return `null` for a row without a thread (a CRASH, a reader who
|
|
116
|
+
* does not see the public parts; `false` is read as `null`). Called only for the open
|
|
117
|
+
* row.
|
|
118
|
+
*
|
|
119
|
+
* ```tsx
|
|
120
|
+
* comments={(row) => <RowComments id={row.id} isAdmin={isAdmin} canComment={!canEdit} />}
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
comments?: (row: T) => ReactNode;
|
|
124
|
+
/** The detail as drawn, to wrap or extend — kastlan's tour anchor:
|
|
125
|
+
* `(row, detail) => <div data-tour="feedback-row-detail">{detail}</div>`. */
|
|
126
|
+
renderDetail?: (row: T, detail: ReactNode) => ReactNode;
|
|
127
|
+
/**
|
|
128
|
+
* The app's own columns over the kit's (§4.3's nine, and Votes): add, drop, reorder —
|
|
129
|
+
* the keys are stable (`columns.filter((c) => c.key !== "email")`). A column brings its
|
|
130
|
+
* filter with it. Keep it stable (module scope or `useCallback`): it is a memo's
|
|
131
|
+
* dependency.
|
|
132
|
+
*/
|
|
133
|
+
columns?: (columns: readonly DataTableColumn<T>[]) => readonly DataTableColumn<T>[];
|
|
134
|
+
/** Which swipe does what on the phone (§4.5) — keksdose's Settings → Interaction binding,
|
|
135
|
+
* `{ end: prefs.right, start: prefs.left }`. Default `DEFAULT_FEEDBACK_SWIPE`. */
|
|
136
|
+
swipe?: FeedbackSwipeBinding;
|
|
137
|
+
/** The status writes the TABLE offers — the status cell and the desktop's actions
|
|
138
|
+
* column — commit: under a locked `WriteLockProvider` they stay and say why
|
|
139
|
+
* (`FeedbackStatusTransitions`' `commit`). Off by default. The detail's own saves:
|
|
140
|
+
* `detail={{ commit }}`. */
|
|
141
|
+
commit?: CommitScope;
|
|
142
|
+
/** `POST /feedback/attachments` (§3.3): the rework's file and the reply's. */
|
|
143
|
+
onUpload?: FeedbackUpload;
|
|
144
|
+
/** The app's authenticated GET for the pictures and the downloads (§3.5). */
|
|
145
|
+
fetcher?: AuthedFetcher | null;
|
|
146
|
+
/** "Capture screenshot" beside the rework's and the reply's file field. Default: the
|
|
147
|
+
* kit's `captureAppScreenshot()`; `null` for no button. */
|
|
148
|
+
onCaptureScreenshot?: (() => Promise<File | null>) | null;
|
|
149
|
+
/**
|
|
150
|
+
* The app's date writer (keksdose's `useDateCell()`, the date-format setting): the date
|
|
151
|
+
* and resolved columns, the card, the phone's day headers AND the detail's "Resolved:",
|
|
152
|
+
* so all five say the same. Left out, the kit's date with the weekday in the table and
|
|
153
|
+
* on the phone, and in the detail its sentence date — as the parts draw them alone.
|
|
154
|
+
*/
|
|
155
|
+
renderDate?: FeedbackRenderDate;
|
|
156
|
+
/** The app's one-shot routes, on top of the kit's (0.52, FLW-7) — for the URL column and
|
|
157
|
+
* the detail's URL section alike. Keep it stable (module scope). */
|
|
158
|
+
pageLinkExclude?: readonly PathPattern[];
|
|
159
|
+
/** The list is still loading (`list.isPending`): the table says "Loading…" where its
|
|
160
|
+
* rows will be, not "None". */
|
|
161
|
+
loading?: boolean;
|
|
162
|
+
/** Over the detail's props the inbox sets — `commit`, `showSubject`,
|
|
163
|
+
* `reworkAttachment`, `replyAttachments` (on here), `labels`, `className`. Merged last,
|
|
164
|
+
* so it wins. */
|
|
165
|
+
detail?: Partial<Omit<FeedbackRowDetailProps, "row">>;
|
|
166
|
+
/** Over the `feedbackPage` namespace: the columns, the card, the empty state, the toggle
|
|
167
|
+
* and the title. Keep it stable: it is a memo's dependency. */
|
|
168
|
+
labels?: LabelOverride<FeedbackPageLabels>;
|
|
169
|
+
}
|
|
170
|
+
/** What {@link useFeedbackInbox} returns: the state, and the props of the parts. */
|
|
171
|
+
export interface FeedbackInboxState<T extends FeedbackRecord> {
|
|
172
|
+
/** `canEdit && !mine`: the admin on the inbox. */
|
|
173
|
+
editable: boolean;
|
|
174
|
+
/** The page's title, `feedbackPage.title` — or `.myTitle` on `/my-feedback`. */
|
|
175
|
+
title: string;
|
|
176
|
+
/** The open row's id, from `?row=`; `null` when none is open or the param named no
|
|
177
|
+
* id (`?row=abc`, `?row=1.5`, `?row=0`). */
|
|
178
|
+
openId: number | null;
|
|
179
|
+
/** Open a row by its id, or close it with `null`: rewrites `?row=`, replacing the
|
|
180
|
+
* history entry rather than stacking one per report looked at. */
|
|
181
|
+
setOpenId: (id: number | null) => void;
|
|
182
|
+
/** A row's own address: this view — the table's page, sort and filters — with the row
|
|
183
|
+
* open. The row's link (a new tab, a copied address); a plain click opens it in place. */
|
|
184
|
+
rowHref: (row: T) => string;
|
|
185
|
+
/** The undoable status change (§4.5): the status cell's, the pills', the swipes'. */
|
|
186
|
+
changeStatus: FeedbackStatusChange;
|
|
187
|
+
/** The phone's "Only what is waiting for you" — page state, not the URL (§4.3). */
|
|
188
|
+
awaiting: boolean;
|
|
189
|
+
setAwaiting: (next: boolean) => void;
|
|
190
|
+
/** The one date writer the columns, the card and the day headers use. */
|
|
191
|
+
renderDate: FeedbackRenderDate;
|
|
192
|
+
/** `FeedbackRowDetail`'s props for a row, slots included. */
|
|
193
|
+
detailProps: (row: T) => FeedbackRowDetailProps;
|
|
194
|
+
/** `DataTable`'s props, ready to spread: the rows (newest first, narrowed by
|
|
195
|
+
* `awaiting`), the columns, the open row, the detail, the phone's card, day headers and
|
|
196
|
+
* swipes, the desktop's actions column, the empty state, `urlSync`,
|
|
197
|
+
* `storageKey="feedback"`, `fillHeight`. */
|
|
198
|
+
table: DataTableProps<T>;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* The inbox's wiring, once (§13): from the app's rows and mutations to what the table,
|
|
202
|
+
* the detail and the phone cards take.
|
|
203
|
+
*
|
|
204
|
+
* ```tsx
|
|
205
|
+
* const list = useQuery({ queryKey: keys.feedback.all, queryFn: api.listFeedback });
|
|
206
|
+
* const update = useMutation({ mutationFn: ({ id, ...patch }: FeedbackDetailPatch) => api.update(id, patch), … });
|
|
207
|
+
* const inbox = useFeedbackInbox({ rows: list.data ?? [], canEdit: isAdmin, viewerId: user?.id, update });
|
|
208
|
+
* <DataTable {...inbox.table} edgeFade />
|
|
209
|
+
* ```
|
|
210
|
+
*
|
|
211
|
+
* {@link FeedbackInbox} is this hook drawn — use the hook alone for a layout of your own.
|
|
212
|
+
* Needs a react-router Router (`?row=`, `urlSync`).
|
|
213
|
+
*/
|
|
214
|
+
export declare function useFeedbackInbox<T extends FeedbackRecord>({ rows, mine, canEdit, viewerId, update, reply, rework, publicSwitch, votes, comments, renderDetail, columns: ownColumns, swipe, commit, onUpload, fetcher, onCaptureScreenshot, renderDate: renderDateProp, pageLinkExclude, loading, detail, labels, }: UseFeedbackInboxOptions<T>): FeedbackInboxState<T>;
|
|
215
|
+
export interface FeedbackInboxProps<T extends FeedbackRecord> extends UseFeedbackInboxOptions<T> {
|
|
216
|
+
/**
|
|
217
|
+
* Above the table. Default: `<PageHeader title={title} className="mb-4 md:shrink-0" />`.
|
|
218
|
+
* A function gets the page's title (`feedbackPage.title` / `.myTitle`) — the app's own
|
|
219
|
+
* header: `(title) => <PageHeader size="compact" title={title} data-tour="feedback-header" />`.
|
|
220
|
+
* `null` for none.
|
|
221
|
+
*/
|
|
222
|
+
header?: ReactNode | ((title: string) => ReactNode);
|
|
223
|
+
/** Over the inbox's `DataTable` props — `edgeFade`, `locale`, `mobileExpandAsDialog`,
|
|
224
|
+
* `className`, another `storageKey`. Merged last, so it wins. */
|
|
225
|
+
table?: Partial<DataTableProps<T>>;
|
|
226
|
+
/** Further `FloatingAction`s on the phone: after the awaiting toggle on the inbox, in a
|
|
227
|
+
* group of their own on `/my-feedback`. */
|
|
228
|
+
phoneActions?: ReactNode;
|
|
229
|
+
/** On the page's frame — the fill-height column (`FILL_HEIGHT_CLASS`); the app's page
|
|
230
|
+
* padding goes here. */
|
|
231
|
+
className?: string;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* The feedback inbox (§13): `/feedback` and `/my-feedback` drawn whole from
|
|
235
|
+
* {@link useFeedbackInbox} — the header, the table with its detail, phone cards and swipes,
|
|
236
|
+
* and the phone's awaiting toggle, in the fill-height frame (page layout §1.3) — so a page
|
|
237
|
+
* is its queries and this:
|
|
238
|
+
*
|
|
239
|
+
* ```tsx
|
|
240
|
+
* export function FeedbackPage({ mine = false }: { mine?: boolean }) {
|
|
241
|
+
* const { user, isAdmin } = useAuth();
|
|
242
|
+
* const list = useQuery({ queryKey: mine ? keys.mine : keys.all, queryFn: mine ? api.mine : api.all });
|
|
243
|
+
* const update = useFeedbackUpdate();
|
|
244
|
+
* const reply = useFeedbackReply();
|
|
245
|
+
* const rework = useFeedbackRework();
|
|
246
|
+
* if (!mine && !isAdmin) return <Navigate to="/my-feedback" replace />;
|
|
247
|
+
* return (
|
|
248
|
+
* <FeedbackInbox
|
|
249
|
+
* rows={list.data ?? []} loading={list.isPending} mine={mine} canEdit={isAdmin} viewerId={user?.id}
|
|
250
|
+
* update={update} reply={reply} rework={rework}
|
|
251
|
+
* onUpload={api.upload} fetcher={api.file}
|
|
252
|
+
* />
|
|
253
|
+
* );
|
|
254
|
+
* }
|
|
255
|
+
* ```
|
|
256
|
+
*
|
|
257
|
+
* Every slot is {@link UseFeedbackInboxOptions}' or one of the four below. The redirect of
|
|
258
|
+
* a non-admin, the routes and the queries stay the app's.
|
|
259
|
+
*/
|
|
260
|
+
export declare function FeedbackInbox<T extends FeedbackRecord>({ header, table, phoneActions, className, ...options }: FeedbackInboxProps<T>): import("react").JSX.Element;
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useCallback, useMemo, useState } from "react";
|
|
4
|
+
import { useHref, useLocation } from "react-router";
|
|
5
|
+
import { cn } from "../lib/cn.js";
|
|
6
|
+
import { DataTable } from "../components/data-table.js";
|
|
7
|
+
import { FloatingActionGroup } from "../components/floating-panel.js";
|
|
8
|
+
import { LoadingState } from "../components/loading-state.js";
|
|
9
|
+
import { PageHeader } from "../components/page-header.js";
|
|
10
|
+
import { useSearchParamState } from "../hooks/use-search-param-state.js";
|
|
11
|
+
import { FILL_HEIGHT_CLASS } from "../shell/fill-height.js";
|
|
12
|
+
import { captureAppScreenshot } from "./feedback-capture.js";
|
|
13
|
+
import { useFeedbackStatusLabels } from "./feedback-labels.js";
|
|
14
|
+
import { runMutation } from "./feedback-mutation.js";
|
|
15
|
+
import {
|
|
16
|
+
FeedbackRowDetail
|
|
17
|
+
} from "./feedback-row-detail.js";
|
|
18
|
+
import { useFeedbackStatusUndo } from "./feedback-status-undo.js";
|
|
19
|
+
import {
|
|
20
|
+
DEFAULT_FEEDBACK_SWIPE,
|
|
21
|
+
feedbackSwipeOmitShown,
|
|
22
|
+
feedbackSwipePlan
|
|
23
|
+
} from "./feedback-swipe.js";
|
|
24
|
+
import {
|
|
25
|
+
FeedbackAwaitingToggle,
|
|
26
|
+
FeedbackEmptyState,
|
|
27
|
+
FeedbackMobileCard,
|
|
28
|
+
feedbackMobileGroupBy,
|
|
29
|
+
isFeedbackAwaiting,
|
|
30
|
+
useFeedbackColumns,
|
|
31
|
+
useFeedbackPageLabels,
|
|
32
|
+
useFeedbackRenderDate
|
|
33
|
+
} from "./feedback-table.js";
|
|
34
|
+
function parseRowId(raw) {
|
|
35
|
+
if (!/^[1-9]\d*$/.test(raw)) return void 0;
|
|
36
|
+
const id = Number(raw);
|
|
37
|
+
return Number.isSafeInteger(id) ? id : void 0;
|
|
38
|
+
}
|
|
39
|
+
const ROW_PARAM = { parse: parseRowId, history: "replace" };
|
|
40
|
+
const newestFirst = (a, b) => a.created_at < b.created_at ? 1 : a.created_at > b.created_at ? -1 : 0;
|
|
41
|
+
const rowId = (row) => row.id;
|
|
42
|
+
const rowTitle = (row) => row.title;
|
|
43
|
+
const captureScreenshot = () => captureAppScreenshot();
|
|
44
|
+
const ignore = () => {
|
|
45
|
+
};
|
|
46
|
+
const threadOf = (node) => node === false || node === "" ? void 0 : node;
|
|
47
|
+
function useFeedbackInbox({
|
|
48
|
+
rows,
|
|
49
|
+
mine = false,
|
|
50
|
+
canEdit,
|
|
51
|
+
viewerId,
|
|
52
|
+
update,
|
|
53
|
+
reply,
|
|
54
|
+
rework,
|
|
55
|
+
publicSwitch = false,
|
|
56
|
+
votes = false,
|
|
57
|
+
comments,
|
|
58
|
+
renderDetail,
|
|
59
|
+
columns: ownColumns,
|
|
60
|
+
swipe = DEFAULT_FEEDBACK_SWIPE,
|
|
61
|
+
commit,
|
|
62
|
+
onUpload,
|
|
63
|
+
fetcher,
|
|
64
|
+
onCaptureScreenshot = captureScreenshot,
|
|
65
|
+
renderDate: renderDateProp,
|
|
66
|
+
pageLinkExclude,
|
|
67
|
+
loading = false,
|
|
68
|
+
detail,
|
|
69
|
+
labels
|
|
70
|
+
}) {
|
|
71
|
+
const editable = canEdit && !mine;
|
|
72
|
+
const pageLabels = useFeedbackPageLabels(labels);
|
|
73
|
+
const statusLabels = useFeedbackStatusLabels();
|
|
74
|
+
const renderDate = useFeedbackRenderDate(renderDateProp);
|
|
75
|
+
const updateAsync = update.mutateAsync;
|
|
76
|
+
const changeStatus = useFeedbackStatusUndo(updateAsync);
|
|
77
|
+
const [openId, setOpenId] = useSearchParamState("row", null, ROW_PARAM);
|
|
78
|
+
const { pathname, search } = useLocation();
|
|
79
|
+
const here = useHref({ pathname });
|
|
80
|
+
const rowHref = useCallback(
|
|
81
|
+
(row) => {
|
|
82
|
+
const params = new URLSearchParams(search);
|
|
83
|
+
params.set("row", String(row.id));
|
|
84
|
+
return `${here}?${params.toString()}`;
|
|
85
|
+
},
|
|
86
|
+
[here, search]
|
|
87
|
+
);
|
|
88
|
+
const [awaiting, setAwaiting] = useState(false);
|
|
89
|
+
const shown = useMemo(
|
|
90
|
+
() => (editable && awaiting ? rows.filter((row) => isFeedbackAwaiting(row.status)) : [...rows]).sort(newestFirst),
|
|
91
|
+
[rows, editable, awaiting]
|
|
92
|
+
);
|
|
93
|
+
const kitColumns = useFeedbackColumns({
|
|
94
|
+
mine,
|
|
95
|
+
canEdit,
|
|
96
|
+
onStatus: changeStatus,
|
|
97
|
+
renderDate,
|
|
98
|
+
commit,
|
|
99
|
+
votes,
|
|
100
|
+
pageLinkExclude,
|
|
101
|
+
labels
|
|
102
|
+
});
|
|
103
|
+
const columns = useMemo(() => ownColumns ? ownColumns(kitColumns) : kitColumns, [ownColumns, kitColumns]);
|
|
104
|
+
const mobileGroupBy = useMemo(() => feedbackMobileGroupBy(renderDate), [renderDate]);
|
|
105
|
+
const pending = Boolean(update.isPending || rework?.isPending);
|
|
106
|
+
const capture = onCaptureScreenshot ?? void 0;
|
|
107
|
+
const detailProps = (row) => ({
|
|
108
|
+
row,
|
|
109
|
+
canEdit: editable,
|
|
110
|
+
viewerId,
|
|
111
|
+
onUpdate: updateAsync,
|
|
112
|
+
pending,
|
|
113
|
+
// The page's change, not one the detail would build: the same Undo as the cell's.
|
|
114
|
+
statusChange: changeStatus,
|
|
115
|
+
onUpload,
|
|
116
|
+
fetcher,
|
|
117
|
+
onCaptureScreenshot: capture,
|
|
118
|
+
// Only the app's own: left out, the detail's "Resolved:" is the kit's sentence date,
|
|
119
|
+
// no weekday — as kastlan's has always been.
|
|
120
|
+
renderDate: renderDateProp,
|
|
121
|
+
pageLinkExclude,
|
|
122
|
+
onReply: reply ? (body, status, attachmentUrl) => reply.mutateAsync({
|
|
123
|
+
id: row.id,
|
|
124
|
+
body,
|
|
125
|
+
...status ? { status } : {},
|
|
126
|
+
...attachmentUrl ? { attachmentUrl } : {}
|
|
127
|
+
}) : void 0,
|
|
128
|
+
// The reply's one file (§12): all three apps are on server-kit 0.18, and the reply
|
|
129
|
+
// mutation's `attachmentUrl` is in its type from the start (the B1 risk the detail's
|
|
130
|
+
// default guards against — an `onReply` that drops the file — cannot arise here).
|
|
131
|
+
replyAttachments: true,
|
|
132
|
+
replying: reply?.isPending ?? false,
|
|
133
|
+
onRework: rework ? (note, attachmentUrl) => rework.mutateAsync({ id: row.id, note, ...attachmentUrl ? { attachmentUrl } : {} }) : void 0,
|
|
134
|
+
comments: threadOf(comments?.(row)),
|
|
135
|
+
onPublicChange: publicSwitch ? (next) => runMutation(updateAsync, { id: row.id, public: next }, ignore) : void 0,
|
|
136
|
+
...detail
|
|
137
|
+
});
|
|
138
|
+
const table = {
|
|
139
|
+
rows: shown,
|
|
140
|
+
columns,
|
|
141
|
+
rowKey: rowId,
|
|
142
|
+
storageKey: "feedback",
|
|
143
|
+
urlSync: true,
|
|
144
|
+
fillHeight: true,
|
|
145
|
+
rowHref,
|
|
146
|
+
// The link covers the row's first cell; a click anywhere on the row opens it — or,
|
|
147
|
+
// on the open one, closes it.
|
|
148
|
+
onRowClick: (row) => setOpenId((id) => id === row.id ? null : row.id),
|
|
149
|
+
isExpanded: (row) => row.id === openId,
|
|
150
|
+
expandedRow: (row) => {
|
|
151
|
+
const node = /* @__PURE__ */ jsx(FeedbackRowDetail, { ...detailProps(row) });
|
|
152
|
+
return renderDetail ? renderDetail(row, node) : node;
|
|
153
|
+
},
|
|
154
|
+
// §7.13: one word, also when a filter or the toggle leaves nothing; and while the
|
|
155
|
+
// first answer is out, what is happening instead.
|
|
156
|
+
empty: loading ? /* @__PURE__ */ jsx(LoadingState, { size: "sm", inline: true }) : /* @__PURE__ */ jsx(FeedbackEmptyState, { labels }),
|
|
157
|
+
mobileGroupBy,
|
|
158
|
+
mobileCard: (row) => /* @__PURE__ */ jsx(FeedbackMobileCard, { row, showSubmitter: editable, renderDate, votes, labels }),
|
|
159
|
+
// The admin inbox only — /my-feedback is read-only by design (keksdose #331) — and
|
|
160
|
+
// every swipe through the same Undo as a tap (§4.5, §7.10).
|
|
161
|
+
mobileSwipeActions: editable ? (row) => feedbackSwipePlan(swipe, row, { change: changeStatus, labels: statusLabels }) : void 0,
|
|
162
|
+
// The swipes as the desktop's last column (0.46, keksdose dev#598), less what the
|
|
163
|
+
// status cell already offers.
|
|
164
|
+
desktopSwipeActions: { omit: feedbackSwipeOmitShown, name: rowTitle, ...commit === void 0 ? {} : { commit } }
|
|
165
|
+
};
|
|
166
|
+
return {
|
|
167
|
+
editable,
|
|
168
|
+
title: mine ? pageLabels.myTitle : pageLabels.title,
|
|
169
|
+
openId,
|
|
170
|
+
setOpenId,
|
|
171
|
+
rowHref,
|
|
172
|
+
changeStatus,
|
|
173
|
+
awaiting,
|
|
174
|
+
setAwaiting,
|
|
175
|
+
renderDate,
|
|
176
|
+
detailProps,
|
|
177
|
+
table
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
function FeedbackInbox({
|
|
181
|
+
header,
|
|
182
|
+
table,
|
|
183
|
+
phoneActions,
|
|
184
|
+
className,
|
|
185
|
+
...options
|
|
186
|
+
}) {
|
|
187
|
+
const inbox = useFeedbackInbox(options);
|
|
188
|
+
const pageLabels = useFeedbackPageLabels(options.labels);
|
|
189
|
+
const head = header === void 0 ? /* @__PURE__ */ jsx(PageHeader, { title: inbox.title, className: "mb-4 md:shrink-0" }) : typeof header === "function" ? header(inbox.title) : header;
|
|
190
|
+
return (
|
|
191
|
+
// A plain element on the way to the table carries the fill (page layout §1.3).
|
|
192
|
+
/* @__PURE__ */ jsxs("div", { className: cn(FILL_HEIGHT_CLASS, className), "aria-busy": options.loading || void 0, "data-feedback-inbox": "", children: [
|
|
193
|
+
head,
|
|
194
|
+
/* @__PURE__ */ jsx(DataTable, { ...inbox.table, ...table }),
|
|
195
|
+
inbox.editable ? (
|
|
196
|
+
// The phone's floating action (keksdose feedback #58): only on the inbox — on
|
|
197
|
+
// /my-feedback the author is not waiting on their own verdict.
|
|
198
|
+
/* @__PURE__ */ jsx(FeedbackAwaitingToggle, { pressed: inbox.awaiting, onPressedChange: inbox.setAwaiting, labels: options.labels, children: phoneActions })
|
|
199
|
+
) : phoneActions && /* @__PURE__ */ jsx(FloatingActionGroup, { "aria-label": pageLabels.phoneActions, className: "md:hidden", children: phoneActions })
|
|
200
|
+
] })
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
export {
|
|
204
|
+
FeedbackInbox,
|
|
205
|
+
useFeedbackInbox
|
|
206
|
+
};
|
|
207
|
+
//# sourceMappingURL=feedback-inbox-page.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/feedback/feedback-inbox-page.tsx"],"sourcesContent":["import { useCallback, useMemo, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { useHref, useLocation } from \"react-router\";\nimport { cn } from \"../lib/cn\";\nimport { DataTable, type DataTableColumn, type DataTableProps } from \"../components/data-table\";\nimport { FloatingActionGroup } from \"../components/floating-panel\";\nimport { LoadingState } from \"../components/loading-state\";\nimport { PageHeader } from \"../components/page-header\";\nimport type { CommitScope } from \"../components/write-lock\";\nimport type { AuthedFetcher } from \"../hooks/use-authed-src\";\nimport { useSearchParamState } from \"../hooks/use-search-param-state\";\nimport type { LabelOverride } from \"../i18n/kit-labels\";\nimport type { PathPattern } from \"../landing/routing\";\nimport { FILL_HEIGHT_CLASS } from \"../shell/fill-height\";\nimport { captureAppScreenshot } from \"./feedback-capture\";\nimport { useFeedbackStatusLabels } from \"./feedback-labels\";\nimport { runMutation } from \"./feedback-mutation\";\nimport type { FeedbackRecord } from \"./feedback-record\";\nimport {\n FeedbackRowDetail,\n type FeedbackDetailPatch,\n type FeedbackRowDetailProps,\n type FeedbackUpload,\n} from \"./feedback-row-detail\";\nimport { useFeedbackStatusUndo, type FeedbackStatusChange } from \"./feedback-status-undo\";\nimport {\n DEFAULT_FEEDBACK_SWIPE,\n feedbackSwipeOmitShown,\n feedbackSwipePlan,\n type FeedbackSwipeBinding,\n} from \"./feedback-swipe\";\nimport {\n FeedbackAwaitingToggle,\n FeedbackEmptyState,\n FeedbackMobileCard,\n feedbackMobileGroupBy,\n isFeedbackAwaiting,\n useFeedbackColumns,\n useFeedbackPageLabels,\n useFeedbackRenderDate,\n type FeedbackPageLabels,\n type FeedbackRenderDate,\n} from \"./feedback-table\";\nimport type { FeedbackStatus } from \"./feedback-vocabulary\";\n\n/**\n * The feedback inbox, ASSEMBLED ONCE (0.55; kastlan reuse audit 2026-11-02, proposal 2;\n * docs/feedback-harmonization.md §13).\n *\n * Since 0.27 every part of `/feedback` and `/my-feedback` has been the kit's — the columns,\n * the phone card and its day headers, the detail, the Undo, the swipes, the awaiting toggle\n * (feedback-table.tsx, feedback-row-detail.tsx, feedback-swipe.tsx). What was not the kit's\n * was the WIRING between them, and each app wrote the same ~150 lines of it:\n * kastlan `frontend/src/features/feedback/pages/feedback-page.tsx:40-205`, keksdose\n * `frontend/src/features/feedback/feedback-page.tsx:51-303`, Kurvenschmiede\n * `frontend/src/features/feedback/feedback-page.tsx:88-245`. The open row in `?row=` with\n * its numeric parse and its `rowHref`, `useFeedbackStatusUndo` over the page's PATCH, the\n * `DataTable` with a dozen props, `FeedbackRowDetail` with a dozen more, the phone's\n * grouping, card and swipe plan, the awaiting filter and its toggle. So every rename the\n * parts took (0.52's `mutateAsync`, 0.53's removals) was made three times, and three\n * times reviewed.\n *\n * Here that wiring is the kit's: {@link useFeedbackInbox} holds it and returns what the\n * table, the detail and the phone cards need; {@link FeedbackInbox} draws the page from\n * it. What stays the app's is what differs between the three, each a slot: where the rows\n * come from and the three mutations (its API client, TanStack Query in all three — the kit\n * sends no request), who may triage, the votes, the public switch, the comments (the app's\n * `FeedbackCommentThread` over its own queries), its own columns, its swipe binding, its\n * date writer, the page's header and frame, and whatever else `DataTable` takes.\n *\n * Additive: every part it is built from stays exported and unchanged, for a page that\n * wants its own layout — call the hook and spread `inbox.table` into a `DataTable`.\n */\n\n/* ── The mutations ──────────────────────────────────────────────────────────── */\n\n/**\n * One of the page's mutations, as the inbox calls it: **TanStack Query's `useMutation`\n * result, passed as it is** — `update={update}`. The inbox reads `mutateAsync` (whose\n * promise settles for every call, refactor audit 2026-10-30 FLW-3) and `isPending`, and\n * nothing else. Any object with those two fits, so a page on another data layer hands\n * `{ mutateAsync: api.update, isPending }`.\n *\n * Taking the mutation rather than a callback per control is the point of the round: how\n * the parts call it (0.52 moved them from `mutate` to `mutateAsync`) is then the kit's to\n * change, once. Failure is the mutation's own: its `onError` toasts the server's sentence\n * (§4.4), and the inbox catches the rejection.\n */\nexport interface FeedbackInboxMutation<V> {\n mutateAsync: (variables: V) => Promise<unknown>;\n /** In flight: the editors' and the composer's buttons wait for it. */\n isPending?: boolean;\n}\n\n/** What the reply mutation is sent: `POST /feedback/{id}/replies` (§9.7, §12) — the\n * body, the status picked (absent: \"No change\") and the uploaded file's URL (absent:\n * none). Keys that carry nothing are left out, so a `mutationFn` may spread them onto\n * the wire. kastlan's `useFeedbackReply` takes exactly this. */\nexport interface FeedbackReplyPost {\n id: number;\n body: string;\n status?: FeedbackStatus;\n attachmentUrl?: string;\n}\n\n/** What the rework mutation is sent: `POST /feedback/{id}/rework` (§10.3) — the author's\n * trimmed note and the uploaded file's URL (absent: none). kastlan's `useFeedbackRework`\n * takes exactly this. */\nexport interface FeedbackReworkPost {\n id: number;\n note: string;\n attachmentUrl?: string;\n}\n\n/* ── The hook ───────────────────────────────────────────────────────────────── */\n\nexport interface UseFeedbackInboxOptions<T extends FeedbackRecord> {\n /** The list as the app's query answered it (`GET /feedback`, `GET /feedback/my`) —\n * `list.data ?? []`. Shown newest first and, behind the awaiting toggle, narrowed. */\n rows: readonly T[];\n /** `/my-feedback`: the viewer's own reports — no triage there, for an admin too (§4.3). */\n mine?: boolean;\n /** The viewer may triage: the admin. Only on the inbox — `mine` wins — so `isAdmin`\n * is enough. The status cell, the pills, the reply composer, the swipes, the submitter\n * on the card and the awaiting toggle. */\n canEdit: boolean;\n /** The signed-in user's id: who the AUTHOR is (the description editor, Rework, the\n * public switch's window). */\n viewerId?: number | null;\n /**\n * `PATCH /feedback/{id}` (§3.4): every edit of the report itself — a status change from\n * the cell, the pills or a swipe (with the Undo, `useFeedbackStatusUndo`), the\n * description, the legacy rework append and, with {@link publicSwitch}, the flip. ONE\n * mutation for all of them, the page's, so its observer outlives a row a status filter\n * removes (§4.5).\n */\n update: FeedbackInboxMutation<FeedbackDetailPatch>;\n /** `POST /feedback/{id}/replies` — the admin's answer (§9.7) with its one file (§12).\n * Without it no composer is drawn. */\n reply?: FeedbackInboxMutation<FeedbackReplyPost>;\n /** `POST /feedback/{id}/rework` — the author's rework entry (§10.3). Without it a rework\n * goes through {@link update} as the legacy body append (§3.4). */\n rework?: FeedbackInboxMutation<FeedbackReworkPost>;\n /**\n * The **Visible to others** switch in the detail (§9.3), its flip sent through\n * {@link update} as `{ id, public }` — as keksdose and Kurvenschmiede send it. Off by\n * default: an app without public parts (kastlan) has no switch.\n */\n publicSwitch?: boolean;\n /** The **Votes** column and the card's count (§9.6). Off by default (kastlan); keksdose\n * always, Kurvenschmiede for a reader of the public parts. */\n votes?: boolean;\n /**\n * The report's comments, in a section of their own under the replies (§9.8): the app's\n * `FeedbackCommentThread` over its own queries — a component of its own, since its\n * queries are hooks. Return `null` for a row without a thread (a CRASH, a reader who\n * does not see the public parts; `false` is read as `null`). Called only for the open\n * row.\n *\n * ```tsx\n * comments={(row) => <RowComments id={row.id} isAdmin={isAdmin} canComment={!canEdit} />}\n * ```\n */\n comments?: (row: T) => ReactNode;\n /** The detail as drawn, to wrap or extend — kastlan's tour anchor:\n * `(row, detail) => <div data-tour=\"feedback-row-detail\">{detail}</div>`. */\n renderDetail?: (row: T, detail: ReactNode) => ReactNode;\n /**\n * The app's own columns over the kit's (§4.3's nine, and Votes): add, drop, reorder —\n * the keys are stable (`columns.filter((c) => c.key !== \"email\")`). A column brings its\n * filter with it. Keep it stable (module scope or `useCallback`): it is a memo's\n * dependency.\n */\n columns?: (columns: readonly DataTableColumn<T>[]) => readonly DataTableColumn<T>[];\n /** Which swipe does what on the phone (§4.5) — keksdose's Settings → Interaction binding,\n * `{ end: prefs.right, start: prefs.left }`. Default `DEFAULT_FEEDBACK_SWIPE`. */\n swipe?: FeedbackSwipeBinding;\n /** The status writes the TABLE offers — the status cell and the desktop's actions\n * column — commit: under a locked `WriteLockProvider` they stay and say why\n * (`FeedbackStatusTransitions`' `commit`). Off by default. The detail's own saves:\n * `detail={{ commit }}`. */\n commit?: CommitScope;\n /** `POST /feedback/attachments` (§3.3): the rework's file and the reply's. */\n onUpload?: FeedbackUpload;\n /** The app's authenticated GET for the pictures and the downloads (§3.5). */\n fetcher?: AuthedFetcher | null;\n /** \"Capture screenshot\" beside the rework's and the reply's file field. Default: the\n * kit's `captureAppScreenshot()`; `null` for no button. */\n onCaptureScreenshot?: (() => Promise<File | null>) | null;\n /**\n * The app's date writer (keksdose's `useDateCell()`, the date-format setting): the date\n * and resolved columns, the card, the phone's day headers AND the detail's \"Resolved:\",\n * so all five say the same. Left out, the kit's date with the weekday in the table and\n * on the phone, and in the detail its sentence date — as the parts draw them alone.\n */\n renderDate?: FeedbackRenderDate;\n /** The app's one-shot routes, on top of the kit's (0.52, FLW-7) — for the URL column and\n * the detail's URL section alike. Keep it stable (module scope). */\n pageLinkExclude?: readonly PathPattern[];\n /** The list is still loading (`list.isPending`): the table says \"Loading…\" where its\n * rows will be, not \"None\". */\n loading?: boolean;\n /** Over the detail's props the inbox sets — `commit`, `showSubject`,\n * `reworkAttachment`, `replyAttachments` (on here), `labels`, `className`. Merged last,\n * so it wins. */\n detail?: Partial<Omit<FeedbackRowDetailProps, \"row\">>;\n /** Over the `feedbackPage` namespace: the columns, the card, the empty state, the toggle\n * and the title. Keep it stable: it is a memo's dependency. */\n labels?: LabelOverride<FeedbackPageLabels>;\n}\n\n/** What {@link useFeedbackInbox} returns: the state, and the props of the parts. */\nexport interface FeedbackInboxState<T extends FeedbackRecord> {\n /** `canEdit && !mine`: the admin on the inbox. */\n editable: boolean;\n /** The page's title, `feedbackPage.title` — or `.myTitle` on `/my-feedback`. */\n title: string;\n /** The open row's id, from `?row=`; `null` when none is open or the param named no\n * id (`?row=abc`, `?row=1.5`, `?row=0`). */\n openId: number | null;\n /** Open a row by its id, or close it with `null`: rewrites `?row=`, replacing the\n * history entry rather than stacking one per report looked at. */\n setOpenId: (id: number | null) => void;\n /** A row's own address: this view — the table's page, sort and filters — with the row\n * open. The row's link (a new tab, a copied address); a plain click opens it in place. */\n rowHref: (row: T) => string;\n /** The undoable status change (§4.5): the status cell's, the pills', the swipes'. */\n changeStatus: FeedbackStatusChange;\n /** The phone's \"Only what is waiting for you\" — page state, not the URL (§4.3). */\n awaiting: boolean;\n setAwaiting: (next: boolean) => void;\n /** The one date writer the columns, the card and the day headers use. */\n renderDate: FeedbackRenderDate;\n /** `FeedbackRowDetail`'s props for a row, slots included. */\n detailProps: (row: T) => FeedbackRowDetailProps;\n /** `DataTable`'s props, ready to spread: the rows (newest first, narrowed by\n * `awaiting`), the columns, the open row, the detail, the phone's card, day headers and\n * swipes, the desktop's actions column, the empty state, `urlSync`,\n * `storageKey=\"feedback\"`, `fillHeight`. */\n table: DataTableProps<T>;\n}\n\n/** `?row=`'s value: a report's id is a positive integer, written in digits. Anything\n * else — a hand-edited link, `1e2`, `0x10`, `-3`, `1.5` — opens no row (and the URL\n * keeps it until a row is opened or closed). The three apps parsed with `Number()`, so\n * `?row=1e2` opened #100 in all three. */\nfunction parseRowId(raw: string): number | undefined {\n if (!/^[1-9]\\d*$/.test(raw)) return undefined;\n const id = Number(raw);\n return Number.isSafeInteger(id) ? id : undefined;\n}\n\nconst ROW_PARAM = { parse: parseRowId, history: \"replace\" } as const;\n\n/** Newest first, as `GET /feedback` sends it (§3.3) — the phone's day headers group runs\n * of equal days, so an older row between two of today's would split the day in two.\n * ISO strings from one server sort as their instants; the sort is stable. */\nconst newestFirst = (a: FeedbackRecord, b: FeedbackRecord) =>\n a.created_at < b.created_at ? 1 : a.created_at > b.created_at ? -1 : 0;\n\nconst rowId = (row: FeedbackRecord) => row.id;\nconst rowTitle = (row: FeedbackRecord) => row.title;\nconst captureScreenshot = () => captureAppScreenshot();\nconst ignore = () => {};\n/** A slot's \"nothing\": `cond && <Thread />` answers `false`, which the detail would draw\n * as an empty Comments section (it draws one for anything but `null`). */\nconst threadOf = (node: ReactNode): ReactNode => (node === false || node === \"\" ? undefined : node);\n\n/**\n * The inbox's wiring, once (§13): from the app's rows and mutations to what the table,\n * the detail and the phone cards take.\n *\n * ```tsx\n * const list = useQuery({ queryKey: keys.feedback.all, queryFn: api.listFeedback });\n * const update = useMutation({ mutationFn: ({ id, ...patch }: FeedbackDetailPatch) => api.update(id, patch), … });\n * const inbox = useFeedbackInbox({ rows: list.data ?? [], canEdit: isAdmin, viewerId: user?.id, update });\n * <DataTable {...inbox.table} edgeFade />\n * ```\n *\n * {@link FeedbackInbox} is this hook drawn — use the hook alone for a layout of your own.\n * Needs a react-router Router (`?row=`, `urlSync`).\n */\nexport function useFeedbackInbox<T extends FeedbackRecord>({\n rows,\n mine = false,\n canEdit,\n viewerId,\n update,\n reply,\n rework,\n publicSwitch = false,\n votes = false,\n comments,\n renderDetail,\n columns: ownColumns,\n swipe = DEFAULT_FEEDBACK_SWIPE,\n commit,\n onUpload,\n fetcher,\n onCaptureScreenshot = captureScreenshot,\n renderDate: renderDateProp,\n pageLinkExclude,\n loading = false,\n detail,\n labels,\n}: UseFeedbackInboxOptions<T>): FeedbackInboxState<T> {\n // An admin on /my-feedback reads as any author does (§4.3), as `feedbackColumns` has it.\n const editable = canEdit && !mine;\n const pageLabels = useFeedbackPageLabels(labels);\n const statusLabels = useFeedbackStatusLabels();\n const renderDate = useFeedbackRenderDate(renderDateProp);\n\n // TanStack's `mutateAsync` is stable, so the Undo and the columns' memo hold across\n // renders; the mutation object around it is not.\n const updateAsync = update.mutateAsync;\n const changeStatus = useFeedbackStatusUndo(updateAsync);\n\n // The open row IS the URL (§4.3: `?row=<id>`, every app) — which is what makes a row a\n // real link at all (keksdose feedback #451). Replace, not push: looking through ten\n // reports is not ten steps for Back.\n const [openId, setOpenId] = useSearchParamState<number | null>(\"row\", null, ROW_PARAM);\n const { pathname, search } = useLocation();\n // Through the router, so a basename (and a hash router's `#`) is in the address.\n const here = useHref({ pathname });\n // Built from the CURRENT query, not a bare `?row=`: the table keeps its `f.*`, `sort`\n // and `p` in the URL, and dropping them would open the new tab on an unfiltered list\n // where the row may not be on the first page (keksdose feedback-page.tsx:145).\n const rowHref = useCallback(\n (row: T) => {\n const params = new URLSearchParams(search);\n params.set(\"row\", String(row.id));\n return `${here}?${params.toString()}`;\n },\n [here, search],\n );\n\n // A thumb gesture on one screen, not a view worth linking to (§4.3; keksdose live #330).\n const [awaiting, setAwaiting] = useState(false);\n const shown = useMemo(\n () => (editable && awaiting ? rows.filter((row) => isFeedbackAwaiting(row.status)) : [...rows]).sort(newestFirst),\n [rows, editable, awaiting],\n );\n\n const kitColumns = useFeedbackColumns<T>({\n mine,\n canEdit,\n onStatus: changeStatus,\n renderDate,\n commit,\n votes,\n pageLinkExclude,\n labels,\n });\n const columns = useMemo(() => (ownColumns ? ownColumns(kitColumns) : kitColumns), [ownColumns, kitColumns]);\n const mobileGroupBy = useMemo(() => feedbackMobileGroupBy(renderDate), [renderDate]);\n\n // The rework's sending is the detail's too (keksdose, Kurvenschmiede): its editors and\n // the public switch wait for whichever write is out.\n const pending = Boolean(update.isPending || rework?.isPending);\n const capture = onCaptureScreenshot ?? undefined;\n\n const detailProps = (row: T): FeedbackRowDetailProps => ({\n row,\n canEdit: editable,\n viewerId,\n onUpdate: updateAsync,\n pending,\n // The page's change, not one the detail would build: the same Undo as the cell's.\n statusChange: changeStatus,\n onUpload,\n fetcher,\n onCaptureScreenshot: capture,\n // Only the app's own: left out, the detail's \"Resolved:\" is the kit's sentence date,\n // no weekday — as kastlan's has always been.\n renderDate: renderDateProp,\n pageLinkExclude,\n onReply: reply\n ? (body, status, attachmentUrl) =>\n reply.mutateAsync({\n id: row.id,\n body,\n ...(status ? { status } : {}),\n ...(attachmentUrl ? { attachmentUrl } : {}),\n })\n : undefined,\n // The reply's one file (§12): all three apps are on server-kit 0.18, and the reply\n // mutation's `attachmentUrl` is in its type from the start (the B1 risk the detail's\n // default guards against — an `onReply` that drops the file — cannot arise here).\n replyAttachments: true,\n replying: reply?.isPending ?? false,\n onRework: rework\n ? (note, attachmentUrl) => rework.mutateAsync({ id: row.id, note, ...(attachmentUrl ? { attachmentUrl } : {}) })\n : undefined,\n comments: threadOf(comments?.(row)),\n onPublicChange: publicSwitch ? (next) => runMutation(updateAsync, { id: row.id, public: next }, ignore) : undefined,\n ...detail,\n });\n\n const table: DataTableProps<T> = {\n rows: shown,\n columns,\n rowKey: rowId,\n storageKey: \"feedback\",\n urlSync: true,\n fillHeight: true,\n rowHref,\n // The link covers the row's first cell; a click anywhere on the row opens it — or,\n // on the open one, closes it.\n onRowClick: (row) => setOpenId((id) => (id === row.id ? null : row.id)),\n isExpanded: (row) => row.id === openId,\n expandedRow: (row) => {\n const node = <FeedbackRowDetail {...detailProps(row)} />;\n return renderDetail ? renderDetail(row, node) : node;\n },\n // §7.13: one word, also when a filter or the toggle leaves nothing; and while the\n // first answer is out, what is happening instead.\n empty: loading ? <LoadingState size=\"sm\" inline /> : <FeedbackEmptyState labels={labels} />,\n mobileGroupBy,\n mobileCard: (row) => (\n <FeedbackMobileCard row={row} showSubmitter={editable} renderDate={renderDate} votes={votes} labels={labels} />\n ),\n // The admin inbox only — /my-feedback is read-only by design (keksdose #331) — and\n // every swipe through the same Undo as a tap (§4.5, §7.10).\n mobileSwipeActions: editable\n ? (row) => feedbackSwipePlan(swipe, row, { change: changeStatus, labels: statusLabels })\n : undefined,\n // The swipes as the desktop's last column (0.46, keksdose dev#598), less what the\n // status cell already offers.\n desktopSwipeActions: { omit: feedbackSwipeOmitShown, name: rowTitle, ...(commit === undefined ? {} : { commit }) },\n };\n\n return {\n editable,\n title: mine ? pageLabels.myTitle : pageLabels.title,\n openId,\n setOpenId,\n rowHref,\n changeStatus,\n awaiting,\n setAwaiting,\n renderDate,\n detailProps,\n table,\n };\n}\n\n/* ── The component ──────────────────────────────────────────────────────────── */\n\nexport interface FeedbackInboxProps<T extends FeedbackRecord> extends UseFeedbackInboxOptions<T> {\n /**\n * Above the table. Default: `<PageHeader title={title} className=\"mb-4 md:shrink-0\" />`.\n * A function gets the page's title (`feedbackPage.title` / `.myTitle`) — the app's own\n * header: `(title) => <PageHeader size=\"compact\" title={title} data-tour=\"feedback-header\" />`.\n * `null` for none.\n */\n header?: ReactNode | ((title: string) => ReactNode);\n /** Over the inbox's `DataTable` props — `edgeFade`, `locale`, `mobileExpandAsDialog`,\n * `className`, another `storageKey`. Merged last, so it wins. */\n table?: Partial<DataTableProps<T>>;\n /** Further `FloatingAction`s on the phone: after the awaiting toggle on the inbox, in a\n * group of their own on `/my-feedback`. */\n phoneActions?: ReactNode;\n /** On the page's frame — the fill-height column (`FILL_HEIGHT_CLASS`); the app's page\n * padding goes here. */\n className?: string;\n}\n\n/**\n * The feedback inbox (§13): `/feedback` and `/my-feedback` drawn whole from\n * {@link useFeedbackInbox} — the header, the table with its detail, phone cards and swipes,\n * and the phone's awaiting toggle, in the fill-height frame (page layout §1.3) — so a page\n * is its queries and this:\n *\n * ```tsx\n * export function FeedbackPage({ mine = false }: { mine?: boolean }) {\n * const { user, isAdmin } = useAuth();\n * const list = useQuery({ queryKey: mine ? keys.mine : keys.all, queryFn: mine ? api.mine : api.all });\n * const update = useFeedbackUpdate();\n * const reply = useFeedbackReply();\n * const rework = useFeedbackRework();\n * if (!mine && !isAdmin) return <Navigate to=\"/my-feedback\" replace />;\n * return (\n * <FeedbackInbox\n * rows={list.data ?? []} loading={list.isPending} mine={mine} canEdit={isAdmin} viewerId={user?.id}\n * update={update} reply={reply} rework={rework}\n * onUpload={api.upload} fetcher={api.file}\n * />\n * );\n * }\n * ```\n *\n * Every slot is {@link UseFeedbackInboxOptions}' or one of the four below. The redirect of\n * a non-admin, the routes and the queries stay the app's.\n */\nexport function FeedbackInbox<T extends FeedbackRecord>({\n header,\n table,\n phoneActions,\n className,\n ...options\n}: FeedbackInboxProps<T>) {\n const inbox = useFeedbackInbox<T>(options);\n const pageLabels = useFeedbackPageLabels(options.labels);\n const head =\n header === undefined ? (\n <PageHeader title={inbox.title} className=\"mb-4 md:shrink-0\" />\n ) : typeof header === \"function\" ? (\n header(inbox.title)\n ) : (\n header\n );\n return (\n // A plain element on the way to the table carries the fill (page layout §1.3).\n <div className={cn(FILL_HEIGHT_CLASS, className)} aria-busy={options.loading || undefined} data-feedback-inbox=\"\">\n {head}\n <DataTable {...inbox.table} {...table} />\n {inbox.editable ? (\n // The phone's floating action (keksdose feedback #58): only on the inbox — on\n // /my-feedback the author is not waiting on their own verdict.\n <FeedbackAwaitingToggle pressed={inbox.awaiting} onPressedChange={inbox.setAwaiting} labels={options.labels}>\n {phoneActions}\n </FeedbackAwaitingToggle>\n ) : (\n phoneActions && (\n <FloatingActionGroup aria-label={pageLabels.phoneActions} className=\"md:hidden\">\n {phoneActions}\n </FloatingActionGroup>\n )\n )}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -53,6 +53,11 @@ export interface FeedbackContext {
|
|
|
53
53
|
ua?: string;
|
|
54
54
|
/** The app build (`__APP_VERSION__`). */
|
|
55
55
|
version?: string;
|
|
56
|
+
/** What the app attached about the thing reported (keksdose's stuck receipt scan, live
|
|
57
|
+
* #481): a flat record of short values, in the order the app wrote them. The row
|
|
58
|
+
* detail shows it to the admin and the author, never to anyone else; erasure drops it
|
|
59
|
+
* (it is not on server-kit's `FEEDBACK_CONTEXT_KEEP`). */
|
|
60
|
+
diagnostics?: Readonly<Record<string, unknown>>;
|
|
56
61
|
fingerprint?: string;
|
|
57
62
|
/** Which error boundary caught it. */
|
|
58
63
|
boundary?: "app" | "page" | (string & {});
|