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
package/README.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
<!-- An absolute URL, not `docs/public/logo-large.png`: this file is the package
|
|
2
|
+
page on npm as well as the front page on GitHub, `.npmignore` keeps `docs/`
|
|
3
|
+
out of the tarball, and npm resolves a relative image against the published
|
|
4
|
+
package before it falls back to anything else. -->
|
|
5
|
+
<img src="https://raw.githubusercontent.com/jooy2/material-plus/main/docs/public/logo-large.png" alt="Material Plus" width="96" height="96">
|
|
6
|
+
|
|
1
7
|
# Material Plus
|
|
2
8
|
|
|
3
9
|
[](https://github.com/jooy2/material-plus/blob/main/LICENSE)  [](https://www.npmjs.com/package/material-plus-ui) [](https://www.npmjs.com/package/material-plus-ui) 
|
|
@@ -8,11 +14,12 @@ Live previews and full props for every component. This README is just the quick
|
|
|
8
14
|
|
|
9
15
|
---
|
|
10
16
|
|
|
11
|
-
**Material Plus is a React component library
|
|
17
|
+
**Material Plus is a React component library implementing Material Design 3.** It is the pile of components you end up writing in every Material project — the field that handles IME composition properly, the icon wrapper that agrees with your set — extracted, documented and tested.
|
|
12
18
|
|
|
13
|
-
It
|
|
19
|
+
It follows the specification directly rather than wrapping somebody's implementation of it, so its colour roles, type scale and shapes are the ones the spec names.
|
|
14
20
|
|
|
15
|
-
- **
|
|
21
|
+
- **Themed in one line.** Set `--mp-source-color` and every colour role follows, the way Material generates a scheme from a source colour. No provider, no theme object, no re-render.
|
|
22
|
+
- **It coexists.** Nothing here is page-level — no reset, no provider, no global styling — and it reads the `--md-sys-color-*` tokens your page already has if they are there. A project already running Material keeps its own setup.
|
|
16
23
|
- **IME-safe by construction.** Korean, Japanese and Chinese composition survives whatever your `onChange` does with the value.
|
|
17
24
|
- **Bring your own icons.** `MPIcon` takes a component or an element from any set. `lucide-react` ships with the package, gathered in one readable constants file.
|
|
18
25
|
- **ESM only**, TypeScript declarations included, tree-shakeable — every component compiles to its own module.
|
|
@@ -42,15 +49,12 @@ pnpm add material-plus-ui
|
|
|
42
49
|
|
|
43
50
|
### Peer dependencies
|
|
44
51
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
|
48
|
-
|
|
|
49
|
-
| `@mui/material` | 6, 7, 8 or 9 |
|
|
50
|
-
| `@emotion/react`, `@emotion/styled` | 11 |
|
|
51
|
-
| `react`, `react-dom` | 18 or 19 |
|
|
52
|
+
| Package | Versions |
|
|
53
|
+
| -------------------- | -------- |
|
|
54
|
+
| `@base-ui/react` | 1 |
|
|
55
|
+
| `react`, `react-dom` | 18 or 19 |
|
|
52
56
|
|
|
53
|
-
|
|
57
|
+
`@base-ui/react` is a peer rather than a dependency because it carries React context: a `Form` of yours has to be able to see a field of ours, and that only works with one copy in the tree.
|
|
54
58
|
|
|
55
59
|
### Setup
|
|
56
60
|
|
|
@@ -60,7 +64,7 @@ Add one line to your app's CSS entry point:
|
|
|
60
64
|
@import 'material-plus-ui/styles.css';
|
|
61
65
|
```
|
|
62
66
|
|
|
63
|
-
This is finished CSS — no PostCSS plugin, no `@source`, no build-side configuration. It deliberately contains **no reset
|
|
67
|
+
This is finished CSS — no PostCSS plugin, no `@source`, no build-side configuration. It deliberately contains **no reset**, and no page-level styling of any kind: a component resets what it owns on the element it owns, so whatever your page already does stays in charge.
|
|
64
68
|
|
|
65
69
|
If Tailwind v4 is already in your project, import the token sheet instead:
|
|
66
70
|
|
|
@@ -71,39 +75,46 @@ If Tailwind v4 is already in your project, import the token sheet instead:
|
|
|
71
75
|
|
|
72
76
|
## Usage
|
|
73
77
|
|
|
74
|
-
|
|
78
|
+
There is no provider. Import a component and render it.
|
|
75
79
|
|
|
76
80
|
```tsx
|
|
77
81
|
import { useState } from 'react';
|
|
78
|
-
import CssBaseline from '@mui/material/CssBaseline';
|
|
79
|
-
import { ThemeProvider, createTheme } from '@mui/material/styles';
|
|
80
82
|
import { MPTextField, MPIcon, ICONS } from 'material-plus-ui';
|
|
81
83
|
|
|
82
|
-
const theme = createTheme({ palette: { mode: 'light' } });
|
|
83
|
-
|
|
84
84
|
export default function App() {
|
|
85
85
|
const [email, setEmail] = useState('');
|
|
86
86
|
|
|
87
87
|
return (
|
|
88
|
-
<
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
startIcon={<MPIcon icon={ICONS.search} size={18} />}
|
|
96
|
-
/>
|
|
97
|
-
</ThemeProvider>
|
|
88
|
+
<MPTextField
|
|
89
|
+
label="Email"
|
|
90
|
+
type="email"
|
|
91
|
+
value={email}
|
|
92
|
+
onChange={setEmail}
|
|
93
|
+
startIcon={<MPIcon icon={ICONS.search} size={18} />}
|
|
94
|
+
/>
|
|
98
95
|
);
|
|
99
96
|
}
|
|
100
97
|
```
|
|
101
98
|
|
|
99
|
+
## Theming
|
|
100
|
+
|
|
101
|
+
Material generates a whole scheme from one source colour, and so does this.
|
|
102
|
+
|
|
103
|
+
```css
|
|
104
|
+
:root {
|
|
105
|
+
--mp-source-color: #7c3aed;
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Dark mode follows `prefers-color-scheme` on its own; `data-mp-scheme="dark"` or `.dark` on any element drives it yourself. To disagree with one generated colour, set that role — `--mp-sys-color-outline` — and to follow tokens your page already defines, do nothing: `--md-sys-color-*` is read where it is present.
|
|
110
|
+
|
|
111
|
+
Full details, including scoped and runtime theming, are in [the theming guide](https://material-plus.cdget.com/guide/getting-started#theming).
|
|
112
|
+
|
|
102
113
|
## Components
|
|
103
114
|
|
|
104
115
|
| Component | What it is |
|
|
105
116
|
| --- | --- |
|
|
106
|
-
| [`MPTextField`](https://material-plus.cdget.com/components/inputs/text-field) |
|
|
117
|
+
| [`MPTextField`](https://material-plus.cdget.com/components/inputs/text-field) | An outlined text field that survives an IME, with the label, supporting text, adornments and password toggle already assembled. |
|
|
107
118
|
| [`MPIcon`](https://material-plus.cdget.com/components/display/icon) | A glyph at a known size in a known colour, from whichever icon set you use. |
|
|
108
119
|
|
|
109
120
|
### Why `MPTextField` exists
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { MPSize, MPVariant } from '../../types';
|
|
3
|
+
export interface MPAccordionProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'defaultValue' | 'onChange'> {
|
|
4
|
+
/**
|
|
5
|
+
* Whether more than one section may be open at once.
|
|
6
|
+
*
|
|
7
|
+
* `false` by default, which is the whole reason an accordion is not just a
|
|
8
|
+
* stack of [collapsibles](./collapsible): closing the last one as the next
|
|
9
|
+
* opens is what keeps the page from growing under the reader.
|
|
10
|
+
* @default false
|
|
11
|
+
*/
|
|
12
|
+
multiple?: boolean;
|
|
13
|
+
/** Which sections are open. Use with `onValueChange` for a controlled accordion. */
|
|
14
|
+
value?: (string | number)[];
|
|
15
|
+
/** Which start open, for an uncontrolled one. */
|
|
16
|
+
defaultValue?: (string | number)[];
|
|
17
|
+
onValueChange?: (value: (string | number)[]) => void;
|
|
18
|
+
/**
|
|
19
|
+
* Separates the sections with a hairline rather than with space.
|
|
20
|
+
*
|
|
21
|
+
* On by default, which is the other way round from `MPList`. A list of tiles
|
|
22
|
+
* is a list; an accordion of tiles is a stack of cards that happen to fold,
|
|
23
|
+
* and the rule is what says the sections are parts of one thing.
|
|
24
|
+
* @default true
|
|
25
|
+
*/
|
|
26
|
+
dividers?: boolean;
|
|
27
|
+
/** Unavailable. Every section stops answering. */
|
|
28
|
+
disabled?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* How much surface the sheet paints.
|
|
31
|
+
* @default 'outlined'
|
|
32
|
+
*/
|
|
33
|
+
variant?: MPVariant;
|
|
34
|
+
/**
|
|
35
|
+
* The room inside every section, and the type scale of its header and body.
|
|
36
|
+
* @default 'md'
|
|
37
|
+
*/
|
|
38
|
+
size?: MPSize;
|
|
39
|
+
/**
|
|
40
|
+
* Keeps closed panels in the DOM so the browser's own page search can find and
|
|
41
|
+
* open them. Overrides `keepMounted`.
|
|
42
|
+
* @default false
|
|
43
|
+
*/
|
|
44
|
+
hiddenUntilFound?: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Keeps closed panels in the DOM. For content that is expensive to build, or
|
|
47
|
+
* that holds form state which should survive being folded away.
|
|
48
|
+
* @default false
|
|
49
|
+
*/
|
|
50
|
+
keepMounted?: boolean;
|
|
51
|
+
/** The `MPAccordionItem`s. */
|
|
52
|
+
children?: React.ReactNode;
|
|
53
|
+
}
|
|
54
|
+
export interface MPAccordionItemProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'title' | 'onChange'> {
|
|
55
|
+
/**
|
|
56
|
+
* Identifies the section to `value` / `defaultValue`. Base UI generates one
|
|
57
|
+
* when it is left out, which is enough for an accordion nobody drives from
|
|
58
|
+
* code.
|
|
59
|
+
*/
|
|
60
|
+
value?: string | number;
|
|
61
|
+
/** The heading on the fold. */
|
|
62
|
+
title?: React.ReactNode;
|
|
63
|
+
/** A second line under it, one step down the type scale and muted. */
|
|
64
|
+
subtitle?: React.ReactNode;
|
|
65
|
+
/** Content before the title — a glyph, a status dot, a count. */
|
|
66
|
+
startIcon?: React.ReactNode;
|
|
67
|
+
/**
|
|
68
|
+
* A control pinned to the end of the header, **outside** the trigger.
|
|
69
|
+
*
|
|
70
|
+
* Deliberately outside it: a header that both folds and holds a switch has two
|
|
71
|
+
* things to press, and a `<button>` inside a `<button>` is markup the browser
|
|
72
|
+
* rewrites on parse. The same shape `MPCollapsible` and `MPListItem` use.
|
|
73
|
+
*/
|
|
74
|
+
action?: React.ReactNode;
|
|
75
|
+
/** Unavailable. This section stops folding; the rest keep working. */
|
|
76
|
+
disabled?: boolean;
|
|
77
|
+
/** The body. */
|
|
78
|
+
children?: React.ReactNode;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* A stack of sections, one of which is open.
|
|
82
|
+
*
|
|
83
|
+
* Base UI owns the parts that are genuinely hard: the `<button>`/`region`
|
|
84
|
+
* pairing and the `aria-controls` / `aria-expanded` wiring between them, the set
|
|
85
|
+
* of open values, and measuring each panel so it has a height to animate from.
|
|
86
|
+
* What is here is the surface, the ladders and Material's state layer.
|
|
87
|
+
*
|
|
88
|
+
* ## Why this is not a stack of collapsibles
|
|
89
|
+
*
|
|
90
|
+
* Because of `multiple`. A [collapsible](./collapsible) has an `open` of its
|
|
91
|
+
* own and answers to nobody; an accordion owns the *set*, and closing the last
|
|
92
|
+
* section as the next one opens is the whole reason the component exists — it is
|
|
93
|
+
* what keeps the page from growing under the reader. Sections that are genuinely
|
|
94
|
+
* unrelated should be collapsibles, and a component that closed one because the
|
|
95
|
+
* other opened would be inventing a relationship the page does not have.
|
|
96
|
+
*
|
|
97
|
+
* ## The surface stays neutral
|
|
98
|
+
*
|
|
99
|
+
* Even on `filled`, which here is `surface-container-highest` — MD3's own filled
|
|
100
|
+
* card — rather than the accent. An accordion is a box holding somebody else's
|
|
101
|
+
* content, and dyeing the box dyes their content's background. That is also why
|
|
102
|
+
* there is no `color`: nothing would read it.
|
|
103
|
+
*/
|
|
104
|
+
export declare const MPAccordion: React.ForwardRefExoticComponent<MPAccordionProps & React.RefAttributes<HTMLDivElement>>;
|
|
105
|
+
/**
|
|
106
|
+
* One section.
|
|
107
|
+
*
|
|
108
|
+
* The header is always a row, and what is inside it is a real `<button>`
|
|
109
|
+
* covering the title and the chevron, with `action` sitting outside that button
|
|
110
|
+
* as a control of its own. The same shape `MPChip` and `MPListItem` use, for the
|
|
111
|
+
* same two reasons: a `<div>` carrying a click handler is invisible to a
|
|
112
|
+
* keyboard, and a `<button>` inside a `<button>` is markup the browser rewrites
|
|
113
|
+
* on parse.
|
|
114
|
+
*/
|
|
115
|
+
export declare const MPAccordionItem: React.ForwardRefExoticComponent<MPAccordionItemProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as n}from"react/jsx-runtime";import*as t from"react";import{Accordion as i}from"@base-ui/react/accordion";import{MPIcon as a}from"../icon/MPIcon";import{ChevronDownIcon as r}from"../../constants/icons";import{MPStateLayer as o}from"../../internal/StateLayer";import{CONTROL_GAP as s,CONTROL_ICON as l,hasContent as d,META_TEXT as c,PROSE_TEXT as m,SHEET_PAD_X as u,SHEET_PAD_Y as f,SHEET_TITLE as p}from"../../internal/scale";import{CONTAINER_SURFACE as h}from"../../internal/surface";const x=t.createContext({size:"md",dividers:!0}),v=["h-(--accordion-panel-height) overflow-hidden","transition-[height] duration-(--mp-sys-motion-duration-short4) ease-mp-standard","motion-reduce:transition-none","data-starting-style:h-0 data-ending-style:h-0"].join(" "),b={xs:"pb-2.5",sm:"pb-3",md:"pb-4",lg:"pb-5",xl:"pb-6"};export const MPAccordion=t.forwardRef(function({multiple:n=!1,value:a,defaultValue:r,onValueChange:o,dividers:s=!0,disabled:l=!1,variant:d="outlined",size:c="md",hiddenUntilFound:m=!1,keepMounted:u=!1,className:f,children:p,...v},b){const N=t.useMemo(()=>({size:c,dividers:s}),[c,s]);return e(x.Provider,{value:N,children:e(i.Root,{ref:b,multiple:n,value:a,defaultValue:r,onValueChange:e=>o?.(e),disabled:l,hiddenUntilFound:m,keepMounted:u,"data-mp-size":c,"data-mp-variant":d,className:["mp-accordion rounded-mp-md flex w-full flex-col",h[d],"text-mp-on-surface",s?"overflow-hidden [&>div+div]:border-mp-outline-variant [&>div+div]:border-t":"p-1",f??""].filter(Boolean).join(" "),...v,children:p})})});export const MPAccordionItem=t.forwardRef(function({value:h,title:N,subtitle:g,startIcon:j,action:w,disabled:y=!1,className:z,children:M,...k},P){const{size:C,dividers:I}=t.useContext(x),V=u[C],B=f[C];return n(i.Item,{ref:P,value:h,disabled:y,className:["mp-accordion__item flex flex-col",z??""].filter(Boolean).join(" "),...k,children:[n(i.Header,{className:"m-0 flex w-full items-center font-[inherit]",children:[n(i.Trigger,{className:["group relative flex min-w-0 flex-1 cursor-pointer items-center text-start","appearance-none border-0 bg-transparent font-[inherit] text-inherit",V,B,s[C],I?"":"rounded-mp-sm","outline-mp-secondary focus-visible:outline-2 focus-visible:-outline-offset-2","focus-visible:outline-solid outline-none","disabled:text-mp-on-surface/38 disabled:cursor-default"].filter(Boolean).join(" "),children:[e(o,{}),d(j)?e("span",{className:"text-mp-on-surface-variant flex h-[1lh] shrink-0 items-center",children:j}):null,n("span",{className:"flex min-w-0 flex-1 flex-col",children:[d(N)?e("span",{className:`truncate ${p[C]}`,children:N}):null,d(g)?e("span",{className:`text-mp-on-surface-variant truncate ${c}`,children:g}):null]}),e("span",{className:["text-mp-on-surface-variant flex h-[1lh] shrink-0 items-center","transition-[rotate] duration-(--mp-sys-motion-duration-short4)","ease-mp-standard motion-reduce:transition-none","group-data-panel-open:rotate-180"].join(" "),children:e(a,{icon:r,size:l[C]})})]}),d(w)?e("span",{className:`flex shrink-0 items-center ${V}`,children:w}):null]}),e(i.Panel,{className:v,children:e("div",{className:["min-w-0",m[C],"text-mp-on-surface-variant",V,b[C]].join(" "),children:M})})]})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{MPAccordion,MPAccordionItem}from"./MPAccordion";
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { MPColor, MPSize, MPVariant } from '../../types';
|
|
3
|
+
export interface MPAlertProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'color' | 'title'> {
|
|
4
|
+
/**
|
|
5
|
+
* How much surface the alert paints.
|
|
6
|
+
*
|
|
7
|
+
* `tonal` rather than `filled`, which is the one place this component's default
|
|
8
|
+
* differs from a button's. A container tone is MD3's own answer for a message
|
|
9
|
+
* set into a page — it separates itself from the surface without competing
|
|
10
|
+
* with the primary action that is usually sitting right beside it, and a page
|
|
11
|
+
* with three saturated alerts on it has no emphasis left to spend.
|
|
12
|
+
* @default 'tonal'
|
|
13
|
+
*/
|
|
14
|
+
variant?: MPVariant;
|
|
15
|
+
/**
|
|
16
|
+
* Which accent family it reads.
|
|
17
|
+
*
|
|
18
|
+
* Four roles, not a severity ladder — there is no `info`, `success` or
|
|
19
|
+
* `warning` here, because [the specification's colour
|
|
20
|
+
* system](../design/color) has no way to derive them and a library that
|
|
21
|
+
* invented three more families would be promising tokens the sheet cannot
|
|
22
|
+
* produce. `error` is the one severity Material does name, and the rest is an
|
|
23
|
+
* emphasis decision: `primary` for a notice, `secondary` or `tertiary` for one
|
|
24
|
+
* that should sit further back.
|
|
25
|
+
* @default 'primary'
|
|
26
|
+
*/
|
|
27
|
+
color?: MPColor;
|
|
28
|
+
/**
|
|
29
|
+
* The room inside, and the type scale of the text in it.
|
|
30
|
+
* @default 'md'
|
|
31
|
+
*/
|
|
32
|
+
size?: MPSize;
|
|
33
|
+
/**
|
|
34
|
+
* The heading line. With it the alert is two-part — a headline and the detail
|
|
35
|
+
* under it; without it the whole thing is one line.
|
|
36
|
+
*/
|
|
37
|
+
title?: React.ReactNode;
|
|
38
|
+
/**
|
|
39
|
+
* The glyph at the start.
|
|
40
|
+
*
|
|
41
|
+
* Defaults to the one that goes with `color`; pass `false` to drop it, or a
|
|
42
|
+
* node to replace it. Only two defaults exist because only two are honest: the
|
|
43
|
+
* error family gets the error glyph and everything else gets the informational
|
|
44
|
+
* one. An alert that means "this worked" should say so with an `icon` of its
|
|
45
|
+
* own rather than by having the library guess from a colour.
|
|
46
|
+
*/
|
|
47
|
+
icon?: React.ReactNode | false;
|
|
48
|
+
/**
|
|
49
|
+
* Content pinned to the end of the row — a "Retry" button, a link. Kept out of
|
|
50
|
+
* `children` so it stays on the first line while the message wraps.
|
|
51
|
+
*/
|
|
52
|
+
action?: React.ReactNode;
|
|
53
|
+
/** Passing it is what makes the dismiss button appear. */
|
|
54
|
+
onClose?: (event: React.MouseEvent<HTMLButtonElement>) => void;
|
|
55
|
+
/**
|
|
56
|
+
* The accessible name of the dismiss button. Defaults to the word for
|
|
57
|
+
* "dismiss" in `locale`.
|
|
58
|
+
*/
|
|
59
|
+
closeLabel?: string;
|
|
60
|
+
/**
|
|
61
|
+
* Which language the dismiss button's default name is written in. Falls back
|
|
62
|
+
* to the nearest `MPLocaleProvider`, then to English.
|
|
63
|
+
*/
|
|
64
|
+
locale?: string;
|
|
65
|
+
/** The message. */
|
|
66
|
+
children?: React.ReactNode;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* A message about something that happened, set into the page it is about.
|
|
70
|
+
*
|
|
71
|
+
* The three shapes people mean by "an alert" are one component with different
|
|
72
|
+
* slots filled rather than three components: a bare line (`<MPAlert icon={false}>`),
|
|
73
|
+
* a line with a glyph (the default), and a glyph with a headline and the detail
|
|
74
|
+
* under it (`title` plus `children`). Nothing about the surface changes between
|
|
75
|
+
* them — only how much of it is used.
|
|
76
|
+
*
|
|
77
|
+
* There is no Base UI primitive under this, and there should not be: an alert has
|
|
78
|
+
* no interaction to delegate. It is a live region with a layout, and the only
|
|
79
|
+
* interactive parts it can grow — the action and the dismiss button — are real
|
|
80
|
+
* buttons that the caller either passes in or gets by passing `onClose`.
|
|
81
|
+
*
|
|
82
|
+
* ## Why this is not a snackbar
|
|
83
|
+
*
|
|
84
|
+
* An alert belongs to the flow of the page it interrupts; a snackbar floats over
|
|
85
|
+
* it and leaves on a timer. That is not a styling difference: a message the
|
|
86
|
+
* reader has to act on must not be able to disappear before it has been read,
|
|
87
|
+
* and a message about the page's *current* state has to still be there when they
|
|
88
|
+
* look back at it. If it can be missed without consequence, it is
|
|
89
|
+
* [MPSnackbar](../feedback/snackbar).
|
|
90
|
+
*/
|
|
91
|
+
export declare const MPAlert: React.ForwardRefExoticComponent<MPAlertProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as t}from"react/jsx-runtime";import*as n from"react";import{MPIcon as r}from"../icon/MPIcon";import{CloseIcon as a,ErrorIcon as l,InfoIcon as o}from"../../constants/icons";import{accentSlots as i}from"../../internal/accent";import{useMPLocale as s,useMPMessages as c}from"../../internal/locale";import{MPStateLayer as m}from"../../internal/StateLayer";import{CONTROL_ICON as d,hasContent as f,PROSE_TEXT as p,SHEET_GAP as u,SHEET_PAD as x,SHEET_TITLE as h,STACK_GAP as v}from"../../internal/scale";const b={filled:"bg-(--_mp-accent) text-(--_mp-on-accent)",tonal:"bg-(--_mp-accent-container) text-(--_mp-on-accent-container)",elevated:"shadow-mp-1 bg-mp-surface-container-low text-mp-on-surface",outlined:"border-mp-outline border bg-transparent text-mp-on-surface",text:"bg-transparent text-mp-on-surface"},y={filled:"",tonal:"",elevated:"text-(--_mp-accent)",outlined:"text-(--_mp-accent)",text:"text-(--_mp-accent)"},N={filled:"",tonal:"",elevated:"text-mp-on-surface-variant",outlined:"text-mp-on-surface-variant",text:"text-mp-on-surface-variant"},j={primary:"status",secondary:"status",tertiary:"status",error:"alert"};export const MPAlert=n.forwardRef(function({variant:n="tonal",color:g="primary",size:_="md",title:w,icon:z,action:k,onClose:B,closeLabel:C,locale:L,className:M,style:P,children:A,...I},R){const S=s(L),$=c("alert",S),q=y[n],D=f(w),E=void 0===z?e(r,{icon:"error"===g?l:o,size:d[_]}):z;return t("div",{ref:R,role:j[g],"data-mp-size":_,"data-mp-variant":n,className:["mp-alert rounded-mp-md flex w-full items-start","box-border",x[_],u[_],p[_],b[n],M??""].filter(Boolean).join(" "),style:{...i(g),...P},...I,children:[f(E)?e("span",{className:["flex h-[1lh] shrink-0 items-center",q].filter(Boolean).join(" "),children:E}):null,t("div",{className:`flex min-w-0 flex-1 flex-col ${v[_]}`,children:[D?e("div",{className:[h[_],q].filter(Boolean).join(" "),children:w}):null,f(A)?e("div",{className:D?N[n]:void 0,children:A}):null]}),f(k)?e("div",{className:"flex h-[1lh] shrink-0 items-center",children:k}):null,B?e("span",{className:"flex h-[1lh] shrink-0 items-center",children:t("button",{type:"button","aria-label":C??$.dismiss,onClick:B,className:["group rounded-mp-full relative -m-1 flex size-8 cursor-pointer items-center","justify-center bg-transparent text-inherit","outline-mp-secondary focus-visible:outline-2 focus-visible:outline-offset-2","focus-visible:outline-solid outline-none"].join(" "),children:[e(m,{}),e(r,{icon:a,size:d[_]})]})}):null]})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{MPAlert}from"./MPAlert";
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useRender } from '@base-ui/react/use-render';
|
|
3
|
+
import type { MPSize } from '../../types';
|
|
4
|
+
/**
|
|
5
|
+
* How the media inside is fitted to the box, spelled the way CSS spells it.
|
|
6
|
+
*
|
|
7
|
+
* These are `object-fit`'s own values rather than a nicer set of words, and for
|
|
8
|
+
* the same reason `MPSide` keeps `top`/`right`/`bottom`/`left`: inventing
|
|
9
|
+
* `fill-the-box` would only make a reader look up which CSS it maps to.
|
|
10
|
+
*/
|
|
11
|
+
export type MPAspectFit = 'cover' | 'contain' | 'fill' | 'none';
|
|
12
|
+
export interface MPAspectRatioProps extends React.ComponentPropsWithoutRef<'div'> {
|
|
13
|
+
/**
|
|
14
|
+
* The proportion the box holds, written the way CSS writes it — a number
|
|
15
|
+
* (`1.5`) or a ratio (`'16 / 9'`). Both reach `aspect-ratio` untouched.
|
|
16
|
+
* @default 1
|
|
17
|
+
*/
|
|
18
|
+
ratio?: number | string;
|
|
19
|
+
/**
|
|
20
|
+
* How a single piece of media inside is fitted.
|
|
21
|
+
*
|
|
22
|
+
* Applies to an `img`, a `video`, a `canvas`, an `svg`, a `picture` or an
|
|
23
|
+
* `iframe` that is a *direct* child; those are stretched to the full box and
|
|
24
|
+
* then fitted. Anything else is laid out normally and this prop does not reach
|
|
25
|
+
* it.
|
|
26
|
+
* @default 'cover'
|
|
27
|
+
*/
|
|
28
|
+
fit?: MPAspectFit;
|
|
29
|
+
/**
|
|
30
|
+
* Rounds the corners to the `size` rung.
|
|
31
|
+
*
|
|
32
|
+
* Off by default. A layout component draws nothing, and a photograph with its
|
|
33
|
+
* corners cut is a decision about the photograph — but it is such a common one
|
|
34
|
+
* that making the caller reach for a `className` would be perverse.
|
|
35
|
+
* @default false
|
|
36
|
+
*/
|
|
37
|
+
rounded?: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Which corner `rounded` uses. There is no height and no type scale on a box
|
|
40
|
+
* whose whole job is a proportion, so this is the one axis `size` has here.
|
|
41
|
+
* @default 'md'
|
|
42
|
+
*/
|
|
43
|
+
size?: MPSize;
|
|
44
|
+
/**
|
|
45
|
+
* Renders something other than a `<div>`: `render={<figure />}`,
|
|
46
|
+
* `render={<a href="…" />}`. Base UI's own escape hatch.
|
|
47
|
+
*/
|
|
48
|
+
render?: useRender.RenderProp;
|
|
49
|
+
children?: React.ReactNode;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* A box that keeps a proportion whatever width it is given.
|
|
53
|
+
*
|
|
54
|
+
* It draws nothing — no surface, no border, no shadow, no colour — which is what
|
|
55
|
+
* makes it layout rather than a component in the Material sense. What it does is
|
|
56
|
+
* *reserve* the space: a card whose image arrives late does not reflow the page
|
|
57
|
+
* around it, and a row of thumbnails is a row of one shape.
|
|
58
|
+
*
|
|
59
|
+
* That is worth more than it sounds. Material's layout guidance is built on a
|
|
60
|
+
* grid whose rows line up, and the single most common way a real page stops
|
|
61
|
+
* lining up is media of unknown height arriving after the text around it has
|
|
62
|
+
* already been laid out.
|
|
63
|
+
*
|
|
64
|
+
* The proportion is CSS's own `aspect-ratio`, so a caller who already knows
|
|
65
|
+
* `16 / 9` has nothing to translate. `fit` is the one convenience on top: the
|
|
66
|
+
* media inside is stretched to the box and then fitted, which is the pair of
|
|
67
|
+
* declarations every use of this component would otherwise start with.
|
|
68
|
+
*/
|
|
69
|
+
export declare const MPAspectRatio: React.ForwardRefExoticComponent<MPAspectRatioProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import*as e from"react";import{useRender as o}from"@base-ui/react/use-render";const i={xs:"rounded-mp-xs",sm:"rounded-mp-sm",md:"rounded-mp-md",lg:"rounded-mp-md",xl:"rounded-mp-xl"},t=["[&>img]:size-full","[&>video]:size-full","[&>canvas]:size-full","[&>svg]:size-full","[&>iframe]:size-full","[&>picture]:size-full","[&>picture>img]:size-full"].join(" "),r={cover:"[&>img]:object-cover [&>video]:object-cover [&>picture>img]:object-cover",contain:"[&>img]:object-contain [&>video]:object-contain [&>picture>img]:object-contain",fill:"[&>img]:object-fill [&>video]:object-fill [&>picture>img]:object-fill",none:"[&>img]:object-none [&>video]:object-none [&>picture>img]:object-none"};export const MPAspectRatio=e.forwardRef(function({ratio:e=1,fit:c="cover",rounded:l=!1,size:n="md",render:s,className:d,style:m,children:a,...u},f){const p=["mp-aspect-ratio relative block w-full overflow-hidden",t,r[c],l?i[n]:"",d??""].filter(Boolean).join(" ");return o({render:s,ref:f,props:{"data-mp-size":n,className:p,style:{aspectRatio:e,...m},children:a,...u}})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{MPAspectRatio}from"./MPAspectRatio";
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { MPColor, MPSize, MPVariant } from '../../types';
|
|
3
|
+
/** What Base UI reports about the picture as it loads. */
|
|
4
|
+
export type MPAvatarLoadingStatus = 'idle' | 'loading' | 'loaded' | 'error';
|
|
5
|
+
/**
|
|
6
|
+
* The crop.
|
|
7
|
+
*
|
|
8
|
+
* `circle` is the default and is what Material draws: MD3's avatar is a circle,
|
|
9
|
+
* and a round crop is what a portrait has been for as long as there have been
|
|
10
|
+
* portraits.
|
|
11
|
+
*
|
|
12
|
+
* `square` cuts the corners off instead, which is what a logo or a repository
|
|
13
|
+
* icon wants — those are drawn to the edges of a rectangle and a round crop eats
|
|
14
|
+
* them.
|
|
15
|
+
*/
|
|
16
|
+
export type MPAvatarShape = 'circle' | 'square';
|
|
17
|
+
export interface MPAvatarProps extends Omit<React.ComponentPropsWithoutRef<'span'>, 'color'> {
|
|
18
|
+
/**
|
|
19
|
+
* The picture. Until it loads — and forever, if it fails — the fallback is
|
|
20
|
+
* what is drawn, so an avatar is never an empty box.
|
|
21
|
+
*/
|
|
22
|
+
src?: string;
|
|
23
|
+
/** Candidate images at other resolutions, as on any `<img>`. */
|
|
24
|
+
srcSet?: string;
|
|
25
|
+
/**
|
|
26
|
+
* What the picture says, for a reader who cannot see it. Defaults to `name`,
|
|
27
|
+
* and to nothing at all when there is no name — an avatar next to the person's
|
|
28
|
+
* own name in the row is decoration, and reading it out says the name twice.
|
|
29
|
+
*/
|
|
30
|
+
alt?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Who or what this is. One prop doing three jobs: it names the picture, the
|
|
33
|
+
* initials are derived from it, and it is the sentence a screen reader hears
|
|
34
|
+
* instead of those initials.
|
|
35
|
+
*
|
|
36
|
+
* The initials are the first character of the first word plus the first
|
|
37
|
+
* character of the last — "Jane Doe" is `JD`, "홍길동" is `홍`. That rule is
|
|
38
|
+
* wrong for some names, which is what `initials` is for.
|
|
39
|
+
*/
|
|
40
|
+
name?: string;
|
|
41
|
+
/** The initials, written out, for when the rule derived the wrong ones. */
|
|
42
|
+
initials?: string;
|
|
43
|
+
/**
|
|
44
|
+
* The crop.
|
|
45
|
+
* @default 'circle'
|
|
46
|
+
*/
|
|
47
|
+
shape?: MPAvatarShape;
|
|
48
|
+
/**
|
|
49
|
+
* How much surface is painted behind the fallback. Invisible once a picture
|
|
50
|
+
* has loaded, apart from the edge `outlined` keeps.
|
|
51
|
+
*
|
|
52
|
+
* `tonal` is the default because it is what MD3 draws a monogram on: the
|
|
53
|
+
* container tone of the accent family, with the matching `on-` ink. A page of
|
|
54
|
+
* `filled` avatars is a page of saturated circles nobody can read a name off.
|
|
55
|
+
* @default 'tonal'
|
|
56
|
+
*/
|
|
57
|
+
variant?: MPVariant;
|
|
58
|
+
/**
|
|
59
|
+
* The box the picture is drawn in — the control heights, so an avatar and the
|
|
60
|
+
* button beside it in a toolbar are the same height.
|
|
61
|
+
* @default 'md'
|
|
62
|
+
*/
|
|
63
|
+
size?: MPSize;
|
|
64
|
+
/** @default 'primary' */
|
|
65
|
+
color?: MPColor;
|
|
66
|
+
/**
|
|
67
|
+
* How long to wait before drawing the fallback, in milliseconds. Set it to
|
|
68
|
+
* roughly the time a cached image takes and the initials stop flashing up in
|
|
69
|
+
* front of a picture that was about to arrive anyway.
|
|
70
|
+
*/
|
|
71
|
+
delay?: number;
|
|
72
|
+
/** Anything else the `<img>` needs — `loading`, `crossOrigin`, `referrerPolicy`. */
|
|
73
|
+
imageProps?: Omit<React.ComponentPropsWithoutRef<'img'>, 'src' | 'srcSet' | 'alt'>;
|
|
74
|
+
/** Called as the picture moves between `idle`, `loading`, `loaded` and `error`. */
|
|
75
|
+
onLoadingStatusChange?: (status: MPAvatarLoadingStatus) => void;
|
|
76
|
+
/**
|
|
77
|
+
* The fallback, drawn instead of the initials. An icon, a logo, a single emoji
|
|
78
|
+
* — whatever stands in for this particular thing when there is no picture of
|
|
79
|
+
* it.
|
|
80
|
+
*/
|
|
81
|
+
children?: React.ReactNode;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* A picture of a person or a thing, at a known size, that is never an empty box.
|
|
85
|
+
*
|
|
86
|
+
* Three things can be drawn in it and exactly one of them is at a time: the
|
|
87
|
+
* picture, if `src` is given and loads; otherwise whatever stands in for it —
|
|
88
|
+
* `children`, or `initials`, or the initials derived from `name`; and failing
|
|
89
|
+
* all of those, a silhouette. Which one is showing is Base UI's `Avatar` to
|
|
90
|
+
* decide, because "has the image loaded" is a question with four answers and a
|
|
91
|
+
* race in the middle of it.
|
|
92
|
+
*
|
|
93
|
+
* It carries no status dot of its own. An avatar with a green mark on it is an
|
|
94
|
+
* `MPBadge` with an avatar in it, and inventing a second spelling for that would
|
|
95
|
+
* give the library two of them.
|
|
96
|
+
*/
|
|
97
|
+
export declare const MPAvatar: React.ForwardRefExoticComponent<MPAvatarProps & React.RefAttributes<HTMLSpanElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as a}from"react/jsx-runtime";import*as t from"react";import{Avatar as n}from"@base-ui/react/avatar";import{accentSlots as r}from"../../internal/accent";import{CONTROL_SQUARE as l,hasContent as i}from"../../internal/scale";import{VISUALLY_HIDDEN as o}from"../../internal/visually-hidden";const m={xs:"text-mp-label-medium",sm:"text-mp-label-large",md:"text-mp-title-large",lg:"text-mp-headline-small",xl:"text-mp-headline-medium"},s={xs:"rounded-mp-xs",sm:"rounded-mp-sm",md:"rounded-mp-md",lg:"rounded-mp-md",xl:"rounded-mp-md"},c={filled:"bg-(--_mp-accent) text-(--_mp-on-accent)",tonal:"bg-(--_mp-accent-container) text-(--_mp-on-accent-container)",elevated:"shadow-mp-1 bg-mp-surface-container-low text-(--_mp-accent)",outlined:"border-mp-outline border bg-transparent text-(--_mp-accent)",text:"text-mp-on-surface-variant bg-transparent"};function d(){return a("svg",{viewBox:"0 0 24 24",fill:"currentColor","aria-hidden":"true",className:"size-[60%]",children:[e("path",{d:"M12 12a4.5 4.5 0 1 0 0-9 4.5 4.5 0 0 0 0 9Z"}),e("path",{d:"M12 14.25c-4.28 0-7.75 2.42-7.75 5.4 0 .75.6 1.35 1.35 1.35h12.8c.75 0 1.35-.6 1.35-1.35 0-2.98-3.47-5.4-7.75-5.4Z"})]})}export const MPAvatar=t.forwardRef(function({src:t,srcSet:p,alt:u,name:f,initials:h,shape:x="circle",variant:g="tonal",size:v="md",color:b="primary",delay:y,imageProps:N,onLoadingStatusChange:j,className:w,style:z,children:_,...C},A){const B=f?function(e){const a=e.normalize("NFC").trim().split(/\s+/).filter(Boolean);return 0===a.length?"":((Array.from(a[0])[0]??"")+(a.length>1?Array.from(a[a.length-1])[0]??"":"")).toLocaleUpperCase()}(f):"",S=u??f,L=i(_)?_:(h??B)||e(d,{}),M=i(_)||Boolean(h??B),k=["mp-avatar relative inline-flex shrink-0 items-center justify-center overflow-hidden","align-middle leading-none font-medium whitespace-nowrap select-none",l[v],m[v],"circle"===x?"rounded-mp-full":s[v],c[g],w??""].filter(Boolean).join(" ");return a(n.Root,{ref:A,"data-mp-size":v,"data-mp-variant":g,className:k,style:{...r(b),...z},...C,children:[t?e(n.Image,{src:t,srcSet:p,alt:S??"",className:"size-full object-cover",onLoadingStatusChange:j,...N}):null,a(n.Fallback,{delay:t?y:void 0,className:"flex size-full items-center justify-center",children:[S&&M?e("span",{className:o,children:S}):null,e("span",{"aria-hidden":!(!S||!M)||void 0,className:"contents",children:L})]})]})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{MPAvatar}from"./MPAvatar";
|