@veevarts/design-system 2.0.0-alpha.52 → 2.0.0-alpha.55
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/dist/index.cjs +6 -6
- package/dist/index.js +5359 -5105
- package/dist/patterns/AdminTextField/AdminTextField.d.ts +4 -44
- package/dist/patterns/AdminTextField/index.d.ts +2 -2
- package/dist/patterns/AdminTextField/styles.d.ts +29 -0
- package/dist/patterns/AdminTextField/types.d.ts +78 -0
- package/dist/patterns/DonationAmounts/index.d.ts +1 -1
- package/dist/patterns/DonationAmounts/styles.d.ts +19 -0
- package/dist/patterns/DonationAmounts/types.d.ts +24 -0
- package/dist/patterns/DonationAmounts/utils/currency.d.ts +16 -0
- package/dist/patterns/EntityRow/styles.d.ts +15 -0
- package/dist/patterns/EntityRow/types.d.ts +7 -0
- package/dist/patterns/TileSelect/TileSelect.d.ts +2 -115
- package/dist/patterns/TileSelect/index.d.ts +1 -1
- package/dist/patterns/TileSelect/styles.d.ts +42 -0
- package/dist/patterns/TileSelect/types.d.ts +140 -0
- package/dist/patterns/UnderlineTabs/UnderlineTabs.d.ts +11 -3
- package/dist/patterns/UnderlineTabs/styles.d.ts +7 -1
- package/dist/patterns/index.d.ts +3 -3
- package/package.json +1 -1
|
@@ -1,53 +1,13 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
+
import { AdminFieldLabelProps, AdminTextFieldProps } from './types';
|
|
2
3
|
/**
|
|
3
4
|
* The uppercase field label, standalone — for a control this component does
|
|
4
5
|
* not cover (a checkbox group, a read-only preview) that should still be
|
|
5
6
|
* captioned like every other admin field. `suffix` is the lighter tail:
|
|
6
7
|
* "· optional", "· auto-generated, immutable".
|
|
7
|
-
*/
|
|
8
|
-
export declare const AdminFieldLabel: React.FC<{
|
|
9
|
-
children: React.ReactNode;
|
|
10
|
-
suffix?: React.ReactNode;
|
|
11
|
-
className?: string;
|
|
12
|
-
'data-testid'?: string;
|
|
13
|
-
}>;
|
|
14
|
-
interface AdminTextFieldBase {
|
|
15
|
-
/** Uppercase label above the control. Omit only when an adjacent element already names it. */
|
|
16
|
-
label?: React.ReactNode;
|
|
17
|
-
/** Lighter annotation after the label (e.g. `· optional`). Ignored without a label. */
|
|
18
|
-
labelSuffix?: React.ReactNode;
|
|
19
|
-
value: string;
|
|
20
|
-
placeholder?: string;
|
|
21
|
-
disabled?: boolean;
|
|
22
|
-
/** Monospace face without the read-only treatment, for codes the user types. */
|
|
23
|
-
mono?: boolean;
|
|
24
|
-
/** Claim initial focus. Only for the first field of a dialog, never on a page. */
|
|
25
|
-
autoFocus?: boolean;
|
|
26
|
-
/** Small helper or error text under the control. */
|
|
27
|
-
hint?: React.ReactNode;
|
|
28
|
-
/** Renders the hint as an error and marks the control invalid. */
|
|
29
|
-
invalid?: boolean;
|
|
30
|
-
className?: string;
|
|
31
|
-
'data-testid'?: string;
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* `onChange` is REQUIRED unless the field is read-only.
|
|
35
|
-
*
|
|
36
|
-
* This is a controlled input: given a `value` and no handler, React pins it and
|
|
37
|
-
* typing does nothing — a field that looks editable, accepts focus, and silently
|
|
38
|
-
* discards every keystroke. That is indistinguishable from a bug at a glance,
|
|
39
|
-
* and it is what happens by accident when someone renders one to show a value.
|
|
40
8
|
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* and announces it correctly.
|
|
9
|
+
* `isRequired` adds a visible `*` and the screen-reader `requiredLabel`;
|
|
10
|
+
* `help` adds an ⓘ that opens it in a popover, kept outside the label text.
|
|
44
11
|
*/
|
|
45
|
-
export
|
|
46
|
-
readOnly: true;
|
|
47
|
-
onChange?: never;
|
|
48
|
-
} | {
|
|
49
|
-
readOnly?: false;
|
|
50
|
-
onChange: (value: string) => void;
|
|
51
|
-
});
|
|
12
|
+
export declare const AdminFieldLabel: React.FC<AdminFieldLabelProps>;
|
|
52
13
|
export declare const AdminTextField: React.FC<AdminTextFieldProps>;
|
|
53
|
-
export {};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { AdminFieldLabel, AdminTextField } from './AdminTextField';
|
|
2
|
-
export type { AdminTextFieldProps } from './
|
|
3
|
-
export { adminFieldErrorClass, adminFieldHintClass, adminFieldLabelClass, adminFieldLabelSuffixClass, adminInputClass, adminInputReadOnlyClass, adminInputWrapperClass, } from './styles';
|
|
2
|
+
export type { AdminTextFieldProps, AdminFieldLabelProps, AdminFieldRequiredProps, AdminFieldHelpProps } from './types';
|
|
3
|
+
export { adminFieldErrorClass, adminFieldHelpButtonClass, adminFieldHelpContentClass, adminFieldHelpIconClass, adminFieldHintClass, adminFieldLabelClass, adminFieldLabelNoAutoMarkClass, adminFieldLabelRowClass, adminFieldLabelSuffixClass, adminFieldRequiredClass, adminInputClass, adminInputReadOnlyClass, adminInputWrapperClass, } from './styles';
|
|
@@ -22,6 +22,35 @@ export declare const adminFieldLabelClass = "text-[11px] font-semibold uppercase
|
|
|
22
22
|
* aside, not as part of the field's name.
|
|
23
23
|
*/
|
|
24
24
|
export declare const adminFieldLabelSuffixClass = "font-normal normal-case tracking-normal";
|
|
25
|
+
/**
|
|
26
|
+
* The visible `*` of a required field. `after:content-none` switches off the
|
|
27
|
+
* `*` HeroUI's own `isRequired` paints into its label slot, so there is one
|
|
28
|
+
* mark, the one carrying the screen-reader word.
|
|
29
|
+
*/
|
|
30
|
+
export declare const adminFieldRequiredClass = "ms-0.5 text-acct-danger";
|
|
31
|
+
/**
|
|
32
|
+
* The label row a field with `help` draws itself, in place of HeroUI's.
|
|
33
|
+
* HeroUI pushes its box down by `font-size-small + 10px` (24px) to make room
|
|
34
|
+
* for its outside label; this row takes the same height from the same
|
|
35
|
+
* variable, so a field with help and one without line up in a form row.
|
|
36
|
+
* `min-h` rather than `h`, so a label that wraps grows the row instead of
|
|
37
|
+
* running into the box.
|
|
38
|
+
*
|
|
39
|
+
* `text-foreground` because that is the color HeroUI's label actually renders
|
|
40
|
+
* in above the box (`group-data-[filled-within=true]:text-foreground` beats
|
|
41
|
+
* the `text-acct-muted` it is given), measured at `rgb(17, 24, 28)`.
|
|
42
|
+
*/
|
|
43
|
+
export declare const adminFieldLabelRowClass = "mb-0 min-h-[calc(var(--heroui-font-size-small)_+_10px)] text-foreground";
|
|
44
|
+
/** Added to HeroUI's `label` slot so its `isRequired` mark does not double ours. */
|
|
45
|
+
export declare const adminFieldLabelNoAutoMarkClass = "after:content-none";
|
|
46
|
+
/**
|
|
47
|
+
* The ⓘ that opens a field's help: a 24px round hit target (WCAG 2.5.8) whose
|
|
48
|
+
* negative margin keeps the 11px label row from growing to fit it.
|
|
49
|
+
*/
|
|
50
|
+
export declare const adminFieldHelpButtonClass = "ms-0.5 -my-1.5 size-6 min-w-6 align-middle text-acct-sub data-[hover=true]:bg-acct-page data-[hover=true]:text-acct-ink";
|
|
51
|
+
export declare const adminFieldHelpIconClass = "size-4";
|
|
52
|
+
/** The popover the ⓘ opens. Body copy, so sentence case and ink. */
|
|
53
|
+
export declare const adminFieldHelpContentClass = "max-w-xs rounded-xl px-3 py-2 text-xs leading-normal text-acct-ink2";
|
|
25
54
|
/**
|
|
26
55
|
* The 38px box — HeroUI's `inputWrapper` slot, which carries the border and
|
|
27
56
|
* background (the `input` slot is the bare field).
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* The required mark. Plain optional props rather than a union that forces
|
|
4
|
+
* `requiredLabel` with `isRequired`: a union collapses under
|
|
5
|
+
* `Omit<AdminTextFieldProps, …>`, so every wrapper that forwards props would
|
|
6
|
+
* stop compiling.
|
|
7
|
+
*/
|
|
8
|
+
export interface AdminFieldRequiredProps {
|
|
9
|
+
/** Adds a visible `*` after the label (and its suffix). */
|
|
10
|
+
isRequired?: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* The word screen readers hear for the `*` ("required", "obligatoire").
|
|
13
|
+
* Pass it with `isRequired`: the `*` itself is hidden from them.
|
|
14
|
+
*/
|
|
15
|
+
requiredLabel?: string;
|
|
16
|
+
}
|
|
17
|
+
/** Help on demand: an ⓘ button after the label that opens it in a popover. */
|
|
18
|
+
export interface AdminFieldHelpProps {
|
|
19
|
+
help?: React.ReactNode;
|
|
20
|
+
/** Accessible name of the ⓘ ("About timezone"). Without it the ⓘ is named by the label text. */
|
|
21
|
+
helpLabel?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface AdminFieldLabelProps extends AdminFieldRequiredProps, AdminFieldHelpProps {
|
|
24
|
+
children: React.ReactNode;
|
|
25
|
+
/** The lighter tail: "· optional", "· auto-generated, immutable". */
|
|
26
|
+
suffix?: React.ReactNode;
|
|
27
|
+
/**
|
|
28
|
+
* `id` of the control this captions. The text then renders as a real
|
|
29
|
+
* `<label>`, so clicking it focuses the control. The ⓘ stays outside it.
|
|
30
|
+
*/
|
|
31
|
+
htmlFor?: string;
|
|
32
|
+
/** `id` of the text element, for a group to point `aria-labelledby` at. */
|
|
33
|
+
id?: string;
|
|
34
|
+
className?: string;
|
|
35
|
+
'data-testid'?: string;
|
|
36
|
+
}
|
|
37
|
+
export interface AdminTextFieldBase extends AdminFieldRequiredProps, AdminFieldHelpProps {
|
|
38
|
+
/** Uppercase label above the control. Omit only when an adjacent element already names it. */
|
|
39
|
+
label?: React.ReactNode;
|
|
40
|
+
/** Lighter annotation after the label (e.g. `· optional`). Ignored without a label. */
|
|
41
|
+
labelSuffix?: React.ReactNode;
|
|
42
|
+
value: string;
|
|
43
|
+
placeholder?: string;
|
|
44
|
+
disabled?: boolean;
|
|
45
|
+
/** Monospace face without the read-only treatment, for codes the user types. */
|
|
46
|
+
mono?: boolean;
|
|
47
|
+
/** Claim initial focus. Only for the first field of a dialog, never on a page. */
|
|
48
|
+
autoFocus?: boolean;
|
|
49
|
+
/** Small helper or error text under the control. */
|
|
50
|
+
hint?: React.ReactNode;
|
|
51
|
+
/** Renders the hint as an error and marks the control invalid. */
|
|
52
|
+
invalid?: boolean;
|
|
53
|
+
className?: string;
|
|
54
|
+
'data-testid'?: string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* `onChange` is REQUIRED unless the field is read-only.
|
|
58
|
+
*
|
|
59
|
+
* This is a controlled input: given a `value` and no handler, React pins it and
|
|
60
|
+
* typing does nothing — a field that looks editable, accepts focus, and silently
|
|
61
|
+
* discards every keystroke. That is indistinguishable from a bug at a glance,
|
|
62
|
+
* and it is what happens by accident when someone renders one to show a value.
|
|
63
|
+
*
|
|
64
|
+
* Showing a value without accepting edits is a real case, so it stays possible;
|
|
65
|
+
* it just has to be said, with `readOnly`, which also renders it as system-owned
|
|
66
|
+
* and announces it correctly.
|
|
67
|
+
*
|
|
68
|
+
* `isRequired` / `help` behave as on {@link AdminFieldLabelProps}, and are
|
|
69
|
+
* ignored without a `label`. `isRequired` also marks the input
|
|
70
|
+
* `aria-required`, without the browser's own `required` validation.
|
|
71
|
+
*/
|
|
72
|
+
export type AdminTextFieldProps = AdminTextFieldBase & ({
|
|
73
|
+
readOnly: true;
|
|
74
|
+
onChange?: never;
|
|
75
|
+
} | {
|
|
76
|
+
readOnly?: false;
|
|
77
|
+
onChange: (value: string) => void;
|
|
78
|
+
});
|
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
* Ensures exclusive selection (preset OR custom).
|
|
6
6
|
*/
|
|
7
7
|
export { DonationAmounts } from './DonationAmounts';
|
|
8
|
-
export type { DonationAmount, SelectedDonation, DonationLabels, DonationAmountsProps, DonationAmountsVariant, } from './types';
|
|
8
|
+
export type { DonationAmount, SelectedDonation, DonationLabels, DonationAmountsProps, DonationAmountsVariant, DonationAmountsCustomAmountPlacement, } from './types';
|
|
9
9
|
export { formatCurrency, parseCurrency } from './utils/currency';
|
|
@@ -20,6 +20,25 @@ interface VariantSlots {
|
|
|
20
20
|
input: string;
|
|
21
21
|
}
|
|
22
22
|
export declare const donationAmountsSlots: Record<TiledVariant, VariantSlots>;
|
|
23
|
+
/**
|
|
24
|
+
* `customAmountPlacement="inline"` on `tile`: the Quick entry amount row
|
|
25
|
+
* (`Main.dc.html`, `QMDonation.dc.html`), merged over the `tile` slots.
|
|
26
|
+
*
|
|
27
|
+
* One wrapping flex row instead of the grid: tiles `flex: 1 1 4.5rem`, the
|
|
28
|
+
* field `flex: 2 1 10rem`, 8px apart, as the mockup lays them out. Tiles and
|
|
29
|
+
* field are both the mockup's 3rem (`min-h-12` drops the tile's own padding
|
|
30
|
+
* height, `h-12` the field's `size` height), so the row lines up. The field
|
|
31
|
+
* keeps the `tile` hairline, radius, padding and focus ring; its digits are
|
|
32
|
+
* the mockup's 15px and the symbol beside them 14px in the neutral tone.
|
|
33
|
+
*/
|
|
34
|
+
export declare const donationAmountsInline: {
|
|
35
|
+
row: string;
|
|
36
|
+
preset: string;
|
|
37
|
+
field: string;
|
|
38
|
+
inputWrapper: string;
|
|
39
|
+
input: string;
|
|
40
|
+
affix: string;
|
|
41
|
+
};
|
|
23
42
|
/**
|
|
24
43
|
* What `size` changes in `tile` and `pos`: the custom field's height and text.
|
|
25
44
|
* `md` is the mockup's field (38px in `tile`, 40px in `pos`); `sm` and `lg`
|
|
@@ -39,6 +39,18 @@ export interface DonationAmount {
|
|
|
39
39
|
* and a visible label over the custom input.
|
|
40
40
|
*/
|
|
41
41
|
export type DonationAmountsVariant = 'pill' | 'tile' | 'pos';
|
|
42
|
+
/**
|
|
43
|
+
* Where the `tile` variant puts the custom amount field.
|
|
44
|
+
*
|
|
45
|
+
* - `below` (default): a row of its own under the preset grid.
|
|
46
|
+
* - `inline`: the last item of the preset row, the Quick entry amount row
|
|
47
|
+
* (`Main.dc.html`, `QMDonation.dc.html`). Tiles share the row evenly and
|
|
48
|
+
* the field takes twice a tile's share; the row wraps, so in a narrow
|
|
49
|
+
* column the field drops to a full-width line of its own. Tiles and field
|
|
50
|
+
* are both 48px tall, and the currency symbol sits beside the digits on the
|
|
51
|
+
* side the locale puts it, so the field shows "$ Other amount".
|
|
52
|
+
*/
|
|
53
|
+
export type DonationAmountsCustomAmountPlacement = 'below' | 'inline';
|
|
42
54
|
/**
|
|
43
55
|
* Selected donation value (can be preset or custom)
|
|
44
56
|
*/
|
|
@@ -196,6 +208,18 @@ export interface DonationAmountsProps {
|
|
|
196
208
|
* @default 'pill'
|
|
197
209
|
*/
|
|
198
210
|
variant?: DonationAmountsVariant;
|
|
211
|
+
/**
|
|
212
|
+
* Where the custom amount field sits. See
|
|
213
|
+
* {@link DonationAmountsCustomAmountPlacement}. `tile` variant only.
|
|
214
|
+
*
|
|
215
|
+
* `inline` lays the presets out as one wrapping row, so `mobileColumns`
|
|
216
|
+
* and `desktopColumns` do not apply, and it has no room for
|
|
217
|
+
* `labels.customAmountLabel` above the field: when set, that label names
|
|
218
|
+
* the field instead. The preset group then holds the field too, so name it
|
|
219
|
+
* for the whole amount (`labels.title` or `labels.presetsAriaLabel`).
|
|
220
|
+
* @default 'below'
|
|
221
|
+
*/
|
|
222
|
+
customAmountPlacement?: DonationAmountsCustomAmountPlacement;
|
|
199
223
|
/**
|
|
200
224
|
* Marks the title as required with a danger asterisk (`tile` and `pos`
|
|
201
225
|
* variants). The asterisk is decorative; announce the requirement through
|
|
@@ -17,6 +17,22 @@
|
|
|
17
17
|
* formatCurrency(5, 'en-US', 'USD', false) // "$5.00"
|
|
18
18
|
*/
|
|
19
19
|
export declare function formatCurrency(amount: number, locale?: string, currency?: string, trimZeroCents?: boolean): string;
|
|
20
|
+
/**
|
|
21
|
+
* What a field that draws the currency symbol beside the digits needs: the
|
|
22
|
+
* symbol, the side of the digits `locale` puts it on ("$" before in en-US,
|
|
23
|
+
* "$" after in fr-CA), and number formatting with the currency's own fraction
|
|
24
|
+
* digits but no symbol, so the field never shows it twice.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* currencyAffix('en-US', 'USD') // { symbol: '$', position: 'start', formatOptions: { ..., minimumFractionDigits: 2 } }
|
|
28
|
+
* currencyAffix('fr-FR', 'EUR') // { symbol: '€', position: 'end', ... }
|
|
29
|
+
* currencyAffix('ja-JP', 'JPY') // { symbol: '¥', position: 'start', formatOptions: { ..., maximumFractionDigits: 0 } }
|
|
30
|
+
*/
|
|
31
|
+
export declare function currencyAffix(locale?: string, currency?: string): {
|
|
32
|
+
symbol: string;
|
|
33
|
+
position: 'start' | 'end';
|
|
34
|
+
formatOptions: Intl.NumberFormatOptions;
|
|
35
|
+
};
|
|
20
36
|
/**
|
|
21
37
|
* Parses a currency string to a number
|
|
22
38
|
* @param value - The currency string to parse
|
|
@@ -20,6 +20,21 @@ export declare const entityRowClass: {
|
|
|
20
20
|
readonly side: "relative z-10 flex shrink-0 items-center gap-1";
|
|
21
21
|
readonly chevron: "flex shrink-0 text-default-500";
|
|
22
22
|
readonly menuTrigger: "text-default-600";
|
|
23
|
+
/** The menu otherwise grows to its longest line; a description wraps instead. */
|
|
24
|
+
readonly menuWithDescriptions: "max-w-xs";
|
|
25
|
+
/**
|
|
26
|
+
* HeroUI truncates a string description; a reason cut short is no reason.
|
|
27
|
+
* default-600 like the row's subtitle, sized by the same per-size token.
|
|
28
|
+
*/
|
|
29
|
+
readonly menuItemDescription: "whitespace-normal text-default-600";
|
|
30
|
+
/**
|
|
31
|
+
* A disabled item with a description. HeroUI dims the whole item, which
|
|
32
|
+
* would take the description to about 2:1, and opacity cannot be undone by
|
|
33
|
+
* a child. So the item stays opaque and the label and icon are dimmed.
|
|
34
|
+
*/
|
|
35
|
+
readonly menuItemDisabledWithDescription: "opacity-100";
|
|
36
|
+
readonly menuItemDimmed: "opacity-disabled";
|
|
37
|
+
readonly menuItemDimmedIcon: "flex shrink-0 opacity-disabled";
|
|
23
38
|
readonly avatar: "shrink-0 bg-default-200 text-default-700";
|
|
24
39
|
readonly dangerItem: "text-danger";
|
|
25
40
|
};
|
|
@@ -33,6 +33,13 @@ export interface EntityRowAction {
|
|
|
33
33
|
icon?: ReactNode;
|
|
34
34
|
tone?: 'default' | 'danger';
|
|
35
35
|
isDisabled?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Second line under the label, typically why a disabled action is
|
|
38
|
+
* unavailable. It stays readable on a disabled item. react-aria never
|
|
39
|
+
* focuses a disabled item, so the descriptions of disabled actions also
|
|
40
|
+
* describe the `⋯` trigger (`aria-describedby`).
|
|
41
|
+
*/
|
|
42
|
+
description?: string;
|
|
36
43
|
onAction: () => void;
|
|
37
44
|
/** Defaults to `<row testid>-menu-<key>`. */
|
|
38
45
|
'data-testid'?: string;
|
|
@@ -1,117 +1,4 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
key: string;
|
|
5
|
-
/** Visible label rendered under the icon. */
|
|
6
|
-
label: string;
|
|
7
|
-
/**
|
|
8
|
-
* Icon: iconify name (`'lucide:credit-card'`) or a `ReactNode` for
|
|
9
|
-
* fully-custom SVGs.
|
|
10
|
-
*/
|
|
11
|
-
icon: string | React.ReactNode;
|
|
12
|
-
/** Disable the tile (greyed out, no click). */
|
|
13
|
-
isDisabled?: boolean;
|
|
14
|
-
/**
|
|
15
|
-
* One line of supporting copy. Rendered only by `variant="compact"`,
|
|
16
|
-
* for an option that ended up in the "More" menu, where the label
|
|
17
|
-
* alone ("Other") rarely says enough.
|
|
18
|
-
*/
|
|
19
|
-
description?: string;
|
|
20
|
-
/**
|
|
21
|
-
* `variant="compact"` only: keep this option in the "More" menu at
|
|
22
|
-
* every width, however much room the track has. For an action that is
|
|
23
|
-
* secondary by decision rather than by measurement — a payments picker
|
|
24
|
-
* that wants "Other" one click away so the methods people actually
|
|
25
|
-
* reach for own the row.
|
|
26
|
-
*
|
|
27
|
-
* The menu is rendered whenever an option asks for it, so this also
|
|
28
|
-
* overrides the rule that suppresses a menu holding a single option.
|
|
29
|
-
*/
|
|
30
|
-
alwaysInMenu?: boolean;
|
|
31
|
-
/**
|
|
32
|
-
* `variant="compact"` only: what this option is worth keeping on the
|
|
33
|
-
* track. When the pill runs out of room the LOWEST priority folds into
|
|
34
|
-
* the menu first; equal priorities fold from the end of the list.
|
|
35
|
-
* Default `0`.
|
|
36
|
-
*
|
|
37
|
-
* Display order is untouched — this decides what survives a squeeze,
|
|
38
|
-
* not where anything sits. A payments picker can list "Other" before
|
|
39
|
-
* "Split payment" and still lose "Other" first, because splitting a
|
|
40
|
-
* payment is the rarer, weightier thing to reach for.
|
|
41
|
-
*/
|
|
42
|
-
priority?: number;
|
|
43
|
-
/** Override per-tile test id; defaults to `${dataTestId}-${key}`. */
|
|
44
|
-
'data-testid'?: string;
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* `'tiles'` — the icon-over-label grid, with a `<Select>` dropdown under
|
|
48
|
-
* `md`. The picker is the subject of the step.
|
|
49
|
-
*
|
|
50
|
-
* `'compact'` — a segmented pill of label-only toggles at every width,
|
|
51
|
-
* keeping every option the track can hold and folding the rest into a
|
|
52
|
-
* "More" menu rather than scrolling. The picker is a control among others.
|
|
53
|
-
*/
|
|
54
|
-
export type TileSelectVariant = 'tiles' | 'compact';
|
|
55
|
-
/**
|
|
56
|
-
* Tile size for `variant="tiles"`.
|
|
57
|
-
*
|
|
58
|
-
* `'md'` (default) — the 80px icon-over-label tile of the payments drop-in.
|
|
59
|
-
*
|
|
60
|
-
* `'sm'` — the 58px tender tile of the Quick Donation / Quick Membership
|
|
61
|
-
* mockups (`.tender-tile`): 17px icon over an 11.5px label, 10px/4px padding,
|
|
62
|
-
* 12px radius, 8px between tiles; the picked tile takes a brand border, a 9%
|
|
63
|
-
* brand tint and brand text. DS tokens only, rem only.
|
|
64
|
-
*/
|
|
65
|
-
export type TileSelectSize = 'md' | 'sm';
|
|
66
|
-
export interface TileSelectProps {
|
|
67
|
-
/** Options to render in order. */
|
|
68
|
-
options: readonly TileSelectOption[];
|
|
69
|
-
/** Currently selected option `key`. `null` = no selection. */
|
|
70
|
-
selectedKey: string | null;
|
|
71
|
-
/** Fires when a tile is selected. */
|
|
72
|
-
onSelect: (key: string) => void;
|
|
73
|
-
/** Optional heading rendered above the grid. */
|
|
74
|
-
heading?: string;
|
|
75
|
-
/**
|
|
76
|
-
* `aria-label` for the wrapping group when `heading` is omitted.
|
|
77
|
-
* Translatable. Default `'Select an option'`. When `heading` is
|
|
78
|
-
* provided this prop is ignored — the grid is labelled by the
|
|
79
|
-
* heading element.
|
|
80
|
-
*/
|
|
81
|
-
ariaLabel?: string;
|
|
82
|
-
/**
|
|
83
|
-
* How the options render. Default `'tiles'`.
|
|
84
|
-
* See {@link TileSelectVariant}.
|
|
85
|
-
*/
|
|
86
|
-
variant?: TileSelectVariant;
|
|
87
|
-
/**
|
|
88
|
-
* `variant="compact"` only: a CAP on how many options stay on the pill.
|
|
89
|
-
* Unset by default, and normally best left that way — the pill already
|
|
90
|
-
* measures the track and keeps every option that fits, folding only
|
|
91
|
-
* what is left over. Set it when a surface wants a shorter row than
|
|
92
|
-
* its width allows.
|
|
93
|
-
*
|
|
94
|
-
* The cap gives way in one case: when honouring it would leave a single
|
|
95
|
-
* option in the menu that the track had room for. A "More" button is
|
|
96
|
-
* wider than most labels, so that fold costs space and buys a click.
|
|
97
|
-
*/
|
|
98
|
-
maxVisible?: number;
|
|
99
|
-
/**
|
|
100
|
-
* `variant="compact"` only: label for the overflow trigger. Shown
|
|
101
|
-
* until an option inside the menu is selected, after which the
|
|
102
|
-
* trigger carries that option's label. Translatable. Default `'More'`.
|
|
103
|
-
*/
|
|
104
|
-
moreLabel?: string;
|
|
105
|
-
/**
|
|
106
|
-
* Grid columns on >= sm. Default `3`. Mobile collapses to 2.
|
|
107
|
-
* `5` and `6` keep a full method set on one row on a wide surface.
|
|
108
|
-
* Ignored by `variant="compact"`, which is a single strip.
|
|
109
|
-
*/
|
|
110
|
-
columnsDesktop?: 2 | 3 | 4 | 5 | 6;
|
|
111
|
-
columnsMobile?: 1 | 2;
|
|
112
|
-
/** `variant="tiles"` only. See {@link TileSelectSize}. Default `'md'`. */
|
|
113
|
-
size?: TileSelectSize;
|
|
114
|
-
className?: string;
|
|
115
|
-
'data-testid'?: string;
|
|
116
|
-
}
|
|
2
|
+
import { TileSelectProps } from './types';
|
|
3
|
+
export type { TileSelectOption, TileSelectProps, TileSelectSize, TileSelectVariant } from './types';
|
|
117
4
|
export declare const TileSelect: React.FC<TileSelectProps>;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { TileSelect } from './TileSelect';
|
|
2
|
-
export type { TileSelectProps, TileSelectOption, TileSelectVariant, TileSelectSize } from './
|
|
2
|
+
export type { TileSelectProps, TileSelectOption, TileSelectVariant, TileSelectSize } from './types';
|
|
@@ -11,4 +11,46 @@ export declare const smallTileClass: {
|
|
|
11
11
|
readonly active: "border-primary bg-primary/[.09] text-primary data-[hover=true]:bg-primary/[.09]";
|
|
12
12
|
readonly icon: "flex h-[1.0625rem] w-[1.0625rem] items-center justify-center";
|
|
13
13
|
readonly label: "text-[0.71875rem] font-medium leading-[0.875rem]";
|
|
14
|
+
/** `isLocked`: dashed and muted, and inert under the pointer. `pos-muted` is 4.83:1 on white. */
|
|
15
|
+
readonly locked: "cursor-not-allowed border-dashed border-pos-line-strong bg-white text-pos-muted data-[hover=true]:border-pos-line-strong data-[hover=true]:bg-white data-[pressed=true]:scale-100";
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* `size="md"` tile classes.
|
|
19
|
+
*
|
|
20
|
+
* Sized to the Figma spec for the payments-drop-in method picker (PP-1154):
|
|
21
|
+
* 48px inner content (icon 20 + gap 8 + label 20) + 32px vertical padding
|
|
22
|
+
* (`py-4`) = 80px. `h-auto` lets the tile grow past that floor when content
|
|
23
|
+
* wraps (localised long labels, a description).
|
|
24
|
+
*
|
|
25
|
+
* `bg-transparent` suppresses HeroUI's own fill so the active and hover
|
|
26
|
+
* surfaces come from these classes alone.
|
|
27
|
+
*/
|
|
28
|
+
export declare const mediumTileClass: {
|
|
29
|
+
readonly tile: "flex flex-col items-center justify-center gap-2 h-auto min-h-20 px-4 py-4 border bg-transparent transition-colors motion-reduce:transition-none [html[data-pos-reduce-motion=true]_&]:transition-none";
|
|
30
|
+
readonly idle: "border-default-200 text-default-800 hover:bg-default-50";
|
|
31
|
+
readonly active: "border-primary bg-primary-50 text-primary";
|
|
32
|
+
readonly label: "text-sm font-medium";
|
|
33
|
+
/**
|
|
34
|
+
* The grid holds a description or a badge: every tile left-aligns, with
|
|
35
|
+
* the icon and badge on one row, then the label, then the description.
|
|
36
|
+
*/
|
|
37
|
+
readonly detailed: "items-start justify-start gap-1 whitespace-normal text-left";
|
|
38
|
+
/** Wraps the badge under the icon rather than overflowing a narrow tile. */
|
|
39
|
+
readonly header: "mb-1 flex w-full flex-wrap items-start justify-between gap-2";
|
|
40
|
+
/**
|
|
41
|
+
* `default-600`, not 500: on the picked tile's `primary-50` tint the 500
|
|
42
|
+
* measured 4.498:1, a hair under the floor.
|
|
43
|
+
*/
|
|
44
|
+
readonly description: "text-xs font-normal leading-snug text-default-600";
|
|
45
|
+
/** The locked tile's description, muted with the rest of it (4.6:1 on `default-50`). */
|
|
46
|
+
readonly lockedDescription: "text-default-500";
|
|
47
|
+
/** `default-600` on `default-100`: about 7:1. */
|
|
48
|
+
readonly badge: "shrink-0 whitespace-nowrap rounded-full bg-default-100 px-2 py-0.5 text-[11px] font-medium leading-4 text-default-600";
|
|
49
|
+
/**
|
|
50
|
+
* `isLocked`: dashed, muted, inert under the pointer. Muted by color, not
|
|
51
|
+
* opacity, so the text keeps its contrast: `default-500` on `default-50`
|
|
52
|
+
* measures 4.6:1. HeroUI's hover dim and press scale are switched off.
|
|
53
|
+
*/
|
|
54
|
+
readonly locked: "cursor-not-allowed border-dashed border-default-300 bg-default-50 text-default-500 hover:bg-default-50 data-[hover=true]:opacity-100 data-[pressed=true]:scale-100";
|
|
55
|
+
readonly lockedIcon: "text-default-400";
|
|
14
56
|
};
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
export interface TileSelectOption {
|
|
3
|
+
/** Stable identifier returned via `onSelect`. */
|
|
4
|
+
key: string;
|
|
5
|
+
/** Visible label rendered under the icon. */
|
|
6
|
+
label: string;
|
|
7
|
+
/**
|
|
8
|
+
* Icon: iconify name (`'lucide:credit-card'`) or a `ReactNode` for
|
|
9
|
+
* fully-custom SVGs.
|
|
10
|
+
*/
|
|
11
|
+
icon: string | React.ReactNode;
|
|
12
|
+
/**
|
|
13
|
+
* Disable the tile (greyed out, no click). The tile is `disabled`, so it
|
|
14
|
+
* also leaves the tab order. For an option that exists but cannot be
|
|
15
|
+
* picked yet, use `isLocked`.
|
|
16
|
+
*/
|
|
17
|
+
isDisabled?: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* One line of supporting copy. `variant="compact"` renders it for an
|
|
20
|
+
* option that ended up in the "More" menu, where the label alone
|
|
21
|
+
* ("Other") rarely says enough. `variant="tiles"` renders it only in a
|
|
22
|
+
* grid opted in to the detailed tile (some option has a `badge` or is
|
|
23
|
+
* `isLocked`): on the `size="md"` tile under the label, and as the item
|
|
24
|
+
* description in the small-viewport `<Select>`. On its own it changes
|
|
25
|
+
* nothing in the tile grid.
|
|
26
|
+
*/
|
|
27
|
+
description?: string;
|
|
28
|
+
/**
|
|
29
|
+
* A short tag on the tile's top row: "Coming soon", "New".
|
|
30
|
+
* `variant="tiles"` at `size="md"`; also the end of its `<Select>` item.
|
|
31
|
+
* Opts the grid in to the detailed tile.
|
|
32
|
+
*/
|
|
33
|
+
badge?: string;
|
|
34
|
+
/**
|
|
35
|
+
* Shown, not pickable: a dashed, muted tile that ignores presses. Unlike
|
|
36
|
+
* `isDisabled` it stays focusable and is `aria-disabled`, so keyboard and
|
|
37
|
+
* screen-reader users reach it and hear `lockedReason`. `variant="compact"`
|
|
38
|
+
* and the small-viewport `<Select>` treat it as disabled. Opts the grid in
|
|
39
|
+
* to the detailed tile.
|
|
40
|
+
*/
|
|
41
|
+
isLocked?: boolean;
|
|
42
|
+
/** What a locked tile announces. Defaults to `badge`. */
|
|
43
|
+
lockedReason?: string;
|
|
44
|
+
/**
|
|
45
|
+
* `variant="compact"` only: keep this option in the "More" menu at
|
|
46
|
+
* every width, however much room the track has. For an action that is
|
|
47
|
+
* secondary by decision rather than by measurement — a payments picker
|
|
48
|
+
* that wants "Other" one click away so the methods people actually
|
|
49
|
+
* reach for own the row.
|
|
50
|
+
*
|
|
51
|
+
* The menu is rendered whenever an option asks for it, so this also
|
|
52
|
+
* overrides the rule that suppresses a menu holding a single option.
|
|
53
|
+
*/
|
|
54
|
+
alwaysInMenu?: boolean;
|
|
55
|
+
/**
|
|
56
|
+
* `variant="compact"` only: what this option is worth keeping on the
|
|
57
|
+
* track. When the pill runs out of room the LOWEST priority folds into
|
|
58
|
+
* the menu first; equal priorities fold from the end of the list.
|
|
59
|
+
* Default `0`.
|
|
60
|
+
*
|
|
61
|
+
* Display order is untouched — this decides what survives a squeeze,
|
|
62
|
+
* not where anything sits. A payments picker can list "Other" before
|
|
63
|
+
* "Split payment" and still lose "Other" first, because splitting a
|
|
64
|
+
* payment is the rarer, weightier thing to reach for.
|
|
65
|
+
*/
|
|
66
|
+
priority?: number;
|
|
67
|
+
/** Override per-tile test id; defaults to `${dataTestId}-${key}`. */
|
|
68
|
+
'data-testid'?: string;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* `'tiles'` — the icon-over-label grid, with a `<Select>` dropdown under
|
|
72
|
+
* `md`. The picker is the subject of the step.
|
|
73
|
+
*
|
|
74
|
+
* `'compact'` — a segmented pill of label-only toggles at every width,
|
|
75
|
+
* keeping every option the track can hold and folding the rest into a
|
|
76
|
+
* "More" menu rather than scrolling. The picker is a control among others.
|
|
77
|
+
*/
|
|
78
|
+
export type TileSelectVariant = 'tiles' | 'compact';
|
|
79
|
+
/**
|
|
80
|
+
* Tile size for `variant="tiles"`.
|
|
81
|
+
*
|
|
82
|
+
* `'md'` (default) — the 80px icon-over-label tile of the payments drop-in.
|
|
83
|
+
*
|
|
84
|
+
* `'sm'` — the 58px tender tile of the Quick Donation / Quick Membership
|
|
85
|
+
* mockups (`.tender-tile`): 17px icon over an 11.5px label, 10px/4px padding,
|
|
86
|
+
* 12px radius, 8px between tiles; the picked tile takes a brand border, a 9%
|
|
87
|
+
* brand tint and brand text. DS tokens only, rem only.
|
|
88
|
+
*/
|
|
89
|
+
export type TileSelectSize = 'md' | 'sm';
|
|
90
|
+
export interface TileSelectProps {
|
|
91
|
+
/** Options to render in order. */
|
|
92
|
+
options: readonly TileSelectOption[];
|
|
93
|
+
/** Currently selected option `key`. `null` = no selection. */
|
|
94
|
+
selectedKey: string | null;
|
|
95
|
+
/** Fires when a tile is selected. */
|
|
96
|
+
onSelect: (key: string) => void;
|
|
97
|
+
/** Optional heading rendered above the grid. */
|
|
98
|
+
heading?: string;
|
|
99
|
+
/**
|
|
100
|
+
* `aria-label` for the wrapping group when `heading` is omitted.
|
|
101
|
+
* Translatable. Default `'Select an option'`. When `heading` is
|
|
102
|
+
* provided this prop is ignored — the grid is labelled by the
|
|
103
|
+
* heading element.
|
|
104
|
+
*/
|
|
105
|
+
ariaLabel?: string;
|
|
106
|
+
/**
|
|
107
|
+
* How the options render. Default `'tiles'`.
|
|
108
|
+
* See {@link TileSelectVariant}.
|
|
109
|
+
*/
|
|
110
|
+
variant?: TileSelectVariant;
|
|
111
|
+
/**
|
|
112
|
+
* `variant="compact"` only: a CAP on how many options stay on the pill.
|
|
113
|
+
* Unset by default, and normally best left that way — the pill already
|
|
114
|
+
* measures the track and keeps every option that fits, folding only
|
|
115
|
+
* what is left over. Set it when a surface wants a shorter row than
|
|
116
|
+
* its width allows.
|
|
117
|
+
*
|
|
118
|
+
* The cap gives way in one case: when honouring it would leave a single
|
|
119
|
+
* option in the menu that the track had room for. A "More" button is
|
|
120
|
+
* wider than most labels, so that fold costs space and buys a click.
|
|
121
|
+
*/
|
|
122
|
+
maxVisible?: number;
|
|
123
|
+
/**
|
|
124
|
+
* `variant="compact"` only: label for the overflow trigger. Shown
|
|
125
|
+
* until an option inside the menu is selected, after which the
|
|
126
|
+
* trigger carries that option's label. Translatable. Default `'More'`.
|
|
127
|
+
*/
|
|
128
|
+
moreLabel?: string;
|
|
129
|
+
/**
|
|
130
|
+
* Grid columns on >= sm. Default `3`. Mobile collapses to 2.
|
|
131
|
+
* `5` and `6` keep a full method set on one row on a wide surface.
|
|
132
|
+
* Ignored by `variant="compact"`, which is a single strip.
|
|
133
|
+
*/
|
|
134
|
+
columnsDesktop?: 2 | 3 | 4 | 5 | 6;
|
|
135
|
+
columnsMobile?: 1 | 2;
|
|
136
|
+
/** `variant="tiles"` only. See {@link TileSelectSize}. Default `'md'`. */
|
|
137
|
+
size?: TileSelectSize;
|
|
138
|
+
className?: string;
|
|
139
|
+
'data-testid'?: string;
|
|
140
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
-
export type UnderlineTabsSize = 'md' | 'sm';
|
|
2
|
+
export type UnderlineTabsSize = 'md' | 'lg' | 'sm';
|
|
3
3
|
/**
|
|
4
4
|
* `primary`: the page's own tabs; the selected label turns ink.
|
|
5
5
|
* `secondary`: tabs nested inside a section; flush, padded, semibold, the
|
|
@@ -37,14 +37,22 @@ export interface UnderlineTabsProps<K extends string = string> {
|
|
|
37
37
|
onChange: (key: K) => void;
|
|
38
38
|
/** Names the tablist. Required — an unnamed tablist gives no context. */
|
|
39
39
|
ariaLabel: string;
|
|
40
|
-
/**
|
|
40
|
+
/**
|
|
41
|
+
* `md` (default): the back-office strip. `sm`: the Quick Donation / Quick
|
|
42
|
+
* Membership strip. `lg`: the Quick entry header strip.
|
|
43
|
+
*/
|
|
41
44
|
size?: UnderlineTabsSize;
|
|
42
45
|
/** See {@link UnderlineTabsLevel}. Default `primary`. Read by `size="sm"` only. */
|
|
43
46
|
level?: UnderlineTabsLevel;
|
|
47
|
+
/**
|
|
48
|
+
* `true` (default): the strip draws its hairline and keeps its gap to what
|
|
49
|
+
* follows. `false`: neither, for a strip at the foot of a card.
|
|
50
|
+
*/
|
|
51
|
+
showDivider?: boolean;
|
|
44
52
|
className?: string;
|
|
45
53
|
'data-testid'?: string;
|
|
46
54
|
}
|
|
47
|
-
export declare function UnderlineTabs<K extends string = string>({ items, value, onChange, ariaLabel, size, level, className, 'data-testid': dataTestId, }: UnderlineTabsProps<K>): import("react/jsx-runtime").JSX.Element;
|
|
55
|
+
export declare function UnderlineTabs<K extends string = string>({ items, value, onChange, ariaLabel, size, level, showDivider, className, 'data-testid': dataTestId, }: UnderlineTabsProps<K>): import("react/jsx-runtime").JSX.Element;
|
|
48
56
|
export declare namespace UnderlineTabs {
|
|
49
57
|
var displayName: string;
|
|
50
58
|
}
|