bestax-mcp 1.18.6 → 1.18.7
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/data/bulma-classes.json +70 -3
- package/data/catalog.json +2 -2
- package/data/components/Autocomplete.json +3 -3
- package/data/components/Card.json +5 -5
- package/data/components/Carousel.json +2 -2
- package/data/components/Checkboxes.json +3 -3
- package/data/components/DateInput.json +9 -9
- package/data/components/DateTimeInput.json +8 -8
- package/data/components/File.json +3 -3
- package/data/components/Input.json +13 -13
- package/data/components/Message.json +4 -4
- package/data/components/Modal.json +30 -11
- package/data/components/Numberinput.json +3 -3
- package/data/components/Radio.json +5 -1
- package/data/components/Radios.json +3 -3
- package/data/components/Rate.json +3 -3
- package/data/components/Select.json +5 -5
- package/data/components/Skeleton.json +11 -11
- package/data/components/Slider.json +3 -3
- package/data/components/Taginput.json +3 -3
- package/data/components/TextArea.json +3 -3
- package/data/components/TimeInput.json +10 -10
- package/data/components/classNames.json +6 -6
- package/data/components/useBulmaClasses.json +14 -14
- package/data/skills/bestax-icons/references/icon-libraries.md +14 -1
- package/data/skills/bestax-migrate/SKILL.md +10 -4
- package/data/skills/bestax-migrate/references/bloomer/unmappables.md +4 -1
- package/data/skills/bestax-migrate/references/bulma-classes/component-map.md +49 -15
- package/data/skills/bestax-migrate/references/bulma-classes/unmappables.md +122 -26
- package/data/skills/bestax-theming/references/css-variables.md +6 -0
- package/data/skills.json +5 -5
- package/dist/bulma-classes.d.ts +45 -0
- package/dist/bulma-classes.d.ts.map +1 -1
- package/dist/bulma-classes.js +183 -28
- package/dist/helper-props.d.ts +6 -0
- package/dist/helper-props.d.ts.map +1 -1
- package/dist/helper-props.js +3 -2
- package/dist/search.d.ts +18 -1
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +119 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +44 -3
- package/dist/version.d.ts +15 -6
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +40 -3
- package/package.json +2 -2
package/data/bulma-classes.json
CHANGED
|
@@ -3197,7 +3197,7 @@
|
|
|
3197
3197
|
"textColor": null,
|
|
3198
3198
|
"bgColor": null,
|
|
3199
3199
|
"part": false,
|
|
3200
|
-
"why": "bestax `Checkbox` renders its own styled markup, not Bulma's",
|
|
3200
|
+
"why": "bestax `Checkbox` renders its own styled markup, not Bulma's. Write it by hand in place of the element that carries `.checkbox`, Bulma's `<label>` or a bare `<input>`, with the `<input>`'s attributes on it: `id`, `name`, `aria-label` and the rest reach its `<input>`, and a `<label>`'s text is its children. Drive it with `checked` and `onChange`, and add `indeterminate` for a select-all box. Its `className` goes on its `<label>`, which declares the `--bulma-checkbox-*` variables, so set the page's colors with those in a rule for your class beside `.styled-checkbox`. Where the page put `.checkbox` on a bare `<input>`, drop its own rules for that box, since bestax draws its own and `.checkbox` is on its `<label>` now",
|
|
3201
3201
|
"modifiers": {},
|
|
3202
3202
|
"omits": {},
|
|
3203
3203
|
"wrapsChildren": null,
|
|
@@ -3658,7 +3658,10 @@
|
|
|
3658
3658
|
"is-medium": { "writes": [{ "prop": "size", "value": "medium" }] },
|
|
3659
3659
|
"is-large": { "writes": [{ "prop": "size", "value": "large" }] }
|
|
3660
3660
|
},
|
|
3661
|
-
"omits": {
|
|
3661
|
+
"omits": {
|
|
3662
|
+
"is-left": "Bulma places it inside a `.control` with `has-icons-left`, and bestax `Control` renders that icon itself from `iconLeft` (`iconLeft={{ library: \"fa\", name: \"envelope\", size: \"small\" }}`), after its children, so a hidden `.icon` there can go as that prop; on `Icon` the class stays in `className`, which renders the same",
|
|
3663
|
+
"is-right": "Bulma places it inside a `.control` with `has-icons-right`, and bestax `Control` renders that icon itself from `iconRight` (`iconRight={{ library: \"fa\", name: \"envelope\", size: \"small\" }}`), after its children, so a hidden `.icon` there can go as that prop; on `Icon` the class stays in `className`, which renders the same"
|
|
3664
|
+
},
|
|
3662
3665
|
"wrapsChildren": null,
|
|
3663
3666
|
"folds": null,
|
|
3664
3667
|
"absorbs": null,
|
|
@@ -13062,5 +13065,69 @@
|
|
|
13062
13065
|
"theme-dark",
|
|
13063
13066
|
"theme-light",
|
|
13064
13067
|
"title"
|
|
13065
|
-
]
|
|
13068
|
+
],
|
|
13069
|
+
"elsewhere": [
|
|
13070
|
+
{
|
|
13071
|
+
"why": "a Font Awesome class: Font Awesome's own stylesheet styles it, not Bulma's, so keep loading Font Awesome (the bestax-migrate skill's `html-asset:font-awesome` says how). bestax `Icon` writes these classes from its props, on the <i> it renders inside a `.icon`",
|
|
13072
|
+
"match": "^(?:fa|fa[srbldt]|fa-[a-z0-9]+(?:-[a-z0-9]+)*|svg-inline--fa)$",
|
|
13073
|
+
"glyph": true
|
|
13074
|
+
},
|
|
13075
|
+
{
|
|
13076
|
+
"why": "a Material Design Icons class: its own stylesheet styles it, not Bulma's, so keep loading it. bestax `Icon` writes these classes from its props, with `library=\"mdi\"`, on the <i> it renders inside a `.icon`",
|
|
13077
|
+
"match": "^mdi(?:-[a-z0-9]+)*$",
|
|
13078
|
+
"glyph": true
|
|
13079
|
+
},
|
|
13080
|
+
{
|
|
13081
|
+
"why": "a bulma-social class, a Bulma extension's brand color for Bulma's `.button`, which bestax's `Button` renders: keep loading bulma-social and keep the class on `Button` in `className`, since bestax has no component for it (the bestax-migrate skill's `html-asset:bulma-extension` has the recipe)",
|
|
13082
|
+
"match": "^is-(?:apple|bitbucket|discord|dropbox|facebook|flickr|foursquare|github|gitlab|instagram|linkedin|microsoft|odnoklassniki|openid|pinterest|reddit|slack|soundcloud|tumblr|twitch|twitter|vimeo|vk|x|yahoo|youtube|animated)$",
|
|
13083
|
+
"glyph": false
|
|
13084
|
+
},
|
|
13085
|
+
{
|
|
13086
|
+
"why": "a bulma-carousel class, a Bulma extension bestax's `Carousel` does the job of (the bestax-migrate skill's `html-asset:bulma-extension` says how). Once the page stops loading bulma-carousel nothing styles it: `is-covered`'s `object-fit: cover` on a slide's image goes in the app's own CSS",
|
|
13087
|
+
"match": "^(?:has-carousel|hero-carousel|is-background|is-covered|slider-(?:container|item|navigation-next|navigation-previous|page|pagination)|video-container)$",
|
|
13088
|
+
"glyph": false
|
|
13089
|
+
}
|
|
13090
|
+
],
|
|
13091
|
+
"ownClasses": {
|
|
13092
|
+
"autocomplete": "Autocomplete",
|
|
13093
|
+
"avatar": "Avatar",
|
|
13094
|
+
"avatars": "Avatars",
|
|
13095
|
+
"badge": "Badge",
|
|
13096
|
+
"carousel": "Carousel",
|
|
13097
|
+
"styled-checkbox": "Checkbox",
|
|
13098
|
+
"collapse": "Collapse",
|
|
13099
|
+
"collapses": "Collapses",
|
|
13100
|
+
"combobox": "Combobox",
|
|
13101
|
+
"context-menu": "ContextMenu",
|
|
13102
|
+
"daterangeinput": "DateRangeInput",
|
|
13103
|
+
"dialog": "Dialog",
|
|
13104
|
+
"empty-state": "EmptyState",
|
|
13105
|
+
"hover-card": "HoverCard",
|
|
13106
|
+
"kbd": "Kbd",
|
|
13107
|
+
"link-button": "LinkButton",
|
|
13108
|
+
"loading": "Loading",
|
|
13109
|
+
"numberinput": "Numberinput",
|
|
13110
|
+
"pin-input": "PinInput",
|
|
13111
|
+
"popover": "Popover",
|
|
13112
|
+
"styled-radio": "Radio",
|
|
13113
|
+
"rate": "Rate",
|
|
13114
|
+
"reveal": "Reveal",
|
|
13115
|
+
"sidebar": "Sidebar",
|
|
13116
|
+
"slider": "Slider",
|
|
13117
|
+
"steps": "Steps",
|
|
13118
|
+
"switch": "Switch",
|
|
13119
|
+
"taginput": "Taginput",
|
|
13120
|
+
"timeline": "Timeline",
|
|
13121
|
+
"toast": "Toast",
|
|
13122
|
+
"tooltip": "Tooltip",
|
|
13123
|
+
"tree-view": "TreeView"
|
|
13124
|
+
},
|
|
13125
|
+
"byHand": {
|
|
13126
|
+
"thead": { "target": "Table.Thead", "props": [] },
|
|
13127
|
+
"tbody": { "target": "Table.Tbody", "props": [] },
|
|
13128
|
+
"tfoot": { "target": "Table.Tfoot", "props": [] },
|
|
13129
|
+
"tr": { "target": "Table.Tr", "props": ["isSelected", "color"] },
|
|
13130
|
+
"th": { "target": "Table.Th", "props": ["isAligned", "width", "color"] },
|
|
13131
|
+
"td": { "target": "Table.Td", "props": ["isAligned", "color"] }
|
|
13132
|
+
}
|
|
13066
13133
|
}
|
package/data/catalog.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"generatedFrom": {
|
|
4
4
|
"package": "@allxsmith/bestax-bulma",
|
|
5
|
-
"version": "5.45.
|
|
5
|
+
"version": "5.45.1"
|
|
6
6
|
},
|
|
7
7
|
"docsBase": "https://bestax.io/docs",
|
|
8
8
|
"categories": [
|
|
@@ -905,7 +905,7 @@
|
|
|
905
905
|
"import": "import { Radio, Radios, Control } from '@allxsmith/bestax-bulma';",
|
|
906
906
|
"compound": false,
|
|
907
907
|
"propCount": 7,
|
|
908
|
-
"exampleCount":
|
|
908
|
+
"exampleCount": 6
|
|
909
909
|
},
|
|
910
910
|
{
|
|
911
911
|
"name": "Radios",
|
|
@@ -42,15 +42,15 @@
|
|
|
42
42
|
"code": "function example() {\n const fruits = [\n 'Apple',\n 'Apricot',\n 'Avocado',\n 'Banana',\n 'Blackberry',\n 'Blueberry',\n ];\n\n return (\n <Autocomplete data={fruits} placeholder=\"Type to filter...\" keepFirst />\n );\n}"
|
|
43
43
|
},
|
|
44
44
|
{
|
|
45
|
-
"title": "Context-Aware Rendering",
|
|
45
|
+
"title": "Context-Aware Rendering › Default (with label)",
|
|
46
46
|
"code": "<Autocomplete\n label=\"Fruit\"\n data={['Apple', 'Banana', 'Cherry']}\n placeholder=\"Search fruit...\"\n/>"
|
|
47
47
|
},
|
|
48
48
|
{
|
|
49
|
-
"title": "Context-Aware Rendering",
|
|
49
|
+
"title": "Context-Aware Rendering › With Field Wrapper",
|
|
50
50
|
"code": "function example() {\n return (\n <Field\n horizontal\n label=\"Fruit\"\n labelProps={{ htmlFor: 'fruit-field', id: 'fruit-field-label' }}\n >\n <Field.Body>\n <Field>\n <Autocomplete\n id=\"fruit-field\"\n data={['Apple', 'Banana', 'Cherry']}\n placeholder=\"Search fruit...\"\n />\n </Field>\n </Field.Body>\n </Field>\n );\n}"
|
|
51
51
|
},
|
|
52
52
|
{
|
|
53
|
-
"title": "Context-Aware Rendering",
|
|
53
|
+
"title": "Context-Aware Rendering › With Field and Control Wrappers",
|
|
54
54
|
"code": "function example() {\n return (\n <Field\n horizontal\n label=\"Fruit\"\n labelProps={{\n htmlFor: 'fruit-field-control',\n id: 'fruit-field-control-label',\n }}\n >\n <Field.Body>\n <Field>\n <Control iconLeftName=\"search\">\n <Autocomplete\n id=\"fruit-field-control\"\n data={['Apple', 'Banana', 'Cherry']}\n placeholder=\"Search fruit...\"\n />\n </Control>\n </Field>\n </Field.Body>\n </Field>\n );\n}"
|
|
55
55
|
}
|
|
56
56
|
],
|
|
@@ -42,23 +42,23 @@
|
|
|
42
42
|
"code": "<Card\n header=\"Upgrade to Pro\"\n headerIcon={\n <button className=\"card-header-icon\">\n <Icon library=\"fa\" name=\"bolt\" textColor=\"warning\" ariaLabel=\"Pro\" />\n </button>\n }\n image=\"https://images.unsplash.com/photo-1551288049-bebda4e38f71?auto=format&fit=crop&w=600&q=80\"\n imageAlt=\"Dashboard analytics\"\n m=\"3\"\n textAlign=\"centered\"\n hasShadow\n footer={[\n <Button key=\"upgrade\" color=\"success\">\n Upgrade Now\n </Button>,\n <Button key=\"learn\" color=\"info\" isOutlined>\n Learn More\n </Button>,\n ]}\n>\n Unlock advanced analytics, priority support, and unlimited exports for your\n team.\n</Card>"
|
|
43
43
|
},
|
|
44
44
|
{
|
|
45
|
-
"title": "Compound (dot-notation) usage",
|
|
45
|
+
"title": "Compound (dot-notation) usage › Complete Card with Compound Components",
|
|
46
46
|
"code": "import { Icon, Image } from '@allxsmith/bestax-bulma';\n\n<Card>\n <Card.Header>\n <Card.Header.Title>Compound Component Card</Card.Header.Title>\n <Card.Header.Icon aria-label=\"more options\">\n <Icon name=\"angle-down\" variant=\"solid\" ariaLabel=\"expand\" />\n </Card.Header.Icon>\n </Card.Header>\n <Card.Image>\n <Image\n src=\"https://images.unsplash.com/photo-1506744038136-46273834b3fb?auto=format&fit=crop&w=600&q=80\"\n alt=\"Beautiful forest\"\n size=\"4by3\"\n />\n </Card.Image>\n <Card.Content>\n <Content>\n This card is built using compound components for maximum flexibility.\n </Content>\n </Card.Content>\n <Card.Footer>\n <Card.FooterItem>\n <Button color=\"primary\">Save</Button>\n </Card.FooterItem>\n <Card.FooterItem>\n <Button>Cancel</Button>\n </Card.FooterItem>\n </Card.Footer>\n</Card>;"
|
|
47
47
|
},
|
|
48
48
|
{
|
|
49
|
-
"title": "Compound (dot-notation) usage",
|
|
49
|
+
"title": "Compound (dot-notation) usage › Minimal Compound Card",
|
|
50
50
|
"code": "<Card>\n <Card.Header>\n <Card.Header.Title>Simple Header</Card.Header.Title>\n </Card.Header>\n <Card.Content>\n <Paragraph>Just some minimal content using compound components.</Paragraph>\n </Card.Content>\n</Card>"
|
|
51
51
|
},
|
|
52
52
|
{
|
|
53
|
-
"title": "Compound (dot-notation) usage",
|
|
53
|
+
"title": "Compound (dot-notation) usage › Card Header with Icon",
|
|
54
54
|
"code": "function ExpandableCard() {\n const [isOpen, setIsOpen] = React.useState(true);\n\n return (\n <Card>\n <Card.Header>\n <Card.Header.Title>Expandable Card</Card.Header.Title>\n <Card.Header.Icon\n aria-label={isOpen ? 'collapse' : 'expand'}\n onClick={() => setIsOpen(!isOpen)}\n >\n <Icon\n library=\"fa\"\n name={isOpen ? 'angle-up' : 'angle-down'}\n ariaLabel={isOpen ? 'collapse' : 'expand'}\n />\n </Card.Header.Icon>\n </Card.Header>\n {isOpen && (\n <Card.Content>\n This card uses React state to toggle content visibility. Click the\n icon in the header to expand or collapse this section.\n </Card.Content>\n )}\n </Card>\n );\n}"
|
|
55
55
|
},
|
|
56
56
|
{
|
|
57
|
-
"title": "Compound (dot-notation) usage",
|
|
57
|
+
"title": "Compound (dot-notation) usage › Mixed Approach",
|
|
58
58
|
"code": "<Card header=\"Prop-based header\" textColor=\"primary\" m=\"3\">\n <Card.Content bgColor=\"light\">\n <Paragraph>\n You can mix prop-based and compound component approaches!\n </Paragraph>\n </Card.Content>\n <Card.Footer>\n <Card.FooterItem>Mixed approach example</Card.FooterItem>\n </Card.Footer>\n</Card>"
|
|
59
59
|
},
|
|
60
60
|
{
|
|
61
|
-
"title": "Compound (dot-notation) usage",
|
|
61
|
+
"title": "Compound (dot-notation) usage › Bulma's Own Markup (`p` Title, `a` Footer Items)",
|
|
62
62
|
"code": "<Card>\n <Card.Header>\n <Card.Header.Title as=\"p\">Component</Card.Header.Title>\n </Card.Header>\n <Card.Content>Card content goes here.</Card.Content>\n <Card.Footer>\n <Card.FooterItem as=\"a\" href=\"#save\">\n Save\n </Card.FooterItem>\n <Card.FooterItem as=\"a\" href=\"#edit\">\n Edit\n </Card.FooterItem>\n </Card.Footer>\n</Card>"
|
|
63
63
|
}
|
|
64
64
|
],
|
|
@@ -14,11 +14,11 @@
|
|
|
14
14
|
"code": "<Carousel itemsToShow={1} itemsToShowTablet={2} itemsToShowDesktop={3}>\n {[\n 'Garden Room',\n 'Harbor Suite',\n 'Loft',\n 'Courtyard Twin',\n 'Terrace Room',\n 'Family Suite',\n ].map(room => (\n <CarouselItem key={room}>\n <Card m=\"2\">\n <Card.Content>\n <Title as=\"p\" size=\"5\">\n {room}\n </Title>\n <SubTitle as=\"p\" size=\"6\">\n Sleeps two\n </SubTitle>\n </Card.Content>\n </Card>\n </CarouselItem>\n ))}\n</Carousel>"
|
|
15
15
|
},
|
|
16
16
|
{
|
|
17
|
-
"title": "Several Items in View",
|
|
17
|
+
"title": "Several Items in View › Stepping and indicators",
|
|
18
18
|
"code": "<Carousel itemsToShow={3} itemsToScroll={3} repeat={false}>\n {[1, 2, 3, 4, 5, 6, 7].map(n => (\n <CarouselItem key={n}>\n <Box m=\"2\" textAlign=\"centered\">\n Item {n}\n </Box>\n </CarouselItem>\n ))}\n</Carousel>"
|
|
19
19
|
},
|
|
20
20
|
{
|
|
21
|
-
"title": "Several Items in View",
|
|
21
|
+
"title": "Several Items in View › Spacing between items",
|
|
22
22
|
"code": "<Carousel className=\"room-gallery\" itemsToShow={3}>\n {/* items */}\n</Carousel>"
|
|
23
23
|
},
|
|
24
24
|
{
|
|
@@ -10,15 +10,15 @@
|
|
|
10
10
|
"code": "<Checkboxes>\n <Checkbox> Make the bed </Checkbox>\n <Checkbox> Brush teeth </Checkbox>\n <Checkbox> Do homework </Checkbox>\n <Checkbox> Feed the pet </Checkbox>\n <Checkbox> Take out the trash </Checkbox>\n <Checkbox> Clean your room </Checkbox>\n <Checkbox> Set the table </Checkbox>\n <Checkbox> Help with dishes </Checkbox>\n <Checkbox> Water the plants </Checkbox>\n <Checkbox> Put away toys </Checkbox>\n</Checkboxes>"
|
|
11
11
|
},
|
|
12
12
|
{
|
|
13
|
-
"title": "Context-Aware Rendering",
|
|
13
|
+
"title": "Context-Aware Rendering › Default (with label)",
|
|
14
14
|
"code": "<Checkboxes label=\"Chores\">\n <Checkbox> Make the bed </Checkbox>\n <Checkbox> Brush teeth </Checkbox>\n <Checkbox> Do homework </Checkbox>\n</Checkboxes>"
|
|
15
15
|
},
|
|
16
16
|
{
|
|
17
|
-
"title": "Context-Aware Rendering",
|
|
17
|
+
"title": "Context-Aware Rendering › With Field Wrapper",
|
|
18
18
|
"code": "function example() {\n return (\n <Field\n horizontal\n label=\"Chores\"\n labelProps={{ id: 'chores-label', htmlFor: undefined }}\n >\n <Field.Body>\n <Field>\n <Checkboxes aria-labelledby=\"chores-label\">\n <Checkbox> Make the bed </Checkbox>\n <Checkbox> Brush teeth </Checkbox>\n <Checkbox> Do homework </Checkbox>\n </Checkboxes>\n </Field>\n </Field.Body>\n </Field>\n );\n}"
|
|
19
19
|
},
|
|
20
20
|
{
|
|
21
|
-
"title": "Context-Aware Rendering",
|
|
21
|
+
"title": "Context-Aware Rendering › With Field and Control Wrappers",
|
|
22
22
|
"code": "function example() {\n return (\n <Field\n horizontal\n label=\"Chores\"\n labelProps={{ id: 'chores-label-control', htmlFor: undefined }}\n >\n <Field.Body>\n <Field>\n <Control>\n <Checkboxes aria-labelledby=\"chores-label-control\">\n <Checkbox> Make the bed </Checkbox>\n <Checkbox> Brush teeth </Checkbox>\n <Checkbox> Do homework </Checkbox>\n </Checkboxes>\n </Control>\n </Field>\n </Field.Body>\n </Field>\n );\n}"
|
|
23
23
|
},
|
|
24
24
|
{
|
|
@@ -86,27 +86,27 @@
|
|
|
86
86
|
"code": "<Field label=\"Date\">\n <Control iconLeftName=\"calendar\" isLoading>\n <DateInput placeholder=\"YYYY-MM-DD\" />\n </Control>\n</Field>"
|
|
87
87
|
},
|
|
88
88
|
{
|
|
89
|
-
"title": "Manual Keyboard Entry",
|
|
89
|
+
"title": "Manual Keyboard Entry › Basic",
|
|
90
90
|
"code": "function example() {\n return (\n <DateInput\n label=\"Click in, then arrow or type\"\n defaultValue={new Date(2024, 5, 7)}\n openOnFocus={false}\n />\n );\n}"
|
|
91
91
|
},
|
|
92
92
|
{
|
|
93
|
-
"title": "Manual Keyboard Entry",
|
|
93
|
+
"title": "Manual Keyboard Entry › Digit entry and auto-advance",
|
|
94
94
|
"code": "function example() {\n return (\n <DateInput\n label=\"Type digits — auto-advance across segments\"\n defaultValue={new Date(2024, 5, 7)}\n openOnFocus={false}\n />\n );\n}"
|
|
95
95
|
},
|
|
96
96
|
{
|
|
97
|
-
"title": "Manual Keyboard Entry",
|
|
97
|
+
"title": "Manual Keyboard Entry › Controlled with live value",
|
|
98
98
|
"code": "function example() {\n const [v, setV] = useState<Date | null>(() => new Date(2024, 5, 7));\n return (\n <Block>\n <DateInput\n label=\"Arrow or type — value updates live\"\n value={v}\n onChange={setV}\n openOnFocus={false}\n />\n <Paragraph mt=\"2\">Selected: {v ? v.toDateString() : '—'}</Paragraph>\n </Block>\n );\n}"
|
|
99
99
|
},
|
|
100
100
|
{
|
|
101
|
-
"title": "Manual Keyboard Entry",
|
|
101
|
+
"title": "Manual Keyboard Entry › Free-form fallback",
|
|
102
102
|
"code": "function example() {\n return (\n <DateInput\n label=\"Free-form (Intl format)\"\n format={{ year: 'numeric', month: 'long', day: 'numeric' }}\n defaultValue={new Date(2024, 5, 7)}\n openOnFocus={false}\n />\n );\n}"
|
|
103
103
|
},
|
|
104
104
|
{
|
|
105
|
-
"title": "Picker vs Input Modes",
|
|
105
|
+
"title": "Picker vs Input Modes › Picker only",
|
|
106
106
|
"code": "<DateInput label=\"Picker only\" editable={false} defaultValue={new Date()} />"
|
|
107
107
|
},
|
|
108
108
|
{
|
|
109
|
-
"title": "Picker vs Input Modes",
|
|
109
|
+
"title": "Picker vs Input Modes › Input only",
|
|
110
110
|
"code": "<DateInput label=\"Input only\" popover={false} defaultValue={new Date()} />"
|
|
111
111
|
},
|
|
112
112
|
{
|
|
@@ -162,15 +162,15 @@
|
|
|
162
162
|
"code": "<DateInput\n label=\"Date of birth\"\n horizontal\n placeholder=\"YYYY-MM-DD\"\n openOnFocus={false}\n/>"
|
|
163
163
|
},
|
|
164
164
|
{
|
|
165
|
-
"title": "Context-Aware Rendering",
|
|
165
|
+
"title": "Context-Aware Rendering › Default (with label)",
|
|
166
166
|
"code": "<DateInput label=\"Date\" placeholder=\"YYYY-MM-DD\" />"
|
|
167
167
|
},
|
|
168
168
|
{
|
|
169
|
-
"title": "Context-Aware Rendering",
|
|
169
|
+
"title": "Context-Aware Rendering › With Field Wrapper",
|
|
170
170
|
"code": "function example() {\n return (\n <Field horizontal label=\"Date\" labelProps={{ htmlFor: 'date-field' }}>\n <Field.Body>\n <Field>\n <DateInput id=\"date-field\" placeholder=\"YYYY-MM-DD\" />\n </Field>\n </Field.Body>\n </Field>\n );\n}"
|
|
171
171
|
},
|
|
172
172
|
{
|
|
173
|
-
"title": "Context-Aware Rendering",
|
|
173
|
+
"title": "Context-Aware Rendering › With Field and Control Wrappers",
|
|
174
174
|
"code": "function example() {\n return (\n <Field\n horizontal\n label=\"Date\"\n labelProps={{ htmlFor: 'date-field-control' }}\n >\n <Field.Body>\n <Field>\n <Control iconLeftName=\"calendar-alt\">\n <DateInput id=\"date-field-control\" placeholder=\"YYYY-MM-DD\" />\n </Control>\n </Field>\n </Field.Body>\n </Field>\n );\n}"
|
|
175
175
|
}
|
|
176
176
|
],
|
|
@@ -138,35 +138,35 @@
|
|
|
138
138
|
"code": "<Block display=\"flex\" flexDirection=\"column\">\n <DateTimeInput label=\"Disabled\" disabled />\n <DateTimeInput label=\"Read only\" readOnly defaultValue={new Date()} />\n <DateTimeInput label=\"Loading\" isLoading />\n</Block>"
|
|
139
139
|
},
|
|
140
140
|
{
|
|
141
|
-
"title": "Context-Aware Rendering",
|
|
141
|
+
"title": "Context-Aware Rendering › Default (with label)",
|
|
142
142
|
"code": "<DateTimeInput label=\"When\" placeholder=\"YYYY-MM-DD HH:MM\" />"
|
|
143
143
|
},
|
|
144
144
|
{
|
|
145
|
-
"title": "Context-Aware Rendering",
|
|
145
|
+
"title": "Context-Aware Rendering › With Field Wrapper",
|
|
146
146
|
"code": "function example() {\n return (\n <Field horizontal label=\"When\" labelProps={{ htmlFor: 'when-field' }}>\n <Field.Body>\n <Field>\n <DateTimeInput id=\"when-field\" placeholder=\"YYYY-MM-DD HH:MM\" />\n </Field>\n </Field.Body>\n </Field>\n );\n}"
|
|
147
147
|
},
|
|
148
148
|
{
|
|
149
|
-
"title": "Context-Aware Rendering",
|
|
149
|
+
"title": "Context-Aware Rendering › With Field and Control Wrappers",
|
|
150
150
|
"code": "function example() {\n return (\n <Field\n horizontal\n label=\"When\"\n labelProps={{ htmlFor: 'when-field-control' }}\n >\n <Field.Body>\n <Field>\n <Control iconLeftName=\"calendar-alt\">\n <DateTimeInput\n id=\"when-field-control\"\n placeholder=\"YYYY-MM-DD HH:MM\"\n />\n </Control>\n </Field>\n </Field.Body>\n </Field>\n );\n}"
|
|
151
151
|
},
|
|
152
152
|
{
|
|
153
|
-
"title": "Manual Keyboard Entry",
|
|
153
|
+
"title": "Manual Keyboard Entry › Basic",
|
|
154
154
|
"code": "function example() {\n return (\n <DateTimeInput\n label=\"Type across date and time\"\n defaultValue={new Date(2024, 5, 7, 13, 45)}\n openOnFocus={false}\n />\n );\n}"
|
|
155
155
|
},
|
|
156
156
|
{
|
|
157
|
-
"title": "Manual Keyboard Entry",
|
|
157
|
+
"title": "Manual Keyboard Entry › Controlled with live value",
|
|
158
158
|
"code": "function example() {\n const [v, setV] = useState<Date | null>(() => new Date(2024, 5, 7, 13, 45));\n return (\n <Block>\n <DateTimeInput\n label=\"Arrow or type — value updates live\"\n value={v}\n onChange={setV}\n openOnFocus={false}\n />\n <Paragraph mt=\"2\">Selected: {v ? v.toString() : '—'}</Paragraph>\n </Block>\n );\n}"
|
|
159
159
|
},
|
|
160
160
|
{
|
|
161
|
-
"title": "Manual Keyboard Entry",
|
|
161
|
+
"title": "Manual Keyboard Entry › Free-form fallback",
|
|
162
162
|
"code": "function example() {\n return (\n <DateTimeInput\n label=\"Free-form (Intl format)\"\n format={{ dateStyle: 'medium', timeStyle: 'short' }}\n defaultValue={new Date(2024, 5, 7, 13, 45)}\n openOnFocus={false}\n />\n );\n}"
|
|
163
163
|
},
|
|
164
164
|
{
|
|
165
|
-
"title": "Picker vs Input Modes",
|
|
165
|
+
"title": "Picker vs Input Modes › Picker only",
|
|
166
166
|
"code": "<DateTimeInput label=\"Picker only\" editable={false} defaultValue={new Date()} />"
|
|
167
167
|
},
|
|
168
168
|
{
|
|
169
|
-
"title": "Picker vs Input Modes",
|
|
169
|
+
"title": "Picker vs Input Modes › Input only",
|
|
170
170
|
"code": "<DateTimeInput label=\"Input only\" popover={false} defaultValue={new Date()} />"
|
|
171
171
|
}
|
|
172
172
|
],
|
|
@@ -62,15 +62,15 @@
|
|
|
62
62
|
"code": "<File\n color=\"primary\"\n isRight\n hasName\n fileName=\"right.pdf\"\n buttonLabel=\"Choose a file…\"\n iconLeft={<Icon name=\"upload\" aria-hidden=\"true\" />}\n/>"
|
|
63
63
|
},
|
|
64
64
|
{
|
|
65
|
-
"title": "Context-Aware Rendering",
|
|
65
|
+
"title": "Context-Aware Rendering › Default (with label)",
|
|
66
66
|
"code": "<File\n label=\"Document\"\n buttonLabel=\"Choose a file…\"\n iconLeft={<Icon name=\"upload\" aria-hidden=\"true\" />}\n/>"
|
|
67
67
|
},
|
|
68
68
|
{
|
|
69
|
-
"title": "Context-Aware Rendering",
|
|
69
|
+
"title": "Context-Aware Rendering › With Field Wrapper",
|
|
70
70
|
"code": "function example() {\n return (\n <Field\n horizontal\n label=\"Document\"\n labelProps={{ htmlFor: 'document-field' }}\n >\n <Field.Body>\n <Field>\n <File\n id=\"document-field\"\n buttonLabel=\"Choose a file…\"\n iconLeft={<Icon name=\"upload\" aria-hidden=\"true\" />}\n />\n </Field>\n </Field.Body>\n </Field>\n );\n}"
|
|
71
71
|
},
|
|
72
72
|
{
|
|
73
|
-
"title": "Context-Aware Rendering",
|
|
73
|
+
"title": "Context-Aware Rendering › With Field and Control Wrappers",
|
|
74
74
|
"code": "function example() {\n return (\n <Field\n horizontal\n label=\"Document\"\n labelProps={{ htmlFor: 'document-field-control' }}\n >\n <Field.Body>\n <Field>\n <Control iconLeftName=\"paperclip\">\n <File\n id=\"document-field-control\"\n buttonLabel=\"Choose a file…\"\n iconLeft={<Icon name=\"upload\" aria-hidden=\"true\" />}\n />\n </Control>\n </Field>\n </Field.Body>\n </Field>\n );\n}"
|
|
75
75
|
}
|
|
76
76
|
],
|
|
@@ -50,23 +50,23 @@
|
|
|
50
50
|
"code": "<>\n <Input\n label=\"Username\"\n color=\"success\"\n value=\"bulma\"\n message=\"This username is available\"\n messageColor=\"success\"\n iconLeftName=\"user\"\n iconRightName=\"check\"\n onChange={() => {}}\n />\n <Input\n label=\"Email\"\n type=\"email\"\n color=\"danger\"\n value=\"hello@\"\n message=\"This email is invalid\"\n messageColor=\"danger\"\n iconLeftName=\"envelope\"\n iconRightName=\"exclamation-triangle\"\n onChange={() => {}}\n />\n</>"
|
|
51
51
|
},
|
|
52
52
|
{
|
|
53
|
-
"title": "Form Addons",
|
|
53
|
+
"title": "Form Addons › Input + Button",
|
|
54
54
|
"code": "<Field hasAddons>\n <Control isExpanded>\n <Input placeholder=\"Find a repository\" aria-label=\"Find a repository\" />\n </Control>\n <Control>\n <Button color=\"info\">Search</Button>\n </Control>\n</Field>"
|
|
55
55
|
},
|
|
56
56
|
{
|
|
57
|
-
"title": "Form Addons",
|
|
57
|
+
"title": "Form Addons › Input + Static Suffix",
|
|
58
58
|
"code": "<Field hasAddons>\n <Control isExpanded>\n <Input placeholder=\"Your email\" aria-label=\"Email username\" />\n </Control>\n <Control>\n <Button isStatic>@gmail.com</Button>\n </Control>\n</Field>"
|
|
59
59
|
},
|
|
60
60
|
{
|
|
61
|
-
"title": "Form Addons",
|
|
61
|
+
"title": "Form Addons › Select + Input + Button",
|
|
62
62
|
"code": "<Field hasAddons>\n <Control>\n <Select aria-label=\"Country code\">\n <option>+1</option>\n <option>+44</option>\n <option>+33</option>\n </Select>\n </Control>\n <Control isExpanded>\n <Input\n type=\"tel\"\n placeholder=\"Your phone number\"\n aria-label=\"Phone number\"\n />\n </Control>\n <Control>\n <Button color=\"primary\">Call</Button>\n </Control>\n</Field>"
|
|
63
63
|
},
|
|
64
64
|
{
|
|
65
|
-
"title": "Form Addons",
|
|
65
|
+
"title": "Form Addons › Centered Addons",
|
|
66
66
|
"code": "<Field hasAddons=\"centered\">\n <Control>\n <Button>Yes</Button>\n </Control>\n <Control>\n <Button>Maybe</Button>\n </Control>\n <Control>\n <Button>No</Button>\n </Control>\n</Field>"
|
|
67
67
|
},
|
|
68
68
|
{
|
|
69
|
-
"title": "Form Addons",
|
|
69
|
+
"title": "Form Addons › Right-Aligned Addons",
|
|
70
70
|
"code": "<Field hasAddons=\"right\">\n <Control>\n <Button>Yes</Button>\n </Control>\n <Control>\n <Button>Maybe</Button>\n </Control>\n <Control>\n <Button>No</Button>\n </Control>\n</Field>"
|
|
71
71
|
},
|
|
72
72
|
{
|
|
@@ -78,23 +78,23 @@
|
|
|
78
78
|
"code": "function CopyButton() {\n const id = React.useId();\n const inputRef = React.useRef<HTMLInputElement>(null);\n const [status, setStatus] = useState<'idle' | 'copied' | 'failed'>('idle');\n const link = 'https://bestax.io/docs/api/form/input';\n\n // Put the button's label back after a moment.\n useEffect(() => {\n if (status !== 'copied') return undefined;\n const timer = setTimeout(() => setStatus('idle'), 2000);\n return () => clearTimeout(timer);\n }, [status]);\n\n const copy = async () => {\n try {\n await navigator.clipboard.writeText(link);\n setStatus('copied');\n } catch {\n // No clipboard on this page, or the browser refused the write.\n inputRef.current?.focus();\n inputRef.current?.select();\n setStatus('failed');\n }\n };\n\n return (\n <Field label=\"Share link\" labelProps={{ htmlFor: id }}>\n <Field hasAddons>\n <Control isExpanded>\n <Input ref={inputRef} id={id} value={link} readOnly />\n </Control>\n <Control>\n <Button type=\"button\" onClick={copy}>\n <Icon\n name={status === 'copied' ? 'check' : 'copy'}\n aria-hidden=\"true\"\n />\n <span>{status === 'copied' ? 'Copied' : 'Copy'}</span>\n </Button>\n </Control>\n </Field>\n <p role=\"status\" className=\"help\">\n {status === 'copied' && 'Copied to the clipboard.'}\n </p>\n <p role=\"alert\" className=\"help is-danger\">\n {status === 'failed' &&\n \"Couldn't copy automatically. The link is selected, so copy it from the field.\"}\n </p>\n </Field>\n );\n}"
|
|
79
79
|
},
|
|
80
80
|
{
|
|
81
|
-
"title": "Form Group",
|
|
81
|
+
"title": "Form Group › Grouped Buttons",
|
|
82
82
|
"code": "<Field grouped>\n <Control>\n <Button color=\"link\">Submit</Button>\n </Control>\n <Control>\n <Button>Cancel</Button>\n </Control>\n</Field>"
|
|
83
83
|
},
|
|
84
84
|
{
|
|
85
|
-
"title": "Form Group",
|
|
85
|
+
"title": "Form Group › Centered Group",
|
|
86
86
|
"code": "<Field grouped=\"centered\">\n <Control>\n <Button color=\"link\">Submit</Button>\n </Control>\n <Control>\n <Button>Cancel</Button>\n </Control>\n</Field>"
|
|
87
87
|
},
|
|
88
88
|
{
|
|
89
|
-
"title": "Form Group",
|
|
89
|
+
"title": "Form Group › Right-Aligned Group",
|
|
90
90
|
"code": "<Field grouped=\"right\">\n <Control>\n <Button color=\"link\">Submit</Button>\n </Control>\n <Control>\n <Button>Cancel</Button>\n </Control>\n</Field>"
|
|
91
91
|
},
|
|
92
92
|
{
|
|
93
|
-
"title": "Form Group",
|
|
93
|
+
"title": "Form Group › Expanded Input + Button",
|
|
94
94
|
"code": "<Field grouped>\n <Control isExpanded>\n <Input placeholder=\"Find a repository\" aria-label=\"Find a repository\" />\n </Control>\n <Control>\n <Button color=\"info\">Search</Button>\n </Control>\n</Field>"
|
|
95
95
|
},
|
|
96
96
|
{
|
|
97
|
-
"title": "Form Group",
|
|
97
|
+
"title": "Form Group › Multiline Group",
|
|
98
98
|
"code": "<Field grouped=\"multiline\">\n {[\n 'One',\n 'Two',\n 'Three',\n 'Four',\n 'Five',\n 'Six',\n 'Seven',\n 'Eight',\n 'Nine',\n 'Ten',\n 'Eleven',\n 'Twelve',\n 'Thirteen',\n ].map(label => (\n <Control key={label}>\n <Button>{label}</Button>\n </Control>\n ))}\n</Field>"
|
|
99
99
|
},
|
|
100
100
|
{
|
|
@@ -114,15 +114,15 @@
|
|
|
114
114
|
"code": "<fieldset disabled>\n <Input label=\"Name\" placeholder=\"Your name\" />\n <Input label=\"Email\" type=\"email\" placeholder=\"Your email\" />\n</fieldset>"
|
|
115
115
|
},
|
|
116
116
|
{
|
|
117
|
-
"title": "Context-Aware Rendering",
|
|
117
|
+
"title": "Context-Aware Rendering › Default (with label)",
|
|
118
118
|
"code": "<Input label=\"Username\" placeholder=\"Enter username\" />"
|
|
119
119
|
},
|
|
120
120
|
{
|
|
121
|
-
"title": "Context-Aware Rendering",
|
|
121
|
+
"title": "Context-Aware Rendering › With Field Wrapper",
|
|
122
122
|
"code": "function example() {\n return (\n <Field\n horizontal\n label=\"Username\"\n labelProps={{ htmlFor: 'username-field' }}\n >\n <Field.Body>\n <Field>\n <Input id=\"username-field\" placeholder=\"Enter username\" />\n </Field>\n </Field.Body>\n </Field>\n );\n}"
|
|
123
123
|
},
|
|
124
124
|
{
|
|
125
|
-
"title": "Context-Aware Rendering",
|
|
125
|
+
"title": "Context-Aware Rendering › With Field and Control Wrappers",
|
|
126
126
|
"code": "function example() {\n return (\n <Field\n horizontal\n label=\"Username\"\n labelProps={{ htmlFor: 'username-field-control' }}\n >\n <Field.Body>\n <Field>\n <Control iconLeftName=\"user\">\n <Input id=\"username-field-control\" placeholder=\"Enter username\" />\n </Control>\n </Field>\n </Field.Body>\n </Field>\n );\n}"
|
|
127
127
|
}
|
|
128
128
|
],
|
|
@@ -22,19 +22,19 @@
|
|
|
22
22
|
"code": "<>\n <Message title=\"Default Size\">This is the default size message.</Message>\n <Message size=\"small\" title=\"Small\">\n This is a small message.\n </Message>\n <Message size=\"medium\" title=\"Medium\">\n This is a medium message.\n </Message>\n <Message size=\"large\" title=\"Large\">\n This is a large message.\n </Message>\n</>"
|
|
23
23
|
},
|
|
24
24
|
{
|
|
25
|
-
"title": "Compound (dot-notation) usage",
|
|
25
|
+
"title": "Compound (dot-notation) usage › Complete Message with Compound Components",
|
|
26
26
|
"code": "<Message color=\"info\">\n <Message.Header>\n <Paragraph>Compound Component Message</Paragraph>\n <Delete aria-label=\"delete\" />\n </Message.Header>\n <Message.Body>\n <Paragraph>\n This message is built using compound components for maximum flexibility\n and control over each section.\n </Paragraph>\n <Paragraph>\n You can include multiple paragraphs and elements in the body.\n </Paragraph>\n </Message.Body>\n</Message>"
|
|
27
27
|
},
|
|
28
28
|
{
|
|
29
|
-
"title": "Compound (dot-notation) usage",
|
|
29
|
+
"title": "Compound (dot-notation) usage › Minimal Message with Body Only",
|
|
30
30
|
"code": "<Message color=\"success\">\n <Message.Body>\n <Paragraph>\n A simple message using only the Message.Body compound component.\n </Paragraph>\n </Message.Body>\n</Message>"
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
|
-
"title": "Compound (dot-notation) usage",
|
|
33
|
+
"title": "Compound (dot-notation) usage › Header-Only Message",
|
|
34
34
|
"code": "<Message color=\"warning\">\n <Message.Header>\n <Paragraph>Header-only message</Paragraph>\n <Delete aria-label=\"delete\" />\n </Message.Header>\n</Message>"
|
|
35
35
|
},
|
|
36
36
|
{
|
|
37
|
-
"title": "Compound (dot-notation) usage",
|
|
37
|
+
"title": "Compound (dot-notation) usage › Mixed Approach",
|
|
38
38
|
"code": "<Message color=\"danger\" title=\"Mixed Approach\">\n <Message.Body>\n <Paragraph>\n You can mix prop-based and compound component approaches!\n </Paragraph>\n <Paragraph>\n This message uses the title prop but compound components for the body.\n </Paragraph>\n </Message.Body>\n</Message>"
|
|
39
39
|
}
|
|
40
40
|
],
|
|
@@ -22,11 +22,11 @@
|
|
|
22
22
|
"code": "function example() {\n const [open, setOpen] = useState(false);\n\n return (\n <>\n <Button color=\"success\" onClick={() => setOpen(true)}>\n Show Modal\n </Button>\n <Modal active={open} onClose={() => setOpen(false)}>\n <Box>\n <Title size=\"4\">Custom Content</Title>\n <Paragraph>Put any content here!</Paragraph>\n </Box>\n </Modal>\n </>\n );\n}"
|
|
23
23
|
},
|
|
24
24
|
{
|
|
25
|
-
"title": "Explicit Modal Types",
|
|
25
|
+
"title": "Explicit Modal Types › Force content style",
|
|
26
26
|
"code": "function example() {\n const [open, setOpen] = useState(false);\n\n return (\n <>\n <Button color=\"success\" onClick={() => setOpen(true)}>\n Show Modal\n </Button>\n <Modal active={open} onClose={() => setOpen(false)} type=\"content\">\n <div>Custom content modal (forced type=\"content\")</div>\n </Modal>\n </>\n );\n}"
|
|
27
27
|
},
|
|
28
28
|
{
|
|
29
|
-
"title": "Explicit Modal Types",
|
|
29
|
+
"title": "Explicit Modal Types › Force card style",
|
|
30
30
|
"code": "function example() {\n const [open, setOpen] = useState(false);\n\n return (\n <>\n <Button color=\"success\" onClick={() => setOpen(true)}>\n Show Modal\n </Button>\n <Modal active={open} onClose={() => setOpen(false)} type=\"card\">\n Modal card body (forced type=\"card\")\n </Modal>\n </>\n );\n}"
|
|
31
31
|
},
|
|
32
32
|
{
|
|
@@ -38,15 +38,15 @@
|
|
|
38
38
|
"code": "function example() {\n const [open, setOpen] = React.useState(false);\n const [width, setWidth] = React.useState<number | null>(null);\n const modalRef = React.useRef<HTMLDivElement>(null);\n\n return (\n <>\n <Button color=\"info\" onClick={() => setOpen(true)}>\n Open and measure\n </Button>\n <Modal\n active={open}\n onClose={() => setOpen(false)}\n ref={modalRef}\n modalCardTitle=\"Measured through the ref\"\n >\n <Button\n onClick={() =>\n setWidth(modalRef.current?.getBoundingClientRect().width ?? null)\n }\n >\n Measure\n </Button>\n <p>Width: {width === null ? '—' : `${Math.round(width)}px`}</p>\n </Modal>\n </>\n );\n}"
|
|
39
39
|
},
|
|
40
40
|
{
|
|
41
|
-
"title": "Compound (dot-notation) usage",
|
|
42
|
-
"code": "function example() {\n const [open, setOpen] = useState(false);\n const closeModal = () => setOpen(false);\n\n return (\n <>\n <Button color=\"success\" onClick={() => setOpen(true)}>\n Show Modal\n </Button>\n <Modal isActive={open}>\n <Modal.Background onClick={closeModal} />\n <Modal.Card>\n <Modal.Card.Head>\n <Modal.Card.Title>Compound Component Modal</Modal.Card.Title>\n <Modal.Close
|
|
41
|
+
"title": "Compound (dot-notation) usage › Modal.Card with compound components",
|
|
42
|
+
"code": "function example() {\n const [open, setOpen] = useState(false);\n const closeModal = () => setOpen(false);\n\n return (\n <>\n <Button color=\"success\" onClick={() => setOpen(true)}>\n Show Modal\n </Button>\n <Modal isActive={open} onClose={closeModal}>\n <Modal.Background onClick={closeModal} />\n <Modal.Card>\n <Modal.Card.Head>\n <Modal.Card.Title>Compound Component Modal</Modal.Card.Title>\n <Modal.Close />\n </Modal.Card.Head>\n <Modal.Card.Body>\n This modal uses the compound components API for better control and\n readability.\n </Modal.Card.Body>\n <Modal.Card.Foot>\n <Buttons>\n <Button color=\"success\" onClick={closeModal}>\n Save\n </Button>\n <Button onClick={closeModal}>Cancel</Button>\n </Buttons>\n </Modal.Card.Foot>\n </Modal.Card>\n </Modal>\n </>\n );\n}"
|
|
43
43
|
},
|
|
44
44
|
{
|
|
45
|
-
"title": "Compound (dot-notation) usage",
|
|
46
|
-
"code": "function example() {\n const [open, setOpen] = useState(false);\n const closeModal = () => setOpen(false);\n\n return (\n <>\n <Button color=\"success\" onClick={() => setOpen(true)}>\n Show Modal\n </Button>\n <Modal isActive={open}>\n <Modal.Background onClick={closeModal} />\n <Modal.Content>\n <Box>\n <Title size=\"4\">Custom Content</Title>\n <Paragraph>Using compound components for full control!</Paragraph>\n </Box>\n </Modal.Content>\n <Modal.Close variant=\"floating\"
|
|
45
|
+
"title": "Compound (dot-notation) usage › Modal.Content with compound components",
|
|
46
|
+
"code": "function example() {\n const [open, setOpen] = useState(false);\n const closeModal = () => setOpen(false);\n\n return (\n <>\n <Button color=\"success\" onClick={() => setOpen(true)}>\n Show Modal\n </Button>\n <Modal isActive={open} onClose={closeModal}>\n <Modal.Background onClick={closeModal} />\n <Modal.Content>\n <Box>\n <Title size=\"4\">Custom Content</Title>\n <Paragraph>Using compound components for full control!</Paragraph>\n </Box>\n </Modal.Content>\n <Modal.Close variant=\"floating\" />\n </Modal>\n </>\n );\n}"
|
|
47
47
|
}
|
|
48
48
|
],
|
|
49
|
-
"accessibility": "- The modal root gets `role=\"dialog\"` and `aria-modal=\"true\"` while active — pass an explicit `role` to override (e.g. `Dialog` passes `role=\"presentation\"` on the `Modal` it wraps so its own `role=\"alertdialog\"` is the only one announced).\n- **Give the dialog an accessible name.** With the legacy API, `modalCardTitle` is wired up as `aria-labelledby` for you. With the compound API, pass your own `aria-label` or `aria-labelledby` on `<Modal>` — a `role=\"dialog\"` with no name is announced as just \"dialog\". An explicit `aria-labelledby` always wins over the generated one.\n- Escape closes the modal (calls `onClose`) by default; opt out with `closeOnEscape={false}`. One Escape closes the topmost overlay only, whichever open Modal, [Dialog](https://bestax.io/docs/api/components/dialog), [Sidebar](https://bestax.io/docs/api/components/sidebar) or full-page [Loading](https://bestax.io/docs/api/components/loading) opened last, and the next Escape closes the one under it. A modal on top with `closeOnEscape={false}` still keeps Escape from the layers under it. A [Toast](https://bestax.io/docs/api/components/toast) waits until no overlay is open.\n- The modal calls `preventDefault()` on the Escape it closes on, so a listener of your own that runs after it can tell the key was used.\n- A popup inside the modal takes its own Escape first. With an Autocomplete list, a Dropdown menu, a Popover or a date picker's calendar open, the first Escape closes that and the next one closes the modal.\n- A popup of your own inside a modal should call `preventDefault()` on the Escape it closes on. The modal leaves an Escape that was prevented alone, whether your popup hears it in a React `onKeyDown` or in a listener on `document`. Call it only when the popup is open and the key was pressed in it, so an Escape with nothing to close still closes the modal, and so does one pressed in a modal opened over your popup.\n- Body scroll is locked while the modal is active; opt out with `lockScroll={false}`. The lock is ref-counted and shared with `Dialog`, `Sidebar` and `Loading`, so whichever overlay closes first doesn't unlock the page underneath one that is still open.\n- Focus moves to the first tab stop (or the modal itself) on open, and is restored to the previously focused element on close — unless another modal is still open on top, in which case that one keeps focus.\n- Tab and Shift+Tab cycle within the modal while it is the topmost modal overlay, so the keyboard order agrees with what `aria-modal=\"true\"` tells assistive technology. They wrap at the same tab stops [`useFocusTrap`](https://bestax.io/docs/api/helpers/usefocustrap) does, so disabled, hidden and `tabIndex={-1}` elements are skipped, and so is inert content, such as a closed [Sidebar](https://bestax.io/docs/api/components/sidebar) inside the modal, and the content of a closed `<details>`. A radio group counts once. A Tab from outside the modal brings focus back in, and so does a Tab the browser takes out anyway, as Safari does past links when its settings say to. With another Modal or Dialog, a [Sidebar](https://bestax.io/docs/api/components/sidebar) with an overlay or a full-page Loading opened over it, the modal leaves Tab alone until that one closes. A Sidebar without an overlay isn't modal: opened over the modal, it takes Escape first, but the modal keeps holding Tab and keeps focus, so the sidebar doesn't take focus when it opens, and a Tab from its controls comes back into the modal. A focus trap of your own inside it, such as a portaled panel's, keeps a Tab it calls `preventDefault()` on, and the modal leaves focus where your trap put it. Note that `aria-modal` does not by itself make background content inert, and no `inert` attribute is applied, so background content remains reachable by pointer and by browser UI such as find-in-page.\n-
|
|
49
|
+
"accessibility": "- The modal root gets `role=\"dialog\"` and `aria-modal=\"true\"` while active — pass an explicit `role` to override (e.g. `Dialog` passes `role=\"presentation\"` on the `Modal` it wraps so its own `role=\"alertdialog\"` is the only one announced).\n- **Give the dialog an accessible name.** With the legacy API, `modalCardTitle` is wired up as `aria-labelledby` for you. With the compound API, pass your own `aria-label` or `aria-labelledby` on `<Modal>` — a `role=\"dialog\"` with no name is announced as just \"dialog\". An explicit `aria-labelledby` always wins over the generated one.\n- Escape closes the modal (calls `onClose`) by default; opt out with `closeOnEscape={false}`. One Escape closes the topmost overlay only, whichever open Modal, [Dialog](https://bestax.io/docs/api/components/dialog), [Sidebar](https://bestax.io/docs/api/components/sidebar) or full-page [Loading](https://bestax.io/docs/api/components/loading) opened last, and the next Escape closes the one under it. A modal on top with `closeOnEscape={false}` still keeps Escape from the layers under it. A [Toast](https://bestax.io/docs/api/components/toast) waits until no overlay is open.\n- The modal calls `preventDefault()` on the Escape it closes on, so a listener of your own that runs after it can tell the key was used.\n- A popup inside the modal takes its own Escape first. With an Autocomplete list, a Dropdown menu, a Popover or a date picker's calendar open, the first Escape closes that and the next one closes the modal.\n- A popup of your own inside a modal should call `preventDefault()` on the Escape it closes on. The modal leaves an Escape that was prevented alone, whether your popup hears it in a React `onKeyDown` or in a listener on `document`. Call it only when the popup is open and the key was pressed in it, so an Escape with nothing to close still closes the modal, and so does one pressed in a modal opened over your popup.\n- Body scroll is locked while the modal is active; opt out with `lockScroll={false}`. The lock is ref-counted and shared with `Dialog`, `Sidebar` and `Loading`, so whichever overlay closes first doesn't unlock the page underneath one that is still open.\n- Focus moves to the first tab stop (or the modal itself) on open, and is restored to the previously focused element on close — unless another modal is still open on top, in which case that one keeps focus.\n- Tab and Shift+Tab cycle within the modal while it is the topmost modal overlay, so the keyboard order agrees with what `aria-modal=\"true\"` tells assistive technology. They wrap at the same tab stops [`useFocusTrap`](https://bestax.io/docs/api/helpers/usefocustrap) does, so disabled, hidden and `tabIndex={-1}` elements are skipped, and so is inert content, such as a closed [Sidebar](https://bestax.io/docs/api/components/sidebar) inside the modal, and the content of a closed `<details>`. A radio group counts once. A Tab from outside the modal brings focus back in, and so does a Tab the browser takes out anyway, as Safari does past links when its settings say to. With another Modal or Dialog, a [Sidebar](https://bestax.io/docs/api/components/sidebar) with an overlay or a full-page Loading opened over it, the modal leaves Tab alone until that one closes. A Sidebar without an overlay isn't modal: opened over the modal, it takes Escape first, but the modal keeps holding Tab and keeps focus, so the sidebar doesn't take focus when it opens, and a Tab from its controls comes back into the modal. A focus trap of your own inside it, such as a portaled panel's, keeps a Tab it calls `preventDefault()` on, and the modal leaves focus where your trap put it. Note that `aria-modal` does not by itself make background content inert, and no `inert` attribute is applied, so background content remains reachable by pointer and by browser UI such as find-in-page.\n- In the props form, the background closes the modal on click, and a close button is provided for both modal-card and modal-content variants (both call `onClose`, so pass it).\n- In the compound form, `Modal.Close` calls the modal's `onClose` unless you give it an `onClick` of your own, and `Modal.Background` closes the modal only when you pass it `onClick={onClose}`.\n\n:::note\nAlways provide an `onClose` handler for accessibility and to allow users to dismiss the modal.\n:::",
|
|
50
50
|
"related": [
|
|
51
51
|
"Button",
|
|
52
52
|
"Dialog",
|
|
@@ -88,7 +88,7 @@
|
|
|
88
88
|
"name": "onClose",
|
|
89
89
|
"type": "() => void",
|
|
90
90
|
"default": null,
|
|
91
|
-
"description": "
|
|
91
|
+
"description": "Called to ask for the modal to close. The props form calls it from the background and the close button it renders. In the compound form, `Modal.Close` calls it unless you give it an `onClick` of your own, and `Modal.Background` doesn't call it on its own: pass it `onClick={onClose}` for a click on the background to close the modal. Escape calls it in both forms unless `closeOnEscape` is `false`.",
|
|
92
92
|
"required": false,
|
|
93
93
|
"inherited": false,
|
|
94
94
|
"deprecated": false
|
|
@@ -202,7 +202,7 @@
|
|
|
202
202
|
},
|
|
203
203
|
{
|
|
204
204
|
"path": "Modal.Background",
|
|
205
|
-
"summary": "Modal.Background - Renders the modal background overlay.",
|
|
205
|
+
"summary": "Modal.Background - Renders the modal background overlay. Pass it `onClick={onClose}` for a click on it to close the modal.",
|
|
206
206
|
"component": null,
|
|
207
207
|
"props": [
|
|
208
208
|
{
|
|
@@ -215,7 +215,17 @@
|
|
|
215
215
|
"deprecated": false
|
|
216
216
|
}
|
|
217
217
|
],
|
|
218
|
-
"extraProps": [
|
|
218
|
+
"extraProps": [
|
|
219
|
+
{
|
|
220
|
+
"name": "onClick",
|
|
221
|
+
"type": "React.MouseEventHandler<HTMLDivElement>",
|
|
222
|
+
"default": null,
|
|
223
|
+
"description": "Called when the background is clicked. The background doesn't call the modal's `onClose` on its own, so pass `onClick={onClose}` for a click on it to close the modal.",
|
|
224
|
+
"required": false,
|
|
225
|
+
"inherited": false,
|
|
226
|
+
"deprecated": false
|
|
227
|
+
}
|
|
228
|
+
],
|
|
219
229
|
"catchAll": "All standard <div> attributes",
|
|
220
230
|
"types": []
|
|
221
231
|
},
|
|
@@ -335,7 +345,7 @@
|
|
|
335
345
|
},
|
|
336
346
|
{
|
|
337
347
|
"path": "Modal.Close",
|
|
338
|
-
"summary": "Modal.Close - Renders modal close button with two variant styles.",
|
|
348
|
+
"summary": "Modal.Close - Renders modal close button with two variant styles. It calls the modal's `onClose` unless given an `onClick` of its own.",
|
|
339
349
|
"component": null,
|
|
340
350
|
"props": [
|
|
341
351
|
{
|
|
@@ -384,6 +394,15 @@
|
|
|
384
394
|
"required": false,
|
|
385
395
|
"inherited": false,
|
|
386
396
|
"deprecated": false
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
"name": "onClick",
|
|
400
|
+
"type": "React.MouseEventHandler<HTMLButtonElement>",
|
|
401
|
+
"default": null,
|
|
402
|
+
"description": "Called when the button is clicked. Without one, the button calls the `onClose` of the `Modal` around it. Yours replaces that rather than running before it, so call `onClose` from it if the button should still close the modal.",
|
|
403
|
+
"required": false,
|
|
404
|
+
"inherited": false,
|
|
405
|
+
"deprecated": false
|
|
387
406
|
}
|
|
388
407
|
],
|
|
389
408
|
"catchAll": "All standard <button> attributes",
|
|
@@ -42,15 +42,15 @@
|
|
|
42
42
|
"code": "<Numberinput defaultValue={5} disabled />"
|
|
43
43
|
},
|
|
44
44
|
{
|
|
45
|
-
"title": "Context-Aware Rendering",
|
|
45
|
+
"title": "Context-Aware Rendering › Default (with label)",
|
|
46
46
|
"code": "<Numberinput\n label=\"Quantity\"\n defaultValue={1}\n min={1}\n max={10}\n color=\"primary\"\n/>"
|
|
47
47
|
},
|
|
48
48
|
{
|
|
49
|
-
"title": "Context-Aware Rendering",
|
|
49
|
+
"title": "Context-Aware Rendering › With Field Wrapper",
|
|
50
50
|
"code": "function example() {\n return (\n <Field\n horizontal\n label=\"Quantity\"\n labelProps={{ htmlFor: 'quantity-field' }}\n >\n <Field.Body>\n <Field>\n <Numberinput\n id=\"quantity-field\"\n bare={false}\n defaultValue={1}\n min={1}\n max={10}\n color=\"primary\"\n />\n </Field>\n </Field.Body>\n </Field>\n );\n}"
|
|
51
51
|
},
|
|
52
52
|
{
|
|
53
|
-
"title": "Context-Aware Rendering",
|
|
53
|
+
"title": "Context-Aware Rendering › With Field and Control Wrappers",
|
|
54
54
|
"code": "function example() {\n return (\n <Field\n horizontal\n label=\"Quantity\"\n labelProps={{ htmlFor: 'quantity-field-control' }}\n >\n <Field.Body>\n <Field>\n <Control>\n <Numberinput\n id=\"quantity-field-control\"\n defaultValue={1}\n min={1}\n max={10}\n color=\"primary\"\n />\n </Control>\n </Field>\n </Field.Body>\n </Field>\n );\n}"
|
|
55
55
|
}
|
|
56
56
|
],
|