@cascivo/mcp 0.1.8 → 0.3.3
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/LICENSE +1 -1
- package/README.md +53 -22
- package/dist/context/accordion.md +93 -0
- package/dist/context/action-sheet.md +117 -0
- package/dist/context/alert-dialog.md +122 -0
- package/dist/context/alert.md +110 -0
- package/dist/context/app-shell.md +98 -0
- package/dist/context/aspect-ratio.md +92 -0
- package/dist/context/avatar-group.md +111 -0
- package/dist/context/avatar.md +100 -0
- package/dist/context/badge.md +119 -0
- package/dist/context/block/console-app.md +66 -0
- package/dist/context/block/dashboard-charts.md +61 -0
- package/dist/context/block/empty-dashboard.md +60 -0
- package/dist/context/block/login-page.md +60 -0
- package/dist/context/block/notification-center.md +61 -0
- package/dist/context/block/page-with-breadcrumb.md +54 -0
- package/dist/context/block/settings-form-page.md +60 -0
- package/dist/context/block/sidebar-app.md +55 -0
- package/dist/context/block/stats-cards.md +61 -0
- package/dist/context/block/users-table-page.md +61 -0
- package/dist/context/blockquote.md +95 -0
- package/dist/context/bottom-sheet.md +112 -0
- package/dist/context/breadcrumb.md +106 -0
- package/dist/context/button-group.md +100 -0
- package/dist/context/button.md +117 -0
- package/dist/context/calendar.md +118 -0
- package/dist/context/card.md +90 -0
- package/dist/context/carousel.md +101 -0
- package/dist/context/chart/area-chart.md +99 -0
- package/dist/context/chart/bar-chart.md +114 -0
- package/dist/context/chart/boxplot.md +82 -0
- package/dist/context/chart/bubble-chart.md +80 -0
- package/dist/context/chart/bullet.md +75 -0
- package/dist/context/chart/calendar.md +79 -0
- package/dist/context/chart/candlestick.md +104 -0
- package/dist/context/chart/combo-chart.md +78 -0
- package/dist/context/chart/funnel.md +87 -0
- package/dist/context/chart/gauge.md +87 -0
- package/dist/context/chart/heatmap.md +77 -0
- package/dist/context/chart/histogram.md +74 -0
- package/dist/context/chart/kpi.md +70 -0
- package/dist/context/chart/line-chart.md +113 -0
- package/dist/context/chart/meter.md +71 -0
- package/dist/context/chart/pie-chart.md +126 -0
- package/dist/context/chart/polar.md +92 -0
- package/dist/context/chart/radar.md +81 -0
- package/dist/context/chart/radial-bar.md +96 -0
- package/dist/context/chart/sankey.md +89 -0
- package/dist/context/chart/scatter-chart.md +90 -0
- package/dist/context/chart/sparkline.md +69 -0
- package/dist/context/chart/stream.md +88 -0
- package/dist/context/chart/sunburst.md +93 -0
- package/dist/context/chart/treemap.md +84 -0
- package/dist/context/chat-bubble.md +116 -0
- package/dist/context/checkbox-card.md +104 -0
- package/dist/context/checkbox.md +104 -0
- package/dist/context/code-snippet.md +118 -0
- package/dist/context/code.md +103 -0
- package/dist/context/collapsible.md +104 -0
- package/dist/context/color-picker.md +101 -0
- package/dist/context/combobox.md +125 -0
- package/dist/context/command-menu.md +121 -0
- package/dist/context/comparison.md +117 -0
- package/dist/context/contained-list.md +103 -0
- package/dist/context/context-menu.md +103 -0
- package/dist/context/copy-button.md +106 -0
- package/dist/context/data-list.md +99 -0
- package/dist/context/data-table.md +149 -0
- package/dist/context/date-picker.md +116 -0
- package/dist/context/date-range-picker.md +113 -0
- package/dist/context/dock.md +117 -0
- package/dist/context/drawer.md +111 -0
- package/dist/context/dropdown.md +96 -0
- package/dist/context/editable.md +101 -0
- package/dist/context/editor/code-editor.md +146 -0
- package/dist/context/editor/highlight.md +74 -0
- package/dist/context/empty-state.md +101 -0
- package/dist/context/fab.md +128 -0
- package/dist/context/field.md +118 -0
- package/dist/context/file-uploader.md +121 -0
- package/dist/context/filter.md +129 -0
- package/dist/context/flow/flow-background.md +103 -0
- package/dist/context/flow/flow-canvas.md +82 -0
- package/dist/context/flow/flow-controls.md +84 -0
- package/dist/context/flow/flow-edge.md +128 -0
- package/dist/context/flow/flow-handle.md +83 -0
- package/dist/context/flow/flow-minimap.md +89 -0
- package/dist/context/flow/flow-node.md +97 -0
- package/dist/context/flow/flow-panel.md +75 -0
- package/dist/context/flow/flow-story.md +145 -0
- package/dist/context/flow/flow.md +139 -0
- package/dist/context/form.md +104 -0
- package/dist/context/header-panel.md +96 -0
- package/dist/context/header.md +104 -0
- package/dist/context/heading.md +107 -0
- package/dist/context/hover-card.md +108 -0
- package/dist/context/icon-button.md +115 -0
- package/dist/context/image.md +115 -0
- package/dist/context/indicator.md +95 -0
- package/dist/context/inline-loading.md +101 -0
- package/dist/context/input-group.md +122 -0
- package/dist/context/input.md +101 -0
- package/dist/context/item.md +109 -0
- package/dist/context/join.md +97 -0
- package/dist/context/kbd.md +100 -0
- package/dist/context/label.md +117 -0
- package/dist/context/layout/app-shell.md +85 -0
- package/dist/context/layout/auth-layout.md +74 -0
- package/dist/context/layout/auto-grid.md +69 -0
- package/dist/context/layout/center.md +67 -0
- package/dist/context/layout/columns.md +70 -0
- package/dist/context/layout/dashboard-layout.md +68 -0
- package/dist/context/layout/grid.md +70 -0
- package/dist/context/layout/masonry.md +70 -0
- package/dist/context/layout/page-header.md +75 -0
- package/dist/context/layout/section.md +69 -0
- package/dist/context/layout/settings-layout.md +68 -0
- package/dist/context/layout/spacer.md +64 -0
- package/dist/context/layout/split-view.md +71 -0
- package/dist/context/layout/stack.md +93 -0
- package/dist/context/link.md +112 -0
- package/dist/context/list.md +109 -0
- package/dist/context/log-viewer.md +124 -0
- package/dist/context/menu-button.md +137 -0
- package/dist/context/menu.md +108 -0
- package/dist/context/menubar.md +92 -0
- package/dist/context/modal.md +96 -0
- package/dist/context/multi-select.md +104 -0
- package/dist/context/native-select.md +118 -0
- package/dist/context/navigation-menu.md +95 -0
- package/dist/context/notification.md +116 -0
- package/dist/context/number-input.md +117 -0
- package/dist/context/otp-input.md +98 -0
- package/dist/context/overflow-menu.md +107 -0
- package/dist/context/pagination.md +123 -0
- package/dist/context/password-input.md +100 -0
- package/dist/context/popover.md +108 -0
- package/dist/context/progress-bar.md +107 -0
- package/dist/context/progress-circle.md +101 -0
- package/dist/context/progress-indicator.md +105 -0
- package/dist/context/progress.md +109 -0
- package/dist/context/prose.md +110 -0
- package/dist/context/pull-to-refresh.md +101 -0
- package/dist/context/qr-code.md +101 -0
- package/dist/context/radial-progress.md +117 -0
- package/dist/context/radio-card.md +95 -0
- package/dist/context/radio.md +94 -0
- package/dist/context/rating-group.md +97 -0
- package/dist/context/relative-time.md +90 -0
- package/dist/context/resizable.md +102 -0
- package/dist/context/scroll-area.md +101 -0
- package/dist/context/search.md +113 -0
- package/dist/context/section/cta.md +83 -0
- package/dist/context/section/feature-grid.md +98 -0
- package/dist/context/section/hero.md +101 -0
- package/dist/context/section/media-masonry.md +77 -0
- package/dist/context/section/page-footer.md +101 -0
- package/dist/context/section/stats-band.md +81 -0
- package/dist/context/segmented-control.md +101 -0
- package/dist/context/select.md +101 -0
- package/dist/context/separator.md +88 -0
- package/dist/context/sheet.md +100 -0
- package/dist/context/shell-header.md +105 -0
- package/dist/context/side-nav.md +134 -0
- package/dist/context/skeleton.md +101 -0
- package/dist/context/skip-nav.md +103 -0
- package/dist/context/slider.md +98 -0
- package/dist/context/spinner.md +89 -0
- package/dist/context/stack.md +96 -0
- package/dist/context/stat.md +101 -0
- package/dist/context/status.md +105 -0
- package/dist/context/steps.md +124 -0
- package/dist/context/structured-list.md +107 -0
- package/dist/context/swap.md +100 -0
- package/dist/context/swipe-item.md +110 -0
- package/dist/context/switcher.md +97 -0
- package/dist/context/tabs.md +93 -0
- package/dist/context/tag.md +110 -0
- package/dist/context/tags-input.md +94 -0
- package/dist/context/text.md +111 -0
- package/dist/context/textarea.md +98 -0
- package/dist/context/tile.md +116 -0
- package/dist/context/time-picker.md +102 -0
- package/dist/context/timeline.md +93 -0
- package/dist/context/toast.md +91 -0
- package/dist/context/toc.md +110 -0
- package/dist/context/toggle-group.md +118 -0
- package/dist/context/toggle.md +103 -0
- package/dist/context/toggletip.md +119 -0
- package/dist/context/tooltip.md +92 -0
- package/dist/context/tree-view.md +107 -0
- package/dist/context/user.md +100 -0
- package/dist/context/visually-hidden.md +90 -0
- package/dist/context.json +22456 -0
- package/dist/index.d.mts +5 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +374 -64
- package/dist/index.mjs.map +1 -1
- package/dist/marketplace.json +70 -0
- package/dist/registry.json +5622 -786
- package/dist/tokens.catalog.json +2375 -0
- package/dist/tokens.variants.json +3291 -0
- package/package.json +4 -3
- package/readme.body.md +53 -22
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Menu
|
|
2
|
+
|
|
3
|
+
**Category:** overlay
|
|
4
|
+
**Description:** Dropdown menu with keyboard navigation, built on usePopover
|
|
5
|
+
|
|
6
|
+
## When to use
|
|
7
|
+
|
|
8
|
+
- Presenting a list of actions or commands triggered from a button
|
|
9
|
+
- Action lists that need arrow-key navigation and Enter/Space activation
|
|
10
|
+
- Grouping related commands with separators behind a single trigger
|
|
11
|
+
|
|
12
|
+
## When NOT to use
|
|
13
|
+
|
|
14
|
+
- Selecting a persistent value from options — use Select or MultiSelect
|
|
15
|
+
- Right-click contextual actions on an element — use ContextMenu
|
|
16
|
+
- A single non-list action — use a Button
|
|
17
|
+
|
|
18
|
+
## Anti-patterns
|
|
19
|
+
|
|
20
|
+
### Menu items use role="menuitem" and close on activation — they are not selectable options and do not model a chosen value
|
|
21
|
+
|
|
22
|
+
**Bad:** `Using Menu items to pick a form value and showing the choice as selected`
|
|
23
|
+
**Good:** `Use Select for value selection; Menu items are one-shot actions`
|
|
24
|
+
**Why:** Menu items use role="menuitem" and close on activation — they are not selectable options and do not model a chosen value
|
|
25
|
+
|
|
26
|
+
## Related components
|
|
27
|
+
|
|
28
|
+
- **ContextMenu** (alternative): Use ContextMenu for right-click activation on a target element
|
|
29
|
+
- **Select** (alternative): Use Select when the user is choosing a value rather than firing an action
|
|
30
|
+
- **Button** (pairs-with): A button (MenuTrigger) opens the menu
|
|
31
|
+
|
|
32
|
+
## Accessibility rationale
|
|
33
|
+
|
|
34
|
+
The trigger exposes aria-haspopup="menu" and aria-expanded, the panel is role="menu" with role="menuitem" children, focus moves to the first enabled item on open, ArrowUp/ArrowDown rove focus between items, disabled items are aria-disabled and removed from the tab order, and separators use role="separator".
|
|
35
|
+
|
|
36
|
+
## Props
|
|
37
|
+
|
|
38
|
+
| Name | Type | Required | Default | Description |
|
|
39
|
+
| ---------- | ----------------- | -------- | ------- | ------------------------------------------------------------------- |
|
|
40
|
+
| `children` | `React.ReactNode` | Yes | — | The MenuTrigger first, followed by MenuItem/MenuSeparator children. |
|
|
41
|
+
|
|
42
|
+
## Tokens
|
|
43
|
+
|
|
44
|
+
- `--cascivo-color-surface`
|
|
45
|
+
- `--cascivo-color-border`
|
|
46
|
+
- `--cascivo-radius-md`
|
|
47
|
+
- `--cascivo-shadow-md`
|
|
48
|
+
- `--cascivo-motion-enter`
|
|
49
|
+
- `--cascivo-motion-exit`
|
|
50
|
+
- `--cascivo-color-bg-subtle`
|
|
51
|
+
|
|
52
|
+
## Examples
|
|
53
|
+
|
|
54
|
+
### Basic
|
|
55
|
+
|
|
56
|
+
```jsx
|
|
57
|
+
<Menu>
|
|
58
|
+
<MenuTrigger>Options</MenuTrigger>
|
|
59
|
+
<MenuItem onSelect={rename}>Rename</MenuItem>
|
|
60
|
+
<MenuItem onSelect={duplicate}>Duplicate</MenuItem>
|
|
61
|
+
</Menu>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### With separator and disabled item
|
|
65
|
+
|
|
66
|
+
```jsx
|
|
67
|
+
<Menu>
|
|
68
|
+
<MenuTrigger aria-label="More actions">…</MenuTrigger>
|
|
69
|
+
<MenuItem onSelect={share}>Share</MenuItem>
|
|
70
|
+
<MenuSeparator />
|
|
71
|
+
<MenuItem onSelect={remove} disabled>
|
|
72
|
+
Delete
|
|
73
|
+
</MenuItem>
|
|
74
|
+
</Menu>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Boundaries
|
|
78
|
+
|
|
79
|
+
| Area | Level | Note |
|
|
80
|
+
| ------------ | -------- | ------------------------------------------------------------------------------------------ |
|
|
81
|
+
| token names | strict | Surface, border, radius, shadow, and motion must resolve to the listed --cascivo-\* tokens |
|
|
82
|
+
| item content | flexible | MenuItem accepts arbitrary children; onSelect defines the action |
|
|
83
|
+
| composition | flexible | MenuItem and MenuSeparator can be mixed freely under the trigger |
|
|
84
|
+
|
|
85
|
+
## AI context prompt
|
|
86
|
+
|
|
87
|
+
Copy this into an LLM context bar before editing this component:
|
|
88
|
+
|
|
89
|
+
```text
|
|
90
|
+
I am modifying the cascivo Menu component (overlay). Dropdown menu with keyboard navigation, built on usePopover
|
|
91
|
+
|
|
92
|
+
Architecture constraints — follow exactly:
|
|
93
|
+
- Signals only (useSignal/useComputed/useSignalEffect from @cascivo/core). Never useState/useEffect/useContext/useReducer.
|
|
94
|
+
- Style only through --cascivo-* custom properties. No Tailwind, no inline styles, no CSS-in-JS.
|
|
95
|
+
- Responsive via @container queries on the canonical scale (30rem/40rem/64rem/80rem). Do not use global viewport @media breakpoints.
|
|
96
|
+
- Visual states (hover/focus/active/disabled) via CSS pseudo-classes, not JS.
|
|
97
|
+
- CSS logical properties only (RTL-safe).
|
|
98
|
+
|
|
99
|
+
Menu is strictly bound to these tokens — use only these, do not invent token names:
|
|
100
|
+
--cascivo-color-surface, --cascivo-color-border, --cascivo-radius-md, --cascivo-shadow-md, --cascivo-motion-enter, --cascivo-motion-exit, --cascivo-color-bg-subtle
|
|
101
|
+
|
|
102
|
+
Accessibility: role "menu", WCAG 2.2-AA, keyboard: ArrowDown/ArrowUp/Enter/Space/Escape. Keep it AA.
|
|
103
|
+
|
|
104
|
+
Do not change (strict): token names — Surface, border, radius, shadow, and motion must resolve to the listed --cascivo-* tokens
|
|
105
|
+
Flexible: item content, composition.
|
|
106
|
+
|
|
107
|
+
Do not invent props, tokens, or global viewport media queries.
|
|
108
|
+
```
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Menubar
|
|
2
|
+
|
|
3
|
+
**Category:** navigation
|
|
4
|
+
**Description:** Horizontal application menu bar with keyboard-navigable dropdown menus
|
|
5
|
+
|
|
6
|
+
## When to use
|
|
7
|
+
|
|
8
|
+
- A persistent application-style command bar (File / Edit / View) where each top-level entry opens a menu of actions
|
|
9
|
+
- Desktop-like apps that expose grouped commands across a horizontal bar
|
|
10
|
+
|
|
11
|
+
## When NOT to use
|
|
12
|
+
|
|
13
|
+
- Site or section navigation between pages or destinations — use NavigationMenu
|
|
14
|
+
- A single trigger that opens one menu of actions — use a Menu/Dropdown
|
|
15
|
+
- Switching between peer content panels — use Tabs
|
|
16
|
+
|
|
17
|
+
## Anti-patterns
|
|
18
|
+
|
|
19
|
+
### menubar implies commands/actions within the current view, not navigation to other pages
|
|
20
|
+
|
|
21
|
+
**Bad:** `Using Menubar entries as page links`
|
|
22
|
+
**Good:** `<NavigationMenu> for navigating between destinations`
|
|
23
|
+
**Why:** menubar implies commands/actions within the current view, not navigation to other pages
|
|
24
|
+
|
|
25
|
+
## Related components
|
|
26
|
+
|
|
27
|
+
- **NavigationMenu** (alternative): NavigationMenu navigates between destinations; Menubar invokes commands
|
|
28
|
+
- **Menu** (contains): Each Menubar entry behaves like a single Menu anchored under its trigger
|
|
29
|
+
|
|
30
|
+
## Accessibility rationale
|
|
31
|
+
|
|
32
|
+
Implements the WAI-ARIA menubar pattern: a roving-tabindex row of menuitem triggers (Left/Right/Home/End) where ArrowDown opens the menu and focuses its first item, Up/Down move within the menu, and Escape closes and restores focus to the trigger
|
|
33
|
+
|
|
34
|
+
## Props
|
|
35
|
+
|
|
36
|
+
| Name | Type | Required | Default | Description |
|
|
37
|
+
| ------------ | --------------- | -------- | ------- | -------------------------------------------------------- |
|
|
38
|
+
| `menus` | `MenubarMenu[]` | Yes | — | The top-level menus to render. |
|
|
39
|
+
| `aria-label` | `string` | Yes | — | Accessible label used when no visible label is present. |
|
|
40
|
+
| `className` | `string` | No | — | Additional CSS class names merged onto the root element. |
|
|
41
|
+
|
|
42
|
+
## Tokens
|
|
43
|
+
|
|
44
|
+
- `--cascivo-color-surface`
|
|
45
|
+
- `--cascivo-color-bg-subtle`
|
|
46
|
+
- `--cascivo-color-text`
|
|
47
|
+
- `--cascivo-color-border`
|
|
48
|
+
- `--cascivo-focus-ring`
|
|
49
|
+
- `--cascivo-motion-enter`
|
|
50
|
+
- `--cascivo-motion-exit`
|
|
51
|
+
|
|
52
|
+
## Examples
|
|
53
|
+
|
|
54
|
+
### Basic
|
|
55
|
+
|
|
56
|
+
```jsx
|
|
57
|
+
<Menubar
|
|
58
|
+
aria-label="Main"
|
|
59
|
+
menus={[{ id: 'file', label: 'File', items: [{ id: 'new', label: 'New', onSelect: () => {} }] }]}
|
|
60
|
+
/>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Boundaries
|
|
64
|
+
|
|
65
|
+
| Area | Level | Note |
|
|
66
|
+
| ------------ | ------ | ---------------------------------------------------------------------------------- |
|
|
67
|
+
| menu content | strict | Menus are described by data (menus prop) so roles and keyboard wiring stay correct |
|
|
68
|
+
| token names | strict | Surface, borders, and focus ring must resolve to --cascivo-\* tokens |
|
|
69
|
+
|
|
70
|
+
## AI context prompt
|
|
71
|
+
|
|
72
|
+
Copy this into an LLM context bar before editing this component:
|
|
73
|
+
|
|
74
|
+
```text
|
|
75
|
+
I am modifying the cascivo Menubar component (navigation). Horizontal application menu bar with keyboard-navigable dropdown menus
|
|
76
|
+
|
|
77
|
+
Architecture constraints — follow exactly:
|
|
78
|
+
- Signals only (useSignal/useComputed/useSignalEffect from @cascivo/core). Never useState/useEffect/useContext/useReducer.
|
|
79
|
+
- Style only through --cascivo-* custom properties. No Tailwind, no inline styles, no CSS-in-JS.
|
|
80
|
+
- Responsive via @container queries on the canonical scale (30rem/40rem/64rem/80rem). Do not use global viewport @media breakpoints.
|
|
81
|
+
- Visual states (hover/focus/active/disabled) via CSS pseudo-classes, not JS.
|
|
82
|
+
- CSS logical properties only (RTL-safe).
|
|
83
|
+
|
|
84
|
+
Menubar is strictly bound to these tokens — use only these, do not invent token names:
|
|
85
|
+
--cascivo-color-surface, --cascivo-color-bg-subtle, --cascivo-color-text, --cascivo-color-border, --cascivo-focus-ring, --cascivo-motion-enter, --cascivo-motion-exit
|
|
86
|
+
|
|
87
|
+
Accessibility: role "menubar", WCAG 2.2-AA, keyboard: ArrowLeft/ArrowRight/ArrowDown/ArrowUp/Home/End/Enter/Escape. Keep it AA.
|
|
88
|
+
|
|
89
|
+
Do not change (strict): menu content — Menus are described by data (menus prop) so roles and keyboard wiring stay correct; token names — Surface, borders, and focus ring must resolve to --cascivo-* tokens
|
|
90
|
+
|
|
91
|
+
Do not invent props, tokens, or global viewport media queries.
|
|
92
|
+
```
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Modal
|
|
2
|
+
|
|
3
|
+
**Category:** overlay
|
|
4
|
+
**Description:** Accessible dialog overlay using native <dialog> element
|
|
5
|
+
|
|
6
|
+
## When to use
|
|
7
|
+
|
|
8
|
+
- Presenting focused content or a task that must interrupt the current flow
|
|
9
|
+
- Confirmations and forms that require the user to act before continuing
|
|
10
|
+
- Cases needing a modal backdrop, focus trap, and Escape-to-close from the native <dialog>
|
|
11
|
+
|
|
12
|
+
## When NOT to use
|
|
13
|
+
|
|
14
|
+
- Anchored, non-modal content next to a trigger — use Popover
|
|
15
|
+
- A side panel or drawer for secondary content — use Sheet
|
|
16
|
+
- A destructive confirmation with a clear yes/no decision — use AlertDialog
|
|
17
|
+
|
|
18
|
+
## Anti-patterns
|
|
19
|
+
|
|
20
|
+
### The open prop drives showModal()/close() on the native dialog, which manages the top layer, backdrop, and focus trap; hiding with CSS breaks all three
|
|
21
|
+
|
|
22
|
+
**Bad:** `Rendering <Modal> mounted but driving visibility with CSS display`
|
|
23
|
+
**Good:** `Control visibility with the open prop`
|
|
24
|
+
**Why:** The open prop drives showModal()/close() on the native dialog, which manages the top layer, backdrop, and focus trap; hiding with CSS breaks all three
|
|
25
|
+
|
|
26
|
+
## Related components
|
|
27
|
+
|
|
28
|
+
- **AlertDialog** (alternative): Use AlertDialog for a focused confirm/cancel decision, especially destructive ones
|
|
29
|
+
- **Sheet** (alternative): Use Sheet for an edge-anchored drawer rather than a centered dialog
|
|
30
|
+
- **Popover** (alternative): Use Popover for lightweight, non-modal content anchored to a trigger
|
|
31
|
+
|
|
32
|
+
## Accessibility rationale
|
|
33
|
+
|
|
34
|
+
Built on the native <dialog> element so showModal() provides a real focus trap, top-layer rendering, and inert background for free; role="dialog" plus aria-labelledby/aria-describedby tie the title and description to the dialog, and Escape closes via the platform.
|
|
35
|
+
|
|
36
|
+
## Props
|
|
37
|
+
|
|
38
|
+
| Name | Type | Required | Default | Description |
|
|
39
|
+
| ------------- | ---------------------- | -------- | ------- | ----------------------------------------------------- |
|
|
40
|
+
| `open` | `boolean` | No | false | Whether the component is open (controlled). |
|
|
41
|
+
| `onClose` | `() => void` | No | — | Called when the component is closed. |
|
|
42
|
+
| `title` | `string` | No | — | Title text for the component. |
|
|
43
|
+
| `description` | `string` | No | — | Supporting description text. |
|
|
44
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | No | md | Visual size of the component (e.g. 'sm', 'md', 'lg'). |
|
|
45
|
+
| `draggable` | `boolean` | No | false | Allow dragging the dialog by its header |
|
|
46
|
+
|
|
47
|
+
## Tokens
|
|
48
|
+
|
|
49
|
+
- `--cascivo-color-surface-overlay`
|
|
50
|
+
- `--cascivo-color-border`
|
|
51
|
+
- `--cascivo-radius-modal`
|
|
52
|
+
- `--cascivo-shadow-xl`
|
|
53
|
+
- `--cascivo-focus-ring`
|
|
54
|
+
|
|
55
|
+
## Examples
|
|
56
|
+
|
|
57
|
+
### Basic modal
|
|
58
|
+
|
|
59
|
+
```jsx
|
|
60
|
+
<Modal open={isOpen} onClose={() => setIsOpen(false)} title="Confirm action">
|
|
61
|
+
<p>Are you sure?</p>
|
|
62
|
+
</Modal>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Boundaries
|
|
66
|
+
|
|
67
|
+
| Area | Level | Note |
|
|
68
|
+
| -------------------------- | -------- | ------------------------------------------------------------------------------------------------------ |
|
|
69
|
+
| token names | strict | Overlay surface, border, radius, shadow, and focus-ring must resolve to the listed --cascivo-\* tokens |
|
|
70
|
+
| size | flexible | sm \| md \| lg, defaulting to md |
|
|
71
|
+
| title / description / body | flexible | All optional; body accepts arbitrary children |
|
|
72
|
+
|
|
73
|
+
## AI context prompt
|
|
74
|
+
|
|
75
|
+
Copy this into an LLM context bar before editing this component:
|
|
76
|
+
|
|
77
|
+
```text
|
|
78
|
+
I am modifying the cascivo Modal component (overlay). Accessible dialog overlay using native <dialog> element
|
|
79
|
+
|
|
80
|
+
Architecture constraints — follow exactly:
|
|
81
|
+
- Signals only (useSignal/useComputed/useSignalEffect from @cascivo/core). Never useState/useEffect/useContext/useReducer.
|
|
82
|
+
- Style only through --cascivo-* custom properties. No Tailwind, no inline styles, no CSS-in-JS.
|
|
83
|
+
- Responsive via @container queries on the canonical scale (30rem/40rem/64rem/80rem). Do not use global viewport @media breakpoints.
|
|
84
|
+
- Visual states (hover/focus/active/disabled) via CSS pseudo-classes, not JS.
|
|
85
|
+
- CSS logical properties only (RTL-safe).
|
|
86
|
+
|
|
87
|
+
Modal is strictly bound to these tokens — use only these, do not invent token names:
|
|
88
|
+
--cascivo-color-surface-overlay, --cascivo-color-border, --cascivo-radius-modal, --cascivo-shadow-xl, --cascivo-focus-ring
|
|
89
|
+
|
|
90
|
+
Accessibility: role "dialog", WCAG 2.2-AA, keyboard: Escape/Tab/Shift+Tab. Keep it AA.
|
|
91
|
+
|
|
92
|
+
Do not change (strict): token names — Overlay surface, border, radius, shadow, and focus-ring must resolve to the listed --cascivo-* tokens
|
|
93
|
+
Flexible: size, title / description / body.
|
|
94
|
+
|
|
95
|
+
Do not invent props, tokens, or global viewport media queries.
|
|
96
|
+
```
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# MultiSelect
|
|
2
|
+
|
|
3
|
+
**Category:** inputs
|
|
4
|
+
**Description:** Searchable multi-value select with popover listbox
|
|
5
|
+
|
|
6
|
+
## When to use
|
|
7
|
+
|
|
8
|
+
- Selecting several values at once from a known list of options
|
|
9
|
+
- Lists long enough that the built-in search/filter helps the user find options
|
|
10
|
+
- Cases needing a compact trigger that summarizes the selected count
|
|
11
|
+
|
|
12
|
+
## When NOT to use
|
|
13
|
+
|
|
14
|
+
- Choosing exactly one value — use Select
|
|
15
|
+
- Allowing free-text entries not in a predefined list — use Combobox or TagsInput
|
|
16
|
+
- A handful of always-visible options — use a Checkbox group
|
|
17
|
+
|
|
18
|
+
## Anti-patterns
|
|
19
|
+
|
|
20
|
+
### Selection is fully controlled; the listbox reflects value, so dropping the update leaves checkboxes out of sync with state
|
|
21
|
+
|
|
22
|
+
**Bad:** `<MultiSelect value={value} onValueChange={...} /> without keeping value in sync`
|
|
23
|
+
**Good:** `Store the selected string[] and update it from onValueChange every toggle`
|
|
24
|
+
**Why:** Selection is fully controlled; the listbox reflects value, so dropping the update leaves checkboxes out of sync with state
|
|
25
|
+
|
|
26
|
+
## Related components
|
|
27
|
+
|
|
28
|
+
- **Select** (alternative): Use Select for single-value selection
|
|
29
|
+
- **Combobox** (alternative): Use Combobox when users may type values not in the list
|
|
30
|
+
- **Checkbox** (alternative): Use a Checkbox group for a small set of always-visible options
|
|
31
|
+
|
|
32
|
+
## Accessibility rationale
|
|
33
|
+
|
|
34
|
+
The trigger advertises aria-haspopup="listbox" and aria-expanded, the panel is role="listbox" with aria-multiselectable, each option is role="option" with aria-selected reflecting membership and aria-disabled for unavailable ones; ArrowUp/ArrowDown move the active option, Space/Enter toggle it, and Escape closes the popover.
|
|
35
|
+
|
|
36
|
+
## Props
|
|
37
|
+
|
|
38
|
+
| Name | Type | Required | Default | Description |
|
|
39
|
+
| --------------- | ----------------------- | -------- | ------- | ------------------------------------------------------------------ |
|
|
40
|
+
| `options` | `MultiSelectOption[]` | Yes | — | The selectable options. |
|
|
41
|
+
| `value` | `string[]` | Yes | — | The controlled value. |
|
|
42
|
+
| `onValueChange` | `(v: string[]) => void` | Yes | — | Called with the new value when it changes. |
|
|
43
|
+
| `placeholder` | `string` | No | — | Placeholder text shown when the field is empty. |
|
|
44
|
+
| `disabled` | `boolean` | No | false | When true, disables the control and removes it from the tab order. |
|
|
45
|
+
| `labels` | `MultiSelectLabels` | No | — | Overrides for the component’s user-visible strings (i18n). |
|
|
46
|
+
|
|
47
|
+
## Tokens
|
|
48
|
+
|
|
49
|
+
- `--cascivo-color-surface`
|
|
50
|
+
- `--cascivo-color-border`
|
|
51
|
+
- `--cascivo-color-accent`
|
|
52
|
+
- `--cascivo-radius-input`
|
|
53
|
+
- `--cascivo-radius-md`
|
|
54
|
+
- `--cascivo-shadow-md`
|
|
55
|
+
- `--cascivo-focus-ring`
|
|
56
|
+
- `--cascivo-motion-enter`
|
|
57
|
+
|
|
58
|
+
## Examples
|
|
59
|
+
|
|
60
|
+
### Basic
|
|
61
|
+
|
|
62
|
+
```jsx
|
|
63
|
+
<MultiSelect
|
|
64
|
+
options={[
|
|
65
|
+
{ label: 'One', value: '1' },
|
|
66
|
+
{ label: 'Two', value: '2' },
|
|
67
|
+
]}
|
|
68
|
+
value={[]}
|
|
69
|
+
onValueChange={() => {}}
|
|
70
|
+
/>
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Boundaries
|
|
74
|
+
|
|
75
|
+
| Area | Level | Note |
|
|
76
|
+
| ----------- | -------- | -------------------------------------------------------------------------------------------------------------- |
|
|
77
|
+
| token names | strict | Surface, border, accent, radius, shadow, focus-ring, and motion must resolve to the listed --cascivo-\* tokens |
|
|
78
|
+
| labels | flexible | placeholder, selected(count), search, and noResults are overridable |
|
|
79
|
+
| options | flexible | Caller supplies the option list and may mark individual options disabled |
|
|
80
|
+
|
|
81
|
+
## AI context prompt
|
|
82
|
+
|
|
83
|
+
Copy this into an LLM context bar before editing this component:
|
|
84
|
+
|
|
85
|
+
```text
|
|
86
|
+
I am modifying the cascivo MultiSelect component (inputs). Searchable multi-value select with popover listbox
|
|
87
|
+
|
|
88
|
+
Architecture constraints — follow exactly:
|
|
89
|
+
- Signals only (useSignal/useComputed/useSignalEffect from @cascivo/core). Never useState/useEffect/useContext/useReducer.
|
|
90
|
+
- Style only through --cascivo-* custom properties. No Tailwind, no inline styles, no CSS-in-JS.
|
|
91
|
+
- Responsive via @container queries on the canonical scale (30rem/40rem/64rem/80rem). Do not use global viewport @media breakpoints.
|
|
92
|
+
- Visual states (hover/focus/active/disabled) via CSS pseudo-classes, not JS.
|
|
93
|
+
- CSS logical properties only (RTL-safe).
|
|
94
|
+
|
|
95
|
+
MultiSelect is strictly bound to these tokens — use only these, do not invent token names:
|
|
96
|
+
--cascivo-color-surface, --cascivo-color-border, --cascivo-color-accent, --cascivo-radius-input, --cascivo-radius-md, --cascivo-shadow-md, --cascivo-focus-ring, --cascivo-motion-enter
|
|
97
|
+
|
|
98
|
+
Accessibility: role "listbox", WCAG 2.2-AA, keyboard: ArrowDown/ArrowUp/Space/Enter/Escape. Keep it AA.
|
|
99
|
+
|
|
100
|
+
Do not change (strict): token names — Surface, border, accent, radius, shadow, focus-ring, and motion must resolve to the listed --cascivo-* tokens
|
|
101
|
+
Flexible: labels, options.
|
|
102
|
+
|
|
103
|
+
Do not invent props, tokens, or global viewport media queries.
|
|
104
|
+
```
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# NativeSelect
|
|
2
|
+
|
|
3
|
+
**Category:** inputs
|
|
4
|
+
**Description:** A styled native <select> that keeps platform form/keyboard behavior with a custom chevron and focus ring
|
|
5
|
+
|
|
6
|
+
## When to use
|
|
7
|
+
|
|
8
|
+
- A standard single-choice dropdown where native behavior and form integration matter most
|
|
9
|
+
- Mobile-first forms that should use the platform picker UI
|
|
10
|
+
- Pairing with a Field/Label inside a regular HTML form
|
|
11
|
+
|
|
12
|
+
## When NOT to use
|
|
13
|
+
|
|
14
|
+
- Multi-select, search/typeahead, or rich option rendering — use the custom Select/Combobox
|
|
15
|
+
- A handful of mutually exclusive options where radios read better
|
|
16
|
+
|
|
17
|
+
## Anti-patterns
|
|
18
|
+
|
|
19
|
+
### Native <option> cannot render icons or be searched; use a custom listbox for rich options
|
|
20
|
+
|
|
21
|
+
**Bad:** `<NativeSelect options={oneHundredOptionsWithIcons} />`
|
|
22
|
+
**Good:** `<Combobox options={...} />`
|
|
23
|
+
**Why:** Native <option> cannot render icons or be searched; use a custom listbox for rich options
|
|
24
|
+
|
|
25
|
+
## Related components
|
|
26
|
+
|
|
27
|
+
- **Select** (alternative): Custom-rendered listbox for richer options at the cost of native form/keyboard behavior
|
|
28
|
+
- **RadioCard** (alternative): Better for a small fixed set of mutually exclusive choices shown inline
|
|
29
|
+
|
|
30
|
+
## Accessibility rationale
|
|
31
|
+
|
|
32
|
+
It is a real <select>, so the browser provides the combobox role, keyboard interaction, and announcement. aria-invalid is set when invalid; the placeholder is a disabled hidden first option so it shows but is not selectable.
|
|
33
|
+
|
|
34
|
+
## Props
|
|
35
|
+
|
|
36
|
+
| Name | Type | Required | Default | Description |
|
|
37
|
+
| -------------- | --------------------------------------------- | -------- | ------- | ------------------------------------------------------------------ |
|
|
38
|
+
| `options` | `NativeSelectOption[]` | No | — | Options to render. Alternatively pass <option> children. |
|
|
39
|
+
| `children` | `React.ReactNode` | No | — | Raw <option> children (used when options is not provided). |
|
|
40
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | No | md | Visual size of the component (e.g. 'sm', 'md', 'lg'). |
|
|
41
|
+
| `invalid` | `boolean` | No | — | Marks the control as invalid for error styling and a11y. |
|
|
42
|
+
| `placeholder` | `string` | No | — | Placeholder rendered as a disabled, hidden first option. |
|
|
43
|
+
| `value` | `string` | No | — | The controlled value. |
|
|
44
|
+
| `defaultValue` | `string` | No | — | The initial value when uncontrolled. |
|
|
45
|
+
| `onChange` | `React.ChangeEventHandler<HTMLSelectElement>` | No | — | Called when the selected value changes. |
|
|
46
|
+
| `disabled` | `boolean` | No | — | When true, disables the control and removes it from the tab order. |
|
|
47
|
+
| `className` | `string` | No | — | Additional CSS class names merged onto the root element. |
|
|
48
|
+
|
|
49
|
+
## Tokens
|
|
50
|
+
|
|
51
|
+
- `--cascivo-color-surface`
|
|
52
|
+
- `--cascivo-color-border`
|
|
53
|
+
- `--cascivo-color-border-strong`
|
|
54
|
+
- `--cascivo-color-accent`
|
|
55
|
+
- `--cascivo-color-destructive`
|
|
56
|
+
- `--cascivo-color-text-muted`
|
|
57
|
+
- `--cascivo-radius-field`
|
|
58
|
+
- `--cascivo-focus-ring`
|
|
59
|
+
|
|
60
|
+
## Examples
|
|
61
|
+
|
|
62
|
+
### Basic
|
|
63
|
+
|
|
64
|
+
```jsx
|
|
65
|
+
<NativeSelect
|
|
66
|
+
placeholder="Choose a country"
|
|
67
|
+
options={[
|
|
68
|
+
{ value: 'us', label: 'United States' },
|
|
69
|
+
{ value: 'de', label: 'Germany' },
|
|
70
|
+
]}
|
|
71
|
+
onChange={(e) => setCountry(e.target.value)}
|
|
72
|
+
/>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Option children
|
|
76
|
+
|
|
77
|
+
```jsx
|
|
78
|
+
<NativeSelect size="sm" defaultValue="light" aria-label="Theme">
|
|
79
|
+
<option value="light">Light</option>
|
|
80
|
+
<option value="dark">Dark</option>
|
|
81
|
+
</NativeSelect>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Invalid
|
|
85
|
+
|
|
86
|
+
```jsx
|
|
87
|
+
<NativeSelect invalid placeholder="Required" options={countries} />
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Boundaries
|
|
91
|
+
|
|
92
|
+
| Area | Level | Note |
|
|
93
|
+
| ------- | -------- | ---------------------------------------------------------- |
|
|
94
|
+
| options | flexible | Pass an options array or raw <option> children |
|
|
95
|
+
| value | flexible | Controlled (value/onChange) or uncontrolled (defaultValue) |
|
|
96
|
+
|
|
97
|
+
## AI context prompt
|
|
98
|
+
|
|
99
|
+
Copy this into an LLM context bar before editing this component:
|
|
100
|
+
|
|
101
|
+
```text
|
|
102
|
+
I am modifying the cascivo NativeSelect component (inputs). A styled native <select> that keeps platform form/keyboard behavior with a custom chevron and focus ring
|
|
103
|
+
|
|
104
|
+
Architecture constraints — follow exactly:
|
|
105
|
+
- Signals only (useSignal/useComputed/useSignalEffect from @cascivo/core). Never useState/useEffect/useContext/useReducer.
|
|
106
|
+
- Style only through --cascivo-* custom properties. No Tailwind, no inline styles, no CSS-in-JS.
|
|
107
|
+
- Responsive via @container queries on the canonical scale (30rem/40rem/64rem/80rem). Do not use global viewport @media breakpoints.
|
|
108
|
+
- Visual states (hover/focus/active/disabled) via CSS pseudo-classes, not JS.
|
|
109
|
+
- CSS logical properties only (RTL-safe).
|
|
110
|
+
|
|
111
|
+
NativeSelect is strictly bound to these tokens — use only these, do not invent token names:
|
|
112
|
+
--cascivo-color-surface, --cascivo-color-border, --cascivo-color-border-strong, --cascivo-color-accent, --cascivo-color-destructive, --cascivo-color-text-muted, --cascivo-radius-field, --cascivo-focus-ring
|
|
113
|
+
|
|
114
|
+
Accessibility: role "combobox", WCAG 2.2-AA, keyboard: ArrowUp/ArrowDown/Enter/Space/Home/End. Keep it AA.
|
|
115
|
+
Flexible: options, value.
|
|
116
|
+
|
|
117
|
+
Do not invent props, tokens, or global viewport media queries.
|
|
118
|
+
```
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# NavigationMenu
|
|
2
|
+
|
|
3
|
+
**Category:** navigation
|
|
4
|
+
**Description:** Site navigation bar with links and dropdown flyout panels
|
|
5
|
+
|
|
6
|
+
## When to use
|
|
7
|
+
|
|
8
|
+
- Primary site navigation where some destinations are plain links and others reveal a flyout of grouped links
|
|
9
|
+
- A header nav bar that mixes direct links with rich dropdown panels
|
|
10
|
+
|
|
11
|
+
## When NOT to use
|
|
12
|
+
|
|
13
|
+
- Application commands and actions grouped under File/Edit/View — use Menubar
|
|
14
|
+
- A single trigger opening a list of actions — use a Menu/Dropdown
|
|
15
|
+
- Switching between peer content panels in place — use Tabs
|
|
16
|
+
|
|
17
|
+
## Anti-patterns
|
|
18
|
+
|
|
19
|
+
### navigation landmark implies moving between destinations, not invoking actions
|
|
20
|
+
|
|
21
|
+
**Bad:** `Putting action commands (Save, Delete) inside NavigationMenu flyouts`
|
|
22
|
+
**Good:** `<Menubar> or <Menu> for commands; NavigationMenu is for destinations`
|
|
23
|
+
**Why:** navigation landmark implies moving between destinations, not invoking actions
|
|
24
|
+
|
|
25
|
+
## Related components
|
|
26
|
+
|
|
27
|
+
- **Menubar** (alternative): Menubar invokes application commands; NavigationMenu navigates to destinations
|
|
28
|
+
- **Tabs** (alternative): Tabs swap in-page panels; NavigationMenu links to other destinations
|
|
29
|
+
|
|
30
|
+
## Accessibility rationale
|
|
31
|
+
|
|
32
|
+
Wrapped in a navigation landmark with a roving-tabindex row of links and disclosure triggers; triggers expose aria-expanded/aria-controls onto a flyout panel, and outside-pointer or Escape dismisses the open panel and restores trigger focus
|
|
33
|
+
|
|
34
|
+
## Props
|
|
35
|
+
|
|
36
|
+
| Name | Type | Required | Default | Description |
|
|
37
|
+
| ------------- | -------------------------------------- | -------- | ------- | -------------------------------------------------------- |
|
|
38
|
+
| `items` | `NavigationMenuItem[]` | Yes | — | The items to render. |
|
|
39
|
+
| `aria-label` | `string` | No | — | Accessible label used when no visible label is present. |
|
|
40
|
+
| `orientation` | `'horizontal' \| 'vertical' \| 'both'` | No | — | Layout orientation of the component. |
|
|
41
|
+
| `className` | `string` | No | — | Additional CSS class names merged onto the root element. |
|
|
42
|
+
|
|
43
|
+
## Tokens
|
|
44
|
+
|
|
45
|
+
- `--cascivo-color-surface`
|
|
46
|
+
- `--cascivo-color-bg-subtle`
|
|
47
|
+
- `--cascivo-color-text`
|
|
48
|
+
- `--cascivo-color-border`
|
|
49
|
+
- `--cascivo-focus-ring`
|
|
50
|
+
- `--cascivo-motion-enter`
|
|
51
|
+
- `--cascivo-motion-exit`
|
|
52
|
+
|
|
53
|
+
## Examples
|
|
54
|
+
|
|
55
|
+
### Basic
|
|
56
|
+
|
|
57
|
+
```jsx
|
|
58
|
+
<NavigationMenu
|
|
59
|
+
aria-label="Main"
|
|
60
|
+
items={[
|
|
61
|
+
{ id: 'home', label: 'Home', href: '/' },
|
|
62
|
+
{ id: 'products', label: 'Products', content: <ul>…</ul> },
|
|
63
|
+
]}
|
|
64
|
+
/>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Boundaries
|
|
68
|
+
|
|
69
|
+
| Area | Level | Note |
|
|
70
|
+
| ------------- | -------- | ----------------------------------------------------------------------------- |
|
|
71
|
+
| orientation | flexible | horizontal (default) or vertical roving navigation |
|
|
72
|
+
| panel content | flexible | content is arbitrary ReactNode; links without content render as plain anchors |
|
|
73
|
+
|
|
74
|
+
## AI context prompt
|
|
75
|
+
|
|
76
|
+
Copy this into an LLM context bar before editing this component:
|
|
77
|
+
|
|
78
|
+
```text
|
|
79
|
+
I am modifying the cascivo NavigationMenu component (navigation). Site navigation bar with links and dropdown flyout panels
|
|
80
|
+
|
|
81
|
+
Architecture constraints — follow exactly:
|
|
82
|
+
- Signals only (useSignal/useComputed/useSignalEffect from @cascivo/core). Never useState/useEffect/useContext/useReducer.
|
|
83
|
+
- Style only through --cascivo-* custom properties. No Tailwind, no inline styles, no CSS-in-JS.
|
|
84
|
+
- Responsive via @container queries on the canonical scale (30rem/40rem/64rem/80rem). Do not use global viewport @media breakpoints.
|
|
85
|
+
- Visual states (hover/focus/active/disabled) via CSS pseudo-classes, not JS.
|
|
86
|
+
- CSS logical properties only (RTL-safe).
|
|
87
|
+
|
|
88
|
+
NavigationMenu is strictly bound to these tokens — use only these, do not invent token names:
|
|
89
|
+
--cascivo-color-surface, --cascivo-color-bg-subtle, --cascivo-color-text, --cascivo-color-border, --cascivo-focus-ring, --cascivo-motion-enter, --cascivo-motion-exit
|
|
90
|
+
|
|
91
|
+
Accessibility: role "navigation", WCAG 2.2-AA, keyboard: ArrowLeft/ArrowRight/Home/End/Enter/Escape. Keep it AA.
|
|
92
|
+
Flexible: orientation, panel content.
|
|
93
|
+
|
|
94
|
+
Do not invent props, tokens, or global viewport media queries.
|
|
95
|
+
```
|