@eifi1/ui-kit 0.10.0 → 0.12.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 +66 -37
- package/dist/chart.d.ts +3 -1
- package/dist/chart.js +2 -0
- package/dist/chart.js.map +1 -1
- package/dist/components/account-settings-labels.d.ts +105 -0
- package/dist/components/account-settings-labels.js +81 -0
- package/dist/components/account-settings-labels.js.map +1 -0
- package/dist/components/account-settings.d.ts +36 -52
- package/dist/components/account-settings.js +44 -8
- package/dist/components/account-settings.js.map +1 -1
- package/dist/components/alert-banner.d.ts +26 -1
- package/dist/components/alert-banner.js +10 -7
- package/dist/components/alert-banner.js.map +1 -1
- package/dist/components/amount-input.d.ts +26 -4
- package/dist/components/amount-input.js +5 -2
- package/dist/components/amount-input.js.map +1 -1
- package/dist/components/authed-image.d.ts +68 -0
- package/dist/components/authed-image.js +117 -0
- package/dist/components/authed-image.js.map +1 -0
- package/dist/components/breadcrumbs.d.ts +2 -1
- package/dist/components/breadcrumbs.js +5 -2
- package/dist/components/breadcrumbs.js.map +1 -1
- package/dist/components/bulk-action-bar.d.ts +51 -5
- package/dist/components/bulk-action-bar.js +88 -41
- package/dist/components/bulk-action-bar.js.map +1 -1
- package/dist/components/button-group.d.ts +107 -3
- package/dist/components/button-group.js +60 -5
- package/dist/components/button-group.js.map +1 -1
- package/dist/components/calculator.d.ts +17 -4
- package/dist/components/calendar-heatmap.d.ts +162 -0
- package/dist/components/calendar-heatmap.js +336 -0
- package/dist/components/calendar-heatmap.js.map +1 -0
- package/dist/components/chip.d.ts +2 -1
- package/dist/components/chip.js +6 -3
- package/dist/components/chip.js.map +1 -1
- package/dist/components/choice-card.d.ts +66 -2
- package/dist/components/choice-card.js +108 -1
- package/dist/components/choice-card.js.map +1 -1
- package/dist/components/combobox-core.js +2 -0
- package/dist/components/combobox-core.js.map +1 -1
- package/dist/components/combobox.d.ts +2 -2
- package/dist/components/combobox.js +31 -9
- package/dist/components/combobox.js.map +1 -1
- package/dist/components/copy-button.d.ts +52 -70
- package/dist/components/copy-button.js +1 -1
- package/dist/components/copy-button.js.map +1 -1
- package/dist/components/data-table-cells.d.ts +63 -0
- package/dist/components/data-table-cells.js +64 -0
- package/dist/components/data-table-cells.js.map +1 -0
- package/dist/components/data-table-filter-popover.d.ts +1 -1
- package/dist/components/data-table-filters.d.ts +1 -1
- package/dist/components/data-table-filters.js +31 -1
- package/dist/components/data-table-filters.js.map +1 -1
- package/dist/components/data-table-labels.d.ts +13 -0
- package/dist/components/data-table-labels.js +8 -1
- package/dist/components/data-table-labels.js.map +1 -1
- package/dist/components/data-table.d.ts +1 -1
- package/dist/components/data-table.js +104 -12
- package/dist/components/data-table.js.map +1 -1
- package/dist/components/date-picker.d.ts +3 -1
- package/dist/components/date-picker.js +15 -2
- package/dist/components/date-picker.js.map +1 -1
- package/dist/components/description-list.d.ts +23 -3
- package/dist/components/description-list.js +23 -3
- package/dist/components/description-list.js.map +1 -1
- package/dist/components/dialog-frame.d.ts +1 -0
- package/dist/components/entity-combobox.d.ts +1 -1
- package/dist/components/entity-combobox.js +18 -3
- package/dist/components/entity-combobox.js.map +1 -1
- package/dist/components/error-boundary.d.ts +92 -0
- package/dist/components/error-boundary.js +111 -0
- package/dist/components/error-boundary.js.map +1 -0
- package/dist/components/field.d.ts +69 -0
- package/dist/components/field.js +75 -0
- package/dist/components/field.js.map +1 -0
- package/dist/components/file-button.d.ts +51 -208
- package/dist/components/file-dropzone.d.ts +50 -2
- package/dist/components/floating-panel.d.ts +156 -4
- package/dist/components/floating-panel.js +193 -29
- package/dist/components/floating-panel.js.map +1 -1
- package/dist/components/form-actions.d.ts +53 -0
- package/dist/components/form-actions.js +98 -0
- package/dist/components/form-actions.js.map +1 -0
- package/dist/components/image-grid.d.ts +67 -0
- package/dist/components/image-grid.js +112 -0
- package/dist/components/image-grid.js.map +1 -0
- package/dist/components/lightbox.d.ts +104 -0
- package/dist/components/lightbox.js +229 -0
- package/dist/components/lightbox.js.map +1 -0
- package/dist/components/line-items.d.ts +114 -0
- package/dist/components/line-items.js +238 -0
- package/dist/components/line-items.js.map +1 -0
- package/dist/components/list.d.ts +37 -3
- package/dist/components/list.js +39 -14
- package/dist/components/list.js.map +1 -1
- package/dist/components/loading-state.d.ts +24 -0
- package/dist/components/loading-state.js +32 -0
- package/dist/components/loading-state.js.map +1 -0
- package/dist/components/menu-item.d.ts +13 -2
- package/dist/components/menu-item.js +11 -2
- package/dist/components/menu-item.js.map +1 -1
- package/dist/components/mini-calendar.d.ts +82 -5
- package/dist/components/mini-calendar.js +212 -64
- package/dist/components/mini-calendar.js.map +1 -1
- package/dist/components/modal.d.ts +20 -1
- package/dist/components/modal.js +26 -2
- package/dist/components/modal.js.map +1 -1
- package/dist/components/month-picker.d.ts +21 -1
- package/dist/components/month-picker.js +139 -26
- package/dist/components/month-picker.js.map +1 -1
- package/dist/components/multi-entity-combobox.d.ts +1 -1
- package/dist/components/multi-entity-combobox.js +19 -3
- package/dist/components/multi-entity-combobox.js.map +1 -1
- package/dist/components/nav-pills.d.ts +67 -0
- package/dist/components/nav-pills.js +69 -0
- package/dist/components/nav-pills.js.map +1 -0
- package/dist/components/number-field.d.ts +26 -5
- package/dist/components/number-field.js +5 -7
- package/dist/components/number-field.js.map +1 -1
- package/dist/components/number-input.d.ts +27 -5
- package/dist/components/number-input.js +7 -1
- package/dist/components/number-input.js.map +1 -1
- package/dist/components/numpad-sheet.d.ts +17 -4
- package/dist/components/passkeys-setting.d.ts +67 -0
- package/dist/components/passkeys-setting.js +214 -0
- package/dist/components/passkeys-setting.js.map +1 -0
- package/dist/components/picker-sheet.js +2 -1
- package/dist/components/picker-sheet.js.map +1 -1
- package/dist/components/pie-chart-labels.d.ts +20 -0
- package/dist/components/pie-chart-labels.js +12 -0
- package/dist/components/pie-chart-labels.js.map +1 -0
- package/dist/components/pie-chart.d.ts +101 -0
- package/dist/components/pie-chart.js +283 -0
- package/dist/components/pie-chart.js.map +1 -0
- package/dist/components/progress-bar.d.ts +73 -3
- package/dist/components/progress-bar.js +110 -8
- package/dist/components/progress-bar.js.map +1 -1
- package/dist/components/qr-code.d.ts +34 -0
- package/dist/components/qr-code.js +57 -0
- package/dist/components/qr-code.js.map +1 -0
- package/dist/components/search-field.d.ts +15 -3
- package/dist/components/search-field.js +5 -1
- package/dist/components/search-field.js.map +1 -1
- package/dist/components/series-chart.d.ts +16 -0
- package/dist/components/series-chart.js +4 -1
- package/dist/components/series-chart.js.map +1 -1
- package/dist/components/settings-fields.d.ts +50 -1
- package/dist/components/signed-amount.d.ts +121 -0
- package/dist/components/signed-amount.js +152 -0
- package/dist/components/signed-amount.js.map +1 -0
- package/dist/components/skeleton.d.ts +10 -3
- package/dist/components/skeleton.js +12 -2
- package/dist/components/skeleton.js.map +1 -1
- package/dist/components/stat-tile.d.ts +2 -1
- package/dist/components/stat-tile.js +5 -2
- package/dist/components/stat-tile.js.map +1 -1
- package/dist/components/status-dot.d.ts +6 -2
- package/dist/components/status-dot.js +6 -1
- package/dist/components/status-dot.js.map +1 -1
- package/dist/components/table.d.ts +77 -11
- package/dist/components/table.js +85 -17
- package/dist/components/table.js.map +1 -1
- package/dist/components/text-link.d.ts +176 -0
- package/dist/components/text-link.js +109 -0
- package/dist/components/text-link.js.map +1 -0
- package/dist/components/text.d.ts +8 -1
- package/dist/components/text.js +1 -0
- package/dist/components/text.js.map +1 -1
- package/dist/components/time-input.d.ts +50 -1
- package/dist/components/toggle-group.d.ts +28 -0
- package/dist/components/toggle-group.js +58 -9
- package/dist/components/toggle-group.js.map +1 -1
- package/dist/components/toggle-legend.d.ts +36 -3
- package/dist/components/toggle-legend.js +49 -0
- package/dist/components/toggle-legend.js.map +1 -1
- package/dist/components/tooltip.d.ts +11 -3
- package/dist/components/tooltip.js +2 -0
- package/dist/components/tooltip.js.map +1 -1
- package/dist/components/ui.d.ts +52 -729
- package/dist/components/ui.js +296 -27
- package/dist/components/ui.js.map +1 -1
- package/dist/components/use-table-state.d.ts +3 -52
- package/dist/components/use-table-state.js +128 -30
- package/dist/components/use-table-state.js.map +1 -1
- package/dist/components/user-avatar.d.ts +25 -3
- package/dist/components/user-avatar.js +32 -3
- package/dist/components/user-avatar.js.map +1 -1
- package/dist/{data-table-filters-Dh9uF_S-.d.ts → data-table-Drun8Fk9.d.ts} +305 -61
- package/dist/data-table.d.ts +2 -1
- package/dist/data-table.js +5 -1
- package/dist/data-table.js.map +1 -1
- package/dist/feedback/feedback-dialog.d.ts +26 -3
- package/dist/feedback/feedback-dialog.js +16 -2
- package/dist/feedback/feedback-dialog.js.map +1 -1
- package/dist/feedback/feedback-thread.d.ts +133 -0
- package/dist/feedback/feedback-thread.js +237 -0
- package/dist/feedback/feedback-thread.js.map +1 -0
- package/dist/feedback.d.ts +2 -1
- package/dist/feedback.js +1 -0
- package/dist/feedback.js.map +1 -1
- package/dist/hooks/use-authed-src.d.ts +71 -0
- package/dist/hooks/use-authed-src.js +63 -0
- package/dist/hooks/use-authed-src.js.map +1 -0
- package/dist/hooks/use-file-drop.d.ts +50 -2
- package/dist/hooks/use-hotkey.d.ts +59 -0
- package/dist/hooks/use-hotkey.js +105 -0
- package/dist/hooks/use-hotkey.js.map +1 -0
- package/dist/hooks/use-search-param-state.d.ts +83 -0
- package/dist/hooks/use-search-param-state.js +94 -0
- package/dist/hooks/use-search-param-state.js.map +1 -0
- package/dist/i18n/defaults.d.ts +17 -4
- package/dist/i18n/defaults.js +33 -1
- package/dist/i18n/defaults.js.map +1 -1
- package/dist/i18n/kit-labels.d.ts +47 -310
- package/dist/i18n/kit-labels.js +20 -5
- package/dist/i18n/kit-labels.js.map +1 -1
- package/dist/i18n/locales/de-CH-informal.d.ts +17 -4
- package/dist/i18n/locales/de-CH.d.ts +17 -4
- package/dist/i18n/locales/de-informal.d.ts +17 -4
- package/dist/i18n/locales/de.d.ts +17 -4
- package/dist/i18n/locales/de.js +165 -4
- package/dist/i18n/locales/de.js.map +1 -1
- package/dist/i18n/locales/es.d.ts +17 -4
- package/dist/i18n/locales/es.js +162 -4
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.d.ts +17 -4
- package/dist/i18n/locales/fr.js +162 -4
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hu.d.ts +17 -4
- package/dist/i18n/locales/hu.js +162 -4
- package/dist/i18n/locales/hu.js.map +1 -1
- package/dist/i18n/locales/it.d.ts +17 -4
- package/dist/i18n/locales/it.js +162 -4
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/zh.d.ts +17 -4
- package/dist/i18n/locales/zh.js +162 -4
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/index.d.ts +45 -21
- package/dist/index.js +43 -1
- package/dist/index.js.map +1 -1
- package/dist/kit-labels-v3biUF1L.d.ts +1645 -0
- package/dist/lib/clipping.d.ts +21 -5
- package/dist/lib/clipping.js +3 -0
- package/dist/lib/clipping.js.map +1 -1
- package/dist/lib/dates.d.ts +17 -1
- package/dist/lib/dates.js +19 -0
- package/dist/lib/dates.js.map +1 -1
- package/dist/lib/format.d.ts +144 -0
- package/dist/lib/format.js +149 -0
- package/dist/lib/format.js.map +1 -0
- package/dist/lib/qr-encode.d.ts +44 -0
- package/dist/lib/qr-encode.js +338 -0
- package/dist/lib/qr-encode.js.map +1 -0
- package/dist/rhf/fields.d.ts +241 -0
- package/dist/rhf/fields.js +601 -0
- package/dist/rhf/fields.js.map +1 -0
- package/dist/rhf/form.d.ts +50 -1
- package/dist/rhf/line-items.d.ts +31 -0
- package/dist/rhf/line-items.js +59 -0
- package/dist/rhf/line-items.js.map +1 -0
- package/dist/rhf/use-rhf-wizard-step.d.ts +22 -0
- package/dist/rhf/use-rhf-wizard-step.js +38 -0
- package/dist/rhf/use-rhf-wizard-step.js.map +1 -0
- package/dist/rhf.d.ts +63 -1
- package/dist/rhf.js +3 -0
- package/dist/rhf.js.map +1 -1
- package/dist/shell/app-shell.d.ts +99 -2
- package/dist/shell/app-shell.js +58 -3
- package/dist/shell/app-shell.js.map +1 -1
- package/dist/shell/auth-layout.d.ts +74 -0
- package/dist/shell/auth-layout.js +97 -0
- package/dist/shell/auth-layout.js.map +1 -0
- package/dist/shell/top-bar-brand.d.ts +81 -0
- package/dist/shell/top-bar-brand.js +47 -0
- package/dist/shell/top-bar-brand.js.map +1 -0
- package/dist/shell/topbar-action-menu.d.ts +84 -3
- package/dist/shell/topbar-action-menu.js +115 -27
- package/dist/shell/topbar-action-menu.js.map +1 -1
- package/dist/shell.d.ts +58 -2
- package/dist/shell.js +2 -0
- package/dist/shell.js.map +1 -1
- package/dist/wizard/stepper-nav.d.ts +49 -1
- package/dist/wizard/wizard-context.d.ts +30 -1
- package/dist/wizard/wizard-context.js +23 -2
- package/dist/wizard/wizard-context.js.map +1 -1
- package/dist/wizard/wizard-step.d.ts +20 -5
- package/dist/wizard/wizard-step.js +16 -3
- package/dist/wizard/wizard-step.js.map +1 -1
- package/dist/wizard.d.ts +51 -3
- package/package.json +1 -1
- package/src/chart.ts +4 -0
- package/src/components/account-settings-labels.ts +190 -0
- package/src/components/account-settings.tsx +110 -63
- package/src/components/alert-banner.tsx +36 -7
- package/src/components/amount-input.tsx +13 -1
- package/src/components/authed-image.tsx +190 -0
- package/src/components/breadcrumbs.tsx +8 -2
- package/src/components/bulk-action-bar.tsx +163 -57
- package/src/components/button-group.tsx +129 -4
- package/src/components/calendar-heatmap.tsx +599 -0
- package/src/components/chip.tsx +8 -4
- package/src/components/choice-card.tsx +208 -1
- package/src/components/combobox-core.tsx +5 -0
- package/src/components/combobox.tsx +31 -9
- package/src/components/copy-button.tsx +3 -2
- package/src/components/data-table-cells.tsx +119 -0
- package/src/components/data-table-filters.ts +77 -0
- package/src/components/data-table-labels.ts +23 -0
- package/src/components/data-table.tsx +231 -13
- package/src/components/date-picker.tsx +19 -3
- package/src/components/description-list.tsx +52 -3
- package/src/components/entity-combobox.tsx +18 -3
- package/src/components/error-boundary.tsx +216 -0
- package/src/components/field.tsx +188 -0
- package/src/components/floating-panel.tsx +380 -16
- package/src/components/form-actions.tsx +191 -0
- package/src/components/image-grid.tsx +181 -0
- package/src/components/lightbox.tsx +374 -0
- package/src/components/line-items.tsx +385 -0
- package/src/components/list.tsx +93 -18
- package/src/components/loading-state.tsx +47 -0
- package/src/components/menu-item.tsx +29 -3
- package/src/components/mini-calendar.tsx +317 -57
- package/src/components/modal.tsx +61 -3
- package/src/components/month-picker.tsx +181 -26
- package/src/components/multi-entity-combobox.tsx +19 -3
- package/src/components/nav-pills.tsx +152 -0
- package/src/components/number-field.tsx +15 -10
- package/src/components/number-input.tsx +16 -1
- package/src/components/passkeys-setting.tsx +331 -0
- package/src/components/picker-sheet.tsx +7 -1
- package/src/components/pie-chart-labels.ts +32 -0
- package/src/components/pie-chart.tsx +479 -0
- package/src/components/progress-bar.tsx +241 -13
- package/src/components/qr-code.tsx +83 -0
- package/src/components/search-field.tsx +20 -4
- package/src/components/series-chart.tsx +21 -0
- package/src/components/signed-amount.tsx +286 -0
- package/src/components/skeleton.tsx +21 -3
- package/src/components/stat-tile.tsx +8 -2
- package/src/components/status-dot.tsx +10 -2
- package/src/components/table.tsx +186 -23
- package/src/components/text-link.tsx +248 -0
- package/src/components/text.tsx +9 -1
- package/src/components/toggle-group.tsx +106 -13
- package/src/components/toggle-legend.tsx +87 -2
- package/src/components/tooltip.tsx +17 -3
- package/src/components/ui.tsx +572 -44
- package/src/components/use-table-state.ts +265 -33
- package/src/components/user-avatar.tsx +57 -3
- package/src/data-table.ts +10 -0
- package/src/feedback/feedback-dialog.tsx +42 -3
- package/src/feedback/feedback-thread.tsx +434 -0
- package/src/feedback.ts +1 -0
- package/src/hooks/use-authed-src.ts +161 -0
- package/src/hooks/use-hotkey.ts +172 -0
- package/src/hooks/use-search-param-state.ts +187 -0
- package/src/i18n/defaults.ts +32 -0
- package/src/i18n/kit-labels.tsx +104 -8
- package/src/i18n/locales/de.ts +162 -0
- package/src/i18n/locales/es.ts +159 -0
- package/src/i18n/locales/fr.ts +162 -0
- package/src/i18n/locales/hu.ts +160 -0
- package/src/i18n/locales/it.ts +160 -0
- package/src/i18n/locales/zh.ts +159 -0
- package/src/index.ts +64 -0
- package/src/lib/clipping.ts +22 -4
- package/src/lib/dates.ts +37 -0
- package/src/lib/format.ts +325 -0
- package/src/lib/qr-encode.ts +420 -0
- package/src/rhf/fields.tsx +1054 -0
- package/src/rhf/line-items.tsx +130 -0
- package/src/rhf/use-rhf-wizard-step.ts +113 -0
- package/src/rhf.ts +8 -0
- package/src/shell/app-shell.tsx +147 -2
- package/src/shell/auth-layout.tsx +190 -0
- package/src/shell/top-bar-brand.tsx +76 -0
- package/src/shell/topbar-action-menu.tsx +260 -49
- package/src/shell.ts +2 -0
- package/src/wizard/wizard-context.tsx +50 -1
- package/src/wizard/wizard-step.tsx +43 -6
- package/tokens.css +12 -0
|
@@ -6,6 +6,7 @@ import { cn } from "../lib/cn";
|
|
|
6
6
|
import { horizontalStep } from "../lib/direction";
|
|
7
7
|
import { useKitLabels } from "../i18n/kit-labels";
|
|
8
8
|
import { useAnnounce } from "../hooks/use-announce";
|
|
9
|
+
import { useMediaQuery } from "../hooks/use-media-query";
|
|
9
10
|
import { OVERLAY_EXIT_MS, prefersReducedMotion } from "../hooks/use-close-transition";
|
|
10
11
|
import { Button, IconButton } from "./ui";
|
|
11
12
|
|
|
@@ -34,16 +35,89 @@ export const DEFAULT_BULK_ACTION_BAR_LABELS: BulkActionBarLabels = {
|
|
|
34
35
|
*/
|
|
35
36
|
export type BulkActionBarVariant = "floating" | "sticky" | "inline";
|
|
36
37
|
|
|
38
|
+
/**
|
|
39
|
+
* A variant per breakpoint, mobile first — `{ base: "floating", md: "sticky" }` is the
|
|
40
|
+
* phone's floating card below 768px and the desktop's sticky bar from there up. The
|
|
41
|
+
* breakpoints are Tailwind's (sm 640, md 768, lg 1024, xl 1280px), the ones the kit's
|
|
42
|
+
* classes already use. keksdose's payees selection bar (payees-selection-bar.tsx)
|
|
43
|
+
* computes exactly this with its own `useMediaQuery("(min-width: 768px)")`; every bar
|
|
44
|
+
* that is a card on a phone and a strip on a desktop would repeat it.
|
|
45
|
+
*
|
|
46
|
+
* Resolved in JS rather than with `md:` classes because the variants differ in more
|
|
47
|
+
* than classes: the floating bar's clear is an icon at the start, the others' a text
|
|
48
|
+
* button at the end, and the floating bar is positioned by inline style.
|
|
49
|
+
*/
|
|
50
|
+
export interface ResponsiveBulkActionBarVariant {
|
|
51
|
+
base: BulkActionBarVariant;
|
|
52
|
+
sm?: BulkActionBarVariant;
|
|
53
|
+
md?: BulkActionBarVariant;
|
|
54
|
+
lg?: BulkActionBarVariant;
|
|
55
|
+
xl?: BulkActionBarVariant;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const BREAKPOINTS = [
|
|
59
|
+
["xl", "(min-width: 1280px)"],
|
|
60
|
+
["lg", "(min-width: 1024px)"],
|
|
61
|
+
["md", "(min-width: 768px)"],
|
|
62
|
+
["sm", "(min-width: 640px)"],
|
|
63
|
+
] as const;
|
|
64
|
+
|
|
65
|
+
/** The variant in force: the widest breakpoint that matches AND names one, else
|
|
66
|
+
* `base`. The four queries are subscribed unconditionally — hooks cannot be skipped —
|
|
67
|
+
* and a plain string variant simply ignores them. Without `matchMedia` (SSR, tests)
|
|
68
|
+
* every query is false, so the bar renders its `base`, the phone's, first. */
|
|
69
|
+
function useResolvedVariant(variant: BulkActionBarVariant | ResponsiveBulkActionBarVariant): BulkActionBarVariant {
|
|
70
|
+
const matches = {
|
|
71
|
+
xl: useMediaQuery(BREAKPOINTS[0][1], false),
|
|
72
|
+
lg: useMediaQuery(BREAKPOINTS[1][1], false),
|
|
73
|
+
md: useMediaQuery(BREAKPOINTS[2][1], false),
|
|
74
|
+
sm: useMediaQuery(BREAKPOINTS[3][1], false),
|
|
75
|
+
};
|
|
76
|
+
if (typeof variant === "string") return variant;
|
|
77
|
+
for (const [key] of BREAKPOINTS) {
|
|
78
|
+
const v = variant[key];
|
|
79
|
+
if (matches[key] && v !== undefined) return v;
|
|
80
|
+
}
|
|
81
|
+
return variant.base;
|
|
82
|
+
}
|
|
83
|
+
|
|
37
84
|
export interface BulkActionBarProps extends Omit<ComponentPropsWithoutRef<"div">, "role" | "children"> {
|
|
38
|
-
/** How many items are selected. The bar shows only while this is above zero
|
|
85
|
+
/** How many items are selected. The bar shows only while this is above zero —
|
|
86
|
+
* unless {@link open} says otherwise. */
|
|
39
87
|
count: number;
|
|
88
|
+
/**
|
|
89
|
+
* Show the bar regardless of `count` — `true` for SELECTION MODE with nothing picked
|
|
90
|
+
* yet, `false` to hide it with rows still selected. Left out, `count > 0` decides, as
|
|
91
|
+
* before.
|
|
92
|
+
*
|
|
93
|
+
* keksdose's invoice lines (invoice-lines-bulk-bar.tsx) enter selection with a
|
|
94
|
+
* "Select" button, and the bar must be there at "0 selected" to hold the way out and
|
|
95
|
+
* a "Select all" (pass it as a child); gated on the count, the bar appeared only at
|
|
96
|
+
* the first tick, and the user who pressed "Select" saw nothing happen. The exit plays
|
|
97
|
+
* when it closes either way, and the count is still announced on every change.
|
|
98
|
+
*/
|
|
99
|
+
open?: boolean;
|
|
40
100
|
/** Clear the selection / leave selection mode. */
|
|
41
101
|
onClear: () => void;
|
|
42
102
|
/** The actions: buttons (`IconButton size="lg"` on a phone, `Button` from md up),
|
|
43
103
|
* in the caller's order. They are the toolbar's arrow-key stops, after the clear. */
|
|
44
104
|
children?: ReactNode;
|
|
45
|
-
/** Default `floating`. See {@link BulkActionBarVariant}
|
|
46
|
-
|
|
105
|
+
/** Default `floating`. See {@link BulkActionBarVariant}; an object picks one per
|
|
106
|
+
* breakpoint, see {@link ResponsiveBulkActionBarVariant}. */
|
|
107
|
+
variant?: BulkActionBarVariant | ResponsiveBulkActionBarVariant;
|
|
108
|
+
/**
|
|
109
|
+
* Content BELOW the toolbar row, inside the same surface — the same floating card or
|
|
110
|
+
* sticky tinted strip — but OUTSIDE the toolbar: its fields keep their own Tab stops
|
|
111
|
+
* and arrow keys, and the toolbar's roving focus never walks into it. keksdose's
|
|
112
|
+
* desktop receipt-line bar (invoice-lines-bulk-bar.tsx) shows its `BulkFields` form —
|
|
113
|
+
* a category picker, an exclude checkbox, Apply — under the count and the clear; a
|
|
114
|
+
* form is not a toolbar's content (`role="toolbar"` promises one arrow-key widget),
|
|
115
|
+
* and set beside the bar it lost the sticky tint and scrolled away from it.
|
|
116
|
+
*
|
|
117
|
+
* On the floating variant the panel scrolls within 60% of the viewport's height, so a
|
|
118
|
+
* long form on a phone cannot push the bar off the top of the screen.
|
|
119
|
+
*/
|
|
120
|
+
panel?: ReactNode;
|
|
47
121
|
/** Default: `bulkActionBar` from the {@link UiKitProvider}, else English. */
|
|
48
122
|
labels?: Partial<BulkActionBarLabels>;
|
|
49
123
|
}
|
|
@@ -105,7 +179,9 @@ export function BulkActionBar({
|
|
|
105
179
|
count,
|
|
106
180
|
onClear,
|
|
107
181
|
children,
|
|
108
|
-
variant = "floating",
|
|
182
|
+
variant: variantProp = "floating",
|
|
183
|
+
open,
|
|
184
|
+
panel,
|
|
109
185
|
labels: labelsProp,
|
|
110
186
|
className,
|
|
111
187
|
style,
|
|
@@ -116,21 +192,22 @@ export function BulkActionBar({
|
|
|
116
192
|
const labels = useKitLabels("bulkActionBar", DEFAULT_BULK_ACTION_BAR_LABELS, labelsProp);
|
|
117
193
|
const { announce, regionProps } = useAnnounce();
|
|
118
194
|
const barRef = useRef<HTMLDivElement>(null);
|
|
119
|
-
const
|
|
195
|
+
const variant = useResolvedVariant(variantProp);
|
|
196
|
+
const shown = open ?? count > 0;
|
|
120
197
|
|
|
121
198
|
// The count the bar last SHOWED, so a bar lowering itself after "clear" still reads
|
|
122
199
|
// "3 selected" on its way out rather than "0 selected". Adjusted during render
|
|
123
200
|
// (`Collapse`'s pattern), as is the exit below.
|
|
124
201
|
const [shownCount, setShownCount] = useState(count);
|
|
125
202
|
const [leaving, setLeaving] = useState(false);
|
|
126
|
-
const [
|
|
127
|
-
if (count !==
|
|
128
|
-
|
|
203
|
+
const [prev, setPrev] = useState({ count, shown });
|
|
204
|
+
if (count !== prev.count || shown !== prev.shown) {
|
|
205
|
+
setPrev({ count, shown });
|
|
129
206
|
if (shown) {
|
|
130
207
|
setShownCount(count);
|
|
131
208
|
setLeaving(false);
|
|
132
|
-
} else {
|
|
133
|
-
setLeaving(
|
|
209
|
+
} else if (prev.shown) {
|
|
210
|
+
setLeaving(!prefersReducedMotion());
|
|
134
211
|
}
|
|
135
212
|
}
|
|
136
213
|
useEffect(() => {
|
|
@@ -145,8 +222,9 @@ export function BulkActionBar({
|
|
|
145
222
|
useEffect(() => {
|
|
146
223
|
if (spoken.current === count) return;
|
|
147
224
|
spoken.current = count;
|
|
148
|
-
|
|
149
|
-
|
|
225
|
+
// In selection mode the bar stays at zero, so zero is a count like any other.
|
|
226
|
+
announce(count > 0 || shown ? labels.selected(count) : labels.cleared);
|
|
227
|
+
}, [count, shown, labels, announce]);
|
|
150
228
|
|
|
151
229
|
// Roving tab stop. The controls are the caller's, so the stop is kept on the DOM
|
|
152
230
|
// rather than through props: after every render the remembered control (or the
|
|
@@ -191,54 +269,82 @@ export function BulkActionBar({
|
|
|
191
269
|
</Button>
|
|
192
270
|
);
|
|
193
271
|
|
|
272
|
+
const hasPanel = panel !== undefined && panel !== null && panel !== false;
|
|
273
|
+
// The surface — where the bar sits and what it looks like — and the toolbar row's
|
|
274
|
+
// own layout. Without a panel they are one element, exactly as before 0.11.0; with
|
|
275
|
+
// one the surface wraps the row and the panel, so both share its tint and position.
|
|
276
|
+
const surfaceClass = floating
|
|
277
|
+
? cn(
|
|
278
|
+
"fixed z-30 rounded-2xl border border-[var(--border)] bg-[var(--bg-surface)] shadow-lg",
|
|
279
|
+
shown ? "animate-sheet" : "animate-sheet-out",
|
|
280
|
+
)
|
|
281
|
+
: cn(
|
|
282
|
+
variant === "sticky" &&
|
|
283
|
+
"sticky top-0 z-20 border-b border-[var(--border)] bg-[color-mix(in_srgb,var(--brand)_8%,var(--bg-surface))] backdrop-blur",
|
|
284
|
+
shown ? "animate-overlay" : "animate-overlay-out",
|
|
285
|
+
);
|
|
286
|
+
const rowClass = cn("flex items-center", floating ? "gap-1 px-2 py-1" : "gap-2 px-3 py-2");
|
|
287
|
+
const surfaceStyle = floating ? { ...FLOATING_STYLE, ...style } : style;
|
|
288
|
+
|
|
289
|
+
const toolbar = (
|
|
290
|
+
<div
|
|
291
|
+
{...(hasPanel ? null : rest)}
|
|
292
|
+
ref={barRef}
|
|
293
|
+
role="toolbar"
|
|
294
|
+
aria-label={labels.selected(shownCount)}
|
|
295
|
+
aria-orientation="horizontal"
|
|
296
|
+
data-bulk-action-bar={hasPanel ? undefined : variant}
|
|
297
|
+
// Leaving: out of the tab order and the accessibility tree at once, while the
|
|
298
|
+
// bar still animates. The selection it acted on is already gone.
|
|
299
|
+
inert={(!hasPanel && !shown) || undefined}
|
|
300
|
+
onKeyDown={handleKeyDown}
|
|
301
|
+
onFocus={(e) => {
|
|
302
|
+
onFocus?.(e);
|
|
303
|
+
// Clicking a control is using it: the stop follows the pointer too.
|
|
304
|
+
const hit = itemsOf(barRef.current).find((el) => el === e.target);
|
|
305
|
+
if (hit) {
|
|
306
|
+
active.current = hit;
|
|
307
|
+
rove(barRef.current, active);
|
|
308
|
+
}
|
|
309
|
+
}}
|
|
310
|
+
style={hasPanel ? undefined : surfaceStyle}
|
|
311
|
+
className={hasPanel ? rowClass : cn(rowClass, surfaceClass, className)}
|
|
312
|
+
>
|
|
313
|
+
{floating && clear}
|
|
314
|
+
<span className="min-w-0 flex-1 truncate text-sm font-medium text-[var(--text-primary)]">
|
|
315
|
+
{labels.selected(shownCount)}
|
|
316
|
+
</span>
|
|
317
|
+
{/* `contents`, so the caller's controls are flex items of the bar itself. */}
|
|
318
|
+
<div className="contents">{children}</div>
|
|
319
|
+
{!floating && clear}
|
|
320
|
+
</div>
|
|
321
|
+
);
|
|
322
|
+
|
|
194
323
|
return (
|
|
195
324
|
<>
|
|
196
325
|
<span {...regionProps} />
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
"flex items-center",
|
|
220
|
-
floating
|
|
221
|
-
? cn(
|
|
222
|
-
"fixed z-30 gap-1 rounded-2xl border border-[var(--border)] bg-[var(--bg-surface)] px-2 py-1 shadow-lg",
|
|
223
|
-
shown ? "animate-sheet" : "animate-sheet-out",
|
|
224
|
-
)
|
|
225
|
-
: cn(
|
|
226
|
-
"gap-2 px-3 py-2",
|
|
227
|
-
variant === "sticky" &&
|
|
228
|
-
"sticky top-0 z-20 border-b border-[var(--border)] bg-[color-mix(in_srgb,var(--brand)_8%,var(--bg-surface))] backdrop-blur",
|
|
229
|
-
shown ? "animate-overlay" : "animate-overlay-out",
|
|
230
|
-
),
|
|
231
|
-
className,
|
|
232
|
-
)}
|
|
233
|
-
>
|
|
234
|
-
{floating && clear}
|
|
235
|
-
<span className="min-w-0 flex-1 truncate text-sm font-medium text-[var(--text-primary)]">
|
|
236
|
-
{labels.selected(shownCount)}
|
|
237
|
-
</span>
|
|
238
|
-
{/* `contents`, so the caller's controls are flex items of the bar itself. */}
|
|
239
|
-
<div className="contents">{children}</div>
|
|
240
|
-
{!floating && clear}
|
|
241
|
-
</div>
|
|
326
|
+
{hasPanel ? (
|
|
327
|
+
<div
|
|
328
|
+
{...rest}
|
|
329
|
+
data-bulk-action-bar={variant}
|
|
330
|
+
inert={!shown || undefined}
|
|
331
|
+
style={surfaceStyle}
|
|
332
|
+
className={cn("flex flex-col", surfaceClass, className)}
|
|
333
|
+
>
|
|
334
|
+
{toolbar}
|
|
335
|
+
<div
|
|
336
|
+
data-bulk-action-bar-panel=""
|
|
337
|
+
className={cn(
|
|
338
|
+
"border-t border-[var(--border)] px-3 py-3",
|
|
339
|
+
floating && "max-h-[60dvh] overflow-y-auto",
|
|
340
|
+
)}
|
|
341
|
+
>
|
|
342
|
+
{panel}
|
|
343
|
+
</div>
|
|
344
|
+
</div>
|
|
345
|
+
) : (
|
|
346
|
+
toolbar
|
|
347
|
+
)}
|
|
242
348
|
</>
|
|
243
349
|
);
|
|
244
350
|
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import type { ComponentPropsWithoutRef } from "react";
|
|
1
|
+
import type { ComponentPropsWithoutRef, MouseEvent, ReactElement, ReactNode, Ref } from "react";
|
|
2
2
|
import { cn } from "../lib/cn";
|
|
3
|
+
import { buttonClasses, type ButtonSize, type ButtonVariant } from "./ui";
|
|
4
|
+
import { useKitLink } from "../i18n/kit-labels";
|
|
5
|
+
import { pickLinkRenderer } from "./text-link";
|
|
3
6
|
|
|
4
7
|
// Every class below is spelled out in full rather than assembled from parts: the
|
|
5
8
|
// consumer's Tailwind build finds classes by scanning this package's source as text,
|
|
@@ -8,12 +11,15 @@ import { cn } from "../lib/cn";
|
|
|
8
11
|
// Each rule is written twice, once for a direct child and once for a `<button>` one
|
|
9
12
|
// level down. The second is for a Tooltip-wrapped IconButton — the map zoom's + and −
|
|
10
13
|
// both carry a tooltip — where the direct child is the tooltip's wrapper span and the
|
|
11
|
-
// button that draws the border and the corners sits inside it.
|
|
14
|
+
// button that draws the border and the corners sits inside it. The same again for an
|
|
15
|
+
// `<a>` one level down: a router link member (see {@link ButtonGroupLink}) under a
|
|
16
|
+
// tooltip. A bare link is a direct child and needs nothing extra.
|
|
12
17
|
const JOINED_COMMON = cn(
|
|
13
18
|
"inline-flex rounded-md border border-[var(--border)]",
|
|
14
19
|
// The group draws the frame; each member gives up its own border, radius and shadow.
|
|
15
20
|
"[&>*]:rounded-none [&>*]:border-0 [&>*]:shadow-none",
|
|
16
21
|
"[&>*>button]:rounded-none [&>*>button]:border-0 [&>*>button]:shadow-none",
|
|
22
|
+
"[&>*>a]:rounded-none [&>*>a]:border-0 [&>*>a]:shadow-none",
|
|
17
23
|
"[&>*]:border-[var(--border)]",
|
|
18
24
|
// A focused member rises above its neighbours so its ring is not painted over by
|
|
19
25
|
// the next one's background.
|
|
@@ -30,6 +36,7 @@ const JOINED: Record<"horizontal" | "vertical", string> = {
|
|
|
30
36
|
"[&>*:not(:first-child)]:border-s",
|
|
31
37
|
"[&>:first-child]:rounded-s-md [&>:last-child]:rounded-e-md",
|
|
32
38
|
"[&>:first-child>button]:rounded-s-md [&>:last-child>button]:rounded-e-md",
|
|
39
|
+
"[&>:first-child>a]:rounded-s-md [&>:last-child>a]:rounded-e-md",
|
|
33
40
|
),
|
|
34
41
|
// The block axis is top-to-bottom in both reading directions, so top/bottom are
|
|
35
42
|
// already the logical edges here.
|
|
@@ -39,13 +46,47 @@ const JOINED: Record<"horizontal" | "vertical", string> = {
|
|
|
39
46
|
"[&>*:not(:first-child)]:border-t",
|
|
40
47
|
"[&>:first-child]:rounded-t-md [&>:last-child]:rounded-b-md",
|
|
41
48
|
"[&>:first-child>button]:rounded-t-md [&>:last-child>button]:rounded-b-md",
|
|
49
|
+
"[&>:first-child>a]:rounded-t-md [&>:last-child>a]:rounded-b-md",
|
|
42
50
|
),
|
|
43
51
|
};
|
|
44
52
|
|
|
53
|
+
// `gapped`: the members keep their own shape — round overlay discs, each its own
|
|
54
|
+
// border and radius — and sit apart. Nothing is stripped, so there is nothing to
|
|
55
|
+
// restore per edge, and the gap is logical by nature.
|
|
56
|
+
const GAPPED: Record<"horizontal" | "vertical", string> = {
|
|
57
|
+
horizontal: "inline-flex flex-row items-center gap-1",
|
|
58
|
+
vertical: "inline-flex flex-col items-center gap-1",
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// `elevated`, joined: the frame itself floats — a filled surface under the members (a
|
|
62
|
+
// ghost member would otherwise show the content through it) and the shadow of a
|
|
63
|
+
// control lifted over the page.
|
|
64
|
+
const ELEVATED_JOINED = "bg-[var(--bg-surface)] shadow-lg";
|
|
65
|
+
// `elevated`, gapped: there is no frame, so each disc carries the shadow. Aimed at the
|
|
66
|
+
// control, not the tooltip's square wrapper span, whose shadow would be a box round a
|
|
67
|
+
// round disc.
|
|
68
|
+
const ELEVATED_GAPPED =
|
|
69
|
+
"[&>button]:shadow-md [&>a]:shadow-md [&>*>button]:shadow-md [&>*>a]:shadow-md";
|
|
70
|
+
|
|
45
71
|
export interface ButtonGroupProps extends Omit<ComponentPropsWithoutRef<"div">, "role"> {
|
|
46
72
|
/** `horizontal` (default): side by side, in reading order. `vertical`: stacked —
|
|
47
73
|
* the map's zoom + over −. */
|
|
48
74
|
orientation?: "horizontal" | "vertical";
|
|
75
|
+
/**
|
|
76
|
+
* `joined` (default): one frame, hairline dividers, outer corners rounded. `gapped`:
|
|
77
|
+
* separate controls with a small gap, each keeping its own shape — the overlay
|
|
78
|
+
* discs of keksdose's receipt preview zoom (scan-file-preview.tsx:362, the − and +
|
|
79
|
+
* `IconButton variant="overlay"` in a hand-made `flex gap-1`), where a joined frame
|
|
80
|
+
* would be a box drawn over the photo.
|
|
81
|
+
*/
|
|
82
|
+
variant?: "joined" | "gapped";
|
|
83
|
+
/**
|
|
84
|
+
* Float it: a surface with a shadow, for a toolbar that sits OVER content (a map's
|
|
85
|
+
* zoom, a photo's controls) rather than in the page's flow — keksdose adds
|
|
86
|
+
* `shadow-sm` to each disc on the receipt preview by hand. On a joined group the
|
|
87
|
+
* frame is filled and shadowed; on a gapped one, each member.
|
|
88
|
+
*/
|
|
89
|
+
elevated?: boolean;
|
|
49
90
|
}
|
|
50
91
|
|
|
51
92
|
/**
|
|
@@ -63,13 +104,97 @@ export interface ButtonGroupProps extends Omit<ComponentPropsWithoutRef<"div">,
|
|
|
63
104
|
* roving, and every member keeps its own tab stop, as plain adjacent buttons do.
|
|
64
105
|
* For one-of-many selection use `ToggleGroup`, which has the radio semantics.
|
|
65
106
|
*/
|
|
66
|
-
export function ButtonGroup({
|
|
107
|
+
export function ButtonGroup({
|
|
108
|
+
orientation = "horizontal",
|
|
109
|
+
variant = "joined",
|
|
110
|
+
elevated = false,
|
|
111
|
+
className,
|
|
112
|
+
...rest
|
|
113
|
+
}: ButtonGroupProps) {
|
|
114
|
+
const joined = variant === "joined";
|
|
67
115
|
return (
|
|
68
116
|
<div
|
|
69
117
|
{...rest}
|
|
70
118
|
role="group"
|
|
71
119
|
data-orientation={orientation}
|
|
72
|
-
|
|
120
|
+
data-variant={variant}
|
|
121
|
+
className={cn(
|
|
122
|
+
joined ? JOINED[orientation] : GAPPED[orientation],
|
|
123
|
+
elevated && (joined ? ELEVATED_JOINED : ELEVATED_GAPPED),
|
|
124
|
+
className,
|
|
125
|
+
)}
|
|
73
126
|
/>
|
|
74
127
|
);
|
|
75
128
|
}
|
|
129
|
+
|
|
130
|
+
/** What {@link ButtonGroupLinkProps.renderLink} is handed. Spread it onto your router's
|
|
131
|
+
* link, mapping `href` — `renderLink={({ href, ...p }) => <Link to={href} {...p} />}`. */
|
|
132
|
+
export interface ButtonGroupLinkRenderProps {
|
|
133
|
+
href: string;
|
|
134
|
+
/** The button look — keep it, or the member is a bare link in the frame. */
|
|
135
|
+
className: string;
|
|
136
|
+
children: ReactNode;
|
|
137
|
+
ref?: Ref<HTMLAnchorElement>;
|
|
138
|
+
"aria-current"?: "page";
|
|
139
|
+
onClick?: (event: MouseEvent<HTMLAnchorElement>) => void;
|
|
140
|
+
[key: `aria-${string}`]: string | boolean | number | undefined;
|
|
141
|
+
[key: `data-${string}`]: unknown;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export interface ButtonGroupLinkProps extends Omit<ComponentPropsWithoutRef<"a">, "href" | "className" | "children"> {
|
|
145
|
+
href: string;
|
|
146
|
+
/** The {@link Button} variant it looks like. Default `secondary`, the usual member. */
|
|
147
|
+
variant?: ButtonVariant;
|
|
148
|
+
size?: ButtonSize;
|
|
149
|
+
/** The member for the page you are on: `aria-current="page"` and the "on" look of a
|
|
150
|
+
* pressed member, so a link row reads as a segmented switch between pages. */
|
|
151
|
+
current?: boolean;
|
|
152
|
+
/** Render through your router's `Link` — see {@link ButtonGroupLinkRenderProps}.
|
|
153
|
+
* Default: the `<UiKitProvider linkComponent>`, then `<a>`. */
|
|
154
|
+
renderLink?: (props: ButtonGroupLinkRenderProps) => ReactElement;
|
|
155
|
+
className?: string;
|
|
156
|
+
children: ReactNode;
|
|
157
|
+
ref?: Ref<HTMLAnchorElement>;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const LINK_CURRENT = "bg-[var(--brand-bg)] text-[var(--brand)] hover:bg-[var(--brand-bg-hover)]";
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* A {@link ButtonGroup} member that navigates: a link drawn as a {@link Button}, so it
|
|
164
|
+
* joins the frame like one. A group mixing actions and pages — "Export" beside "Open
|
|
165
|
+
* report" — had to either make the page a button with an `onClick` navigate (no
|
|
166
|
+
* middle-click, no "open in new tab", no link semantics) or style an `<a>` whose
|
|
167
|
+
* corners the group did not know about. Plain `<a>` by default; `renderLink` for the
|
|
168
|
+
* router's `Link`, the kit's usual shape (`Chip`, `MenuItem`, `StatTile`).
|
|
169
|
+
*/
|
|
170
|
+
export function ButtonGroupLink({
|
|
171
|
+
href,
|
|
172
|
+
variant = "secondary",
|
|
173
|
+
size,
|
|
174
|
+
current = false,
|
|
175
|
+
renderLink,
|
|
176
|
+
className,
|
|
177
|
+
children,
|
|
178
|
+
...rest
|
|
179
|
+
}: ButtonGroupLinkProps) {
|
|
180
|
+
const kitLink = useKitLink();
|
|
181
|
+
const props: ButtonGroupLinkRenderProps = {
|
|
182
|
+
...rest,
|
|
183
|
+
href,
|
|
184
|
+
"aria-current": current ? "page" : undefined,
|
|
185
|
+
className: buttonClasses(variant, { size, className: cn(current && LINK_CURRENT, className) }),
|
|
186
|
+
children,
|
|
187
|
+
};
|
|
188
|
+
const render = pickLinkRenderer(renderLink, kitLink, href);
|
|
189
|
+
if (render) return <RenderedGroupLink render={render} {...props} />;
|
|
190
|
+
const { children: content, ...anchor } = props;
|
|
191
|
+
return <a {...anchor}>{content}</a>;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/** Calls `renderLink` as a component, so the router link's hooks are its own. */
|
|
195
|
+
function RenderedGroupLink({
|
|
196
|
+
render,
|
|
197
|
+
...props
|
|
198
|
+
}: ButtonGroupLinkRenderProps & { render: (props: ButtonGroupLinkRenderProps) => ReactElement }) {
|
|
199
|
+
return render(props);
|
|
200
|
+
}
|