tgui-core 2.1.0 → 3.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/dist/common/keys.d.ts +2 -0
- package/dist/common/keys.js +1 -1
- package/dist/components/Box.d.ts +1 -1
- package/dist/components/Floating.js +1 -1
- package/dist/components/ImageButton.js +1 -1
- package/dist/components/Input.d.ts +51 -41
- package/dist/components/Input.js +1 -1
- package/dist/components/RestrictedInput.d.ts +38 -21
- package/dist/components/RestrictedInput.js +1 -1
- package/dist/components/TextArea.d.ts +10 -32
- package/dist/components/TextArea.js +1 -1
- package/package.json +1 -1
- package/styles/components/ImageButton.scss +60 -11
- package/styles/components/Input.scss +30 -48
- package/styles/components/TextArea.scss +0 -79
- package/styles/vars-components.scss +11 -0
package/dist/common/keys.d.ts
CHANGED
package/dist/common/keys.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var r,e=((r={}).A="a",r.Alt="Alt",r.Backspace="Backspace",r.Control="Control",r.D="d",r.Delete="Delete",r.Down="ArrowDown",r.E="e",r.End="End",r.Enter="Enter",r.Esc="Esc",r.Escape="Escape",r.Home="Home",r.Insert="Insert",r.Left="ArrowLeft",r.N="n",r.PageDown="PageDown",r.PageUp="PageUp",r.Right="ArrowRight",r.S="s",r.Shift="Shift",r.Space=" ",r.Tab="Tab",r.Up="ArrowUp",r.W="w",r.Z="z",r);function n(r){return"Esc"===r||"Escape"===r}function t(r){return r>="a"&&r<="z"}function o(r){return r>="0"&&r<="9"}function
|
|
1
|
+
var r,e=((r={}).A="a",r.Alt="Alt",r.Backspace="Backspace",r.Control="Control",r.D="d",r.Delete="Delete",r.Down="ArrowDown",r.E="e",r.End="End",r.Enter="Enter",r.Esc="Esc",r.Escape="Escape",r.Home="Home",r.Insert="Insert",r.Left="ArrowLeft",r.Minus="-",r.N="n",r.PageDown="PageDown",r.PageUp="PageUp",r.Plus="+",r.Right="ArrowRight",r.S="s",r.Shift="Shift",r.Space=" ",r.Tab="Tab",r.Up="ArrowUp",r.W="w",r.Z="z",r);function n(r){return"Esc"===r||"Escape"===r}function t(r){return r>="a"&&r<="z"}function o(r){return r>="0"&&r<="9"}function s(r){return"n"===r||"s"===r||"w"===r||"e"===r}function a(r){return"ArrowUp"===r||"ArrowDown"===r||"ArrowLeft"===r||"ArrowRight"===r}function i(r){return"w"===r||"a"===r||"s"===r||"d"===r}function c(r){return i(r)||a(r)}export{e as KEY,t as isAlphabetic,a as isArrow,s as isCardinal,n as isEscape,c as isMovement,o as isNumeric,i as isWasd};
|
package/dist/components/Box.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ type EventHandlers = {
|
|
|
12
12
|
onMouseMove: MouseEventHandler<HTMLDivElement>;
|
|
13
13
|
onMouseOver: MouseEventHandler<HTMLDivElement>;
|
|
14
14
|
onMouseUp: MouseEventHandler<HTMLDivElement>;
|
|
15
|
-
onScroll: UIEventHandler<HTMLDivElement>;
|
|
15
|
+
onScroll: UIEventHandler<HTMLDivElement | HTMLTextAreaElement>;
|
|
16
16
|
};
|
|
17
17
|
type InternalProps = {
|
|
18
18
|
/** The component used for the root node. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import*as e from"react/jsx-runtime";import*as t from"@floating-ui/react";import*as a from"react";import*as n from"../common/react.js";function o(o){let s,{allowedOutsideClasses:i,animationDuration:r,children:l,closeAfterInteract:c,content:m,contentAutoWidth:d,contentClasses:p,contentOffset:f=6,contentStyles:u,disabled:g,hoverDelay:h,hoverOpen:x,onMounted:F,placement:b,stopChildPropagation:j,onOpenChange:C}=o,[k,v]=(0,a.useState)(!1),{refs:w,floatingStyles:E,context:P}=(0,t.useFloating)({open:k,onOpenChange(e){v(e),C?.(e)},whileElementsMounted:(e,a,n)=>(void 0!==F&&F(),(0,t.autoUpdate)(e,a,n)),placement:b||"bottom",transform:!1,middleware:[(0,t.offset)(f),(0,t.flip)({padding:6,fallbackPlacements:["bottom-start","bottom-end","top","top-start","top-end"]}),d&&(0,t.size)({apply({rects:e,elements:t}){t.floating.style.width=`${e.reference.width}px`}})]}),{isMounted:y,status:S}=(0,t.useTransitionStatus)(P,{duration:r||200}),M=(0,t.useDismiss)(P,{ancestorScroll:!0,outsidePress:e
|
|
1
|
+
import*as e from"react/jsx-runtime";import*as t from"@floating-ui/react";import*as a from"react";import*as n from"../common/react.js";function o(o){let s,{allowedOutsideClasses:i,animationDuration:r,children:l,closeAfterInteract:c,content:m,contentAutoWidth:d,contentClasses:p,contentOffset:f=6,contentStyles:u,disabled:g,hoverDelay:h,hoverOpen:x,onMounted:F,placement:b,stopChildPropagation:j,onOpenChange:C}=o,[k,v]=(0,a.useState)(!1),{refs:w,floatingStyles:E,context:P}=(0,t.useFloating)({open:k,onOpenChange(e){v(e),C?.(e)},whileElementsMounted:(e,a,n)=>(void 0!==F&&F(),(0,t.autoUpdate)(e,a,n)),placement:b||"bottom",transform:!1,middleware:[(0,t.offset)(f),(0,t.flip)({padding:6,fallbackPlacements:["bottom-start","bottom-end","top","top-start","top-end"]}),d&&(0,t.size)({apply({rects:e,elements:t}){t.floating.style.width=`${e.reference.width}px`}})]}),{isMounted:y,status:S}=(0,t.useTransitionStatus)(P,{duration:r||200}),M=(0,t.useDismiss)(P,{ancestorScroll:!0,outsidePress:e=>!i||e.target instanceof Element&&!e.target.closest(i)}),O=(0,t.useClick)(P,{enabled:!g}),z=(0,t.useHover)(P,{enabled:!g,restMs:h||200}),{getReferenceProps:D,getFloatingProps:H}=(0,t.useInteractions)([M,x?z:O]),I=D({ref:w.setReference,...j&&{onClick:e=>e.stopPropagation()}}),N=H({onClick:()=>{c&&P.onOpenChange(!1)}});return s=(0,a.isValidElement)(l)?(0,a.cloneElement)(l,I):(0,e.jsx)("div",{...I,children:l}),(0,e.jsxs)(e.Fragment,{children:[s,y&&!!m&&(0,e.jsx)(t.FloatingPortal,{children:(0,e.jsx)("div",{ref:w.setFloating,className:(0,n.classes)(["Floating",!r&&"Floating--animated",p]),"data-position":P.placement,"data-transition":S,style:{...E,...u},...N,children:m})})]})}export{o as Floating};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import*as t from"react/jsx-runtime";import*as e from"../common/react.js";import*as s from"../common/ui.js";import*as n from"./DmIcon.js";import*as o from"./Icon.js";import*as a from"./Image.js";import*as i from"./Stack.js";import*as c from"./Tooltip.js";function m(o){let{asset:i,assetSize:m=32,base64:r,buttons:
|
|
1
|
+
import*as t from"react/jsx-runtime";import*as e from"../common/react.js";import*as s from"../common/ui.js";import*as n from"./DmIcon.js";import*as o from"./Icon.js";import*as a from"./Image.js";import*as i from"./Stack.js";import*as c from"./Tooltip.js";function m(o){let{asset:i,assetSize:m=32,base64:r,buttons:u,buttonsAlt:p,children:x,className:g,color:d,disabled:I,dmFallback:_,dmIcon:h,dmIconState:j,fluid:B,imageSize:f=64,imageSrc:$,onClick:y,onRightClick:N,selected:b,title:v,tooltip:w,tooltipPosition:k,...D}=o,S=(0,t.jsxs)("div",{className:"ImageButton__container",tabIndex:I?void 0:0,onClick:t=>{!I&&y&&y(t)},onKeyDown:t=>{"Enter"===t.key&&!I&&y&&y(t)},onContextMenu:t=>{t.preventDefault(),!I&&N&&N(t)},style:{width:B?"auto":`calc(${f}px + 0.5em + 2px)`},children:[(0,t.jsx)("div",{className:"ImageButton__image",children:r||$?(0,t.jsx)(a.Image,{src:r?`data:image/png;base64,${r}`:$,height:`${f}px`,width:`${f}px`}):h&&j?(0,t.jsx)(n.DmIcon,{icon:h,icon_state:j,fallback:_||(0,t.jsx)(l,{spin:!0,icon:"spinner",size:f}),height:`${f}px`,width:`${f}px`}):i?(0,t.jsx)(a.Image,{className:(0,e.classes)(i||[]),height:`${f}px`,width:`${f}px`,style:{transform:`scale(${f/m})`,transformOrigin:"top left"}}):(0,t.jsx)(l,{icon:"question",size:f})}),B?(0,t.jsxs)("div",{className:"ImageButton__content",children:[v&&(0,t.jsx)("span",{className:(0,e.classes)(["ImageButton__content--title",!!x&&"ImageButton__content--divider"]),children:v}),x&&(0,t.jsx)("span",{className:"ImageButton__content--text",children:x})]}):!!x&&(0,t.jsx)("span",{className:"ImageButton__content",children:x})]});return w&&(S=(0,t.jsx)(c.Tooltip,{content:w,position:k,children:S})),(0,t.jsxs)("div",{className:(0,e.classes)(["ImageButton",B&&"ImageButton--fluid",b&&"ImageButton--selected",I&&"ImageButton--disabled",!x&&"ImageButton--empty",!(y||N)&&"ImageButton--noAction",d&&"string"==typeof d?`ImageButton__color--${d}`:"ImageButton__color--default",g]),...(0,s.computeBoxProps)(D),children:[S,u&&(0,t.jsx)("div",{className:(0,e.classes)(["ImageButton__buttons",!x&&"ImageButton__buttons--empty"]),style:{width:"auto"},children:u}),p&&(0,t.jsx)("div",{className:(0,e.classes)(["ImageButton__buttons","ImageButton__buttons--alt",!x&&"ImageButton__buttons--empty"]),style:{width:`calc(${f}px + ${.5*!B}em)`,maxWidth:B?"auto":`calc(${f}px + 0.5em)`},children:p})]})}function l(e){let{icon:s,spin:n,size:a=64}=e;return(0,t.jsx)(i.Stack,{height:`${a}px`,width:`${a}px`,children:(0,t.jsx)(i.Stack.Item,{grow:!0,textAlign:"center",align:"center",children:(0,t.jsx)(o.Icon,{spin:n,name:s,color:"gray",style:{fontSize:`calc(${a}px * 0.75)`}})})})}export{m as ImageButton};
|
|
@@ -1,63 +1,73 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
import {
|
|
3
|
-
type
|
|
4
|
-
/**
|
|
5
|
-
* Mark this if you want to debounce onInput.
|
|
6
|
-
*
|
|
7
|
-
* This is useful for expensive filters, large lists etc.
|
|
8
|
-
*
|
|
9
|
-
* Requires `onInput` to be set.
|
|
10
|
-
*/
|
|
11
|
-
expensive?: boolean;
|
|
12
|
-
/**
|
|
13
|
-
* Fires on each key press / value change. Used for searching.
|
|
14
|
-
*
|
|
15
|
-
* If it's a large list, consider using `expensive` prop.
|
|
16
|
-
*/
|
|
17
|
-
onInput: (event: SyntheticEvent<HTMLInputElement>, value: string) => void;
|
|
18
|
-
} | {
|
|
19
|
-
/** This prop requires onInput to be set */
|
|
20
|
-
expensive?: never;
|
|
21
|
-
onInput?: never;
|
|
22
|
-
};
|
|
23
|
-
type OptionalProps = Partial<{
|
|
1
|
+
import { type RefObject } from 'react';
|
|
2
|
+
import type { BoxProps } from './Box';
|
|
3
|
+
export type BaseInputProps = Partial<{
|
|
24
4
|
/** Automatically focuses the input on mount */
|
|
25
5
|
autoFocus: boolean;
|
|
26
6
|
/** Automatically selects the input value on focus */
|
|
27
7
|
autoSelect: boolean;
|
|
28
|
-
/**
|
|
8
|
+
/** Custom css classes */
|
|
29
9
|
className: string;
|
|
30
|
-
/** Disables the input */
|
|
10
|
+
/** Disables the input. Outlined in gray */
|
|
31
11
|
disabled: boolean;
|
|
32
|
-
/**
|
|
12
|
+
/** Fills the parent container */
|
|
33
13
|
fluid: boolean;
|
|
34
|
-
/** The maximum length of the input value */
|
|
35
|
-
maxLength: number;
|
|
36
14
|
/** Mark this if you want to use a monospace font */
|
|
37
15
|
monospace: boolean;
|
|
38
|
-
|
|
39
|
-
|
|
16
|
+
}> & BoxProps;
|
|
17
|
+
export type TextInputProps = Partial<{
|
|
18
|
+
/** The maximum length of the input value */
|
|
19
|
+
maxLength: number;
|
|
20
|
+
/** Fires each time the input has been changed */
|
|
21
|
+
onChange: (value: string) => void;
|
|
40
22
|
/** Fires once the enter key is pressed */
|
|
41
|
-
onEnter: (
|
|
23
|
+
onEnter: (value: string) => void;
|
|
42
24
|
/** Fires once the escape key is pressed */
|
|
43
|
-
onEscape: (
|
|
25
|
+
onEscape: (value: string) => void;
|
|
44
26
|
/** The placeholder text when everything is cleared */
|
|
45
27
|
placeholder: string;
|
|
46
28
|
/** Clears the input value on enter */
|
|
47
29
|
selfClear: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Generally, input can handle its own state value.
|
|
32
|
+
*
|
|
33
|
+
* Use this if you want to hold the value in the parent for external manipulation.
|
|
34
|
+
*
|
|
35
|
+
* ```tsx
|
|
36
|
+
* const [value, setValue] = useState('');
|
|
37
|
+
*
|
|
38
|
+
* return (
|
|
39
|
+
* <>
|
|
40
|
+
* <Button onClick={() => act('inputVal', {inputVal: value})}>
|
|
41
|
+
* Submit
|
|
42
|
+
* </Button>
|
|
43
|
+
* <Input value={value} onChange={setValue} />
|
|
44
|
+
* <Button onClick={() => setValue('')}>
|
|
45
|
+
* Clear
|
|
46
|
+
* </Button>
|
|
47
|
+
* </>
|
|
48
|
+
* )
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
value: string;
|
|
52
|
+
}> & BaseInputProps;
|
|
53
|
+
type Props = Partial<{
|
|
54
|
+
/**
|
|
55
|
+
* Whether to debounce the input.
|
|
56
|
+
* Do this if it's performing expensive ops on each input.
|
|
57
|
+
* It will only fire once every 250ms.
|
|
58
|
+
*/
|
|
59
|
+
expensive: boolean;
|
|
60
|
+
/** Ref of the input element */
|
|
61
|
+
ref: RefObject<HTMLInputElement | null>;
|
|
48
62
|
/** Auto-updates the input value on props change, ie, data from Byond */
|
|
49
63
|
updateOnPropsChange: boolean;
|
|
50
|
-
|
|
51
|
-
value: string | number;
|
|
52
|
-
}>;
|
|
53
|
-
type Props = OptionalProps & ConditionalProps & Omit<BoxProps, 'children'>;
|
|
54
|
-
type InputValue = string | number | undefined;
|
|
55
|
-
export declare function toInputValue(value: InputValue): string;
|
|
64
|
+
}> & BaseInputProps & TextInputProps;
|
|
56
65
|
/**
|
|
57
|
-
*
|
|
66
|
+
* ## Input
|
|
67
|
+
*
|
|
58
68
|
* A basic text input which allow users to enter text into a UI.
|
|
59
|
-
*
|
|
60
|
-
*
|
|
69
|
+
*
|
|
70
|
+
* @see https://github.com/tgstation/tgui-core/blob/main/lib/components/Input.tsx
|
|
61
71
|
*/
|
|
62
72
|
export declare function Input(props: Props): import("react/jsx-runtime").JSX.Element;
|
|
63
73
|
export {};
|
package/dist/components/Input.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import*as e from"react/jsx-runtime";import*as t from"react";import*as r from"../common/keys.js";import*as
|
|
1
|
+
import*as e from"react/jsx-runtime";import*as t from"react";import*as r from"../common/keys.js";import*as u from"../common/react.js";import*as o from"../common/timer.js";import*as n from"../common/ui.js";let a=(0,o.debounce)(e=>e(),250);function c(o){let{autoFocus:c,autoSelect:s,className:m,disabled:l,expensive:p,fluid:f,maxLength:i,monospace:v,onChange:d,onEnter:g,onEscape:T,placeholder:j,ref:x,selfClear:E,updateOnPropsChange:b,...y}=o,I=(0,t.useRef)(null),h=x??I,[k,C]=(0,t.useState)(o.value),D=(0,t.useMemo)(()=>(0,n.computeBoxProps)(y),[y]),K=(0,t.useMemo)(()=>(0,u.classes)(["Input",l&&"Input--disabled",f&&"Input--fluid",v&&"Input--monospace",m]),[m,f,v]);return(0,t.useEffect)(()=>{let e;return(c||s)&&(e=setTimeout(()=>{h.current?.focus(),s&&h.current?.select()},1)),()=>clearTimeout(e)},[]),(0,t.useEffect)(()=>{b&&h.current&&document.activeElement!==h.current&&o.value!==k&&C(o.value??"")},[o.value]),(0,e.jsx)("input",{...D,autoComplete:"off",className:K,disabled:l,maxLength:i,onChange:function(e){let t=e.currentTarget?.value;p?a(()=>d?.(t)):d?.(t),C(t)},onKeyDown:function(e){if(e.key===r.KEY.Enter){e.preventDefault(),g?.(e.currentTarget.value),E&&C(""),e.currentTarget.blur();return}(0,r.isEscape)(e.key)&&(e.preventDefault(),T?.(e.currentTarget.value),e.currentTarget.blur())},placeholder:j,ref:h,type:"text",value:k,spellCheck:!1})}export{c as Input};
|
|
@@ -1,29 +1,46 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
type Props = {
|
|
3
|
-
|
|
4
|
-
} & Partial<{
|
|
1
|
+
import type { BaseInputProps } from './Input';
|
|
2
|
+
type Props = Partial<{
|
|
3
|
+
/** Restricted inputs round by default. */
|
|
5
4
|
allowFloats: boolean;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
5
|
+
/** Max value. 10,000 by default. */
|
|
6
|
+
maxValue: number;
|
|
7
|
+
/** Min value. 0 by default. */
|
|
8
|
+
minValue: number;
|
|
9
|
+
/** Fires each time the input has been changed */
|
|
10
|
+
onChange: (value: number) => void;
|
|
11
|
+
/** Fires once the enter key is pressed */
|
|
12
|
+
onEnter: (value: number) => void;
|
|
13
|
+
/** Fires once the escape key is pressed */
|
|
14
|
+
onEscape: (value: number) => void;
|
|
15
|
+
/**
|
|
16
|
+
* Generally, input can handle its own state value.
|
|
17
|
+
*
|
|
18
|
+
* Use this if you want to hold the value in the parent for external manipulation.
|
|
19
|
+
*
|
|
20
|
+
* ```tsx
|
|
21
|
+
* const [value, setValue] = useState(1;
|
|
22
|
+
*
|
|
23
|
+
* return (
|
|
24
|
+
* <>
|
|
25
|
+
* <Button onClick={() => act('inputVal', {inputVal: value})}>
|
|
26
|
+
* Submit
|
|
27
|
+
* </Button>
|
|
28
|
+
* <RestrictedInput value={value} onChange={setValue} />
|
|
29
|
+
* <Button onClick={() => setValue(1)}>
|
|
30
|
+
* Clear
|
|
31
|
+
* </Button>
|
|
32
|
+
* </>
|
|
33
|
+
* )
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
value: number;
|
|
37
|
+
}> & BaseInputProps;
|
|
16
38
|
/**
|
|
17
39
|
* ## RestrictedInput
|
|
18
|
-
* Creates an input which rejects improper keys.
|
|
19
|
-
*
|
|
20
|
-
* @deprecated Use `NumberInput` instead.
|
|
21
40
|
*
|
|
22
|
-
*
|
|
23
|
-
* made because it's poor UX. Users should be allowed to type in whatever they
|
|
24
|
-
* want, but have the UI notify them it's invalid after it's entered.
|
|
41
|
+
* Creates a numerical input which rejects improper keys.
|
|
25
42
|
*
|
|
26
|
-
*
|
|
43
|
+
* @see https://github.com/tgstation/tgui-core/blob/main/lib/components/RestrictedInput.tsx
|
|
27
44
|
*/
|
|
28
45
|
export declare function RestrictedInput(props: Props): import("react/jsx-runtime").JSX.Element;
|
|
29
46
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import*as e from"react/jsx-runtime";import*as r from"../common/
|
|
1
|
+
import*as e from"react/jsx-runtime";import*as t from"../common/math.js";import*as r from"../common/react.js";import*as u from"../common/ui.js";import*as n from"react";import*as o from"../common/keys.js";function m(m){let{allowFloats:s,autoFocus:a,autoSelect:c,className:i,disabled:l,fluid:f,maxValue:p=1e4,minValue:v=0,monospace:d,onChange:b,onEnter:E,onEscape:j,...y}=m,I=(0,n.useRef)(null),[k,x]=(0,n.useState)(m.value??v),N=(0,n.useMemo)(()=>(0,u.computeBoxProps)(y),[y]),h=(0,n.useMemo)(()=>(0,r.classes)(["Input","RestrictedInput",l&&"Input--disabled",f&&"Input--fluid",d&&"Input--monospace",i]),[i,f,d]);function D(e){if(e===k)return;let r=e;Number.isNaN(e)?r=v:s||(r=Math.round(e)),x(r=(0,t.clamp)(r,v,p)),b?.(r)}return(0,n.useEffect)(()=>{let e;return(a||c)&&(e=setTimeout(()=>{I.current?.focus(),c&&I.current?.select()},1)),()=>clearTimeout(e)},[]),(0,n.useEffect)(()=>{document.activeElement===I.current&&m.value!==k&&x(m.value??v)},[m.value]),(0,e.jsx)("input",{...N,autoComplete:"off",className:h,disabled:l,max:p,min:v,onChange:function(e){D(Number(e.target.value))},onKeyDown:function(e){if(e.key===o.KEY.Enter){e.preventDefault(),E?.(k),I.current?.blur();return}if((0,o.isEscape)(e.key)){e.preventDefault(),j?.(k),I.current?.blur();return}if(e.key===o.KEY.Minus){e.preventDefault(),D(-1*k);return}},ref:I,spellCheck:!1,type:"number",value:k})}export{m as RestrictedInput};
|
|
@@ -1,46 +1,24 @@
|
|
|
1
|
-
import type { RefObject
|
|
2
|
-
import {
|
|
1
|
+
import type { RefObject } from 'react';
|
|
2
|
+
import type { TextInputProps } from './Input';
|
|
3
3
|
type Props = Partial<{
|
|
4
|
-
/** Automatically focus the textarea on mount */
|
|
5
|
-
autoFocus: boolean;
|
|
6
|
-
/** Selects all text on mount */
|
|
7
|
-
autoSelect: boolean;
|
|
8
|
-
/** The value to display in the textarea */
|
|
9
|
-
displayedValue: string;
|
|
10
4
|
/** Don't use tab for indent */
|
|
11
5
|
dontUseTabForIndent: boolean;
|
|
12
|
-
/** Sets width to 100% */
|
|
13
|
-
fluid: boolean;
|
|
14
|
-
/** Maximum length of the textarea */
|
|
15
|
-
maxLength: number;
|
|
16
|
-
/** Removes the border. */
|
|
17
|
-
noborder: boolean;
|
|
18
|
-
/** Fires when user is 'done typing': Clicked out, blur, enter key (but not shift+enter) */
|
|
19
|
-
onChange: (event: SyntheticEvent<HTMLTextAreaElement>, value: string) => void;
|
|
20
|
-
/** Fires once the enter key is pressed */
|
|
21
|
-
onEnter: (event: SyntheticEvent<HTMLTextAreaElement>, value: string) => void;
|
|
22
|
-
/** Fires once the escape key is pressed */
|
|
23
|
-
onEscape: (event: SyntheticEvent<HTMLTextAreaElement>) => void;
|
|
24
|
-
/** Fires on each key press / value change. Used for searching */
|
|
25
|
-
onInput: (event: SyntheticEvent<HTMLTextAreaElement>, value: string) => void;
|
|
26
|
-
/** Dummy text inside the textarea when it's empty */
|
|
27
|
-
placeholder: string;
|
|
28
6
|
/** Ref to the textarea element. */
|
|
29
7
|
ref: RefObject<HTMLTextAreaElement | null>;
|
|
30
|
-
/**
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Provides a Record with key: markupChar entries which can be used for
|
|
10
|
+
* ctrl + key combinations to surround a selected text with the markup
|
|
11
|
+
* character
|
|
12
|
+
*/
|
|
35
13
|
userMarkup: Record<string, string>;
|
|
36
|
-
|
|
37
|
-
value: string;
|
|
38
|
-
}> & BoxProps;
|
|
14
|
+
}> & TextInputProps;
|
|
39
15
|
/**
|
|
40
16
|
* ## Textarea
|
|
41
17
|
*
|
|
42
18
|
* An input for larger amounts of text. Use this when you want inputs larger
|
|
43
19
|
* than one row.
|
|
20
|
+
*
|
|
21
|
+
* @see https://github.com/tgstation/tgui-core/blob/main/lib/components/TextArea.tsx
|
|
44
22
|
*/
|
|
45
23
|
export declare function TextArea(props: Props): import("react/jsx-runtime").JSX.Element;
|
|
46
24
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import*as e from"react/jsx-runtime";import*as
|
|
1
|
+
import*as e from"react/jsx-runtime";import*as t from"react";import*as r from"../common/keys.js";import*as u from"../common/react.js";import*as n from"../common/ui.js";function a(a){let{autoFocus:s,autoSelect:c,disabled:o,dontUseTabForIndent:l,fluid:m,maxLength:i,monospace:f,onChange:p,onEnter:g,onEscape:T,placeholder:v,ref:y,selfClear:b,userMarkup:E,...x}=a,d=(0,t.useRef)(null),k=y??d,[$,h]=(0,t.useState)(a.value??""),K=(0,t.useMemo)(()=>(0,n.computeBoxProps)(x),[x]),j=(0,t.useMemo)(()=>(0,u.classes)(["Input","TextArea",m&&"Input--fluid",f&&"Input--monospace",o&&"Input--disabled"]),[o,m,f]);return(0,t.useEffect)(()=>{(s||c)&&setTimeout(()=>{k.current?.focus(),c&&k.current?.select()},1)},[]),(0,t.useEffect)(()=>{document.activeElement===k.current&&a.value!==$&&h(a.value??"")},[a.value]),(0,e.jsx)("textarea",{...K,autoComplete:"off",className:j,maxLength:i,onChange:function(e){h(e.currentTarget.value)},onKeyDown:function(e){if(e.key===r.KEY.Enter&&!e.shiftKey){e.preventDefault(),g?.(e.currentTarget.value),b&&h(""),e.currentTarget.blur();return}if((0,r.isEscape)(e.key)){T?.(e.currentTarget.value),e.currentTarget.blur();return}if(!l&&e.key===r.KEY.Tab){e.preventDefault();let{value:t,selectionStart:r,selectionEnd:u}=e.currentTarget;h(`${t.substring(0,r)} ${t.substring(u)}`),e.currentTarget.selectionEnd=r+1,p?.(e.currentTarget.value);return}if(E&&(e.ctrlKey||e.metaKey)&&E[e.key]){e.preventDefault();let{selectionStart:t,selectionEnd:r,value:u}=e.currentTarget,n=E[e.key];h(`${u.substring(0,t)}${n}${u.substring(t,r)}${n}${u.substring(r)}`),e.currentTarget.selectionEnd=r+2*n.length,p?.(e.currentTarget.value);return}},placeholder:v,ref:k,spellCheck:!1,value:$})}export{a as TextArea};
|
package/package.json
CHANGED
|
@@ -4,15 +4,24 @@ $bg-map: colors.$color-map !default;
|
|
|
4
4
|
|
|
5
5
|
@mixin button-style($color) {
|
|
6
6
|
background-color: hsl(
|
|
7
|
-
from $color h s calc(l - var(--adjust-color) * 2) /
|
|
7
|
+
from $color h s calc(l - var(--adjust-color) * 2) /
|
|
8
|
+
var(--imagebutton-transparecy)
|
|
8
9
|
);
|
|
9
|
-
border:
|
|
10
|
+
border: var(--border-thickness-tiny) solid
|
|
11
|
+
hsl(
|
|
12
|
+
from $color h s calc(l + var(--adjust-color)) /
|
|
13
|
+
var(--imagebutton-transparecy)
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
&:not(.ImageButton--disabled, .ImageButton--noAction) {
|
|
17
|
+
.ImageButton__container {
|
|
18
|
+
cursor: var(--cursor-pointer);
|
|
19
|
+
}
|
|
10
20
|
|
|
11
|
-
&:not(.ImageButton--disabled) {
|
|
12
21
|
&:hover {
|
|
13
22
|
background-color: hsl(
|
|
14
23
|
from $color h s calc(l - var(--adjust-color) + var(--adjust-hover)) /
|
|
15
|
-
|
|
24
|
+
var(--imagebutton-transparecy)
|
|
16
25
|
);
|
|
17
26
|
}
|
|
18
27
|
|
|
@@ -27,7 +36,8 @@ $bg-map: colors.$color-map !default;
|
|
|
27
36
|
&:has(.ImageButton__buttons:hover),
|
|
28
37
|
&:has(.ImageButton__buttons:active) {
|
|
29
38
|
background-color: hsl(
|
|
30
|
-
from $color h s calc(l - var(--adjust-color) * 2) /
|
|
39
|
+
from $color h s calc(l - var(--adjust-color) * 2) /
|
|
40
|
+
var(--imagebutton-transparecy)
|
|
31
41
|
);
|
|
32
42
|
box-shadow: none;
|
|
33
43
|
}
|
|
@@ -51,6 +61,27 @@ $bg-map: colors.$color-map !default;
|
|
|
51
61
|
@include button-style(hsl(from var(--color-base) h s 30));
|
|
52
62
|
}
|
|
53
63
|
|
|
64
|
+
.ImageButton__color--primary {
|
|
65
|
+
@include button-style(hsl(from var(--color-primary) h s 30));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.ImageButton__color--transparent {
|
|
69
|
+
@include button-style(hsl(from var(--color-base) h s 30));
|
|
70
|
+
|
|
71
|
+
background-color: transparent;
|
|
72
|
+
border-color: transparent !important;
|
|
73
|
+
|
|
74
|
+
.ImageButton__content {
|
|
75
|
+
background-color: transparent !important;
|
|
76
|
+
color: var(--color-text-translucent);
|
|
77
|
+
border-color: transparent !important;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
&:hover:not(.ImageButton--disabled) .ImageButton__content {
|
|
81
|
+
color: var(--color-text);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
54
85
|
.ImageButton--selected {
|
|
55
86
|
@include button-style(var(--button-background-selected));
|
|
56
87
|
}
|
|
@@ -83,7 +114,6 @@ $bg-map: colors.$color-map !default;
|
|
|
83
114
|
border-width: 0;
|
|
84
115
|
|
|
85
116
|
&__container {
|
|
86
|
-
cursor: var(--cursor-pointer);
|
|
87
117
|
display: flex;
|
|
88
118
|
flex-direction: column;
|
|
89
119
|
transition: opacity var(--transition-time-medium);
|
|
@@ -97,8 +127,8 @@ $bg-map: colors.$color-map !default;
|
|
|
97
127
|
overflow: hidden;
|
|
98
128
|
line-height: 0;
|
|
99
129
|
padding: var(--space-s);
|
|
100
|
-
border:
|
|
101
|
-
border-bottom:
|
|
130
|
+
border: var(--border-thickness-tiny) solid;
|
|
131
|
+
border-bottom: none;
|
|
102
132
|
border-color: inherit;
|
|
103
133
|
border-radius: var(--border-radius-medium) var(--border-radius-medium) 0 0;
|
|
104
134
|
}
|
|
@@ -116,7 +146,7 @@ $bg-map: colors.$color-map !default;
|
|
|
116
146
|
display: flex;
|
|
117
147
|
position: absolute;
|
|
118
148
|
overflow: hidden;
|
|
119
|
-
left:
|
|
149
|
+
left: var(--border-thickness-tiny);
|
|
120
150
|
bottom: 1.8em;
|
|
121
151
|
max-width: 100%;
|
|
122
152
|
z-index: 1;
|
|
@@ -125,8 +155,8 @@ $bg-map: colors.$color-map !default;
|
|
|
125
155
|
overflow: visible;
|
|
126
156
|
flex-direction: column;
|
|
127
157
|
pointer-events: none;
|
|
128
|
-
top:
|
|
129
|
-
bottom:
|
|
158
|
+
top: var(--border-thickness-tiny);
|
|
159
|
+
bottom: unset !important;
|
|
130
160
|
/** Text outline. Sort of. */
|
|
131
161
|
text-shadow:
|
|
132
162
|
0px 1px 2px var(--color-base),
|
|
@@ -135,6 +165,11 @@ $bg-map: colors.$color-map !default;
|
|
|
135
165
|
0px -1px 2px var(--color-base);
|
|
136
166
|
}
|
|
137
167
|
|
|
168
|
+
&--empty {
|
|
169
|
+
bottom: 0;
|
|
170
|
+
left: 0;
|
|
171
|
+
}
|
|
172
|
+
|
|
138
173
|
& > * {
|
|
139
174
|
/* I know !important is bad, but here's no other way */
|
|
140
175
|
margin: 0 !important;
|
|
@@ -142,6 +177,20 @@ $bg-map: colors.$color-map !default;
|
|
|
142
177
|
border-radius: 0 !important;
|
|
143
178
|
}
|
|
144
179
|
}
|
|
180
|
+
|
|
181
|
+
&--empty {
|
|
182
|
+
border-width: var(--border-thickness-tiny);
|
|
183
|
+
|
|
184
|
+
.ImageButton__image {
|
|
185
|
+
border: none;
|
|
186
|
+
border-radius: var(--border-radius-medium);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.Stack > &,
|
|
191
|
+
.Stack__item > & {
|
|
192
|
+
margin: 0;
|
|
193
|
+
}
|
|
145
194
|
}
|
|
146
195
|
|
|
147
196
|
.ImageButton--fluid {
|
|
@@ -1,63 +1,45 @@
|
|
|
1
|
-
@use "../base";
|
|
2
|
-
|
|
3
|
-
$text-color: 0 !default;
|
|
4
|
-
$background-color: 0 !default;
|
|
5
|
-
$border-color: 0 !default;
|
|
6
|
-
$border-radius: 0 !default;
|
|
7
|
-
$font-family: 0 !default;
|
|
8
|
-
$mono-font-family: 0 !default;
|
|
9
|
-
|
|
10
1
|
.Input {
|
|
11
|
-
overflow: visible;
|
|
12
|
-
position: relative;
|
|
13
|
-
display: inline-block;
|
|
14
|
-
width: base.em(120px);
|
|
15
|
-
line-height: base.em(17px);
|
|
16
|
-
padding: 0 var(--space-sm);
|
|
17
|
-
margin-right: var(--space-xs);
|
|
18
2
|
background-color: var(--input-background);
|
|
19
|
-
color: var(--input-color);
|
|
20
|
-
border: var(--border-thickness-tiny) solid var(--input-border-color);
|
|
21
3
|
border-radius: var(--input-border-radius);
|
|
22
|
-
|
|
4
|
+
border: var(--border-thickness-tiny) solid var(--input-border-color);
|
|
5
|
+
color: var(--input-color);
|
|
6
|
+
font-family: var(--input-font-family);
|
|
7
|
+
padding: var(--space-xxs) var(--space-sm);
|
|
8
|
+
width: var(--input-width);
|
|
9
|
+
&:focus {
|
|
10
|
+
outline: none;
|
|
11
|
+
}
|
|
23
12
|
&:focus-within {
|
|
24
13
|
border-color: var(--input-border-color-focus);
|
|
25
14
|
}
|
|
15
|
+
&::placeholder {
|
|
16
|
+
font-style: italic;
|
|
17
|
+
color: var(--input-color-placeholder);
|
|
18
|
+
}
|
|
26
19
|
}
|
|
27
20
|
|
|
28
|
-
.Input--
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
.Input__baseline {
|
|
34
|
-
display: inline-block;
|
|
35
|
-
color: transparent;
|
|
21
|
+
.Input--disabled {
|
|
22
|
+
border-color: var(--input-border-disabled);
|
|
23
|
+
color: var(--input-color-placeholder);
|
|
36
24
|
}
|
|
37
25
|
|
|
38
|
-
.
|
|
39
|
-
display: block;
|
|
40
|
-
position: absolute;
|
|
41
|
-
inset: 0;
|
|
42
|
-
border: 0;
|
|
43
|
-
outline: 0;
|
|
26
|
+
.Input--fluid {
|
|
44
27
|
width: 100%;
|
|
45
|
-
font-size: base.em(12px);
|
|
46
|
-
line-height: base.em(17px);
|
|
47
|
-
height: base.em(17px);
|
|
48
|
-
margin: 0;
|
|
49
|
-
padding: 0 var(--space-m);
|
|
50
|
-
font-family: var(--input-font-family);
|
|
51
|
-
background-color: transparent;
|
|
52
|
-
color: var(--input-color);
|
|
53
|
-
color: inherit;
|
|
54
|
-
|
|
55
|
-
&::placeholder {
|
|
56
|
-
font-style: italic;
|
|
57
|
-
color: var(--input-color-placeholder);
|
|
58
|
-
}
|
|
59
28
|
}
|
|
60
29
|
|
|
61
|
-
.Input--monospace
|
|
30
|
+
.Input--monospace {
|
|
62
31
|
font-family: var(--input-font-family-mono);
|
|
63
32
|
}
|
|
33
|
+
|
|
34
|
+
.RestrictedInput {
|
|
35
|
+
border-color: var(--restricted-input-border-color);
|
|
36
|
+
text-align: right;
|
|
37
|
+
&:focus-within {
|
|
38
|
+
border-color: var(--restricted-input-border-color-focus);
|
|
39
|
+
}
|
|
40
|
+
&::-webkit-inner-spin-button,
|
|
41
|
+
&::-webkit-outer-spin-button {
|
|
42
|
+
-webkit-appearance: none;
|
|
43
|
+
margin: 0;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -1,82 +1,3 @@
|
|
|
1
|
-
@use "../base";
|
|
2
|
-
@use "./Input";
|
|
3
|
-
|
|
4
|
-
$text-color: 0 !default;
|
|
5
|
-
$background-color: 0 !default;
|
|
6
|
-
$border-color: 0 !default;
|
|
7
|
-
$border-radius: 0 !default;
|
|
8
|
-
|
|
9
1
|
.TextArea {
|
|
10
|
-
background-color: var(--input-background);
|
|
11
|
-
border-radius: var(--input-border-radius);
|
|
12
|
-
border: var(--border-thickness-tiny) solid var(--input-border-color);
|
|
13
|
-
box-sizing: border-box;
|
|
14
|
-
display: inline-block;
|
|
15
|
-
line-height: base.em(17px);
|
|
16
|
-
margin-right: base.em(2px);
|
|
17
|
-
position: relative;
|
|
18
|
-
width: 100%;
|
|
19
|
-
&:focus-within {
|
|
20
|
-
border-color: var(--input-border-color-focus);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
.TextArea--fluid {
|
|
25
|
-
display: block;
|
|
26
|
-
height: auto;
|
|
27
|
-
width: auto;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
.TextArea--noborder {
|
|
31
|
-
border: 0px;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
.TextArea__textarea.TextArea__textarea--scrollable {
|
|
35
|
-
overflow: hidden auto;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
.TextArea__textarea {
|
|
39
|
-
background-color: transparent;
|
|
40
|
-
border: 0;
|
|
41
|
-
box-sizing: border-box;
|
|
42
|
-
color: var(--input-color);
|
|
43
|
-
display: block;
|
|
44
|
-
font-family: inherit;
|
|
45
|
-
font-size: 1em;
|
|
46
|
-
height: 100%;
|
|
47
|
-
inset: 0;
|
|
48
|
-
line-height: base.em(17px);
|
|
49
|
-
margin: 0;
|
|
50
|
-
min-height: base.em(17px);
|
|
51
|
-
outline: 0;
|
|
52
|
-
overflow: hidden;
|
|
53
|
-
padding: 0 var(--space-m);
|
|
54
|
-
position: absolute;
|
|
55
2
|
resize: none;
|
|
56
|
-
width: 100%;
|
|
57
|
-
// Make sure the div and the textarea wrap words in the same way
|
|
58
|
-
word-wrap: break-word;
|
|
59
|
-
|
|
60
|
-
&::placeholder {
|
|
61
|
-
font-style: italic;
|
|
62
|
-
color: var(--input-color-placeholder);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
.TextArea__textarea_custom {
|
|
67
|
-
overflow: visible;
|
|
68
|
-
white-space: pre-wrap;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
.TextArea__nowrap {
|
|
72
|
-
overflow-wrap: normal;
|
|
73
|
-
overflow-x: scroll;
|
|
74
|
-
white-space: nowrap;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
.TextArea__value-container {
|
|
78
|
-
height: 100%;
|
|
79
|
-
overflow: hidden;
|
|
80
|
-
position: absolute;
|
|
81
|
-
width: 100%;
|
|
82
3
|
}
|
|
@@ -80,6 +80,9 @@
|
|
|
80
80
|
--tab-transition: var(--transition-time-medium);
|
|
81
81
|
--tabs-container-background: var(--color-section);
|
|
82
82
|
|
|
83
|
+
/* ImageButton */
|
|
84
|
+
--imagebutton-transparecy: 0.25;
|
|
85
|
+
|
|
83
86
|
/* Input */
|
|
84
87
|
--input-background-lightness: 5;
|
|
85
88
|
--input-background: hsl(
|
|
@@ -90,9 +93,11 @@
|
|
|
90
93
|
--input-border-color: var(--color-border-primary);
|
|
91
94
|
--input-border-color-focus: var(--color-border-secondary);
|
|
92
95
|
--input-border-radius: var(--border-radius-tiny);
|
|
96
|
+
--input-border-disabled: var(--color-gray);
|
|
93
97
|
--input-transition: var(--transition-time-medium);
|
|
94
98
|
--input-font-family: var(--font-family);
|
|
95
99
|
--input-font-family-mono: var(--font-family-mono);
|
|
100
|
+
--input-width: 9em;
|
|
96
101
|
|
|
97
102
|
/* Knob */
|
|
98
103
|
--knob-color: hsl(from var(--color-base) h 5 20);
|
|
@@ -131,6 +136,12 @@
|
|
|
131
136
|
--progress-bar-border-radius: var(--border-radius-tiny);
|
|
132
137
|
--progress-bar-transition: var(--transition-time-slowest);
|
|
133
138
|
|
|
139
|
+
/* Restricted Input */
|
|
140
|
+
--restricted-input-border-color: var(--color-green);
|
|
141
|
+
--restricted-input-border-color-focus: hsl(
|
|
142
|
+
from var(--color-green) h s calc(l + 10)
|
|
143
|
+
);
|
|
144
|
+
|
|
134
145
|
/* Round Gauge */
|
|
135
146
|
--round-gauge-ring-color: var(--input-border-color);
|
|
136
147
|
--round-gauge-transition: var(--transition-time-medium);
|