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,138 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Popover } from '@base-ui/react/popover';
|
|
3
|
+
import type { MPAlign, MPSide, MPSize } from '../../types';
|
|
4
|
+
/**
|
|
5
|
+
* A popover takes `side`, `align` and `size`, and stops there.
|
|
6
|
+
*
|
|
7
|
+
* There is no `variant` — the five weights answer "how much does this surface
|
|
8
|
+
* assert itself against the page", and a popup that had to be asked for has
|
|
9
|
+
* already been asserted. There is no `color` either: MD3's own answer for a
|
|
10
|
+
* surface that floats beside a control is `surface-container` at elevation 2,
|
|
11
|
+
* neutral, and a popover that could be dyed would dye the form somebody put in
|
|
12
|
+
* it.
|
|
13
|
+
*/
|
|
14
|
+
export interface MPPopoverProps {
|
|
15
|
+
/**
|
|
16
|
+
* The element the popup hangs off and that opens it. Exactly one element, and
|
|
17
|
+
* it must accept a ref and spread props — every Material Plus component does.
|
|
18
|
+
*
|
|
19
|
+
* Optional: a controlled popover anchored from elsewhere needs none, though it
|
|
20
|
+
* then has nothing to position against and will sit against the viewport.
|
|
21
|
+
*/
|
|
22
|
+
trigger?: React.ReactElement;
|
|
23
|
+
/** The heading, rendered as the element that names the popup. */
|
|
24
|
+
title?: React.ReactNode;
|
|
25
|
+
/** A line under it, and the popup's accessible description. */
|
|
26
|
+
description?: React.ReactNode;
|
|
27
|
+
/**
|
|
28
|
+
* Which edge of the trigger it appears on. Flips to the opposite side when
|
|
29
|
+
* there is no room, which is Base UI's doing and is the right behaviour.
|
|
30
|
+
* @default 'bottom'
|
|
31
|
+
*/
|
|
32
|
+
side?: MPSide;
|
|
33
|
+
/**
|
|
34
|
+
* Where it sits along that edge.
|
|
35
|
+
* @default 'center'
|
|
36
|
+
*/
|
|
37
|
+
align?: MPAlign;
|
|
38
|
+
/**
|
|
39
|
+
* Distance from the trigger, in pixels.
|
|
40
|
+
* @default 8
|
|
41
|
+
*/
|
|
42
|
+
sideOffset?: number;
|
|
43
|
+
/**
|
|
44
|
+
* Shift along that edge, in pixels.
|
|
45
|
+
* @default 0
|
|
46
|
+
*/
|
|
47
|
+
alignOffset?: number;
|
|
48
|
+
/**
|
|
49
|
+
* Draws the little wedge pointing at the trigger.
|
|
50
|
+
*
|
|
51
|
+
* Off by default. MD3 draws no wedge on a menu and none on a rich tooltip: a
|
|
52
|
+
* popup eight pixels from the control that opened it does not need to say what
|
|
53
|
+
* it belongs to. Turn it on where the trigger is far enough away that it does.
|
|
54
|
+
* @default false
|
|
55
|
+
*/
|
|
56
|
+
arrow?: boolean;
|
|
57
|
+
/** Whether the popover is open. Use with `onOpenChange` for a controlled one. */
|
|
58
|
+
open?: boolean;
|
|
59
|
+
/** Whether it starts open, for an uncontrolled one. */
|
|
60
|
+
defaultOpen?: boolean;
|
|
61
|
+
onOpenChange?: (open: boolean) => void;
|
|
62
|
+
/**
|
|
63
|
+
* Whether the page behind is taken away.
|
|
64
|
+
*
|
|
65
|
+
* `false` — the default — leaves the page scrollable and clickable, which is
|
|
66
|
+
* what separates a popover from a [dialog](./dialog): it is a detail *beside*
|
|
67
|
+
* the page, not instead of it. `'trap-focus'` holds focus inside without
|
|
68
|
+
* locking the scroll.
|
|
69
|
+
* @default false
|
|
70
|
+
*/
|
|
71
|
+
modal?: boolean | 'trap-focus';
|
|
72
|
+
/**
|
|
73
|
+
* Whether pressing Escape or clicking outside closes the popup. Turn it off
|
|
74
|
+
* only for a popup with its own way out, because there will be no other.
|
|
75
|
+
* @default true
|
|
76
|
+
*/
|
|
77
|
+
dismissible?: boolean;
|
|
78
|
+
/**
|
|
79
|
+
* Shows the × in the corner.
|
|
80
|
+
* @default false
|
|
81
|
+
*/
|
|
82
|
+
showClose?: boolean;
|
|
83
|
+
/**
|
|
84
|
+
* Accessible name of the × button.
|
|
85
|
+
* @default 'Close'
|
|
86
|
+
*/
|
|
87
|
+
closeLabel?: string;
|
|
88
|
+
/**
|
|
89
|
+
* A hard cap on the popup's width, overriding the one `size` implies. Numbers
|
|
90
|
+
* are pixels. For the popover whose *content* decides its width — a form, a
|
|
91
|
+
* single line of help — rather than for tuning the scale, which is `size`.
|
|
92
|
+
*/
|
|
93
|
+
width?: number | string;
|
|
94
|
+
/**
|
|
95
|
+
* The room inside the popup, the type scale in it, and how wide it may get.
|
|
96
|
+
* @default 'md'
|
|
97
|
+
*/
|
|
98
|
+
size?: MPSize;
|
|
99
|
+
/** The body. */
|
|
100
|
+
children?: React.ReactNode;
|
|
101
|
+
className?: string;
|
|
102
|
+
style?: React.CSSProperties;
|
|
103
|
+
}
|
|
104
|
+
export type MPPopoverCloseProps = React.ComponentProps<typeof Popover.Close>;
|
|
105
|
+
/**
|
|
106
|
+
* Closes the popover it is inside.
|
|
107
|
+
*
|
|
108
|
+
* Exported for `MPDialogClose`'s reason: an uncontrolled popover has no
|
|
109
|
+
* `setOpen` for its Cancel button to call, and making every popover controlled
|
|
110
|
+
* is a piece of state per popover that exists only to answer a button.
|
|
111
|
+
*
|
|
112
|
+
* `render` is Base UI's own escape hatch, so a real Material Plus button
|
|
113
|
+
* dismisses: `<MPPopoverClose render={<MPButton variant="text">Cancel</MPButton>} />`.
|
|
114
|
+
*/
|
|
115
|
+
export declare const MPPopoverClose: React.ForwardRefExoticComponent<Omit<import("@base-ui/react").PopoverCloseProps, "ref"> & React.RefAttributes<HTMLButtonElement>>;
|
|
116
|
+
/**
|
|
117
|
+
* A sheet that opens beside the thing that opened it.
|
|
118
|
+
*
|
|
119
|
+
* The difference from a [tooltip](./tooltip) is that this one can be *reached*:
|
|
120
|
+
* it stays up until it is dismissed, it can be entered with the pointer or the
|
|
121
|
+
* keyboard, and what is inside it can be clicked and typed into. The difference
|
|
122
|
+
* from a [dialog](./dialog) is that it does not take the page — it is anchored
|
|
123
|
+
* to a control, and the page behind goes on working.
|
|
124
|
+
*
|
|
125
|
+
* Base UI owns everything hard about it: the anchoring and the flip at the
|
|
126
|
+
* window's edge, the click outside and Escape, returning focus to the trigger,
|
|
127
|
+
* and the `aria-labelledby` / `aria-describedby` wiring. What is left here is
|
|
128
|
+
* the surface, the width ladder and the header.
|
|
129
|
+
*
|
|
130
|
+
* ## The surface
|
|
131
|
+
*
|
|
132
|
+
* `surface-container` at elevation 2 and `corner-medium`, which is what MD3
|
|
133
|
+
* gives a menu and a rich tooltip — the two things in the specification that are
|
|
134
|
+
* this: a small sheet anchored to a control. It is deliberately *not* the
|
|
135
|
+
* dialog's `surface-container-high` at elevation 3, because a popover has not
|
|
136
|
+
* taken the page and should not sit above the menus that did not either.
|
|
137
|
+
*/
|
|
138
|
+
export declare function MPPopover({ trigger, title, description, side, align, sideOffset, alignOffset, arrow, open, defaultOpen, onOpenChange, modal, dismissible, showClose, closeLabel, width, size, className, style, children }: MPPopoverProps): React.JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as o}from"react/jsx-runtime";import{Popover as t}from"@base-ui/react/popover";import{MPIcon as i}from"../icon/MPIcon";import{CloseIcon as a}from"../../constants/icons";import{MPStateLayer as s}from"../../internal/StateLayer";import{hasContent as l,META_TEXT as r,PROSE_TEXT as n,SHEET_GAP as c,SHEET_PAD as d,SHEET_TITLE as m}from"../../internal/scale";import{FADE as p,PORTAL_LAYER as f}from"../../internal/surface";const u={xs:"max-w-56",sm:"max-w-64",md:"max-w-80",lg:"max-w-96",xl:"max-w-lg"},x={xs:8,sm:9,md:10,lg:11,xl:12};export const MPPopoverClose=t.Close;export function MPPopover({trigger:h,title:g,description:v,side:b="bottom",align:w="center",sideOffset:N=8,alignOffset:O=0,arrow:P=!1,open:j,defaultOpen:y,onOpenChange:C,modal:z=!1,dismissible:k=!0,showClose:M=!1,closeLabel:L="Close",width:$,size:B="md",className:T,style:A,children:D}){const I=l(g)||l(v),R=x[B];return o(t.Root,{open:j,defaultOpen:y,modal:z,onOpenChange:(e,o)=>{k||e||"escape-key"!==o.reason&&"outside-press"!==o.reason&&"focus-out"!==o.reason?C?.(e):o.cancel()},children:[h?e(t.Trigger,{render:h}):null,e(t.Portal,{children:e(t.Positioner,{className:f,side:b,align:w,sideOffset:N,alignOffset:O,children:o(t.Popup,{"data-mp-size":B,className:["mp-popover rounded-mp-md relative flex flex-col outline-none","bg-mp-surface-container text-mp-on-surface shadow-mp-2","box-border",d[B],c[B],n[B],void 0===$?u[B]:"",p,T??""].filter(Boolean).join(" "),style:{...void 0===$?null:{maxWidth:"number"==typeof $?`${$}px`:$},...A},children:[P?e(t.Arrow,{className:["data-[side=top]:bottom-[-1px]","data-[side=bottom]:top-[-1px] data-[side=bottom]:rotate-180","data-[side=left]:right-[-1px] data-[side=left]:-rotate-90","data-[side=right]:left-[-1px] data-[side=right]:rotate-90"].join(" "),children:e("svg",{width:R,height:R/2,viewBox:"0 0 10 5","aria-hidden":"true",className:"block",children:e("path",{d:"M0 0h10L5 5z",fill:"var(--_mp-color-surface-container)"})})}):null,I||M?o("div",{className:"flex shrink-0 items-start gap-3",children:[o("div",{className:"flex min-w-0 flex-1 flex-col",children:[l(g)?e(t.Title,{className:`m-0 ${m[B]}`,children:g}):null,l(v)?e(t.Description,{className:`text-mp-on-surface-variant m-0 ${r}`,children:v}):null]}),M?o(t.Close,{"aria-label":L,className:["group text-mp-on-surface-variant relative flex size-8 shrink-0","rounded-mp-full -m-1 cursor-pointer items-center justify-center","appearance-none border-0 bg-transparent","outline-mp-secondary focus-visible:outline-2 focus-visible:outline-offset-2","focus-visible:outline-solid outline-none"].join(" "),children:[e(s,{}),e(i,{icon:a,size:18})]}):null]}):null,l(D)?e("div",{className:"min-w-0",children:D}):null]})})})]})}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{MPPopover,MPPopoverClose}from"./MPPopover";
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { type MPProgressProps } from '../../internal/progress';
|
|
3
|
+
import type { MPColor, MPSize } from '../../types';
|
|
4
|
+
export interface MPProgressBoxProps extends MPProgressProps {
|
|
5
|
+
/** Size of one segment. @default 'md' */
|
|
6
|
+
size?: MPSize;
|
|
7
|
+
/** @default 'primary' */
|
|
8
|
+
color?: MPColor;
|
|
9
|
+
/**
|
|
10
|
+
* How many segments the row is made of.
|
|
11
|
+
*
|
|
12
|
+
* Four by default: enough that the wave reads as a wave, few enough that a
|
|
13
|
+
* determinate row can be counted at a glance rather than measured. Set it to
|
|
14
|
+
* the number of steps when the thing being waited on genuinely has steps.
|
|
15
|
+
* @default 4
|
|
16
|
+
*/
|
|
17
|
+
count?: number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* A row of segments that light up.
|
|
21
|
+
*
|
|
22
|
+
* The third shape, and the one that answers a different question from the other
|
|
23
|
+
* two. A bar and a ring both say "this much of it is done" — a quantity a reader
|
|
24
|
+
* reads off a length. A row of four segments says "this is step three", which is
|
|
25
|
+
* a quantity they *count*, and counting is faster than measuring for any number
|
|
26
|
+
* small enough to count.
|
|
27
|
+
*
|
|
28
|
+
* That is what makes it the right indicator for work that genuinely has steps —
|
|
29
|
+
* an upload with a verify and a publish after it, a four-page form — and the
|
|
30
|
+
* wrong one for a percentage. This is not an MD3 component: the specification
|
|
31
|
+
* has a bar and a ring and stops there. It is drawn out of the spec's own parts
|
|
32
|
+
* all the same — `corner-extra-small` tiles, the accent, `on-surface` at 12% —
|
|
33
|
+
* so a row of them sits in a Material page without announcing that it is extra.
|
|
34
|
+
*
|
|
35
|
+
* It answers a value when it has one: the segments fill left to right, the
|
|
36
|
+
* leading one partially, so four segments read as a four-part bar rather than
|
|
37
|
+
* rounding 30% away to a quarter. Without a value they cycle, each held back by
|
|
38
|
+
* its own index.
|
|
39
|
+
*/
|
|
40
|
+
export declare const MPProgressBox: React.ForwardRefExoticComponent<MPProgressBoxProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as a}from"react/jsx-runtime";import*as r from"react";import{Progress as t}from"@base-ui/react/progress";import{accentSlots as s}from"../../internal/accent";import{META_TEXT as n,STACK_GAP as l}from"../../internal/scale";import{SEGMENT_GAP as o,SEGMENT_RADIUS as i,SEGMENT_SIZE as m,progressAriaText as c,progressFraction as u,progressText as f}from"../../internal/progress";export const MPProgressBox=r.forwardRef(function({size:r="md",color:p="primary",count:d=4,value:x=null,min:h=0,max:g=100,label:b,showValue:y=!1,format:v,className:j,style:w},N){const M=u(x,h,g),B=null===M,V=void 0!==v,_=Math.max(1,Math.floor(d));return a(t.Root,{ref:N,value:x??null,min:h,max:g,format:v,getAriaValueText:c(M,V),"data-mp-size":r,className:["mp-progress-box inline-flex flex-col",l[r],j??""].filter(Boolean).join(" "),style:{...s(p),...w},children:[b||y?a("div",{className:["flex items-baseline gap-2",b?"justify-between":"justify-end",n].join(" "),children:[b?e(t.Label,{className:"text-mp-on-surface min-w-0 truncate",children:b}):null,y?e(t.Value,{className:"text-mp-on-surface-variant shrink-0 tabular-nums",children:e=>f(M,e,V)}):null]}):null,e(t.Track,{className:`flex ${o[r]}`,children:Array.from({length:_},(a,t)=>e("span",{className:["bg-mp-on-surface/12 relative overflow-hidden",m[r],i[r],B?"mp-progress-segment-wave bg-(--_mp-accent)":""].filter(Boolean).join(" "),style:B?{"--_mp-index":t}:void 0,children:B?null:e("span",{className:"absolute inset-y-0 start-0 bg-(--_mp-accent) transition-[width] duration-(--mp-sys-motion-duration-short4) ease-mp-standard",style:{width:`${Math.min(100,Math.max(0,100*(M*_-t)))}%`}})},t))})]})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{MPProgressBox}from"./MPProgressBox";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { type MPProgressProps } from '../../internal/progress';
|
|
3
|
+
import type { MPColor, MPSize } from '../../types';
|
|
4
|
+
export interface MPProgressCircularProps extends MPProgressProps {
|
|
5
|
+
/**
|
|
6
|
+
* Diameter of the ring. `md` is MD3's own 48dp, and every rung sits inside the
|
|
7
|
+
* control height of the same name — so a spinner dropped into a button, a field
|
|
8
|
+
* or a table row never makes the row taller than it was.
|
|
9
|
+
* @default 'md'
|
|
10
|
+
*/
|
|
11
|
+
size?: MPSize;
|
|
12
|
+
/** @default 'primary' */
|
|
13
|
+
color?: MPColor;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* The ring that fills, and the one to reach for where there is no room for a bar
|
|
17
|
+
* — inside a button, at the end of a table row, next to a field.
|
|
18
|
+
*
|
|
19
|
+
* The value and the label sit *beside* the ring rather than inside it. A number
|
|
20
|
+
* in the middle of a dial is the picture everyone has of this component, and it
|
|
21
|
+
* only works at two of the five sizes: at `xs` the ring is twenty-four pixels
|
|
22
|
+
* across and there is nowhere for "40%" to go. Beside it, every size reads.
|
|
23
|
+
*
|
|
24
|
+
* ## `pathLength`
|
|
25
|
+
*
|
|
26
|
+
* The circle declares `pathLength={100}`, which re-scales the units
|
|
27
|
+
* `stroke-dasharray` and `stroke-dashoffset` are measured in — so an arc is
|
|
28
|
+
* written as a percentage rather than as a fraction of 2πr. That is what lets one
|
|
29
|
+
* `@keyframes` rule in the stylesheet serve all five diameters: without it, every
|
|
30
|
+
* rung would need arithmetic in a stylesheet that cannot do arithmetic.
|
|
31
|
+
*/
|
|
32
|
+
export declare const MPProgressCircular: React.ForwardRefExoticComponent<MPProgressCircularProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as r,jsxs as e}from"react/jsx-runtime";import*as a from"react";import{Progress as s}from"@base-ui/react/progress";import{accentSlots as t}from"../../internal/accent";import{CONTROL_GAP as o,META_TEXT as n}from"../../internal/scale";import{RING_DIAMETER as i,RING_STROKE as l,progressAriaText as c,progressFraction as m,progressText as u}from"../../internal/progress";export const MPProgressCircular=a.forwardRef(function({size:a="md",color:p="primary",value:f=null,min:h=0,max:d=100,label:x,showValue:k=!1,format:g,className:v,style:y},N){const w=m(f,h,d),b=null===w,j=void 0!==g,$=i[a],L=l[a],V=$/2,z=V-L/2;return e(s.Root,{ref:N,value:f??null,min:h,max:d,format:g,getAriaValueText:c(w,j),"data-mp-size":a,className:["mp-progress-circular inline-flex items-center",o[a],n,v??""].filter(Boolean).join(" "),style:{...t(p),...y},children:[e("svg",{className:b?"mp-progress-circular-turn shrink-0":"shrink-0",width:$,height:$,viewBox:`0 0 ${$} ${$}`,fill:"none","aria-hidden":"true",children:[r("circle",{cx:V,cy:V,r:z,stroke:"var(--_mp-color-on-surface)",strokeOpacity:.12,strokeWidth:L}),r("circle",{cx:V,cy:V,r:z,pathLength:100,stroke:"var(--_mp-accent)",strokeWidth:L,strokeLinecap:"round",className:b?"mp-progress-circular-arc":"transition-[stroke-dashoffset] duration-(--mp-sys-motion-duration-short4) ease-mp-standard",transform:`rotate(-90 ${V} ${V})`,...b?null:{strokeDasharray:100,strokeDashoffset:100*(1-w)}})]}),x?r(s.Label,{className:"text-mp-on-surface min-w-0 truncate",children:x}):null,k?r(s.Value,{className:"text-mp-on-surface-variant shrink-0 tabular-nums",children:r=>u(w,r,j)}):null]})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{MPProgressCircular}from"./MPProgressCircular";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { type MPProgressProps } from '../../internal/progress';
|
|
3
|
+
import type { MPColor, MPSize } from '../../types';
|
|
4
|
+
export interface MPProgressLinearProps extends MPProgressProps {
|
|
5
|
+
/**
|
|
6
|
+
* Thickness of the track. `md` is MD3's own 4dp; nothing else on a bar has a
|
|
7
|
+
* size, so this is the only thing `size` touches here.
|
|
8
|
+
* @default 'md'
|
|
9
|
+
*/
|
|
10
|
+
size?: MPSize;
|
|
11
|
+
/** @default 'primary' */
|
|
12
|
+
color?: MPColor;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The bar that fills, and the workhorse of the three.
|
|
16
|
+
*
|
|
17
|
+
* It is the only one that can show *how much* is left at a glance, because length
|
|
18
|
+
* is the one quantity a reader compares without counting. MD3 draws it as a 4dp
|
|
19
|
+
* groove in `secondary-container` with the active indicator in `primary`; here
|
|
20
|
+
* the two are the chosen family's own container and accent, so `color="error"` is
|
|
21
|
+
* a red bar in a red groove rather than a red bar in a blue one.
|
|
22
|
+
*
|
|
23
|
+
* Both ends are fully rounded, which is MD3's own shape for it: at four pixels
|
|
24
|
+
* tall there is no flat run left to preserve, and a square-ended bar reads as a
|
|
25
|
+
* rendering fault rather than as a decision.
|
|
26
|
+
*
|
|
27
|
+
* Base UI's Progress owns the semantics — `role="progressbar"`, the value and
|
|
28
|
+
* range attributes, `aria-valuetext`, and dropping the value entirely while the
|
|
29
|
+
* bar is indeterminate — and it computes the fill width too, so the determinate
|
|
30
|
+
* case here is a class list and nothing else.
|
|
31
|
+
*/
|
|
32
|
+
export declare const MPProgressLinear: React.ForwardRefExoticComponent<MPProgressLinearProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as a}from"react/jsx-runtime";import*as r from"react";import{Progress as l}from"@base-ui/react/progress";import{accentSlots as s}from"../../internal/accent";import{META_TEXT as n,STACK_GAP as t}from"../../internal/scale";import{BAR_THICKNESS as i,progressAriaText as o,progressFraction as m,progressText as c}from"../../internal/progress";export const MPProgressLinear=r.forwardRef(function({size:u="md",color:p="primary",value:f=null,min:d=0,max:x=100,label:g,showValue:h=!1,format:b,className:N,style:j},w){const v=m(f,d,x),y=null===v,V=void 0!==b,$="absolute inset-y-0 rounded-mp-full bg-(--_mp-accent)";return a(l.Root,{ref:w,value:f??null,min:d,max:x,format:b,getAriaValueText:o(v,V),"data-mp-size":u,className:["mp-progress-linear flex w-full flex-col",t[u],N??""].filter(Boolean).join(" "),style:{...s(p),...j},children:[g||h?a("div",{className:["flex items-baseline gap-2",g?"justify-between":"justify-end",n].join(" "),children:[g?e(l.Label,{className:"text-mp-on-surface min-w-0 truncate",children:g}):null,h?e(l.Value,{className:"text-mp-on-surface-variant shrink-0 tabular-nums",children:e=>c(v,e,V)}):null]}):null,e(l.Track,{className:["rounded-mp-full bg-mp-on-surface/12 relative w-full overflow-hidden",i[u]].join(" "),children:y?a(r.Fragment,{children:[e("span",{className:`${$} mp-progress-linear-lead`}),e("span",{className:`${$} mp-progress-linear-trail`})]}):e(l.Indicator,{className:`${$} start-0 transition-[width] duration-(--mp-sys-motion-duration-short4) ease-mp-standard`})})]})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{MPProgressLinear}from"./MPProgressLinear";
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { MPColor, MPOrientation, MPSize } from '../../types';
|
|
3
|
+
export interface MPRadioProps {
|
|
4
|
+
/** What this option is worth. Reported by the group's `onValueChange`. */
|
|
5
|
+
value: string;
|
|
6
|
+
/** The text beside the dot, wired to it by Base UI's Field. */
|
|
7
|
+
label?: React.ReactNode;
|
|
8
|
+
/** The line under the label. */
|
|
9
|
+
description?: React.ReactNode;
|
|
10
|
+
/** Unavailable, but still listed — the option exists, it just cannot be taken. */
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
/** The id put on the control and pointed at by the label. */
|
|
13
|
+
id?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* One option in an `MPRadioGroup`.
|
|
17
|
+
*
|
|
18
|
+
* It has no `size` and no `color` of its own. Both come from the group, which is
|
|
19
|
+
* the only place they can be set once and mean the same thing for every option.
|
|
20
|
+
*/
|
|
21
|
+
export declare const MPRadio: React.ForwardRefExoticComponent<MPRadioProps & React.RefAttributes<HTMLElement>>;
|
|
22
|
+
export interface MPRadioGroupProps {
|
|
23
|
+
/** The chosen value. Use with `onValueChange` for a controlled group. */
|
|
24
|
+
value?: string | null;
|
|
25
|
+
/** The value chosen at the start, for an uncontrolled group. */
|
|
26
|
+
defaultValue?: string | null;
|
|
27
|
+
/** Called with the newly chosen value — a string, not an event. */
|
|
28
|
+
onValueChange?: (value: string) => void;
|
|
29
|
+
/**
|
|
30
|
+
* The question the options answer. Rendered as the set's own label, which is
|
|
31
|
+
* what a screen reader reads before the first option.
|
|
32
|
+
*/
|
|
33
|
+
label?: React.ReactNode;
|
|
34
|
+
/** The line under the label. Replaced by `errorMessage` when there is one. */
|
|
35
|
+
description?: React.ReactNode;
|
|
36
|
+
/**
|
|
37
|
+
* The message under the options. Its presence is also what turns the group
|
|
38
|
+
* over into its error state.
|
|
39
|
+
*/
|
|
40
|
+
errorMessage?: React.ReactNode;
|
|
41
|
+
/**
|
|
42
|
+
* Which way the options stack. A column is scannable at any length; a row
|
|
43
|
+
* silently stops being readable the moment one label is longer than expected.
|
|
44
|
+
* @default 'vertical'
|
|
45
|
+
*/
|
|
46
|
+
orientation?: MPOrientation;
|
|
47
|
+
/**
|
|
48
|
+
* The dots' size and the labels' type scale, for every option at once.
|
|
49
|
+
* @default 'md'
|
|
50
|
+
*/
|
|
51
|
+
size?: MPSize;
|
|
52
|
+
/**
|
|
53
|
+
* Which accent family the chosen option is drawn in.
|
|
54
|
+
* @default 'primary'
|
|
55
|
+
*/
|
|
56
|
+
color?: MPColor;
|
|
57
|
+
/** Marks the group required. */
|
|
58
|
+
required?: boolean;
|
|
59
|
+
/** Greys every option out and stops the set taking input. */
|
|
60
|
+
disabled?: boolean;
|
|
61
|
+
/** Shows the choice without allowing it to be changed. */
|
|
62
|
+
readOnly?: boolean;
|
|
63
|
+
/** Name of the form control, as on a set of native radios. */
|
|
64
|
+
name?: string;
|
|
65
|
+
/** The `MPRadio`s. */
|
|
66
|
+
children?: React.ReactNode;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* A Material Design radio group: a set of options where exactly one is chosen.
|
|
70
|
+
*
|
|
71
|
+
* Base UI owns the part that makes it a group rather than a `<div>` full of
|
|
72
|
+
* inputs — the set takes **one** tab stop and the arrow keys move within it,
|
|
73
|
+
* which is what the ARIA pattern requires and what hand-rolled radio groups
|
|
74
|
+
* almost always get wrong.
|
|
75
|
+
*
|
|
76
|
+
* The options are children rather than an `items` array, unlike `MPSelect`. The
|
|
77
|
+
* difference is that a radio option is a *block* — it carries a label and a
|
|
78
|
+
* description and is laid out down the page — so what a caller wants to vary is
|
|
79
|
+
* its content, not just its text. A select's options are rows in a popup.
|
|
80
|
+
*/
|
|
81
|
+
export declare const MPRadioGroup: React.ForwardRefExoticComponent<MPRadioGroupProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as r}from"react/jsx-runtime";import*as a from"react";import{Radio as i}from"@base-ui/react/radio";import{RadioGroup as l}from"@base-ui/react/radio-group";import{Field as n}from"@base-ui/react/field";import{accentSlots as o}from"../../internal/accent";import{MPStateLayer as t}from"../../internal/StateLayer";import{MPSupportingText as s}from"../../internal/SupportingText";import{META_TEXT as d,PROSE_TEXT as c,hasContent as p}from"../../internal/scale";const u={xs:{ring:"size-4",fill:"size-2",halo:"size-8"},sm:{ring:"size-[18px]",fill:"size-[9px]",halo:"size-9"},md:{ring:"size-5",fill:"size-2.5",halo:"size-10"},lg:{ring:"size-[22px]",fill:"size-[11px]",halo:"size-11"},xl:{ring:"size-6",fill:"size-3",halo:"size-12"}},m=a.createContext({size:"md",readOnly:!1,invalid:!1});export const MPRadio=a.forwardRef(function({value:l,label:o,description:s,disabled:f=!1,id:x},h){const g=a.useContext(m),b=u[g.size],z=a.useId(),v=x??`mp-radio-${z}`;return e(n.Root,{className:"mp-radio inline-block align-top",disabled:f,"data-mp-value":l,children:r("div",{className:["flex items-start gap-3",c[g.size]].join(" "),children:[e("span",{className:"flex h-[1lh] shrink-0 items-center",children:r(i.Root,{ref:h,id:v,value:l,disabled:f,className:["mp-radio__dot group relative inline-flex shrink-0 items-center justify-center","box-border rounded-full border-2 p-0","appearance-none bg-transparent font-[inherit] outline-none","transition-[border-color] duration-(--mp-sys-motion-duration-short4)",b.ring,f?"border-mp-on-surface/38 cursor-default":[g.readOnly?"cursor-default":"cursor-pointer",g.invalid?"border-mp-error":"border-mp-on-surface-variant","data-checked:border-(--_mp-accent)"].join(" ")].join(" "),children:[f?null:e(t,{layer:["top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 rounded-full",b.halo,"bg-mp-on-surface","group-data-checked:bg-(--_mp-accent)"].join(" ")}),e(i.Indicator,{className:["rounded-full",b.fill,f?"bg-mp-on-surface/38":"bg-(--_mp-accent)"].join(" ")})]})}),p(o)||p(s)?r("span",{className:"flex min-w-0 flex-col gap-0.5",children:[p(o)?e(n.Label,{htmlFor:v,className:["leading-[1.4]",f?"text-mp-on-surface/38 cursor-default":g.readOnly?"text-mp-on-surface":"text-mp-on-surface cursor-pointer"].join(" "),children:o}):null,p(s)?e(n.Description,{className:`${d} text-mp-on-surface-variant data-disabled:text-mp-on-surface/38`,children:s}):null]}):null]})})});export const MPRadioGroup=a.forwardRef(function({value:i,defaultValue:t,onValueChange:c,label:u,description:f,errorMessage:x,orientation:h="vertical",size:g="md",color:b="primary",required:z=!1,disabled:v=!1,readOnly:y=!1,name:j,children:N},R){const O=p(x),k=O?"error":b,w=a.useId(),M=a.useMemo(()=>({size:g,readOnly:y,invalid:O}),[g,y,O]);return e(m.Provider,{value:M,children:r(n.Root,{className:"mp-radio-group flex flex-col gap-2",disabled:v,invalid:O,"data-mp-size":g,"data-mp-orientation":h,style:o(k),children:[p(u)?r("span",{id:w,className:[d,v?"text-mp-on-surface/38":"text-mp-on-surface-variant"].join(" "),children:[u,z?e("span",{"aria-hidden":"true",children:" *"}):null]}):null,e(l,{ref:R,"aria-labelledby":p(u)?w:void 0,value:i,defaultValue:t,onValueChange:e=>c?.(String(e??"")),disabled:v,readOnly:y,required:z,name:j,className:["flex","horizontal"===h?"flex-row flex-wrap gap-x-6 gap-y-2":"flex-col gap-2"].join(" "),children:N}),e(s,{description:f,errorMessage:x})]})})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{MPRadio,MPRadioGroup}from"./MPRadioGroup";
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { MPStyleProps } from '../../types';
|
|
3
|
+
export interface MPSegment {
|
|
4
|
+
/** Identifies the segment. What `onValueChange` reports. */
|
|
5
|
+
value: string;
|
|
6
|
+
/** The words in the segment. */
|
|
7
|
+
label?: React.ReactNode;
|
|
8
|
+
/**
|
|
9
|
+
* A glyph before the label. Replaced by the tick while the segment is chosen,
|
|
10
|
+
* which is what MD3 does — the tick and the icon share one slot rather than
|
|
11
|
+
* both being shown, so the segment does not change width on selection.
|
|
12
|
+
*/
|
|
13
|
+
icon?: React.ReactNode;
|
|
14
|
+
/** Unavailable, but still part of the set. */
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
}
|
|
17
|
+
export interface MPSegmentedButtonProps extends MPStyleProps {
|
|
18
|
+
/** The segments, in the order they are drawn. */
|
|
19
|
+
items: readonly MPSegment[];
|
|
20
|
+
/**
|
|
21
|
+
* Which segments are chosen. Use with `onValueChange` for a controlled set.
|
|
22
|
+
*
|
|
23
|
+
* An array in both modes, including single-select where it holds at most one
|
|
24
|
+
* entry. A segmented button is genuinely the same control either way — MD3
|
|
25
|
+
* documents one component with a multi-select option, not two — and a `value`
|
|
26
|
+
* whose *type* changed with a boolean prop would be a union every caller has
|
|
27
|
+
* to narrow before they can read it.
|
|
28
|
+
*/
|
|
29
|
+
value?: readonly string[];
|
|
30
|
+
/** Which segments start chosen, for an uncontrolled set. */
|
|
31
|
+
defaultValue?: readonly string[];
|
|
32
|
+
/** Called with every chosen value, in the order the segments are drawn. */
|
|
33
|
+
onValueChange?: (value: string[]) => void;
|
|
34
|
+
/**
|
|
35
|
+
* Whether more than one segment may be chosen at a time.
|
|
36
|
+
* @default false
|
|
37
|
+
*/
|
|
38
|
+
multiple?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Whether a chosen segment shows a tick.
|
|
41
|
+
*
|
|
42
|
+
* On by default, and the slot is reserved whether or not anything is chosen —
|
|
43
|
+
* a tick that appears from nothing would push the label sideways at the exact
|
|
44
|
+
* moment the reader is looking at it. Turn it off for a set of icon-only
|
|
45
|
+
* segments, where the fill already says which one is on.
|
|
46
|
+
* @default true
|
|
47
|
+
*/
|
|
48
|
+
showCheck?: boolean;
|
|
49
|
+
/** Greys every segment out and stops the set taking input. */
|
|
50
|
+
disabled?: boolean;
|
|
51
|
+
/** The accessible name of the set. */
|
|
52
|
+
'aria-label'?: string;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* A Material Design segmented button: two to five choices in one pill.
|
|
56
|
+
*
|
|
57
|
+
* The container is a hairline `outline` with the segments divided by more of the
|
|
58
|
+
* same, and the chosen one fills with `secondary-container` — deliberately not
|
|
59
|
+
* `primary`, which is what MD3 reserves for the action a screen is about. A
|
|
60
|
+
* segmented button changes what you are *looking at*; it does not do anything.
|
|
61
|
+
*
|
|
62
|
+
* Underneath it is Base UI's toggle group, which gives the set one tab stop with
|
|
63
|
+
* the arrow keys moving inside it, and `aria-pressed` on each segment. Built out
|
|
64
|
+
* of plain buttons instead, a four-way switch would announce itself as four
|
|
65
|
+
* unrelated actions.
|
|
66
|
+
*
|
|
67
|
+
* ## When this is the wrong component
|
|
68
|
+
*
|
|
69
|
+
* At more than five segments, use `MPSelect` — the labels stop fitting and the
|
|
70
|
+
* set starts wrapping, and a segmented button that has wrapped to two lines has
|
|
71
|
+
* lost the one thing it was for. For choosing something *in a form*, use
|
|
72
|
+
* `MPRadioGroup`: that is the control a form's value comes from, and it scales
|
|
73
|
+
* down the page rather than across it.
|
|
74
|
+
*/
|
|
75
|
+
export declare const MPSegmentedButton: React.ForwardRefExoticComponent<MPSegmentedButtonProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as r}from"react/jsx-runtime";import*as n from"react";import{Toggle as t}from"@base-ui/react/toggle";import{ToggleGroup as o}from"@base-ui/react/toggle-group";import{MPIcon as a}from"../icon/MPIcon";import{CheckIcon as l}from"../../constants/icons";import{MPStateLayer as i}from"../../internal/StateLayer";import{CONTROL_GAP as s,CONTROL_HEIGHT as d,CONTROL_ICON as c,CONTROL_PAD_X as m,CONTROL_TEXT as u}from"../../internal/scale";export const MPSegmentedButton=n.forwardRef(function({items:n,value:p,defaultValue:f,onValueChange:b,multiple:h=!1,showCheck:g=!0,size:x="md",fullWidth:j=!1,disabled:v=!1,"aria-label":w},y){return e(o,{ref:y,"aria-label":w,value:p,defaultValue:f,onValueChange:e=>b?.(e),multiple:h,disabled:v,"data-mp-size":x,className:["mp-segmented-button rounded-mp-full box-border items-center align-middle","overflow-hidden border",v?"border-mp-on-surface/12":"border-mp-outline",j?"flex w-full":"inline-flex w-fit",d[x]].join(" "),children:n.map((n,o)=>{const d=v||n.disabled;return r(t,{value:n.value,disabled:n.disabled,className:["mp-segmented-button__segment group relative flex h-full items-center","box-border justify-center bg-transparent font-[inherit] whitespace-nowrap","select-none","appearance-none overflow-hidden outline-none","transition-[background-color,color] duration-(--mp-sys-motion-duration-short4)",u[x],s[x],m[x],0===o?"":"border-s",d?"border-mp-on-surface/12 text-mp-on-surface/38 cursor-default":["border-mp-outline cursor-pointer","text-mp-on-surface","data-pressed:bg-mp-secondary-container","data-pressed:text-mp-on-secondary-container"].join(" "),j?"flex-1":""].filter(Boolean).join(" "),children:[d?null:e(i,{}),g||n.icon?r("span",{className:"relative flex shrink-0 items-center justify-center",style:{width:c[x],height:c[x]},children:[g?e("span",{className:"hidden items-center group-data-pressed:flex",children:e(a,{icon:l,size:c[x]})}):null,n.icon?e("span",{className:["flex items-center",g?"group-data-pressed:hidden":""].filter(Boolean).join(" "),children:n.icon}):null]}):null,e("span",{className:"truncate",children:n.label})]},n.value)})})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{MPSegmentedButton}from"./MPSegmentedButton";
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { MPStyleProps } from '../../types';
|
|
3
|
+
/**
|
|
4
|
+
* What a select's value may be.
|
|
5
|
+
*
|
|
6
|
+
* Deliberately not generic over arbitrary objects. A select is a form control,
|
|
7
|
+
* its value is what a form submits, and every escape from that — object values,
|
|
8
|
+
* a custom equality, a stringifier for the trigger — buys flexibility by making
|
|
9
|
+
* the common case harder to write. Keep the identifier here and look the object
|
|
10
|
+
* up on the other side.
|
|
11
|
+
*/
|
|
12
|
+
export type MPSelectValue = string | number;
|
|
13
|
+
export interface MPSelectOption {
|
|
14
|
+
/** Submitted, and what `value` and `onValueChange` speak in. */
|
|
15
|
+
value: MPSelectValue;
|
|
16
|
+
/** Shown in the list and in the trigger. Defaults to the value itself. */
|
|
17
|
+
label?: React.ReactNode;
|
|
18
|
+
/** Unavailable, but still listed — the option exists, it just cannot be taken. */
|
|
19
|
+
disabled?: boolean;
|
|
20
|
+
}
|
|
21
|
+
export interface MPSelectProps extends MPStyleProps {
|
|
22
|
+
/**
|
|
23
|
+
* The options, as data. There is no `<MPSelect.Option>` to compose: what a
|
|
24
|
+
* caller has is almost always an array already, and the list has to be
|
|
25
|
+
* available to the trigger before the popup has ever been opened — otherwise
|
|
26
|
+
* a closed select can only show its raw value.
|
|
27
|
+
*/
|
|
28
|
+
items: readonly MPSelectOption[];
|
|
29
|
+
/** The chosen value. Use with `onValueChange` for a controlled select. */
|
|
30
|
+
value?: MPSelectValue | null;
|
|
31
|
+
/** The value chosen at the start, for an uncontrolled select. */
|
|
32
|
+
defaultValue?: MPSelectValue | null;
|
|
33
|
+
/** Called with the newly chosen value — a value, not an event. */
|
|
34
|
+
onValueChange?: (value: MPSelectValue | null) => void;
|
|
35
|
+
/** Shown in the trigger while nothing is chosen. */
|
|
36
|
+
placeholder?: React.ReactNode;
|
|
37
|
+
/**
|
|
38
|
+
* Label in the outline's notch. Always drawn there rather than floating over
|
|
39
|
+
* the placeholder, so a select with a label and one without sit at the same
|
|
40
|
+
* height in a form.
|
|
41
|
+
*/
|
|
42
|
+
label?: React.ReactNode;
|
|
43
|
+
/** The line under the control. Replaced by `errorMessage` when there is one. */
|
|
44
|
+
description?: React.ReactNode;
|
|
45
|
+
/**
|
|
46
|
+
* The message under the control. Its presence is also what puts the select
|
|
47
|
+
* into its error state.
|
|
48
|
+
*/
|
|
49
|
+
errorMessage?: React.ReactNode;
|
|
50
|
+
/** Content placed before the value — an `MPIcon`, usually. */
|
|
51
|
+
startIcon?: React.ReactNode;
|
|
52
|
+
/** Marks the select required, both to assistive technology and to the label. */
|
|
53
|
+
required?: boolean;
|
|
54
|
+
/** Greys the select out and stops it opening. */
|
|
55
|
+
disabled?: boolean;
|
|
56
|
+
/** Shows the value without allowing it to be changed, and stays focusable. */
|
|
57
|
+
readOnly?: boolean;
|
|
58
|
+
/** Name of the form control. */
|
|
59
|
+
name?: string;
|
|
60
|
+
/**
|
|
61
|
+
* The id put on the trigger and pointed at by the label. Derived from `name`
|
|
62
|
+
* when omitted, and generated when there is no name either.
|
|
63
|
+
*/
|
|
64
|
+
id?: string;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* A Material Design select.
|
|
68
|
+
*
|
|
69
|
+
* The trigger is `MPTextField`'s shell wearing a chevron, and that is the point:
|
|
70
|
+
* a form where the dropdown is a different height, radius or outline weight from
|
|
71
|
+
* the fields around it is a form that looks assembled rather than designed. The
|
|
72
|
+
* notched outline, the label in the notch and the supporting text underneath are
|
|
73
|
+
* the same components the field uses.
|
|
74
|
+
*
|
|
75
|
+
* The popup is `surface-container` at elevation 2 — the one surface in this
|
|
76
|
+
* library that genuinely floats, and the only one that carries a shadow by
|
|
77
|
+
* default. A chosen row is marked with a tick rather than only with a highlight,
|
|
78
|
+
* because a highlight is also what the keyboard's cursor looks like, and a list
|
|
79
|
+
* where "selected" and "where the arrow keys are" are the same colour is a list
|
|
80
|
+
* you cannot read.
|
|
81
|
+
*
|
|
82
|
+
* Base UI owns everything hard here: positioning and flipping the popup, the
|
|
83
|
+
* focus trap, typeahead, and the hidden input that makes the whole thing submit
|
|
84
|
+
* with a form.
|
|
85
|
+
*/
|
|
86
|
+
export declare const MPSelect: React.ForwardRefExoticComponent<MPSelectProps & React.RefAttributes<HTMLButtonElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as a}from"react/jsx-runtime";import*as t from"react";import{Select as n}from"@base-ui/react/select";import{Field as r}from"@base-ui/react/field";import{MPIcon as i}from"../icon/MPIcon";import{CheckIcon as l,ChevronDownIcon as o}from"../../constants/icons";import{MPFieldLabel as s,MPFieldOutline as c}from"../../internal/FieldOutline";import{MPSupportingText as d}from"../../internal/SupportingText";import{CONTROL_ICON as m,PROSE_TEXT as p,hasContent as u}from"../../internal/scale";const h={xs:{padding:"px-2",height:"h-8"},sm:{padding:"px-3",height:"h-10"},md:{padding:"px-4",height:"h-14"},lg:{padding:"px-4",height:"h-16"},xl:{padding:"px-5",height:"h-18"}};export const MPSelect=t.forwardRef(function({items:f,value:g,defaultValue:x,onValueChange:v,placeholder:b,label:N,description:j,errorMessage:w,startIcon:I,size:y="md",fullWidth:z=!1,required:M=!1,disabled:P=!1,readOnly:S=!1,name:V,id:q},O){const T=u(w),_=h[y],k=t.useId(),R=q??`mp-select-${V??k}`,C=t.useMemo(()=>f.map(e=>({label:e.label??String(e.value),value:e.value})),[f]);return a(r.Root,{className:["mp-select group flex-col align-top",z?"flex w-full":"inline-flex w-fit"].join(" "),disabled:P,invalid:T,"data-mp-size":y,children:[a(n.Root,{id:R,name:V,items:C,value:g,defaultValue:x,onValueChange:e=>v?.(e??null),disabled:P,readOnly:S,required:M,children:[a("div",{className:"relative w-full",children:[a(n.Trigger,{ref:O,className:["relative flex w-full items-center gap-2 select-none","appearance-none bg-transparent font-[inherit] outline-none",_.padding,_.height,p[y],P?"text-mp-on-surface/38 cursor-default":"text-mp-on-surface "+(S?"cursor-default":"cursor-pointer")].join(" "),children:[I?e("span",{className:["flex shrink-0 items-center",P?"text-mp-on-surface/38":"text-mp-on-surface-variant"].join(" "),children:I}):null,e(n.Value,{className:["min-w-0 flex-1 truncate text-start","data-placeholder:text-mp-on-surface-variant",P?"data-placeholder:text-mp-on-surface/38":""].filter(Boolean).join(" "),placeholder:b}),e(n.Icon,{className:["flex shrink-0 items-center","transition-transform duration-(--mp-sys-motion-duration-short4)","data-popup-open:rotate-180",P?"text-mp-on-surface/38":"text-mp-on-surface-variant"].join(" "),children:e(i,{icon:o,size:m[y]})})]}),e(c,{label:N,required:M}),u(N)?e(s,{size:y,label:N,required:M,htmlFor:R}):null]}),e(n.Portal,{children:e(n.Positioner,{className:"z-50 outline-none",sideOffset:4,alignItemWithTrigger:!1,children:e(n.Popup,{className:["mp-select__popup rounded-mp-xs shadow-mp-2 bg-mp-surface-container p-2","text-mp-on-surface min-w-[var(--anchor-width)] outline-none",p[y]].join(" "),children:e(n.List,{className:"max-h-[min(20rem,var(--available-height))] overflow-y-auto overscroll-contain",children:f.map(t=>a(n.Item,{value:t.value,disabled:t.disabled,className:["mp-select__item group rounded-mp-xs relative flex cursor-pointer items-center","gap-3 py-2 pe-3 ps-2 select-none outline-none","data-highlighted:bg-mp-on-surface/8","data-selected:text-mp-on-secondary-container","data-selected:bg-mp-secondary-container","data-disabled:text-mp-on-surface/38 data-disabled:cursor-default"].join(" "),children:[e("span",{className:"flex size-5 shrink-0 items-center justify-center",children:e(n.ItemIndicator,{children:e(i,{icon:l,size:18})})}),e(n.ItemText,{className:"min-w-0 flex-1 truncate",children:t.label??String(t.value)})]},String(t.value)))})})})})]}),e(d,{description:j,errorMessage:w,className:_.padding})]})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{MPSelect}from"./MPSelect";
|