@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,34 @@
|
|
|
1
|
+
import type { HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
import './Tabs.css';
|
|
3
|
+
export interface TabSpec {
|
|
4
|
+
/** Stable identity, used for the id/aria-controls pair. */
|
|
5
|
+
id: string;
|
|
6
|
+
/** Visible tab label. */
|
|
7
|
+
label: string;
|
|
8
|
+
/** Panel content rendered when this tab is selected. */
|
|
9
|
+
content: ReactNode;
|
|
10
|
+
/** Renders a close affordance in the tab. */
|
|
11
|
+
closable?: boolean;
|
|
12
|
+
/** Called when the close affordance is activated. */
|
|
13
|
+
onClose?: () => void;
|
|
14
|
+
/** Renders as disabled and unselectable. */
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
/** Panel content is not rendered until first activation. */
|
|
17
|
+
lazy?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export interface TabsProps extends HTMLAttributes<HTMLDivElement> {
|
|
20
|
+
/** Tabs in order. The first enabled tab is selected when uncontrolled. */
|
|
21
|
+
tabs: TabSpec[];
|
|
22
|
+
/** Controlled selection. Pair with onValueChange. */
|
|
23
|
+
value?: string;
|
|
24
|
+
/** Initial selection when uncontrolled. */
|
|
25
|
+
defaultValue?: string;
|
|
26
|
+
/** Called with the newly selected tab id. */
|
|
27
|
+
onValueChange?: (id: string) => void;
|
|
28
|
+
/** Selection follows focus, as VGUI's tab strip behaves. Defaults to true. */
|
|
29
|
+
activateOnFocus?: boolean;
|
|
30
|
+
/** Panel surface. 'clay' is the VGUI property-sheet interior. */
|
|
31
|
+
variant?: 'clay' | 'green';
|
|
32
|
+
}
|
|
33
|
+
export declare const Tabs: import("react").ForwardRefExoticComponent<TabsProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
34
|
+
//# sourceMappingURL=Tabs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Tabs.d.ts","sourceRoot":"","sources":["../../../src/components/Tabs/Tabs.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAA6B,SAAS,EAAE,MAAM,OAAO,CAAA;AAEjF,OAAO,YAAY,CAAA;AAEnB,MAAM,WAAW,OAAO;IACtB,2DAA2D;IAC3D,EAAE,EAAE,MAAM,CAAA;IACV,yBAAyB;IACzB,KAAK,EAAE,MAAM,CAAA;IACb,wDAAwD;IACxD,OAAO,EAAE,SAAS,CAAA;IAClB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,qDAAqD;IACrD,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,4DAA4D;IAC5D,IAAI,CAAC,EAAE,OAAO,CAAA;CACf;AAED,MAAM,WAAW,SAAU,SAAQ,cAAc,CAAC,cAAc,CAAC;IAC/D,0EAA0E;IAC1E,IAAI,EAAE,OAAO,EAAE,CAAA;IACf,qDAAqD;IACrD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,2CAA2C;IAC3C,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,6CAA6C;IAC7C,aAAa,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACpC,8EAA8E;IAC9E,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,iEAAiE;IACjE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CAC3B;AAED,eAAO,MAAM,IAAI,sGA+Lf,CAAA"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { forwardRef, useEffect, useId, useRef, useState } from "react";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import "./Tabs.css";
|
|
4
|
+
//#region src/components/Tabs/Tabs.tsx
|
|
5
|
+
var Tabs = forwardRef(function Tabs({ tabs, value, defaultValue, onValueChange, activateOnFocus = true, variant = "clay", className, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, ...rest }, ref) {
|
|
6
|
+
const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);
|
|
7
|
+
const [visited, setVisited] = useState(() => defaultValue ? [defaultValue] : []);
|
|
8
|
+
const baseId = useId();
|
|
9
|
+
const tabNodes = useRef(/* @__PURE__ */ new Map());
|
|
10
|
+
const firstEnabled = tabs.find((tab) => !tab.disabled)?.id;
|
|
11
|
+
const requestedId = value !== void 0 ? value : uncontrolledValue;
|
|
12
|
+
const requested = tabs.find((tab) => tab.id === requestedId);
|
|
13
|
+
const selectedId = requested && !requested.disabled ? requested.id : firstEnabled;
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
if (selectedId && !visited.includes(selectedId)) setVisited((seen) => [...seen, selectedId]);
|
|
16
|
+
}, [selectedId, visited]);
|
|
17
|
+
const setTabNode = (id, node) => {
|
|
18
|
+
if (node) tabNodes.current.set(id, node);
|
|
19
|
+
else tabNodes.current.delete(id);
|
|
20
|
+
};
|
|
21
|
+
const selectTab = (nextId) => {
|
|
22
|
+
const tab = tabs.find((item) => item.id === nextId);
|
|
23
|
+
if (!tab || tab.disabled) return;
|
|
24
|
+
if (value === void 0) setUncontrolledValue(nextId);
|
|
25
|
+
if (nextId !== selectedId) onValueChange?.(nextId);
|
|
26
|
+
};
|
|
27
|
+
const focusTab = (nextId) => {
|
|
28
|
+
if (!nextId) return;
|
|
29
|
+
if (activateOnFocus) selectTab(nextId);
|
|
30
|
+
tabNodes.current.get(nextId)?.focus();
|
|
31
|
+
};
|
|
32
|
+
const handleKeyDown = (event) => {
|
|
33
|
+
const currentId = (event.target?.closest("[role=\"tab\"]"))?.dataset.tabId;
|
|
34
|
+
if (!currentId) return;
|
|
35
|
+
const enabledIds = tabs.filter((tab) => !tab.disabled).map((tab) => tab.id);
|
|
36
|
+
const index = enabledIds.indexOf(currentId);
|
|
37
|
+
if (index === -1) return;
|
|
38
|
+
switch (event.key) {
|
|
39
|
+
case "ArrowRight":
|
|
40
|
+
event.preventDefault();
|
|
41
|
+
focusTab(enabledIds[(index + 1) % enabledIds.length]);
|
|
42
|
+
break;
|
|
43
|
+
case "ArrowLeft":
|
|
44
|
+
event.preventDefault();
|
|
45
|
+
focusTab(enabledIds[(index - 1 + enabledIds.length) % enabledIds.length]);
|
|
46
|
+
break;
|
|
47
|
+
case "Home":
|
|
48
|
+
event.preventDefault();
|
|
49
|
+
focusTab(enabledIds[0]);
|
|
50
|
+
break;
|
|
51
|
+
case "End":
|
|
52
|
+
event.preventDefault();
|
|
53
|
+
focusTab(enabledIds[enabledIds.length - 1]);
|
|
54
|
+
break;
|
|
55
|
+
case "Delete":
|
|
56
|
+
event.preventDefault();
|
|
57
|
+
tabs.find((tab) => tab.id === currentId)?.onClose?.();
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
const rootClasses = ["vgui-tabs", `vgui-tabs--${variant}`];
|
|
61
|
+
if (tabs.some((tab) => tab.closable)) rootClasses.push("vgui-tabs--closable");
|
|
62
|
+
if (className) rootClasses.push(className);
|
|
63
|
+
const panelClasses = ["vgui-tabs__panel", `vgui-tabs__panel--${variant}`];
|
|
64
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
65
|
+
className: rootClasses.join(" "),
|
|
66
|
+
ref,
|
|
67
|
+
...rest,
|
|
68
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
69
|
+
className: "vgui-tabs__strip",
|
|
70
|
+
role: "tablist",
|
|
71
|
+
"aria-label": ariaLabel,
|
|
72
|
+
"aria-labelledby": ariaLabelledBy,
|
|
73
|
+
onKeyDown: handleKeyDown,
|
|
74
|
+
children: tabs.map((tab) => {
|
|
75
|
+
const isSelected = tab.id === selectedId;
|
|
76
|
+
const tabClasses = ["vgui-tabs__tab"];
|
|
77
|
+
if (isSelected) tabClasses.push("vgui-tabs__tab--selected");
|
|
78
|
+
if (tab.disabled) tabClasses.push("vgui-tabs__tab--disabled");
|
|
79
|
+
const shared = {
|
|
80
|
+
className: tabClasses.join(" "),
|
|
81
|
+
id: `${baseId}-tab-${tab.id}`,
|
|
82
|
+
role: "tab",
|
|
83
|
+
"aria-selected": isSelected,
|
|
84
|
+
"aria-controls": `${baseId}-panel-${tab.id}`,
|
|
85
|
+
"aria-disabled": tab.disabled || void 0,
|
|
86
|
+
"aria-keyshortcuts": tab.closable && !tab.disabled ? "Delete" : void 0,
|
|
87
|
+
tabIndex: isSelected ? 0 : -1,
|
|
88
|
+
"data-tab-id": tab.id,
|
|
89
|
+
onClick: () => selectTab(tab.id)
|
|
90
|
+
};
|
|
91
|
+
const label = /* @__PURE__ */ jsx("span", {
|
|
92
|
+
className: "vgui-tabs__label",
|
|
93
|
+
children: tab.label
|
|
94
|
+
});
|
|
95
|
+
if (!tab.closable) return /* @__PURE__ */ jsx("button", {
|
|
96
|
+
type: "button",
|
|
97
|
+
disabled: tab.disabled,
|
|
98
|
+
...shared,
|
|
99
|
+
ref: (node) => {
|
|
100
|
+
setTabNode(tab.id, node);
|
|
101
|
+
},
|
|
102
|
+
children: label
|
|
103
|
+
}, tab.id);
|
|
104
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
105
|
+
...shared,
|
|
106
|
+
ref: (node) => {
|
|
107
|
+
setTabNode(tab.id, node);
|
|
108
|
+
},
|
|
109
|
+
children: [label, tab.disabled ? null : /* @__PURE__ */ jsx("span", {
|
|
110
|
+
className: "vgui-tabs__close",
|
|
111
|
+
"aria-hidden": "true",
|
|
112
|
+
title: `Close ${tab.label} tab`,
|
|
113
|
+
onClick: (event) => {
|
|
114
|
+
event.stopPropagation();
|
|
115
|
+
tab.onClose?.();
|
|
116
|
+
},
|
|
117
|
+
children: "✕"
|
|
118
|
+
})]
|
|
119
|
+
}, tab.id);
|
|
120
|
+
})
|
|
121
|
+
}), tabs.map((tab) => {
|
|
122
|
+
const isSelected = tab.id === selectedId;
|
|
123
|
+
if (!(!tab.lazy || isSelected || visited.includes(tab.id))) return null;
|
|
124
|
+
return /* @__PURE__ */ jsx("div", {
|
|
125
|
+
className: panelClasses.join(" "),
|
|
126
|
+
role: "tabpanel",
|
|
127
|
+
id: `${baseId}-panel-${tab.id}`,
|
|
128
|
+
"aria-labelledby": `${baseId}-tab-${tab.id}`,
|
|
129
|
+
tabIndex: 0,
|
|
130
|
+
hidden: !isSelected,
|
|
131
|
+
children: tab.content
|
|
132
|
+
}, tab.id);
|
|
133
|
+
})]
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
Tabs.displayName = "Tabs";
|
|
137
|
+
//#endregion
|
|
138
|
+
export { Tabs };
|
|
139
|
+
|
|
140
|
+
//# sourceMappingURL=Tabs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Tabs.js","names":[],"sources":["../../../src/components/Tabs/Tabs.tsx"],"sourcesContent":["import { forwardRef, useEffect, useId, useRef, useState } from 'react'\nimport type { HTMLAttributes, KeyboardEvent, MouseEvent, ReactNode } from 'react'\n\nimport './Tabs.css'\n\nexport interface TabSpec {\n /** Stable identity, used for the id/aria-controls pair. */\n id: string\n /** Visible tab label. */\n label: string\n /** Panel content rendered when this tab is selected. */\n content: ReactNode\n /** Renders a close affordance in the tab. */\n closable?: boolean\n /** Called when the close affordance is activated. */\n onClose?: () => void\n /** Renders as disabled and unselectable. */\n disabled?: boolean\n /** Panel content is not rendered until first activation. */\n lazy?: boolean\n}\n\nexport interface TabsProps extends HTMLAttributes<HTMLDivElement> {\n /** Tabs in order. The first enabled tab is selected when uncontrolled. */\n tabs: TabSpec[]\n /** Controlled selection. Pair with onValueChange. */\n value?: string\n /** Initial selection when uncontrolled. */\n defaultValue?: string\n /** Called with the newly selected tab id. */\n onValueChange?: (id: string) => void\n /** Selection follows focus, as VGUI's tab strip behaves. Defaults to true. */\n activateOnFocus?: boolean\n /** Panel surface. 'clay' is the VGUI property-sheet interior. */\n variant?: 'clay' | 'green'\n}\n\nexport const Tabs = forwardRef<HTMLDivElement, TabsProps>(function Tabs(\n {\n tabs,\n value,\n defaultValue,\n onValueChange,\n activateOnFocus = true,\n variant = 'clay',\n className,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n ...rest\n },\n ref,\n) {\n const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue)\n const [visited, setVisited] = useState<string[]>(() => (defaultValue ? [defaultValue] : []))\n const baseId = useId()\n const tabNodes = useRef(new Map<string, HTMLButtonElement | HTMLDivElement>())\n\n const firstEnabled = tabs.find((tab) => !tab.disabled)?.id\n const requestedId = value !== undefined ? value : uncontrolledValue\n const requested = tabs.find((tab) => tab.id === requestedId)\n const selectedId = requested && !requested.disabled ? requested.id : firstEnabled\n\n // A lazy panel stays mounted once it has been shown, so switching away and\n // back does not throw away scroll position or form state.\n useEffect(() => {\n if (selectedId && !visited.includes(selectedId)) {\n setVisited((seen) => [...seen, selectedId])\n }\n }, [selectedId, visited])\n\n const setTabNode = (id: string, node: HTMLButtonElement | HTMLDivElement | null) => {\n if (node) {\n tabNodes.current.set(id, node)\n } else {\n tabNodes.current.delete(id)\n }\n }\n\n const selectTab = (nextId: string) => {\n const tab = tabs.find((item) => item.id === nextId)\n if (!tab || tab.disabled) return\n if (value === undefined) setUncontrolledValue(nextId)\n if (nextId !== selectedId) onValueChange?.(nextId)\n }\n\n const focusTab = (nextId: string | undefined) => {\n if (!nextId) return\n if (activateOnFocus) selectTab(nextId)\n tabNodes.current.get(nextId)?.focus()\n }\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n const current = (event.target as HTMLElement | null)?.closest<HTMLElement>('[role=\"tab\"]')\n const currentId = current?.dataset.tabId\n if (!currentId) return\n const enabledIds = tabs.filter((tab) => !tab.disabled).map((tab) => tab.id)\n const index = enabledIds.indexOf(currentId)\n if (index === -1) return\n\n switch (event.key) {\n case 'ArrowRight':\n event.preventDefault()\n focusTab(enabledIds[(index + 1) % enabledIds.length])\n break\n case 'ArrowLeft':\n event.preventDefault()\n focusTab(enabledIds[(index - 1 + enabledIds.length) % enabledIds.length])\n break\n case 'Home':\n event.preventDefault()\n focusTab(enabledIds[0])\n break\n case 'End':\n event.preventDefault()\n focusTab(enabledIds[enabledIds.length - 1])\n break\n case 'Delete':\n event.preventDefault()\n tabs.find((tab) => tab.id === currentId)?.onClose?.()\n break\n default:\n break\n }\n }\n\n const rootClasses = ['vgui-tabs', `vgui-tabs--${variant}`]\n if (tabs.some((tab) => tab.closable)) rootClasses.push('vgui-tabs--closable')\n if (className) rootClasses.push(className)\n\n const panelClasses = ['vgui-tabs__panel', `vgui-tabs__panel--${variant}`]\n\n return (\n <div className={rootClasses.join(' ')} ref={ref} {...rest}>\n <div\n className=\"vgui-tabs__strip\"\n role=\"tablist\"\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n onKeyDown={handleKeyDown}\n >\n {tabs.map((tab) => {\n const isSelected = tab.id === selectedId\n const tabClasses = ['vgui-tabs__tab']\n if (isSelected) tabClasses.push('vgui-tabs__tab--selected')\n if (tab.disabled) tabClasses.push('vgui-tabs__tab--disabled')\n\n const shared = {\n className: tabClasses.join(' '),\n id: `${baseId}-tab-${tab.id}`,\n role: 'tab' as const,\n 'aria-selected': isSelected,\n 'aria-controls': `${baseId}-panel-${tab.id}`,\n 'aria-disabled': tab.disabled || undefined,\n 'aria-keyshortcuts': tab.closable && !tab.disabled ? 'Delete' : undefined,\n tabIndex: isSelected ? 0 : -1,\n 'data-tab-id': tab.id,\n onClick: () => selectTab(tab.id),\n }\n\n const label = <span className=\"vgui-tabs__label\">{tab.label}</span>\n\n if (!tab.closable) {\n return (\n <button\n key={tab.id}\n type=\"button\"\n disabled={tab.disabled}\n {...shared}\n ref={(node) => {\n setTabNode(tab.id, node)\n }}\n >\n {label}\n </button>\n )\n }\n\n // A `role=\"tab\"` element has presentational children, so the close\n // affordance must not be focusable or it breaks the tab's own\n // interaction model (axe `nested-interactive`). Keyboard users close\n // the tab with Delete, announced through `aria-keyshortcuts`.\n return (\n <div\n key={tab.id}\n {...shared}\n ref={(node) => {\n setTabNode(tab.id, node)\n }}\n >\n {label}\n {tab.disabled ? null : (\n <span\n className=\"vgui-tabs__close\"\n aria-hidden=\"true\"\n title={`Close ${tab.label} tab`}\n onClick={(event: MouseEvent<HTMLSpanElement>) => {\n event.stopPropagation()\n tab.onClose?.()\n }}\n >\n ✕\n </span>\n )}\n </div>\n )\n })}\n </div>\n\n {tabs.map((tab) => {\n const isSelected = tab.id === selectedId\n const rendered = !tab.lazy || isSelected || visited.includes(tab.id)\n if (!rendered) return null\n return (\n <div\n key={tab.id}\n className={panelClasses.join(' ')}\n role=\"tabpanel\"\n id={`${baseId}-panel-${tab.id}`}\n aria-labelledby={`${baseId}-tab-${tab.id}`}\n tabIndex={0}\n hidden={!isSelected}\n >\n {tab.content}\n </div>\n )\n })}\n </div>\n )\n})\n\nTabs.displayName = 'Tabs'\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Tabs/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAC7B,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Green Steam text field — VGUI `TextEntry` (docs/components/TextInput.md).
|
|
3
|
+
*
|
|
4
|
+
* Two things define the look and are easy to "improve" away:
|
|
5
|
+
*
|
|
6
|
+
* 1. The interior is genuinely black rather than `--vgui-surface`. It is the
|
|
7
|
+
* darkest surface in the theme, so the value text on it reaches 15.31:1 —
|
|
8
|
+
* the best contrast pairing in the library.
|
|
9
|
+
* 2. The inset is `4 0 4 0`: horizontal padding only, which is what makes a
|
|
10
|
+
* VGUI field feel tight.
|
|
11
|
+
*
|
|
12
|
+
* The black interior is read through `--vgui-field-bg`, the token
|
|
13
|
+
* docs/components/TextInput.md asks the token layer to add. No literal fallback
|
|
14
|
+
* is declared here: components in this library never contain a colour value.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
.vgui-text-input {
|
|
18
|
+
/* Component-local metrics. The palette is never declared locally. */
|
|
19
|
+
--vgui-text-input-height: 19px;
|
|
20
|
+
--vgui-text-input-icon-inset: 20px;
|
|
21
|
+
--vgui-text-input-suffix-inset: 28px;
|
|
22
|
+
|
|
23
|
+
position: relative;
|
|
24
|
+
display: inline-flex;
|
|
25
|
+
align-items: center;
|
|
26
|
+
min-width: 0;
|
|
27
|
+
font: inherit;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.vgui-text-input__field {
|
|
31
|
+
box-sizing: border-box;
|
|
32
|
+
width: 100%;
|
|
33
|
+
min-width: 0;
|
|
34
|
+
min-height: var(--vgui-text-input-height);
|
|
35
|
+
padding: 0 var(--vgui-field-inset);
|
|
36
|
+
font: inherit;
|
|
37
|
+
color: var(--vgui-text);
|
|
38
|
+
background-color: var(--vgui-field-bg);
|
|
39
|
+
/* The UA draws a rounded, inset native field; the bevel replaces it. */
|
|
40
|
+
appearance: none;
|
|
41
|
+
border-top: var(--vgui-bevel-width) solid var(--vgui-bevel-dark);
|
|
42
|
+
border-left: var(--vgui-bevel-width) solid var(--vgui-bevel-dark);
|
|
43
|
+
border-bottom: var(--vgui-bevel-width) solid var(--vgui-bevel-light);
|
|
44
|
+
border-right: var(--vgui-bevel-width) solid var(--vgui-bevel-light);
|
|
45
|
+
/* Explicit because `appearance: none` still leaves Safari rounding corners. */
|
|
46
|
+
border-radius: 0;
|
|
47
|
+
caret-color: var(--vgui-text);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.vgui-text-input__field::placeholder {
|
|
51
|
+
color: var(--vgui-text-dim);
|
|
52
|
+
/* Firefox dims placeholders to 0.54 by default. */
|
|
53
|
+
opacity: 1;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/*
|
|
57
|
+
* Valve's ring for a field is `1px dotted black`, drawn over an interior where
|
|
58
|
+
* it is invisible rather than merely low-contrast. The accent ring is the
|
|
59
|
+
* default; the faithful one stays reachable through `.vgui-crisp`.
|
|
60
|
+
*/
|
|
61
|
+
.vgui-text-input__field:focus-visible {
|
|
62
|
+
outline: var(--vgui-focus-ring);
|
|
63
|
+
outline-offset: var(--vgui-focus-ring-offset);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.vgui-crisp .vgui-text-input__field:focus-visible {
|
|
67
|
+
outline: var(--vgui-focus-ring-valve);
|
|
68
|
+
outline-offset: var(--vgui-focus-ring-valve-offset);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/* `#232421` on the accent is 4.39:1; the theme's body colour is only 2.59:1. */
|
|
72
|
+
.vgui-text-input__field::selection {
|
|
73
|
+
background-color: var(--vgui-selection-bg);
|
|
74
|
+
color: var(--vgui-selection-text);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/* Read-only stays legible and selectable; disabled is not submitted at all. */
|
|
78
|
+
.vgui-text-input__field:read-only {
|
|
79
|
+
color: var(--vgui-text-muted);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.vgui-text-input__field:disabled {
|
|
83
|
+
color: var(--vgui-text-disabled);
|
|
84
|
+
text-shadow: 1px 1px 0 var(--vgui-text-disabled-shadow);
|
|
85
|
+
cursor: not-allowed;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.vgui-text-input--invalid .vgui-text-input__field {
|
|
89
|
+
border-top-color: var(--vgui-danger);
|
|
90
|
+
border-left-color: var(--vgui-danger);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.vgui-text-input--large .vgui-text-input__field {
|
|
94
|
+
min-height: var(--vgui-control-height);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.vgui-text-input__adornment {
|
|
98
|
+
position: absolute;
|
|
99
|
+
display: flex;
|
|
100
|
+
align-items: center;
|
|
101
|
+
color: var(--vgui-text-dim);
|
|
102
|
+
pointer-events: none;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.vgui-text-input__adornment--start {
|
|
106
|
+
left: var(--vgui-field-inset);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.vgui-text-input__adornment--end {
|
|
110
|
+
right: var(--vgui-field-inset);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.vgui-text-input--with-icon .vgui-text-input__field {
|
|
114
|
+
padding-left: var(--vgui-text-input-icon-inset);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.vgui-text-input--with-suffix .vgui-text-input__field {
|
|
118
|
+
padding-right: var(--vgui-text-input-suffix-inset);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/*
|
|
122
|
+
* `--clay` is a hook rather than a repaint: the field itself stays black inside
|
|
123
|
+
* a property sheet and only the chrome around it turns grey, so the class
|
|
124
|
+
* declares nothing beyond the adornment glyph colour.
|
|
125
|
+
*/
|
|
126
|
+
.vgui-text-input--clay .vgui-text-input__adornment {
|
|
127
|
+
color: var(--vgui-clay-glyph);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.vgui-text-input--clay .vgui-text-input__field:disabled {
|
|
131
|
+
color: var(--vgui-clay-glyph-dim);
|
|
132
|
+
text-shadow: none;
|
|
133
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { InputHTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
import './TextInput.css';
|
|
3
|
+
export interface TextInputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size'> {
|
|
4
|
+
/** Field height: `default` is 19px, `large` is 25px and lines up with a Button. */
|
|
5
|
+
size?: 'default' | 'large';
|
|
6
|
+
/** Glyph shown inside the field's leading edge. */
|
|
7
|
+
icon?: ReactNode | string;
|
|
8
|
+
/** Text shown inside the field's trailing edge, e.g. a unit. */
|
|
9
|
+
suffix?: ReactNode;
|
|
10
|
+
/** Draw the invalid bevel. Does not set aria-invalid. */
|
|
11
|
+
invalid?: boolean;
|
|
12
|
+
/** Grey property-sheet chrome. */
|
|
13
|
+
clay?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare const TextInput: import("react").ForwardRefExoticComponent<TextInputProps & import("react").RefAttributes<HTMLInputElement>>;
|
|
16
|
+
//# sourceMappingURL=TextInput.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TextInput.d.ts","sourceRoot":"","sources":["../../../src/components/TextInput/TextInput.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAE3D,OAAO,iBAAiB,CAAA;AAExB,MAAM,WAAW,cAAe,SAAQ,IAAI,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACzF,mFAAmF;IACnF,IAAI,CAAC,EAAE,SAAS,GAAG,OAAO,CAAA;IAC1B,mDAAmD;IACnD,IAAI,CAAC,EAAE,SAAS,GAAG,MAAM,CAAA;IACzB,gEAAgE;IAChE,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB,yDAAyD;IACzD,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,kCAAkC;IAClC,IAAI,CAAC,EAAE,OAAO,CAAA;CACf;AAED,eAAO,MAAM,SAAS,6GAiCpB,CAAA"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { forwardRef } from "react";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import "./TextInput.css";
|
|
4
|
+
//#region src/components/TextInput/TextInput.tsx
|
|
5
|
+
var TextInput = forwardRef(function TextInput({ className, size = "default", icon, suffix, invalid = false, clay = false, ...rest }, ref) {
|
|
6
|
+
const classes = ["vgui-text-input"];
|
|
7
|
+
if (size === "large") classes.push("vgui-text-input--large");
|
|
8
|
+
if (icon != null) classes.push("vgui-text-input--with-icon");
|
|
9
|
+
if (suffix != null) classes.push("vgui-text-input--with-suffix");
|
|
10
|
+
if (invalid) classes.push("vgui-text-input--invalid");
|
|
11
|
+
if (clay) classes.push("vgui-text-input--clay");
|
|
12
|
+
if (className) classes.push(className);
|
|
13
|
+
return /* @__PURE__ */ jsxs("span", {
|
|
14
|
+
className: classes.join(" "),
|
|
15
|
+
children: [
|
|
16
|
+
icon != null ? /* @__PURE__ */ jsx("span", {
|
|
17
|
+
className: "vgui-text-input__adornment vgui-text-input__adornment--start",
|
|
18
|
+
"aria-hidden": "true",
|
|
19
|
+
children: icon
|
|
20
|
+
}) : null,
|
|
21
|
+
/* @__PURE__ */ jsx("input", {
|
|
22
|
+
ref,
|
|
23
|
+
className: "vgui-text-input__field",
|
|
24
|
+
...rest
|
|
25
|
+
}),
|
|
26
|
+
suffix != null ? /* @__PURE__ */ jsx("span", {
|
|
27
|
+
className: "vgui-text-input__adornment vgui-text-input__adornment--end",
|
|
28
|
+
"aria-hidden": "true",
|
|
29
|
+
children: suffix
|
|
30
|
+
}) : null
|
|
31
|
+
]
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
TextInput.displayName = "TextInput";
|
|
35
|
+
//#endregion
|
|
36
|
+
export { TextInput };
|
|
37
|
+
|
|
38
|
+
//# sourceMappingURL=TextInput.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TextInput.js","names":[],"sources":["../../../src/components/TextInput/TextInput.tsx"],"sourcesContent":["import { forwardRef } from 'react'\nimport type { InputHTMLAttributes, ReactNode } from 'react'\n\nimport './TextInput.css'\n\nexport interface TextInputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size'> {\n /** Field height: `default` is 19px, `large` is 25px and lines up with a Button. */\n size?: 'default' | 'large'\n /** Glyph shown inside the field's leading edge. */\n icon?: ReactNode | string\n /** Text shown inside the field's trailing edge, e.g. a unit. */\n suffix?: ReactNode\n /** Draw the invalid bevel. Does not set aria-invalid. */\n invalid?: boolean\n /** Grey property-sheet chrome. */\n clay?: boolean\n}\n\nexport const TextInput = forwardRef<HTMLInputElement, TextInputProps>(function TextInput(\n { className, size = 'default', icon, suffix, invalid = false, clay = false, ...rest },\n ref,\n) {\n const classes = ['vgui-text-input']\n if (size === 'large') classes.push('vgui-text-input--large')\n if (icon != null) classes.push('vgui-text-input--with-icon')\n if (suffix != null) classes.push('vgui-text-input--with-suffix')\n if (invalid) classes.push('vgui-text-input--invalid')\n if (clay) classes.push('vgui-text-input--clay')\n if (className) classes.push(className)\n\n return (\n <span className={classes.join(' ')}>\n {icon != null ? (\n <span\n className=\"vgui-text-input__adornment vgui-text-input__adornment--start\"\n aria-hidden=\"true\"\n >\n {icon}\n </span>\n ) : null}\n <input ref={ref} className=\"vgui-text-input__field\" {...rest} />\n {suffix != null ? (\n <span\n className=\"vgui-text-input__adornment vgui-text-input__adornment--end\"\n aria-hidden=\"true\"\n >\n {suffix}\n </span>\n ) : null}\n </span>\n )\n})\n\nTextInput.displayName = 'TextInput'\n"],"mappings":";;;;AAkBA,IAAa,YAAY,WAA6C,SAAS,UAC7E,EAAE,WAAW,OAAO,WAAW,MAAM,QAAQ,UAAU,OAAO,OAAO,OAAO,GAAG,QAC/E,KACA;CACA,MAAM,UAAU,CAAC,iBAAiB;CAClC,IAAI,SAAS,SAAS,QAAQ,KAAK,wBAAwB;CAC3D,IAAI,QAAQ,MAAM,QAAQ,KAAK,4BAA4B;CAC3D,IAAI,UAAU,MAAM,QAAQ,KAAK,8BAA8B;CAC/D,IAAI,SAAS,QAAQ,KAAK,0BAA0B;CACpD,IAAI,MAAM,QAAQ,KAAK,uBAAuB;CAC9C,IAAI,WAAW,QAAQ,KAAK,SAAS;CAErC,OACE,qBAAC,QAAD;EAAM,WAAW,QAAQ,KAAK,GAAG;EAAjC,UAAA;GACG,QAAQ,OACP,oBAAC,QAAD;IACE,WAAU;IACV,eAAY;IAEX,UAAA;GACG,CAAA,IACJ;GACJ,oBAAC,SAAD;IAAY;IAAK,WAAU;IAAyB,GAAI;GAAO,CAAA;GAC9D,UAAU,OACT,oBAAC,QAAD;IACE,WAAU;IACV,eAAY;IAEX,UAAA;GACG,CAAA,IACJ;EACA;;AAEV,CAAC;AAED,UAAU,cAAc"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/TextInput/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Green Steam multi-line text field — VGUI `TextEntry` with
|
|
3
|
+
* `SetMultiline(true)` (docs/components/Textarea.md).
|
|
4
|
+
*
|
|
5
|
+
* The chrome is identical to TextInput: black interior, inset bevel, 1px caret.
|
|
6
|
+
* Everything else is behavioural, which is why there is no separate VGUI class.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
.vgui-textarea {
|
|
10
|
+
--vgui-textarea-min-height: 60px;
|
|
11
|
+
|
|
12
|
+
position: relative;
|
|
13
|
+
display: block;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.vgui-textarea__field {
|
|
17
|
+
box-sizing: border-box;
|
|
18
|
+
display: block;
|
|
19
|
+
width: 100%;
|
|
20
|
+
/* `rows="1"` on a 200%-zoom browser is a sliver, so a floor is always kept. */
|
|
21
|
+
min-height: var(--vgui-textarea-min-height);
|
|
22
|
+
/* The `4 0 4 0` inset, plus 2px of vertical breathing room. */
|
|
23
|
+
padding: 2px var(--vgui-field-inset);
|
|
24
|
+
font: inherit;
|
|
25
|
+
line-height: var(--vgui-line-height);
|
|
26
|
+
color: var(--vgui-text);
|
|
27
|
+
background-color: var(--vgui-field-bg);
|
|
28
|
+
border-top: var(--vgui-bevel-width) solid var(--vgui-bevel-dark);
|
|
29
|
+
border-left: var(--vgui-bevel-width) solid var(--vgui-bevel-dark);
|
|
30
|
+
border-bottom: var(--vgui-bevel-width) solid var(--vgui-bevel-light);
|
|
31
|
+
border-right: var(--vgui-bevel-width) solid var(--vgui-bevel-light);
|
|
32
|
+
border-radius: 0;
|
|
33
|
+
/* Vertical only: a horizontally resizable field reflows the whole page. */
|
|
34
|
+
resize: vertical;
|
|
35
|
+
overflow: auto;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.vgui-textarea__field::placeholder {
|
|
39
|
+
color: var(--vgui-text-dim);
|
|
40
|
+
opacity: 1;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.vgui-textarea__field::selection {
|
|
44
|
+
background-color: var(--vgui-selection-bg);
|
|
45
|
+
color: var(--vgui-selection-text);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/*
|
|
49
|
+
* The worst case for the Valve ring: the dotted black outline is drawn over the
|
|
50
|
+
* field's own black interior, where it is literally invisible. The accent ring
|
|
51
|
+
* is the default and the faithful one is reachable through `.vgui-crisp`.
|
|
52
|
+
*/
|
|
53
|
+
.vgui-textarea__field:focus-visible {
|
|
54
|
+
outline: var(--vgui-focus-ring);
|
|
55
|
+
outline-offset: var(--vgui-focus-ring-offset);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.vgui-crisp .vgui-textarea__field:focus-visible {
|
|
59
|
+
outline: var(--vgui-focus-ring-valve);
|
|
60
|
+
outline-offset: var(--vgui-focus-ring-valve-offset);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.vgui-textarea__field:read-only {
|
|
64
|
+
color: var(--vgui-text-muted);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.vgui-textarea__field:disabled {
|
|
68
|
+
color: var(--vgui-text-disabled);
|
|
69
|
+
text-shadow: 1px 1px 0 var(--vgui-text-disabled-shadow);
|
|
70
|
+
cursor: not-allowed;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.vgui-textarea--invalid .vgui-textarea__field {
|
|
74
|
+
border-top-color: var(--vgui-danger);
|
|
75
|
+
border-left-color: var(--vgui-danger);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/* `--fixed`: height comes from `rows` alone. */
|
|
79
|
+
.vgui-textarea--fixed .vgui-textarea__field {
|
|
80
|
+
resize: none;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/*
|
|
84
|
+
* `--auto-grow` height is set by JS from `scrollHeight`; `max-height` and
|
|
85
|
+
* `overflow-y` are the fallback for tall content. `height: auto` is deliberately
|
|
86
|
+
* not declared here — the script needs `auto` only for the measurement pass.
|
|
87
|
+
*/
|
|
88
|
+
.vgui-textarea--auto-grow .vgui-textarea__field {
|
|
89
|
+
resize: none;
|
|
90
|
+
overflow: hidden;
|
|
91
|
+
overflow-y: auto;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.vgui-textarea--mono .vgui-textarea__field {
|
|
95
|
+
font-family: var(--vgui-font-mono);
|
|
96
|
+
font-size: var(--vgui-font-size-small);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/*
|
|
100
|
+
* The counter overlays the field's trailing corner rather than taking a row of
|
|
101
|
+
* its own: a VGUI property sheet has no space for one, and `aria-hidden` means
|
|
102
|
+
* it never has to be read out.
|
|
103
|
+
*/
|
|
104
|
+
.vgui-textarea__count {
|
|
105
|
+
position: absolute;
|
|
106
|
+
right: var(--vgui-field-inset);
|
|
107
|
+
bottom: 2px;
|
|
108
|
+
font-size: var(--vgui-font-size-small);
|
|
109
|
+
color: var(--vgui-text-dim);
|
|
110
|
+
pointer-events: none;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/* `--clay` has no prop of its own; callers opt in through `className`. */
|
|
114
|
+
.vgui-textarea--clay .vgui-textarea__field:disabled {
|
|
115
|
+
color: var(--vgui-clay-glyph-dim);
|
|
116
|
+
text-shadow: none;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.vgui-textarea--clay .vgui-textarea__count {
|
|
120
|
+
color: var(--vgui-clay-glyph-dim);
|
|
121
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { TextareaHTMLAttributes } from 'react';
|
|
2
|
+
import './Textarea.css';
|
|
3
|
+
import '../../styles/scrollbars.css';
|
|
4
|
+
export interface TextareaProps extends Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, 'children'> {
|
|
5
|
+
/** Visible rows. Sets `rows`; the 60px `min-height` still applies. */
|
|
6
|
+
rows?: number;
|
|
7
|
+
/** Grow to fit content instead of scrolling, up to `maxHeight`. */
|
|
8
|
+
autoGrow?: boolean;
|
|
9
|
+
/** Cap for `autoGrow`, in pixels. Defaults to 240. */
|
|
10
|
+
maxHeight?: number;
|
|
11
|
+
/** Prevent the user from resizing the field. Defaults to `vertical`. */
|
|
12
|
+
resize?: 'none' | 'vertical';
|
|
13
|
+
/** Monospaced text, for console and config content. */
|
|
14
|
+
mono?: boolean;
|
|
15
|
+
/** Show a live character count, expressed against `maxLength` when given. */
|
|
16
|
+
showCount?: boolean;
|
|
17
|
+
/** Render the invalid border. Does not set aria-invalid. */
|
|
18
|
+
invalid?: boolean;
|
|
19
|
+
}
|
|
20
|
+
export declare const Textarea: import("react").ForwardRefExoticComponent<TextareaProps & import("react").RefAttributes<HTMLTextAreaElement>>;
|
|
21
|
+
//# sourceMappingURL=Textarea.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Textarea.d.ts","sourceRoot":"","sources":["../../../src/components/Textarea/Textarea.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAc,sBAAsB,EAAE,MAAM,OAAO,CAAA;AAE/D,OAAO,gBAAgB,CAAA;AACvB,OAAO,6BAA6B,CAAA;AAEpC,MAAM,WAAW,aAAc,SAAQ,IAAI,CAAC,sBAAsB,CAAC,mBAAmB,CAAC,EAAE,UAAU,CAAC;IAClG,sEAAsE;IACtE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,mEAAmE;IACnE,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,wEAAwE;IACxE,MAAM,CAAC,EAAE,MAAM,GAAG,UAAU,CAAA;IAC5B,uDAAuD;IACvD,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,6EAA6E;IAC7E,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,4DAA4D;IAC5D,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,eAAO,MAAM,QAAQ,+GAqFnB,CAAA"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { forwardRef, useCallback, useLayoutEffect, useRef, useState } from "react";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import "../../styles/scrollbars.css";
|
|
4
|
+
import "./Textarea.css";
|
|
5
|
+
//#region src/components/Textarea/Textarea.tsx
|
|
6
|
+
var Textarea = forwardRef(function Textarea({ className, rows, autoGrow = false, maxHeight = 240, resize = "vertical", mono = false, showCount = false, invalid = false, value, defaultValue, maxLength, onInput, style, ...rest }, ref) {
|
|
7
|
+
const fieldRef = useRef(null);
|
|
8
|
+
const [uncontrolledLength, setUncontrolledLength] = useState(() => String(defaultValue ?? "").length);
|
|
9
|
+
const setRefs = useCallback((node) => {
|
|
10
|
+
fieldRef.current = node;
|
|
11
|
+
if (typeof ref === "function") ref(node);
|
|
12
|
+
else if (ref) ref.current = node;
|
|
13
|
+
}, [ref]);
|
|
14
|
+
const resizeToContent = useCallback(() => {
|
|
15
|
+
const field = fieldRef.current;
|
|
16
|
+
if (!field) return;
|
|
17
|
+
field.style.height = "auto";
|
|
18
|
+
field.style.height = `${Math.min(field.scrollHeight, maxHeight)}px`;
|
|
19
|
+
}, [maxHeight]);
|
|
20
|
+
useLayoutEffect(() => {
|
|
21
|
+
if (autoGrow) resizeToContent();
|
|
22
|
+
});
|
|
23
|
+
const classes = ["vgui-textarea"];
|
|
24
|
+
if (resize === "none") classes.push("vgui-textarea--fixed");
|
|
25
|
+
if (autoGrow) classes.push("vgui-textarea--auto-grow");
|
|
26
|
+
if (mono) classes.push("vgui-textarea--mono");
|
|
27
|
+
if (invalid) classes.push("vgui-textarea--invalid");
|
|
28
|
+
if (className) classes.push(className);
|
|
29
|
+
const length = value !== void 0 ? String(value).length : uncontrolledLength;
|
|
30
|
+
const handleInput = (event) => {
|
|
31
|
+
if (value === void 0) setUncontrolledLength(event.currentTarget.value.length);
|
|
32
|
+
if (autoGrow) resizeToContent();
|
|
33
|
+
onInput?.(event);
|
|
34
|
+
};
|
|
35
|
+
return /* @__PURE__ */ jsxs("span", {
|
|
36
|
+
className: classes.join(" "),
|
|
37
|
+
children: [/* @__PURE__ */ jsx("textarea", {
|
|
38
|
+
ref: setRefs,
|
|
39
|
+
className: "vgui-textarea__field vgui-scroll-surface",
|
|
40
|
+
rows,
|
|
41
|
+
value,
|
|
42
|
+
defaultValue,
|
|
43
|
+
maxLength,
|
|
44
|
+
style: autoGrow ? {
|
|
45
|
+
...style,
|
|
46
|
+
maxHeight
|
|
47
|
+
} : style,
|
|
48
|
+
onInput: handleInput,
|
|
49
|
+
...rest
|
|
50
|
+
}), showCount ? /* @__PURE__ */ jsx("span", {
|
|
51
|
+
className: "vgui-textarea__count",
|
|
52
|
+
"aria-hidden": "true",
|
|
53
|
+
children: maxLength != null ? `${length} / ${maxLength}` : length
|
|
54
|
+
}) : null]
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
Textarea.displayName = "Textarea";
|
|
58
|
+
//#endregion
|
|
59
|
+
export { Textarea };
|
|
60
|
+
|
|
61
|
+
//# sourceMappingURL=Textarea.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Textarea.js","names":[],"sources":["../../../src/components/Textarea/Textarea.tsx"],"sourcesContent":["import { forwardRef, useCallback, useLayoutEffect, useRef, useState } from 'react'\nimport type { InputEvent, TextareaHTMLAttributes } from 'react'\n\nimport './Textarea.css'\nimport '../../styles/scrollbars.css'\n\nexport interface TextareaProps extends Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, 'children'> {\n /** Visible rows. Sets `rows`; the 60px `min-height` still applies. */\n rows?: number\n /** Grow to fit content instead of scrolling, up to `maxHeight`. */\n autoGrow?: boolean\n /** Cap for `autoGrow`, in pixels. Defaults to 240. */\n maxHeight?: number\n /** Prevent the user from resizing the field. Defaults to `vertical`. */\n resize?: 'none' | 'vertical'\n /** Monospaced text, for console and config content. */\n mono?: boolean\n /** Show a live character count, expressed against `maxLength` when given. */\n showCount?: boolean\n /** Render the invalid border. Does not set aria-invalid. */\n invalid?: boolean\n}\n\nexport const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(function Textarea(\n {\n className,\n rows,\n autoGrow = false,\n maxHeight = 240,\n resize = 'vertical',\n mono = false,\n showCount = false,\n invalid = false,\n value,\n defaultValue,\n maxLength,\n onInput,\n style,\n ...rest\n },\n ref,\n) {\n const fieldRef = useRef<HTMLTextAreaElement>(null)\n const [uncontrolledLength, setUncontrolledLength] = useState(\n () => String(defaultValue ?? '').length,\n )\n\n const setRefs = useCallback(\n (node: HTMLTextAreaElement | null) => {\n fieldRef.current = node\n if (typeof ref === 'function') {\n ref(node)\n } else if (ref) {\n ref.current = node\n }\n },\n [ref],\n )\n\n const resizeToContent = useCallback(() => {\n const field = fieldRef.current\n if (!field) return\n // Mirror `scrollHeight`: it is only meaningful once the box is unconstrained.\n field.style.height = 'auto'\n field.style.height = `${Math.min(field.scrollHeight, maxHeight)}px`\n }, [maxHeight])\n\n // Runs after every render so a controlled value resizes the box too. An\n // uncontrolled field does not re-render, hence the `onInput` hook below.\n useLayoutEffect(() => {\n if (autoGrow) resizeToContent()\n })\n\n const classes = ['vgui-textarea']\n if (resize === 'none') classes.push('vgui-textarea--fixed')\n if (autoGrow) classes.push('vgui-textarea--auto-grow')\n if (mono) classes.push('vgui-textarea--mono')\n if (invalid) classes.push('vgui-textarea--invalid')\n if (className) classes.push(className)\n\n const length = value !== undefined ? String(value).length : uncontrolledLength\n\n const handleInput = (event: InputEvent<HTMLTextAreaElement>) => {\n if (value === undefined) setUncontrolledLength(event.currentTarget.value.length)\n if (autoGrow) resizeToContent()\n onInput?.(event)\n }\n\n return (\n <span className={classes.join(' ')}>\n <textarea\n ref={setRefs}\n className=\"vgui-textarea__field vgui-scroll-surface\"\n rows={rows}\n value={value}\n defaultValue={defaultValue}\n maxLength={maxLength}\n style={autoGrow ? { ...style, maxHeight } : style}\n onInput={handleInput}\n {...rest}\n />\n {showCount ? (\n <span className=\"vgui-textarea__count\" aria-hidden=\"true\">\n {maxLength != null ? `${length} / ${maxLength}` : length}\n </span>\n ) : null}\n </span>\n )\n})\n\nTextarea.displayName = 'Textarea'\n"],"mappings":";;;;;AAuBA,IAAa,WAAW,WAA+C,SAAS,SAC9E,EACE,WACA,MACA,WAAW,OACX,YAAY,KACZ,SAAS,YACT,OAAO,OACP,YAAY,OACZ,UAAU,OACV,OACA,cACA,WACA,SACA,OACA,GAAG,QAEL,KACA;CACA,MAAM,WAAW,OAA4B,IAAI;CACjD,MAAM,CAAC,oBAAoB,yBAAyB,eAC5C,OAAO,gBAAgB,EAAE,CAAC,CAAC,MACnC;CAEA,MAAM,UAAU,aACb,SAAqC;EACpC,SAAS,UAAU;EACnB,IAAI,OAAO,QAAQ,YACjB,IAAI,IAAI;OACH,IAAI,KACT,IAAI,UAAU;CAElB,GACA,CAAC,GAAG,CACN;CAEA,MAAM,kBAAkB,kBAAkB;EACxC,MAAM,QAAQ,SAAS;EACvB,IAAI,CAAC,OAAO;EAEZ,MAAM,MAAM,SAAS;EACrB,MAAM,MAAM,SAAS,GAAG,KAAK,IAAI,MAAM,cAAc,SAAS,EAAE;CAClE,GAAG,CAAC,SAAS,CAAC;CAId,sBAAsB;EACpB,IAAI,UAAU,gBAAgB;CAChC,CAAC;CAED,MAAM,UAAU,CAAC,eAAe;CAChC,IAAI,WAAW,QAAQ,QAAQ,KAAK,sBAAsB;CAC1D,IAAI,UAAU,QAAQ,KAAK,0BAA0B;CACrD,IAAI,MAAM,QAAQ,KAAK,qBAAqB;CAC5C,IAAI,SAAS,QAAQ,KAAK,wBAAwB;CAClD,IAAI,WAAW,QAAQ,KAAK,SAAS;CAErC,MAAM,SAAS,UAAU,KAAA,IAAY,OAAO,KAAK,CAAC,CAAC,SAAS;CAE5D,MAAM,eAAe,UAA2C;EAC9D,IAAI,UAAU,KAAA,GAAW,sBAAsB,MAAM,cAAc,MAAM,MAAM;EAC/E,IAAI,UAAU,gBAAgB;EAC9B,UAAU,KAAK;CACjB;CAEA,OACE,qBAAC,QAAD;EAAM,WAAW,QAAQ,KAAK,GAAG;EAAjC,UAAA,CACE,oBAAC,YAAD;GACE,KAAK;GACL,WAAU;GACJ;GACC;GACO;GACH;GACX,OAAO,WAAW;IAAE,GAAG;IAAO;GAAU,IAAI;GAC5C,SAAS;GACT,GAAI;EACL,CAAA,GACA,YACC,oBAAC,QAAD;GAAM,WAAU;GAAuB,eAAY;GAChD,UAAA,aAAa,OAAO,GAAG,OAAO,KAAK,cAAc;EAC9C,CAAA,IACJ,IACA;;AAEV,CAAC;AAED,SAAS,cAAc"}
|