@dalcvil/steam-green-react 0.1.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +25 -25
- package/README.md +38 -12
- package/dist/components/Avatar/Avatar.css +136 -0
- package/dist/components/Avatar/Avatar.d.ts +22 -0
- package/dist/components/Avatar/Avatar.d.ts.map +1 -0
- package/dist/components/Avatar/Avatar.js +49 -0
- package/dist/components/Avatar/Avatar.js.map +1 -0
- package/dist/components/Avatar/index.d.ts +3 -0
- package/dist/components/Avatar/index.d.ts.map +1 -0
- package/dist/components/Button/Button.css +117 -0
- package/dist/components/Button/Button.css.d.ts +1 -0
- package/dist/components/Button/Button.d.ts +18 -0
- package/dist/components/Button/Button.d.ts.map +1 -0
- package/dist/components/Button/Button.js +29 -0
- package/dist/components/Button/Button.js.map +1 -0
- package/dist/components/Button/index.d.ts +3 -0
- package/dist/components/Button/index.d.ts.map +1 -0
- package/dist/components/Checkbox/Checkbox.css +116 -0
- package/dist/components/Checkbox/Checkbox.css.d.ts +1 -0
- package/dist/components/Checkbox/Checkbox.d.ts +19 -0
- package/dist/components/Checkbox/Checkbox.d.ts.map +1 -0
- package/dist/components/Checkbox/Checkbox.js +51 -0
- package/dist/components/Checkbox/Checkbox.js.map +1 -0
- package/dist/components/Checkbox/index.d.ts +3 -0
- package/dist/components/Checkbox/index.d.ts.map +1 -0
- package/dist/components/ColorPicker/ColorPicker.css +331 -0
- package/dist/components/ColorPicker/ColorPicker.css.d.ts +1 -0
- package/dist/components/ColorPicker/ColorPicker.d.ts +29 -0
- package/dist/components/ColorPicker/ColorPicker.d.ts.map +1 -0
- package/dist/components/ColorPicker/ColorPicker.js +534 -0
- package/dist/components/ColorPicker/ColorPicker.js.map +1 -0
- package/dist/components/ColorPicker/index.d.ts +3 -0
- package/dist/components/{GreenButton → ColorPicker}/index.d.ts.map +1 -1
- package/dist/components/Console/Console.css +96 -0
- package/dist/components/Console/Console.css.d.ts +1 -0
- package/dist/components/Console/Console.d.ts +26 -0
- package/dist/components/Console/Console.d.ts.map +1 -0
- package/dist/components/Console/Console.js +59 -0
- package/dist/components/Console/Console.js.map +1 -0
- package/dist/components/Console/index.d.ts +3 -0
- package/dist/components/Console/index.d.ts.map +1 -0
- package/dist/components/Dialog/Dialog.css +137 -0
- package/dist/components/Dialog/Dialog.css.d.ts +1 -0
- package/dist/components/Dialog/Dialog.d.ts +28 -0
- package/dist/components/Dialog/Dialog.d.ts.map +1 -0
- package/dist/components/Dialog/Dialog.js +151 -0
- package/dist/components/Dialog/Dialog.js.map +1 -0
- package/dist/components/Dialog/index.d.ts +3 -0
- package/dist/components/Dialog/index.d.ts.map +1 -0
- package/dist/components/Divider/Divider.css +68 -0
- package/dist/components/Divider/Divider.css.d.ts +1 -0
- package/dist/components/Divider/Divider.d.ts +12 -0
- package/dist/components/Divider/Divider.d.ts.map +1 -0
- package/dist/components/Divider/Divider.js +23 -0
- package/dist/components/Divider/Divider.js.map +1 -0
- package/dist/components/Divider/index.d.ts +3 -0
- package/dist/components/Divider/index.d.ts.map +1 -0
- package/dist/components/FieldLabel/FieldLabel.css +98 -0
- package/dist/components/FieldLabel/FieldLabel.css.d.ts +1 -0
- package/dist/components/FieldLabel/FieldLabel.d.ts +29 -0
- package/dist/components/FieldLabel/FieldLabel.d.ts.map +1 -0
- package/dist/components/FieldLabel/FieldLabel.js +42 -0
- package/dist/components/FieldLabel/FieldLabel.js.map +1 -0
- package/dist/components/FieldLabel/index.d.ts +3 -0
- package/dist/components/FieldLabel/index.d.ts.map +1 -0
- package/dist/components/GroupBox/GroupBox.css +101 -0
- package/dist/components/GroupBox/GroupBox.css.d.ts +1 -0
- package/dist/components/GroupBox/GroupBox.d.ts +14 -0
- package/dist/components/GroupBox/GroupBox.d.ts.map +1 -0
- package/dist/components/GroupBox/GroupBox.js +25 -0
- package/dist/components/GroupBox/GroupBox.js.map +1 -0
- package/dist/components/GroupBox/index.d.ts +3 -0
- package/dist/components/GroupBox/index.d.ts.map +1 -0
- package/dist/components/IconButton/IconButton.css +184 -0
- package/dist/components/IconButton/IconButton.css.d.ts +1 -0
- package/dist/components/IconButton/IconButton.d.ts +56 -0
- package/dist/components/IconButton/IconButton.d.ts.map +1 -0
- package/dist/components/IconButton/IconButton.js +77 -0
- package/dist/components/IconButton/IconButton.js.map +1 -0
- package/dist/components/IconButton/index.d.ts +3 -0
- package/dist/components/IconButton/index.d.ts.map +1 -0
- package/dist/components/LevelMeter/LevelMeter.css +117 -0
- package/dist/components/LevelMeter/LevelMeter.css.d.ts +1 -0
- package/dist/components/LevelMeter/LevelMeter.d.ts +20 -0
- package/dist/components/LevelMeter/LevelMeter.d.ts.map +1 -0
- package/dist/components/LevelMeter/LevelMeter.js +44 -0
- package/dist/components/LevelMeter/LevelMeter.js.map +1 -0
- package/dist/components/LevelMeter/index.d.ts +3 -0
- package/dist/components/LevelMeter/index.d.ts.map +1 -0
- package/dist/components/Link/Link.css +127 -0
- package/dist/components/Link/Link.css.d.ts +1 -0
- package/dist/components/Link/Link.d.ts +26 -0
- package/dist/components/Link/Link.d.ts.map +1 -0
- package/dist/components/Link/Link.js +60 -0
- package/dist/components/Link/Link.js.map +1 -0
- package/dist/components/Link/index.d.ts +3 -0
- package/dist/components/Link/index.d.ts.map +1 -0
- package/dist/components/List/List.css +224 -0
- package/dist/components/List/List.css.d.ts +1 -0
- package/dist/components/List/List.d.ts +49 -0
- package/dist/components/List/List.d.ts.map +1 -0
- package/dist/components/List/List.js +300 -0
- package/dist/components/List/List.js.map +1 -0
- package/dist/components/List/index.d.ts +3 -0
- package/dist/components/List/index.d.ts.map +1 -0
- package/dist/components/Menu/Menu.css +122 -0
- package/dist/components/Menu/Menu.css.d.ts +1 -0
- package/dist/components/Menu/Menu.d.ts +46 -0
- package/dist/components/Menu/Menu.d.ts.map +1 -0
- package/dist/components/Menu/Menu.js +246 -0
- package/dist/components/Menu/Menu.js.map +1 -0
- package/dist/components/Menu/index.d.ts +3 -0
- package/dist/components/Menu/index.d.ts.map +1 -0
- package/dist/components/MenuBar/MenuBar.css +94 -0
- package/dist/components/MenuBar/MenuBar.css.d.ts +1 -0
- package/dist/components/MenuBar/MenuBar.d.ts +34 -0
- package/dist/components/MenuBar/MenuBar.d.ts.map +1 -0
- package/dist/components/MenuBar/MenuBar.js +129 -0
- package/dist/components/MenuBar/MenuBar.js.map +1 -0
- package/dist/components/MenuBar/index.d.ts +3 -0
- package/dist/components/MenuBar/index.d.ts.map +1 -0
- package/dist/components/NavBar/NavBar.css +179 -0
- package/dist/components/NavBar/NavBar.css.d.ts +1 -0
- package/dist/components/NavBar/NavBar.d.ts +39 -0
- package/dist/components/NavBar/NavBar.d.ts.map +1 -0
- package/dist/components/NavBar/NavBar.js +198 -0
- package/dist/components/NavBar/NavBar.js.map +1 -0
- package/dist/components/NavBar/index.d.ts +3 -0
- package/dist/components/NavBar/index.d.ts.map +1 -0
- package/dist/components/Notification/Notification.css +176 -0
- package/dist/components/Notification/Notification.css.d.ts +1 -0
- package/dist/components/Notification/Notification.d.ts +26 -0
- package/dist/components/Notification/Notification.d.ts.map +1 -0
- package/dist/components/Notification/Notification.js +181 -0
- package/dist/components/Notification/Notification.js.map +1 -0
- package/dist/components/Notification/index.d.ts +3 -0
- package/dist/components/Notification/index.d.ts.map +1 -0
- package/dist/components/Panel/Panel.css +56 -0
- package/dist/components/Panel/Panel.css.d.ts +1 -0
- package/dist/components/Panel/Panel.d.ts +14 -0
- package/dist/components/Panel/Panel.d.ts.map +1 -0
- package/dist/components/Panel/Panel.js +42 -0
- package/dist/components/Panel/Panel.js.map +1 -0
- package/dist/components/Panel/index.d.ts +3 -0
- package/dist/components/Panel/index.d.ts.map +1 -0
- package/dist/components/ProgressBar/ProgressBar.css +108 -0
- package/dist/components/ProgressBar/ProgressBar.css.d.ts +1 -0
- package/dist/components/ProgressBar/ProgressBar.d.ts +22 -0
- package/dist/components/ProgressBar/ProgressBar.d.ts.map +1 -0
- package/dist/components/ProgressBar/ProgressBar.js +43 -0
- package/dist/components/ProgressBar/ProgressBar.js.map +1 -0
- package/dist/components/ProgressBar/index.d.ts +3 -0
- package/dist/components/ProgressBar/index.d.ts.map +1 -0
- package/dist/components/Radio/Radio.css +125 -0
- package/dist/components/Radio/Radio.css.d.ts +1 -0
- package/dist/components/Radio/Radio.d.ts +40 -0
- package/dist/components/Radio/Radio.d.ts.map +1 -0
- package/dist/components/Radio/Radio.js +91 -0
- package/dist/components/Radio/Radio.js.map +1 -0
- package/dist/components/Radio/index.d.ts +3 -0
- package/dist/components/Radio/index.d.ts.map +1 -0
- package/dist/components/RichText/RichText.css +96 -0
- package/dist/components/RichText/RichText.css.d.ts +1 -0
- package/dist/components/RichText/RichText.d.ts +25 -0
- package/dist/components/RichText/RichText.d.ts.map +1 -0
- package/dist/components/RichText/RichText.js +56 -0
- package/dist/components/RichText/RichText.js.map +1 -0
- package/dist/components/RichText/index.d.ts +3 -0
- package/dist/components/RichText/index.d.ts.map +1 -0
- package/dist/components/ScrollArea/ScrollArea.css +236 -0
- package/dist/components/ScrollArea/ScrollArea.css.d.ts +1 -0
- package/dist/components/ScrollArea/ScrollArea.d.ts +25 -0
- package/dist/components/ScrollArea/ScrollArea.d.ts.map +1 -0
- package/dist/components/ScrollArea/ScrollArea.js +124 -0
- package/dist/components/ScrollArea/ScrollArea.js.map +1 -0
- package/dist/components/ScrollArea/index.d.ts +3 -0
- package/dist/components/ScrollArea/index.d.ts.map +1 -0
- package/dist/components/Scrollbar/Scrollbar.css +260 -0
- package/dist/components/Scrollbar/Scrollbar.css.d.ts +1 -0
- package/dist/components/Scrollbar/Scrollbar.d.ts +31 -0
- package/dist/components/Scrollbar/Scrollbar.d.ts.map +1 -0
- package/dist/components/Scrollbar/Scrollbar.js +277 -0
- package/dist/components/Scrollbar/Scrollbar.js.map +1 -0
- package/dist/components/Scrollbar/index.d.ts +3 -0
- package/dist/components/Scrollbar/index.d.ts.map +1 -0
- package/dist/components/Select/Select.css +299 -0
- package/dist/components/Select/Select.css.d.ts +1 -0
- package/dist/components/Select/Select.d.ts +52 -0
- package/dist/components/Select/Select.d.ts.map +1 -0
- package/dist/components/Select/Select.js +281 -0
- package/dist/components/Select/Select.js.map +1 -0
- package/dist/components/Select/index.d.ts +3 -0
- package/dist/components/Select/index.d.ts.map +1 -0
- package/dist/components/Slider/Slider.css +158 -0
- package/dist/components/Slider/Slider.css.d.ts +1 -0
- package/dist/components/Slider/Slider.d.ts +26 -0
- package/dist/components/Slider/Slider.d.ts.map +1 -0
- package/dist/components/Slider/Slider.js +67 -0
- package/dist/components/Slider/Slider.js.map +1 -0
- package/dist/components/Slider/index.d.ts +3 -0
- package/dist/components/Slider/index.d.ts.map +1 -0
- package/dist/components/SpinBox/SpinBox.css +152 -0
- package/dist/components/SpinBox/SpinBox.css.d.ts +1 -0
- package/dist/components/SpinBox/SpinBox.d.ts +28 -0
- package/dist/components/SpinBox/SpinBox.d.ts.map +1 -0
- package/dist/components/SpinBox/SpinBox.js +207 -0
- package/dist/components/SpinBox/SpinBox.js.map +1 -0
- package/dist/components/SpinBox/index.d.ts +3 -0
- package/dist/components/SpinBox/index.d.ts.map +1 -0
- package/dist/components/Spinner/Spinner.css +137 -0
- package/dist/components/Spinner/Spinner.css.d.ts +1 -0
- package/dist/components/Spinner/Spinner.d.ts +20 -0
- package/dist/components/Spinner/Spinner.d.ts.map +1 -0
- package/dist/components/Spinner/Spinner.js +36 -0
- package/dist/components/Spinner/Spinner.js.map +1 -0
- package/dist/components/Spinner/index.d.ts +3 -0
- package/dist/components/Spinner/index.d.ts.map +1 -0
- package/dist/components/Splitter/Splitter.css +119 -0
- package/dist/components/Splitter/Splitter.css.d.ts +1 -0
- package/dist/components/Splitter/Splitter.d.ts +25 -0
- package/dist/components/Splitter/Splitter.d.ts.map +1 -0
- package/dist/components/Splitter/Splitter.js +212 -0
- package/dist/components/Splitter/Splitter.js.map +1 -0
- package/dist/components/Splitter/index.d.ts +3 -0
- package/dist/components/Splitter/index.d.ts.map +1 -0
- package/dist/components/StatusBar/StatusBar.css +97 -0
- package/dist/components/StatusBar/StatusBar.css.d.ts +1 -0
- package/dist/components/StatusBar/StatusBar.d.ts +22 -0
- package/dist/components/StatusBar/StatusBar.d.ts.map +1 -0
- package/dist/components/StatusBar/StatusBar.js +56 -0
- package/dist/components/StatusBar/StatusBar.js.map +1 -0
- package/dist/components/StatusBar/index.d.ts +3 -0
- package/dist/components/StatusBar/index.d.ts.map +1 -0
- package/dist/components/StatusLabel/StatusLabel.css +93 -0
- package/dist/components/StatusLabel/StatusLabel.css.d.ts +1 -0
- package/dist/components/StatusLabel/StatusLabel.d.ts +20 -0
- package/dist/components/StatusLabel/StatusLabel.d.ts.map +1 -0
- package/dist/components/StatusLabel/StatusLabel.js +42 -0
- package/dist/components/StatusLabel/StatusLabel.js.map +1 -0
- package/dist/components/StatusLabel/index.d.ts +3 -0
- package/dist/components/StatusLabel/index.d.ts.map +1 -0
- package/dist/components/Table/Table.css +253 -0
- package/dist/components/Table/Table.css.d.ts +1 -0
- package/dist/components/Table/Table.d.ts +67 -0
- package/dist/components/Table/Table.d.ts.map +1 -0
- package/dist/components/Table/Table.js +429 -0
- package/dist/components/Table/Table.js.map +1 -0
- package/dist/components/Table/index.d.ts +3 -0
- package/dist/components/Table/index.d.ts.map +1 -0
- package/dist/components/Tabs/Tabs.css +138 -0
- package/dist/components/Tabs/Tabs.css.d.ts +1 -0
- package/dist/components/Tabs/Tabs.d.ts +34 -0
- package/dist/components/Tabs/Tabs.d.ts.map +1 -0
- package/dist/components/Tabs/Tabs.js +140 -0
- package/dist/components/Tabs/Tabs.js.map +1 -0
- package/dist/components/Tabs/index.d.ts +3 -0
- package/dist/components/Tabs/index.d.ts.map +1 -0
- package/dist/components/TextInput/TextInput.css +133 -0
- package/dist/components/TextInput/TextInput.css.d.ts +1 -0
- package/dist/components/TextInput/TextInput.d.ts +16 -0
- package/dist/components/TextInput/TextInput.d.ts.map +1 -0
- package/dist/components/TextInput/TextInput.js +38 -0
- package/dist/components/TextInput/TextInput.js.map +1 -0
- package/dist/components/TextInput/index.d.ts +3 -0
- package/dist/components/TextInput/index.d.ts.map +1 -0
- package/dist/components/Textarea/Textarea.css +121 -0
- package/dist/components/Textarea/Textarea.css.d.ts +1 -0
- package/dist/components/Textarea/Textarea.d.ts +21 -0
- package/dist/components/Textarea/Textarea.d.ts.map +1 -0
- package/dist/components/Textarea/Textarea.js +61 -0
- package/dist/components/Textarea/Textarea.js.map +1 -0
- package/dist/components/Textarea/index.d.ts +3 -0
- package/dist/components/Textarea/index.d.ts.map +1 -0
- package/dist/components/TitleBar/TitleBar.css +76 -0
- package/dist/components/TitleBar/TitleBar.css.d.ts +1 -0
- package/dist/components/TitleBar/TitleBar.d.ts +20 -0
- package/dist/components/TitleBar/TitleBar.d.ts.map +1 -0
- package/dist/components/TitleBar/TitleBar.js +43 -0
- package/dist/components/TitleBar/TitleBar.js.map +1 -0
- package/dist/components/TitleBar/index.d.ts +3 -0
- package/dist/components/TitleBar/index.d.ts.map +1 -0
- package/dist/components/ToggleButton/ToggleButton.css +162 -0
- package/dist/components/ToggleButton/ToggleButton.css.d.ts +1 -0
- package/dist/components/ToggleButton/ToggleButton.d.ts +27 -0
- package/dist/components/ToggleButton/ToggleButton.d.ts.map +1 -0
- package/dist/components/ToggleButton/ToggleButton.js +52 -0
- package/dist/components/ToggleButton/ToggleButton.js.map +1 -0
- package/dist/components/ToggleButton/index.d.ts +3 -0
- package/dist/components/ToggleButton/index.d.ts.map +1 -0
- package/dist/components/Toolbar/Toolbar.css +202 -0
- package/dist/components/Toolbar/Toolbar.css.d.ts +1 -0
- package/dist/components/Toolbar/Toolbar.d.ts +46 -0
- package/dist/components/Toolbar/Toolbar.d.ts.map +1 -0
- package/dist/components/Toolbar/Toolbar.js +102 -0
- package/dist/components/Toolbar/Toolbar.js.map +1 -0
- package/dist/components/Toolbar/index.d.ts +3 -0
- package/dist/components/Toolbar/index.d.ts.map +1 -0
- package/dist/components/Tooltip/Tooltip.css +86 -0
- package/dist/components/Tooltip/Tooltip.css.d.ts +1 -0
- package/dist/components/Tooltip/Tooltip.d.ts +22 -0
- package/dist/components/Tooltip/Tooltip.d.ts.map +1 -0
- package/dist/components/Tooltip/Tooltip.js +92 -0
- package/dist/components/Tooltip/Tooltip.js.map +1 -0
- package/dist/components/Tooltip/index.d.ts +3 -0
- package/dist/components/Tooltip/index.d.ts.map +1 -0
- package/dist/components/TreeView/TreeView.css +191 -0
- package/dist/components/TreeView/TreeView.css.d.ts +1 -0
- package/dist/components/TreeView/TreeView.d.ts +46 -0
- package/dist/components/TreeView/TreeView.d.ts.map +1 -0
- package/dist/components/TreeView/TreeView.js +331 -0
- package/dist/components/TreeView/TreeView.js.map +1 -0
- package/dist/components/TreeView/index.d.ts +3 -0
- package/dist/components/TreeView/index.d.ts.map +1 -0
- package/dist/components/Window/Window.css +218 -0
- package/dist/components/Window/Window.css.d.ts +1 -0
- package/dist/components/Window/Window.d.ts +30 -0
- package/dist/components/Window/Window.d.ts.map +1 -0
- package/dist/components/Window/Window.js +156 -0
- package/dist/components/Window/Window.js.map +1 -0
- package/dist/components/Window/index.d.ts +3 -0
- package/dist/components/Window/index.d.ts.map +1 -0
- package/dist/index.d.ts +91 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +41 -2
- package/dist/styles/scrollbars.css +123 -0
- package/dist/styles/scrollbars.css.d.ts +1 -0
- package/dist/styles/theme.css +167 -122
- package/dist/styles/tokens.css +202 -0
- package/dist/styles/tokens.css.d.ts +1 -0
- package/dist/test/a11y.d.ts +3 -0
- package/dist/test/a11y.d.ts.map +1 -0
- package/dist/test/index.d.ts +2 -0
- package/dist/test/index.d.ts.map +1 -0
- package/dist/test/setup.d.ts +2 -0
- package/dist/test/setup.d.ts.map +1 -0
- package/package.json +23 -14
- package/dist/components/GreenButton/GreenButton.css +0 -47
- package/dist/components/GreenButton/GreenButton.d.ts +0 -8
- package/dist/components/GreenButton/GreenButton.d.ts.map +0 -1
- package/dist/components/GreenButton/GreenButton.js +0 -20
- package/dist/components/GreenButton/GreenButton.js.map +0 -1
- package/dist/components/GreenButton/index.d.ts +0 -3
- /package/dist/components/{GreenButton/GreenButton.css.d.ts → Avatar/Avatar.css.d.ts} +0 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { HTMLAttributes } from 'react';
|
|
2
|
+
import './Toolbar.css';
|
|
3
|
+
/** One glyph — or text — button on a {@link Toolbar}. */
|
|
4
|
+
export interface ToolbarItem {
|
|
5
|
+
/** Stable identity; also the React key. */
|
|
6
|
+
id: string;
|
|
7
|
+
/** Accessible name; required because the button is glyph-only. */
|
|
8
|
+
label: string;
|
|
9
|
+
/** Glyph base name, e.g. "icon_button_back". Sets `--vgui-toolbar-back`. */
|
|
10
|
+
icon: string;
|
|
11
|
+
/** Called on activation. */
|
|
12
|
+
onClick?: () => void;
|
|
13
|
+
/** Dims the glyph to `--vgui-text-disabled` and blocks activation. */
|
|
14
|
+
disabled?: boolean;
|
|
15
|
+
/** Sticky pressed state for toggles, e.g. fullscreen. */
|
|
16
|
+
pressed?: boolean;
|
|
17
|
+
/** Renders a text label instead of a sprite. */
|
|
18
|
+
text?: string;
|
|
19
|
+
}
|
|
20
|
+
/** Props of {@link Toolbar}. */
|
|
21
|
+
export interface ToolbarProps extends HTMLAttributes<HTMLDivElement> {
|
|
22
|
+
/** Items in display order. */
|
|
23
|
+
items: ToolbarItem[];
|
|
24
|
+
/** Bevelled buttons instead of the chromeless default. */
|
|
25
|
+
raised?: boolean;
|
|
26
|
+
/** Draws the 34px footer bar with 24px controls. */
|
|
27
|
+
footer?: boolean;
|
|
28
|
+
/** Accessible name for the toolbar landmark. */
|
|
29
|
+
label?: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* A horizontal strip of compact buttons acting on the surface below it.
|
|
33
|
+
*
|
|
34
|
+
* The VGUI original has **no** `ToolBar` block at all: a toolbar is a plain
|
|
35
|
+
* panel with buttons on it, and the buttons paint nothing (`bgcolor = none`
|
|
36
|
+
* plus an empty `render_bg {}`). The strip is therefore deliberately bare, and
|
|
37
|
+
* every state is carried by the glyph rather than by a background tint.
|
|
38
|
+
*
|
|
39
|
+
* The sprites themselves are procedural stand-ins rather than Valve's artwork —
|
|
40
|
+
* see `docs/assets.md` — and each one is overridable through a
|
|
41
|
+
* `--vgui-toolbar-<glyph>` custom property, so a consumer who owns the original
|
|
42
|
+
* `.tga` set can drop it straight in.
|
|
43
|
+
* See `docs/components/Toolbar.md`.
|
|
44
|
+
*/
|
|
45
|
+
export declare const Toolbar: import("react").ForwardRefExoticComponent<ToolbarProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
46
|
+
//# sourceMappingURL=Toolbar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Toolbar.d.ts","sourceRoot":"","sources":["../../../src/components/Toolbar/Toolbar.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAuC,MAAM,OAAO,CAAA;AAEhF,OAAO,eAAe,CAAA;AAEtB,yDAAyD;AACzD,MAAM,WAAW,WAAW;IAC1B,2CAA2C;IAC3C,EAAE,EAAE,MAAM,CAAA;IACV,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAA;IACb,4EAA4E;IAC5E,IAAI,EAAE,MAAM,CAAA;IACZ,4BAA4B;IAC5B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,yDAAyD;IACzD,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,gDAAgD;IAChD,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,gCAAgC;AAChC,MAAM,WAAW,YAAa,SAAQ,cAAc,CAAC,cAAc,CAAC;IAClE,8BAA8B;IAC9B,KAAK,EAAE,WAAW,EAAE,CAAA;IACpB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,oDAAoD;IACpD,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,gDAAgD;IAChD,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAaD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,OAAO,yGA4GlB,CAAA"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { forwardRef, useRef, useState } from "react";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import "./Toolbar.css";
|
|
4
|
+
//#region src/components/Toolbar/Toolbar.tsx
|
|
5
|
+
/**
|
|
6
|
+
* `icon_button_back` → `back`, `icon_controller_bpm` → `controller-bpm`.
|
|
7
|
+
*
|
|
8
|
+
* The class is the bridge between the `icon` data field and the sprite
|
|
9
|
+
* selectors in `Toolbar.css`; the full sprite name stays on `data-icon` so the
|
|
10
|
+
* markup still says which asset was asked for.
|
|
11
|
+
*/
|
|
12
|
+
function glyphClass(icon) {
|
|
13
|
+
return icon.replace(/^icon_(button_)?/, "").replace(/_/g, "-");
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* A horizontal strip of compact buttons acting on the surface below it.
|
|
17
|
+
*
|
|
18
|
+
* The VGUI original has **no** `ToolBar` block at all: a toolbar is a plain
|
|
19
|
+
* panel with buttons on it, and the buttons paint nothing (`bgcolor = none`
|
|
20
|
+
* plus an empty `render_bg {}`). The strip is therefore deliberately bare, and
|
|
21
|
+
* every state is carried by the glyph rather than by a background tint.
|
|
22
|
+
*
|
|
23
|
+
* The sprites themselves are procedural stand-ins rather than Valve's artwork —
|
|
24
|
+
* see `docs/assets.md` — and each one is overridable through a
|
|
25
|
+
* `--vgui-toolbar-<glyph>` custom property, so a consumer who owns the original
|
|
26
|
+
* `.tga` set can drop it straight in.
|
|
27
|
+
* See `docs/components/Toolbar.md`.
|
|
28
|
+
*/
|
|
29
|
+
var Toolbar = forwardRef(function Toolbar({ items, raised = false, footer = false, label, className, onKeyDown, ...rest }, ref) {
|
|
30
|
+
const buttonRefs = useRef([]);
|
|
31
|
+
const firstEnabled = items.findIndex((item) => !item.disabled);
|
|
32
|
+
const [activeIndex, setActiveIndex] = useState(firstEnabled === -1 ? 0 : firstEnabled);
|
|
33
|
+
const current = items[activeIndex] && !items[activeIndex].disabled ? activeIndex : firstEnabled;
|
|
34
|
+
const enabledIndices = () => items.map((item, index) => ({
|
|
35
|
+
item,
|
|
36
|
+
index
|
|
37
|
+
})).filter(({ item }) => !item.disabled);
|
|
38
|
+
const focusAt = (index) => {
|
|
39
|
+
setActiveIndex(index);
|
|
40
|
+
buttonRefs.current[index]?.focus();
|
|
41
|
+
};
|
|
42
|
+
const moveBy = (delta) => {
|
|
43
|
+
const enabled = enabledIndices();
|
|
44
|
+
if (enabled.length === 0) return;
|
|
45
|
+
const position = enabled.findIndex(({ index }) => index === current);
|
|
46
|
+
const next = enabled[(position === -1 ? 0 : position + delta + enabled.length) % enabled.length];
|
|
47
|
+
focusAt(next.index);
|
|
48
|
+
};
|
|
49
|
+
const handleKeyDown = (event) => {
|
|
50
|
+
onKeyDown?.(event);
|
|
51
|
+
if (event.defaultPrevented) return;
|
|
52
|
+
const enabled = enabledIndices();
|
|
53
|
+
if (event.key === "ArrowRight") moveBy(1);
|
|
54
|
+
else if (event.key === "ArrowLeft") moveBy(-1);
|
|
55
|
+
else if (event.key === "Home" && enabled.length > 0) focusAt(enabled[0].index);
|
|
56
|
+
else if (event.key === "End" && enabled.length > 0) focusAt(enabled[enabled.length - 1].index);
|
|
57
|
+
else return;
|
|
58
|
+
event.preventDefault();
|
|
59
|
+
};
|
|
60
|
+
return /* @__PURE__ */ jsx("div", {
|
|
61
|
+
...rest,
|
|
62
|
+
ref,
|
|
63
|
+
role: "toolbar",
|
|
64
|
+
"aria-orientation": "horizontal",
|
|
65
|
+
"aria-label": label,
|
|
66
|
+
className: [
|
|
67
|
+
"vgui-toolbar",
|
|
68
|
+
raised ? "vgui-toolbar--raised" : "vgui-toolbar--bare",
|
|
69
|
+
footer ? "vgui-toolbar--footer" : null,
|
|
70
|
+
className
|
|
71
|
+
].filter(Boolean).join(" "),
|
|
72
|
+
onKeyDown: handleKeyDown,
|
|
73
|
+
children: items.map((item, index) => {
|
|
74
|
+
const glyph = glyphClass(item.icon);
|
|
75
|
+
const isText = item.text !== void 0;
|
|
76
|
+
return /* @__PURE__ */ jsx("button", {
|
|
77
|
+
ref: (node) => {
|
|
78
|
+
buttonRefs.current[index] = node;
|
|
79
|
+
},
|
|
80
|
+
type: "button",
|
|
81
|
+
className: [
|
|
82
|
+
"vgui-toolbar__button",
|
|
83
|
+
isText ? "vgui-toolbar__button--text" : null,
|
|
84
|
+
!isText && glyph ? `vgui-toolbar__button--${glyph}` : null
|
|
85
|
+
].filter(Boolean).join(" "),
|
|
86
|
+
"data-icon": item.icon,
|
|
87
|
+
"aria-label": isText ? void 0 : item.label,
|
|
88
|
+
"aria-pressed": item.pressed,
|
|
89
|
+
disabled: item.disabled,
|
|
90
|
+
tabIndex: current === index ? 0 : -1,
|
|
91
|
+
onFocus: () => setActiveIndex(index),
|
|
92
|
+
onClick: () => item.onClick?.(),
|
|
93
|
+
children: isText ? item.text : null
|
|
94
|
+
}, item.id);
|
|
95
|
+
})
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
Toolbar.displayName = "Toolbar";
|
|
99
|
+
//#endregion
|
|
100
|
+
export { Toolbar };
|
|
101
|
+
|
|
102
|
+
//# sourceMappingURL=Toolbar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Toolbar.js","names":[],"sources":["../../../src/components/Toolbar/Toolbar.tsx"],"sourcesContent":["import { forwardRef, useRef, useState } from 'react'\nimport type { HTMLAttributes, KeyboardEvent as ReactKeyboardEvent } from 'react'\n\nimport './Toolbar.css'\n\n/** One glyph — or text — button on a {@link Toolbar}. */\nexport interface ToolbarItem {\n /** Stable identity; also the React key. */\n id: string\n /** Accessible name; required because the button is glyph-only. */\n label: string\n /** Glyph base name, e.g. \"icon_button_back\". Sets `--vgui-toolbar-back`. */\n icon: string\n /** Called on activation. */\n onClick?: () => void\n /** Dims the glyph to `--vgui-text-disabled` and blocks activation. */\n disabled?: boolean\n /** Sticky pressed state for toggles, e.g. fullscreen. */\n pressed?: boolean\n /** Renders a text label instead of a sprite. */\n text?: string\n}\n\n/** Props of {@link Toolbar}. */\nexport interface ToolbarProps extends HTMLAttributes<HTMLDivElement> {\n /** Items in display order. */\n items: ToolbarItem[]\n /** Bevelled buttons instead of the chromeless default. */\n raised?: boolean\n /** Draws the 34px footer bar with 24px controls. */\n footer?: boolean\n /** Accessible name for the toolbar landmark. */\n label?: string\n}\n\n/**\n * `icon_button_back` → `back`, `icon_controller_bpm` → `controller-bpm`.\n *\n * The class is the bridge between the `icon` data field and the sprite\n * selectors in `Toolbar.css`; the full sprite name stays on `data-icon` so the\n * markup still says which asset was asked for.\n */\nfunction glyphClass(icon: string): string {\n return icon.replace(/^icon_(button_)?/, '').replace(/_/g, '-')\n}\n\n/**\n * A horizontal strip of compact buttons acting on the surface below it.\n *\n * The VGUI original has **no** `ToolBar` block at all: a toolbar is a plain\n * panel with buttons on it, and the buttons paint nothing (`bgcolor = none`\n * plus an empty `render_bg {}`). The strip is therefore deliberately bare, and\n * every state is carried by the glyph rather than by a background tint.\n *\n * The sprites themselves are procedural stand-ins rather than Valve's artwork —\n * see `docs/assets.md` — and each one is overridable through a\n * `--vgui-toolbar-<glyph>` custom property, so a consumer who owns the original\n * `.tga` set can drop it straight in.\n * See `docs/components/Toolbar.md`.\n */\nexport const Toolbar = forwardRef<HTMLDivElement, ToolbarProps>(function Toolbar(\n { items, raised = false, footer = false, label, className, onKeyDown, ...rest },\n ref,\n) {\n const buttonRefs = useRef<Array<HTMLButtonElement | null>>([])\n\n const firstEnabled = items.findIndex((item) => !item.disabled)\n const [activeIndex, setActiveIndex] = useState(firstEnabled === -1 ? 0 : firstEnabled)\n\n // Roving tabindex: the toolbar is a single tab stop (WCAG-conformant\n // `role=\"toolbar\"`), so only the active button is reachable with Tab.\n const current =\n items[activeIndex] && !items[activeIndex].disabled ? activeIndex : firstEnabled\n\n const enabledIndices = () =>\n items.map((item, index) => ({ item, index })).filter(({ item }) => !item.disabled)\n\n const focusAt = (index: number) => {\n setActiveIndex(index)\n buttonRefs.current[index]?.focus()\n }\n\n const moveBy = (delta: number) => {\n const enabled = enabledIndices()\n\n if (enabled.length === 0) return\n\n const position = enabled.findIndex(({ index }) => index === current)\n const next = enabled[(position === -1 ? 0 : position + delta + enabled.length) % enabled.length]\n\n focusAt(next.index)\n }\n\n const handleKeyDown = (event: ReactKeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(event)\n\n if (event.defaultPrevented) return\n\n const enabled = enabledIndices()\n\n if (event.key === 'ArrowRight') {\n moveBy(1)\n } else if (event.key === 'ArrowLeft') {\n moveBy(-1)\n } else if (event.key === 'Home' && enabled.length > 0) {\n focusAt(enabled[0].index)\n } else if (event.key === 'End' && enabled.length > 0) {\n focusAt(enabled[enabled.length - 1].index)\n } else {\n return\n }\n\n event.preventDefault()\n }\n\n return (\n <div\n {...rest}\n ref={ref}\n role=\"toolbar\"\n aria-orientation=\"horizontal\"\n aria-label={label}\n className={[\n 'vgui-toolbar',\n // `--bare` is the default and paints nothing at all; it is kept in the\n // markup so the documented selector for the chromeless variant exists.\n raised ? 'vgui-toolbar--raised' : 'vgui-toolbar--bare',\n footer ? 'vgui-toolbar--footer' : null,\n className,\n ]\n .filter(Boolean)\n .join(' ')}\n onKeyDown={handleKeyDown}\n >\n {items.map((item, index) => {\n const glyph = glyphClass(item.icon)\n const isText = item.text !== undefined\n\n return (\n <button\n key={item.id}\n ref={(node) => {\n buttonRefs.current[index] = node\n }}\n type=\"button\"\n className={[\n 'vgui-toolbar__button',\n isText ? 'vgui-toolbar__button--text' : null,\n !isText && glyph ? `vgui-toolbar__button--${glyph}` : null,\n ]\n .filter(Boolean)\n .join(' ')}\n data-icon={item.icon}\n // A text button is named by its own visible text, so a label that\n // differed from it would break WCAG 2.5.3 (label in name).\n aria-label={isText ? undefined : item.label}\n aria-pressed={item.pressed}\n disabled={item.disabled}\n tabIndex={current === index ? 0 : -1}\n onFocus={() => setActiveIndex(index)}\n onClick={() => item.onClick?.()}\n >\n {isText ? item.text : null}\n </button>\n )\n })}\n </div>\n )\n})\n\nToolbar.displayName = 'Toolbar'\n"],"mappings":";;;;;;;;;;;AA0CA,SAAS,WAAW,MAAsB;CACxC,OAAO,KAAK,QAAQ,oBAAoB,EAAE,CAAC,CAAC,QAAQ,MAAM,GAAG;AAC/D;;;;;;;;;;;;;;;AAgBA,IAAa,UAAU,WAAyC,SAAS,QACvE,EAAE,OAAO,SAAS,OAAO,SAAS,OAAO,OAAO,WAAW,WAAW,GAAG,QACzE,KACA;CACA,MAAM,aAAa,OAAwC,CAAC,CAAC;CAE7D,MAAM,eAAe,MAAM,WAAW,SAAS,CAAC,KAAK,QAAQ;CAC7D,MAAM,CAAC,aAAa,kBAAkB,SAAS,iBAAiB,KAAK,IAAI,YAAY;CAIrF,MAAM,UACJ,MAAM,gBAAgB,CAAC,MAAM,YAAY,CAAC,WAAW,cAAc;CAErE,MAAM,uBACJ,MAAM,KAAK,MAAM,WAAW;EAAE;EAAM;CAAM,EAAE,CAAC,CAAC,QAAQ,EAAE,WAAW,CAAC,KAAK,QAAQ;CAEnF,MAAM,WAAW,UAAkB;EACjC,eAAe,KAAK;EACpB,WAAW,QAAQ,MAAM,EAAE,MAAM;CACnC;CAEA,MAAM,UAAU,UAAkB;EAChC,MAAM,UAAU,eAAe;EAE/B,IAAI,QAAQ,WAAW,GAAG;EAE1B,MAAM,WAAW,QAAQ,WAAW,EAAE,YAAY,UAAU,OAAO;EACnE,MAAM,OAAO,SAAS,aAAa,KAAK,IAAI,WAAW,QAAQ,QAAQ,UAAU,QAAQ;EAEzF,QAAQ,KAAK,KAAK;CACpB;CAEA,MAAM,iBAAiB,UAA8C;EACnE,YAAY,KAAK;EAEjB,IAAI,MAAM,kBAAkB;EAE5B,MAAM,UAAU,eAAe;EAE/B,IAAI,MAAM,QAAQ,cAChB,OAAO,CAAC;OACH,IAAI,MAAM,QAAQ,aACvB,OAAO,EAAE;OACJ,IAAI,MAAM,QAAQ,UAAU,QAAQ,SAAS,GAClD,QAAQ,QAAQ,EAAE,CAAC,KAAK;OACnB,IAAI,MAAM,QAAQ,SAAS,QAAQ,SAAS,GACjD,QAAQ,QAAQ,QAAQ,SAAS,EAAE,CAAC,KAAK;OAEzC;EAGF,MAAM,eAAe;CACvB;CAEA,OACE,oBAAC,OAAD;EACE,GAAI;EACC;EACL,MAAK;EACL,oBAAiB;EACjB,cAAY;EACZ,WAAW;GACT;GAGA,SAAS,yBAAyB;GAClC,SAAS,yBAAyB;GAClC;EACF,CAAC,CACE,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;EACX,WAAW;EAEV,UAAA,MAAM,KAAK,MAAM,UAAU;GAC1B,MAAM,QAAQ,WAAW,KAAK,IAAI;GAClC,MAAM,SAAS,KAAK,SAAS,KAAA;GAE7B,OACE,oBAAC,UAAD;IAEE,MAAM,SAAS;KACb,WAAW,QAAQ,SAAS;IAC9B;IACA,MAAK;IACL,WAAW;KACT;KACA,SAAS,+BAA+B;KACxC,CAAC,UAAU,QAAQ,yBAAyB,UAAU;IACxD,CAAC,CACE,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;IACX,aAAW,KAAK;IAGhB,cAAY,SAAS,KAAA,IAAY,KAAK;IACtC,gBAAc,KAAK;IACnB,UAAU,KAAK;IACf,UAAU,YAAY,QAAQ,IAAI;IAClC,eAAe,eAAe,KAAK;IACnC,eAAe,KAAK,UAAU;IAE7B,UAAA,SAAS,KAAK,OAAO;GAChB,GAvBD,KAAK,EAuBJ;EAEZ,CAAC;CACE,CAAA;AAET,CAAC;AAED,QAAQ,cAAc"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Toolbar/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Green Steam tooltip — the one place in the theme where the palette inverts:
|
|
3
|
+
* near-black text on a maize card (docs/components/Tooltip.md).
|
|
4
|
+
*
|
|
5
|
+
* The card is a floating surface, so it is positioned by the consumer's
|
|
6
|
+
* positioning logic. The `--placement-*` modifiers exist as that hook and
|
|
7
|
+
* additionally set the transform origin, so a consumer's own enter/exit
|
|
8
|
+
* transition grows away from the trigger rather than from the card's corner.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
.vgui-tooltip {
|
|
12
|
+
position: absolute;
|
|
13
|
+
z-index: 1000;
|
|
14
|
+
box-sizing: border-box;
|
|
15
|
+
max-width: 320px;
|
|
16
|
+
padding: 4px 8px;
|
|
17
|
+
background-color: var(--vgui-heading);
|
|
18
|
+
/* Uniform on all four sides — the bevel is deliberately absent, which is what
|
|
19
|
+
makes the card read as floating rather than raised. */
|
|
20
|
+
border: 1px solid var(--vgui-surface-light);
|
|
21
|
+
color: var(--vgui-selection-text);
|
|
22
|
+
font-family: var(--vgui-font);
|
|
23
|
+
font-size: var(--vgui-font-size);
|
|
24
|
+
line-height: var(--vgui-line-height);
|
|
25
|
+
overflow-wrap: anywhere;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.vgui-tooltip__headline {
|
|
29
|
+
display: block;
|
|
30
|
+
/* Valve's literal value from `tooltip_headline`. It is not a typo: browsers
|
|
31
|
+
clamp it to the heaviest available weight. */
|
|
32
|
+
font-weight: 1000;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.vgui-tooltip__body {
|
|
36
|
+
display: block;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.vgui-tooltip--compact {
|
|
40
|
+
padding: 2px 6px;
|
|
41
|
+
font-size: var(--vgui-font-size-small);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/* The shortcut chip. `kbd` has no UA styling worth keeping, so the bevel is
|
|
45
|
+
declared here rather than reset. */
|
|
46
|
+
.vgui-tooltip__key {
|
|
47
|
+
display: inline-block;
|
|
48
|
+
padding: 0 4px;
|
|
49
|
+
background-color: var(--vgui-surface);
|
|
50
|
+
border-top: 1px solid var(--vgui-bevel-light);
|
|
51
|
+
border-left: 1px solid var(--vgui-bevel-light);
|
|
52
|
+
border-bottom: 1px solid var(--vgui-bevel-dark);
|
|
53
|
+
border-right: 1px solid var(--vgui-bevel-dark);
|
|
54
|
+
color: var(--vgui-text);
|
|
55
|
+
font-family: var(--vgui-font-mono);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/* `--keyboard`: a hint that is only a shortcut, so the card shrinks to it. */
|
|
59
|
+
.vgui-tooltip--keyboard {
|
|
60
|
+
display: inline-flex;
|
|
61
|
+
gap: 4px;
|
|
62
|
+
align-items: center;
|
|
63
|
+
padding: 2px 6px;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/* `--error`: a validation hint. Colour alone is never the indicator, so this
|
|
67
|
+
only draws the border — the caller owes an icon or wording as well. */
|
|
68
|
+
.vgui-tooltip--error {
|
|
69
|
+
border-color: var(--vgui-danger);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.vgui-tooltip--placement-top {
|
|
73
|
+
transform-origin: bottom center;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.vgui-tooltip--placement-bottom {
|
|
77
|
+
transform-origin: top center;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.vgui-tooltip--placement-left {
|
|
81
|
+
transform-origin: center right;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.vgui-tooltip--placement-right {
|
|
85
|
+
transform-origin: center left;
|
|
86
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ReactElement, ReactNode } from 'react';
|
|
2
|
+
import './Tooltip.css';
|
|
3
|
+
export interface TooltipProps {
|
|
4
|
+
/** Tooltip contents — usually a string, but accepts nodes. */
|
|
5
|
+
content: ReactNode;
|
|
6
|
+
/** Optional bold first line above the body. */
|
|
7
|
+
headline?: ReactNode;
|
|
8
|
+
/** The element the tooltip describes. Must be focusable. */
|
|
9
|
+
children: ReactElement;
|
|
10
|
+
/** Where to prefer to render; flips automatically when it would overflow. */
|
|
11
|
+
placement?: 'top' | 'bottom' | 'left' | 'right';
|
|
12
|
+
/** Milliseconds before showing on pointer hover. 0 disables the delay. */
|
|
13
|
+
delay?: number;
|
|
14
|
+
/** Render the compact variant. */
|
|
15
|
+
compact?: boolean;
|
|
16
|
+
/** Controlled visibility. */
|
|
17
|
+
open?: boolean;
|
|
18
|
+
/** Called when the tooltip wants to open or close. */
|
|
19
|
+
onOpenChange?: (open: boolean) => void;
|
|
20
|
+
}
|
|
21
|
+
export declare const Tooltip: import("react").ForwardRefExoticComponent<TooltipProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
22
|
+
//# sourceMappingURL=Tooltip.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Tooltip.d.ts","sourceRoot":"","sources":["../../../src/components/Tooltip/Tooltip.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEpD,OAAO,eAAe,CAAA;AAEtB,MAAM,WAAW,YAAY;IAC3B,8DAA8D;IAC9D,OAAO,EAAE,SAAS,CAAA;IAClB,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,SAAS,CAAA;IACpB,4DAA4D;IAC5D,QAAQ,EAAE,YAAY,CAAA;IACtB,6EAA6E;IAC7E,SAAS,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAA;IAC/C,0EAA0E;IAC1E,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,kCAAkC;IAClC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,6BAA6B;IAC7B,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,sDAAsD;IACtD,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;CACvC;AAED,eAAO,MAAM,OAAO,yGA2HlB,CAAA"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { cloneElement, forwardRef, useCallback, useEffect, useId, useRef, useState } from "react";
|
|
2
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import "./Tooltip.css";
|
|
4
|
+
//#region src/components/Tooltip/Tooltip.tsx
|
|
5
|
+
var Tooltip = forwardRef(function Tooltip({ content, headline, children, placement = "top", delay = 600, compact = false, open, onOpenChange }, ref) {
|
|
6
|
+
const tooltipId = useId();
|
|
7
|
+
const [uncontrolledOpen, setUncontrolledOpen] = useState(false);
|
|
8
|
+
const [dismissed, setDismissed] = useState(false);
|
|
9
|
+
const timer = useRef(null);
|
|
10
|
+
const isControlled = open !== void 0;
|
|
11
|
+
const visible = isControlled ? open : uncontrolledOpen && !dismissed;
|
|
12
|
+
const clearTimer = useCallback(() => {
|
|
13
|
+
if (timer.current !== null) {
|
|
14
|
+
clearTimeout(timer.current);
|
|
15
|
+
timer.current = null;
|
|
16
|
+
}
|
|
17
|
+
}, []);
|
|
18
|
+
const requestOpen = useCallback((next) => {
|
|
19
|
+
if (!isControlled) setUncontrolledOpen(next);
|
|
20
|
+
onOpenChange?.(next);
|
|
21
|
+
}, [isControlled, onOpenChange]);
|
|
22
|
+
useEffect(() => clearTimer, [clearTimer]);
|
|
23
|
+
const childProps = children.props;
|
|
24
|
+
const describedBy = [childProps["aria-describedby"], visible ? tooltipId : null].filter((value) => typeof value === "string" && value.length > 0).join(" ");
|
|
25
|
+
const handleFocus = (event) => {
|
|
26
|
+
if (typeof childProps.onFocus === "function") childProps.onFocus(event);
|
|
27
|
+
clearTimer();
|
|
28
|
+
setDismissed(false);
|
|
29
|
+
requestOpen(true);
|
|
30
|
+
};
|
|
31
|
+
const handleBlur = (event) => {
|
|
32
|
+
if (typeof childProps.onBlur === "function") childProps.onBlur(event);
|
|
33
|
+
clearTimer();
|
|
34
|
+
setDismissed(false);
|
|
35
|
+
requestOpen(false);
|
|
36
|
+
};
|
|
37
|
+
const handlePointerEnter = (event) => {
|
|
38
|
+
if (typeof childProps.onPointerEnter === "function") childProps.onPointerEnter(event);
|
|
39
|
+
setDismissed(false);
|
|
40
|
+
if (delay <= 0) {
|
|
41
|
+
requestOpen(true);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
clearTimer();
|
|
45
|
+
timer.current = setTimeout(() => {
|
|
46
|
+
timer.current = null;
|
|
47
|
+
requestOpen(true);
|
|
48
|
+
}, delay);
|
|
49
|
+
};
|
|
50
|
+
const handlePointerLeave = (event) => {
|
|
51
|
+
if (typeof childProps.onPointerLeave === "function") childProps.onPointerLeave(event);
|
|
52
|
+
clearTimer();
|
|
53
|
+
setDismissed(false);
|
|
54
|
+
requestOpen(false);
|
|
55
|
+
};
|
|
56
|
+
const handleKeyDown = (event) => {
|
|
57
|
+
if (typeof childProps.onKeyDown === "function") childProps.onKeyDown(event);
|
|
58
|
+
if (event.key === "Escape" && visible) {
|
|
59
|
+
clearTimer();
|
|
60
|
+
setDismissed(true);
|
|
61
|
+
requestOpen(false);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
const trigger = cloneElement(children, {
|
|
65
|
+
"aria-describedby": describedBy.length > 0 ? describedBy : void 0,
|
|
66
|
+
onFocus: handleFocus,
|
|
67
|
+
onBlur: handleBlur,
|
|
68
|
+
onPointerEnter: handlePointerEnter,
|
|
69
|
+
onPointerLeave: handlePointerLeave,
|
|
70
|
+
onKeyDown: handleKeyDown
|
|
71
|
+
});
|
|
72
|
+
const classes = ["vgui-tooltip", `vgui-tooltip--placement-${placement}`];
|
|
73
|
+
if (compact) classes.push("vgui-tooltip--compact");
|
|
74
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [trigger, visible ? /* @__PURE__ */ jsxs("div", {
|
|
75
|
+
ref,
|
|
76
|
+
id: tooltipId,
|
|
77
|
+
role: "tooltip",
|
|
78
|
+
className: classes.join(" "),
|
|
79
|
+
children: [headline != null ? /* @__PURE__ */ jsx("span", {
|
|
80
|
+
className: "vgui-tooltip__headline",
|
|
81
|
+
children: headline
|
|
82
|
+
}) : null, /* @__PURE__ */ jsx("span", {
|
|
83
|
+
className: "vgui-tooltip__body",
|
|
84
|
+
children: content
|
|
85
|
+
})]
|
|
86
|
+
}) : null] });
|
|
87
|
+
});
|
|
88
|
+
Tooltip.displayName = "Tooltip";
|
|
89
|
+
//#endregion
|
|
90
|
+
export { Tooltip };
|
|
91
|
+
|
|
92
|
+
//# sourceMappingURL=Tooltip.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Tooltip.js","names":[],"sources":["../../../src/components/Tooltip/Tooltip.tsx"],"sourcesContent":["import { cloneElement, forwardRef, useCallback, useEffect, useId, useRef, useState } from 'react'\nimport type { ReactElement, ReactNode } from 'react'\n\nimport './Tooltip.css'\n\nexport interface TooltipProps {\n /** Tooltip contents — usually a string, but accepts nodes. */\n content: ReactNode\n /** Optional bold first line above the body. */\n headline?: ReactNode\n /** The element the tooltip describes. Must be focusable. */\n children: ReactElement\n /** Where to prefer to render; flips automatically when it would overflow. */\n placement?: 'top' | 'bottom' | 'left' | 'right'\n /** Milliseconds before showing on pointer hover. 0 disables the delay. */\n delay?: number\n /** Render the compact variant. */\n compact?: boolean\n /** Controlled visibility. */\n open?: boolean\n /** Called when the tooltip wants to open or close. */\n onOpenChange?: (open: boolean) => void\n}\n\nexport const Tooltip = forwardRef<HTMLDivElement, TooltipProps>(function Tooltip(\n {\n content,\n headline,\n children,\n placement = 'top',\n delay = 600,\n compact = false,\n open,\n onOpenChange,\n },\n ref,\n) {\n const tooltipId = useId()\n const [uncontrolledOpen, setUncontrolledOpen] = useState(false)\n // Escape dismissal is sticky: the tooltip must not come back until the\n // pointer leaves and re-enters, or focus moves away and back (WCAG 1.4.13).\n const [dismissed, setDismissed] = useState(false)\n const timer = useRef<ReturnType<typeof setTimeout> | null>(null)\n\n const isControlled = open !== undefined\n const visible = isControlled ? open : uncontrolledOpen && !dismissed\n\n const clearTimer = useCallback(() => {\n if (timer.current !== null) {\n clearTimeout(timer.current)\n timer.current = null\n }\n }, [])\n\n const requestOpen = useCallback(\n (next: boolean) => {\n if (!isControlled) setUncontrolledOpen(next)\n onOpenChange?.(next)\n },\n [isControlled, onOpenChange],\n )\n\n useEffect(() => clearTimer, [clearTimer])\n\n const childProps = children.props as Record<string, unknown>\n const existingDescribedBy = childProps['aria-describedby']\n // `aria-describedby` appends to the accessible name rather than replacing it,\n // which is exactly what a description is. An `aria-label` here would erase the\n // trigger's real name, so it is never used.\n const describedBy = [existingDescribedBy, visible ? tooltipId : null]\n .filter((value): value is string => typeof value === 'string' && value.length > 0)\n .join(' ')\n\n const handleFocus = (event: unknown) => {\n if (typeof childProps.onFocus === 'function') (childProps.onFocus as (e: unknown) => void)(event)\n // Keyboard focus is already an expression of intent, so it is never delayed.\n clearTimer()\n setDismissed(false)\n requestOpen(true)\n }\n\n const handleBlur = (event: unknown) => {\n if (typeof childProps.onBlur === 'function') (childProps.onBlur as (e: unknown) => void)(event)\n clearTimer()\n setDismissed(false)\n requestOpen(false)\n }\n\n const handlePointerEnter = (event: unknown) => {\n if (typeof childProps.onPointerEnter === 'function') {\n (childProps.onPointerEnter as (e: unknown) => void)(event)\n }\n setDismissed(false)\n if (delay <= 0) {\n requestOpen(true)\n return\n }\n clearTimer()\n timer.current = setTimeout(() => {\n timer.current = null\n requestOpen(true)\n }, delay)\n }\n\n const handlePointerLeave = (event: unknown) => {\n if (typeof childProps.onPointerLeave === 'function') {\n (childProps.onPointerLeave as (e: unknown) => void)(event)\n }\n clearTimer()\n setDismissed(false)\n requestOpen(false)\n }\n\n const handleKeyDown = (event: { key?: string }) => {\n if (typeof childProps.onKeyDown === 'function') {\n (childProps.onKeyDown as (e: unknown) => void)(event)\n }\n if (event.key === 'Escape' && visible) {\n clearTimer()\n setDismissed(true)\n requestOpen(false)\n }\n }\n\n const trigger = cloneElement(children, {\n 'aria-describedby': describedBy.length > 0 ? describedBy : undefined,\n onFocus: handleFocus,\n onBlur: handleBlur,\n onPointerEnter: handlePointerEnter,\n onPointerLeave: handlePointerLeave,\n onKeyDown: handleKeyDown,\n } as Record<string, unknown>)\n\n const classes = ['vgui-tooltip', `vgui-tooltip--placement-${placement}`]\n if (compact) classes.push('vgui-tooltip--compact')\n\n return (\n <>\n {trigger}\n {visible ? (\n <div ref={ref} id={tooltipId} role=\"tooltip\" className={classes.join(' ')}>\n {headline != null ? <span className=\"vgui-tooltip__headline\">{headline}</span> : null}\n <span className=\"vgui-tooltip__body\">{content}</span>\n </div>\n ) : null}\n </>\n )\n})\n\nTooltip.displayName = 'Tooltip'\n"],"mappings":";;;;AAwBA,IAAa,UAAU,WAAyC,SAAS,QACvE,EACE,SACA,UACA,UACA,YAAY,OACZ,QAAQ,KACR,UAAU,OACV,MACA,gBAEF,KACA;CACA,MAAM,YAAY,MAAM;CACxB,MAAM,CAAC,kBAAkB,uBAAuB,SAAS,KAAK;CAG9D,MAAM,CAAC,WAAW,gBAAgB,SAAS,KAAK;CAChD,MAAM,QAAQ,OAA6C,IAAI;CAE/D,MAAM,eAAe,SAAS,KAAA;CAC9B,MAAM,UAAU,eAAe,OAAO,oBAAoB,CAAC;CAE3D,MAAM,aAAa,kBAAkB;EACnC,IAAI,MAAM,YAAY,MAAM;GAC1B,aAAa,MAAM,OAAO;GAC1B,MAAM,UAAU;EAClB;CACF,GAAG,CAAC,CAAC;CAEL,MAAM,cAAc,aACjB,SAAkB;EACjB,IAAI,CAAC,cAAc,oBAAoB,IAAI;EAC3C,eAAe,IAAI;CACrB,GACA,CAAC,cAAc,YAAY,CAC7B;CAEA,gBAAgB,YAAY,CAAC,UAAU,CAAC;CAExC,MAAM,aAAa,SAAS;CAK5B,MAAM,cAAc,CAJQ,WAAW,qBAIG,UAAU,YAAY,IAAI,CAAC,CAClE,QAAQ,UAA2B,OAAO,UAAU,YAAY,MAAM,SAAS,CAAC,CAAC,CACjF,KAAK,GAAG;CAEX,MAAM,eAAe,UAAmB;EACtC,IAAI,OAAO,WAAW,YAAY,YAAY,WAAY,QAAiC,KAAK;EAEhG,WAAW;EACX,aAAa,KAAK;EAClB,YAAY,IAAI;CAClB;CAEA,MAAM,cAAc,UAAmB;EACrC,IAAI,OAAO,WAAW,WAAW,YAAY,WAAY,OAAgC,KAAK;EAC9F,WAAW;EACX,aAAa,KAAK;EAClB,YAAY,KAAK;CACnB;CAEA,MAAM,sBAAsB,UAAmB;EAC7C,IAAI,OAAO,WAAW,mBAAmB,YACvC,WAAY,eAAwC,KAAK;EAE3D,aAAa,KAAK;EAClB,IAAI,SAAS,GAAG;GACd,YAAY,IAAI;GAChB;EACF;EACA,WAAW;EACX,MAAM,UAAU,iBAAiB;GAC/B,MAAM,UAAU;GAChB,YAAY,IAAI;EAClB,GAAG,KAAK;CACV;CAEA,MAAM,sBAAsB,UAAmB;EAC7C,IAAI,OAAO,WAAW,mBAAmB,YACvC,WAAY,eAAwC,KAAK;EAE3D,WAAW;EACX,aAAa,KAAK;EAClB,YAAY,KAAK;CACnB;CAEA,MAAM,iBAAiB,UAA4B;EACjD,IAAI,OAAO,WAAW,cAAc,YAClC,WAAY,UAAmC,KAAK;EAEtD,IAAI,MAAM,QAAQ,YAAY,SAAS;GACrC,WAAW;GACX,aAAa,IAAI;GACjB,YAAY,KAAK;EACnB;CACF;CAEA,MAAM,UAAU,aAAa,UAAU;EACrC,oBAAoB,YAAY,SAAS,IAAI,cAAc,KAAA;EAC3D,SAAS;EACT,QAAQ;EACR,gBAAgB;EAChB,gBAAgB;EAChB,WAAW;CACb,CAA4B;CAE5B,MAAM,UAAU,CAAC,gBAAgB,2BAA2B,WAAW;CACvE,IAAI,SAAS,QAAQ,KAAK,uBAAuB;CAEjD,OACE,qBAAA,YAAA,EAAA,UAAA,CACG,SACA,UACC,qBAAC,OAAD;EAAU;EAAK,IAAI;EAAW,MAAK;EAAU,WAAW,QAAQ,KAAK,GAAG;EAAxE,UAAA,CACG,YAAY,OAAO,oBAAC,QAAD;GAAM,WAAU;GAA0B,UAAA;EAAe,CAAA,IAAI,MACjF,oBAAC,QAAD;GAAM,WAAU;GAAsB,UAAA;EAAc,CAAA,CACjD;CACH,CAAA,IAAA,IACJ,EAAA,CAAA;AAEN,CAAC;AAED,QAAQ,cAAc"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Tooltip/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA"}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/* TreeView — TreeNode / TreeNodeImage / TreeViewSubPanel.
|
|
2
|
+
*
|
|
3
|
+
* `steam.styles:2653–2682` is the sparsest block in the corpus: three of its
|
|
4
|
+
* four rules are empty. Only four values are evidence —
|
|
5
|
+
* `font-size = 13` (the only 13px text in the file), `Text` `#A0AA95`,
|
|
6
|
+
* `selectedtextcolor = White` and `selectedbgcolor = BorderDark` — plus the
|
|
7
|
+
* `TreeViewSubPanel` fill (`DarkGreenBG`) and its two-sided recess. The row
|
|
8
|
+
* height, the indent step and the disclosure glyph are invention and are
|
|
9
|
+
* commented as such. The only colours allowed here are `var(--vgui-*)` (see
|
|
10
|
+
* `src/styles/tokens.css`).
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
.vgui-tree {
|
|
14
|
+
position: relative;
|
|
15
|
+
color: var(--vgui-text-muted);
|
|
16
|
+
font-size: var(--vgui-tree-font-size, 13px);
|
|
17
|
+
/* The interior scrolls, not the frame — the recess must not scroll with the
|
|
18
|
+
rows or the top/left shading would slide away. */
|
|
19
|
+
overflow: hidden;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/* TreeViewSubPanel (the `TreeViewSubPanel` rule), drawn on the element that
|
|
23
|
+
carries `role="tree"` so the inset frames exactly what scrolls.
|
|
24
|
+
*
|
|
25
|
+
* The source has the bottom and right lines *commented out*, i.e. a deliberate
|
|
26
|
+
* two-sided recess that only reads correctly when the panel is docked against a
|
|
27
|
+
* parent supplying the other two sides. The default variant therefore draws all
|
|
28
|
+
* four sides — the departure the doc's open questions ask for so a standalone
|
|
29
|
+
* tree does not look broken — and `--sidebar` reproduces the source exactly. */
|
|
30
|
+
.vgui-tree > .vgui-tree__subpanel {
|
|
31
|
+
background-color: var(--vgui-tree-bg, var(--vgui-surface-dark));
|
|
32
|
+
border-top: 1px solid var(--vgui-bevel-dark);
|
|
33
|
+
border-left: 1px solid var(--vgui-bevel-dark);
|
|
34
|
+
border-right: 1px solid var(--vgui-bevel-light);
|
|
35
|
+
border-bottom: 1px solid var(--vgui-bevel-light);
|
|
36
|
+
overflow: auto;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/* Sidebar: the faithful recess plus full height. */
|
|
40
|
+
.vgui-tree--sidebar {
|
|
41
|
+
height: 100%;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.vgui-tree--sidebar > .vgui-tree__subpanel {
|
|
45
|
+
border-right: 0;
|
|
46
|
+
border-bottom: 0;
|
|
47
|
+
height: 100%;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* Rows are a flex column so a node and its `role="group"` stack in one flow and
|
|
51
|
+
the group needs no box of its own. */
|
|
52
|
+
.vgui-tree__group {
|
|
53
|
+
display: flex;
|
|
54
|
+
flex-direction: column;
|
|
55
|
+
min-width: 0;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.vgui-tree__node {
|
|
59
|
+
position: relative;
|
|
60
|
+
display: flex;
|
|
61
|
+
align-items: center;
|
|
62
|
+
gap: 2px;
|
|
63
|
+
/* Unverified: `TreeNode {}` is empty, so 16px is the doc's inference. */
|
|
64
|
+
min-height: 16px;
|
|
65
|
+
padding: 0 4px;
|
|
66
|
+
color: var(--vgui-text-muted);
|
|
67
|
+
font-size: var(--vgui-tree-font-size, 13px);
|
|
68
|
+
cursor: default;
|
|
69
|
+
/* No transition and no hover rule: `TreeNodeText` has no hover state, so any
|
|
70
|
+
treatment here would be invented rather than reproduced. */
|
|
71
|
+
/* The per-level step is padding, never ` ` runs, which break at
|
|
72
|
+
wide/narrow fonts. The recipe's `--level` is namespaced here because a
|
|
73
|
+
generic custom property would be inherited from unrelated ancestors. */
|
|
74
|
+
padding-left: calc(4px + var(--vgui-tree-level, 0) * var(--vgui-tree-indent, 16px));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/* Selection is "pushed in": `selectedbgcolor = BorderDark` is *darker* than the
|
|
78
|
+
panel behind it, 1.41:1 against `#3E4637`. That fails WCAG 1.4.11 on its own,
|
|
79
|
+
so the state carries two non-colour cues as well — a recessed 1px inset
|
|
80
|
+
shadow and a bold label. No accent stripe: VGUI fills the whole row. */
|
|
81
|
+
.vgui-tree__node[aria-selected='true'] {
|
|
82
|
+
background-color: var(--vgui-tree-selected-bg, var(--vgui-bevel-dark));
|
|
83
|
+
color: var(--vgui-text-strong);
|
|
84
|
+
box-shadow: inset 1px 1px 0 var(--vgui-bevel-dark);
|
|
85
|
+
font-weight: 700;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* `selectedbgcolor = BorderDark` is a bevel colour on purpose: `ListPanel`,
|
|
89
|
+
`"Page ListPanel"` and `CGamesListPanel` all select the same way, so the
|
|
90
|
+
recession is house style and the maize vocabulary is deliberately not used. */
|
|
91
|
+
|
|
92
|
+
.vgui-tree__node[aria-disabled='true'] {
|
|
93
|
+
color: var(--vgui-text-disabled);
|
|
94
|
+
text-shadow: 1px 1px 0 var(--vgui-text-disabled-shadow);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/* Roving tabindex: the ring marks the *active* node, so it must be visible on a
|
|
98
|
+
row that is not selected as well as on one that is. */
|
|
99
|
+
.vgui-tree__node:focus-visible {
|
|
100
|
+
outline: var(--vgui-focus-ring);
|
|
101
|
+
outline-offset: var(--vgui-focus-ring-offset);
|
|
102
|
+
/* `focused` text is White in the states table. */
|
|
103
|
+
color: var(--vgui-text-strong);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/* Valve's fallback ring: a 1px dashed inner outline. */
|
|
107
|
+
.vgui-crisp .vgui-tree__node:focus-visible {
|
|
108
|
+
outline: var(--vgui-focus-ring-valve);
|
|
109
|
+
outline-offset: var(--vgui-focus-ring-valve-offset);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/* `TreeNodeImage {}` is empty and no `tree_expand`/`tree_collapse` asset exists
|
|
113
|
+
in the port's 16-file set, so the glyph box is the doc's inferred 13px and
|
|
114
|
+
the triangle is drawn with borders in `currentColor`, which lets it follow the
|
|
115
|
+
node from idle to selected to disabled without a second palette. */
|
|
116
|
+
.vgui-tree__image {
|
|
117
|
+
position: relative;
|
|
118
|
+
flex: 0 0 var(--vgui-tree-glyph-size, 13px);
|
|
119
|
+
width: var(--vgui-tree-glyph-size, 13px);
|
|
120
|
+
height: var(--vgui-tree-glyph-size, 13px);
|
|
121
|
+
background-repeat: no-repeat;
|
|
122
|
+
background-position: center;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/* Plain (collapsed) glyph: points right. */
|
|
126
|
+
.vgui-tree__image::before {
|
|
127
|
+
content: '';
|
|
128
|
+
position: absolute;
|
|
129
|
+
top: 50%;
|
|
130
|
+
left: 50%;
|
|
131
|
+
transform: translate(-50%, -50%);
|
|
132
|
+
border-top: 4px solid transparent;
|
|
133
|
+
border-bottom: 4px solid transparent;
|
|
134
|
+
border-left: 6px solid currentColor;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.vgui-tree__image--expanded::before {
|
|
138
|
+
border-top: 6px solid currentColor;
|
|
139
|
+
border-bottom: 0;
|
|
140
|
+
border-left: 4px solid transparent;
|
|
141
|
+
border-right: 4px solid transparent;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/* A leaf keeps the 13px slot — that is what aligns every label in a column —
|
|
145
|
+
but draws nothing, because a disclosure triangle on a childless node is a
|
|
146
|
+
lie. */
|
|
147
|
+
.vgui-tree__image--leaf::before {
|
|
148
|
+
content: none;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/* The glyph is `aria-hidden` (the row carries `aria-expanded`), so it is not a
|
|
152
|
+
control of its own: the full-width row is the target and this box only grows
|
|
153
|
+
the *hit* area of the disclosure half of the row, which the row's own click
|
|
154
|
+
handler resolves. */
|
|
155
|
+
.vgui-tree__image--expanded::after,
|
|
156
|
+
.vgui-tree__image--collapsed::after {
|
|
157
|
+
content: '';
|
|
158
|
+
position: absolute;
|
|
159
|
+
top: 0;
|
|
160
|
+
right: 0;
|
|
161
|
+
bottom: 0;
|
|
162
|
+
left: calc(-1 * (var(--vgui-min-target-size, 24px) - var(--vgui-tree-glyph-size, 13px)));
|
|
163
|
+
/* The growth is to the left, into the node's own indent, so the label is
|
|
164
|
+
never covered and the node above/below never loses a click. */
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.vgui-tree__text {
|
|
168
|
+
overflow: hidden;
|
|
169
|
+
text-overflow: ellipsis;
|
|
170
|
+
white-space: nowrap;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.vgui-tree__empty {
|
|
174
|
+
margin: 0;
|
|
175
|
+
padding: 4px;
|
|
176
|
+
color: var(--vgui-text);
|
|
177
|
+
font-size: var(--vgui-tree-font-size, 13px);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/* The selection live region: audible, never visible. */
|
|
181
|
+
.vgui-tree__live {
|
|
182
|
+
position: absolute;
|
|
183
|
+
width: 1px;
|
|
184
|
+
height: 1px;
|
|
185
|
+
margin: -1px;
|
|
186
|
+
padding: 0;
|
|
187
|
+
overflow: hidden;
|
|
188
|
+
clip-path: inset(50%);
|
|
189
|
+
white-space: nowrap;
|
|
190
|
+
border: 0;
|
|
191
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { HTMLAttributes } from 'react';
|
|
2
|
+
import './TreeView.css';
|
|
3
|
+
import '../../styles/scrollbars.css';
|
|
4
|
+
export interface TreeNode {
|
|
5
|
+
/** Stable identity; also the React key. */
|
|
6
|
+
id: string;
|
|
7
|
+
/** Visible node label. */
|
|
8
|
+
label: string;
|
|
9
|
+
/** Child nodes. A node with an empty array still renders a leaf. */
|
|
10
|
+
children?: TreeNode[];
|
|
11
|
+
/** Renders disabled and unselectable. */
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
/** Initial expansion when uncontrolled. */
|
|
14
|
+
defaultExpanded?: boolean;
|
|
15
|
+
/** Arbitrary payload returned on selection. */
|
|
16
|
+
data?: unknown;
|
|
17
|
+
}
|
|
18
|
+
export type TreeViewVariant = 'default' | 'sidebar';
|
|
19
|
+
export interface TreeViewProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
|
|
20
|
+
/** Root nodes, in order. */
|
|
21
|
+
nodes: TreeNode[];
|
|
22
|
+
/** `sidebar` draws the two-sided `TreeViewSubPanel` recess and fills its parent. */
|
|
23
|
+
variant?: TreeViewVariant;
|
|
24
|
+
/** Controlled selection. Use `string[]` when `multi` is set. */
|
|
25
|
+
selected?: string | string[];
|
|
26
|
+
/** Initial selection when uncontrolled. */
|
|
27
|
+
defaultSelected?: string | string[];
|
|
28
|
+
/** Allows Ctrl/Shift multi-selection. */
|
|
29
|
+
multi?: boolean;
|
|
30
|
+
/** Called with the newly selected node id, or ids when `multi` is set. */
|
|
31
|
+
onSelectedChange?: (ids: string | string[]) => void;
|
|
32
|
+
/** Expands nodes when the whole row is clicked, not just the disclosure glyph. */
|
|
33
|
+
expandOnRowClick?: boolean;
|
|
34
|
+
/** Indent per level in pixels. Defaults to 16. */
|
|
35
|
+
indentSize?: number;
|
|
36
|
+
/** Message rendered when there are no nodes. */
|
|
37
|
+
emptyMessage?: string;
|
|
38
|
+
/**
|
|
39
|
+
* Accessible name for the tree, used when neither `aria-label` nor
|
|
40
|
+
* `aria-labelledby` is given. ARIA requires a tree to be named, so it falls
|
|
41
|
+
* back to `"Tree"`.
|
|
42
|
+
*/
|
|
43
|
+
label?: string;
|
|
44
|
+
}
|
|
45
|
+
export declare const TreeView: import("react").ForwardRefExoticComponent<TreeViewProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
46
|
+
//# sourceMappingURL=TreeView.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TreeView.d.ts","sourceRoot":"","sources":["../../../src/components/TreeView/TreeView.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,cAAc,EAIf,MAAM,OAAO,CAAA;AAEd,OAAO,gBAAgB,CAAA;AACvB,OAAO,6BAA6B,CAAA;AAEpC,MAAM,WAAW,QAAQ;IACvB,2CAA2C;IAC3C,EAAE,EAAE,MAAM,CAAA;IACV,0BAA0B;IAC1B,KAAK,EAAE,MAAM,CAAA;IACb,oEAAoE;IACpE,QAAQ,CAAC,EAAE,QAAQ,EAAE,CAAA;IACrB,yCAAyC;IACzC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,2CAA2C;IAC3C,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,+CAA+C;IAC/C,IAAI,CAAC,EAAE,OAAO,CAAA;CACf;AAED,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,SAAS,CAAA;AAEnD,MAAM,WAAW,aAAc,SAAQ,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC;IACrF,4BAA4B;IAC5B,KAAK,EAAE,QAAQ,EAAE,CAAA;IACjB,oFAAoF;IACpF,OAAO,CAAC,EAAE,eAAe,CAAA;IACzB,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IAC5B,2CAA2C;IAC3C,eAAe,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IACnC,yCAAyC;IACzC,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,0EAA0E;IAC1E,gBAAgB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,IAAI,CAAA;IACnD,kFAAkF;IAClF,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,kDAAkD;IAClD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,gDAAgD;IAChD,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AA2DD,eAAO,MAAM,QAAQ,0GAganB,CAAA"}
|