material-plus-ui 0.0.1 → 1.0.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 +39 -28
- package/dist/components/accordion/MPAccordion.d.ts +115 -0
- package/dist/components/accordion/MPAccordion.js +1 -0
- package/dist/components/accordion/index.d.ts +2 -0
- package/dist/components/accordion/index.js +1 -0
- package/dist/components/alert/MPAlert.d.ts +91 -0
- package/dist/components/alert/MPAlert.js +1 -0
- package/dist/components/alert/index.d.ts +2 -0
- package/dist/components/alert/index.js +1 -0
- package/dist/components/aspect-ratio/MPAspectRatio.d.ts +69 -0
- package/dist/components/aspect-ratio/MPAspectRatio.js +1 -0
- package/dist/components/aspect-ratio/index.d.ts +2 -0
- package/dist/components/aspect-ratio/index.js +1 -0
- package/dist/components/avatar/MPAvatar.d.ts +97 -0
- package/dist/components/avatar/MPAvatar.js +1 -0
- package/dist/components/avatar/index.d.ts +2 -0
- package/dist/components/avatar/index.js +1 -0
- package/dist/components/badge/MPBadge.d.ts +104 -0
- package/dist/components/badge/MPBadge.js +1 -0
- package/dist/components/badge/index.d.ts +2 -0
- package/dist/components/badge/index.js +1 -0
- package/dist/components/blockquote/MPBlockquote.d.ts +73 -0
- package/dist/components/blockquote/MPBlockquote.js +1 -0
- package/dist/components/blockquote/index.d.ts +2 -0
- package/dist/components/blockquote/index.js +1 -0
- package/dist/components/box/MPBox.d.ts +78 -0
- package/dist/components/box/MPBox.js +1 -0
- package/dist/components/box/index.d.ts +2 -0
- package/dist/components/box/index.js +1 -0
- package/dist/components/breadcrumb/MPBreadcrumb.d.ts +105 -0
- package/dist/components/breadcrumb/MPBreadcrumb.js +1 -0
- package/dist/components/breadcrumb/index.d.ts +2 -0
- package/dist/components/breadcrumb/index.js +1 -0
- package/dist/components/button/MPButton.d.ts +70 -0
- package/dist/components/button/MPButton.js +1 -0
- package/dist/components/button/index.d.ts +2 -0
- package/dist/components/button/index.js +1 -0
- package/dist/components/button-group/MPButtonGroup.d.ts +31 -0
- package/dist/components/button-group/MPButtonGroup.js +1 -0
- package/dist/components/button-group/index.d.ts +2 -0
- package/dist/components/button-group/index.js +1 -0
- package/dist/components/card/MPCard.d.ts +73 -0
- package/dist/components/card/MPCard.js +1 -0
- package/dist/components/card/index.d.ts +2 -0
- package/dist/components/card/index.js +1 -0
- package/dist/components/carousel/MPCarousel.d.ts +116 -0
- package/dist/components/carousel/MPCarousel.js +1 -0
- package/dist/components/carousel/index.d.ts +2 -0
- package/dist/components/carousel/index.js +1 -0
- package/dist/components/chat-bubble/MPChatBubble.d.ts +132 -0
- package/dist/components/chat-bubble/MPChatBubble.js +1 -0
- package/dist/components/chat-bubble/index.d.ts +2 -0
- package/dist/components/chat-bubble/index.js +1 -0
- package/dist/components/checkbox/MPCheckbox.d.ts +76 -0
- package/dist/components/checkbox/MPCheckbox.js +1 -0
- package/dist/components/checkbox/index.d.ts +2 -0
- package/dist/components/checkbox/index.js +1 -0
- package/dist/components/chip/MPChip.d.ts +64 -0
- package/dist/components/chip/MPChip.js +1 -0
- package/dist/components/chip/index.d.ts +2 -0
- package/dist/components/chip/index.js +1 -0
- package/dist/components/collapsible/MPCollapsible.d.ts +97 -0
- package/dist/components/collapsible/MPCollapsible.js +1 -0
- package/dist/components/collapsible/index.d.ts +2 -0
- package/dist/components/collapsible/index.js +1 -0
- package/dist/components/color-picker/MPColorPicker.d.ts +113 -0
- package/dist/components/color-picker/MPColorPicker.js +1 -0
- package/dist/components/color-picker/index.d.ts +2 -0
- package/dist/components/color-picker/index.js +1 -0
- package/dist/components/combobox/MPCombobox.d.ts +147 -0
- package/dist/components/combobox/MPCombobox.js +1 -0
- package/dist/components/combobox/index.d.ts +2 -0
- package/dist/components/combobox/index.js +1 -0
- package/dist/components/date-picker/MPDatePicker.d.ts +95 -0
- package/dist/components/date-picker/MPDatePicker.js +1 -0
- package/dist/components/date-picker/index.d.ts +2 -0
- package/dist/components/date-picker/index.js +1 -0
- package/dist/components/date-range-picker/MPDateRangePicker.d.ts +98 -0
- package/dist/components/date-range-picker/MPDateRangePicker.js +1 -0
- package/dist/components/date-range-picker/index.d.ts +2 -0
- package/dist/components/date-range-picker/index.js +1 -0
- package/dist/components/date-time-picker/MPDateTimePicker.d.ts +78 -0
- package/dist/components/date-time-picker/MPDateTimePicker.js +1 -0
- package/dist/components/date-time-picker/index.d.ts +2 -0
- package/dist/components/date-time-picker/index.js +1 -0
- package/dist/components/dialog/MPDialog.d.ts +145 -0
- package/dist/components/dialog/MPDialog.js +1 -0
- package/dist/components/dialog/index.d.ts +2 -0
- package/dist/components/dialog/index.js +1 -0
- package/dist/components/divider/MPDivider.d.ts +80 -0
- package/dist/components/divider/MPDivider.js +1 -0
- package/dist/components/divider/index.d.ts +2 -0
- package/dist/components/divider/index.js +1 -0
- package/dist/components/drawer/MPDrawer.d.ts +163 -0
- package/dist/components/drawer/MPDrawer.js +1 -0
- package/dist/components/drawer/index.d.ts +2 -0
- package/dist/components/drawer/index.js +1 -0
- package/dist/components/empty/MPEmpty.d.ts +64 -0
- package/dist/components/empty/MPEmpty.js +1 -0
- package/dist/components/empty/index.d.ts +2 -0
- package/dist/components/empty/index.js +1 -0
- package/dist/components/file-picker/MPFilePicker.d.ts +103 -0
- package/dist/components/file-picker/MPFilePicker.js +1 -0
- package/dist/components/file-picker/index.d.ts +2 -0
- package/dist/components/file-picker/index.js +1 -0
- package/dist/components/highlight/MPHighlight.d.ts +95 -0
- package/dist/components/highlight/MPHighlight.js +1 -0
- package/dist/components/highlight/index.d.ts +2 -0
- package/dist/components/highlight/index.js +1 -0
- package/dist/components/icon-button/MPIconButton.d.ts +59 -0
- package/dist/components/icon-button/MPIconButton.js +1 -0
- package/dist/components/icon-button/index.d.ts +2 -0
- package/dist/components/icon-button/index.js +1 -0
- package/dist/components/list/MPList.d.ts +96 -0
- package/dist/components/list/MPList.js +1 -0
- package/dist/components/list/index.d.ts +2 -0
- package/dist/components/list/index.js +1 -0
- package/dist/components/locale/MPLocaleProvider.d.ts +63 -0
- package/dist/components/locale/MPLocaleProvider.js +1 -0
- package/dist/components/locale/index.d.ts +2 -0
- package/dist/components/locale/index.js +1 -0
- package/dist/components/menu/MPMenu.d.ts +223 -0
- package/dist/components/menu/MPMenu.js +1 -0
- package/dist/components/menu/index.d.ts +2 -0
- package/dist/components/menu/index.js +1 -0
- package/dist/components/number-field/MPNumberField.d.ts +99 -0
- package/dist/components/number-field/MPNumberField.js +1 -0
- package/dist/components/number-field/index.d.ts +2 -0
- package/dist/components/number-field/index.js +1 -0
- package/dist/components/otp-field/MPOtpField.d.ts +89 -0
- package/dist/components/otp-field/MPOtpField.js +1 -0
- package/dist/components/otp-field/index.d.ts +2 -0
- package/dist/components/otp-field/index.js +1 -0
- package/dist/components/overlay/MPOverlay.d.ts +96 -0
- package/dist/components/overlay/MPOverlay.js +1 -0
- package/dist/components/overlay/index.d.ts +2 -0
- package/dist/components/overlay/index.js +1 -0
- package/dist/components/panes/MPPanes.d.ts +100 -0
- package/dist/components/panes/MPPanes.js +1 -0
- package/dist/components/panes/index.d.ts +2 -0
- package/dist/components/panes/index.js +1 -0
- package/dist/components/pill/MPPill.d.ts +117 -0
- package/dist/components/pill/MPPill.js +1 -0
- package/dist/components/pill/index.d.ts +2 -0
- package/dist/components/pill/index.js +1 -0
- package/dist/components/popover/MPPopover.d.ts +138 -0
- package/dist/components/popover/MPPopover.js +1 -0
- package/dist/components/popover/index.d.ts +2 -0
- package/dist/components/popover/index.js +1 -0
- package/dist/components/progress-box/MPProgressBox.d.ts +40 -0
- package/dist/components/progress-box/MPProgressBox.js +1 -0
- package/dist/components/progress-box/index.d.ts +2 -0
- package/dist/components/progress-box/index.js +1 -0
- package/dist/components/progress-circular/MPProgressCircular.d.ts +32 -0
- package/dist/components/progress-circular/MPProgressCircular.js +1 -0
- package/dist/components/progress-circular/index.d.ts +2 -0
- package/dist/components/progress-circular/index.js +1 -0
- package/dist/components/progress-linear/MPProgressLinear.d.ts +32 -0
- package/dist/components/progress-linear/MPProgressLinear.js +1 -0
- package/dist/components/progress-linear/index.d.ts +2 -0
- package/dist/components/progress-linear/index.js +1 -0
- package/dist/components/radio-group/MPRadioGroup.d.ts +81 -0
- package/dist/components/radio-group/MPRadioGroup.js +1 -0
- package/dist/components/radio-group/index.d.ts +2 -0
- package/dist/components/radio-group/index.js +1 -0
- package/dist/components/segmented-button/MPSegmentedButton.d.ts +75 -0
- package/dist/components/segmented-button/MPSegmentedButton.js +1 -0
- package/dist/components/segmented-button/index.d.ts +2 -0
- package/dist/components/segmented-button/index.js +1 -0
- package/dist/components/select/MPSelect.d.ts +86 -0
- package/dist/components/select/MPSelect.js +1 -0
- package/dist/components/select/index.d.ts +2 -0
- package/dist/components/select/index.js +1 -0
- package/dist/components/shortcut/MPShortcut.d.ts +67 -0
- package/dist/components/shortcut/MPShortcut.js +1 -0
- package/dist/components/shortcut/index.d.ts +2 -0
- package/dist/components/shortcut/index.js +1 -0
- package/dist/components/skeleton/MPSkeleton.d.ts +76 -0
- package/dist/components/skeleton/MPSkeleton.js +1 -0
- package/dist/components/skeleton/index.d.ts +2 -0
- package/dist/components/skeleton/index.js +1 -0
- package/dist/components/slider/MPSlider.d.ts +77 -0
- package/dist/components/slider/MPSlider.js +1 -0
- package/dist/components/slider/index.d.ts +2 -0
- package/dist/components/slider/index.js +1 -0
- package/dist/components/snackbar/MPSnackbar.d.ts +170 -0
- package/dist/components/snackbar/MPSnackbar.js +1 -0
- package/dist/components/snackbar/index.d.ts +2 -0
- package/dist/components/snackbar/index.js +1 -0
- package/dist/components/spoiler/MPSpoiler.d.ts +106 -0
- package/dist/components/spoiler/MPSpoiler.js +1 -0
- package/dist/components/spoiler/index.d.ts +2 -0
- package/dist/components/spoiler/index.js +1 -0
- package/dist/components/switch/MPSwitch.d.ts +75 -0
- package/dist/components/switch/MPSwitch.js +1 -0
- package/dist/components/switch/index.d.ts +2 -0
- package/dist/components/switch/index.js +1 -0
- package/dist/components/table/MPTable.d.ts +107 -0
- package/dist/components/table/MPTable.js +1 -0
- package/dist/components/table/index.d.ts +2 -0
- package/dist/components/table/index.js +1 -0
- package/dist/components/text-field/MPTextField.d.ts +17 -18
- package/dist/components/text-field/MPTextField.js +1 -1
- package/dist/components/text-link/MPTextLink.d.ts +88 -0
- package/dist/components/text-link/MPTextLink.js +1 -0
- package/dist/components/text-link/index.d.ts +2 -0
- package/dist/components/text-link/index.js +1 -0
- package/dist/components/time-picker/MPTimePicker.d.ts +108 -0
- package/dist/components/time-picker/MPTimePicker.js +1 -0
- package/dist/components/time-picker/index.d.ts +2 -0
- package/dist/components/time-picker/index.js +1 -0
- package/dist/components/timeline/MPTimeline.d.ts +96 -0
- package/dist/components/timeline/MPTimeline.js +1 -0
- package/dist/components/timeline/index.d.ts +2 -0
- package/dist/components/timeline/index.js +1 -0
- package/dist/components/tooltip/MPTooltip.d.ts +117 -0
- package/dist/components/tooltip/MPTooltip.js +1 -0
- package/dist/components/tooltip/index.d.ts +2 -0
- package/dist/components/tooltip/index.js +1 -0
- package/dist/components/typography/MPTypography.d.ts +94 -0
- package/dist/components/typography/MPTypography.js +1 -0
- package/dist/components/typography/index.d.ts +2 -0
- package/dist/components/typography/index.js +1 -0
- package/dist/constants/icons.d.ts +36 -0
- package/dist/constants/icons.js +1 -1
- package/dist/index.d.ts +55 -0
- package/dist/index.js +1 -1
- package/dist/internal/Calendar.d.ts +118 -0
- package/dist/internal/Calendar.js +1 -0
- package/dist/internal/FieldOutline.d.ts +38 -0
- package/dist/internal/FieldOutline.js +1 -0
- package/dist/internal/Picker.d.ts +110 -0
- package/dist/internal/Picker.js +1 -0
- package/dist/internal/StateLayer.d.ts +45 -0
- package/dist/internal/StateLayer.js +1 -0
- package/dist/internal/SupportingText.d.ts +23 -0
- package/dist/internal/SupportingText.js +1 -0
- package/dist/internal/WidthSizer.d.ts +31 -0
- package/dist/internal/WidthSizer.js +1 -0
- package/dist/internal/accent.d.ts +39 -0
- package/dist/internal/accent.js +1 -0
- package/dist/internal/button-group.d.ts +21 -0
- package/dist/internal/button-group.js +1 -0
- package/dist/internal/color.d.ts +125 -0
- package/dist/internal/color.js +1 -0
- package/dist/internal/date.d.ts +179 -0
- package/dist/internal/date.js +1 -0
- package/dist/internal/i18n.d.ts +131 -0
- package/dist/internal/i18n.js +1 -0
- package/dist/internal/locale.d.ts +43 -0
- package/dist/internal/locale.js +1 -0
- package/dist/internal/menu.d.ts +23 -0
- package/dist/internal/menu.js +1 -0
- package/dist/internal/progress.d.ts +126 -0
- package/dist/internal/progress.js +1 -0
- package/dist/internal/scale.d.ts +127 -0
- package/dist/internal/scale.js +1 -0
- package/dist/internal/surface.d.ts +76 -0
- package/dist/internal/surface.js +1 -0
- package/dist/internal/visually-hidden.d.ts +23 -0
- package/dist/internal/visually-hidden.js +1 -0
- package/dist/styles.css +1 -1
- package/dist/tailwind.css +1285 -20
- package/dist/types.d.ts +107 -16
- package/package.json +16 -21
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { MPStyleProps } from '../../types';
|
|
3
|
+
/**
|
|
4
|
+
* Where the two steppers sit.
|
|
5
|
+
*
|
|
6
|
+
* - `end` — both at the trailing edge, the way a spinner has always looked.
|
|
7
|
+
* - `split` — minus at the start, plus at the end, with the number between them.
|
|
8
|
+
* For a quantity that is nudged rather than typed.
|
|
9
|
+
* - `none` — no buttons. It is still a number field: the arrow keys, the
|
|
10
|
+
* clamping and the formatting all stay.
|
|
11
|
+
*
|
|
12
|
+
* There is deliberately no stacked pair of half-height chevrons. At `xs` each
|
|
13
|
+
* arrow would be under three pixels tall, and a target that small is a target
|
|
14
|
+
* nobody hits.
|
|
15
|
+
*/
|
|
16
|
+
export type MPNumberFieldSteppers = 'end' | 'split' | 'none';
|
|
17
|
+
export interface MPNumberFieldProps extends MPStyleProps {
|
|
18
|
+
/** The number. Use with `onValueChange` for a controlled field. */
|
|
19
|
+
value?: number | null;
|
|
20
|
+
/** The starting number, for an uncontrolled field. */
|
|
21
|
+
defaultValue?: number;
|
|
22
|
+
/** Called on every change — typing, stepping, the wheel. */
|
|
23
|
+
onValueChange?: (value: number | null) => void;
|
|
24
|
+
/**
|
|
25
|
+
* Called when the value settles: on blur after typing, on pointer release
|
|
26
|
+
* after a press, and together with `onValueChange` for the keyboard.
|
|
27
|
+
*/
|
|
28
|
+
onValueCommitted?: (value: number | null) => void;
|
|
29
|
+
/** The bottom of the range. Stepping stops here. */
|
|
30
|
+
min?: number;
|
|
31
|
+
/** The top of the range. */
|
|
32
|
+
max?: number;
|
|
33
|
+
/** How far one step goes. @default 1 */
|
|
34
|
+
step?: number;
|
|
35
|
+
/** The step taken while Shift is held. @default 10 */
|
|
36
|
+
largeStep?: number;
|
|
37
|
+
/** The step taken while Alt is held. @default 0.1 */
|
|
38
|
+
smallStep?: number;
|
|
39
|
+
/**
|
|
40
|
+
* Whether the wheel changes the value while the field is focused and hovered.
|
|
41
|
+
* Off by default: a page that scrolls under the pointer and a field that
|
|
42
|
+
* changes under it are the same gesture, and only one of them was meant.
|
|
43
|
+
* @default false
|
|
44
|
+
*/
|
|
45
|
+
allowWheelScrub?: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* How the number is written — currency, percent, decimal places. Passed
|
|
48
|
+
* straight to `Intl.NumberFormat`, so the field can show `$1,240.00` and still
|
|
49
|
+
* report `1240`.
|
|
50
|
+
*/
|
|
51
|
+
format?: Intl.NumberFormatOptions;
|
|
52
|
+
/** Which locale the number is written and parsed in. Defaults to the runtime's. */
|
|
53
|
+
locale?: Intl.LocalesArgument;
|
|
54
|
+
/**
|
|
55
|
+
* Where the steppers sit, or `none` for a field without them.
|
|
56
|
+
* @default 'end'
|
|
57
|
+
*/
|
|
58
|
+
steppers?: MPNumberFieldSteppers;
|
|
59
|
+
/** The accessible name of the increment button. @default 'Increase' */
|
|
60
|
+
incrementLabel?: string;
|
|
61
|
+
/** The accessible name of the decrement button. @default 'Decrease' */
|
|
62
|
+
decrementLabel?: string;
|
|
63
|
+
/** Label in the outline's notch. */
|
|
64
|
+
label?: React.ReactNode;
|
|
65
|
+
/** The line under the control. Replaced by `errorMessage` when there is one. */
|
|
66
|
+
description?: React.ReactNode;
|
|
67
|
+
/** The message under the control, which also turns the field over. */
|
|
68
|
+
errorMessage?: React.ReactNode;
|
|
69
|
+
/** Placeholder shown while the field is empty. */
|
|
70
|
+
placeholder?: string;
|
|
71
|
+
/** Content placed before the number — a currency mark, a unit, an icon. */
|
|
72
|
+
startIcon?: React.ReactNode;
|
|
73
|
+
/** Marks the field required. */
|
|
74
|
+
required?: boolean;
|
|
75
|
+
/** Greys the field out and stops it taking input. */
|
|
76
|
+
disabled?: boolean;
|
|
77
|
+
/** Shows the number without allowing edits, and drops the steppers. */
|
|
78
|
+
readOnly?: boolean;
|
|
79
|
+
/** Name of the form control. */
|
|
80
|
+
name?: string;
|
|
81
|
+
/** The id put on the control and pointed at by the label. */
|
|
82
|
+
id?: string;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* A Material Design field that only holds a number.
|
|
86
|
+
*
|
|
87
|
+
* The shell is `MPTextField`'s, to the pixel — the same notched outline, the same
|
|
88
|
+
* label in the notch, the same supporting text — because a form where the
|
|
89
|
+
* quantity box is a different height or radius from the boxes around it is a form
|
|
90
|
+
* that looks assembled rather than designed.
|
|
91
|
+
*
|
|
92
|
+
* What is added on top is a real numeric control rather than
|
|
93
|
+
* `<input type="number">`, which is worth being explicit about: the native one
|
|
94
|
+
* silently accepts text in some browsers, has a spinner nobody can style, scrubs
|
|
95
|
+
* on scroll by default, and reports `''` for anything it cannot parse. Base UI's
|
|
96
|
+
* owns the parsing against the locale, the clamping, the press-and-hold repeat on
|
|
97
|
+
* the steppers, and the hidden input that submits with a form.
|
|
98
|
+
*/
|
|
99
|
+
export declare function MPNumberField({ value, defaultValue, onValueChange, onValueCommitted, min, max, step, largeStep, smallStep, allowWheelScrub, format, locale, steppers, incrementLabel, decrementLabel, label, description, errorMessage, placeholder, startIcon, size, fullWidth, required, disabled, readOnly, name, id }: MPNumberFieldProps): React.JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as a}from"react/jsx-runtime";import*as r from"react";import{NumberField as l}from"@base-ui/react/number-field";import{Field as n}from"@base-ui/react/field";import{MPIcon as t}from"../icon/MPIcon";import{AddIcon as i,RemoveIcon as s}from"../../constants/icons";import{MPFieldLabel as o,MPFieldOutline as p}from"../../internal/FieldOutline";import{MPStateLayer as m}from"../../internal/StateLayer";import{MPSupportingText as d}from"../../internal/SupportingText";import{CONTROL_ICON as c,PROSE_TEXT as u,hasContent as f}from"../../internal/scale";const h={xs:{padding:"px-2",height:"h-8",stepper:"size-6"},sm:{padding:"px-3",height:"h-10",stepper:"size-8"},md:{padding:"px-4",height:"h-14",stepper:"size-10"},lg:{padding:"px-4",height:"h-16",stepper:"size-11"},xl:{padding:"px-5",height:"h-18",stepper:"size-12"}};export function MPNumberField({value:x,defaultValue:g,onValueChange:b,onValueCommitted:N,min:v,max:z,step:j,largeStep:y,smallStep:w,allowWheelScrub:S=!1,format:I,locale:V,steppers:q="end",incrementLabel:C="Increase",decrementLabel:M="Decrease",label:k,description:F,errorMessage:L,placeholder:O,startIcon:W,size:D="md",fullWidth:P=!1,required:R=!1,disabled:$=!1,readOnly:_=!1,name:B,id:G}){const T=f(L),A=h[D],E=r.useId(),H=G??`mp-number-field-${B??E}`,J="none"!==q&&!_&&!$,K=["mp-number-field__stepper group relative flex shrink-0 items-center justify-center","rounded-mp-full cursor-pointer appearance-none bg-transparent p-0 font-[inherit]","text-mp-on-surface-variant outline-none","disabled:text-mp-on-surface/38 disabled:cursor-default",A.stepper].join(" "),Q=a(l.Decrement,{"aria-label":M,className:K,children:[e(m,{}),e(t,{icon:s,size:c[D]})]}),U=a(l.Increment,{"aria-label":C,className:K,children:[e(m,{}),e(t,{icon:i,size:c[D]})]});return a(n.Root,{className:["mp-number-field group flex-col align-top",P?"flex w-full":"inline-flex w-fit"].join(" "),disabled:$,invalid:T,"data-mp-size":D,children:[e(l.Root,{id:H,name:B,className:"contents",value:x,defaultValue:g,onValueChange:e=>b?.(e),onValueCommitted:e=>N?.(e),min:v,max:z,step:j,largeStep:y,smallStep:w,allowWheelScrub:S,format:I,locale:V,disabled:$,readOnly:_,required:R,children:a("div",{className:"relative w-full",children:[a(l.Group,{className:["flex w-full items-center gap-2",A.height,J&&"end"===q?`${A.padding} pe-1`:J&&"split"===q?"px-1":A.padding].join(" "),children:[J&&"split"===q?Q:null,W?e("span",{className:["flex shrink-0 items-center",$?"text-mp-on-surface/38":"text-mp-on-surface-variant"].join(" "),children:W}):null,e(l.Input,{placeholder:O,className:["w-full min-w-0 flex-1 tabular-nums",u[D],"font-[family-name:var(--mp-sys-typescale-body-large-font)]","appearance-none border-0 bg-transparent px-0 outline-none","caret-mp-primary text-mp-on-surface","placeholder:text-mp-on-surface-variant","disabled:text-mp-on-surface/38 disabled:placeholder:text-mp-on-surface/38",J&&"split"===q?"text-center":""].filter(Boolean).join(" ")}),J&&"end"===q?a("span",{className:"flex shrink-0 items-center",children:[Q,U]}):null,J&&"split"===q?U:null]}),e(p,{label:k,required:R}),f(k)?e(o,{size:D,label:k,required:R,htmlFor:H}):null]})}),e(d,{description:F,errorMessage:L,className:A.padding})]})}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{MPNumberField}from"./MPNumberField";
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { MPStyleProps } from '../../types';
|
|
3
|
+
/**
|
|
4
|
+
* What may be typed into a slot.
|
|
5
|
+
*
|
|
6
|
+
* `numeric` is the default because that is what a texted code is, and it is also
|
|
7
|
+
* what puts a number pad in front of a phone. `any` accepts whatever the keyboard
|
|
8
|
+
* produces — for a licence key with punctuation in it.
|
|
9
|
+
*/
|
|
10
|
+
export type MPOtpFieldCharset = 'numeric' | 'alpha' | 'alphanumeric' | 'any';
|
|
11
|
+
export interface MPOtpFieldProps extends MPStyleProps {
|
|
12
|
+
/**
|
|
13
|
+
* How many characters the code has. Clamped to 2–12: a single box is an
|
|
14
|
+
* `MPTextField`, and past twelve the row stops fitting a phone.
|
|
15
|
+
* @default 6
|
|
16
|
+
*/
|
|
17
|
+
length?: number;
|
|
18
|
+
/**
|
|
19
|
+
* What may be typed. Anything rejected is dropped rather than shown, and
|
|
20
|
+
* `onValueInvalid` reports it.
|
|
21
|
+
* @default 'numeric'
|
|
22
|
+
*/
|
|
23
|
+
charset?: MPOtpFieldCharset;
|
|
24
|
+
/** Hides the characters, the way a password field does. @default false */
|
|
25
|
+
mask?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Splits the row every `groupSize` slots with a separator. `3` on a six-digit
|
|
28
|
+
* code gives the familiar two blocks of three.
|
|
29
|
+
*/
|
|
30
|
+
groupSize?: number;
|
|
31
|
+
/** What is drawn between two groups. @default '–' */
|
|
32
|
+
separator?: React.ReactNode;
|
|
33
|
+
/** The code. Use with `onValueChange` for a controlled field. */
|
|
34
|
+
value?: string;
|
|
35
|
+
/** What it starts as, for an uncontrolled one. */
|
|
36
|
+
defaultValue?: string;
|
|
37
|
+
onValueChange?: (value: string) => void;
|
|
38
|
+
/** Fires once every slot is filled — the moment to verify the code. */
|
|
39
|
+
onComplete?: (value: string) => void;
|
|
40
|
+
/** Fires when typed or pasted text held characters the charset rejects. */
|
|
41
|
+
onValueInvalid?: (value: string) => void;
|
|
42
|
+
/** Submits the owning form as soon as the code is complete. @default false */
|
|
43
|
+
autoSubmit?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* The label above the row.
|
|
46
|
+
*
|
|
47
|
+
* Above it rather than in a notch, which is the one place this control departs
|
|
48
|
+
* from `MPTextField`'s shell. A notched label belongs to *one* outlined box; a
|
|
49
|
+
* code is six of them, and cutting the notch into the first would name the
|
|
50
|
+
* first digit rather than the field.
|
|
51
|
+
*/
|
|
52
|
+
label?: React.ReactNode;
|
|
53
|
+
/** The line under the row. Replaced by `errorMessage` when there is one. */
|
|
54
|
+
description?: React.ReactNode;
|
|
55
|
+
/**
|
|
56
|
+
* The message under the row. Its presence is also what puts the field into its
|
|
57
|
+
* error state — there is no separate boolean, so there is no way to render a
|
|
58
|
+
* control that is visibly wrong with no explanation of why.
|
|
59
|
+
*/
|
|
60
|
+
errorMessage?: React.ReactNode;
|
|
61
|
+
/** Name of the form control. */
|
|
62
|
+
name?: string;
|
|
63
|
+
/** The form must have a complete code before it submits. @default false */
|
|
64
|
+
required?: boolean;
|
|
65
|
+
/** Greys every slot out and stops them taking input. */
|
|
66
|
+
disabled?: boolean;
|
|
67
|
+
/** Readable and copyable, but not typeable. @default false */
|
|
68
|
+
readOnly?: boolean;
|
|
69
|
+
/** Puts the caret in the first slot on mount. @default false */
|
|
70
|
+
autoFocus?: boolean;
|
|
71
|
+
className?: string;
|
|
72
|
+
style?: React.CSSProperties;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* A row of one-character slots: a PIN, a texted verification code, an invite key.
|
|
76
|
+
*
|
|
77
|
+
* Base UI owns everything that makes this harder than it looks — one hidden value
|
|
78
|
+
* behind however many inputs, paste spread across the slots from wherever the
|
|
79
|
+
* caret was, backspace stepping back a box, a click landing on the first empty
|
|
80
|
+
* slot rather than the one under the pointer, and the autofill hook that lets a
|
|
81
|
+
* phone offer the code straight from the message.
|
|
82
|
+
*
|
|
83
|
+
* What is here is the box a slot is drawn in, and it is Material's outlined text
|
|
84
|
+
* field cut down to one character: the same `corner-extra-small`, the same
|
|
85
|
+
* hairline in `outline`, the same two-pixel `primary` ring on focus. A form
|
|
86
|
+
* holding a text field and a code should not look like two form kits stacked on
|
|
87
|
+
* each other.
|
|
88
|
+
*/
|
|
89
|
+
export declare const MPOtpField: React.ForwardRefExoticComponent<MPOtpFieldProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as r}from"react/jsx-runtime";import*as a from"react";import{Field as t}from"@base-ui/react/field";import{OTPField as o}from"@base-ui/react/otp-field";import{MPSupportingText as n}from"../../internal/SupportingText";import{META_TEXT as l,STACK_GAP as i,hasContent as m}from"../../internal/scale";const s={xs:"h-8 w-7",sm:"h-10 w-9",md:"h-14 w-12",lg:"h-16 w-14",xl:"h-18 w-16"},d={xs:"text-mp-body-large",sm:"text-mp-title-medium",md:"text-mp-title-large",lg:"text-mp-headline-small",xl:"text-mp-headline-medium"},u={xs:"gap-1",sm:"gap-1.5",md:"gap-2",lg:"gap-2.5",xl:"gap-3"},p={numeric:"numeric",alpha:"alpha",alphanumeric:"alphanumeric",any:"none"};export const MPOtpField=a.forwardRef(function({size:c="md",fullWidth:f=!1,length:h=6,charset:x="numeric",mask:b=!1,groupSize:g,separator:v="–",value:y,defaultValue:w,onValueChange:M,onComplete:V,onValueInvalid:N,autoSubmit:j=!1,label:C,description:F,errorMessage:S,name:z,required:I=!1,disabled:O=!1,readOnly:R=!1,autoFocus:$=!1,className:k,style:q},T){const A=Math.min(12,Math.max(2,Math.round(h))),B=m(S),L=g&&g>0?Math.round(g):0,P=["rounded-mp-xs border bg-transparent text-center font-[inherit]",s[c],d[c],"transition-[border-color,color] duration-(--mp-sys-motion-duration-short4)","focus:border-2 focus:border-mp-primary focus:outline-none",O?"border-mp-on-surface/12 text-mp-on-surface/38 cursor-default":B?"border-mp-error text-mp-on-surface caret-mp-error hover:border-mp-error":R?"border-mp-outline-variant text-mp-on-surface cursor-default":"border-mp-outline text-mp-on-surface caret-mp-primary hover:border-mp-on-surface"].join(" ");return r(t.Root,{disabled:O,invalid:B,"data-mp-size":c,className:["mp-otp-field flex-col align-top",i[c],f?"flex w-full":"inline-flex w-fit",k??""].filter(Boolean).join(" "),style:q,children:[m(C)?r(t.Label,{className:`${l} text-mp-on-surface-variant data-disabled:text-mp-on-surface/38 data-invalid:text-mp-error`,children:[C,I?e("span",{"aria-hidden":"true",children:" *"}):null]}):null,e(o.Root,{ref:T,length:A,validationType:p[x],mask:b,name:z,required:I,disabled:O,readOnly:R,autoSubmit:j,value:y,defaultValue:w,onValueChange:e=>M?.(e),onValueComplete:e=>V?.(e),onValueInvalid:e=>N?.(e),className:`flex items-center ${u[c]}`,children:Array.from({length:A},(t,n)=>r(a.Fragment,{children:[L>0&&n>0&&n%L===0?e("span",{"aria-hidden":"true",className:`text-mp-on-surface-variant px-0.5 select-none ${d[c]}`,children:v}):null,e(o.Input,{className:P,autoFocus:$&&0===n})]},n))}),e(n,{description:F,errorMessage:S})]})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{MPOtpField}from"./MPOtpField";
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { MPAlign, MPSize } from '../../types';
|
|
3
|
+
/**
|
|
4
|
+
* How much of the page the overlay takes away.
|
|
5
|
+
*
|
|
6
|
+
* One axis, four steps — how legible is what is behind — and they are tuned with
|
|
7
|
+
* the blur radius as much as with the alpha, because past about 16px a backdrop
|
|
8
|
+
* smears into flat colour and the sheet reads opaque however low its alpha goes.
|
|
9
|
+
*
|
|
10
|
+
* - `scrim` — MD3's own scrim, and exactly what `MPDialog` puts behind itself.
|
|
11
|
+
* The page is still there and still readable; it has only stopped being
|
|
12
|
+
* reachable.
|
|
13
|
+
* - `blur` — frosted. A lighter dim over a real blur, so the page is present as
|
|
14
|
+
* shape and colour but not as words. For "this is being replaced".
|
|
15
|
+
* - `solid` — the page's own `surface`, opaque. For a screen that is genuinely
|
|
16
|
+
* gone.
|
|
17
|
+
* - `clear` — nothing drawn at all. Still blocks the pointer, which is the whole
|
|
18
|
+
* reason to reach for it: an invisible sheet that catches a click.
|
|
19
|
+
*/
|
|
20
|
+
export type MPOverlayTone = 'scrim' | 'blur' | 'solid' | 'clear';
|
|
21
|
+
/**
|
|
22
|
+
* An overlay takes `size`, `align` and `tone` and stops there.
|
|
23
|
+
*
|
|
24
|
+
* There is no `variant` — the five weights answer "how much of a surface does
|
|
25
|
+
* this paint", and an overlay has taken the page. There is no `color` either: an
|
|
26
|
+
* accent is what a control uses to say which of several things it is, and there
|
|
27
|
+
* is only ever one overlay.
|
|
28
|
+
*/
|
|
29
|
+
export interface MPOverlayProps {
|
|
30
|
+
/** The overlay is shown. Use with `onOpenChange` for a controlled overlay. */
|
|
31
|
+
open?: boolean;
|
|
32
|
+
/** Whether the overlay starts shown, for an uncontrolled one. */
|
|
33
|
+
defaultOpen?: boolean;
|
|
34
|
+
onOpenChange?: (open: boolean) => void;
|
|
35
|
+
/**
|
|
36
|
+
* How much of the page is taken away.
|
|
37
|
+
* @default 'scrim'
|
|
38
|
+
*/
|
|
39
|
+
tone?: MPOverlayTone;
|
|
40
|
+
/**
|
|
41
|
+
* Whether clicking the overlay or pressing Escape closes it.
|
|
42
|
+
*
|
|
43
|
+
* Off by default, which is the other way round from `MPDialog`. A dialog asks a
|
|
44
|
+
* question and Escape is the universal "no"; an overlay is not asking anything
|
|
45
|
+
* — it is saying *wait* — and a save that can be dismissed by a stray click is
|
|
46
|
+
* a save the reader will believe finished. Turn it on for the overlay whose job
|
|
47
|
+
* is to catch a click outside something.
|
|
48
|
+
* @default false
|
|
49
|
+
*/
|
|
50
|
+
dismissible?: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Whether the page behind is taken away for the keyboard too. `'trap-focus'`
|
|
53
|
+
* leaves the page scrollable and clickable while still holding focus inside,
|
|
54
|
+
* which is usually what a `clear` overlay wants.
|
|
55
|
+
* @default true
|
|
56
|
+
*/
|
|
57
|
+
modal?: boolean | 'trap-focus';
|
|
58
|
+
/**
|
|
59
|
+
* Where the content sits down the viewport.
|
|
60
|
+
* @default 'center'
|
|
61
|
+
*/
|
|
62
|
+
align?: MPAlign;
|
|
63
|
+
/**
|
|
64
|
+
* The room between the content and the edge of the viewport. The one thing
|
|
65
|
+
* `size` decides here — an overlay has no surface of its own to scale.
|
|
66
|
+
* @default 'md'
|
|
67
|
+
*/
|
|
68
|
+
size?: MPSize;
|
|
69
|
+
/**
|
|
70
|
+
* The accessible name of the overlay.
|
|
71
|
+
*
|
|
72
|
+
* It has a default rather than being optional, which almost nothing else in
|
|
73
|
+
* this library does: an overlay that holds nothing readable — a bare spinner, a
|
|
74
|
+
* `clear` sheet — still has to say what it is, and the alternative is a modal
|
|
75
|
+
* region a screen reader announces as nothing at all.
|
|
76
|
+
* @default 'Overlay'
|
|
77
|
+
*/
|
|
78
|
+
label?: string;
|
|
79
|
+
/** What sits on top — a spinner, a line of text, a small card. */
|
|
80
|
+
children?: React.ReactNode;
|
|
81
|
+
className?: string;
|
|
82
|
+
style?: React.CSSProperties;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* A sheet over the whole page that stops it being used.
|
|
86
|
+
*
|
|
87
|
+
* What separates this from `MPDialog` is what is *not* here: no surface, no
|
|
88
|
+
* outline, no title, no actions. An overlay is the scrim on its own, with
|
|
89
|
+
* whatever the caller puts on top of it — most often an `MPProgressCircular` and
|
|
90
|
+
* a line saying what is being waited for.
|
|
91
|
+
*
|
|
92
|
+
* `dismissible` is the one prop worth reading twice, and it is off. Everything
|
|
93
|
+
* else Base UI owns: the portal, the scroll lock, the focus held inside, the page
|
|
94
|
+
* behind going inert, and focus returning to wherever it came from on close.
|
|
95
|
+
*/
|
|
96
|
+
export declare function MPOverlay({ open, defaultOpen, onOpenChange, tone, dismissible, modal, align, size, label, className, style, children }: MPOverlayProps): React.JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as a}from"react/jsx-runtime";import{Dialog as r}from"@base-ui/react/dialog";import{FADE as l,PORTAL_LAYER as s,SCRIM as t}from"../../internal/surface";import{SHEET_PAD as i}from"../../internal/scale";const n={scrim:t,blur:"bg-mp-scrim/20 [backdrop-filter:blur(14px)_saturate(1.4)]",solid:"bg-mp-surface",clear:""},o={start:"items-start",center:"items-center",end:"items-end"};export function MPOverlay({open:t,defaultOpen:c,onOpenChange:m,tone:p="scrim",dismissible:d=!1,modal:f=!0,align:u="center",size:x="md",label:b="Overlay",className:h,style:y,children:j}){return e(r.Root,{open:t,defaultOpen:c,modal:f,disablePointerDismissal:!d,onOpenChange:(e,a)=>{d||e||"escape-key"!==a.reason?m?.(e):a.cancel()},children:a(r.Portal,{children:[e(r.Backdrop,{className:`${s} fixed inset-0 ${l} ${n[p]}`}),e(r.Viewport,{className:[s,"fixed inset-0 flex justify-center",o[u],i[x]].join(" "),children:e(r.Popup,{"aria-label":b,"data-mp-size":x,className:["mp-overlay flex max-h-full max-w-full flex-col items-center justify-center","text-mp-on-surface outline-none",l,h??""].filter(Boolean).join(" "),style:y,children:j})})]})})}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{MPOverlay}from"./MPOverlay";
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { MPColor, MPOrientation, MPSize } from '../../types';
|
|
3
|
+
/**
|
|
4
|
+
* A pane's share of the split, as a percentage of the container or as a CSS
|
|
5
|
+
* length.
|
|
6
|
+
*
|
|
7
|
+
* A bare number is a percentage — that is what a split is usually described in,
|
|
8
|
+
* and a percentage keeps its meaning when the window changes size. A string is
|
|
9
|
+
* an absolute length (`'240px'`, `'15rem'`, `'20%'`), which is what a sidebar
|
|
10
|
+
* with a minimum actually needs: "at least 200 pixels" does not survive being
|
|
11
|
+
* written down as a percentage of a width nobody knows yet.
|
|
12
|
+
*/
|
|
13
|
+
export type MPPaneSize = number | string;
|
|
14
|
+
export interface MPPanesProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'color'> {
|
|
15
|
+
/**
|
|
16
|
+
* Which way the panes run. `horizontal` puts them side by side with upright
|
|
17
|
+
* handles between them; `vertical` stacks them.
|
|
18
|
+
* @default 'horizontal'
|
|
19
|
+
*/
|
|
20
|
+
orientation?: MPOrientation;
|
|
21
|
+
/**
|
|
22
|
+
* Whether the handles between the panes can be dragged. Turn it off for a
|
|
23
|
+
* split that is a layout rather than a control.
|
|
24
|
+
* @default true
|
|
25
|
+
*/
|
|
26
|
+
resizable?: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Which accent family the handles light up in.
|
|
29
|
+
* @default 'primary'
|
|
30
|
+
*/
|
|
31
|
+
color?: MPColor;
|
|
32
|
+
/**
|
|
33
|
+
* How thick a handle is, and how far it reaches.
|
|
34
|
+
* @default 'md'
|
|
35
|
+
*/
|
|
36
|
+
size?: MPSize;
|
|
37
|
+
/** Fires with every pane's share, in percent, while a handle is dragged. */
|
|
38
|
+
onResize?: (sizes: number[]) => void;
|
|
39
|
+
/** Fires once, with the same shape, when the handle is let go. */
|
|
40
|
+
onResizeEnd?: (sizes: number[]) => void;
|
|
41
|
+
/** The panes. Anything that is not an `MPPane` is laid out but has no size. */
|
|
42
|
+
children?: React.ReactNode;
|
|
43
|
+
}
|
|
44
|
+
export interface MPPaneProps extends React.ComponentPropsWithoutRef<'div'> {
|
|
45
|
+
/**
|
|
46
|
+
* The share this pane starts with. Panes with no `defaultSize` split whatever
|
|
47
|
+
* is left over equally.
|
|
48
|
+
*/
|
|
49
|
+
defaultSize?: MPPaneSize;
|
|
50
|
+
/**
|
|
51
|
+
* How small it may be dragged.
|
|
52
|
+
* @default 0
|
|
53
|
+
*/
|
|
54
|
+
minSize?: MPPaneSize;
|
|
55
|
+
/** How large it may be dragged. Unbounded when left out. */
|
|
56
|
+
maxSize?: MPPaneSize;
|
|
57
|
+
/** What is inside the pane. */
|
|
58
|
+
children?: React.ReactNode;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* A set of panes with draggable handles between them.
|
|
62
|
+
*
|
|
63
|
+
* The panes are sized in **fractions**, written out as
|
|
64
|
+
* `flex-basis: calc((100% - gutters) * fraction)`. That is the one decision the
|
|
65
|
+
* rest of this file follows from: a split described in percentages survives the
|
|
66
|
+
* window being resized without a single line of JavaScript running, so the
|
|
67
|
+
* component measures itself only twice — once on mount, to turn a `'240px'`
|
|
68
|
+
* default into a fraction, and once at the start of each drag, to know what a
|
|
69
|
+
* pixel of pointer movement is worth.
|
|
70
|
+
*
|
|
71
|
+
* The handles are interleaved here rather than written by the caller, so the
|
|
72
|
+
* children of an `MPPanes` are just panes. That does mean the direct children
|
|
73
|
+
* have to *be* panes: the constraints are read off their props, and an `MPPane`
|
|
74
|
+
* wrapped in something else is a pane with no minimum.
|
|
75
|
+
*
|
|
76
|
+
* ## Why there is no Base UI primitive under this
|
|
77
|
+
*
|
|
78
|
+
* There is nothing to delegate. A splitter's behaviour is a pointer capture and
|
|
79
|
+
* a clamp, and its accessibility is one ARIA role — `separator` with a value,
|
|
80
|
+
* which is the window-splitter pattern — carried by an element the component has
|
|
81
|
+
* to own anyway because it draws it. What Base UI is here for is the things that
|
|
82
|
+
* are genuinely hard and invisible when they work: a focus trap, a positioner, a
|
|
83
|
+
* typeahead. A rail between two boxes is not one of them.
|
|
84
|
+
*
|
|
85
|
+
* ## What it does not draw
|
|
86
|
+
*
|
|
87
|
+
* No surface, on either half. A split is layout, and the moment a pane drew a
|
|
88
|
+
* sheet it would stop being usable as the thing a table, a card or an editor is
|
|
89
|
+
* put *inside*. The family reaches exactly three places — the hairline, the wash
|
|
90
|
+
* under a hovered handle, and the focus ring — because those are the only marks
|
|
91
|
+
* this component makes.
|
|
92
|
+
*/
|
|
93
|
+
export declare const MPPanes: React.ForwardRefExoticComponent<MPPanesProps & React.RefAttributes<HTMLDivElement>>;
|
|
94
|
+
/**
|
|
95
|
+
* One region of a split.
|
|
96
|
+
*
|
|
97
|
+
* `defaultSize`, `minSize` and `maxSize` are read by the `MPPanes` around it
|
|
98
|
+
* rather than used here — a pane cannot know what "half" is, only the split can.
|
|
99
|
+
*/
|
|
100
|
+
export declare const MPPane: React.ForwardRefExoticComponent<MPPaneProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as t}from"react/jsx-runtime";import*as n from"react";import{accentSlots as r}from"../../internal/accent";const o=n.createContext({basis:null}),i={xs:"basis-1",sm:"basis-1.5",md:"basis-2",lg:"basis-2.5",xl:"basis-3"},a={xs:4,sm:6,md:8,lg:10,xl:12};function s(e,t,n){if(null==e)return;if("number"==typeof e)return t*e/100;const r=/^\s*(-?[\d.]+)\s*(px|rem|em|%)\s*$/.exec(e);if(!r)return;const o=Number(r[1]);if(!Number.isNaN(o))switch(r[2]){case"px":return o;case"%":return t*o/100;case"rem":return o*Number.parseFloat(getComputedStyle(document.documentElement).fontSize||"16");case"em":return o*Number.parseFloat(n&&getComputedStyle(n).fontSize||"16");default:return}}export const MPPanes=n.forwardRef(function({orientation:l="horizontal",resizable:c=!0,color:u="primary",size:m="md",onResize:d,onResizeEnd:p,className:f,style:h,children:g,...v},x){const b=n.Children.toArray(g).filter(n.isValidElement),y=b.length,z=n.useRef(null),w=n.useCallback(e=>{z.current=e,"function"==typeof x?x(e):x&&(x.current=e)},[x]),S=n.useRef([]);S.current=b.map(e=>e.props);const[N,M]=n.useState(null),R=N&&N.length===y?N:null,j=n.useRef(null);j.current=R;const C="horizontal"===l,E=a[m]*Math.max(0,y-1);function L(e){const t=z.current,n=j.current;if(!c||!t||!n||void 0===n[e+1])return null;const r=t.getBoundingClientRect(),o=(C?r.width:r.height)-E;if(o<=0)return null;const i=S.current[e],a=S.current[e+1],l=n[e]*o,u=l+n[e+1]*o,m=Math.max(s(i?.minSize,o,t)??0,u-(s(a?.maxSize,o,t)??u)),p=Math.min(s(i?.maxSize,o,t)??u,u-(s(a?.minSize,o,t)??0));return p<m?null:{root:t,current:n,resize(t){const r=Math.min(p,Math.max(m,l+t)),i=[...n];return i[e]=r/o,i[e+1]=(u-r)/o,M(i),d?.(i.map(e=>100*e)),i}}}n.useEffect(()=>{const e=z.current;if(!e)return;const t=()=>{const t=e.getBoundingClientRect(),n=(C?t.width:t.height)-E;n<=0||M(t=>t&&t.length===y?t:function(e,t,n){const r=e.map(e=>s(e.defaultSize,t,n)),o=r.reduce((e,t)=>e+(t??0),0),i=r.filter(e=>void 0===e).length,a=i>0?Math.max(0,t-o)/i:0,l=r.map(e=>Math.max(0,e??a)),c=l.reduce((e,t)=>e+t,0);return c<=0?l.map(()=>1/Math.max(1,l.length)):l.map(e=>e/c)}(S.current,n,e))};t();const n=new ResizeObserver(t);return n.observe(e),()=>n.disconnect()},[y,C,E]);const P=["mp-panes__handle group/handle relative z-1 flex shrink-0 grow-0 items-center justify-center",i[m],"transition-colors duration-(--mp-sys-motion-duration-short4)","outline-mp-secondary focus-visible:outline-2 focus-visible:outline-offset-0","focus-visible:outline-solid outline-none",c?[C?"cursor-col-resize":"cursor-row-resize","hover:bg-(--_mp-accent)/8 data-[dragging]:bg-(--_mp-accent)/10"].join(" "):""].filter(Boolean).join(" ");return e("div",{ref:w,"data-mp-size":m,className:["mp-panes flex h-full w-full",C?"flex-row":"flex-col","min-h-0 min-w-0",f??""].filter(Boolean).join(" "),style:{...r(u),...h},...v,children:b.map((r,i)=>t(n.Fragment,{children:[i>0?e("div",{role:"separator","aria-orientation":C?"vertical":"horizontal","aria-valuenow":R?Math.round(100*R[i-1]):void 0,"aria-valuemin":0,"aria-valuemax":100,"aria-disabled":!c||void 0,tabIndex:c?0:-1,className:P,onPointerDown:e=>{0===e.button&&function(e,t){const n=L(e);if(!n)return;const r=t.currentTarget;r.setPointerCapture(t.pointerId),r.dataset.dragging="true";const o=document.body.style.userSelect;document.body.style.userSelect="none";const i=C?t.clientX:t.clientY,a=C&&"rtl"===getComputedStyle(n.root).direction?-1:1;let s=n.current;const l=e=>{const t=C?e.clientX:e.clientY;s=n.resize((t-i)*a)},c=()=>{r.removeEventListener("pointermove",l),r.removeEventListener("pointerup",c),r.removeEventListener("pointercancel",c),delete r.dataset.dragging,document.body.style.userSelect=o,p?.(s.map(e=>100*e))};r.addEventListener("pointermove",l),r.addEventListener("pointerup",c),r.addEventListener("pointercancel",c)}(i-1,e)},onKeyDown:e=>{const t=C?"ArrowLeft":"ArrowUp",n=C?"ArrowRight":"ArrowDown";e.key!==t&&e.key!==n||(e.preventDefault(),function(e,t){const n=L(e);if(!n)return;const r=n.resize(t);p?.(r.map(e=>100*e))}(i-1,e.key===n?16:-16))},children:e("span",{"aria-hidden":"true",className:["bg-mp-outline-variant pointer-events-none","transition-colors duration-(--mp-sys-motion-duration-short4)",C?"h-full w-px":"h-px w-full",c?["group-hover/handle:bg-(--_mp-accent)","group-focus-visible/handle:bg-(--_mp-accent)","group-data-[dragging]/handle:bg-(--_mp-accent)"].join(" "):""].filter(Boolean).join(" ")})}):null,e(o.Provider,{value:{basis:R?`calc((100% - ${E}px) * ${R[i].toFixed(6)})`:null},children:r})]},r.key??i))})});export const MPPane=n.forwardRef(function({defaultSize:t,minSize:r,maxSize:i,className:a,style:s,children:l,...c},u){const{basis:m}=n.useContext(o);return e("div",{ref:u,className:["mp-pane relative min-h-0 min-w-0 overflow-auto",a??""].filter(Boolean).join(" "),style:{flex:m?`0 0 ${m}`:"1 1 0%",...s},...c,children:l})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{MPPane,MPPanes}from"./MPPanes";
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { MPColor, MPSize, MPVariant } from '../../types';
|
|
3
|
+
/**
|
|
4
|
+
* How the lozenge sits in the page's scroll.
|
|
5
|
+
*
|
|
6
|
+
* Local to this component rather than in `src/types.ts`, which is the rule that
|
|
7
|
+
* file states: an axis joins the shared vocabulary when a **second** component
|
|
8
|
+
* needs it, not in anticipation of one. Nothing else in the library pins itself
|
|
9
|
+
* to the viewport.
|
|
10
|
+
*/
|
|
11
|
+
export type MPPillPosition = 'static' | 'sticky' | 'fixed';
|
|
12
|
+
export interface MPPillProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'color' | 'onClick' | 'title'> {
|
|
13
|
+
/**
|
|
14
|
+
* The leading slot — a glyph, an avatar, a status dot, a photograph.
|
|
15
|
+
*
|
|
16
|
+
* It is given a square box of its own and clipped to a circle, so an `<img>`
|
|
17
|
+
* lands in it as readily as an icon does: the picture fills the box and is
|
|
18
|
+
* cropped rather than letterboxed, which is what a 20px avatar wants.
|
|
19
|
+
*/
|
|
20
|
+
startIcon?: React.ReactNode;
|
|
21
|
+
/** The trailing slot. Outside the pressable area, so it can be a control. */
|
|
22
|
+
endIcon?: React.ReactNode;
|
|
23
|
+
/**
|
|
24
|
+
* The headline in the middle — what the pill is currently about.
|
|
25
|
+
*
|
|
26
|
+
* A prop rather than something to compose, for the reason a card's title is
|
|
27
|
+
* one: the arrangement is fixed. Almost every pill is a line of text with an
|
|
28
|
+
* optional second line under it, and spelling that as children means every
|
|
29
|
+
* caller inventing their own centring and type scale.
|
|
30
|
+
*/
|
|
31
|
+
title?: React.ReactNode;
|
|
32
|
+
/** The second line, under the title. One step down and quieter. */
|
|
33
|
+
description?: React.ReactNode;
|
|
34
|
+
/**
|
|
35
|
+
* The second half, revealed when `expanded`.
|
|
36
|
+
*
|
|
37
|
+
* The pill grows downward into it rather than swapping to a different shape:
|
|
38
|
+
* one object saying more, which is the whole idea behind this component.
|
|
39
|
+
*/
|
|
40
|
+
details?: React.ReactNode;
|
|
41
|
+
/**
|
|
42
|
+
* Whether `details` is showing.
|
|
43
|
+
* @default false
|
|
44
|
+
*/
|
|
45
|
+
expanded?: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* How it sits in the page's scroll. `fixed` pins it against the viewport and
|
|
48
|
+
* centres it, which is the arrangement this shape exists for.
|
|
49
|
+
* @default 'static'
|
|
50
|
+
*/
|
|
51
|
+
position?: MPPillPosition;
|
|
52
|
+
/**
|
|
53
|
+
* Which edge it is held against when `position` is not `static`.
|
|
54
|
+
* @default 'top'
|
|
55
|
+
*/
|
|
56
|
+
side?: 'top' | 'bottom';
|
|
57
|
+
/** Passing it makes the middle a real button. */
|
|
58
|
+
onClick?: React.MouseEventHandler<HTMLButtonElement>;
|
|
59
|
+
/**
|
|
60
|
+
* How much surface the lozenge paints.
|
|
61
|
+
*
|
|
62
|
+
* The **control** ladder rather than the container one: a pill is the thing
|
|
63
|
+
* being coloured, so `filled` takes the accent under its own ink.
|
|
64
|
+
* @default 'filled'
|
|
65
|
+
*/
|
|
66
|
+
variant?: MPVariant;
|
|
67
|
+
/**
|
|
68
|
+
* The row's minimum height and the type scale in it. The same numbers a button
|
|
69
|
+
* is drawn at, so a collapsed pill lines up with one beside it.
|
|
70
|
+
* @default 'md'
|
|
71
|
+
*/
|
|
72
|
+
size?: MPSize;
|
|
73
|
+
/**
|
|
74
|
+
* @default 'secondary'
|
|
75
|
+
*/
|
|
76
|
+
color?: MPColor;
|
|
77
|
+
/**
|
|
78
|
+
* Anything the middle needs that `title` and `description` cannot say — a pair
|
|
79
|
+
* of small readouts, a live counter, a progress indicator. Rendered under
|
|
80
|
+
* them, in the same centred column.
|
|
81
|
+
*/
|
|
82
|
+
children?: React.ReactNode;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* A floating lozenge holding a small amount of live information.
|
|
86
|
+
*
|
|
87
|
+
* MD3 does not describe this shape, and the library ships it for the reason it
|
|
88
|
+
* ships [MPProgressBox](../feedback/progress-box): there is a real thing here
|
|
89
|
+
* that the specification's own parts can draw, and no component in the set draws
|
|
90
|
+
* it. What it is *for* is the state a page has that is not about any one control
|
|
91
|
+
* — a call in progress, an upload that is still going, a recording, a train two
|
|
92
|
+
* minutes away.
|
|
93
|
+
*
|
|
94
|
+
* ## The shape, and the one house rule it bends
|
|
95
|
+
*
|
|
96
|
+
* A collapsed pill is a stadium: `corner-full`, which every other **sheet** in
|
|
97
|
+
* this library is held back from. That is allowed here for the same reason the
|
|
98
|
+
* rule exists — a radius says what kind of object something is, and this is not
|
|
99
|
+
* a sheet lying on the page. It is an object hovering over it, and an object
|
|
100
|
+
* hovering over the page should not look like it was cut from the same material.
|
|
101
|
+
*
|
|
102
|
+
* Opening `details` moves the corner to `corner-extra-large`, and the move is
|
|
103
|
+
* transitioned. That is not decoration: `corner-full` on a box that has grown to
|
|
104
|
+
* six lines is a corner a third of its height, which eats the first two words of
|
|
105
|
+
* every line. The pill morphs from a lozenge into a rounded rectangle with the
|
|
106
|
+
* loudest corner the sheet ladder has, which is the shape it should have been
|
|
107
|
+
* all along at that size.
|
|
108
|
+
*
|
|
109
|
+
* ## What is measured, and why
|
|
110
|
+
*
|
|
111
|
+
* `details` is revealed by animating a **measured** height, exactly as an
|
|
112
|
+
* accordion panel is — but the measurement is a `ResizeObserver` rather than
|
|
113
|
+
* Base UI's one-shot one, because live information is the kind of content that
|
|
114
|
+
* changes while it is on screen. A pill whose details grew after they opened
|
|
115
|
+
* would otherwise be clipped at the height they had when they arrived.
|
|
116
|
+
*/
|
|
117
|
+
export declare const MPPill: React.ForwardRefExoticComponent<MPPillProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as t,Fragment as n}from"react/jsx-runtime";import*as o from"react";import{accentSlots as i}from"../../internal/accent";import{MPStateLayer as r}from"../../internal/StateLayer";import{CONTROL_GAP as s,CONTROL_ICON as l,CONTROL_TEXT as a,hasContent as c,META_TEXT as m,PROSE_TEXT as d,SHEET_PAD_X as p}from"../../internal/scale";const u={xs:"min-h-8",sm:"min-h-10",md:"min-h-14",lg:"min-h-16",xl:"min-h-18"},f={xs:"px-4",sm:"px-5",md:"px-6",lg:"px-8",xl:"px-10"},h={filled:"shadow-mp-2 bg-(--_mp-accent) text-(--_mp-on-accent)",tonal:"shadow-mp-2 bg-(--_mp-accent-container) text-(--_mp-on-accent-container)",elevated:"shadow-mp-2 bg-mp-surface-container-low text-(--_mp-accent)",outlined:"border-mp-outline shadow-mp-1 border bg-mp-surface-container text-mp-on-surface",text:"shadow-mp-1 bg-mp-surface-container text-mp-on-surface"},x={static:{top:"",bottom:""},sticky:{top:"sticky top-3 z-20",bottom:"sticky bottom-3 z-20"},fixed:{top:"fixed inset-x-0 top-3 z-30 mx-auto w-fit",bottom:"fixed inset-x-0 bottom-3 z-30 mx-auto w-fit"}};export const MPPill=o.forwardRef(function({startIcon:b,endIcon:w,title:g,description:v,details:y,expanded:j=!1,position:N="static",side:k="top",onClick:_,variant:z="filled",size:B="md",color:C="secondary",className:R,style:$,children:H,...I},P){const S=o.useRef(null),[E,F]=o.useState(0);o.useEffect(()=>{const e=S.current;if(!e)return;const t=new ResizeObserver(()=>F(e.scrollHeight));return t.observe(e),F(e.scrollHeight),()=>t.disconnect()},[y]);const L=Boolean(_),M=p[B],O=t(n,{children:[c(b)?e("span",{className:"flex shrink-0 items-center justify-center overflow-hidden rounded-mp-full [&_img]:size-full [&_img]:object-cover",style:{width:l[B],height:l[B]},children:b}):null,c(g)||c(v)||c(H)?t("span",{className:["flex min-w-0 flex-1 flex-col items-center justify-center text-center",f[B]].join(" "),children:[c(g)?e("span",{className:"max-w-full truncate",children:g}):null,c(v)?e("span",{className:`max-w-full truncate font-normal ${m} [color:color-mix(in_oklab,currentColor_72%,transparent)]`,children:v}):null,H]}):null]});return t("div",{ref:P,"data-mp-size":B,"data-mp-variant":z,"data-mp-expanded":j||void 0,className:["mp-pill inline-flex max-w-full flex-col overflow-hidden align-middle","box-border whitespace-nowrap select-none",j?"rounded-mp-xl":"rounded-mp-full","transition-[border-radius,background-color,box-shadow]","duration-(--mp-sys-motion-duration-short4) ease-mp-standard","motion-reduce:transition-none",a[B],h[z],x[N][k],R??""].filter(Boolean).join(" "),style:{...i(C),...$},...I,children:[t("div",{className:["flex shrink-0 items-center py-1",u[B],s[B],L?"ps-0":M,c(w)?"pe-1":L?"pe-0":""].filter(Boolean).join(" "),children:[L?t("button",{type:"button",className:["group relative flex min-w-0 flex-1 cursor-pointer items-center justify-center","self-stretch appearance-none border-0 bg-transparent font-[inherit] text-inherit","rounded-[inherit]",s[B],M,"outline-mp-secondary focus-visible:outline-2 focus-visible:-outline-offset-2","focus-visible:outline-solid outline-none"].join(" "),onClick:_,children:[e(r,{}),O]}):O,c(w)?e("span",{className:"flex h-[1lh] shrink-0 items-center",children:w}):null]}),c(y)?e("div",{className:["overflow-hidden","transition-[height] duration-(--mp-sys-motion-duration-short4) ease-mp-standard","motion-reduce:transition-none"].join(" "),style:{height:j?E:0},inert:!j,children:e("div",{ref:S,className:`${M} pb-2 whitespace-normal ${d[B]}`,children:y})}):null]})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{MPPill}from"./MPPill";
|