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,95 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { MPTypographyWeight } from '../typography/MPTypography';
|
|
3
|
+
import type { MPColor, MPVariant } from '../../types';
|
|
4
|
+
/**
|
|
5
|
+
* The four weights a mark can be drawn at.
|
|
6
|
+
*
|
|
7
|
+
* `elevated` is deliberately absent, and it is the one member of `MPVariant` that
|
|
8
|
+
* could not mean anything here: elevation is a surface lifting off the page, and
|
|
9
|
+
* a mark is *inside* a line of text. A raised word would cast a shadow onto the
|
|
10
|
+
* sentence it is part of.
|
|
11
|
+
*/
|
|
12
|
+
export type MPHighlightVariant = Exclude<MPVariant, 'elevated'>;
|
|
13
|
+
export interface MPHighlightProps extends Omit<React.ComponentPropsWithoutRef<'span'>, 'color'> {
|
|
14
|
+
/**
|
|
15
|
+
* What to find.
|
|
16
|
+
*
|
|
17
|
+
* A string is one term, an array is several — the longest is tried first, so
|
|
18
|
+
* `['data', 'database']` marks the whole word rather than the first four
|
|
19
|
+
* letters of it. A `RegExp` is used as written, with the global flag forced on;
|
|
20
|
+
* `caseSensitive` and `wholeWord` are ignored for it, because a regular
|
|
21
|
+
* expression already says both of those things itself.
|
|
22
|
+
*/
|
|
23
|
+
query: string | string[] | RegExp;
|
|
24
|
+
/**
|
|
25
|
+
* How much surface the mark paints.
|
|
26
|
+
*
|
|
27
|
+
* `tonal` is the default, and it is the only one of the four that is a
|
|
28
|
+
* highlighter pen: MD3's container roles are a pale wash under dark ink, which
|
|
29
|
+
* is a marked word rather than a word replaced by a block of colour. `filled`
|
|
30
|
+
* is the accent proper under its own ink — loud, and right for one match on a
|
|
31
|
+
* page. `outlined` boxes the word, `text` recolours it and draws nothing.
|
|
32
|
+
* @default 'tonal'
|
|
33
|
+
*/
|
|
34
|
+
variant?: MPHighlightVariant;
|
|
35
|
+
/**
|
|
36
|
+
* Which accent family the mark reads.
|
|
37
|
+
*
|
|
38
|
+
* `tertiary` rather than `primary`, and this is the one place in the library
|
|
39
|
+
* where that is the right default. `primary` is what a page uses for the thing
|
|
40
|
+
* it wants pressed; a search match is not that, and a page whose marked words
|
|
41
|
+
* are the same colour as its buttons has two things competing to be the loudest
|
|
42
|
+
* thing on it.
|
|
43
|
+
* @default 'tertiary'
|
|
44
|
+
*/
|
|
45
|
+
color?: MPColor;
|
|
46
|
+
/**
|
|
47
|
+
* Whether `a` and `A` are different letters.
|
|
48
|
+
* @default false
|
|
49
|
+
*/
|
|
50
|
+
caseSensitive?: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Whether a term has to be a word on its own — `cat` marking "cat" but not
|
|
53
|
+
* "concatenate".
|
|
54
|
+
*
|
|
55
|
+
* A word here is a run of letters, digits and underscores in any script, so it
|
|
56
|
+
* means what it should for `café` and `naïve`. It means very little for Korean
|
|
57
|
+
* or Japanese, where a phrase is not delimited by spaces at all; that is a
|
|
58
|
+
* property of the writing system rather than of this prop, and is why it is off
|
|
59
|
+
* by default.
|
|
60
|
+
* @default false
|
|
61
|
+
*/
|
|
62
|
+
wholeWord?: boolean;
|
|
63
|
+
/** Underlines the mark as well. Combines with every variant. */
|
|
64
|
+
underline?: boolean;
|
|
65
|
+
/**
|
|
66
|
+
* Sets the mark's weight. Omit it and the mark is the weight of the text around
|
|
67
|
+
* it — the surface is already saying "this one", and a bolded word inside a
|
|
68
|
+
* sentence changes the rhythm of the whole line.
|
|
69
|
+
*/
|
|
70
|
+
weight?: MPTypographyWeight;
|
|
71
|
+
/**
|
|
72
|
+
* The text to search. Elements are walked into and left otherwise untouched, so
|
|
73
|
+
* a match inside a `<strong>` is still marked and the `<strong>` survives.
|
|
74
|
+
*/
|
|
75
|
+
children?: React.ReactNode;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Marks the words a reader is looking for, inside text they were already reading.
|
|
79
|
+
*
|
|
80
|
+
* The component is the search, not just the styling: `query` is what a search box
|
|
81
|
+
* holds, and everything about *how* the matching is done — case, whole words, a
|
|
82
|
+
* regular expression — is a prop rather than something a caller has to
|
|
83
|
+
* pre-compute into a list of offsets.
|
|
84
|
+
*
|
|
85
|
+
* The mark is a real `<mark>`, which is the element for text of relevance to the
|
|
86
|
+
* reader and is announced as such. That has one consequence worth knowing:
|
|
87
|
+
* marking eleven words in a paragraph tells a screen reader that eleven things
|
|
88
|
+
* are important, which is a way of saying nothing. A highlight is for a handful
|
|
89
|
+
* of matches.
|
|
90
|
+
*
|
|
91
|
+
* Nothing here is stateful and nothing measures — the whole component is a pure
|
|
92
|
+
* function of `children` and `query`, so it re-marks on its own the moment the
|
|
93
|
+
* search box changes.
|
|
94
|
+
*/
|
|
95
|
+
export declare const MPHighlight: React.ForwardRefExoticComponent<MPHighlightProps & React.RefAttributes<HTMLSpanElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e}from"react/jsx-runtime";import*as n from"react";import{accentSlots as t}from"../../internal/accent";const r={filled:"bg-(--_mp-accent) text-(--_mp-on-accent)",tonal:"bg-(--_mp-accent-container) text-(--_mp-on-accent-container)",outlined:"border border-(--_mp-accent) bg-transparent text-(--_mp-accent)",text:"bg-transparent text-(--_mp-accent)"},o={regular:"font-normal",medium:"font-medium",semibold:"font-semibold",bold:"font-bold"},i=/[\p{L}\p{N}_]/u;function l(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function a(e,n,t){const r=n>0?e[n-1]:"",o=t<e.length?e[t]:"";return!i.test(r)&&!i.test(o)}function c(e,n,t,r){n.lastIndex=0;const o=[];let i,l=0;for(;null!==(i=n.exec(e));){if(""===i[0]){n.lastIndex+=1;continue}const c=i.index,s=c+i[0].length;t&&!a(e,c,s)||(c>l&&o.push(e.slice(l,c)),o.push(r(i[0],String(c))),l=s)}return 0===o.length?e:(l<e.length&&o.push(e.slice(l)),o)}function s(e,t,r,o){if("string"==typeof e)return c(e,t,r,o);if("number"==typeof e)return c(String(e),t,r,o);if(Array.isArray(e))return n.Children.map(e,e=>s(e,t,r,o));if(n.isValidElement(e)){const i=e.props.children;return void 0===i||"function"==typeof i?e:n.cloneElement(e,void 0,s(i,t,r,o))}return e}export const MPHighlight=n.forwardRef(function({query:i,variant:a="tonal",color:c="tertiary",caseSensitive:u=!1,wholeWord:m=!1,underline:f=!1,weight:p,className:d,style:g,children:h,...x},b){const y=n.useMemo(()=>function(e,n){if(e instanceof RegExp)return e.global?e:new RegExp(e.source,`${e.flags}g`);const t=(Array.isArray(e)?e:[e]).map(e=>e.trim()).filter(Boolean).sort((e,n)=>n.length-e.length);return 0===t.length?null:new RegExp(t.map(l).join("|"),n?"gu":"giu")}(i,u),[i,u]),_=["rounded-mp-xs -mx-0.5 px-0.5","box-decoration-clone",r[a],f?"underline decoration-2 underline-offset-2":"",p?o[p]:""].filter(Boolean).join(" "),j=y?s(h,y,m,(n,t)=>e("mark",{className:_,children:n},t)):h;return e("span",{ref:b,className:["mp-highlight",d??""].filter(Boolean).join(" "),style:{...t(c),...g},...x,children:j})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{MPHighlight}from"./MPHighlight";
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { type MPButtonProps } from '../button/MPButton';
|
|
3
|
+
export interface MPIconButtonProps extends Omit<MPButtonProps, 'children' | 'startIcon' | 'endIcon' | 'fullWidth'> {
|
|
4
|
+
/**
|
|
5
|
+
* The glyph.
|
|
6
|
+
*
|
|
7
|
+
* Wrap it in an `MPIcon` when it needs a size of its own; passed bare it is
|
|
8
|
+
* laid out exactly as a button's `startIcon` is, which is what keeps an icon
|
|
9
|
+
* button and a labelled button with the same glyph drawing it at the same
|
|
10
|
+
* size.
|
|
11
|
+
*/
|
|
12
|
+
icon: React.ReactNode;
|
|
13
|
+
/**
|
|
14
|
+
* What the button does, in words.
|
|
15
|
+
*
|
|
16
|
+
* Required, and the one prop here that is. A button whose whole label is a
|
|
17
|
+
* drawing has no accessible name at all, and "an icon button with no
|
|
18
|
+
* `aria-label`" is the single most common accessibility defect a component
|
|
19
|
+
* library ships. Making it required is the only fix that survives review — a
|
|
20
|
+
* default would be a name that is right for nobody, and a warning is a thing
|
|
21
|
+
* that gets filtered out of a console.
|
|
22
|
+
*/
|
|
23
|
+
label: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* A round button with a glyph in it and nothing else.
|
|
27
|
+
*
|
|
28
|
+
* There is almost nothing here, and that is the point: an [MPButton](./button)
|
|
29
|
+
* with an icon and no children already goes square and is already a pill, which
|
|
30
|
+
* for a square is a circle — MD3's icon button shape falls out of the button's
|
|
31
|
+
* own `corner-full` with no second table to keep in step. What this component
|
|
32
|
+
* adds is the *name*, which is the part that cannot be defaulted and is the part
|
|
33
|
+
* that is always missing.
|
|
34
|
+
*
|
|
35
|
+
* Everything else is the button's, unchanged and on purpose: the five variants,
|
|
36
|
+
* the four families, the size ladder, the state layer, `loading`, and the values
|
|
37
|
+
* a surrounding `MPButtonGroup` sets. Two components drawing the same surface
|
|
38
|
+
* from two copies of one table are two components that will eventually disagree
|
|
39
|
+
* about it.
|
|
40
|
+
*
|
|
41
|
+
* ## Why the default variant is `text` and the button's is `filled`
|
|
42
|
+
*
|
|
43
|
+
* Because MD3's default icon button is its *standard* one — a glyph with no
|
|
44
|
+
* container at all — and the specification is right about why. A labelled button
|
|
45
|
+
* is usually the one thing on a row worth pressing; an icon button is usually
|
|
46
|
+
* one of several sitting in a toolbar or a card's corner, and five filled discs
|
|
47
|
+
* in a row is a row with no emphasis left in it. Reach for `filled` when the
|
|
48
|
+
* icon button *is* the action on the screen.
|
|
49
|
+
*
|
|
50
|
+
* ## No toggle state
|
|
51
|
+
*
|
|
52
|
+
* MD3 also describes a *toggle* icon button, which swaps its container and its
|
|
53
|
+
* ink when selected. This is not that, and a `selected` prop would make it half
|
|
54
|
+
* of one: a toggle needs a pressed state that survives the press, a group that
|
|
55
|
+
* can enforce one choice, and a name that changes with the state. That is
|
|
56
|
+
* [MPSegmentedButton](./segmented-button) for a set, and a `<MPIconButton>` whose
|
|
57
|
+
* `icon` and `label` are both derived from your own state for a single one.
|
|
58
|
+
*/
|
|
59
|
+
export declare const MPIconButton: React.ForwardRefExoticComponent<MPIconButtonProps & React.RefAttributes<HTMLButtonElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as t}from"react/jsx-runtime";import*as r from"react";import{MPButton as o}from"../button/MPButton";export const MPIconButton=r.forwardRef(function({icon:r,label:a,variant:n="text",...e},i){return t(o,{ref:i,"aria-label":a,variant:n,startIcon:r,...e})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{MPIconButton}from"./MPIconButton";
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useRender } from '@base-ui/react/use-render';
|
|
3
|
+
import type { MPColor, MPSize, MPVariant } from '../../types';
|
|
4
|
+
export interface MPListProps extends Omit<React.ComponentPropsWithoutRef<'ul'>, 'color'> {
|
|
5
|
+
/**
|
|
6
|
+
* How much surface the sheet paints behind the rows.
|
|
7
|
+
* @default 'outlined'
|
|
8
|
+
*/
|
|
9
|
+
variant?: MPVariant;
|
|
10
|
+
/**
|
|
11
|
+
* The row height and type scale. Each rung lands a one-line row on exactly the
|
|
12
|
+
* control height of the same name — see `PAD_Y`.
|
|
13
|
+
* @default 'md'
|
|
14
|
+
*/
|
|
15
|
+
size?: MPSize;
|
|
16
|
+
/**
|
|
17
|
+
* Which accent family a selected or hovered row reads. The sheet itself stays
|
|
18
|
+
* neutral whatever this is.
|
|
19
|
+
* @default 'primary'
|
|
20
|
+
*/
|
|
21
|
+
color?: MPColor;
|
|
22
|
+
/**
|
|
23
|
+
* Separates the rows with a hairline instead of with space.
|
|
24
|
+
*
|
|
25
|
+
* It changes more than it sounds like: with dividers the rules have to reach
|
|
26
|
+
* both edges of the sheet, so the list gives up its inner padding and the rows
|
|
27
|
+
* give up their rounded corners. A row cannot be a floating tile and a ruled
|
|
28
|
+
* line at the same time.
|
|
29
|
+
* @default false
|
|
30
|
+
*/
|
|
31
|
+
dividers?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Renders something other than a `<ul>` — `render={<ol />}` for a list where
|
|
34
|
+
* the order is the point. Base UI's own escape hatch.
|
|
35
|
+
*/
|
|
36
|
+
render?: useRender.RenderProp;
|
|
37
|
+
children?: React.ReactNode;
|
|
38
|
+
}
|
|
39
|
+
export interface MPListItemProps extends Omit<React.ComponentPropsWithoutRef<'li'>, 'color' | 'onClick'> {
|
|
40
|
+
/**
|
|
41
|
+
* Passing it is what turns the row into a real `<button>`. It lands on that
|
|
42
|
+
* button rather than on the `<li>`, which is why the type is loosened from the
|
|
43
|
+
* list item the shell actually is.
|
|
44
|
+
*/
|
|
45
|
+
onClick?: React.MouseEventHandler<HTMLElement>;
|
|
46
|
+
/** Content before the label — an icon, an avatar, a status dot. */
|
|
47
|
+
startIcon?: React.ReactNode;
|
|
48
|
+
/** Content after the label, inside the pressable area. */
|
|
49
|
+
endIcon?: React.ReactNode;
|
|
50
|
+
/**
|
|
51
|
+
* A second line under the label. MD3 calls this the supporting text, and it is
|
|
52
|
+
* one step down the type scale in `on-surface-variant`.
|
|
53
|
+
*/
|
|
54
|
+
description?: React.ReactNode;
|
|
55
|
+
/**
|
|
56
|
+
* A control pinned to the end of the row — a switch, a menu button.
|
|
57
|
+
*
|
|
58
|
+
* Deliberately outside the pressable area: a row that both navigates and holds
|
|
59
|
+
* a toggle has two things to press, and nesting one button inside another is
|
|
60
|
+
* markup the browser rewrites on parse.
|
|
61
|
+
*/
|
|
62
|
+
action?: React.ReactNode;
|
|
63
|
+
/** Renders the row as a link. Mutually exclusive with `onClick` in practice. */
|
|
64
|
+
href?: string;
|
|
65
|
+
/** Marks the row as the chosen one — the open page, the current filter. */
|
|
66
|
+
selected?: boolean;
|
|
67
|
+
/** Unavailable. Drops the accent family, as everywhere else in the library. */
|
|
68
|
+
disabled?: boolean;
|
|
69
|
+
/** The label. */
|
|
70
|
+
children?: React.ReactNode;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* A stack of rows.
|
|
74
|
+
*
|
|
75
|
+
* The list is a sheet and the rows are what is on it, which is the whole reason
|
|
76
|
+
* the two are separate components: `size` and `color` are properties of the
|
|
77
|
+
* stack, not of any one line in it, and a context is what carries them down.
|
|
78
|
+
*
|
|
79
|
+
* There is no Base UI primitive under this on purpose. A list is not a composite
|
|
80
|
+
* widget — it has no roving focus, no selection model, no keyboard contract of
|
|
81
|
+
* its own. Reaching for a menu or a listbox primitive to get one would hand
|
|
82
|
+
* every consumer's plain list of links the semantics of a menu, which is the
|
|
83
|
+
* most common way a component library breaks a screen reader.
|
|
84
|
+
*/
|
|
85
|
+
export declare const MPList: React.ForwardRefExoticComponent<MPListProps & React.RefAttributes<HTMLUListElement>>;
|
|
86
|
+
/**
|
|
87
|
+
* One row.
|
|
88
|
+
*
|
|
89
|
+
* The shell is always an `<li>`. What changes is what is inside it: a plain run
|
|
90
|
+
* of content, or — when `onClick` or `href` is given — a real `<button>` or
|
|
91
|
+
* `<a>` wrapping that content, with `action` sitting outside it as a separate
|
|
92
|
+
* control. This is the same shape `MPChip` uses, for the same two reasons: a
|
|
93
|
+
* `<span>` carrying a click handler is invisible to a keyboard, and a `<button>`
|
|
94
|
+
* inside a `<button>` is markup Chrome silently un-nests.
|
|
95
|
+
*/
|
|
96
|
+
export declare const MPListItem: React.ForwardRefExoticComponent<MPListItemProps & React.RefAttributes<HTMLLIElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as r,Fragment as n}from"react/jsx-runtime";import*as t from"react";import{useRender as i}from"@base-ui/react/use-render";import{accentSlots as o}from"../../internal/accent";import{CONTROL_GAP as l,hasContent as a,PROSE_TEXT as s,SHEET_PAD_X as c}from"../../internal/scale";import{MPStateLayer as d}from"../../internal/StateLayer";import{CONTAINER_SURFACE as m}from"../../internal/surface";const p=t.createContext({size:"md",color:"primary",dividers:!1}),u={xs:"py-1.5",sm:"py-2.5",md:"py-4",lg:"py-5",xl:"py-6"},f={xs:"text-mp-body-small",sm:"text-mp-body-small",md:"text-mp-body-medium",lg:"text-mp-body-medium",xl:"text-mp-body-medium"},x={xs:"rounded-mp-xs",sm:"rounded-mp-xs",md:"rounded-mp-sm",lg:"rounded-mp-sm",xl:"rounded-mp-md"};export const MPList=t.forwardRef(function({variant:r="outlined",size:n="md",color:l="primary",dividers:a=!1,render:s,className:c,style:d,children:u,...f},x){const h=t.useMemo(()=>({size:n,color:l,dividers:a}),[n,l,a]),v=["mp-list rounded-mp-md flex flex-col",m[r],"text-mp-on-surface",a?"overflow-hidden [&>li+li]:border-mp-outline-variant [&>li+li]:border-t":"p-1",c??""].filter(Boolean).join(" "),b=i({render:s??e("ul",{}),ref:x,props:{role:"list","data-mp-size":n,"data-mp-variant":r,className:v,style:{...o(l),...d},children:u,...f}});return e(p.Provider,{value:h,children:b})});export const MPListItem=t.forwardRef(function({startIcon:i,endIcon:o,description:m,action:h,href:v,selected:b=!1,disabled:y=!1,className:N,children:g,onClick:j,...k},w){const{size:z,dividers:C}=t.useContext(p),B=Boolean(j||v)&&!y,I=c[z],L=["group relative flex min-w-0 flex-1 items-center overflow-hidden text-start","font-[inherit] no-underline",I,u[z],l[z],s[z],"transition-[background-color,color] duration-(--mp-sys-motion-duration-short4)",C?"":x[z],y?"text-mp-on-surface/38 cursor-default":b?"bg-(--_mp-accent-container) text-(--_mp-on-accent-container)":"",B?["cursor-pointer 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(" "):"",B&&b?"bg-(--_mp-accent-container)":""].filter(Boolean).join(" "),M=r(n,{children:[B?e(d,{}):null,a(i)?e("span",{className:"flex h-[1lh] shrink-0 items-center",children:i}):null,r("span",{className:"flex min-w-0 flex-1 flex-col",children:[a(g)?e("span",{className:"truncate",children:g}):null,a(m)?e("span",{className:["truncate",f[z],b?"opacity-80":"text-mp-on-surface-variant"].join(" "),children:m}):null]}),a(o)?e("span",{className:"flex h-[1lh] shrink-0 items-center",children:o}):null]});return r("li",{ref:w,"data-selected":b||void 0,className:["flex w-full items-center",N??""].filter(Boolean).join(" "),...k,children:[B&&v?e("a",{href:v,className:L,"aria-current":b?"page":void 0,onClick:j,children:M}):B?e("button",{type:"button",className:L,"aria-current":!!b||void 0,onClick:j,children:M}):e("div",{className:L,"aria-disabled":y||void 0,children:M}),a(h)?e("div",{className:`flex shrink-0 items-center ${I}`,children:h}):null]})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{MPList,MPListItem}from"./MPList";
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useMPLocale } from '../../internal/locale';
|
|
3
|
+
export interface MPLocaleProviderProps {
|
|
4
|
+
/**
|
|
5
|
+
* A BCP 47 tag — `ko`, `ja`, `pt-BR`, `zh-Hant`.
|
|
6
|
+
*
|
|
7
|
+
* It reaches two different systems and they degrade differently, which is
|
|
8
|
+
* worth knowing before choosing one:
|
|
9
|
+
*
|
|
10
|
+
* - **`Intl` formats the dates and the numbers**, and speaks every language
|
|
11
|
+
* the platform does. A tag with no entry in this library's own table still
|
|
12
|
+
* gets month names, weekday names, AM/PM and the right date order.
|
|
13
|
+
* - **This library's table supplies the words `Intl` has no opinion about** —
|
|
14
|
+
* "Previous month", "Today", "Hour". Those fall back to English for a tag it
|
|
15
|
+
* does not carry, and a `labels` prop on the component fills the gap.
|
|
16
|
+
*
|
|
17
|
+
* Left `undefined` the platform's own default is used for the first and
|
|
18
|
+
* English for the second, which is exactly what a component with no provider
|
|
19
|
+
* over it does.
|
|
20
|
+
*/
|
|
21
|
+
locale?: string;
|
|
22
|
+
children?: React.ReactNode;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The language the components speak, set once for everything under it.
|
|
26
|
+
*
|
|
27
|
+
* Wrap the application. Every component in this library that writes a word or
|
|
28
|
+
* formats a date takes a `locale` prop of its own, and this is where that prop
|
|
29
|
+
* gets its default — so a form of four pickers is one decision rather than four.
|
|
30
|
+
*
|
|
31
|
+
* ```tsx
|
|
32
|
+
* <MPLocaleProvider locale="ko">
|
|
33
|
+
* <App />
|
|
34
|
+
* </MPLocaleProvider>
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* ## Why it is not a whole theme object
|
|
38
|
+
*
|
|
39
|
+
* Everything else a provider might carry here is already a CSS custom property:
|
|
40
|
+
* the colour roles, the type scale, the corners, the motion durations. Those
|
|
41
|
+
* reach a component through the cascade, which means a section of a page can
|
|
42
|
+
* differ from the rest of it without a second provider and without a re-render.
|
|
43
|
+
* A locale cannot travel that way — it decides which *string* is rendered, not
|
|
44
|
+
* how one is painted — so it is the one thing left that needs context, and this
|
|
45
|
+
* provider carries that and nothing else.
|
|
46
|
+
*
|
|
47
|
+
* ## Nesting
|
|
48
|
+
*
|
|
49
|
+
* Providers nest, and the nearest one wins. A page in Korean with one section
|
|
50
|
+
* showing a Japanese listing's dates is two providers, and the inner one does
|
|
51
|
+
* not have to restate anything: there is only the one value.
|
|
52
|
+
*/
|
|
53
|
+
export declare function MPLocaleProvider({ locale, children }: MPLocaleProviderProps): React.JSX.Element;
|
|
54
|
+
/**
|
|
55
|
+
* The locale in force at this point in the tree.
|
|
56
|
+
*
|
|
57
|
+
* Exported because an application that has told this library its language should
|
|
58
|
+
* not have to tell itself the same thing twice — the same tag is what its own
|
|
59
|
+
* `Intl.NumberFormat` calls want. Passing an argument makes it the
|
|
60
|
+
* prop-beats-provider resolution the components themselves use, which is what a
|
|
61
|
+
* wrapper component around one of them wants.
|
|
62
|
+
*/
|
|
63
|
+
export { useMPLocale };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as r}from"react/jsx-runtime";import{MPLocaleContext as e,useMPLocale as o}from"../../internal/locale";export function MPLocaleProvider({locale:o,children:i}){return r(e.Provider,{value:o,children:i})}export{o as useMPLocale};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{MPLocaleProvider,useMPLocale}from"./MPLocaleProvider";
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { MPAlign, MPColor, MPSide, MPSize } from '../../types';
|
|
3
|
+
/**
|
|
4
|
+
* A menu takes `size` and `color` and stops there.
|
|
5
|
+
*
|
|
6
|
+
* There is no `variant`, for the reason `MPDialog` has none: the five weights
|
|
7
|
+
* answer "how much of a surface does this paint", and a popup that has taken the
|
|
8
|
+
* pointer has already answered it. There is no `elevation` either — MD3 puts a
|
|
9
|
+
* menu at level 2 and nowhere else, and a menu that could be told to sit flat
|
|
10
|
+
* would be a list.
|
|
11
|
+
*/
|
|
12
|
+
interface MPMenuSurfaceProps {
|
|
13
|
+
/**
|
|
14
|
+
* The row height and type scale.
|
|
15
|
+
* @default 'md'
|
|
16
|
+
*/
|
|
17
|
+
size?: MPSize;
|
|
18
|
+
/**
|
|
19
|
+
* Which accent family a ticked or chosen row reads. The popup itself stays
|
|
20
|
+
* neutral, as MD3's does.
|
|
21
|
+
* @default 'primary'
|
|
22
|
+
*/
|
|
23
|
+
color?: MPColor;
|
|
24
|
+
className?: string;
|
|
25
|
+
style?: React.CSSProperties;
|
|
26
|
+
}
|
|
27
|
+
export interface MPMenuProps extends MPMenuSurfaceProps {
|
|
28
|
+
/**
|
|
29
|
+
* The element that opens the menu, wired up by Base UI. Optional — a controlled
|
|
30
|
+
* menu opened from elsewhere needs no trigger of its own.
|
|
31
|
+
*/
|
|
32
|
+
trigger?: React.ReactElement;
|
|
33
|
+
/** Whether the menu is open. Use with `onOpenChange` for a controlled menu. */
|
|
34
|
+
open?: boolean;
|
|
35
|
+
/** Whether it starts open, for an uncontrolled one. */
|
|
36
|
+
defaultOpen?: boolean;
|
|
37
|
+
onOpenChange?: (open: boolean) => void;
|
|
38
|
+
/** Which edge of the trigger it hangs off. @default 'bottom' */
|
|
39
|
+
side?: MPSide;
|
|
40
|
+
/** Where it sits along that edge. @default 'start' */
|
|
41
|
+
align?: MPAlign;
|
|
42
|
+
/** Distance from the trigger, in pixels. @default 4 */
|
|
43
|
+
sideOffset?: number;
|
|
44
|
+
/** Whether the page behind is taken away while the menu is open. @default true */
|
|
45
|
+
modal?: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Opens on hover as well as on click. For a menu bar, where crossing the row
|
|
48
|
+
* with one menu open should walk through the others rather than close them.
|
|
49
|
+
* @default false
|
|
50
|
+
*/
|
|
51
|
+
openOnHover?: boolean;
|
|
52
|
+
/** Whether the arrow keys wrap from the last row back to the first. @default true */
|
|
53
|
+
loopFocus?: boolean;
|
|
54
|
+
/** Unavailable. The trigger stops opening anything. */
|
|
55
|
+
disabled?: boolean;
|
|
56
|
+
/** The rows. */
|
|
57
|
+
children?: React.ReactNode;
|
|
58
|
+
}
|
|
59
|
+
export interface MPContextMenuProps extends MPMenuSurfaceProps {
|
|
60
|
+
/** The rows, exactly as they are written inside an `MPMenu`. */
|
|
61
|
+
content: React.ReactNode;
|
|
62
|
+
/**
|
|
63
|
+
* The area that answers a right-click or a long press. Rendered inside a
|
|
64
|
+
* `<div>` of Base UI's, which is what listens for the gesture.
|
|
65
|
+
*/
|
|
66
|
+
children: React.ReactNode;
|
|
67
|
+
open?: boolean;
|
|
68
|
+
defaultOpen?: boolean;
|
|
69
|
+
onOpenChange?: (open: boolean) => void;
|
|
70
|
+
/** @default true */
|
|
71
|
+
loopFocus?: boolean;
|
|
72
|
+
disabled?: boolean;
|
|
73
|
+
}
|
|
74
|
+
export interface MPMenuItemProps {
|
|
75
|
+
/** What the row does. Not given, and not a link, the row is a label. */
|
|
76
|
+
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
|
|
77
|
+
/** Renders the row as a real `<a>`. A menu of links has to be links. */
|
|
78
|
+
href?: string;
|
|
79
|
+
/** Where the link opens — `_blank` and the rest. Ignored without `href`. */
|
|
80
|
+
target?: string;
|
|
81
|
+
/** Content before the label — an icon, a swatch, an avatar. */
|
|
82
|
+
startIcon?: React.ReactNode;
|
|
83
|
+
/** Content after the label, before any `shortcut`. */
|
|
84
|
+
endIcon?: React.ReactNode;
|
|
85
|
+
/**
|
|
86
|
+
* The keystroke that does the same thing, set at the end of the row and muted.
|
|
87
|
+
* Text only — the row does not bind it, the application does.
|
|
88
|
+
*/
|
|
89
|
+
shortcut?: React.ReactNode;
|
|
90
|
+
/** A second line under the label, one step down the type scale and muted. */
|
|
91
|
+
description?: React.ReactNode;
|
|
92
|
+
/**
|
|
93
|
+
* Re-points the row's family — `error` for the one that deletes. Defaults to
|
|
94
|
+
* the menu's own.
|
|
95
|
+
*/
|
|
96
|
+
color?: MPColor;
|
|
97
|
+
/** Whether picking the row closes the menu. @default true */
|
|
98
|
+
closeOnClick?: boolean;
|
|
99
|
+
/** Unavailable. Still listed, and still found by typeahead. */
|
|
100
|
+
disabled?: boolean;
|
|
101
|
+
/** What typeahead matches against, when the label is not a plain string. */
|
|
102
|
+
label?: string;
|
|
103
|
+
/** The label. */
|
|
104
|
+
children?: React.ReactNode;
|
|
105
|
+
className?: string;
|
|
106
|
+
style?: React.CSSProperties;
|
|
107
|
+
}
|
|
108
|
+
export interface MPMenuSubmenuProps {
|
|
109
|
+
/** The label on the row that opens it. */
|
|
110
|
+
label?: React.ReactNode;
|
|
111
|
+
startIcon?: React.ReactNode;
|
|
112
|
+
disabled?: boolean;
|
|
113
|
+
/** Which edge of the parent row it opens against. @default 'right' */
|
|
114
|
+
side?: MPSide;
|
|
115
|
+
/** Distance from the parent menu, in pixels. @default 0 */
|
|
116
|
+
sideOffset?: number;
|
|
117
|
+
/** The nested rows. */
|
|
118
|
+
children?: React.ReactNode;
|
|
119
|
+
className?: string;
|
|
120
|
+
style?: React.CSSProperties;
|
|
121
|
+
}
|
|
122
|
+
export interface MPMenuGroupProps {
|
|
123
|
+
/** The heading over the group. Wired to it by Base UI. */
|
|
124
|
+
label?: React.ReactNode;
|
|
125
|
+
children?: React.ReactNode;
|
|
126
|
+
className?: string;
|
|
127
|
+
}
|
|
128
|
+
export interface MPMenuCheckboxItemProps extends Omit<MPMenuItemProps, 'href' | 'target' | 'startIcon' | 'onClick'> {
|
|
129
|
+
checked?: boolean;
|
|
130
|
+
defaultChecked?: boolean;
|
|
131
|
+
onCheckedChange?: (checked: boolean) => void;
|
|
132
|
+
/**
|
|
133
|
+
* Whether ticking the row closes the menu. `false` here rather than the `true`
|
|
134
|
+
* a plain row takes: a list of things to tick is a list you tick more than one
|
|
135
|
+
* of.
|
|
136
|
+
* @default false
|
|
137
|
+
*/
|
|
138
|
+
closeOnClick?: boolean;
|
|
139
|
+
}
|
|
140
|
+
export interface MPMenuRadioGroupProps {
|
|
141
|
+
value?: string | number;
|
|
142
|
+
defaultValue?: string | number;
|
|
143
|
+
onValueChange?: (value: string | number) => void;
|
|
144
|
+
disabled?: boolean;
|
|
145
|
+
children?: React.ReactNode;
|
|
146
|
+
className?: string;
|
|
147
|
+
}
|
|
148
|
+
export interface MPMenuRadioItemProps extends Omit<MPMenuItemProps, 'href' | 'target' | 'startIcon' | 'onClick'> {
|
|
149
|
+
/** What this row sets the group to. */
|
|
150
|
+
value: string | number;
|
|
151
|
+
/** @default false */
|
|
152
|
+
closeOnClick?: boolean;
|
|
153
|
+
}
|
|
154
|
+
export type MPMenuSeparatorProps = React.ComponentPropsWithoutRef<'div'>;
|
|
155
|
+
/**
|
|
156
|
+
* One row of a menu.
|
|
157
|
+
*
|
|
158
|
+
* Renders a real `<a>` when it is given an `href` and Base UI's own item
|
|
159
|
+
* otherwise. A menu of links that are not links cannot be opened in a new tab,
|
|
160
|
+
* cannot be copied, and tells a screen reader the wrong thing about every one of
|
|
161
|
+
* them.
|
|
162
|
+
*/
|
|
163
|
+
export declare function MPMenuItem({ onClick, href, target, startIcon, endIcon, shortcut, description, color, closeOnClick, disabled, label, children, className, style }: MPMenuItemProps): React.JSX.Element;
|
|
164
|
+
/** A row that ticks. The tick lands in the column a `startIcon` would. */
|
|
165
|
+
export declare function MPMenuCheckboxItem({ checked, defaultChecked, onCheckedChange, endIcon, shortcut, description, color, closeOnClick, disabled, label, children, className, style }: MPMenuCheckboxItemProps): React.JSX.Element;
|
|
166
|
+
/** One choice out of a set. Wraps the rows that make up the set. */
|
|
167
|
+
export declare function MPMenuRadioGroup({ value, defaultValue, onValueChange, disabled, children, className }: MPMenuRadioGroupProps): React.JSX.Element;
|
|
168
|
+
/**
|
|
169
|
+
* A row inside an `MPMenuRadioGroup`.
|
|
170
|
+
*
|
|
171
|
+
* Marked with a filled dot rather than a tick, which is the same distinction
|
|
172
|
+
* `MPCheckbox` and `MPRadio` make everywhere else: a tick says "and", a dot says
|
|
173
|
+
* "instead of".
|
|
174
|
+
*/
|
|
175
|
+
export declare function MPMenuRadioItem({ value, endIcon, shortcut, description, color, closeOnClick, disabled, label, children, className, style }: MPMenuRadioItemProps): React.JSX.Element;
|
|
176
|
+
/** A named run of rows. The label is a heading, not a row — it cannot be picked. */
|
|
177
|
+
export declare function MPMenuGroup({ label, children, className }: MPMenuGroupProps): React.JSX.Element;
|
|
178
|
+
/** The hairline between two runs of rows. `outline-variant`, as MD3 draws it. */
|
|
179
|
+
export declare function MPMenuSeparator({ className, ...props }: MPMenuSeparatorProps): React.JSX.Element;
|
|
180
|
+
/**
|
|
181
|
+
* A menu inside a menu.
|
|
182
|
+
*
|
|
183
|
+
* The row that opens it is the same row every other item is, wearing a chevron —
|
|
184
|
+
* and it opens on hover, on Enter and on the arrow key that points at it, all of
|
|
185
|
+
* which is Base UI's. What is here is the surface and the glyph.
|
|
186
|
+
*
|
|
187
|
+
* Nesting is unlimited: a submenu renders its children inside a popup that is
|
|
188
|
+
* itself a menu, so a submenu of a submenu needs no different component.
|
|
189
|
+
*/
|
|
190
|
+
export declare function MPMenuSubmenu({ label, startIcon, disabled, side, sideOffset, children, className, style }: MPMenuSubmenuProps): React.JSX.Element;
|
|
191
|
+
/**
|
|
192
|
+
* A list of actions that appears when something is pressed.
|
|
193
|
+
*
|
|
194
|
+
* Everything that makes a menu a menu rather than a floating list of divs is Base
|
|
195
|
+
* UI's: roving focus with the arrow keys, Home and End, typeahead, Escape,
|
|
196
|
+
* closing on an outside click, restoring focus to the trigger, submenus opening
|
|
197
|
+
* on hover with the safe triangle so a diagonal reach does not close them, and
|
|
198
|
+
* the `menu` / `menuitem` roles that make any of it mean something to a screen
|
|
199
|
+
* reader. What is here is the surface, the ladders and the row layout.
|
|
200
|
+
*
|
|
201
|
+
* ## Why the rows are composed and a select's options are data
|
|
202
|
+
*
|
|
203
|
+
* The opposite of `MPSelect`, and deliberately. A select's options are values out
|
|
204
|
+
* of a list a caller already has, and its trigger has to be able to name the
|
|
205
|
+
* chosen one before the popup has ever been mounted. A menu's rows are *code* —
|
|
206
|
+
* each one a different handler, a different icon, sometimes a submenu — and
|
|
207
|
+
* nothing has to know about them until the menu opens. Data would mean an `items`
|
|
208
|
+
* type with a variant for every shape a row can take, which is a component tree
|
|
209
|
+
* spelled as a discriminated union.
|
|
210
|
+
*/
|
|
211
|
+
export declare function MPMenu({ size, color, trigger, open, defaultOpen, onOpenChange, side, align, sideOffset, modal, openOnHover, loopFocus, disabled, className, style, children }: MPMenuProps): React.JSX.Element;
|
|
212
|
+
/**
|
|
213
|
+
* The same menu, opened by a right-click or a long press instead of by a button.
|
|
214
|
+
*
|
|
215
|
+
* It takes the rows as `content` and the area as `children`, which is
|
|
216
|
+
* `MPTooltip`'s shape rather than `MPMenu`'s — because here the trigger is not
|
|
217
|
+
* one element handed over, it is a region of the page, and the region is the
|
|
218
|
+
* thing being wrapped. Base UI positions the popup at the pointer rather than
|
|
219
|
+
* against an anchor, and the long press is what makes it reachable on a touch
|
|
220
|
+
* screen at all.
|
|
221
|
+
*/
|
|
222
|
+
export declare function MPContextMenu({ size, color, content, children, open, defaultOpen, onOpenChange, loopFocus, disabled, className, style }: MPContextMenuProps): React.JSX.Element;
|
|
223
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as n}from"react/jsx-runtime";import*as t from"react";import{Menu as a}from"@base-ui/react/menu";import{ContextMenu as l}from"@base-ui/react/context-menu";import{MPIcon as r}from"../icon/MPIcon";import{CheckIcon as o,ChevronRightIcon as s}from"../../constants/icons";import{MPMenuContext as i}from"../../internal/menu";import{accentSlots as c}from"../../internal/accent";import{MPStateLayer as d}from"../../internal/StateLayer";import{CONTROL_ICON as m,META_TEXT as u,hasContent as p}from"../../internal/scale";import{FADE as h,PORTAL_LAYER as f}from"../../internal/surface";const x=["mp-menu__popup rounded-mp-xs shadow-mp-2 bg-mp-surface-container text-mp-on-surface","max-h-[min(24rem,var(--available-height))] min-w-[112px] max-w-[280px]","overflow-y-auto overscroll-contain py-2 outline-none",h].join(" "),b={xs:"min-h-8",sm:"min-h-10",md:"min-h-12",lg:"min-h-14",xl:"min-h-16"},g={xs:"px-2",sm:"px-2.5",md:"px-3",lg:"px-4",xl:"px-5"},N={xs:"gap-2",sm:"gap-2.5",md:"gap-3",lg:"gap-3",xl:"gap-4"},v={xs:"text-mp-label-medium",sm:"text-mp-label-large",md:"text-mp-label-large",lg:"text-mp-title-medium",xl:"text-mp-title-medium"};function C(e,n,t){return["group relative flex w-full cursor-pointer items-center select-none",n?"text-(--_mp-accent)":"text-mp-on-surface",b[e],g[e],N[e],v[e],"data-disabled:text-mp-on-surface/38 data-disabled:cursor-default","outline-none",t??""].filter(Boolean).join(" ")}function y(){return e(d,{layer:"inset-0 bg-current",className:"group-data-highlighted:opacity-8 group-data-popup-open:opacity-8 group-data-disabled:opacity-0"})}const k="relative flex shrink-0 items-center justify-center";function M({children:t,description:a}){return p(a)?n("span",{className:"relative flex min-w-0 flex-1 flex-col py-1.5 text-start",children:[e("span",{className:"truncate",children:t}),e("span",{className:`text-mp-on-surface-variant truncate ${u}`,children:a})]}):e("span",{className:"relative min-w-0 flex-1 truncate text-start",children:t})}function O({shortcut:n}){return p(n)?e("span",{className:`text-mp-on-surface-variant relative ms-2 shrink-0 ${u}`,children:n}):null}export function MPMenuItem({onClick:l,href:r,target:o,startIcon:s,endIcon:c,shortcut:d,description:m,color:u,closeOnClick:h=!0,disabled:f=!1,label:x,children:b,className:g,style:N}){const{size:v}=t.useContext(i),P=n(t.Fragment,{children:[e(y,{}),p(s)?e("span",{className:`${k} text-mp-on-surface-variant`,children:s}):null,e(M,{description:m,children:b}),p(c)?e("span",{className:`${k} text-mp-on-surface-variant`,children:c}):null,e(O,{shortcut:d})]}),I=u?{"--_mp-accent":`var(--_mp-color-${u})`}:void 0,$=I||N?{...I,...N}:void 0;return void 0!==r?e(a.LinkItem,{href:r,target:o,label:x,closeOnClick:h,onClick:l,className:C(v,Boolean(u),g),style:$,children:P}):e(a.Item,{disabled:f,label:x,closeOnClick:h,onClick:l,className:C(v,Boolean(u),g),style:$,children:P})}export function MPMenuCheckboxItem({checked:l,defaultChecked:s,onCheckedChange:c,endIcon:d,shortcut:u,description:h,color:f,closeOnClick:x=!1,disabled:b=!1,label:g,children:N,className:v,style:P}){const{size:I}=t.useContext(i),$=f?{"--_mp-accent":`var(--_mp-color-${f})`}:void 0;return n(a.CheckboxItem,{checked:l,defaultChecked:s,onCheckedChange:e=>c?.(e),disabled:b,label:g,closeOnClick:x,className:C(I,Boolean(f),v),style:$||P?{...$,...P}:void 0,children:[e(y,{}),e("span",{className:`${k} text-(--_mp-accent)`,style:{width:m[I]},children:e(a.CheckboxItemIndicator,{className:"flex items-center justify-center",children:e(r,{icon:o,size:m[I]})})}),e(M,{description:h,children:N}),p(d)?e("span",{className:`${k} text-mp-on-surface-variant`,children:d}):null,e(O,{shortcut:u})]})}export function MPMenuRadioGroup({value:n,defaultValue:t,onValueChange:l,disabled:r=!1,children:o,className:s}){return e(a.RadioGroup,{value:n,defaultValue:t,onValueChange:e=>l?.(e),disabled:r,className:s,children:o})}export function MPMenuRadioItem({value:l,endIcon:r,shortcut:o,description:s,color:c,closeOnClick:d=!1,disabled:u=!1,label:h,children:f,className:x,style:b}){const{size:g}=t.useContext(i),N=c?{"--_mp-accent":`var(--_mp-color-${c})`}:void 0;return n(a.RadioItem,{value:l,disabled:u,label:h,closeOnClick:d,className:C(g,Boolean(c),x),style:N||b?{...N,...b}:void 0,children:[e(y,{}),e("span",{className:`${k} text-(--_mp-accent)`,style:{width:m[g]},children:e(a.RadioItemIndicator,{className:"flex items-center justify-center",children:e("span",{className:"block size-2.5 rounded-full bg-current"})})}),e(M,{description:s,children:f}),p(r)?e("span",{className:`${k} text-mp-on-surface-variant`,children:r}):null,e(O,{shortcut:o})]})}export function MPMenuGroup({label:l,children:r,className:o}){const{size:s}=t.useContext(i);return n(a.Group,{className:o,children:[p(l)?e(a.GroupLabel,{className:`text-mp-on-surface-variant pt-2 pb-1 ${g[s]} ${u}`,children:l}):null,r]})}export function MPMenuSeparator({className:n,...t}){return e(a.Separator,{className:["bg-mp-outline-variant my-2 h-px",n??""].filter(Boolean).join(" "),...t})}export function MPMenuSubmenu({label:l,startIcon:o,disabled:d=!1,side:u="right",sideOffset:h=0,children:b,className:g,style:N}){const{size:v,color:M}=t.useContext(i);return n(a.SubmenuRoot,{children:[n(a.SubmenuTrigger,{disabled:d,className:C(v,!1),children:[e(y,{}),p(o)?e("span",{className:`${k} text-mp-on-surface-variant`,children:o}):null,e("span",{className:"relative min-w-0 flex-1 truncate text-start",children:l}),e("span",{className:`${k} text-mp-on-surface-variant rtl:rotate-180`,children:e(r,{icon:s,size:m[v]})})]}),e(a.Portal,{children:e(a.Positioner,{className:f,side:u,sideOffset:h,align:"start",children:e(a.Popup,{className:[x,g??""].filter(Boolean).join(" "),style:{...c(M),...N},children:b})})})]})}export function MPMenu({size:l="md",color:r="primary",trigger:o,open:s,defaultOpen:d,onOpenChange:m,side:u="bottom",align:p="start",sideOffset:h=4,modal:b=!0,openOnHover:g=!1,loopFocus:N=!0,disabled:v=!1,className:C,style:y,children:k}){const M=t.useMemo(()=>({size:l,color:r}),[l,r]);return e(i.Provider,{value:M,children:n(a.Root,{open:s,defaultOpen:d,onOpenChange:e=>m?.(e),modal:b,loopFocus:N,disabled:v,children:[o?e(a.Trigger,{render:o,openOnHover:g,disabled:v}):null,e(a.Portal,{children:e(a.Positioner,{className:f,side:u,align:p,sideOffset:h,children:e(a.Popup,{"data-mp-size":l,className:[x,C??""].filter(Boolean).join(" "),style:{...c(r),...y},children:k})})})]})})}export function MPContextMenu({size:a="md",color:r="primary",content:o,children:s,open:d,defaultOpen:m,onOpenChange:u,loopFocus:p=!0,disabled:h=!1,className:b,style:g}){const N=t.useMemo(()=>({size:a,color:r}),[a,r]);return e(i.Provider,{value:N,children:n(l.Root,{open:d,defaultOpen:m,onOpenChange:e=>u?.(e),loopFocus:p,disabled:h,children:[e(l.Trigger,{children:s}),e(l.Portal,{children:e(l.Positioner,{className:f,children:e(l.Popup,{"data-mp-size":a,className:[x,b??""].filter(Boolean).join(" "),style:{...c(r),...g},children:o})})})]})})}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { MPContextMenu, MPMenu, MPMenuCheckboxItem, MPMenuGroup, MPMenuItem, MPMenuRadioGroup, MPMenuRadioItem, MPMenuSeparator, MPMenuSubmenu } from './MPMenu';
|
|
2
|
+
export type { MPContextMenuProps, MPMenuCheckboxItemProps, MPMenuGroupProps, MPMenuItemProps, MPMenuProps, MPMenuRadioGroupProps, MPMenuRadioItemProps, MPMenuSeparatorProps, MPMenuSubmenuProps } from './MPMenu';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{MPContextMenu,MPMenu,MPMenuCheckboxItem,MPMenuGroup,MPMenuItem,MPMenuRadioGroup,MPMenuRadioItem,MPMenuSeparator,MPMenuSubmenu}from"./MPMenu";
|