@eifi1/ui-kit 0.29.0 → 0.30.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 +26 -4
- package/dist/account/account-parts.d.ts +21 -0
- package/dist/account/account-parts.js +40 -0
- package/dist/account/account-parts.js.map +1 -0
- package/dist/account/data-export-setting.d.ts +73 -0
- package/dist/account/data-export-setting.js +113 -0
- package/dist/account/data-export-setting.js.map +1 -0
- package/dist/account/delete-account-setting.d.ts +91 -0
- package/dist/account/delete-account-setting.js +199 -0
- package/dist/account/delete-account-setting.js.map +1 -0
- package/dist/account/email-change-setting.d.ts +136 -0
- package/dist/account/email-change-setting.js +277 -0
- package/dist/account/email-change-setting.js.map +1 -0
- package/dist/account/sessions-setting.d.ts +110 -0
- package/dist/account/sessions-setting.js +146 -0
- package/dist/account/sessions-setting.js.map +1 -0
- package/dist/admin/admin-action-confirm.d.ts +91 -0
- package/dist/admin/admin-action-confirm.js +276 -0
- package/dist/admin/admin-action-confirm.js.map +1 -0
- package/dist/admin/admin-action-log.d.ts +105 -0
- package/dist/admin/admin-action-log.js +153 -0
- package/dist/admin/admin-action-log.js.map +1 -0
- package/dist/admin/admin-parts.d.ts +40 -0
- package/dist/admin/admin-parts.js +45 -0
- package/dist/admin/admin-parts.js.map +1 -0
- package/dist/admin/invitations-panel.d.ts +91 -0
- package/dist/admin/invitations-panel.js +289 -0
- package/dist/admin/invitations-panel.js.map +1 -0
- package/dist/admin/reviewer-scope-editor.d.ts +91 -0
- package/dist/admin/reviewer-scope-editor.js +134 -0
- package/dist/admin/reviewer-scope-editor.js.map +1 -0
- package/dist/admin/role-select.d.ts +91 -0
- package/dist/admin/role-select.js +128 -0
- package/dist/admin/role-select.js.map +1 -0
- package/dist/admin/transfer-ownership-dialog.d.ts +91 -0
- package/dist/admin/transfer-ownership-dialog.js +83 -0
- package/dist/admin/transfer-ownership-dialog.js.map +1 -0
- package/dist/admin/user-roster.d.ts +91 -0
- package/dist/admin/user-roster.js +285 -0
- package/dist/admin/user-roster.js.map +1 -0
- package/dist/auth/auth-errors.d.ts +85 -6
- package/dist/auth/auth-errors.js +62 -2
- package/dist/auth/auth-errors.js.map +1 -1
- package/dist/auth/forgot-password-form.d.ts +10 -3
- package/dist/auth/forgot-password-form.js +6 -3
- package/dist/auth/forgot-password-form.js.map +1 -1
- package/dist/auth/register-form.d.ts +17 -12
- package/dist/auth/register-form.js +6 -4
- package/dist/auth/register-form.js.map +1 -1
- package/dist/auth/reset-password-form.d.ts +10 -3
- package/dist/auth/reset-password-form.js +6 -3
- package/dist/auth/reset-password-form.js.map +1 -1
- package/dist/auth/sign-in-form.d.ts +61 -9
- package/dist/auth/sign-in-form.js +94 -13
- package/dist/auth/sign-in-form.js.map +1 -1
- package/dist/auth/verify-email.d.ts +7 -2
- package/dist/auth/verify-email.js +44 -8
- package/dist/auth/verify-email.js.map +1 -1
- package/dist/chart.d.ts +16 -11
- package/dist/components/account-chips.d.ts +47 -7
- package/dist/components/account-chips.js +19 -3
- package/dist/components/account-chips.js.map +1 -1
- package/dist/components/account-settings-labels.d.ts +12 -1
- package/dist/components/account-settings-labels.js +4 -1
- package/dist/components/account-settings-labels.js.map +1 -1
- package/dist/components/account-settings.d.ts +61 -6
- package/dist/components/account-settings.js +115 -15
- package/dist/components/account-settings.js.map +1 -1
- package/dist/components/amount-input.d.ts +17 -12
- package/dist/components/button-group.d.ts +17 -12
- package/dist/components/calculator.d.ts +17 -12
- package/dist/components/confirm-dialog.d.ts +17 -12
- package/dist/components/copy-button.d.ts +14 -9
- package/dist/components/danger-confirm.d.ts +17 -12
- package/dist/components/facing-pair.d.ts +17 -12
- package/dist/components/file-button.d.ts +17 -12
- package/dist/components/file-dropzone.d.ts +17 -12
- package/dist/components/form-actions.d.ts +17 -12
- package/dist/components/iban-input.d.ts +17 -12
- package/dist/components/language-select.d.ts +17 -12
- package/dist/components/legal-page.d.ts +17 -12
- package/dist/components/legal.d.ts +17 -12
- package/dist/components/money-field.d.ts +17 -12
- package/dist/components/number-field.d.ts +17 -12
- package/dist/components/number-input.d.ts +17 -12
- package/dist/components/numpad-sheet.d.ts +17 -12
- package/dist/components/phone-input.d.ts +17 -12
- package/dist/components/series-chart.d.ts +17 -12
- package/dist/components/settings-fields.d.ts +16 -11
- package/dist/components/share-card.d.ts +16 -11
- package/dist/components/text-link.d.ts +17 -12
- package/dist/components/time-input.d.ts +17 -12
- package/dist/components/ui.d.ts +13 -8
- package/dist/{register-form-V1OeNlMr.d.ts → delete-account-setting-CGVMckMw.d.ts} +6616 -5645
- package/dist/feedback/feedback-attachment.d.ts +17 -12
- package/dist/feedback/feedback-context.d.ts +17 -12
- package/dist/feedback/feedback-crash.d.ts +17 -12
- package/dist/feedback/feedback-dialog.d.ts +17 -12
- package/dist/feedback/feedback-inbox.d.ts +17 -12
- package/dist/feedback/feedback-labels.d.ts +17 -12
- package/dist/feedback/feedback-menu.d.ts +17 -12
- package/dist/feedback/feedback-record.d.ts +17 -12
- package/dist/feedback/feedback-row-detail.d.ts +17 -12
- package/dist/feedback/feedback-status-undo.d.ts +17 -12
- package/dist/feedback/feedback-submit.d.ts +17 -12
- package/dist/feedback/feedback-swipe.d.ts +17 -12
- package/dist/feedback/feedback-table.d.ts +14 -9
- package/dist/feedback/feedback-thread.d.ts +17 -12
- package/dist/feedback.d.ts +17 -12
- package/dist/hooks/use-anchored-panel.d.ts +6 -2
- package/dist/hooks/use-anchored-panel.js +2 -1
- package/dist/hooks/use-anchored-panel.js.map +1 -1
- package/dist/hooks/use-file-drop.d.ts +17 -12
- package/dist/i18n/defaults.d.ts +17 -12
- package/dist/i18n/defaults.js +22 -0
- package/dist/i18n/defaults.js.map +1 -1
- package/dist/i18n/german.d.ts +17 -12
- package/dist/i18n/german.js +215 -11
- package/dist/i18n/german.js.map +1 -1
- package/dist/i18n/kit-labels.d.ts +10 -5
- package/dist/i18n/kit-labels.js.map +1 -1
- package/dist/i18n/languages.d.ts +11 -6
- package/dist/i18n/locales/de-CH.d.ts +17 -12
- package/dist/i18n/locales/en.d.ts +17 -12
- package/dist/i18n/locales/es.d.ts +17 -12
- package/dist/i18n/locales/es.js +207 -9
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.d.ts +17 -12
- package/dist/i18n/locales/fr.js +209 -6
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hu.d.ts +17 -12
- package/dist/i18n/locales/hu.js +207 -11
- package/dist/i18n/locales/hu.js.map +1 -1
- package/dist/i18n/locales/it.d.ts +17 -12
- package/dist/i18n/locales/it.js +209 -6
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/zh.d.ts +17 -12
- package/dist/i18n/locales/zh.js +200 -6
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/i18n/review.d.ts +17 -12
- package/dist/i18n/review.js +37 -1
- package/dist/i18n/review.js.map +1 -1
- package/dist/index.d.ts +8 -3
- package/dist/index.js +53 -0
- package/dist/index.js.map +1 -1
- package/dist/rhf/fields.d.ts +17 -12
- package/dist/rhf/form.d.ts +17 -12
- package/dist/rhf.d.ts +17 -12
- package/dist/shell/app-shell.d.ts +17 -12
- package/dist/shell/top-bar-brand.d.ts +17 -12
- package/dist/shell.d.ts +11 -6
- package/dist/wizard/stepper-nav.d.ts +17 -12
- package/dist/wizard.d.ts +17 -12
- package/package.json +1 -1
- package/src/account/account-parts.ts +67 -0
- package/src/account/data-export-setting.tsx +218 -0
- package/src/account/delete-account-setting.tsx +362 -0
- package/src/account/email-change-setting.tsx +457 -0
- package/src/account/sessions-setting.tsx +283 -0
- package/src/admin/admin-action-confirm.tsx +495 -0
- package/src/admin/admin-action-log.tsx +297 -0
- package/src/admin/admin-parts.ts +82 -0
- package/src/admin/invitations-panel.tsx +516 -0
- package/src/admin/reviewer-scope-editor.tsx +234 -0
- package/src/admin/role-select.tsx +286 -0
- package/src/admin/transfer-ownership-dialog.tsx +172 -0
- package/src/admin/user-roster.tsx +573 -0
- package/src/auth/auth-errors.ts +165 -8
- package/src/auth/forgot-password-form.tsx +21 -5
- package/src/auth/register-form.tsx +24 -6
- package/src/auth/reset-password-form.tsx +19 -5
- package/src/auth/sign-in-form.tsx +207 -35
- package/src/auth/verify-email.tsx +59 -8
- package/src/components/account-chips.tsx +64 -7
- package/src/components/account-settings-labels.ts +15 -1
- package/src/components/account-settings.tsx +199 -23
- package/src/hooks/use-anchored-panel.ts +14 -3
- package/src/i18n/defaults.ts +22 -0
- package/src/i18n/german.ts +241 -5
- package/src/i18n/kit-labels.tsx +33 -0
- package/src/i18n/locales/es.ts +230 -3
- package/src/i18n/locales/fr.ts +232 -0
- package/src/i18n/locales/hu.ts +224 -5
- package/src/i18n/locales/it.ts +230 -0
- package/src/i18n/locales/zh.ts +205 -0
- package/src/i18n/review.ts +36 -0
- package/src/index.ts +93 -0
package/dist/rhf.d.ts
CHANGED
|
@@ -4,7 +4,10 @@ export { RhfCheckbox, RhfCheckboxProps, RhfCombobox, RhfComboboxProps, RhfCountr
|
|
|
4
4
|
export { RhfLineItemCellContext, RhfLineItems, RhfLineItemsColumn, RhfLineItemsProps } from './rhf/line-items.js';
|
|
5
5
|
import 'react';
|
|
6
6
|
import 'react-hook-form';
|
|
7
|
-
import './
|
|
7
|
+
import './delete-account-setting-CGVMckMw.js';
|
|
8
|
+
import './components/tooltip.js';
|
|
9
|
+
import './hooks/use-anchored-rect.js';
|
|
10
|
+
import './lib/clipping.js';
|
|
8
11
|
import './data-table-labels-DUELeXpa.js';
|
|
9
12
|
import './components/data-table-sort.js';
|
|
10
13
|
import './components/swipeable-row.js';
|
|
@@ -14,10 +17,6 @@ import './components/popover.js';
|
|
|
14
17
|
import './components/chip.js';
|
|
15
18
|
import 'lucide-react';
|
|
16
19
|
import './components/field-sync.js';
|
|
17
|
-
import './components/tooltip.js';
|
|
18
|
-
import './hooks/use-anchored-rect.js';
|
|
19
|
-
import './lib/clipping.js';
|
|
20
|
-
import './components/field-parts.js';
|
|
21
20
|
import './wizard/types.js';
|
|
22
21
|
import './tour/tour.js';
|
|
23
22
|
import './search/command-palette.js';
|
|
@@ -60,6 +59,12 @@ import './components/image-grid.js';
|
|
|
60
59
|
import './components/lightbox.js';
|
|
61
60
|
import './components/write-lock.js';
|
|
62
61
|
import './auth/sign-in-form.js';
|
|
62
|
+
import './shell/topbar-controls.js';
|
|
63
|
+
import './theme/palette-presets.js';
|
|
64
|
+
import './theme/chart-palette.js';
|
|
65
|
+
import './theme/theme-store.js';
|
|
66
|
+
import 'zustand/middleware';
|
|
67
|
+
import 'zustand';
|
|
63
68
|
import './auth/complete-name-dialog.js';
|
|
64
69
|
import './auth/forgot-password-form.js';
|
|
65
70
|
import './auth/status-parts.js';
|
|
@@ -68,8 +73,13 @@ import './auth/verify-email.js';
|
|
|
68
73
|
import './auth/not-found-page.js';
|
|
69
74
|
import './auth/accept-invitation.js';
|
|
70
75
|
import './shell/company-switcher.js';
|
|
71
|
-
import './
|
|
76
|
+
import './account/email-change-setting.js';
|
|
77
|
+
import './account/sessions-setting.js';
|
|
72
78
|
import './lib/format.js';
|
|
79
|
+
import './account/data-export-setting.js';
|
|
80
|
+
import './components/account-chips.js';
|
|
81
|
+
import './admin/admin-parts.js';
|
|
82
|
+
import './admin/admin-action-log.js';
|
|
73
83
|
import './components/reauth-dialog.js';
|
|
74
84
|
import './components/server-wake.js';
|
|
75
85
|
import './lib/server-wake.js';
|
|
@@ -83,12 +93,7 @@ import './components/sign-chip.js';
|
|
|
83
93
|
import './components/column-mapper.js';
|
|
84
94
|
import './lib/column-mapping.js';
|
|
85
95
|
import './lib/table-text.js';
|
|
86
|
-
import './
|
|
87
|
-
import './theme/palette-presets.js';
|
|
88
|
-
import './theme/chart-palette.js';
|
|
89
|
-
import './theme/theme-store.js';
|
|
90
|
-
import 'zustand/middleware';
|
|
91
|
-
import 'zustand';
|
|
96
|
+
import './components/field-parts.js';
|
|
92
97
|
import './components/number-field.js';
|
|
93
98
|
import './components/number-input.js';
|
|
94
99
|
import './components/calculator.js';
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ComponentPropsWithoutRef, ReactNode } from 'react';
|
|
3
3
|
import { LucideIcon } from 'lucide-react';
|
|
4
|
-
import {
|
|
4
|
+
import { dR as KitLinkComponent } from '../delete-account-setting-CGVMckMw.js';
|
|
5
|
+
import '../components/tooltip.js';
|
|
6
|
+
import '../hooks/use-anchored-rect.js';
|
|
7
|
+
import '../lib/clipping.js';
|
|
5
8
|
import '../data-table-labels-DUELeXpa.js';
|
|
6
9
|
import '../components/data-table-sort.js';
|
|
7
10
|
import '../components/swipeable-row.js';
|
|
@@ -10,10 +13,6 @@ import '../components/calendar-heatmap.js';
|
|
|
10
13
|
import '../components/popover.js';
|
|
11
14
|
import '../components/chip.js';
|
|
12
15
|
import '../components/field-sync.js';
|
|
13
|
-
import '../components/tooltip.js';
|
|
14
|
-
import '../hooks/use-anchored-rect.js';
|
|
15
|
-
import '../lib/clipping.js';
|
|
16
|
-
import '../components/field-parts.js';
|
|
17
16
|
import '../wizard/types.js';
|
|
18
17
|
import '../tour/tour.js';
|
|
19
18
|
import '../search/command-palette.js';
|
|
@@ -56,6 +55,12 @@ import '../components/image-grid.js';
|
|
|
56
55
|
import '../components/lightbox.js';
|
|
57
56
|
import '../components/write-lock.js';
|
|
58
57
|
import '../auth/sign-in-form.js';
|
|
58
|
+
import './topbar-controls.js';
|
|
59
|
+
import '../theme/palette-presets.js';
|
|
60
|
+
import '../theme/chart-palette.js';
|
|
61
|
+
import '../theme/theme-store.js';
|
|
62
|
+
import 'zustand/middleware';
|
|
63
|
+
import 'zustand';
|
|
59
64
|
import '../auth/complete-name-dialog.js';
|
|
60
65
|
import '../auth/forgot-password-form.js';
|
|
61
66
|
import '../auth/status-parts.js';
|
|
@@ -64,8 +69,13 @@ import '../auth/verify-email.js';
|
|
|
64
69
|
import '../auth/not-found-page.js';
|
|
65
70
|
import '../auth/accept-invitation.js';
|
|
66
71
|
import './company-switcher.js';
|
|
67
|
-
import '../
|
|
72
|
+
import '../account/email-change-setting.js';
|
|
73
|
+
import '../account/sessions-setting.js';
|
|
68
74
|
import '../lib/format.js';
|
|
75
|
+
import '../account/data-export-setting.js';
|
|
76
|
+
import '../components/account-chips.js';
|
|
77
|
+
import '../admin/admin-parts.js';
|
|
78
|
+
import '../admin/admin-action-log.js';
|
|
69
79
|
import '../components/reauth-dialog.js';
|
|
70
80
|
import '../components/server-wake.js';
|
|
71
81
|
import '../lib/server-wake.js';
|
|
@@ -79,12 +89,7 @@ import '../components/sign-chip.js';
|
|
|
79
89
|
import '../components/column-mapper.js';
|
|
80
90
|
import '../lib/column-mapping.js';
|
|
81
91
|
import '../lib/table-text.js';
|
|
82
|
-
import '
|
|
83
|
-
import '../theme/palette-presets.js';
|
|
84
|
-
import '../theme/chart-palette.js';
|
|
85
|
-
import '../theme/theme-store.js';
|
|
86
|
-
import 'zustand/middleware';
|
|
87
|
-
import 'zustand';
|
|
92
|
+
import '../components/field-parts.js';
|
|
88
93
|
|
|
89
94
|
interface AppShellSubItem {
|
|
90
95
|
to: string;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
import {
|
|
3
|
+
import { dS as KitLinkProps, dR as KitLinkComponent } from '../delete-account-setting-CGVMckMw.js';
|
|
4
|
+
import '../components/tooltip.js';
|
|
5
|
+
import '../hooks/use-anchored-rect.js';
|
|
6
|
+
import '../lib/clipping.js';
|
|
4
7
|
import '../data-table-labels-DUELeXpa.js';
|
|
5
8
|
import '../components/data-table-sort.js';
|
|
6
9
|
import '../components/swipeable-row.js';
|
|
@@ -10,10 +13,6 @@ import '../components/popover.js';
|
|
|
10
13
|
import '../components/chip.js';
|
|
11
14
|
import 'lucide-react';
|
|
12
15
|
import '../components/field-sync.js';
|
|
13
|
-
import '../components/tooltip.js';
|
|
14
|
-
import '../hooks/use-anchored-rect.js';
|
|
15
|
-
import '../lib/clipping.js';
|
|
16
|
-
import '../components/field-parts.js';
|
|
17
16
|
import '../wizard/types.js';
|
|
18
17
|
import '../tour/tour.js';
|
|
19
18
|
import '../search/command-palette.js';
|
|
@@ -56,6 +55,12 @@ import '../components/image-grid.js';
|
|
|
56
55
|
import '../components/lightbox.js';
|
|
57
56
|
import '../components/write-lock.js';
|
|
58
57
|
import '../auth/sign-in-form.js';
|
|
58
|
+
import './topbar-controls.js';
|
|
59
|
+
import '../theme/palette-presets.js';
|
|
60
|
+
import '../theme/chart-palette.js';
|
|
61
|
+
import '../theme/theme-store.js';
|
|
62
|
+
import 'zustand/middleware';
|
|
63
|
+
import 'zustand';
|
|
59
64
|
import '../auth/complete-name-dialog.js';
|
|
60
65
|
import '../auth/forgot-password-form.js';
|
|
61
66
|
import '../auth/status-parts.js';
|
|
@@ -64,8 +69,13 @@ import '../auth/verify-email.js';
|
|
|
64
69
|
import '../auth/not-found-page.js';
|
|
65
70
|
import '../auth/accept-invitation.js';
|
|
66
71
|
import './company-switcher.js';
|
|
67
|
-
import '../
|
|
72
|
+
import '../account/email-change-setting.js';
|
|
73
|
+
import '../account/sessions-setting.js';
|
|
68
74
|
import '../lib/format.js';
|
|
75
|
+
import '../account/data-export-setting.js';
|
|
76
|
+
import '../components/account-chips.js';
|
|
77
|
+
import '../admin/admin-parts.js';
|
|
78
|
+
import '../admin/admin-action-log.js';
|
|
69
79
|
import '../components/reauth-dialog.js';
|
|
70
80
|
import '../components/server-wake.js';
|
|
71
81
|
import '../lib/server-wake.js';
|
|
@@ -79,12 +89,7 @@ import '../components/sign-chip.js';
|
|
|
79
89
|
import '../components/column-mapper.js';
|
|
80
90
|
import '../lib/column-mapping.js';
|
|
81
91
|
import '../lib/table-text.js';
|
|
82
|
-
import '
|
|
83
|
-
import '../theme/palette-presets.js';
|
|
84
|
-
import '../theme/chart-palette.js';
|
|
85
|
-
import '../theme/theme-store.js';
|
|
86
|
-
import 'zustand/middleware';
|
|
87
|
-
import 'zustand';
|
|
92
|
+
import '../components/field-parts.js';
|
|
88
93
|
|
|
89
94
|
interface TopBarBrandProps extends Omit<KitLinkProps, "href" | "children"> {
|
|
90
95
|
/** The brand mark — an SVG, sized by the caller or `h-6 w-auto` by default. */
|
package/dist/shell.d.ts
CHANGED
|
@@ -13,7 +13,10 @@ import './theme/theme-store.js';
|
|
|
13
13
|
import 'zustand/middleware';
|
|
14
14
|
import 'zustand';
|
|
15
15
|
import 'lucide-react';
|
|
16
|
-
import './
|
|
16
|
+
import './delete-account-setting-CGVMckMw.js';
|
|
17
|
+
import './components/tooltip.js';
|
|
18
|
+
import './hooks/use-anchored-rect.js';
|
|
19
|
+
import './lib/clipping.js';
|
|
17
20
|
import './data-table-labels-DUELeXpa.js';
|
|
18
21
|
import './components/data-table-sort.js';
|
|
19
22
|
import './components/swipeable-row.js';
|
|
@@ -22,10 +25,6 @@ import './components/calendar-heatmap.js';
|
|
|
22
25
|
import './components/popover.js';
|
|
23
26
|
import './components/chip.js';
|
|
24
27
|
import './components/field-sync.js';
|
|
25
|
-
import './components/tooltip.js';
|
|
26
|
-
import './hooks/use-anchored-rect.js';
|
|
27
|
-
import './lib/clipping.js';
|
|
28
|
-
import './components/field-parts.js';
|
|
29
28
|
import './wizard/types.js';
|
|
30
29
|
import './tour/tour.js';
|
|
31
30
|
import './search/command-palette.js';
|
|
@@ -74,8 +73,13 @@ import './auth/verify-email.js';
|
|
|
74
73
|
import './auth/not-found-page.js';
|
|
75
74
|
import './auth/accept-invitation.js';
|
|
76
75
|
import './shell/company-switcher.js';
|
|
77
|
-
import './
|
|
76
|
+
import './account/email-change-setting.js';
|
|
77
|
+
import './account/sessions-setting.js';
|
|
78
78
|
import './lib/format.js';
|
|
79
|
+
import './account/data-export-setting.js';
|
|
80
|
+
import './components/account-chips.js';
|
|
81
|
+
import './admin/admin-parts.js';
|
|
82
|
+
import './admin/admin-action-log.js';
|
|
79
83
|
import './components/reauth-dialog.js';
|
|
80
84
|
import './components/server-wake.js';
|
|
81
85
|
import './lib/server-wake.js';
|
|
@@ -89,4 +93,5 @@ import './components/sign-chip.js';
|
|
|
89
93
|
import './components/column-mapper.js';
|
|
90
94
|
import './lib/column-mapping.js';
|
|
91
95
|
import './lib/table-text.js';
|
|
96
|
+
import './components/field-parts.js';
|
|
92
97
|
import './components/menu-item.js';
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode, ReactElement } from 'react';
|
|
3
|
-
import {
|
|
3
|
+
import { bH as ButtonVariant } from '../delete-account-setting-CGVMckMw.js';
|
|
4
4
|
import { UseWizardReturn, WizardLabels } from './types.js';
|
|
5
|
+
import '../components/tooltip.js';
|
|
6
|
+
import '../hooks/use-anchored-rect.js';
|
|
7
|
+
import '../lib/clipping.js';
|
|
5
8
|
import '../data-table-labels-DUELeXpa.js';
|
|
6
9
|
import '../components/data-table-sort.js';
|
|
7
10
|
import '../components/swipeable-row.js';
|
|
@@ -11,10 +14,6 @@ import '../components/popover.js';
|
|
|
11
14
|
import '../components/chip.js';
|
|
12
15
|
import 'lucide-react';
|
|
13
16
|
import '../components/field-sync.js';
|
|
14
|
-
import '../components/tooltip.js';
|
|
15
|
-
import '../hooks/use-anchored-rect.js';
|
|
16
|
-
import '../lib/clipping.js';
|
|
17
|
-
import '../components/field-parts.js';
|
|
18
17
|
import '../tour/tour.js';
|
|
19
18
|
import '../search/command-palette.js';
|
|
20
19
|
import '../search/global-search.js';
|
|
@@ -56,6 +55,12 @@ import '../components/image-grid.js';
|
|
|
56
55
|
import '../components/lightbox.js';
|
|
57
56
|
import '../components/write-lock.js';
|
|
58
57
|
import '../auth/sign-in-form.js';
|
|
58
|
+
import '../shell/topbar-controls.js';
|
|
59
|
+
import '../theme/palette-presets.js';
|
|
60
|
+
import '../theme/chart-palette.js';
|
|
61
|
+
import '../theme/theme-store.js';
|
|
62
|
+
import 'zustand/middleware';
|
|
63
|
+
import 'zustand';
|
|
59
64
|
import '../auth/complete-name-dialog.js';
|
|
60
65
|
import '../auth/forgot-password-form.js';
|
|
61
66
|
import '../auth/status-parts.js';
|
|
@@ -64,8 +69,13 @@ import '../auth/verify-email.js';
|
|
|
64
69
|
import '../auth/not-found-page.js';
|
|
65
70
|
import '../auth/accept-invitation.js';
|
|
66
71
|
import '../shell/company-switcher.js';
|
|
67
|
-
import '../
|
|
72
|
+
import '../account/email-change-setting.js';
|
|
73
|
+
import '../account/sessions-setting.js';
|
|
68
74
|
import '../lib/format.js';
|
|
75
|
+
import '../account/data-export-setting.js';
|
|
76
|
+
import '../components/account-chips.js';
|
|
77
|
+
import '../admin/admin-parts.js';
|
|
78
|
+
import '../admin/admin-action-log.js';
|
|
69
79
|
import '../components/reauth-dialog.js';
|
|
70
80
|
import '../components/server-wake.js';
|
|
71
81
|
import '../lib/server-wake.js';
|
|
@@ -79,12 +89,7 @@ import '../components/sign-chip.js';
|
|
|
79
89
|
import '../components/column-mapper.js';
|
|
80
90
|
import '../lib/column-mapping.js';
|
|
81
91
|
import '../lib/table-text.js';
|
|
82
|
-
import '../
|
|
83
|
-
import '../theme/palette-presets.js';
|
|
84
|
-
import '../theme/chart-palette.js';
|
|
85
|
-
import '../theme/theme-store.js';
|
|
86
|
-
import 'zustand/middleware';
|
|
87
|
-
import 'zustand';
|
|
92
|
+
import '../components/field-parts.js';
|
|
88
93
|
|
|
89
94
|
/**
|
|
90
95
|
* The chrome around a wizard: the step indicator, the step content, and the
|
package/dist/wizard.d.ts
CHANGED
|
@@ -6,7 +6,10 @@ export { WizardStep, WizardStepProps } from './wizard/wizard-step.js';
|
|
|
6
6
|
export { WizardSummary } from './wizard/wizard-summary.js';
|
|
7
7
|
export { StepperNav } from './wizard/stepper-nav.js';
|
|
8
8
|
import 'react';
|
|
9
|
-
import './
|
|
9
|
+
import './delete-account-setting-CGVMckMw.js';
|
|
10
|
+
import './components/tooltip.js';
|
|
11
|
+
import './hooks/use-anchored-rect.js';
|
|
12
|
+
import './lib/clipping.js';
|
|
10
13
|
import './data-table-labels-DUELeXpa.js';
|
|
11
14
|
import './components/data-table-sort.js';
|
|
12
15
|
import './components/swipeable-row.js';
|
|
@@ -16,10 +19,6 @@ import './components/popover.js';
|
|
|
16
19
|
import './components/chip.js';
|
|
17
20
|
import 'lucide-react';
|
|
18
21
|
import './components/field-sync.js';
|
|
19
|
-
import './components/tooltip.js';
|
|
20
|
-
import './hooks/use-anchored-rect.js';
|
|
21
|
-
import './lib/clipping.js';
|
|
22
|
-
import './components/field-parts.js';
|
|
23
22
|
import './tour/tour.js';
|
|
24
23
|
import './search/command-palette.js';
|
|
25
24
|
import './search/global-search.js';
|
|
@@ -61,6 +60,12 @@ import './components/image-grid.js';
|
|
|
61
60
|
import './components/lightbox.js';
|
|
62
61
|
import './components/write-lock.js';
|
|
63
62
|
import './auth/sign-in-form.js';
|
|
63
|
+
import './shell/topbar-controls.js';
|
|
64
|
+
import './theme/palette-presets.js';
|
|
65
|
+
import './theme/chart-palette.js';
|
|
66
|
+
import './theme/theme-store.js';
|
|
67
|
+
import 'zustand/middleware';
|
|
68
|
+
import 'zustand';
|
|
64
69
|
import './auth/complete-name-dialog.js';
|
|
65
70
|
import './auth/forgot-password-form.js';
|
|
66
71
|
import './auth/status-parts.js';
|
|
@@ -69,8 +74,13 @@ import './auth/verify-email.js';
|
|
|
69
74
|
import './auth/not-found-page.js';
|
|
70
75
|
import './auth/accept-invitation.js';
|
|
71
76
|
import './shell/company-switcher.js';
|
|
72
|
-
import './
|
|
77
|
+
import './account/email-change-setting.js';
|
|
78
|
+
import './account/sessions-setting.js';
|
|
73
79
|
import './lib/format.js';
|
|
80
|
+
import './account/data-export-setting.js';
|
|
81
|
+
import './components/account-chips.js';
|
|
82
|
+
import './admin/admin-parts.js';
|
|
83
|
+
import './admin/admin-action-log.js';
|
|
74
84
|
import './components/reauth-dialog.js';
|
|
75
85
|
import './components/server-wake.js';
|
|
76
86
|
import './lib/server-wake.js';
|
|
@@ -84,9 +94,4 @@ import './components/sign-chip.js';
|
|
|
84
94
|
import './components/column-mapper.js';
|
|
85
95
|
import './lib/column-mapping.js';
|
|
86
96
|
import './lib/table-text.js';
|
|
87
|
-
import './
|
|
88
|
-
import './theme/palette-presets.js';
|
|
89
|
-
import './theme/chart-palette.js';
|
|
90
|
-
import './theme/theme-store.js';
|
|
91
|
-
import 'zustand/middleware';
|
|
92
|
-
import 'zustand';
|
|
97
|
+
import './components/field-parts.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eifi1/ui-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.30.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "App-agnostic shared design system: domain-free React components, theme and tokens.",
|
|
6
6
|
"_sideEffects": "The barrel (src/index.ts) re-exports EVERY component, including components/chart, which statically imports recharts. Without this field a bundler must assume each of those modules has side effects, so it cannot drop the unused ones: importing a Button from '@eifi1/ui-kit' dragged all 433KB of recharts into the consumer's ENTRY chunk, and Keksdose was preloading it on every page load, login included. Nothing in src/ imports for side effects (no bare imports, no CSS imports from JS, no module-level global writes) — the token stylesheet is its own './tokens.css' export — so this is safe. CSS is still listed so any future stylesheet survives. Re-checked when `flag-icons` left `dependencies` and tsup started emitting a `\"use client\"` banner: neither touches this. The flag stylesheet was never imported from JS in the first place (that was the finding), and a directive prologue is a string literal every bundler lifts out before it decides whether a module is inert.",
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { useEffect, useRef } from "react";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* What the account's own settings parts share (docs/user-admin-harmonization.md §6):
|
|
5
|
+
* the companies a refusal names, a mounted guard, and the card's type.
|
|
6
|
+
*
|
|
7
|
+
* @internal Not part of the barrel; the parts are.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
type Bag = Record<string, unknown>;
|
|
11
|
+
|
|
12
|
+
const isBag = (value: unknown): value is Bag => typeof value === "object" && value !== null;
|
|
13
|
+
|
|
14
|
+
/** `companies` on a parsed body, or under FastAPI's nested `detail`: a list of names. */
|
|
15
|
+
function companiesOfBody(body: unknown): string[] | undefined {
|
|
16
|
+
if (!isBag(body)) return undefined;
|
|
17
|
+
const pick = (value: unknown) =>
|
|
18
|
+
Array.isArray(value) && value.length > 0 && value.every((item) => typeof item === "string")
|
|
19
|
+
? (value as string[])
|
|
20
|
+
: undefined;
|
|
21
|
+
return pick(body.companies) ?? (isBag(body.detail) ? pick(body.detail.companies) : undefined);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The companies a `last_admin` refusal names — kastlan checks the last admin per company
|
|
26
|
+
* and answers `409 {detail, code: "last_admin", companies: ["Example AG"]}` (§6.4,
|
|
27
|
+
* server-kit's `AccountError(…, extra={"companies": …})`). Read where `authErrorCode`
|
|
28
|
+
* reads the code: axios' `response.data`, ofetch's `data`, a generated client's `body`,
|
|
29
|
+
* a body thrown as it came. `undefined` when there is no such list.
|
|
30
|
+
*/
|
|
31
|
+
export function refusalCompanies(err: unknown): string[] | undefined {
|
|
32
|
+
if (!isBag(err)) return undefined;
|
|
33
|
+
const response = err.response;
|
|
34
|
+
return (
|
|
35
|
+
(isBag(response) ? companiesOfBody(response.data) : undefined) ??
|
|
36
|
+
companiesOfBody(err.data) ??
|
|
37
|
+
companiesOfBody(err.body) ??
|
|
38
|
+
companiesOfBody(err)
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Whether the component is still mounted — a late answer after the app navigated away
|
|
43
|
+
* (the deletion signs out) must not set state. */
|
|
44
|
+
export function useMounted(): { readonly current: boolean } {
|
|
45
|
+
const mounted = useRef(true);
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
mounted.current = true;
|
|
48
|
+
return () => {
|
|
49
|
+
mounted.current = false;
|
|
50
|
+
};
|
|
51
|
+
}, []);
|
|
52
|
+
return mounted;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Call `call` and hand back a promise, a throw included — a callback may return
|
|
56
|
+
* nothing (done at once), a promise, or throw before it returns one. */
|
|
57
|
+
export function settle(call: () => unknown): Promise<unknown> {
|
|
58
|
+
try {
|
|
59
|
+
return Promise.resolve(call());
|
|
60
|
+
} catch (error) {
|
|
61
|
+
return Promise.reject(error);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** The settings cards' type scale, PasskeysSetting's: a small title and a muted line. */
|
|
66
|
+
export const CARD_TITLE_CLASS = "text-sm font-medium";
|
|
67
|
+
export const CARD_DESCRIPTION_CLASS = "text-xs text-[var(--text-muted)]";
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
import type { ComponentPropsWithoutRef, ReactNode } from "react";
|
|
3
|
+
import { Download } from "lucide-react";
|
|
4
|
+
|
|
5
|
+
import { useKitLabels } from "../i18n/kit-labels";
|
|
6
|
+
import { cn } from "../lib/cn";
|
|
7
|
+
import { AlertBanner } from "../components/alert-banner";
|
|
8
|
+
import { hasMessage } from "../components/choice-parts";
|
|
9
|
+
import { TextLink } from "../components/text-link";
|
|
10
|
+
import { Button, Card } from "../components/ui";
|
|
11
|
+
import { englishWait, isRateLimited, retryAfterSeconds } from "../auth/auth-errors";
|
|
12
|
+
import { CARD_DESCRIPTION_CLASS, CARD_TITLE_CLASS, settle, useMounted } from "./account-parts";
|
|
13
|
+
|
|
14
|
+
/* ── Labels ──────────────────────────────────────────────────────────────── */
|
|
15
|
+
|
|
16
|
+
/** Every string {@link DataExportSetting} renders — the `dataExport` namespace of
|
|
17
|
+
* `<UiKitProvider labels>`, overridable per instance through `labels`. */
|
|
18
|
+
export interface DataExportLabels {
|
|
19
|
+
/** The card's title. */
|
|
20
|
+
title: string;
|
|
21
|
+
/** What the download is. The app's own sentence (`description`) follows it. */
|
|
22
|
+
description: string;
|
|
23
|
+
/** The button. */
|
|
24
|
+
download: string;
|
|
25
|
+
/** Said once the file was handed to the browser. */
|
|
26
|
+
started: string;
|
|
27
|
+
/** The link under it that saves the same file again, for a browser that held the
|
|
28
|
+
* download back. */
|
|
29
|
+
saveAgain: string;
|
|
30
|
+
/** The export was throttled — HTTP 429 (§6.5: once a minute) — given its
|
|
31
|
+
* `Retry-After` wait in seconds, or `undefined` without one. */
|
|
32
|
+
rateLimited: (seconds?: number) => string;
|
|
33
|
+
/** Any other failure. */
|
|
34
|
+
failed: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const DEFAULT_DATA_EXPORT_LABELS: DataExportLabels = {
|
|
38
|
+
title: "Export your data",
|
|
39
|
+
description: "Download a copy of your account’s data as a JSON file.",
|
|
40
|
+
download: "Download my data",
|
|
41
|
+
started: "Your download has started.",
|
|
42
|
+
saveAgain: "Didn’t start? Save the file",
|
|
43
|
+
rateLimited: (seconds) =>
|
|
44
|
+
seconds && seconds > 0
|
|
45
|
+
? `You exported your data a moment ago. Try again in ${englishWait(seconds)}.`
|
|
46
|
+
: "You exported your data a moment ago. Please try again in a minute.",
|
|
47
|
+
failed: "The export failed. Please try again.",
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/* ── Props ───────────────────────────────────────────────────────────────── */
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* What {@link DataExportSettingProps.onExport} resolves with: the file itself — a `Blob`
|
|
54
|
+
* (axios' `responseType: "blob"`, `await res.blob()`) — or a URL the browser fetches
|
|
55
|
+
* itself (a signed link), with the file name to save it under.
|
|
56
|
+
*/
|
|
57
|
+
export type DataExportFile = Blob | { url: string; filename?: string };
|
|
58
|
+
|
|
59
|
+
export interface DataExportSettingProps extends Omit<ComponentPropsWithoutRef<"div">, "children"> {
|
|
60
|
+
/**
|
|
61
|
+
* Fetch the export (`GET /auth/me/export`, §6.5). Resolve with the file — the card
|
|
62
|
+
* saves it under `filename` — or reject with the client's error: a 429 (the export is
|
|
63
|
+
* throttled to once a minute) says `rateLimited`, anything else (a demo account's 403)
|
|
64
|
+
* goes through `describeError`, else `failed`.
|
|
65
|
+
*/
|
|
66
|
+
onExport: () => Promise<DataExportFile>;
|
|
67
|
+
/**
|
|
68
|
+
* The app's sentence under the kit's — what the export holds and what it doesn't.
|
|
69
|
+
* kastlan's: "Your account; your company's records are your company's, ask them."
|
|
70
|
+
*/
|
|
71
|
+
description?: ReactNode;
|
|
72
|
+
/** The name the file is saved under. Default `account-export-YYYY-MM-DD.json` (the
|
|
73
|
+
* local day); a `{ url, filename }` answer's own name wins. */
|
|
74
|
+
filename?: string;
|
|
75
|
+
/** The app's own words for a failure, or `undefined` for the kit's. Asked first. */
|
|
76
|
+
describeError?: (error: unknown) => ReactNode | undefined;
|
|
77
|
+
labels?: Partial<DataExportLabels>;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
interface Saved {
|
|
81
|
+
href: string;
|
|
82
|
+
filename: string;
|
|
83
|
+
/** An object URL of ours, revoked when it is replaced or the card goes. */
|
|
84
|
+
owned: boolean;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** `account-export-2026-10-07.json`, the local day — the one a person looks for. */
|
|
88
|
+
function defaultFilename(now = new Date()): string {
|
|
89
|
+
const pad = (n: number) => String(n).padStart(2, "0");
|
|
90
|
+
return `account-export-${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}.json`;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** A `{ url }` answer, as opposed to a Blob or anything else. */
|
|
94
|
+
function isUrlAnswer(value: unknown): value is { url: string; filename?: string } {
|
|
95
|
+
return typeof value === "object" && value !== null && typeof (value as { url?: unknown }).url === "string";
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** Hand `href` to the browser as a download named `filename`: a link with `download`,
|
|
99
|
+
* clicked once and taken out again — the one way a page saves a file without a new
|
|
100
|
+
* tab that would show the JSON instead. */
|
|
101
|
+
function startDownload(href: string, filename: string) {
|
|
102
|
+
const link = document.createElement("a");
|
|
103
|
+
link.href = href;
|
|
104
|
+
link.download = filename;
|
|
105
|
+
link.rel = "noopener";
|
|
106
|
+
link.hidden = true;
|
|
107
|
+
document.body.appendChild(link);
|
|
108
|
+
link.click();
|
|
109
|
+
link.remove();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* The account's data as a download (docs/user-admin-harmonization.md §6.5, §2.2): what it
|
|
114
|
+
* is, the app's sentence on what it holds, and one button.
|
|
115
|
+
*
|
|
116
|
+
* **The kit saves the file.** `onExport` fetches it — the request is the app's, with its
|
|
117
|
+
* auth (auth §8) — and resolves with a `Blob` or a `{ url }`; the card hands it to the
|
|
118
|
+
* browser through a link with a `download` name, so it lands as `account-export-….json`
|
|
119
|
+
* rather than opening as a page of JSON. A `Blob` becomes an object URL, revoked when
|
|
120
|
+
* the next export replaces it or the card unmounts.
|
|
121
|
+
*
|
|
122
|
+
* The click comes after an `await`, which some browsers count as no longer the
|
|
123
|
+
* person's: "Didn't start? Save the file" stays under the confirmation, a real link to
|
|
124
|
+
* the same file that the person clicks themselves.
|
|
125
|
+
*
|
|
126
|
+
* **The throttle** (once a minute, §6.5) is a 429, said as such; the app's
|
|
127
|
+
* `describeError` comes first (keksdose's demo account answers 403).
|
|
128
|
+
*/
|
|
129
|
+
export function DataExportSetting({
|
|
130
|
+
onExport,
|
|
131
|
+
description,
|
|
132
|
+
filename,
|
|
133
|
+
describeError,
|
|
134
|
+
labels: labelsProp,
|
|
135
|
+
className,
|
|
136
|
+
...rest
|
|
137
|
+
}: DataExportSettingProps) {
|
|
138
|
+
const labels = useKitLabels("dataExport", DEFAULT_DATA_EXPORT_LABELS, labelsProp);
|
|
139
|
+
const [busy, setBusy] = useState(false);
|
|
140
|
+
const [saved, setSaved] = useState<Saved | null>(null);
|
|
141
|
+
const [failure, setFailure] = useState<ReactNode>(null);
|
|
142
|
+
const mounted = useMounted();
|
|
143
|
+
|
|
144
|
+
// Our object URL lives as long as the "Save the file" link that points at it.
|
|
145
|
+
useEffect(() => {
|
|
146
|
+
if (!saved?.owned) return;
|
|
147
|
+
const href = saved.href;
|
|
148
|
+
return () => URL.revokeObjectURL(href);
|
|
149
|
+
}, [saved]);
|
|
150
|
+
|
|
151
|
+
const run = () => {
|
|
152
|
+
if (busy) return;
|
|
153
|
+
setBusy(true);
|
|
154
|
+
setFailure(null);
|
|
155
|
+
// The last file's link goes (and its object URL with it): it would sit beside this
|
|
156
|
+
// export's answer as if it were it.
|
|
157
|
+
setSaved(null);
|
|
158
|
+
settle(onExport).then(
|
|
159
|
+
(answer) => {
|
|
160
|
+
if (!mounted.current) return;
|
|
161
|
+
setBusy(false);
|
|
162
|
+
let next: Saved;
|
|
163
|
+
if (answer instanceof Blob) {
|
|
164
|
+
next = { href: URL.createObjectURL(answer), filename: filename ?? defaultFilename(), owned: true };
|
|
165
|
+
} else if (isUrlAnswer(answer)) {
|
|
166
|
+
next = { href: answer.url, filename: answer.filename ?? filename ?? defaultFilename(), owned: false };
|
|
167
|
+
} else {
|
|
168
|
+
// Nothing to save: an app that resolved with its response object, say.
|
|
169
|
+
setFailure(labels.failed);
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
setSaved(next);
|
|
173
|
+
startDownload(next.href, next.filename);
|
|
174
|
+
},
|
|
175
|
+
(error: unknown) => {
|
|
176
|
+
if (!mounted.current) return;
|
|
177
|
+
setBusy(false);
|
|
178
|
+
const own = describeError?.(error);
|
|
179
|
+
setFailure(
|
|
180
|
+
hasMessage(own) ? own : isRateLimited(error) ? labels.rateLimited(retryAfterSeconds(error)) : labels.failed,
|
|
181
|
+
);
|
|
182
|
+
},
|
|
183
|
+
);
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
return (
|
|
187
|
+
<Card {...rest} className={cn("p-4 space-y-3", className)}>
|
|
188
|
+
<div className="space-y-1">
|
|
189
|
+
<div className={CARD_TITLE_CLASS}>{labels.title}</div>
|
|
190
|
+
<div className={CARD_DESCRIPTION_CLASS}>{labels.description}</div>
|
|
191
|
+
{hasMessage(description) && <div className={CARD_DESCRIPTION_CLASS}>{description}</div>}
|
|
192
|
+
</div>
|
|
193
|
+
<div className="flex flex-wrap items-center gap-x-3 gap-y-2">
|
|
194
|
+
<Button type="button" variant="secondary" pending={busy} onClick={run}>
|
|
195
|
+
<Download aria-hidden className="size-4" />
|
|
196
|
+
{labels.download}
|
|
197
|
+
</Button>
|
|
198
|
+
{/* Always in the tree, so the confirmation that appears in it is announced; in
|
|
199
|
+
the button's row, so an empty one takes no line of its own. */}
|
|
200
|
+
<span role="status" className="text-xs text-[var(--text-secondary)]">
|
|
201
|
+
{saved && (
|
|
202
|
+
<>
|
|
203
|
+
{labels.started}{" "}
|
|
204
|
+
<TextLink href={saved.href} download={saved.filename} reloadDocument tone="secondary">
|
|
205
|
+
{labels.saveAgain}
|
|
206
|
+
</TextLink>
|
|
207
|
+
</>
|
|
208
|
+
)}
|
|
209
|
+
</span>
|
|
210
|
+
</div>
|
|
211
|
+
{hasMessage(failure) && (
|
|
212
|
+
<AlertBanner tone="danger" size="sm" role="alert">
|
|
213
|
+
{failure}
|
|
214
|
+
</AlertBanner>
|
|
215
|
+
)}
|
|
216
|
+
</Card>
|
|
217
|
+
);
|
|
218
|
+
}
|