bestax-mcp 1.18.26 → 1.18.27
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/catalog.json +14 -2
- package/data/components/LocaleProvider.json +8 -2
- package/data/components/NumberFormatter.json +140 -0
- package/data/components/TreeView.json +13 -9
- package/data/skills/bestax-custom-component/references/api.md +9 -5
- package/data/skills/bestax-custom-component/references/component-catalog.md +2 -1
- package/data/skills/bestax-custom-component/references/library-contributor.md +11 -0
- package/data/skills/bestax-layout-scaffold/SKILL.md +12 -1
- package/data/skills/bestax-migrate/references/bloomer/prop-map.md +1 -1
- package/data/skills/bestax-migrate/references/rbx/prop-map.md +1 -1
- package/data/skills/bestax-migrate/references/react-bulma-components/unmappables.md +1 -1
- package/data/skills.json +6 -6
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +3 -0
- package/package.json +2 -2
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.
|
|
5
|
+
"version": "5.58.0"
|
|
6
6
|
},
|
|
7
7
|
"docsBase": "https://bestax.io/docs",
|
|
8
8
|
"categories": [
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"ListItem",
|
|
32
32
|
"Loader",
|
|
33
33
|
"Notification",
|
|
34
|
+
"NumberFormatter",
|
|
34
35
|
"OrderedList",
|
|
35
36
|
"Paragraph",
|
|
36
37
|
"Pre",
|
|
@@ -917,6 +918,17 @@
|
|
|
917
918
|
"propCount": 7,
|
|
918
919
|
"exampleCount": 7
|
|
919
920
|
},
|
|
921
|
+
{
|
|
922
|
+
"name": "NumberFormatter",
|
|
923
|
+
"kind": "component",
|
|
924
|
+
"category": "elements",
|
|
925
|
+
"purpose": "The `NumberFormatter` component writes a number the way a locale writes it, such as a price, a percentage or a count, in a `<data>` element that keeps the…",
|
|
926
|
+
"slug": "elements/numberformatter",
|
|
927
|
+
"import": "import { NumberFormatter, useNumberFormat } from '@allxsmith/bestax-bulma';",
|
|
928
|
+
"compound": false,
|
|
929
|
+
"propCount": 6,
|
|
930
|
+
"exampleCount": 10
|
|
931
|
+
},
|
|
920
932
|
{
|
|
921
933
|
"name": "Numberinput",
|
|
922
934
|
"kind": "component",
|
|
@@ -1388,7 +1400,7 @@
|
|
|
1388
1400
|
"import": "import { TreeView } from '@allxsmith/bestax-bulma';",
|
|
1389
1401
|
"compound": true,
|
|
1390
1402
|
"propCount": 27,
|
|
1391
|
-
"exampleCount":
|
|
1403
|
+
"exampleCount": 10
|
|
1392
1404
|
},
|
|
1393
1405
|
{
|
|
1394
1406
|
"name": "UnorderedList",
|
|
@@ -43,7 +43,13 @@
|
|
|
43
43
|
}
|
|
44
44
|
],
|
|
45
45
|
"accessibility": "- `lang` tells a screen reader which voice and pronunciation to use, and a translation tool what it's reading. The provider puts it on its wrapper and on portaled content, so a dialog or a notification announced from the end of the page comes in the same language.\n- `dir` decides the reading order of the content inside, and which side text starts on. Set the one the content is written in: a left-to-right quote in a right-to-left page needs its own provider or `dir`.\n- The provider changes no focus order and adds no role. The element it wraps portaled content in has `display: contents`, so it adds no box and no landmark.",
|
|
46
|
-
"related": [
|
|
46
|
+
"related": [
|
|
47
|
+
"ConfigProvider",
|
|
48
|
+
"DateInput",
|
|
49
|
+
"NumberFormatter",
|
|
50
|
+
"Portal",
|
|
51
|
+
"Theme"
|
|
52
|
+
],
|
|
47
53
|
"storybook": "https://bestax.io/storybook/?path=/story/helpers-localeprovider--default",
|
|
48
54
|
"summary": "Sets the language and writing direction for the part of the app inside it, on a wrapper `<div>` and on what the library portals out of it. The wrapper carries `dir` and `lang`, so CSS and the components that read the computed direction follow it, as they follow `<html dir>`. A `locale` alone sets the direction of its script, and a `dir` sets the direction whatever the locale. A nested provider keeps whatever it leaves unset. Inside it, the date and time pickers take its `locale` unless given their own, and their week starts on the first day of the locale they use unless `firstDayOfWeek` is set, and a picker with a `locale` of its own is read like a nested provider. With a `locale`, the numbers the library writes, such as page numbers and badge counts, follow it, and so does the filtering in `Combobox`, `Autocomplete`, `Taginput` and `Command`, which then ignores accents where the language treats letters as the same. The library's portaled content, such as a `Popover` panel, a `Modal` with `portal`, a `Toast` or a `Portal`'s children, keeps the same `dir` and `lang` though it renders outside the wrapper: in a container outside the wrapper, it sits in a `display: contents` element that carries them. Without a provider none of this changes.",
|
|
49
55
|
"import": "import { LocaleProvider, useLocale } from '@allxsmith/bestax-bulma';",
|
|
@@ -107,5 +113,5 @@
|
|
|
107
113
|
}
|
|
108
114
|
],
|
|
109
115
|
"cssVars": [],
|
|
110
|
-
"doc": "# LocaleProvider\n\n## Overview\n\n`LocaleProvider` sets the language and writing direction for the part of the app inside it, on a wrapper `<div>` and on what the library portals out of it.\n\nIt takes a `locale` and a `dir`, and each works alone. A `locale` such as `\"ar-EG\"` becomes the wrapper's `lang`, and its script decides the direction, so `dir=\"rtl\"` comes with it. A `dir` sets the direction whatever the locale, for a right-to-left layout with no particular language, or a locale whose script reads one way on a page laid out the other. A nested provider keeps whatever it leaves unset.\n\nThe direction lives on the wrapper as a `dir` attribute, so CSS follows it, and so do the components that read the direction they're laid out in, as they follow `<html dir>`. A page whose `<html>` already has `dir=\"rtl\"` needs no provider for that. What the provider adds is the rest:\n\n- a section of the page in another language or direction than the page around it;\n- the content the library portals to the end of `document.body`, such as a `Popover` panel, a `Modal` with `portal`, a `Toast` or a `Portal`'s children, which leaves the section it came from and gets the provider's `dir` and `lang` back;\n- the date and time pickers inside, which take its `locale` and start the week on that locale's first day;\n- the numbers the library writes, such as page numbers, badge counts and a slider's output, and the filtering in `Combobox`, `Autocomplete`, `Taginput` and `Command`, which follow the `locale` too.\n\nWithout a provider none of this changes: a picker uses the runtime's own locale and starts the week on Sunday, numbers are written as they always have been, and filtering ignores case only.\n\n---\n\n## Import\n\n```tsx\nimport { LocaleProvider, useLocale } from '@allxsmith/bestax-bulma';\n```\n\n---\n\n## Hooks\n\n### useLocale\n\nReturns the `locale` and `dir` the nearest provider sets, both `undefined` outside one. The locale is in its canonical form, so `\"en-us\"` comes back as `\"en-US\"`. Use it for your own `Intl` calls, so they match the components around them, or for `dir` and `lang` on content you portal yourself.\n\n```tsx\nfunction Price({ amount }: { amount: number }) {\n const { locale } = useLocale();\n return (\n <span>\n {new Intl.NumberFormat(locale, {\n style: 'currency',\n currency: 'EUR',\n }).format(amount)}\n </span>\n );\n}\n```\n\nIt isn't the direction of the page: with no provider, or one that sets no direction, `<html dir>` still decides. To act on the direction an element is laid out in, read `getComputedStyle(element).direction`.\n\n---\n\n## Usage\n\n### A Right-to-Left Section\n\nA `locale` alone sets the direction of its script. Arabic reads right to left, so the wrapper gets `dir=\"rtl\"` and `lang=\"ar-EG\"`, and the steps lay out from the right.\n\n```tsx live\n<LocaleProvider locale=\"ar-EG\">\n <Steps\n value={1}\n items={[{ label: 'السلة' }, { label: 'الشحن' }, { label: 'الدفع' }]}\n />\n</LocaleProvider>\n```\n\nThe wrapper is a plain `<div>` with no class of its own. It takes the helper props and any other attributes, and forwards its `ref`.\n\n### Direction Only\n\n`dir` sets the direction and leaves the language alone. It also wins over a `locale`'s own direction.\n\n```tsx live\n<LocaleProvider dir=\"rtl\">\n <Buttons>\n <Button color=\"primary\">First</Button>\n <Button>Second</Button>\n </Buttons>\n</LocaleProvider>\n```\n\n### Nested Providers\n\nAn inner provider keeps whatever it leaves unset. One that sets only a `locale` takes that locale's direction, so a French quote inside a Hebrew section reads left to right, and one that sets only a `dir` keeps the outer locale.\n\n```tsx live\n<LocaleProvider locale=\"he\">\n <Content>\n <p>הציטוט האהוב עליי:</p>\n <LocaleProvider locale=\"fr\">\n <blockquote>La simplicité est la sophistication suprême.</blockquote>\n </LocaleProvider>\n </Content>\n</LocaleProvider>\n```\n\n### Date Pickers\n\nThe date and time pickers take the provider's `locale` unless they have their own, for their day and month names and any `Intl` format. Inside a provider, the week starts on the first day of the locale the picker uses: Monday for `\"de\"`, Saturday for `\"ar-EG\"`, Sunday for `\"en-US\"`. A picker's own `firstDayOfWeek` still wins, and a picker with its own `dayNames` keeps Sunday unless it sets `firstDayOfWeek` too, since it shows those names exactly as given.\n\n```tsx live\n<LocaleProvider locale=\"de\">\n <DateInput inline label=\"Liefertermin\" />\n</LocaleProvider>\n```\n\nOutside a provider a picker keeps Sunday, even with a `locale` of its own, so pages that never asked for a different first day don't get one. The first day comes from a copy of [CLDR](https://cldr.unicode.org/)'s week data that the library carries, rather than from each browser's, because browsers disagree about a few regions, China among them, and a calendar rendered on the server has to come out the same in the browser. A `-u-fw-` extension in the tag, such as `\"en-US-u-fw-mon\"`, picks the day outright.\n\n### Numbers and Matching\n\nWith a `locale`, the numbers the library writes itself are written the way that locale writes them, with its digits and separators: `Pagination`'s page numbers, `Steps` markers, a `Badge` count, the `Avatars` surplus, a `RingProgress` in sections, `Rate`'s score, the `Slider` output, `Taginput`'s counter and the count of files `File` shows. Where an accessible name repeats a number on screen, as a page link's does, it's written the same way, so the name still holds the text. A label function you pass, such as `getPageLabel` or `formatOutput`, takes over as before.\n\n```tsx live\n<LocaleProvider locale=\"ar-EG\">\n <Pagination total={12} current={5} />\n</LocaleProvider>\n```\n\nTyping in `Combobox`, `Autocomplete`, `Taginput` and `Command` filters the list the way the language compares letters: case and accents are ignored where it treats them as the same letter, so \"cafe\" finds \"Café\", while in Swedish \"a\" doesn't find \"å\", a letter of its own there. Vowel marks the language leaves out of comparisons, such as Arabic harakat and Hebrew niqqud, don't count on either side, so a name typed without them finds one written with them, and the other way round.\n\n```tsx live\n<LocaleProvider locale=\"fr\">\n <Combobox\n label=\"Boisson\"\n data={['Café', 'Thé', 'Chocolat chaud']}\n placeholder=\"Tapez « the »\"\n />\n</LocaleProvider>\n```\n\nThe pickers' digits stay as they are: their typed text is a token format of ASCII digits, and a calendar in another set of digits would sit under it. Numbers inside the library's English labels that aren't on screen, such as a carousel slide's \"1 of 3\", stay as they are too, since they get translated together with their words.\n\n### Portaled Content\n\nWhat the library portals renders outside the provider's wrapper, at the end of `document.body` or in the `portalContainer` a [`ConfigProvider`](https://bestax.io/docs/api/helpers/config) sets. Inside a provider, that content keeps the provider's `dir` and `lang`. That covers a `Portal`'s children, a `Popover`, `HoverCard` or `ContextMenu` panel, a `Combobox` menu or picker popover with `appendToBody`, a `Modal` or `Dialog` with `portal`, a `Sidebar`, and toasts and notifications.\n\nA container inside the provider's own wrapper takes the content as it is, and the content follows the provider through the page. Any other, `document.body` included, gets it inside one `<div>` carrying the values, with `display: contents`, so it adds no box and changes no layout. It is still an element, though, so content that must be its container's direct child, such as a `<tr>` portaled into a `<tbody>`, belongs in a container inside the provider. Which of the two is settled when the content mounts: switching the locale while a dialog or a toast is open updates that `<div>` in place, so what's open keeps its typed text, focus and timers.\n\n```tsx live\n<LocaleProvider locale=\"fa\">\n <Popover trigger={<Button>جزئیات</Button>} appendToBody ariaLabel=\"جزئیات\">\n <Popover.Body>\n این پنل بیرون از بخش رندر میشود و همچنان راستبهچپ است.\n </Popover.Body>\n </Popover>\n</LocaleProvider>\n```\n\nA date or time picker with a `locale` of its own is read the way a nested provider is: its popover, portaled or not, and an inline calendar take its `lang`, and the direction of its locale unless it has a `dir` of its own. So a French picker in an Arabic section shows a French calendar laid out left to right.\n\nFor content you portal yourself without `Portal`, put the values from `useLocale()` on it.\n\n### Server Rendering\n\nThe wrapper's `dir` and `lang` come from its props, so the server and the browser write the same ones, and portaled content only renders after hydration.\n\nSet a `locale` when an `inline` picker renders on the server. With none, `Intl` names its days in the runtime's own language, which is the server's on the server and the reader's in the browser, and the two renders don't match when those differ. With a locale they match, as long as the server's `Intl` data and the browser's spell the names alike. They don't always: Node and Safari write the short name for Saturday differently in Arabic. Where that matters, pass the picker its own `dayNames`, and with them the `firstDayOfWeek` they start on. The calendar shows `dayNames` exactly as given, from the first column, so a picker that brings its own keeps the week on Sunday, as it did before the provider, unless `firstDayOfWeek` says otherwise.\n\n```tsx live\n<LocaleProvider locale=\"ar-EG\">\n <DateInput\n inline\n label=\"تاريخ التسليم\"\n firstDayOfWeek={6}\n dayNames={[\n 'السبت',\n 'الأحد',\n 'الاثنين',\n 'الثلاثاء',\n 'الأربعاء',\n 'الخميس',\n 'الجمعة',\n ]}\n />\n</LocaleProvider>\n```\n\nFor an app that's in one language throughout, also set `lang` and `dir` on `<html>` in your page shell. That reaches what sits outside any provider, and the provider still carries them onto portaled content.\n\nIn the Next.js App Router, render it straight from the root layout, which stays a Server Component. `LocaleProvider` holds React context, so it's a client component, and bestax-bulma marks it one, so the layout can render it without a `'use client'` wrapper of its own. The `locale` and `children` here are values a Server Component can pass. It also takes the wrapper `<div>`'s attributes, and an event handler among them can't cross from a Server Component, so set one from a client component:\n\n```tsx title=\"app/layout.tsx\"\nimport type { ReactNode } from 'react';\nimport { LocaleProvider } from '@allxsmith/bestax-bulma';\n\nexport default function RootLayout({ children }: { children: ReactNode }) {\n return (\n <html lang=\"ar-EG\" dir=\"rtl\">\n <body>\n <LocaleProvider locale=\"ar-EG\">{children}</LocaleProvider>\n </body>\n </html>\n );\n}\n```\n\n### A Locale Intl Doesn't Accept\n\nA tag `Intl` refuses, such as `\"en_US\"` with an underscore, is ignored: the provider writes no `lang`, keeps an outer provider's locale, and warns once in development. A picker's own `locale` isn't checked this way, and `Intl` throws on such a tag when the picker formats with it, as it always has.\n\n---\n\n## Accessibility\n\n- `lang` tells a screen reader which voice and pronunciation to use, and a translation tool what it's reading. The provider puts it on its wrapper and on portaled content, so a dialog or a notification announced from the end of the page comes in the same language.\n- `dir` decides the reading order of the content inside, and which side text starts on. Set the one the content is written in: a left-to-right quote in a right-to-left page needs its own provider or `dir`.\n- The provider changes no focus order and adds no role. The element it wraps portaled content in has `display: contents`, so it adds no box and no landmark.\n\n---\n\n## Related Components\n\n- [`ConfigProvider`](https://bestax.io/docs/api/helpers/config): The class prefix, icon library and portal container. A nested one replaces the outer one's settings, which is why the locale lives here instead.\n- [`Portal`](https://bestax.io/docs/api/helpers/portal): Inside a `LocaleProvider`, its children keep the provider's `dir` and `lang`.\n- [`DateInput`](https://bestax.io/docs/api/form/datetime/dateinput): Takes the provider's locale and first day of the week.\n- [`Theme`](https://bestax.io/docs/api/helpers/theme): Its scoped wrapper is the same idea for CSS variables.\n\n---\n\n## Additional Resources\n\n- [Storybook: LocaleProvider Stories](https://bestax.io/storybook/?path=/story/helpers-localeprovider--default)\n- [W3C: Structural markup and right-to-left text in HTML](https://www.w3.org/International/questions/qa-html-dir)\n- [MDN: the `lang` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/lang)\n- [MDN: `Intl.Locale.prototype.getWeekInfo()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/getWeekInfo)\n\n---\n\n## Props\n\n| Prop | Type | Default | Description |\n| ---------- | ------------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `locale` | `string` | — | A BCP 47 language tag, such as `\"de\"` or `\"ar-EG\"`: the wrapper's `lang`, the pickers' default `locale`, and, with no `dir`, the direction of its script. Unset, a nested provider keeps the outer one's. A tag `Intl` refuses is ignored. |\n| `dir` | `'ltr'` \\| `'rtl'` | — | The direction, whatever the locale. Unset, it follows this provider's `locale`, else an outer provider's direction, else the page's. |\n| `children` | `ReactNode` | — | The part of the app it covers. |\n\nThe helper props, the other attributes of a `<div>` and the `ref` land on the wrapper."
|
|
116
|
+
"doc": "# LocaleProvider\n\n## Overview\n\n`LocaleProvider` sets the language and writing direction for the part of the app inside it, on a wrapper `<div>` and on what the library portals out of it.\n\nIt takes a `locale` and a `dir`, and each works alone. A `locale` such as `\"ar-EG\"` becomes the wrapper's `lang`, and its script decides the direction, so `dir=\"rtl\"` comes with it. A `dir` sets the direction whatever the locale, for a right-to-left layout with no particular language, or a locale whose script reads one way on a page laid out the other. A nested provider keeps whatever it leaves unset.\n\nThe direction lives on the wrapper as a `dir` attribute, so CSS follows it, and so do the components that read the direction they're laid out in, as they follow `<html dir>`. A page whose `<html>` already has `dir=\"rtl\"` needs no provider for that. What the provider adds is the rest:\n\n- a section of the page in another language or direction than the page around it;\n- the content the library portals to the end of `document.body`, such as a `Popover` panel, a `Modal` with `portal`, a `Toast` or a `Portal`'s children, which leaves the section it came from and gets the provider's `dir` and `lang` back;\n- the date and time pickers inside, which take its `locale` and start the week on that locale's first day;\n- the numbers the library writes, such as page numbers, badge counts and a slider's output, and the filtering in `Combobox`, `Autocomplete`, `Taginput` and `Command`, which follow the `locale` too.\n\nWithout a provider none of this changes: a picker uses the runtime's own locale and starts the week on Sunday, numbers are written as they always have been, and filtering ignores case only.\n\n---\n\n## Import\n\n```tsx\nimport { LocaleProvider, useLocale } from '@allxsmith/bestax-bulma';\n```\n\n---\n\n## Hooks\n\n### useLocale\n\nReturns the `locale` and `dir` the nearest provider sets, both `undefined` outside one. The locale is in its canonical form, so `\"en-us\"` comes back as `\"en-US\"`. Use it for your own `Intl` calls, so they match the components around them, or for `dir` and `lang` on content you portal yourself.\n\n```tsx\nfunction Price({ amount }: { amount: number }) {\n const { locale } = useLocale();\n return (\n <span>\n {new Intl.NumberFormat(locale, {\n style: 'currency',\n currency: 'EUR',\n }).format(amount)}\n </span>\n );\n}\n```\n\nFor numbers, [`NumberFormatter`](https://bestax.io/docs/api/elements/numberformatter) and its `useNumberFormat` hook do this for you, and build one formatter for each set of options rather than one on every render.\n\nIt isn't the direction of the page: with no provider, or one that sets no direction, `<html dir>` still decides. To act on the direction an element is laid out in, read `getComputedStyle(element).direction`.\n\n---\n\n## Usage\n\n### A Right-to-Left Section\n\nA `locale` alone sets the direction of its script. Arabic reads right to left, so the wrapper gets `dir=\"rtl\"` and `lang=\"ar-EG\"`, and the steps lay out from the right.\n\n```tsx live\n<LocaleProvider locale=\"ar-EG\">\n <Steps\n value={1}\n items={[{ label: 'السلة' }, { label: 'الشحن' }, { label: 'الدفع' }]}\n />\n</LocaleProvider>\n```\n\nThe wrapper is a plain `<div>` with no class of its own. It takes the helper props and any other attributes, and forwards its `ref`.\n\n### Direction Only\n\n`dir` sets the direction and leaves the language alone. It also wins over a `locale`'s own direction.\n\n```tsx live\n<LocaleProvider dir=\"rtl\">\n <Buttons>\n <Button color=\"primary\">First</Button>\n <Button>Second</Button>\n </Buttons>\n</LocaleProvider>\n```\n\n### Nested Providers\n\nAn inner provider keeps whatever it leaves unset. One that sets only a `locale` takes that locale's direction, so a French quote inside a Hebrew section reads left to right, and one that sets only a `dir` keeps the outer locale.\n\n```tsx live\n<LocaleProvider locale=\"he\">\n <Content>\n <p>הציטוט האהוב עליי:</p>\n <LocaleProvider locale=\"fr\">\n <blockquote>La simplicité est la sophistication suprême.</blockquote>\n </LocaleProvider>\n </Content>\n</LocaleProvider>\n```\n\n### Date Pickers\n\nThe date and time pickers take the provider's `locale` unless they have their own, for their day and month names and any `Intl` format. Inside a provider, the week starts on the first day of the locale the picker uses: Monday for `\"de\"`, Saturday for `\"ar-EG\"`, Sunday for `\"en-US\"`. A picker's own `firstDayOfWeek` still wins, and a picker with its own `dayNames` keeps Sunday unless it sets `firstDayOfWeek` too, since it shows those names exactly as given.\n\n```tsx live\n<LocaleProvider locale=\"de\">\n <DateInput inline label=\"Liefertermin\" />\n</LocaleProvider>\n```\n\nOutside a provider a picker keeps Sunday, even with a `locale` of its own, so pages that never asked for a different first day don't get one. The first day comes from a copy of [CLDR](https://cldr.unicode.org/)'s week data that the library carries, rather than from each browser's, because browsers disagree about a few regions, China among them, and a calendar rendered on the server has to come out the same in the browser. A `-u-fw-` extension in the tag, such as `\"en-US-u-fw-mon\"`, picks the day outright.\n\n### Numbers and Matching\n\nWith a `locale`, the numbers the library writes itself are written the way that locale writes them, with its digits and separators: `Pagination`'s page numbers, `Steps` markers, a `Badge` count, the `Avatars` surplus, a `RingProgress` in sections, `Rate`'s score, the `Slider` output, `Taginput`'s counter and the count of files `File` shows. Where an accessible name repeats a number on screen, as a page link's does, it's written the same way, so the name still holds the text. A label function you pass, such as `getPageLabel` or `formatOutput`, takes over as before.\n\n```tsx live\n<LocaleProvider locale=\"ar-EG\">\n <Pagination total={12} current={5} />\n</LocaleProvider>\n```\n\nNumbers of your own follow it through [`NumberFormatter`](https://bestax.io/docs/api/elements/numberformatter), and through its `useNumberFormat` hook for text outside JSX, such as an `aria-label`. Outside a provider, those write in the runtime's locale, while the library's own numbers stay as they always were.\n\nTyping in `Combobox`, `Autocomplete`, `Taginput` and `Command` filters the list the way the language compares letters: case and accents are ignored where it treats them as the same letter, so \"cafe\" finds \"Café\", while in Swedish \"a\" doesn't find \"å\", a letter of its own there. Vowel marks the language leaves out of comparisons, such as Arabic harakat and Hebrew niqqud, don't count on either side, so a name typed without them finds one written with them, and the other way round.\n\n```tsx live\n<LocaleProvider locale=\"fr\">\n <Combobox\n label=\"Boisson\"\n data={['Café', 'Thé', 'Chocolat chaud']}\n placeholder=\"Tapez « the »\"\n />\n</LocaleProvider>\n```\n\nThe pickers' digits stay as they are: their typed text is a token format of ASCII digits, and a calendar in another set of digits would sit under it. Numbers inside the library's English labels that aren't on screen, such as a carousel slide's \"1 of 3\", stay as they are too, since they get translated together with their words.\n\n### Portaled Content\n\nWhat the library portals renders outside the provider's wrapper, at the end of `document.body` or in the `portalContainer` a [`ConfigProvider`](https://bestax.io/docs/api/helpers/config) sets. Inside a provider, that content keeps the provider's `dir` and `lang`. That covers a `Portal`'s children, a `Popover`, `HoverCard` or `ContextMenu` panel, a `Combobox` menu or picker popover with `appendToBody`, a `Modal` or `Dialog` with `portal`, a `Sidebar`, and toasts and notifications.\n\nA container inside the provider's own wrapper takes the content as it is, and the content follows the provider through the page. Any other, `document.body` included, gets it inside one `<div>` carrying the values, with `display: contents`, so it adds no box and changes no layout. It is still an element, though, so content that must be its container's direct child, such as a `<tr>` portaled into a `<tbody>`, belongs in a container inside the provider. Which of the two is settled when the content mounts: switching the locale while a dialog or a toast is open updates that `<div>` in place, so what's open keeps its typed text, focus and timers.\n\n```tsx live\n<LocaleProvider locale=\"fa\">\n <Popover trigger={<Button>جزئیات</Button>} appendToBody ariaLabel=\"جزئیات\">\n <Popover.Body>\n این پنل بیرون از بخش رندر میشود و همچنان راستبهچپ است.\n </Popover.Body>\n </Popover>\n</LocaleProvider>\n```\n\nA date or time picker with a `locale` of its own is read the way a nested provider is: its popover, portaled or not, and an inline calendar take its `lang`, and the direction of its locale unless it has a `dir` of its own. So a French picker in an Arabic section shows a French calendar laid out left to right.\n\nFor content you portal yourself without `Portal`, put the values from `useLocale()` on it.\n\n### Server Rendering\n\nThe wrapper's `dir` and `lang` come from its props, so the server and the browser write the same ones, and portaled content only renders after hydration.\n\nSet a `locale` when an `inline` picker renders on the server. With none, `Intl` names its days in the runtime's own language, which is the server's on the server and the reader's in the browser, and the two renders don't match when those differ. With a locale they match, as long as the server's `Intl` data and the browser's spell the names alike. They don't always: Node and Safari write the short name for Saturday differently in Arabic. Where that matters, pass the picker its own `dayNames`, and with them the `firstDayOfWeek` they start on. The calendar shows `dayNames` exactly as given, from the first column, so a picker that brings its own keeps the week on Sunday, as it did before the provider, unless `firstDayOfWeek` says otherwise.\n\n```tsx live\n<LocaleProvider locale=\"ar-EG\">\n <DateInput\n inline\n label=\"تاريخ التسليم\"\n firstDayOfWeek={6}\n dayNames={[\n 'السبت',\n 'الأحد',\n 'الاثنين',\n 'الثلاثاء',\n 'الأربعاء',\n 'الخميس',\n 'الجمعة',\n ]}\n />\n</LocaleProvider>\n```\n\nFor an app that's in one language throughout, also set `lang` and `dir` on `<html>` in your page shell. That reaches what sits outside any provider, and the provider still carries them onto portaled content.\n\nIn the Next.js App Router, render it straight from the root layout, which stays a Server Component. `LocaleProvider` holds React context, so it's a client component, and bestax-bulma marks it one, so the layout can render it without a `'use client'` wrapper of its own. The `locale` and `children` here are values a Server Component can pass. It also takes the wrapper `<div>`'s attributes, and an event handler among them can't cross from a Server Component, so set one from a client component:\n\n```tsx title=\"app/layout.tsx\"\nimport type { ReactNode } from 'react';\nimport { LocaleProvider } from '@allxsmith/bestax-bulma';\n\nexport default function RootLayout({ children }: { children: ReactNode }) {\n return (\n <html lang=\"ar-EG\" dir=\"rtl\">\n <body>\n <LocaleProvider locale=\"ar-EG\">{children}</LocaleProvider>\n </body>\n </html>\n );\n}\n```\n\n### A Locale Intl Doesn't Accept\n\nA tag `Intl` refuses, such as `\"en_US\"` with an underscore, is ignored: the provider writes no `lang`, keeps an outer provider's locale, and warns once in development. A `NumberFormatter`'s or `useNumberFormat`'s own `locale` is checked the same way: a tag `Intl` refuses is ignored with a warning, and the number is written in the provider's locale. A picker's own `locale` isn't checked this way, and `Intl` throws on such a tag when the picker formats with it, as it always has.\n\n---\n\n## Accessibility\n\n- `lang` tells a screen reader which voice and pronunciation to use, and a translation tool what it's reading. The provider puts it on its wrapper and on portaled content, so a dialog or a notification announced from the end of the page comes in the same language.\n- `dir` decides the reading order of the content inside, and which side text starts on. Set the one the content is written in: a left-to-right quote in a right-to-left page needs its own provider or `dir`.\n- The provider changes no focus order and adds no role. The element it wraps portaled content in has `display: contents`, so it adds no box and no landmark.\n\n---\n\n## Related Components\n\n- [`ConfigProvider`](https://bestax.io/docs/api/helpers/config): The class prefix, icon library and portal container. A nested one replaces the outer one's settings, which is why the locale lives here instead.\n- [`Portal`](https://bestax.io/docs/api/helpers/portal): Inside a `LocaleProvider`, its children keep the provider's `dir` and `lang`.\n- [`DateInput`](https://bestax.io/docs/api/form/datetime/dateinput): Takes the provider's locale and first day of the week.\n- [`NumberFormatter`](https://bestax.io/docs/api/elements/numberformatter): Writes a number in the provider's locale, and `useNumberFormat` does the same for text outside JSX.\n- [`Theme`](https://bestax.io/docs/api/helpers/theme): Its scoped wrapper is the same idea for CSS variables.\n\n---\n\n## Additional Resources\n\n- [Storybook: LocaleProvider Stories](https://bestax.io/storybook/?path=/story/helpers-localeprovider--default)\n- [W3C: Structural markup and right-to-left text in HTML](https://www.w3.org/International/questions/qa-html-dir)\n- [MDN: the `lang` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/lang)\n- [MDN: `Intl.Locale.prototype.getWeekInfo()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/getWeekInfo)\n\n---\n\n## Props\n\n| Prop | Type | Default | Description |\n| ---------- | ------------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `locale` | `string` | — | A BCP 47 language tag, such as `\"de\"` or `\"ar-EG\"`: the wrapper's `lang`, the pickers' default `locale`, and, with no `dir`, the direction of its script. Unset, a nested provider keeps the outer one's. A tag `Intl` refuses is ignored. |\n| `dir` | `'ltr'` \\| `'rtl'` | — | The direction, whatever the locale. Unset, it follows this provider's `locale`, else an outer provider's direction, else the page's. |\n| `children` | `ReactNode` | — | The part of the app it covers. |\n\nThe helper props, the other attributes of a `<div>` and the `ref` land on the wrapper."
|
|
111
117
|
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "NumberFormatter",
|
|
3
|
+
"kind": "component",
|
|
4
|
+
"category": "elements",
|
|
5
|
+
"slug": "elements/numberformatter",
|
|
6
|
+
"docsUrl": "https://bestax.io/docs/api/elements/numberformatter",
|
|
7
|
+
"examples": [
|
|
8
|
+
{
|
|
9
|
+
"title": "Basic Usage",
|
|
10
|
+
"code": "<NumberFormatter value={1234567.891} />"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"title": "Currencies",
|
|
14
|
+
"code": "<Paragraph>\n Order total:{' '}\n <NumberFormatter\n value={8456.4}\n locale=\"en-US\"\n format={{ style: 'currency', currency: 'USD' }}\n />\n</Paragraph>"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"title": "Percentages, Units and Signs",
|
|
18
|
+
"code": "<DescriptionList>\n <DescriptionList.Item\n label=\"Conversion rate\"\n value={\n <NumberFormatter\n value={0.125}\n locale=\"en-US\"\n format={{ style: 'percent', maximumFractionDigits: 1 }}\n />\n }\n />\n <DescriptionList.Item\n label=\"Average speed\"\n value={\n <NumberFormatter\n value={12}\n locale=\"en-US\"\n format={{ style: 'unit', unit: 'kilometer-per-hour' }}\n />\n }\n />\n <DescriptionList.Item\n label=\"Change\"\n value={\n <NumberFormatter\n value={0.034}\n locale=\"en-US\"\n format={{\n style: 'percent',\n signDisplay: 'exceptZero',\n maximumFractionDigits: 1,\n }}\n />\n }\n />\n</DescriptionList>"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"title": "Compact Notation",
|
|
22
|
+
"code": "<DescriptionList>\n {['en-US', 'fr-FR', 'ja-JP', 'de-DE'].map(locale => (\n <DescriptionList.Item\n key={locale}\n label={locale}\n value={\n <NumberFormatter\n value={123456}\n locale={locale}\n format={{ notation: 'compact' }}\n />\n }\n />\n ))}\n</DescriptionList>"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"title": "Locales",
|
|
26
|
+
"code": "<DescriptionList>\n {['en-US', 'de-DE', 'fr-FR', 'en-IN', 'ar-EG', 'ja-JP'].map(locale => (\n <DescriptionList.Item\n key={locale}\n label={locale}\n value={<NumberFormatter value={1234567.891} locale={locale} />}\n />\n ))}\n</DescriptionList>"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"title": "In a LocaleProvider",
|
|
30
|
+
"code": "<LocaleProvider locale=\"fr-FR\">\n <Paragraph>\n Vitesse moyenne :{' '}\n <NumberFormatter\n value={1234.5}\n format={{ style: 'unit', unit: 'kilometer-per-hour' }}\n />\n </Paragraph>\n</LocaleProvider>"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"title": "Helper Props",
|
|
34
|
+
"code": "<Title as=\"p\" size=\"3\">\n <NumberFormatter\n value={0.986}\n locale=\"en-US\"\n format={{ style: 'percent', maximumFractionDigits: 1 }}\n textColor=\"success\"\n colorShade=\"on-scheme\"\n />{' '}\n uptime\n</Title>"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"title": "The useNumberFormat Hook",
|
|
38
|
+
"code": "function example() {\n const format = useNumberFormat('de-DE');\n return (\n <Input\n label=\"Monatliches Budget\"\n placeholder={format(1500, { style: 'currency', currency: 'EUR' })}\n />\n );\n}"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"title": "A Number That Changes",
|
|
42
|
+
"code": "function example() {\n const [items, setItems] = React.useState(1);\n return (\n <>\n <Buttons>\n <Button onClick={() => setItems(n => n + 1)}>Add one</Button>\n </Buttons>\n <Paragraph role=\"status\">\n Total:{' '}\n <NumberFormatter\n value={(items * 1999) / 100}\n locale=\"en-US\"\n format={{ style: 'currency', currency: 'USD' }}\n />\n </Paragraph>\n </>\n );\n}"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"title": "Server Rendering",
|
|
46
|
+
"code": "import type { ReactNode } from 'react';\nimport { LocaleProvider } from '@allxsmith/bestax-bulma';\n\nexport default function RootLayout({ children }: { children: ReactNode }) {\n return (\n <html lang=\"de-DE\">\n <body>\n <LocaleProvider locale=\"de-DE\">{children}</LocaleProvider>\n </body>\n </html>\n );\n}"
|
|
47
|
+
}
|
|
48
|
+
],
|
|
49
|
+
"accessibility": "- **No role:** `<data>` maps to no role, so a screen reader reads the formatted text, with the\n locale's currency symbol, percent sign, units and sign, as it would read the same text anywhere\n else.\n- **Compact notation** is read as written (\"123K\"). Show the exact figure too where it matters.\n- **Language:** a `locale` that differs from the page's language changes how the number is\n written, not the voice that reads it. A passage in another language still needs `lang` on its\n container, which `LocaleProvider` sets.\n- **Not live:** a changing value isn't announced. Wrap the one figure that should be in a\n `role=\"status\"` element, as in [A Number That Changes](https://bestax.io/docs/api/elements/numberformatter#a-number-that-changes).\n- **Not color alone:** for a rise or a fall, write the sign with `signDisplay`, so the direction\n doesn't depend on a `textColor`.",
|
|
50
|
+
"related": [
|
|
51
|
+
"DescriptionList",
|
|
52
|
+
"LocaleProvider",
|
|
53
|
+
"Numberinput",
|
|
54
|
+
"useBulmaClasses"
|
|
55
|
+
],
|
|
56
|
+
"storybook": "https://bestax.io/storybook/?path=/story/elements-numberformatter--default",
|
|
57
|
+
"summary": "The `NumberFormatter` component writes a number the way a locale writes it, such as a price, a percentage or a count, in a `<data>` element that keeps the number itself in its `value`. It formats with `Intl.NumberFormat`, in its own `locale`, else the `LocaleProvider`'s around it, else the runtime's, with `format` as the options. The `<data>` has no role and no class of its own, so a screen reader reads the formatted text and it takes the look of the text around it. For text outside JSX, such as an `aria-label`, `useNumberFormat` gives the same formatting as a function.",
|
|
58
|
+
"import": "import { NumberFormatter, useNumberFormat } from '@allxsmith/bestax-bulma';",
|
|
59
|
+
"sourceFile": "bulma-ui/src/elements/NumberFormatter.tsx",
|
|
60
|
+
"rootClass": null,
|
|
61
|
+
"parts": [
|
|
62
|
+
{
|
|
63
|
+
"path": "NumberFormatter",
|
|
64
|
+
"summary": "The `NumberFormatter` component writes a number the way a locale writes it, such as a price, a percentage or a count, in a `<data>` element that keeps the number itself in its `value`. It formats with `Intl.NumberFormat`, in its own `locale`, else the `LocaleProvider`'s around it, else the runtime's, with `format` as the options. The `<data>` has no role and no class of its own, so a screen reader reads the formatted text and it takes the look of the text around it. For text outside JSX, such as an `aria-label`, `useNumberFormat` gives the same formatting as a function.",
|
|
65
|
+
"component": null,
|
|
66
|
+
"props": [
|
|
67
|
+
{
|
|
68
|
+
"name": "className",
|
|
69
|
+
"type": "string",
|
|
70
|
+
"default": null,
|
|
71
|
+
"description": "Additional CSS classes to apply.",
|
|
72
|
+
"required": false,
|
|
73
|
+
"inherited": false,
|
|
74
|
+
"deprecated": false
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"name": "value",
|
|
78
|
+
"type": "number",
|
|
79
|
+
"default": null,
|
|
80
|
+
"description": "The number. The text is what `Intl.NumberFormat` writes for it, `NaN` and `Infinity` included. The `<data>` element's `value` attribute holds it as `String()` writes it, except that `-0` keeps its sign, so `Number()` reads it back: `1234.5`, `1e+21` for a very large one and `1e-7` for a very small one, `NaN`, `Infinity` and `-0`.",
|
|
81
|
+
"required": false,
|
|
82
|
+
"inherited": false,
|
|
83
|
+
"deprecated": false
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"name": "format",
|
|
87
|
+
"type": "Intl.NumberFormatOptions",
|
|
88
|
+
"default": null,
|
|
89
|
+
"description": "`Intl.NumberFormat` options: a currency, a percentage, a unit, compact notation, the fraction digits, the sign. Options `Intl` refuses, such as `style: 'currency'` with no `currency`, throw its error.",
|
|
90
|
+
"required": false,
|
|
91
|
+
"inherited": false,
|
|
92
|
+
"deprecated": false
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"name": "locale",
|
|
96
|
+
"type": "string",
|
|
97
|
+
"default": null,
|
|
98
|
+
"description": "BCP 47 locale tag. Unset, it's the `locale` of a `LocaleProvider` around it, and with neither, the runtime's own. On a server render that's the server's, so give it a locale, here or through a `LocaleProvider`, where the server's and the browser's can differ. A tag `Intl` refuses, such as `\"en_US\"`, is ignored, with a warning in development, as `LocaleProvider` ignores one.",
|
|
99
|
+
"required": false,
|
|
100
|
+
"inherited": false,
|
|
101
|
+
"deprecated": false
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"name": "textColor",
|
|
105
|
+
"type": "Bulma color | 'inherit' | 'current'",
|
|
106
|
+
"default": null,
|
|
107
|
+
"description": "Text color helper.",
|
|
108
|
+
"required": false,
|
|
109
|
+
"inherited": false,
|
|
110
|
+
"deprecated": false,
|
|
111
|
+
"valuesRef": "helpers/valid-values"
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"name": "bgColor",
|
|
115
|
+
"type": "Bulma color | 'inherit' | 'current'",
|
|
116
|
+
"default": null,
|
|
117
|
+
"description": "Background color helper.",
|
|
118
|
+
"required": false,
|
|
119
|
+
"inherited": false,
|
|
120
|
+
"deprecated": false,
|
|
121
|
+
"valuesRef": "helpers/valid-values"
|
|
122
|
+
}
|
|
123
|
+
],
|
|
124
|
+
"extraProps": [
|
|
125
|
+
{
|
|
126
|
+
"name": "ref",
|
|
127
|
+
"type": "React.Ref<HTMLDataElement>",
|
|
128
|
+
"default": null,
|
|
129
|
+
"description": "Ref forwarded to the `<data>`.",
|
|
130
|
+
"required": false,
|
|
131
|
+
"inherited": false,
|
|
132
|
+
"deprecated": false
|
|
133
|
+
}
|
|
134
|
+
],
|
|
135
|
+
"catchAll": "All standard <data> attributes and Bulma helper props",
|
|
136
|
+
"types": []
|
|
137
|
+
}
|
|
138
|
+
],
|
|
139
|
+
"cssVars": []
|
|
140
|
+
}
|
|
@@ -21,6 +21,10 @@
|
|
|
21
21
|
"title": "Checkboxes",
|
|
22
22
|
"code": "function example() {\n const [checked, setChecked] = useState<string[]>(['projects/read']);\n\n return (\n <>\n <Buttons size=\"small\">\n <Button onClick={() => setChecked(['projects', 'billing'])}>\n Check all\n </Button>\n <Button onClick={() => setChecked([])}>Clear</Button>\n </Buttons>\n <TreeView\n aria-label=\"Permissions\"\n selectionMode=\"checkbox\"\n checked={checked}\n onCheckedChange={setChecked}\n defaultExpanded={['projects']}\n >\n <TreeView.Item value=\"projects\" label=\"Projects\">\n <TreeView.Item value=\"projects/read\" label=\"Read\" />\n <TreeView.Item value=\"projects/write\" label=\"Write\" />\n <TreeView.Item value=\"projects/delete\" label=\"Delete\" disabled />\n </TreeView.Item>\n <TreeView.Item value=\"billing\" label=\"Billing\">\n <TreeView.Item value=\"billing/view\" label=\"View invoices\" />\n <TreeView.Item value=\"billing/pay\" label=\"Pay invoices\" />\n </TreeView.Item>\n </TreeView>\n <Paragraph mt=\"3\" textSize=\"7\">\n Checked: {checked.length ? checked.join(', ') : 'nothing'}\n </Paragraph>\n </>\n );\n}"
|
|
23
23
|
},
|
|
24
|
+
{
|
|
25
|
+
"title": "Checkboxes That Check One Item",
|
|
26
|
+
"code": "function example() {\n const [checked, setChecked] = useState<string[]>([\n 'clothing',\n 'clothing/shoes/running',\n ]);\n\n return (\n <>\n <TreeView\n aria-label=\"Categories\"\n selectionMode=\"checkbox-independent\"\n checked={checked}\n onCheckedChange={setChecked}\n defaultExpanded={['clothing', 'clothing/shoes']}\n >\n <TreeView.Item value=\"clothing\" label=\"Clothing\">\n <TreeView.Item value=\"clothing/shoes\" label=\"Shoes\">\n <TreeView.Item value=\"clothing/shoes/running\" label=\"Running\" />\n <TreeView.Item value=\"clothing/shoes/hiking\" label=\"Hiking\" />\n </TreeView.Item>\n <TreeView.Item value=\"clothing/jackets\" label=\"Jackets\" />\n </TreeView.Item>\n <TreeView.Item value=\"outdoors\" label=\"Outdoors\">\n <TreeView.Item value=\"outdoors/tents\" label=\"Tents\" />\n <TreeView.Item value=\"outdoors/stoves\" label=\"Stoves\" />\n </TreeView.Item>\n </TreeView>\n <Paragraph mt=\"3\" textSize=\"7\">\n Filed under: {checked.length ? checked.join(', ') : 'nothing'}\n </Paragraph>\n </>\n );\n}"
|
|
27
|
+
},
|
|
24
28
|
{
|
|
25
29
|
"title": "Folders That Load",
|
|
26
30
|
"code": "function example() {\n interface Folder {\n id: string;\n name: string;\n hasFolders: boolean;\n }\n\n // A pretend server: each folder holds two more, three levels down.\n const listFolders = (id: string, fail: boolean) =>\n new Promise<Folder[]>((resolve, reject) =>\n setTimeout(() => {\n if (fail) {\n reject(new Error(`Couldn't reach ${id}`));\n return;\n }\n resolve(\n ['a', 'b'].map(name => ({\n id: `${id}/${name}`,\n name: `Folder ${name.toUpperCase()}`,\n hasFolders: id.split('/').length < 3,\n }))\n );\n }, 800)\n );\n\n const [expanded, setExpanded] = useState<string[]>([]);\n // A folder's children, or how loading them is going.\n const [found, setFound] = useState<\n Record<string, Folder[] | 'loading' | 'error'>\n >({});\n // Shared fails the first time, so there's a Retry to press.\n const [sharedFails, setSharedFails] = useState(true);\n\n function load(id: string) {\n const fail = id === 'shared' && sharedFails;\n if (fail) setSharedFails(false);\n setFound(current => ({ ...current, [id]: 'loading' }));\n listFolders(id, fail).then(\n folders => setFound(current => ({ ...current, [id]: folders })),\n () => setFound(current => ({ ...current, [id]: 'error' }))\n );\n }\n\n function changeOpen(next: string[]) {\n setExpanded(next);\n for (const id of next) {\n if (!found[id]) load(id);\n }\n }\n\n const items = (folders: Folder[]): React.ReactNode =>\n folders.map(folder => {\n const state = found[folder.id];\n return (\n <TreeView.Item\n key={folder.id}\n value={folder.id}\n label={folder.name}\n icon=\"folder\"\n hasChildren={folder.hasFolders}\n isLoading={state === 'loading'}\n loadError={\n state === 'error' ? `Couldn't load ${folder.name}` : undefined\n }\n onRetry={() => load(folder.id)}\n >\n {Array.isArray(state) && items(state)}\n </TreeView.Item>\n );\n });\n\n return (\n <TreeView\n aria-label=\"Folders\"\n expanded={expanded}\n onExpandedChange={changeOpen}\n >\n {items([\n { id: 'home', name: 'Home', hasFolders: true },\n { id: 'shared', name: 'Shared', hasFolders: true },\n ])}\n </TreeView>\n );\n}"
|
|
@@ -42,7 +46,7 @@
|
|
|
42
46
|
"code": "<TreeView\n aria-label=\"Files\"\n selectionMode=\"single\"\n defaultSelected=\"src/App.tsx\"\n defaultExpanded={['src']}\n>\n <TreeView.Item value=\"src\" label=\"src\" icon=\"folder\">\n <TreeView.Item value=\"src/index.ts\" label=\"index.ts\" icon=\"file\" />\n <TreeView.Item value=\"src/App.tsx\" label=\"App.tsx\" icon=\"file\" />\n <TreeView.Item value=\"src/legacy.ts\" label=\"legacy.ts\" disabled />\n </TreeView.Item>\n <TreeView.Item value=\"package.json\" label=\"package.json\" icon=\"file\" />\n</TreeView>"
|
|
43
47
|
}
|
|
44
48
|
],
|
|
45
|
-
"accessibility": "`TreeView` follows the [APG Tree View Pattern](https://www.w3.org/WAI/ARIA/apg/patterns/treeview/).\n\n- **Roles:** the root is a `<ul role=\"tree\">`, each item an `<li role=\"treeitem\">`, and an open\n parent's children sit in a `<ul role=\"group\">` inside it. A closed item's children have no\n markup.\n- **A name:** a tree needs one, from `aria-label` or `aria-labelledby`, and a development build\n warns when it has neither. Each item is named by `aria-labelledby` pointing at its own label, and\n declares its `aria-level`, which VoiceOver needs according to\n [GitHub's testing](https://github.blog/engineering/user-experience/considerations-for-making-a-tree-view-component-accessible/).\n `aria-expanded` is on parents only.\n- **Positions:** each item also declares `aria-posinset` and `aria-setsize`, its place among the\n items beside it, so a screen reader that doesn't work positions out for itself still has them.\n The tree reads them off the page once it mounts, and again whenever items open, close, load or\n move, so server markup leaves them to the browser until then. They're the values a browser works\n out on its own: a loading row or a failed load's row counts with the items beside it. When the\n page holds only part of a set, such as the first page of a long folder, pass both on every item\n of that set: yours win, and the tree's own stay on any item without them.\n- **One tab stop, with real focus:** one item holds `tabIndex={0}` and the rest `-1`, and focus\n moves from item to item, rather than through `aria-activedescendant`. When focus comes into the\n tree, it lands on the selected item, or in a checkbox tree on the first checked item on the page.\n Without one, it lands where focus last was, or on the first item. If the item holding the stop\n goes away, its nearest ancestor on the page takes it, and focus goes too if it had focus.\n- **Selection:** a `single` tree marks each enabled item `aria-selected`, `true` or `false`. A\n `checkbox` tree marks `aria-checked` on every item, `true`, `false` or `mixed`, disabled ones\n included, and adds `aria-multiselectable=\"true\"` to the tree. A tree never has both, and a tree\n with no `selectionMode` has neither. Selection doesn't follow focus.\n- **The box** is a [`Checkbox`](https://bestax.io/docs/api/form/checkbox) inside an `aria-hidden` span, with\n `tabIndex={-1}`, so it's neither a tab stop nor a second thing for a screen reader to read. The\n item's `aria-checked` is what a screen reader hears.\n- **Disabled items** are `aria-disabled` and stay reachable from the arrow keys, Home, End and\n typing, so a screen reader user finds them. They're never selected, checked, opened or closed.\n One that's already open stays open, so what's under it is still reachable. In a `single` tree a\n disabled item has no `aria-selected`. In a `checkbox` tree it keeps `aria-checked`, so the state\n its box shows is heard as well as seen, such as \"checked, disabled\".\n- **A loading item's row** is a `treeitem` that says Loading…, marked `aria-disabled` and reached\n the way a disabled item is, so a screen reader user who moves into the folder hears what's\n happening. It has no value: it's never selected or checked, it has no `aria-selected` or\n `aria-checked`, and a checkbox tree doesn't count it. If it goes with focus on it, focus moves to\n the item it was loading for. Bulma's loader turns in its chevron's place, hidden from assistive\n tech.\n- **A failed load's row** is a `treeitem` named by its message and the Retry button's text, such\n as \"Couldn't load src Retry\". Enter, Space or a click on the row calls `onRetry`, in every mode.\n The button is drawn inside an `aria-hidden` span and takes no focus, the way an item's box is,\n so the tree keeps its one tab stop, and nothing in the message should be a link or a button\n either. A retry that starts loading keeps the same row, so focus stays on it. With no `onRetry`,\n the row is disabled and shows the message alone.\n- **Announcements:** a visually hidden `role=\"status\"` region with `aria-live=\"polite\"` sits right\n after the tree, one for the whole tree, from the moment it mounts, so a screen reader is already\n listening when something is written into it. It says \"Loading src\" when an open item starts\n loading, a failed load's message, and \"src loaded\" when the loading row or a failed load's row\n goes with the item still open.\n The name is the item's label as a screen reader reads it. A closed item, or one in a closed\n branch, says nothing. Each announcement is written a moment after the change and cleared soon\n after, so the page doesn't keep a second copy of the text. A selection or a check isn't written\n there: it changes `aria-selected` or `aria-checked` on the focused item, which a screen reader\n reads out again, as the simulated one below does.\n\nEnter and Space do the item's one thing, which depends on the mode:\n\n| Key | No `selectionMode` | `single` | `checkbox` |\n| ----- | ------------------------ | ---------------- | ------------------------ |\n| Enter | Opens or closes a parent | Selects the item | Opens or closes a parent |\n| Space | Opens or closes a parent | Selects the item | Checks or unchecks it |\n\nOn a failed load's row, both retry, whatever the mode. The rest work the same in every mode:\n\n| Key | What it does |\n| ---------- | ----------------------------------------------------------------------------------------- |\n| Down, Up | The next or previous item on the page, without wrapping |\n| Right | Opens a closed parent, and focus stays. On an open parent, moves to its first child |\n| Left | Closes an open parent. Otherwise moves to its parent |\n| Home, End | The first item, and the last one on the page |\n| `*` | Opens every closed parent beside the focused item, itself included. Focus stays |\n| Characters | Moves to the next item whose label starts with what's typed, several characters adding up |\n| Tab | Leaves the tree |\n\n- **Right to left:** Right and Left swap in a right-to-left page, and the chevron points to the\n left while closed.\n- **Keys it leaves alone:** anything with Control, Alt or Meta held, anything while an input method\n is composing, and Escape, so it reaches a Modal or Popover around the tree. An item's own\n `onKeyDown` runs first, and calling `preventDefault()` there keeps the tree from acting on the\n key.\n- **Clicks:** the chevron only opens and closes. The rest of the row does the item's one thing:\n opens or closes it with no `selectionMode`, selects it (and opens or closes a parent) in a\n `single` tree, and checks it in a `checkbox` tree. A click moves focus and the tab stop to the\n item.\n- **Not for site navigation:** APG's own\n [navigation tree example](https://www.w3.org/WAI/ARIA/apg/patterns/treeview/examples/treeview-navigation/)\n says \"A pattern more suited for typical site navigation with expandable groups of links is the\n disclosure pattern\", and a tree's items aren't links. Keep a sidebar on [`Menu`](https://bestax.io/docs/api/components/menu),\n whose `Menu.Section` is that disclosure pattern.\n- **Focus and the selected look differ:** the focus ring sits outside the row, so it shows on the\n selected fill as well as on a plain row.\n- **Forced colors:** in Windows high contrast mode the selected row is the system's Highlight and\n HighlightText, a disabled row or a loading one is GrayText, and the focus ring, the chevrons and\n the guide lines stay visible, since they're outlines and borders. A mixed box keeps its dash, and\n the loader's ring stays open.\n- **Motion:** the chevron turns with a short transition, and the loader spins. Both stop when the\n reader asks for reduced motion, and the loader stays drawn.\n\n**What a screen reader says.** What follows is simulated, with\n[Guidepup's Virtual Screen Reader](https://www.guidepup.dev/docs/virtual) 0.33.0, which reads the\naccessibility tree the way the ARIA and HTML specs describe. It isn't a recording of NVDA, JAWS\nor VoiceOver, and each of those words things its own way. The library's tests press these keys\nthrough it on the FileBrowser, Permissions and DeepTree stories, and fail if what it says changes.\n\n1. **Onto a closed parent, then Right and Left:** \"treeitem, helpers, not expanded, level 2,\n position 2, not selected, set size 3\". Right reads it again as \"expanded\" and Left as \"not\n expanded\", with focus staying on it. The items that appear are read when focus reaches them.\n2. **Enter and Space with no `selectionMode`:** each press on a parent reads it again with its new\n state, \"treeitem, src, not expanded, level 1, position 1, set size 4\", then \"expanded\". A tree\n with no selection says nothing about one.\n3. **A level deeper and back up:** Right from components reads its first child, \"treeitem,\n Button.tsx, level 3, position 1, not selected, set size 3\", and Left goes back to \"treeitem,\n components, expanded, level 2, position 1, not selected, set size 3\".\n4. **Enter in a `single` tree:** the item is read again, \"treeitem, TreeView.tsx, level 3, position\n 3, selected, set size 3\". The item that lost the selection says \"not selected\" when focus gets\n back to it.\n5. **Space in a `checkbox` tree:** the item is read again as \"checked\". Its parent turns mixed\n without a word, and Left to it reads \"treeitem, Billing, partially checked, expanded, level 1,\n position 2, set size 2\". Space on the parent reads \"checked\", and so does each item under it as\n focus reaches it.\n6. **A disabled item:** in a `single` tree, \"treeitem, legacy.ts, disabled, level 2, position 3, set\n size 3\", with no selection state. In a `checkbox` tree, \"treeitem, Delete, not checked,\n disabled, level 4, position 3, set size 3\", or \"checked, disabled\" for one its own value checks.\n Enter and Space on it change nothing and say nothing.\n7. **Positions:** each item says its place among the items beside it, such as \"position 2\" and \"set\n size 3\", at every level.\n8. **Tab in and back out, with an item selected:** Tab lands on the selected item, \"treeitem,\n Card.tsx, level 3, position 2, selected, set size 3\", and Tab again leaves the tree for the next\n control. Shift+Tab comes back to Card.tsx, wherever focus was in the tree before.\n\nStill open in [#1171](https://github.com/allxsmith/bestax/issues/1171): recordings with NVDA, JAWS\nand VoiceOver on macOS and iOS, a real Windows contrast theme in place of Chromium's forced colors\nemulation, and runs in Firefox and Safari.",
|
|
49
|
+
"accessibility": "`TreeView` follows the [APG Tree View Pattern](https://www.w3.org/WAI/ARIA/apg/patterns/treeview/).\n\n- **Roles:** the root is a `<ul role=\"tree\">`, each item an `<li role=\"treeitem\">`, and an open\n parent's children sit in a `<ul role=\"group\">` inside it. A closed item's children have no\n markup.\n- **A name:** a tree needs one, from `aria-label` or `aria-labelledby`, and a development build\n warns when it has neither. Each item is named by `aria-labelledby` pointing at its own label, and\n declares its `aria-level`, which VoiceOver needs according to\n [GitHub's testing](https://github.blog/engineering/user-experience/considerations-for-making-a-tree-view-component-accessible/).\n `aria-expanded` is on parents only.\n- **Positions:** each item also declares `aria-posinset` and `aria-setsize`, its place among the\n items beside it, so a screen reader that doesn't work positions out for itself still has them.\n The tree reads them off the page once it mounts, and again whenever items open, close, load or\n move, so server markup leaves them to the browser until then. They're the values a browser works\n out on its own: a loading row or a failed load's row counts with the items beside it. When the\n page holds only part of a set, such as the first page of a long folder, pass both on every item\n of that set: yours win, and the tree's own stay on any item without them.\n- **One tab stop, with real focus:** one item holds `tabIndex={0}` and the rest `-1`, and focus\n moves from item to item, rather than through `aria-activedescendant`. When focus comes into the\n tree, it lands on the selected item, or in either checkbox tree on the first checked item on the\n page.\n Without one, it lands where focus last was, or on the first item. If the item holding the stop\n goes away, its nearest ancestor on the page takes it, and focus goes too if it had focus.\n- **Selection:** a `single` tree marks each enabled item `aria-selected`, `true` or `false`. A\n `checkbox` tree marks `aria-checked` on every item, `true`, `false` or `mixed`, disabled ones\n included, and adds `aria-multiselectable=\"true\"` to the tree. A `checkbox-independent` tree does\n the same, except that `aria-checked` is only ever `true` or `false`: each says whether that item\n is checked, and a parent's says nothing about what's under it. A tree never has both\n `aria-selected` and `aria-checked`, and a tree with no `selectionMode` has neither. Selection\n doesn't follow focus.\n- **The box** is a [`Checkbox`](https://bestax.io/docs/api/form/checkbox) inside an `aria-hidden` span, with\n `tabIndex={-1}`, so it's neither a tab stop nor a second thing for a screen reader to read. The\n item's `aria-checked` is what a screen reader hears.\n- **Disabled items** are `aria-disabled` and stay reachable from the arrow keys, Home, End and\n typing, so a screen reader user finds them. They're never selected, checked, opened or closed.\n One that's already open stays open, so what's under it is still reachable. In a `single` tree a\n disabled item has no `aria-selected`. In either checkbox tree it keeps `aria-checked`, so the\n state its box shows is heard as well as seen, such as \"checked, disabled\".\n- **A loading item's row** is a `treeitem` that says Loading…, marked `aria-disabled` and reached\n the way a disabled item is, so a screen reader user who moves into the folder hears what's\n happening. It has no value: it's never selected or checked, it has no `aria-selected` or\n `aria-checked`, and a checkbox tree doesn't count it. If it goes with focus on it, focus moves to\n the item it was loading for. Bulma's loader turns in its chevron's place, hidden from assistive\n tech.\n- **A failed load's row** is a `treeitem` named by its message and the Retry button's text, such\n as \"Couldn't load src Retry\". Enter, Space or a click on the row calls `onRetry`, in every mode.\n The button is drawn inside an `aria-hidden` span and takes no focus, the way an item's box is,\n so the tree keeps its one tab stop, and nothing in the message should be a link or a button\n either. A retry that starts loading keeps the same row, so focus stays on it. With no `onRetry`,\n the row is disabled and shows the message alone.\n- **Announcements:** a visually hidden `role=\"status\"` region with `aria-live=\"polite\"` sits right\n after the tree, one for the whole tree, from the moment it mounts, so a screen reader is already\n listening when something is written into it. It says \"Loading src\" when an open item starts\n loading, a failed load's message, and \"src loaded\" when the loading row or a failed load's row\n goes with the item still open.\n The name is the item's label as a screen reader reads it. A closed item, or one in a closed\n branch, says nothing. Each announcement is written a moment after the change and cleared soon\n after, so the page doesn't keep a second copy of the text. A selection or a check isn't written\n there: it changes `aria-selected` or `aria-checked` on the focused item, which a screen reader\n reads out again, as the simulated one below does.\n\nEnter and Space do the item's one thing, which depends on the mode:\n\n| Key | No `selectionMode` | `single` | `checkbox` and `checkbox-independent` |\n| ----- | ------------------------ | ---------------- | ------------------------------------- |\n| Enter | Opens or closes a parent | Selects the item | Opens or closes a parent |\n| Space | Opens or closes a parent | Selects the item | Checks or unchecks it |\n\nOn a failed load's row, both retry, whatever the mode. The rest work the same in every mode:\n\n| Key | What it does |\n| ---------- | ----------------------------------------------------------------------------------------- |\n| Down, Up | The next or previous item on the page, without wrapping |\n| Right | Opens a closed parent, and focus stays. On an open parent, moves to its first child |\n| Left | Closes an open parent. Otherwise moves to its parent |\n| Home, End | The first item, and the last one on the page |\n| `*` | Opens every closed parent beside the focused item, itself included. Focus stays |\n| Characters | Moves to the next item whose label starts with what's typed, several characters adding up |\n| Tab | Leaves the tree |\n\n- **Right to left:** Right and Left swap in a right-to-left page, and the chevron points to the\n left while closed.\n- **Keys it leaves alone:** anything with Control, Alt or Meta held, anything while an input method\n is composing, and Escape, so it reaches a Modal or Popover around the tree. An item's own\n `onKeyDown` runs first, and calling `preventDefault()` there keeps the tree from acting on the\n key.\n- **Clicks:** the chevron only opens and closes. The rest of the row does the item's one thing:\n opens or closes it with no `selectionMode`, selects it (and opens or closes a parent) in a\n `single` tree, and checks or unchecks it in either checkbox tree. A click moves focus and the tab\n stop to the item.\n- **Not for site navigation:** APG's own\n [navigation tree example](https://www.w3.org/WAI/ARIA/apg/patterns/treeview/examples/treeview-navigation/)\n says \"A pattern more suited for typical site navigation with expandable groups of links is the\n disclosure pattern\", and a tree's items aren't links. Keep a sidebar on [`Menu`](https://bestax.io/docs/api/components/menu),\n whose `Menu.Section` is that disclosure pattern.\n- **Focus and the selected look differ:** the focus ring sits outside the row, so it shows on the\n selected fill as well as on a plain row.\n- **Forced colors:** in Windows high contrast mode the selected row is the system's Highlight and\n HighlightText, a disabled row or a loading one is GrayText, and the focus ring, the chevrons and\n the guide lines stay visible, since they're outlines and borders. A mixed box keeps its dash, and\n the loader's ring stays open.\n- **Motion:** the chevron turns with a short transition, and the loader spins. Both stop when the\n reader asks for reduced motion, and the loader stays drawn.\n\n**What a screen reader says.** What follows is simulated, with\n[Guidepup's Virtual Screen Reader](https://www.guidepup.dev/docs/virtual) 0.33.0, which reads the\naccessibility tree the way the ARIA and HTML specs describe. It isn't a recording of NVDA, JAWS\nor VoiceOver, and each of those words things its own way. The library's tests press these keys\nthrough it on the FileBrowser, Permissions, DeepTree and Categories stories, and fail if what it\nsays changes.\n\n1. **Onto a closed parent, then Right and Left:** \"treeitem, helpers, not expanded, level 2,\n position 2, not selected, set size 3\". Right reads it again as \"expanded\" and Left as \"not\n expanded\", with focus staying on it. The items that appear are read when focus reaches them.\n2. **Enter and Space with no `selectionMode`:** each press on a parent reads it again with its new\n state, \"treeitem, src, not expanded, level 1, position 1, set size 4\", then \"expanded\". A tree\n with no selection says nothing about one.\n3. **A level deeper and back up:** Right from components reads its first child, \"treeitem,\n Button.tsx, level 3, position 1, not selected, set size 3\", and Left goes back to \"treeitem,\n components, expanded, level 2, position 1, not selected, set size 3\".\n4. **Enter in a `single` tree:** the item is read again, \"treeitem, TreeView.tsx, level 3, position\n 3, selected, set size 3\". The item that lost the selection says \"not selected\" when focus gets\n back to it.\n5. **Space in a `checkbox` tree:** the item is read again as \"checked\". Its parent turns mixed\n without a word, and Left to it reads \"treeitem, Billing, partially checked, expanded, level 1,\n position 2, set size 2\". Space on the parent reads \"checked\", and so does each item under it as\n focus reaches it.\n6. **A disabled item:** in a `single` tree, \"treeitem, legacy.ts, disabled, level 2, position 3, set\n size 3\", with no selection state. In a `checkbox` tree, \"treeitem, Delete, not checked,\n disabled, level 4, position 3, set size 3\", or \"checked, disabled\" for one its own value checks.\n Enter and Space on it change nothing and say nothing.\n7. **Positions:** each item says its place among the items beside it, such as \"position 2\" and \"set\n size 3\", at every level.\n8. **Tab in and back out, with an item selected:** Tab lands on the selected item, \"treeitem,\n Card.tsx, level 3, position 2, selected, set size 3\", and Tab again leaves the tree for the next\n control. Shift+Tab comes back to Card.tsx, wherever focus was in the tree before.\n9. **Space in a `checkbox-independent` tree:** the item is read again as \"checked\", and nothing\n else changes. With both items under it checked, Left to Shoes still reads \"treeitem, Shoes, not\n checked, expanded, level 2, position 1, set size 2\". Space on Shoes reads \"checked\", and\n unchecking Running under it leaves Shoes \"checked\" when focus gets back to it, where a\n `checkbox` tree would read \"partially checked\". No item in this mode is ever partially checked.\n\nStill open in [#1171](https://github.com/allxsmith/bestax/issues/1171): recordings with NVDA, JAWS\nand VoiceOver on macOS and iOS, a real Windows contrast theme in place of Chromium's forced colors\nemulation, and runs in Firefox and Safari.",
|
|
46
50
|
"related": [
|
|
47
51
|
"Checkbox",
|
|
48
52
|
"Collapse",
|
|
@@ -52,14 +56,14 @@
|
|
|
52
56
|
"useBulmaClasses"
|
|
53
57
|
],
|
|
54
58
|
"storybook": "https://bestax.io/storybook/?path=/story/components-treeview--default",
|
|
55
|
-
"summary": "The `TreeView` component renders a tree of items you browse and pick from, the way a file explorer works: one tab stop, the arrow keys to move, and Right and Left to open and close. It's the APG Tree View pattern, drawn to look like Bulma's menu. It isn't for site navigation: items aren't links, and a sidebar whose sections open and close is `Menu`'s job. The root owns which items are open, through `expanded`, `defaultExpanded` and `onExpandedChange`. `selectionMode` picks
|
|
59
|
+
"summary": "The `TreeView` component renders a tree of items you browse and pick from, the way a file explorer works: one tab stop, the arrow keys to move, and Right and Left to open and close. It's the APG Tree View pattern, drawn to look like Bulma's menu. It isn't for site navigation: items aren't links, and a sidebar whose sections open and close is `Menu`'s job. The root owns which items are open, through `expanded`, `defaultExpanded` and `onExpandedChange`. `selectionMode` picks the kind of tree. With `none`, nothing is picked. With `single`, one item is, and `selected` says which. With `checkbox`, each item has a box, a check reaches every enabled item under it, closed branches included, and a parent with some of its items checked is mixed. With `checkbox-independent`, each item has a box that checks that item alone, so a parent means only itself and is never mixed. `selected` is read in a `single` tree only, and `checked` in the two checkbox trees only. Selection never follows focus. Disabled items stay reachable from the keys, so a screen reader finds them. The tree needs a name, from `aria-label` or `aria-labelledby`, and a development build warns when it has neither.",
|
|
56
60
|
"import": "import { TreeView } from '@allxsmith/bestax-bulma';",
|
|
57
61
|
"sourceFile": "bulma-ui/src/components/TreeView.tsx",
|
|
58
62
|
"rootClass": "tree-view",
|
|
59
63
|
"parts": [
|
|
60
64
|
{
|
|
61
65
|
"path": "TreeView",
|
|
62
|
-
"summary": "The `TreeView` component renders a tree of items you browse and pick from, the way a file explorer works: one tab stop, the arrow keys to move, and Right and Left to open and close. It's the APG Tree View pattern, drawn to look like Bulma's menu. It isn't for site navigation: items aren't links, and a sidebar whose sections open and close is `Menu`'s job. The root owns which items are open, through `expanded`, `defaultExpanded` and `onExpandedChange`. `selectionMode` picks
|
|
66
|
+
"summary": "The `TreeView` component renders a tree of items you browse and pick from, the way a file explorer works: one tab stop, the arrow keys to move, and Right and Left to open and close. It's the APG Tree View pattern, drawn to look like Bulma's menu. It isn't for site navigation: items aren't links, and a sidebar whose sections open and close is `Menu`'s job. The root owns which items are open, through `expanded`, `defaultExpanded` and `onExpandedChange`. `selectionMode` picks the kind of tree. With `none`, nothing is picked. With `single`, one item is, and `selected` says which. With `checkbox`, each item has a box, a check reaches every enabled item under it, closed branches included, and a parent with some of its items checked is mixed. With `checkbox-independent`, each item has a box that checks that item alone, so a parent means only itself and is never mixed. `selected` is read in a `single` tree only, and `checked` in the two checkbox trees only. Selection never follows focus. Disabled items stay reachable from the keys, so a screen reader finds them. The tree needs a name, from `aria-label` or `aria-labelledby`, and a development build warns when it has neither.",
|
|
63
67
|
"component": null,
|
|
64
68
|
"props": [
|
|
65
69
|
{
|
|
@@ -73,9 +77,9 @@
|
|
|
73
77
|
},
|
|
74
78
|
{
|
|
75
79
|
"name": "selectionMode",
|
|
76
|
-
"type": "'none' | 'single' | 'checkbox'",
|
|
80
|
+
"type": "'none' | 'single' | 'checkbox' | 'checkbox-independent'",
|
|
77
81
|
"default": "'none'",
|
|
78
|
-
"description": "`none`: nothing is picked, and Enter and Space open and close a parent. `single`: one item, picked with Enter, Space or a click. `checkbox`: any number, checked with Space or a click. A check reaches every enabled item under it, and a parent with some of them checked is mixed.",
|
|
82
|
+
"description": "`none`: nothing is picked, and Enter and Space open and close a parent. `single`: one item, picked with Enter, Space or a click. `checkbox`: any number, checked with Space or a click. A check reaches every enabled item under it, and a parent with some of them checked is mixed. `checkbox-independent`: any number, checked with Space or a click, each box for its own item. A check reaches nothing under it, and no parent is mixed (Mantine's and Ant Design's `checkStrictly`).",
|
|
79
83
|
"required": false,
|
|
80
84
|
"inherited": false,
|
|
81
85
|
"deprecated": false
|
|
@@ -111,7 +115,7 @@
|
|
|
111
115
|
"name": "checked",
|
|
112
116
|
"type": "string[]",
|
|
113
117
|
"default": null,
|
|
114
|
-
"description": "The checked items' values when you hold the state. Read with `checkbox` only. A value checks its item
|
|
118
|
+
"description": "The checked items' values when you hold the state. Read with `checkbox` and `checkbox-independent` only. A value checks its item. In `checkbox`, an enabled item also counts as checked when any item above it is in the list, so a parent's value stands for its whole branch, loaded or not, and a disabled item is checked only by its own value. In `checkbox-independent`, a value checks its own item and nothing else.",
|
|
115
119
|
"required": false,
|
|
116
120
|
"inherited": false,
|
|
117
121
|
"deprecated": false
|
|
@@ -120,7 +124,7 @@
|
|
|
120
124
|
"name": "defaultChecked",
|
|
121
125
|
"type": "string[]",
|
|
122
126
|
"default": "[]",
|
|
123
|
-
"description": "The values checked to begin with, when the tree holds its own state. Read with `checkbox` only.",
|
|
127
|
+
"description": "The values checked to begin with, when the tree holds its own state. Read with `checkbox` and `checkbox-independent` only.",
|
|
124
128
|
"required": false,
|
|
125
129
|
"inherited": false,
|
|
126
130
|
"deprecated": false
|
|
@@ -129,7 +133,7 @@
|
|
|
129
133
|
"name": "onCheckedChange",
|
|
130
134
|
"type": "(checked: string[]) => void",
|
|
131
135
|
"default": null,
|
|
132
|
-
"description": "Called after a check or an uncheck with every item that now shows checked, parents included, plus any earlier value that matches no item the tree knows, left as it was
|
|
136
|
+
"description": "Called after a check or an uncheck. In `checkbox`, with every item that now shows checked, parents included, plus any earlier value that matches no item the tree knows, left as it was, and the order means nothing. In `checkbox-independent`, with the list as it was, the item's value added at the end or every copy of it taken out, and everything else in the same order. Passed back as `checked`, the list shows the same boxes.",
|
|
133
137
|
"required": false,
|
|
134
138
|
"inherited": false,
|
|
135
139
|
"deprecated": false
|
|
@@ -284,7 +288,7 @@
|
|
|
284
288
|
"name": "children",
|
|
285
289
|
"type": "React.ReactNode",
|
|
286
290
|
"default": null,
|
|
287
|
-
"description": "`TreeView.Item`s under this one. Render them whenever you have them, open or not: the tree hides them while it's closed, and a checkbox tree needs them to know what a check reaches.",
|
|
291
|
+
"description": "`TreeView.Item`s under this one. Render them whenever you have them, open or not: the tree hides them while it's closed, and a `checkbox` tree needs them to know what a check reaches.",
|
|
288
292
|
"required": false,
|
|
289
293
|
"inherited": false,
|
|
290
294
|
"deprecated": false
|
|
@@ -176,12 +176,16 @@ or lays something out by side, reads `getComputedStyle(element).direction` when
|
|
|
176
176
|
pointer arrives, and uses logical properties (`margin-inline-start`, `inset-inline-end`) in its
|
|
177
177
|
CSS, so `<html dir>` works with or without a provider.
|
|
178
178
|
|
|
179
|
+
For numbers, use `useNumberFormat()` rather than an `Intl.NumberFormat` of your own. It returns a
|
|
180
|
+
function that writes in the `locale` you pass it, else the provider's, else the runtime's. The
|
|
181
|
+
function is the same from render to render for one locale, and it shares one formatter for each
|
|
182
|
+
locale and set of options. In JSX, `<NumberFormatter value format locale>` writes the same text in
|
|
183
|
+
a `<data value>` element. Inside the library, `library-contributor.md` says which hook a component
|
|
184
|
+
takes.
|
|
185
|
+
|
|
179
186
|
```tsx
|
|
180
|
-
const
|
|
181
|
-
const total =
|
|
182
|
-
style: 'currency',
|
|
183
|
-
currency: 'EUR',
|
|
184
|
-
}).format(amount);
|
|
187
|
+
const format = useNumberFormat();
|
|
188
|
+
const total = format(amount, { style: 'currency', currency: 'EUR' });
|
|
185
189
|
```
|
|
186
190
|
|
|
187
191
|
## Holding focus: `useFocusTrap`
|
|
@@ -37,7 +37,7 @@ instead of hand-writing markup.
|
|
|
37
37
|
- Raw `*Base` form exports (`InputBase`, `SelectBase`, `TextAreaBase`, …) are
|
|
38
38
|
escape-hatch variants of the convenience wrappers above them; see the Form docs.
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
119 documented components. Generated from the API docs — every exported
|
|
41
41
|
component is guaranteed to appear (the generator fails if one lacks an API page).
|
|
42
42
|
|
|
43
43
|
## Elements
|
|
@@ -63,6 +63,7 @@ component is guaranteed to appear (the generator fails if one lacks an API page)
|
|
|
63
63
|
- [ListItem](https://bestax.io/docs/api/elements/listitem) — The `ListItem` component renders a styled list item (`<li>`) element with Bulma helper class integration.
|
|
64
64
|
- [Loader](https://bestax.io/docs/api/elements/loader) — The `Loader` component renders Bulma's `.loader`, a small spinning ring for inline loading states.
|
|
65
65
|
- [Notification](https://bestax.io/docs/api/elements/notification) — The `Notification` component is a Bulma-styled alert/message area for providing feedback, warnings, or information to users.
|
|
66
|
+
- [NumberFormatter](https://bestax.io/docs/api/elements/numberformatter) — The `NumberFormatter` component writes a number the way a locale writes it, such as a price, a percentage or a count…
|
|
66
67
|
- [OrderedList](https://bestax.io/docs/api/elements/orderedlist) — The `OrderedList` component renders a styled ordered list (`<ol>`) element with Bulma helper class integration.
|
|
67
68
|
- [Paragraph](https://bestax.io/docs/api/elements/paragraph) — The `Paragraph` component renders a styled `<p>` element with Bulma helper class integration.
|
|
68
69
|
- [Pre](https://bestax.io/docs/api/elements/pre) — The `Pre` component renders a styled `<pre>` element with Bulma helper class integration.
|
|
@@ -178,6 +178,17 @@ Rules that keep components consistent:
|
|
|
178
178
|
`LocaleProvider` around it reach content that has left its wrapper. `Portal` already does.
|
|
179
179
|
Outside a provider the scope renders its children alone, so the markup there doesn't change.
|
|
180
180
|
|
|
181
|
+
- **Numbers go through the locale hooks** in `helpers/localeFormat.ts`, never
|
|
182
|
+
`toLocaleString()` or an `Intl.NumberFormat` of the component's own, so they follow a
|
|
183
|
+
`LocaleProvider` and share the formatter cache. Which hook depends on the component's job. A
|
|
184
|
+
component whose job is to write a number, such as `NumberFormatter` or a stat, uses the public
|
|
185
|
+
`useNumberFormat`, or renders `NumberFormatter`, and so writes in the runtime's locale outside a
|
|
186
|
+
provider, as the pickers do. Any other component that shows a number in passing, such as a
|
|
187
|
+
badge count, a page number or a step's number, uses the internal `useScopedNumberFormat`. It
|
|
188
|
+
returns `null` outside a provider and inside one that gives no locale, and the component then
|
|
189
|
+
writes the number as it always has, so `LocaleProvider`'s promise that nothing changes without
|
|
190
|
+
one holds.
|
|
191
|
+
|
|
181
192
|
- **Direction comes from the DOM.** A component that handles Left and Right, or places things by
|
|
182
193
|
side, reads `getComputedStyle(el).direction` when the key or pointer arrives, as `Splitter` and
|
|
183
194
|
`useTreeView` do, and uses logical properties or `:dir(rtl)` in its SCSS. It never reads
|
|
@@ -126,11 +126,22 @@ Centered; a collection of items → Card grid. For mixed requests, pick the domi
|
|
|
126
126
|
`DescriptionList.Value` children. Several records with the same fields stay a `Table`, and so
|
|
127
127
|
do facts a screen reader must announce with their labels, as a `Table` with `scope="row"`
|
|
128
128
|
headers.
|
|
129
|
+
- **A number shown to the reader (a price, a total, a count, a percentage, a dashboard figure) is
|
|
130
|
+
`NumberFormatter`**, not `toLocaleString()` or an `Intl.NumberFormat` built by hand:
|
|
131
|
+
`<NumberFormatter value={8456.4} format={{ style: 'currency', currency: 'USD' }} />`, with any
|
|
132
|
+
`Intl.NumberFormat` options in `format` (`style: 'percent'` takes a fraction, `0.125` for
|
|
133
|
+
12.5%). It writes in its own `locale`, else the `LocaleProvider`'s, else the runtime's, so a
|
|
134
|
+
server-rendered app sets a `locale` on a `LocaleProvider` at the root. Its text is the number
|
|
135
|
+
alone, so words go around it: `Total: <NumberFormatter … />`. Text that can't hold an element,
|
|
136
|
+
an `aria-label` or a `placeholder`, gets the same from `const format = useNumberFormat();` and
|
|
137
|
+
`format(1500, { style: 'currency', currency: 'EUR' })`.
|
|
129
138
|
- **A file browser, a checkbox tree (permissions, filters) or an outline you browse is
|
|
130
139
|
`TreeView`**, with `<TreeView.Item value="…" label="…" icon="folder">` items nested inside each
|
|
131
140
|
other: `<TreeView aria-label="Files" selectionMode="single">` with `selected`/`onSelectedChange`
|
|
132
141
|
picks one, and `selectionMode="checkbox"` with `checked`/`onCheckedChange` draws boxes with
|
|
133
|
-
mixed parents, where a parent's value checks its whole branch.
|
|
142
|
+
mixed parents, where a parent's value checks its whole branch. For categories, where checking a
|
|
143
|
+
parent means only the parent, `selectionMode="checkbox-independent"` draws a box per item that
|
|
144
|
+
checks that item alone, with no mixed parents. Map the data with a recursive
|
|
134
145
|
function, and render an item's children whether it's open or not. A folder that loads when it
|
|
135
146
|
opens takes `hasChildren`, `isLoading` while its children are on their way, and
|
|
136
147
|
`loadError="Couldn't load src"` with `onRetry` when the load fails, setting `isLoading` again
|
|
@@ -192,7 +192,7 @@ value is flagged. The same conversion covers the modifiers bestax has no prop fo
|
|
|
192
192
|
bloomer forwarded no refs. bestax forwards a ref from the form controls, plus `Avatar`, `Button`,
|
|
193
193
|
`Carousel`, `CarouselItem`, `ColorSwatch`, `Command`, `Command.Dialog`, `Command.Input`, `DataTable`, `DescriptionList`, `DescriptionList.Item`, `DescriptionList.Label`, `DescriptionList.Value`, `Dialog`, `Dropdown`, `EmptyState`, `Kbd`, `Kbd.Group`, `Link`,
|
|
194
194
|
`LinkButton`, `Loader`, `LocaleProvider`, `Menu.Item`, `Modal`, `Navbar`, `Navbar.Burger`, `Navbar.Dropdown`,
|
|
195
|
-
`Navbar.Item`, `Navbar.Link`, `RingProgress`, `ScrollArea`, `SegmentedControl`, `SegmentedControl.Segment`, `Sidebar`, `Splitter`, `Splitter.Pane`, `Timeline`,
|
|
195
|
+
`Navbar.Item`, `Navbar.Link`, `NumberFormatter`, `RingProgress`, `ScrollArea`, `SegmentedControl`, `SegmentedControl.Segment`, `Sidebar`, `Splitter`, `Splitter.Pane`, `Timeline`,
|
|
196
196
|
`Timeline.Item`, `Toast`, `ToggleButton`, `TreeView` and `TreeView.Item` — pass `ref` directly on
|
|
197
197
|
those. "The form controls" means the inputs themselves: the `Field`, `Field.Label`, `Field.Body`,
|
|
198
198
|
`Checkboxes` and `Radios` wrappers around them forward nothing.
|
|
@@ -189,7 +189,7 @@ An existing `ref` is passed through untouched — which is safe only where the b
|
|
|
189
189
|
one. rbx forwards a ref on every component; bestax does so on the form controls, plus `Avatar`,
|
|
190
190
|
`Button`, `Carousel`, `CarouselItem`, `ColorSwatch`, `Command`, `Command.Dialog`, `Command.Input`, `DataTable`, `DescriptionList`, `DescriptionList.Item`, `DescriptionList.Label`, `DescriptionList.Value`, `Dialog`, `Dropdown`, `EmptyState`, `Kbd`, `Kbd.Group`,
|
|
191
191
|
`Link`, `LinkButton`, `Loader`, `LocaleProvider`, `Menu.Item`, `Modal`, `Navbar`, `Navbar.Burger`, `Navbar.Dropdown`,
|
|
192
|
-
`Navbar.Item`, `Navbar.Link`, `RingProgress`, `ScrollArea`, `SegmentedControl`, `SegmentedControl.Segment`, `Sidebar`, `Splitter`, `Splitter.Pane`, `Timeline`,
|
|
192
|
+
`Navbar.Item`, `Navbar.Link`, `NumberFormatter`, `RingProgress`, `ScrollArea`, `SegmentedControl`, `SegmentedControl.Segment`, `Sidebar`, `Splitter`, `Splitter.Pane`, `Timeline`,
|
|
193
193
|
`Timeline.Item`, `Toast`, `ToggleButton`, `TreeView` and `TreeView.Item`. "The form controls" there
|
|
194
194
|
means the inputs themselves: the `Field`, `Field.Label`, `Field.Body`, `Checkboxes` and `Radios`
|
|
195
195
|
wrappers around them forward nothing, and `Field` is a target this codemod emits.
|
|
@@ -191,7 +191,7 @@ The same TODO marks a `Heading` that sets `size` and `textSize` both: drop `size
|
|
|
191
191
|
bestax components don't take `domRef`, but many forward a plain `ref` — the form controls, plus
|
|
192
192
|
`Avatar`, `Button`, `Carousel`, `CarouselItem`, `ColorSwatch`, `Command`, `Command.Dialog`, `Command.Input`, `DataTable`, `DescriptionList`, `DescriptionList.Item`, `DescriptionList.Label`, `DescriptionList.Value`, `Dialog`, `Dropdown`, `EmptyState`, `Kbd`,
|
|
193
193
|
`Kbd.Group`, `Link`, `LinkButton`, `Loader`, `LocaleProvider`, `Menu.Item`, `Modal`, `Navbar`, `Navbar.Burger`,
|
|
194
|
-
`Navbar.Dropdown`, `Navbar.Item`, `Navbar.Link`, `RingProgress`, `ScrollArea`, `SegmentedControl`, `SegmentedControl.Segment`,
|
|
194
|
+
`Navbar.Dropdown`, `Navbar.Item`, `Navbar.Link`, `NumberFormatter`, `RingProgress`, `ScrollArea`, `SegmentedControl`, `SegmentedControl.Segment`,
|
|
195
195
|
`Sidebar`, `Splitter`, `Splitter.Pane`, `Timeline`, `Timeline.Item`, `Toast`, `ToggleButton`, `TreeView` and `TreeView.Item`. On
|
|
196
196
|
those, rename `domRef` to `ref` and it works; do not restructure the markup. "The form controls"
|
|
197
197
|
means the inputs themselves: the `Field`, `Field.Label`, `Field.Body`, `Checkboxes` and `Radios`
|
package/data/skills.json
CHANGED
|
@@ -6,16 +6,16 @@
|
|
|
6
6
|
"promptName": "custom-component",
|
|
7
7
|
"dir": "bestax-custom-component",
|
|
8
8
|
"references": [
|
|
9
|
-
{ "id": "api", "file": "references/api.md", "bytes":
|
|
9
|
+
{ "id": "api", "file": "references/api.md", "bytes": 14426 },
|
|
10
10
|
{
|
|
11
11
|
"id": "component-catalog",
|
|
12
12
|
"file": "references/component-catalog.md",
|
|
13
|
-
"bytes":
|
|
13
|
+
"bytes": 23823
|
|
14
14
|
},
|
|
15
15
|
{
|
|
16
16
|
"id": "library-contributor",
|
|
17
17
|
"file": "references/library-contributor.md",
|
|
18
|
-
"bytes":
|
|
18
|
+
"bytes": 22941
|
|
19
19
|
},
|
|
20
20
|
{ "id": "patterns", "file": "references/patterns.md", "bytes": 4601 }
|
|
21
21
|
],
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
{
|
|
94
94
|
"id": "bloomer-prop-map",
|
|
95
95
|
"file": "references/bloomer/prop-map.md",
|
|
96
|
-
"bytes":
|
|
96
|
+
"bytes": 26925
|
|
97
97
|
},
|
|
98
98
|
{
|
|
99
99
|
"id": "bloomer-unmappables",
|
|
@@ -128,7 +128,7 @@
|
|
|
128
128
|
{
|
|
129
129
|
"id": "rbx-prop-map",
|
|
130
130
|
"file": "references/rbx/prop-map.md",
|
|
131
|
-
"bytes":
|
|
131
|
+
"bytes": 15766
|
|
132
132
|
},
|
|
133
133
|
{
|
|
134
134
|
"id": "rbx-unmappables",
|
|
@@ -148,7 +148,7 @@
|
|
|
148
148
|
{
|
|
149
149
|
"id": "react-bulma-components-unmappables",
|
|
150
150
|
"file": "references/react-bulma-components/unmappables.md",
|
|
151
|
-
"bytes":
|
|
151
|
+
"bytes": 14117
|
|
152
152
|
}
|
|
153
153
|
],
|
|
154
154
|
"examples": []
|
package/dist/search.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAIjE,MAAM,MAAM,OAAO,GAAG,WAAW,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;AAE7E,MAAM,WAAW,GAAG;IAClB,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAID;;;GAGG;AACH,eAAO,MAAM,YAAY,GAAI,GAAG,MAAM,WACI,CAAC;AAE3C;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAI5E;AAkJD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAIjE,MAAM,MAAM,OAAO,GAAG,WAAW,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;AAE7E,MAAM,WAAW,GAAG;IAClB,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAID;;;GAGG;AACH,eAAO,MAAM,YAAY,GAAI,GAAG,MAAM,WACI,CAAC;AAE3C;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAI5E;AAkJD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAiE/D,CAAC;AAqBF;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,EACb,KAAK,GAAE,SAAS,MAAM,EAAO,GAC5B,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAyBrB;AAED;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,4EAA4E;IAC5E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AA+BD;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,QAAQ,EAAE,MAAM,GACf,YAAY,EAAE,CAsBhB;AA0FD,wBAAgB,SAAS,CACvB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,eAAe,EAAE,EAC7B,MAAM,EAAE,KAAK,EAAE,EACf,KAAK,EAAE,OAAO,EAAE,EAChB,QAAQ,GAAE,SAAS,YAAY,EAAO,GACrC,GAAG,EAAE,CAiMP;AAoBD;;;;;;;;;;GAUG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,KAAK,SAAI,GAAG,MAAM,EAAE,CAe3E"}
|
package/dist/search.js
CHANGED
|
@@ -209,6 +209,9 @@ export const ALIASES = {
|
|
|
209
209
|
dropdownmenu: ['Dropdown'],
|
|
210
210
|
dropzone: ['Dropzone', 'File'],
|
|
211
211
|
fileupload: ['Dropzone', 'File'],
|
|
212
|
+
// Chakra's and react-intl's names for it.
|
|
213
|
+
formatnumber: ['NumberFormatter'],
|
|
214
|
+
formattednumber: ['NumberFormatter'],
|
|
212
215
|
keyvalue: ['DescriptionList'],
|
|
213
216
|
modaldialog: ['Modal', 'Dialog'],
|
|
214
217
|
offcanvas: ['Sidebar'],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bestax-mcp",
|
|
3
|
-
"version": "1.18.
|
|
3
|
+
"version": "1.18.27",
|
|
4
4
|
"mcpName": "io.github.allxsmith/bestax-mcp",
|
|
5
5
|
"description": "MCP server for @allxsmith/bestax-bulma — component props, examples, CSS variables and agent skills, served offline from a version-pinned index",
|
|
6
6
|
"type": "module",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"@modelcontextprotocol/sdk": "^1.32.2",
|
|
44
44
|
"zod": "^4.6.7",
|
|
45
|
-
"@allxsmith/bestax-bulma": "^5.
|
|
45
|
+
"@allxsmith/bestax-bulma": "^5.58.0"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@types/node": "^26.6.6",
|