@eifi1/ui-kit 0.35.0 → 0.37.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 +35 -5
- package/dist/admin/role-select.d.ts +3 -2
- package/dist/admin/role-select.js +2 -0
- package/dist/admin/role-select.js.map +1 -1
- package/dist/components/amount-input.d.ts +2 -2
- package/dist/components/amount-input.js.map +1 -1
- package/dist/components/autocomplete.d.ts +2 -2
- package/dist/components/autocomplete.js +2 -1
- package/dist/components/autocomplete.js.map +1 -1
- package/dist/components/button-look.d.ts +1 -1
- package/dist/components/button-look.js +9 -4
- package/dist/components/button-look.js.map +1 -1
- package/dist/components/checkbox-group.d.ts +5 -2
- package/dist/components/checkbox-group.js +15 -4
- package/dist/components/checkbox-group.js.map +1 -1
- package/dist/components/column-mapper.d.ts +5 -3
- package/dist/components/column-mapper.js +2 -0
- package/dist/components/column-mapper.js.map +1 -1
- package/dist/components/combobox.d.ts +2 -2
- package/dist/components/combobox.js +2 -1
- package/dist/components/combobox.js.map +1 -1
- package/dist/components/country-select.d.ts +3 -3
- package/dist/components/country-select.js +3 -0
- package/dist/components/country-select.js.map +1 -1
- package/dist/components/currency-select.d.ts +3 -2
- package/dist/components/currency-select.js +10 -1
- package/dist/components/currency-select.js.map +1 -1
- package/dist/components/date-field.d.ts +2 -1
- package/dist/components/date-field.js.map +1 -1
- package/dist/components/date-picker.js +3 -0
- package/dist/components/date-picker.js.map +1 -1
- package/dist/components/date-range-picker.js +3 -0
- package/dist/components/date-range-picker.js.map +1 -1
- package/dist/components/entity-combobox.d.ts +2 -2
- package/dist/components/entity-combobox.js +2 -1
- package/dist/components/entity-combobox.js.map +1 -1
- package/dist/components/field-parts.d.ts +66 -11
- package/dist/components/field-parts.js +32 -10
- package/dist/components/field-parts.js.map +1 -1
- package/dist/components/field-strip.d.ts +3 -2
- package/dist/components/field-strip.js +2 -1
- package/dist/components/field-strip.js.map +1 -1
- package/dist/components/field.d.ts +3 -2
- package/dist/components/field.js +24 -15
- package/dist/components/field.js.map +1 -1
- package/dist/components/help-popover.d.ts +9 -7
- package/dist/components/help-popover.js.map +1 -1
- package/dist/components/icon-picker.d.ts +3 -2
- package/dist/components/icon-picker.js +3 -0
- package/dist/components/icon-picker.js.map +1 -1
- package/dist/components/inline-entity-combobox.d.ts +2 -2
- package/dist/components/inline-entity-combobox.js +2 -1
- package/dist/components/inline-entity-combobox.js.map +1 -1
- package/dist/components/input.d.ts +2 -2
- package/dist/components/input.js +2 -1
- package/dist/components/input.js.map +1 -1
- package/dist/components/month-picker.d.ts +2 -1
- package/dist/components/month-picker.js +8 -1
- package/dist/components/month-picker.js.map +1 -1
- package/dist/components/multi-entity-combobox.d.ts +2 -2
- package/dist/components/multi-entity-combobox.js +2 -1
- package/dist/components/multi-entity-combobox.js.map +1 -1
- package/dist/components/multi-select.d.ts +2 -2
- package/dist/components/multi-select.js +3 -0
- package/dist/components/multi-select.js.map +1 -1
- package/dist/components/number-input.d.ts +2 -2
- package/dist/components/number-input.js.map +1 -1
- package/dist/components/numeric-field.d.ts +5 -2
- package/dist/components/numeric-field.js +4 -1
- package/dist/components/numeric-field.js.map +1 -1
- package/dist/components/one-time-code-input.d.ts +2 -1
- package/dist/components/one-time-code-input.js +2 -1
- package/dist/components/one-time-code-input.js.map +1 -1
- package/dist/components/phone-input.d.ts +1 -1
- package/dist/components/phone-input.js +4 -0
- package/dist/components/phone-input.js.map +1 -1
- package/dist/components/popover.js +1 -1
- package/dist/components/popover.js.map +1 -1
- package/dist/components/select.d.ts +4 -3
- package/dist/components/select.js +2 -1
- package/dist/components/select.js.map +1 -1
- package/dist/components/slider.d.ts +3 -2
- package/dist/components/slider.js +7 -1
- package/dist/components/slider.js.map +1 -1
- package/dist/components/stat-tile.js +2 -11
- package/dist/components/stat-tile.js.map +1 -1
- package/dist/components/swatch-picker.d.ts +3 -2
- package/dist/components/swatch-picker.js +3 -0
- package/dist/components/swatch-picker.js.map +1 -1
- package/dist/components/text-link.js +3 -1
- package/dist/components/text-link.js.map +1 -1
- package/dist/components/textarea.d.ts +2 -1
- package/dist/components/textarea.js +9 -3
- package/dist/components/textarea.js.map +1 -1
- package/dist/components/toggle-group.d.ts +2 -2
- package/dist/components/toggle-group.js +7 -3
- package/dist/components/toggle-group.js.map +1 -1
- package/dist/eslint/index.js +1 -1
- package/dist/eslint/role-utilities.d.ts +34 -2
- package/dist/eslint/role-utilities.js +30 -9
- package/dist/eslint/role-utilities.js.map +1 -1
- package/dist/i18n/defaults.js +5 -1
- package/dist/i18n/defaults.js.map +1 -1
- package/dist/i18n/german.js +97 -1
- package/dist/i18n/german.js.map +1 -1
- package/dist/i18n/kit-labels.d.ts +16 -0
- package/dist/i18n/kit-labels.js +21 -1
- package/dist/i18n/kit-labels.js.map +1 -1
- package/dist/i18n/locales/en.js +103 -2
- package/dist/i18n/locales/en.js.map +3 -3
- package/dist/i18n/locales/es.js +95 -1
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.js +96 -1
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hu.js +95 -1
- package/dist/i18n/locales/hu.js.map +1 -1
- package/dist/i18n/locales/it.js +96 -1
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/zh.js +95 -1
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/i18n/review.js +13 -0
- package/dist/i18n/review.js.map +1 -1
- package/dist/i18n/shared-labels.js +3 -1
- package/dist/i18n/shared-labels.js.map +1 -1
- package/dist/index.d.ts +21 -0
- package/dist/index.js +38 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/device-settings.d.ts +72 -0
- package/dist/lib/device-settings.js +64 -0
- package/dist/lib/device-settings.js.map +1 -0
- package/dist/lib/plain-text.d.ts +11 -0
- package/dist/lib/plain-text.js +16 -0
- package/dist/lib/plain-text.js.map +1 -0
- package/dist/lib/safe-storage.d.ts +6 -0
- package/dist/lib/safe-storage.js +11 -0
- package/dist/lib/safe-storage.js.map +1 -1
- package/dist/notifications/notification-parts.d.ts +39 -0
- package/dist/notifications/notification-parts.js +47 -0
- package/dist/notifications/notification-parts.js.map +1 -0
- package/dist/notifications/notification-types-setting.d.ts +62 -0
- package/dist/notifications/notification-types-setting.js +192 -0
- package/dist/notifications/notification-types-setting.js.map +1 -0
- package/dist/notifications/notification-types.d.ts +75 -0
- package/dist/notifications/notification-types.js +2 -0
- package/dist/notifications/notification-types.js.map +1 -0
- package/dist/notifications/notifications-labels.d.ts +131 -0
- package/dist/notifications/notifications-labels.js +83 -0
- package/dist/notifications/notifications-labels.js.map +1 -0
- package/dist/notifications/push-device-setting.d.ts +37 -0
- package/dist/notifications/push-device-setting.js +164 -0
- package/dist/notifications/push-device-setting.js.map +1 -0
- package/dist/notifications/push-devices-setting.d.ts +44 -0
- package/dist/notifications/push-devices-setting.js +203 -0
- package/dist/notifications/push-devices-setting.js.map +1 -0
- package/dist/notifications/quiet-hours-setting.d.ts +47 -0
- package/dist/notifications/quiet-hours-setting.js +131 -0
- package/dist/notifications/quiet-hours-setting.js.map +1 -0
- package/dist/notifications/time-zone-select.d.ts +50 -0
- package/dist/notifications/time-zone-select.js +76 -0
- package/dist/notifications/time-zone-select.js.map +1 -0
- package/dist/notifications/unsubscribe-panel.d.ts +53 -0
- package/dist/notifications/unsubscribe-panel.js +139 -0
- package/dist/notifications/unsubscribe-panel.js.map +1 -0
- package/dist/notifications/use-push-device.d.ts +122 -0
- package/dist/notifications/use-push-device.js +230 -0
- package/dist/notifications/use-push-device.js.map +1 -0
- package/dist/rhf/fields.d.ts +26 -19
- package/dist/rhf/fields.js +51 -22
- package/dist/rhf/fields.js.map +1 -1
- package/dist/settings/device-reset-setting-labels.d.ts +3 -0
- package/dist/settings/device-reset-setting-labels.js +15 -0
- package/dist/settings/device-reset-setting-labels.js.map +1 -0
- package/dist/settings/device-reset-setting.d.ts +58 -0
- package/dist/settings/device-reset-setting.js +51 -0
- package/dist/settings/device-reset-setting.js.map +1 -0
- package/dist/shell/app-shell.js +5 -0
- package/dist/shell/app-shell.js.map +1 -1
- package/dist/theme/contrast-tokens.d.ts +42 -4
- package/dist/theme/contrast-tokens.js +56 -9
- package/dist/theme/contrast-tokens.js.map +1 -1
- package/dist/theme/contrast.d.ts +4 -2
- package/dist/theme/contrast.js +13 -0
- package/dist/theme/contrast.js.map +1 -1
- package/dist/theme/palette-derive.d.ts +15 -1
- package/dist/theme/palette-derive.js +37 -8
- package/dist/theme/palette-derive.js.map +1 -1
- package/dist/theme/palette-presets.d.ts +2 -1
- package/dist/theme/palette-presets.js +5 -5
- package/dist/theme/palette-presets.js.map +1 -1
- package/dist/theme/palette-store.js +6 -0
- package/dist/theme/palette-store.js.map +1 -1
- package/dist/theme/text-size.js +6 -0
- package/dist/theme/text-size.js.map +1 -1
- package/dist/theme/theme-store.js +6 -0
- package/dist/theme/theme-store.js.map +1 -1
- package/package.json +1 -1
- package/src/admin/role-select.tsx +4 -1
- package/src/components/amount-input.tsx +2 -1
- package/src/components/autocomplete.tsx +5 -2
- package/src/components/button-look.ts +15 -5
- package/src/components/checkbox-group.tsx +22 -4
- package/src/components/column-mapper.tsx +6 -2
- package/src/components/combobox.tsx +5 -2
- package/src/components/country-select.tsx +6 -1
- package/src/components/currency-select.tsx +12 -3
- package/src/components/date-field.tsx +2 -2
- package/src/components/date-picker.tsx +3 -0
- package/src/components/date-range-picker.tsx +3 -0
- package/src/components/entity-combobox.tsx +5 -2
- package/src/components/field-parts.tsx +107 -19
- package/src/components/field-strip.tsx +4 -3
- package/src/components/field.tsx +28 -15
- package/src/components/help-popover.tsx +9 -7
- package/src/components/icon-picker.tsx +8 -3
- package/src/components/inline-entity-combobox.tsx +5 -2
- package/src/components/input.tsx +4 -2
- package/src/components/month-picker.tsx +10 -3
- package/src/components/multi-entity-combobox.tsx +5 -2
- package/src/components/multi-select.tsx +6 -1
- package/src/components/number-input.tsx +2 -2
- package/src/components/numeric-field.ts +10 -2
- package/src/components/one-time-code-input.tsx +5 -3
- package/src/components/phone-input.tsx +4 -0
- package/src/components/popover.tsx +3 -1
- package/src/components/select.tsx +6 -3
- package/src/components/slider.tsx +10 -3
- package/src/components/stat-tile.tsx +3 -18
- package/src/components/swatch-picker.tsx +9 -4
- package/src/components/text-link.tsx +3 -1
- package/src/components/textarea.tsx +11 -4
- package/src/components/toggle-group.tsx +21 -5
- package/src/eslint/role-utilities.ts +67 -11
- package/src/i18n/defaults.ts +4 -0
- package/src/i18n/german.ts +113 -0
- package/src/i18n/kit-labels.tsx +52 -1
- package/src/i18n/locales/en.ts +6 -0
- package/src/i18n/locales/es.ts +106 -0
- package/src/i18n/locales/fr.ts +106 -0
- package/src/i18n/locales/hu.ts +104 -0
- package/src/i18n/locales/it.ts +105 -0
- package/src/i18n/locales/zh.ts +96 -0
- package/src/i18n/review.ts +13 -0
- package/src/i18n/shared-labels.ts +2 -0
- package/src/index.ts +50 -0
- package/src/lib/device-settings.ts +146 -0
- package/src/lib/plain-text.ts +22 -0
- package/src/lib/safe-storage.ts +16 -0
- package/src/notifications/notification-parts.tsx +83 -0
- package/src/notifications/notification-types-setting.tsx +309 -0
- package/src/notifications/notification-types.ts +80 -0
- package/src/notifications/notifications-labels.ts +238 -0
- package/src/notifications/push-device-setting.tsx +224 -0
- package/src/notifications/push-devices-setting.tsx +306 -0
- package/src/notifications/quiet-hours-setting.tsx +185 -0
- package/src/notifications/time-zone-select.tsx +126 -0
- package/src/notifications/unsubscribe-panel.tsx +203 -0
- package/src/notifications/use-push-device.ts +392 -0
- package/src/rhf/fields.tsx +77 -29
- package/src/settings/device-reset-setting-labels.ts +20 -0
- package/src/settings/device-reset-setting.tsx +119 -0
- package/src/shell/app-shell.tsx +8 -0
- package/src/theme/contrast-tokens.ts +106 -12
- package/src/theme/contrast.ts +30 -4
- package/src/theme/palette-derive.ts +68 -7
- package/src/theme/palette-presets.ts +9 -6
- package/src/theme/palette-store.ts +12 -0
- package/src/theme/text-size.ts +8 -0
- package/src/theme/theme-store.ts +10 -0
- package/tokens.css +38 -4
|
@@ -148,6 +148,7 @@ export function PhoneInput({
|
|
|
148
148
|
inputClassName,
|
|
149
149
|
label,
|
|
150
150
|
hint,
|
|
151
|
+
help,
|
|
151
152
|
error,
|
|
152
153
|
invalid,
|
|
153
154
|
disabled,
|
|
@@ -225,6 +226,9 @@ export function PhoneInput({
|
|
|
225
226
|
// since 0.34, not a copy of its rule (DUP-2, DUP-8).
|
|
226
227
|
const messages = useFieldMessages({
|
|
227
228
|
hint,
|
|
229
|
+
// The number's label line takes the help's "?" (0.36); the hint is then the caption.
|
|
230
|
+
help,
|
|
231
|
+
name: label ?? rest["aria-label"],
|
|
228
232
|
error,
|
|
229
233
|
invalid,
|
|
230
234
|
describedBy: ariaDescribedBy,
|
|
@@ -10,7 +10,9 @@ import { dirOf } from "../lib/direction";
|
|
|
10
10
|
import type { Direction } from "../lib/direction";
|
|
11
11
|
import { useKitLabels, type LabelOverride } from "../i18n/kit-labels";
|
|
12
12
|
import { DEFAULT_POPOVER_LABELS } from "./popover-labels";
|
|
13
|
-
|
|
13
|
+
// From ../lib/refs, not field-parts (round 0.36): field-parts renders a HelpPopover for a
|
|
14
|
+
// field's `help`, so importing from there would close a cycle, as it did for Tooltip.
|
|
15
|
+
import { mergeRefs } from "../lib/refs";
|
|
14
16
|
|
|
15
17
|
/** The panel's accessible name. A `role="dialog"` with no name announces as "dialog"
|
|
16
18
|
* and nothing else, which is worse than the unlabelled div it replaced — so it is a
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
LockedReason,
|
|
7
7
|
mergeDescribedBy,
|
|
8
8
|
type DisabledReasonDisplay,
|
|
9
|
+
type FieldHelpProps,
|
|
9
10
|
useFieldError,
|
|
10
11
|
useFieldHint,
|
|
11
12
|
useLockReason,
|
|
@@ -20,7 +21,7 @@ import {
|
|
|
20
21
|
fieldBelow,
|
|
21
22
|
} from "./field-base";
|
|
22
23
|
|
|
23
|
-
export interface SelectProps extends Omit<SelectHTMLAttributes<HTMLSelectElement>, "size"
|
|
24
|
+
export interface SelectProps extends Omit<SelectHTMLAttributes<HTMLSelectElement>, "size">, FieldHelpProps {
|
|
24
25
|
label?: ReactNode;
|
|
25
26
|
/** See {@link Input}'s `invalid`. */
|
|
26
27
|
invalid?: boolean;
|
|
@@ -33,7 +34,8 @@ export interface SelectProps extends Omit<SelectHTMLAttributes<HTMLSelectElement
|
|
|
33
34
|
* set in the value's type on top of both the label and the value. On an
|
|
34
35
|
* UNLABELLED Select (no label line) a FieldHint sits at the field's end edge,
|
|
35
36
|
* outside the box. Since 0.34 a FieldHint is the caption at Large and on a touch
|
|
36
|
-
* screen, as on Input (`useInlineHint`); a `HelpPopover` stays a "?".
|
|
37
|
+
* screen, as on Input (`useInlineHint`); a `HelpPopover` stays a "?". Beside a
|
|
38
|
+
* `help` (0.36) the hint is the caption at every size: the help's "?" is the only one. */
|
|
37
39
|
hint?: ReactNode;
|
|
38
40
|
/**
|
|
39
41
|
* `"sm"`: a 28px, 12px-type select for a toolbar or a table header, where the
|
|
@@ -109,6 +111,7 @@ export function Select(props: SelectProps) {
|
|
|
109
111
|
invalid,
|
|
110
112
|
error,
|
|
111
113
|
hint: hintProp,
|
|
114
|
+
help,
|
|
112
115
|
size,
|
|
113
116
|
selectClassName,
|
|
114
117
|
disabledReason,
|
|
@@ -138,7 +141,7 @@ export function Select(props: SelectProps) {
|
|
|
138
141
|
// and on a touch screen is its words, a caption like any text (§4; a HelpPopover stays
|
|
139
142
|
// on the label line, §10.23). See `hint` above. Through useFieldHint since 0.34, not a
|
|
140
143
|
// copy of its rule (DUP-2, refactor audit 2026-10).
|
|
141
|
-
const hintParts = useFieldHint(hintProp, rest["aria-describedby"]);
|
|
144
|
+
const hintParts = useFieldHint(hintProp, rest["aria-describedby"], { help, name: label ?? rest["aria-label"] });
|
|
142
145
|
const hint = hintParts.labelHint;
|
|
143
146
|
const { isInvalid, describedBy, errorEl } = useFieldError(
|
|
144
147
|
error,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useId } from "react";
|
|
2
2
|
import type { CSSProperties, ChangeEvent, InputHTMLAttributes, ReactNode, Ref } from "react";
|
|
3
3
|
import { cn } from "../lib/cn";
|
|
4
|
-
import { useFieldMessages } from "./field-parts";
|
|
4
|
+
import { useFieldMessages, type FieldHelpProps } from "./field-parts";
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* A range control on a native `<input type="range">`.
|
|
@@ -123,7 +123,8 @@ export interface SliderProps
|
|
|
123
123
|
extends Omit<
|
|
124
124
|
InputHTMLAttributes<HTMLInputElement>,
|
|
125
125
|
"type" | "value" | "defaultValue" | "onChange" | "min" | "max" | "step" | "children"
|
|
126
|
-
|
|
126
|
+
>,
|
|
127
|
+
FieldHelpProps {
|
|
127
128
|
/** The value. On a log scale this is the real value, not the track position. */
|
|
128
129
|
value: number;
|
|
129
130
|
/** The new value — a number, not the DOM event, like `ToggleGroup`. Fired on every
|
|
@@ -201,6 +202,7 @@ export function Slider({
|
|
|
201
202
|
formatValue,
|
|
202
203
|
label,
|
|
203
204
|
hint,
|
|
205
|
+
help,
|
|
204
206
|
readout,
|
|
205
207
|
marks,
|
|
206
208
|
className,
|
|
@@ -254,7 +256,12 @@ export function Slider({
|
|
|
254
256
|
const hasMarkLabels = normalizedMarks.some((m) => m.label !== undefined);
|
|
255
257
|
|
|
256
258
|
// The label line's "?", or the caption under the track (DUP-2).
|
|
257
|
-
const messages = useFieldMessages({
|
|
259
|
+
const messages = useFieldMessages({
|
|
260
|
+
hint,
|
|
261
|
+
help,
|
|
262
|
+
name: label ?? rest["aria-label"],
|
|
263
|
+
describedBy: rest["aria-describedby"],
|
|
264
|
+
});
|
|
258
265
|
const labelHint = messages.labelHint;
|
|
259
266
|
const hasHeader = label !== undefined || labelHint !== undefined || readout !== undefined;
|
|
260
267
|
const plainReadout = typeof readout === "string" || typeof readout === "number";
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { createContext,
|
|
1
|
+
import { createContext, useContext, useId, useLayoutEffect, useState } from "react";
|
|
2
2
|
import type { ComponentPropsWithRef, CSSProperties, ReactElement, ReactNode } from "react";
|
|
3
3
|
import { ArrowDown, ArrowUp, Minus } from "lucide-react";
|
|
4
4
|
import { cn } from "../lib/cn";
|
|
5
|
+
// The sparkline's name: the label's text (lib since 0.36, which a field's `help` "?" shares).
|
|
6
|
+
import { plainText } from "../lib/plain-text";
|
|
5
7
|
import { useKitLabels, useKitLink, useKitLocale, type LabelOverride } from "../i18n/kit-labels";
|
|
6
8
|
import { pickLinkRenderer, RenderedKitLink } from "./text-link";
|
|
7
9
|
import { Card } from "./card";
|
|
@@ -612,23 +614,6 @@ function FigureRow({
|
|
|
612
614
|
);
|
|
613
615
|
}
|
|
614
616
|
|
|
615
|
-
/**
|
|
616
|
-
* The text of a label node, for the sparkline's name: a string or number as is, an
|
|
617
|
-
* element by its children, recursively. A `<Tooltip label="…">Spend</Tooltip>` label
|
|
618
|
-
* yields "Spend" — the text the reader sees, not the bubble's. `undefined` when there
|
|
619
|
-
* is no text to find (an icon), so the sparkline falls back to its unnamed summary.
|
|
620
|
-
*/
|
|
621
|
-
function plainText(node: ReactNode): string | undefined {
|
|
622
|
-
const walk = (n: ReactNode): string => {
|
|
623
|
-
if (typeof n === "string" || typeof n === "number") return String(n);
|
|
624
|
-
if (Array.isArray(n)) return n.map(walk).join("");
|
|
625
|
-
if (isValidElement<{ children?: ReactNode }>(n)) return walk(n.props.children);
|
|
626
|
-
return "";
|
|
627
|
-
};
|
|
628
|
-
const text = walk(node).replace(/\s+/g, " ").trim();
|
|
629
|
-
return text === "" ? undefined : text;
|
|
630
|
-
}
|
|
631
|
-
|
|
632
617
|
/**
|
|
633
618
|
* Whether `el`'s text is wider than its box — i.e. whether `truncate` is cutting it.
|
|
634
619
|
* Re-measured whenever the box resizes (a grid reflowing, a translation loading), not
|
|
@@ -7,7 +7,7 @@ import type { TileItem, TileSize } from "./tile-radio";
|
|
|
7
7
|
import { Tooltip } from "./tooltip";
|
|
8
8
|
import { useCommitReason, type CommitScope } from "./write-lock";
|
|
9
9
|
import { hasContent } from "../lib/presence";
|
|
10
|
-
import { LabelStrip, mergeDescribedBy, useFieldMessages } from "./field-parts";
|
|
10
|
+
import { LabelStrip, mergeDescribedBy, useFieldMessages, type FieldHelpProps } from "./field-parts";
|
|
11
11
|
import { DEFAULT_SWATCH_PICKER_LABELS } from "./swatch-picker-labels";
|
|
12
12
|
|
|
13
13
|
export interface SwatchPickerLabels {
|
|
@@ -62,7 +62,8 @@ export interface SwatchOption<T extends string> {
|
|
|
62
62
|
* is omitted rather than shadowed, as on {@link ToggleGroup}.
|
|
63
63
|
*/
|
|
64
64
|
export interface SwatchPickerProps<T extends string>
|
|
65
|
-
extends Omit<ComponentPropsWithRef<"div">, "onChange" | "children" | "defaultValue"
|
|
65
|
+
extends Omit<ComponentPropsWithRef<"div">, "onChange" | "children" | "defaultValue">,
|
|
66
|
+
FieldHelpProps {
|
|
66
67
|
options: SwatchOption<T>[];
|
|
67
68
|
/** The chosen colour, or `null` for none. */
|
|
68
69
|
value: T | null;
|
|
@@ -145,6 +146,7 @@ export function SwatchPicker<T extends string>({
|
|
|
145
146
|
labels,
|
|
146
147
|
label,
|
|
147
148
|
hint,
|
|
149
|
+
help,
|
|
148
150
|
disabledReason: ownDisabledReason,
|
|
149
151
|
commit,
|
|
150
152
|
className,
|
|
@@ -157,10 +159,13 @@ export function SwatchPicker<T extends string>({
|
|
|
157
159
|
const disabledReason = useCommitReason(commit, ownDisabledReason);
|
|
158
160
|
const locked = hasContent(disabledReason);
|
|
159
161
|
const labelled = hasContent(label);
|
|
160
|
-
// The label line's "?", or the caption under the swatches (DUP-2). Only with a label
|
|
161
|
-
// The caller's ids, the caption, then the group's state:
|
|
162
|
+
// The label line's "?", or the caption under the swatches (DUP-2). Only with a label,
|
|
163
|
+
// the help's "?" too (0.36). The caller's ids, the caption, then the group's state:
|
|
164
|
+
// mixed, locked.
|
|
162
165
|
const messages = useFieldMessages({
|
|
163
166
|
hint: labelled ? hint : undefined,
|
|
167
|
+
help: labelled ? help : undefined,
|
|
168
|
+
name: label,
|
|
164
169
|
describedBy: rest["aria-describedby"],
|
|
165
170
|
reasonId: mergeDescribedBy(mixed && mixedId, locked && reasonId),
|
|
166
171
|
});
|
|
@@ -228,7 +228,9 @@ export interface TextLinkProps
|
|
|
228
228
|
}
|
|
229
229
|
|
|
230
230
|
const TONE: Record<TextLinkTone, string> = {
|
|
231
|
-
brand
|
|
231
|
+
// Under More contrast the brand as text, `--brand-muted`, at rest and hovered (0.36,
|
|
232
|
+
// colour-roles §13.3 decision 8): `--brand` is a mark's colour, solved to 3:1.
|
|
233
|
+
brand: "text-brand hover:text-[var(--brand-hover)] contrast:text-brand-muted contrast:hover:text-brand-muted",
|
|
232
234
|
muted: "text-muted hover:text-primary",
|
|
233
235
|
danger: "text-danger hover:text-[var(--danger-hover)]",
|
|
234
236
|
inherit: "",
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import { useId, useLayoutEffect, useRef } from "react";
|
|
2
2
|
import type { ChangeEvent, ReactNode, Ref, TextareaHTMLAttributes } from "react";
|
|
3
3
|
import { cn } from "../lib/cn";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
EndHintRow,
|
|
6
|
+
FieldCaption,
|
|
7
|
+
mergeDescribedBy,
|
|
8
|
+
useFieldError,
|
|
9
|
+
useFieldHint,
|
|
10
|
+
type FieldHelpProps,
|
|
11
|
+
} from "./field-parts";
|
|
5
12
|
import {
|
|
6
13
|
CharacterCount,
|
|
7
14
|
FIELD_BASE,
|
|
@@ -221,7 +228,7 @@ function TextareaLabelStrip() {
|
|
|
221
228
|
return <span ref={ref} aria-hidden data-slot="label-strip" className={TEXTAREA_LABEL_STRIP} />;
|
|
222
229
|
}
|
|
223
230
|
|
|
224
|
-
export interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement
|
|
231
|
+
export interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement>, FieldHelpProps {
|
|
225
232
|
label?: ReactNode;
|
|
226
233
|
/** See {@link Input}'s `invalid`. */
|
|
227
234
|
invalid?: boolean;
|
|
@@ -240,13 +247,13 @@ export interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElemen
|
|
|
240
247
|
}
|
|
241
248
|
|
|
242
249
|
export function Textarea(props: TextareaProps) {
|
|
243
|
-
const { ref, className, label, id, placeholder, invalid, error, hint, showCount, countLabels, ...rest } = props;
|
|
250
|
+
const { ref, className, label, id, placeholder, invalid, error, hint, help, showCount, countLabels, ...rest } = props;
|
|
244
251
|
// See Input's `reserve`.
|
|
245
252
|
const reserve = "error" in props || "hint" in props || "showCount" in props;
|
|
246
253
|
const generated = useId();
|
|
247
254
|
const fieldId = id ?? generated;
|
|
248
255
|
const countId = useId();
|
|
249
|
-
const hintParts = useFieldHint(hint, rest["aria-describedby"]);
|
|
256
|
+
const hintParts = useFieldHint(hint, rest["aria-describedby"], { help, name: label ?? rest["aria-label"] });
|
|
250
257
|
const maxLength = rest.maxLength;
|
|
251
258
|
const counting = Boolean(showCount) && typeof maxLength === "number" && maxLength > 0;
|
|
252
259
|
const length = useTypedLength(rest.value, rest.defaultValue);
|
|
@@ -11,11 +11,13 @@ import {
|
|
|
11
11
|
DISABLED_REASON_LINE_CLASS,
|
|
12
12
|
FIELD_CAPTION_CLASS,
|
|
13
13
|
FIELD_ERROR_CLASS,
|
|
14
|
+
fieldHelpMark,
|
|
14
15
|
isTextHint,
|
|
15
16
|
LabelStrip,
|
|
16
17
|
useDisabledReasonLine,
|
|
17
18
|
useInlineHint,
|
|
18
19
|
type DisabledReasonDisplay,
|
|
20
|
+
type FieldHelpProps,
|
|
19
21
|
} from "./field-parts";
|
|
20
22
|
import { FOCUS_RING_WIDTH } from "./focus-ring";
|
|
21
23
|
|
|
@@ -35,7 +37,8 @@ export interface ToggleOption<T extends string> {
|
|
|
35
37
|
* worse than one that does not compile.
|
|
36
38
|
*/
|
|
37
39
|
export interface ToggleGroupBaseProps<T extends string>
|
|
38
|
-
extends Omit<ComponentPropsWithoutRef<"div">, "onChange" | "children"
|
|
40
|
+
extends Omit<ComponentPropsWithoutRef<"div">, "onChange" | "children">,
|
|
41
|
+
FieldHelpProps {
|
|
39
42
|
options: ToggleOption<T>[];
|
|
40
43
|
className?: string;
|
|
41
44
|
/** Applied to every option button (e.g. to tune height/rounding to match
|
|
@@ -380,6 +383,7 @@ export function ToggleGroup<T extends string>(props: ToggleGroupProps<T>): React
|
|
|
380
383
|
labelPlacement = "field",
|
|
381
384
|
chromeClassName,
|
|
382
385
|
hint,
|
|
386
|
+
help,
|
|
383
387
|
error,
|
|
384
388
|
disabledReason: ownDisabledReason,
|
|
385
389
|
disabledReasonDisplay,
|
|
@@ -407,10 +411,22 @@ export function ToggleGroup<T extends string>(props: ToggleGroupProps<T>): React
|
|
|
407
411
|
// §4: at Large and on touch the reason is a line under the group, not a bubble.
|
|
408
412
|
const reasonLine = useDisabledReasonLine(disabledReasonDisplay) && locked;
|
|
409
413
|
// §4: likewise a FieldHint "?" on the label line becomes a caption under the group at
|
|
410
|
-
// Large and on touch; text is a caption at every size, as Select's (see `hint`).
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
const
|
|
414
|
+
// Large and on touch; text is a caption at every size, as Select's (see `hint`). With
|
|
415
|
+
// a `help` (0.36, only with `label`, as `hint`), its "?" is the label line's only one,
|
|
416
|
+
// and the hint — a FieldHint's words included — is the caption at every size.
|
|
417
|
+
const helpMark = fieldHelpMark(hasContent(label) ? help : undefined, label);
|
|
418
|
+
const withHelp = helpMark !== undefined;
|
|
419
|
+
const inlineHint = useInlineHint(hint, withHelp);
|
|
420
|
+
const hintAsCaption = withHelp
|
|
421
|
+
? hasContent(inlineHint)
|
|
422
|
+
? inlineHint
|
|
423
|
+
: undefined
|
|
424
|
+
: isTextHint(hint)
|
|
425
|
+
? hint
|
|
426
|
+
: inlineHint !== hint
|
|
427
|
+
? inlineHint
|
|
428
|
+
: undefined;
|
|
429
|
+
const labelHint = helpMark ?? (hintAsCaption === undefined ? hint : undefined);
|
|
414
430
|
// Locked looks disabled — the dimmed group, the not-allowed cursor, no hover offer —
|
|
415
431
|
// but stays focusable; `disabled` alone also takes the segments out of the tab order.
|
|
416
432
|
const dimmed = disabled || locked;
|
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
// The table itself is role-utilities.generated.ts, re-rendered from tokens.css's
|
|
6
6
|
// `@theme inline` block by scripts/gen-role-utilities.mjs with the parser below; the
|
|
7
7
|
// check fails while it is stale. So tokens.css stays the source: a role that gains a
|
|
8
|
-
// utility there is flagged in the kit and in the apps from the next release on.
|
|
8
|
+
// utility there is flagged in the kit and in the apps from the next release on. The
|
|
9
|
+
// README's role-utility table (scripts/gen-styling-inventory.mjs) reads the block with
|
|
10
|
+
// the same parser since 0.37, so the README, the check and the plugin cannot disagree.
|
|
9
11
|
//
|
|
10
12
|
// This module imports NOTHING, and its TypeScript is erasable only (no enum, no
|
|
11
13
|
// namespace, no parameter property): the check imports it from source under Node's type
|
|
@@ -43,20 +45,74 @@ export type RoleUtilityTable = {
|
|
|
43
45
|
readonly [P in RoleProperty]: Readonly<Record<string, readonly string[]>>;
|
|
44
46
|
};
|
|
45
47
|
|
|
48
|
+
/** One `--<namespace>-<name>: <value>;` of the `@theme inline` block. */
|
|
49
|
+
export interface ThemeInlineDeclaration {
|
|
50
|
+
/** The theme variable without its dashes: `text-color-muted`, `ring-width-focus`. */
|
|
51
|
+
variable: string;
|
|
52
|
+
/** The property whose namespace it is in; `null` for a namespace ROLE_NAMESPACES lacks. */
|
|
53
|
+
property: RoleProperty | null;
|
|
54
|
+
/** The name after the namespace, `muted`; `null` with `property`. */
|
|
55
|
+
name: string | null;
|
|
56
|
+
/** The utility it makes: `text-muted`, `ring-focus` (a width is `ring-*` like a colour). */
|
|
57
|
+
utility: string | null;
|
|
58
|
+
/** The token the value reads, `--text-muted`; `null` unless the value is a bare `var()`. */
|
|
59
|
+
token: string | null;
|
|
60
|
+
/** The value as written, trimmed. */
|
|
61
|
+
value: string;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** The `@theme inline` block: where it stands, and every declaration in it in block order. */
|
|
65
|
+
export interface ThemeInlineBlock {
|
|
66
|
+
/** Its first and one-past-last offset in `stripCssComments(css)`, not in `css`. */
|
|
67
|
+
start: number;
|
|
68
|
+
end: number;
|
|
69
|
+
declarations: ThemeInlineDeclaration[];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** `css` without its comments: a declaration commented out is not one. */
|
|
73
|
+
export function stripCssComments(css: string): string {
|
|
74
|
+
return css.replace(/\/\*[\s\S]*?\*\//g, "");
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const PROPERTIES = Object.keys(ROLE_NAMESPACES) as RoleProperty[];
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* tokens.css's `@theme inline` block, read once for every reader: the table below, and
|
|
81
|
+
* the README's (scripts/gen-styling-inventory.mjs), which fails on a `property: null`
|
|
82
|
+
* where the table leaves it out. `null` when there is no such block — the role utilities
|
|
83
|
+
* are gone, or this parser is. Theme blocks hold only declarations, so the first `}`
|
|
84
|
+
* closes it; no namespace is another's prefix, so the first that fits is the one.
|
|
85
|
+
*/
|
|
86
|
+
export function parseThemeInline(css: string): ThemeInlineBlock | null {
|
|
87
|
+
const block = /@theme\s+inline\s*\{([^}]*)\}/.exec(stripCssComments(css));
|
|
88
|
+
if (!block) return null;
|
|
89
|
+
const declarations = [...block[1].matchAll(/--([a-z0-9-]+)\s*:\s*([^;]+);/g)].map(([, variable, raw]) => {
|
|
90
|
+
const value = raw.trim();
|
|
91
|
+
const property = PROPERTIES.find((p) => variable.startsWith(`${ROLE_NAMESPACES[p]}-`)) ?? null;
|
|
92
|
+
const name = property && variable.slice(ROLE_NAMESPACES[property].length + 1);
|
|
93
|
+
return {
|
|
94
|
+
variable,
|
|
95
|
+
property,
|
|
96
|
+
name,
|
|
97
|
+
utility: property && `${property.replace(/-width$/, "")}-${name}`,
|
|
98
|
+
token: /^var\((--[a-z0-9-]+)\)$/.exec(value)?.[1] ?? null,
|
|
99
|
+
value,
|
|
100
|
+
};
|
|
101
|
+
});
|
|
102
|
+
return { start: block.index, end: block.index + block[0].length, declarations };
|
|
103
|
+
}
|
|
104
|
+
|
|
46
105
|
/**
|
|
47
106
|
* The table `tokens.css` declares: every `--<namespace>-<name>: var(--<token>)` in its
|
|
48
|
-
* `@theme inline` block, in block order
|
|
49
|
-
*
|
|
107
|
+
* `@theme inline` block, in block order, each property present (in ROLE_NAMESPACES' order)
|
|
108
|
+
* even when it has none. `null` when there is no such block.
|
|
50
109
|
*/
|
|
51
110
|
export function roleUtilitiesFromCss(css: string): RoleUtilityTable | null {
|
|
52
|
-
const
|
|
53
|
-
if (
|
|
54
|
-
const table = {} as Record<RoleProperty, Record<string, string[]>>;
|
|
55
|
-
for (const
|
|
56
|
-
|
|
57
|
-
const declared = new RegExp(`--${ROLE_NAMESPACES[prop]}-([a-z0-9-]+)\\s*:\\s*var\\((--[a-z0-9-]+)\\)`, "g");
|
|
58
|
-
for (const [, name, token] of theme.matchAll(declared)) (names[token] ??= []).push(name);
|
|
59
|
-
table[prop] = names;
|
|
111
|
+
const block = parseThemeInline(css);
|
|
112
|
+
if (!block) return null;
|
|
113
|
+
const table = Object.fromEntries(PROPERTIES.map((p) => [p, {}])) as Record<RoleProperty, Record<string, string[]>>;
|
|
114
|
+
for (const { property, name, token } of block.declarations) {
|
|
115
|
+
if (property && name && token) (table[property][token] ??= []).push(name);
|
|
60
116
|
}
|
|
61
117
|
return table;
|
|
62
118
|
}
|
package/src/i18n/defaults.ts
CHANGED
|
@@ -87,6 +87,7 @@ import { DEFAULT_DEMO_LABELS } from "../demo/demo-labels";
|
|
|
87
87
|
import { DEFAULT_BILLING_LABELS } from "../billing/billing-labels";
|
|
88
88
|
import { DEFAULT_PLAN_CHANGE_LABELS } from "../admin/plan-change-labels";
|
|
89
89
|
import { DEFAULT_APPEARANCE_LABELS } from "../components/appearance-labels";
|
|
90
|
+
import { DEFAULT_DEVICE_RESET_LABELS } from "../settings/device-reset-setting-labels";
|
|
90
91
|
import { DEFAULT_ROW_ACTIONS_LABELS } from "../components/row-actions-labels";
|
|
91
92
|
import { DEFAULT_APP_SHELL_MORE_LABELS } from "../shell/app-shell-labels";
|
|
92
93
|
import { DEFAULT_ACCOUNT_STATE_LABELS } from "../components/account-chips-labels";
|
|
@@ -100,6 +101,7 @@ import { DEFAULT_IBAN_INPUT_LABELS } from "../components/iban-input-labels";
|
|
|
100
101
|
import { DEFAULT_PHONE_INPUT_LABELS } from "../components/phone-input-labels";
|
|
101
102
|
import { DEFAULT_SIGN_CHIP_LABELS } from "../components/sign-chip-labels";
|
|
102
103
|
import { DEFAULT_COLUMN_MAPPER_LABELS } from "../components/column-mapper-labels";
|
|
104
|
+
import { DEFAULT_NOTIFICATIONS_LABELS } from "../notifications/notifications-labels";
|
|
103
105
|
import {
|
|
104
106
|
DEFAULT_APP_SHELL_LABELS,
|
|
105
107
|
DEFAULT_CALCULATOR_LABELS,
|
|
@@ -231,6 +233,7 @@ export const DEFAULT_UI_KIT_LABELS: UiKitLabels = {
|
|
|
231
233
|
billing: DEFAULT_BILLING_LABELS,
|
|
232
234
|
planChange: DEFAULT_PLAN_CHANGE_LABELS,
|
|
233
235
|
appearance: DEFAULT_APPEARANCE_LABELS,
|
|
236
|
+
deviceReset: DEFAULT_DEVICE_RESET_LABELS,
|
|
234
237
|
rowActions: DEFAULT_ROW_ACTIONS_LABELS,
|
|
235
238
|
appShellMore: DEFAULT_APP_SHELL_MORE_LABELS,
|
|
236
239
|
characterCount: DEFAULT_CHARACTER_COUNT_LABELS,
|
|
@@ -240,4 +243,5 @@ export const DEFAULT_UI_KIT_LABELS: UiKitLabels = {
|
|
|
240
243
|
phoneInput: DEFAULT_PHONE_INPUT_LABELS,
|
|
241
244
|
signChip: DEFAULT_SIGN_CHIP_LABELS,
|
|
242
245
|
columnMapper: DEFAULT_COLUMN_MAPPER_LABELS,
|
|
246
|
+
notifications: DEFAULT_NOTIFICATIONS_LABELS,
|
|
243
247
|
};
|
package/src/i18n/german.ts
CHANGED
|
@@ -268,6 +268,8 @@ export function germanLabels(numberLocale: string): UiKitLabels {
|
|
|
268
268
|
noResults: "Keine Ergebnisse",
|
|
269
269
|
fieldValue: (field, value) => `${field}: ${value}`,
|
|
270
270
|
opensInNewTab: "öffnet in einem neuen Tab",
|
|
271
|
+
aboutField: (field) => `Hilfe zu „${field}“`,
|
|
272
|
+
help: "Hilfe",
|
|
271
273
|
},
|
|
272
274
|
dataTable: {
|
|
273
275
|
columns: "Spalten",
|
|
@@ -1072,6 +1074,102 @@ export function germanLabels(numberLocale: string): UiKitLabels {
|
|
|
1072
1074
|
rateLimited,
|
|
1073
1075
|
failed: "Das hat nicht geklappt. Bitte erneut versuchen.",
|
|
1074
1076
|
},
|
|
1077
|
+
// 0.36.0 — docs/notifications-harmonization.md §4.2: the notification cards. The push
|
|
1078
|
+
// and device words follow keksdose's reviewed German, formal.
|
|
1079
|
+
notifications: {
|
|
1080
|
+
typesTitle: "Benachrichtigungen zu",
|
|
1081
|
+
typesDescription: "Wählen Sie, worüber Sie benachrichtigt werden, und wie.",
|
|
1082
|
+
byEmail: "Per E-Mail",
|
|
1083
|
+
emailUnverified: "Bestätigen Sie Ihre Adresse, um diese zu erhalten.",
|
|
1084
|
+
digestCadence: "Häufigkeit",
|
|
1085
|
+
digestWeekly: "Wöchentlich",
|
|
1086
|
+
digestMonthly: "Monatlich",
|
|
1087
|
+
typesLoading: "Benachrichtigungseinstellungen werden geladen…",
|
|
1088
|
+
typesEmpty: "Für dieses Konto gibt es keine Benachrichtigungen.",
|
|
1089
|
+
quietTitle: "Ruhezeiten",
|
|
1090
|
+
quietDescription: (inbox) =>
|
|
1091
|
+
inbox
|
|
1092
|
+
? "In diesem Zeitfenster kommen keine Push-Benachrichtigungen. Im Posteingang kommen sie trotzdem an."
|
|
1093
|
+
: "In diesem Zeitfenster kommen keine Push-Benachrichtigungen.",
|
|
1094
|
+
quietFrom: "Von",
|
|
1095
|
+
quietUntil: "Bis",
|
|
1096
|
+
quietIncomplete: "Legen Sie eine Start- und eine Endzeit fest. Ruhezeiten gelten erst, wenn beide gesetzt sind.",
|
|
1097
|
+
timeZone: "Zeitzone",
|
|
1098
|
+
deviceZone: (zone) => `Dieses Gerät ist in der Zeitzone ${zone}.`,
|
|
1099
|
+
useDeviceZone: "Übernehmen",
|
|
1100
|
+
regions: {
|
|
1101
|
+
Africa: "Afrika",
|
|
1102
|
+
America: "Amerika",
|
|
1103
|
+
Antarctica: "Antarktis",
|
|
1104
|
+
Arctic: "Arktis",
|
|
1105
|
+
Asia: "Asien",
|
|
1106
|
+
Atlantic: "Atlantik",
|
|
1107
|
+
Australia: "Australien",
|
|
1108
|
+
Europe: "Europa",
|
|
1109
|
+
Indian: "Indischer Ozean",
|
|
1110
|
+
Pacific: "Pazifik",
|
|
1111
|
+
},
|
|
1112
|
+
pushTitle: "Push-Benachrichtigungen",
|
|
1113
|
+
pushDescription: "Benachrichtigungen auf diesem Gerät, auch wenn die App geschlossen ist.",
|
|
1114
|
+
unsupported: "Dieser Browser unterstützt keine Push-Benachrichtigungen.",
|
|
1115
|
+
iosInstall: (app) =>
|
|
1116
|
+
`Fügen Sie ${app} auf dem iPhone oder iPad zuerst zum Home-Bildschirm hinzu: iOS stellt Benachrichtigungen nur der installierten App zu.`,
|
|
1117
|
+
notConfigured: "Push-Benachrichtigungen sind auf diesem Server nicht eingerichtet.",
|
|
1118
|
+
blocked: "Benachrichtigungen sind in den Einstellungen dieses Browsers blockiert.",
|
|
1119
|
+
on: "Benachrichtigungen sind für dieses Gerät eingeschaltet.",
|
|
1120
|
+
off: "Benachrichtigungen sind für dieses Gerät ausgeschaltet.",
|
|
1121
|
+
otherAccount:
|
|
1122
|
+
"Dieser Browser erhält Benachrichtigungen für ein anderes Konto. Schalten Sie sie hier ein, um sie für das angemeldete Konto zu erhalten.",
|
|
1123
|
+
enable: "Benachrichtigungen einschalten",
|
|
1124
|
+
disable: "Ausschalten",
|
|
1125
|
+
sendTest: "Test senden",
|
|
1126
|
+
enableFailed: "Benachrichtigungen konnten nicht eingeschaltet werden.",
|
|
1127
|
+
noServiceWorker:
|
|
1128
|
+
"Der Service Worker der App ist nicht erreichbar. Laden Sie die Seite neu und versuchen Sie es erneut.",
|
|
1129
|
+
pushTimeout:
|
|
1130
|
+
"Der Push-Dienst des Browsers antwortet nicht. Prüfen Sie Ihre Verbindung und versuchen Sie es erneut.",
|
|
1131
|
+
testSent: (count) =>
|
|
1132
|
+
count === 1 ? `Test an ${n(count)} Gerät gesendet` : `Test an ${n(count)} Geräte gesendet`,
|
|
1133
|
+
testNone:
|
|
1134
|
+
"Kein Gerät hat den Test angenommen. Schalten Sie zuerst die Benachrichtigungen für dieses Gerät ein.",
|
|
1135
|
+
testFailed: "Die Test-Benachrichtigung konnte nicht gesendet werden.",
|
|
1136
|
+
explainerTitle: "Benachrichtigungen einschalten?",
|
|
1137
|
+
explainerBody: (app) =>
|
|
1138
|
+
`${app} sendet nur Benachrichtigungen zu dem, was Sie auswählen, und Sie können sie jederzeit ausschalten.`,
|
|
1139
|
+
explainerHint: "Als Nächstes fragt Ihr Browser nach der Berechtigung.",
|
|
1140
|
+
explainerContinue: "Weiter",
|
|
1141
|
+
devicesTitle: "Benachrichtigungsgeräte",
|
|
1142
|
+
devicesDescription:
|
|
1143
|
+
"Alle Geräte, die Push-Benachrichtigungen für Ihr Konto erhalten. Entfernen Sie die, die Sie nicht mehr nutzen.",
|
|
1144
|
+
devicesLoading: "Geräte werden geladen…",
|
|
1145
|
+
devicesEmpty: "Noch kein Gerät erhält Benachrichtigungen.",
|
|
1146
|
+
unknownDevice: "Unbekanntes Gerät",
|
|
1147
|
+
thisDevice: "Dieses Gerät",
|
|
1148
|
+
added: (date) => `Hinzugefügt am ${date}`,
|
|
1149
|
+
lastDelivery: (date) => `Letzte Zustellung am ${date}`,
|
|
1150
|
+
noDelivery: "Noch keine Zustellung",
|
|
1151
|
+
failures: (count) =>
|
|
1152
|
+
count === 1
|
|
1153
|
+
? `${n(count)} fehlgeschlagene Zustellung in Folge`
|
|
1154
|
+
: `${n(count)} fehlgeschlagene Zustellungen in Folge`,
|
|
1155
|
+
remove: "Entfernen",
|
|
1156
|
+
// Starts with `remove`, the button's visible text, for voice control.
|
|
1157
|
+
removeItem: (device) => `Entfernen: ${device}`,
|
|
1158
|
+
removePrompt: "Keine Benachrichtigungen mehr an dieses Gerät senden?",
|
|
1159
|
+
unsubscribeTitle: "E-Mail-Benachrichtigungen",
|
|
1160
|
+
unsubscribeAbout: (type) => `Sie erhalten E-Mails zu: ${type}.`,
|
|
1161
|
+
unsubscribeGeneric: "Sie erhalten Benachrichtigungs-E-Mails.",
|
|
1162
|
+
stopThese: "Diese E-Mails abbestellen",
|
|
1163
|
+
stopAll: (app) => `Alle Benachrichtigungs-E-Mails von ${app} abbestellen`,
|
|
1164
|
+
stoppedThese: "Erledigt. Sie erhalten diese E-Mails nicht mehr.",
|
|
1165
|
+
stoppedAll: (app) => `Erledigt. Sie erhalten keine Benachrichtigungs-E-Mails von ${app} mehr.`,
|
|
1166
|
+
accountMail: "E-Mails zu Ihrem Konto erhalten Sie weiterhin.",
|
|
1167
|
+
turnBackOn: "Sie können sie jederzeit in den Einstellungen wieder einschalten.",
|
|
1168
|
+
openSettings: "Einstellungen öffnen",
|
|
1169
|
+
invalidLink:
|
|
1170
|
+
"Dieser Link funktioniert nicht mehr. Sie können E-Mails stattdessen in den Einstellungen abbestellen.",
|
|
1171
|
+
failed: "Das hat nicht geklappt. Bitte erneut versuchen.",
|
|
1172
|
+
},
|
|
1075
1173
|
sessions: {
|
|
1076
1174
|
title: "Sitzungen",
|
|
1077
1175
|
description:
|
|
@@ -1634,6 +1732,21 @@ export function germanLabels(numberLocale: string): UiKitLabels {
|
|
|
1634
1732
|
contrastModes: { system: "System", standard: "Standard", more: "Mehr" },
|
|
1635
1733
|
saveFailed: "Konnte nicht in Ihrem Konto gespeichert werden. Auf diesem Gerät gilt es trotzdem.",
|
|
1636
1734
|
},
|
|
1735
|
+
// 0.36.0 — docs/settings-harmonization.md §11.3: resetting this device's settings, the
|
|
1736
|
+
// last card of "Darstellung". "Theme", as `topBar.theme`; "Bereiche" for the panels
|
|
1737
|
+
// (the sidebar, folded groups).
|
|
1738
|
+
deviceReset: {
|
|
1739
|
+
title: "Dieses Gerät zurücksetzen",
|
|
1740
|
+
description:
|
|
1741
|
+
"Setzt die Darstellung auf diesem Gerät und die Ansicht seiner Tabellen und Bereiche auf die Standardwerte zurück. Ihr Konto, Ihre Daten und Ihre Anmeldung bleiben unberührt.",
|
|
1742
|
+
action: "Einstellungen dieses Geräts zurücksetzen",
|
|
1743
|
+
confirmTitle: "Einstellungen dieses Geräts zurücksetzen?",
|
|
1744
|
+
confirmBody:
|
|
1745
|
+
"Theme, Farben, Textgröße, Kontrast und Sprache kehren hier zu ihren Standardwerten zurück, und Tabellen und Bereiche öffnen sich wie beim ersten Mal. Wo Ihr Konto eine Sprache, eine Textgröße oder einen Kontrast festlegt, folgt dieses Gerät wieder dem Konto. Ihr Konto und Ihre anderen Geräte bleiben, wie sie sind.",
|
|
1746
|
+
confirmAction: "Zurücksetzen",
|
|
1747
|
+
done: "Die Einstellungen dieses Geräts sind auf die Standardwerte zurückgesetzt.",
|
|
1748
|
+
keywords: "zurücksetzen standard standardwerte gerät wiederherstellen darstellung tabellen layout",
|
|
1749
|
+
},
|
|
1637
1750
|
rowActions: {
|
|
1638
1751
|
actions: "Aktionen",
|
|
1639
1752
|
actionsFor: (name) => `Aktionen für ${name}`,
|