tgui-core 5.7.2 → 5.9.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.
@@ -16,3 +16,8 @@ export declare function throttle<F extends (...args: any[]) => any>(fn: F, time:
16
16
  * @param {number} time
17
17
  */
18
18
  export declare function sleep(time: number): Promise<void>;
19
+ /**
20
+ * Prevent input parent change event from being called too often
21
+ * @param dTime Debounce time, default is 250
22
+ */
23
+ export declare function inputDebounce(dTime?: number): (onChange: () => void) => void;
@@ -1 +1 @@
1
- function e(t,n,o=!1){let u;return(...e)=>{let i=o&&!u;clearTimeout(u),u=setTimeout(function(){u=null,o||t(...e)},n),i&&t(...e)}}function t(e,t){let n,o;return function u(...i){let r=Date.now();o&&clearTimeout(o),!n||r-n>=t?(e(...i),n=r):o=setTimeout(()=>u(...i),t-(r-(n??0)))}}function n(e){return new Promise(t=>setTimeout(t,e))}export{e as debounce,n as sleep,t as throttle};
1
+ function e(t,n,u=!1){let o;return(...e)=>{let i=u&&!o;clearTimeout(o),o=setTimeout(function(){o=null,u||t(...e)},n),i&&t(...e)}}function t(e,t){let n,u;return function o(...i){let r=Date.now();u&&clearTimeout(u),!n||r-n>=t?(e(...i),n=r):u=setTimeout(()=>o(...i),t-(r-(n??0)))}}function n(e){return new Promise(t=>setTimeout(t,e))}function u(t=250){return e(e=>e(),t)}export{e as debounce,u as inputDebounce,n as sleep,t as throttle};
@@ -1,6 +1,6 @@
1
1
  import type { DOMAttributes } from 'react';
2
2
  import type { BoxProps } from '../components/Box';
3
- import { type BooleanLike } from './react';
3
+ import { type BooleanLike } from './react.ts';
4
4
  type UnitMapper = (value: unknown) => string | undefined;
5
5
  /**
6
6
  * Coverts our rem-like spacing unit into a CSS unit.
@@ -1 +1 @@
1
- import{jsx as r}from"react/jsx-runtime";import{clamp as t,isSafeNumber as n,toFixed as e}from"../common/math.js";import{useEffect as l,useRef as u,useState as c}from"react";let i=1e3/60;function m(m){let o,{format:a,initial:f,value:p}=m,s=u(null),[h,d]=c(void 0!==f&&n(f)?f:n(p)?p:0);l(()=>(h!==p&&null===s.current&&(s.current=setInterval(v,i)),()=>g()),[p]),l(()=>()=>g(),[]);function g(){null!==s.current&&(clearInterval(s.current),s.current=null)}function v(){n(p)?d(r=>{let t=.8333*r+.16669999999999996*p;return Math.abs(p-t)<Math.max(.001,.001*p)?(g(),p):t}):g()}return r("span",{children:n(p)?a?a(h):e(h,t((o=String(p).split(".")[1])?o.length:0,0,8)):String(p)})}export{m as AnimatedNumber};
1
+ import{jsx as r}from"react/jsx-runtime";import{clamp as n,isSafeNumber as t,toFixed as e}from"../common/math.js";import{useEffect as u,useMemo as l,useRef as c,useState as i}from"react";let m=1e3/60;function o(o){let{format:a,initial:f,value:p}=o,s=c(null),h=c(null),[d,g]=i(void 0!==f&&t(f)?f:t(p)?p:0),x=l(()=>{if(!t(p))return 0;let r=String(p).split(".")[1];return n(r?r.length:0,0,8)},[p]);function A(){null===s.current&&(h.current=null,s.current=requestAnimationFrame(j))}function b(){null!==s.current&&(cancelAnimationFrame(s.current),s.current=null,h.current=null)}function j(r){if(s.current=null,!t(p))return void b();let n=null===h.current?m:r-h.current;h.current=r;let e=.8333**(n/m),u=!0;g(r=>{let n=r*e+p*(1-e);return Math.abs(p-n)<Math.max(.001,.001*p)?(u=!1,p):n}),u&&A()}return u(()=>(d!==p&&A(),()=>b()),[p]),r("span",{children:t(p)?a?a(d):e(d,x):String(p)})}export{o as AnimatedNumber};
@@ -1,6 +1,7 @@
1
1
  import { type RefObject } from 'react';
2
2
  import type { BoxProps } from './Box';
3
- export type BaseInputProps<TElement = HTMLInputElement> = Partial<{
3
+ /** Takes two optional params: The dom element type & the input type */
4
+ export type BaseInputProps<TElement = HTMLInputElement, TInput = string> = Partial<{
4
5
  /** Automatically focuses the input on mount */
5
6
  autoFocus: boolean;
6
7
  /** Automatically selects the input value on focus */
@@ -15,31 +16,32 @@ export type BaseInputProps<TElement = HTMLInputElement> = Partial<{
15
16
  * Do this if it's performing expensive ops on each input, like filtering or
16
17
  * sending the value immediate to Byond (via act).
17
18
  *
18
- * It will only fire once every 250ms.
19
+ * It will only fire once every 250ms by default. Pass in a number in ms
20
+ * for a custom fire rate
19
21
  */
20
- expensive: boolean;
22
+ expensive: boolean | number;
21
23
  /** Fills the parent container */
22
24
  fluid: boolean;
23
25
  /** Mark this if you want to use a monospace font */
24
26
  monospace: boolean;
25
- /** Allows to toggle on spellcheck on inputs */
26
- spellcheck: boolean;
27
- }> & BoxProps<TElement>;
28
- export type TextInputProps<TElement = HTMLInputElement> = Partial<{
29
- /** The maximum length of the input value */
30
- maxLength: number;
31
27
  /** Fires each time focus leaves the input, including if Esc or Enter are pressed */
32
- onBlur: (value: string) => void;
33
- /** Fires each time the input has been changed */
34
- onChange: (value: string) => void;
28
+ onBlur: (value: TInput) => void;
29
+ /**
30
+ * Fires each time the input has been changed. You do not need to enter the second param unless you're using it. All of these are valid:
31
+ *
32
+ * @example
33
+ * ```tsx
34
+ * <Input onChange={(value) => console.log(value)} />
35
+ * <Input onChange={(value, event) => console.log(value, event)} />
36
+ * <Input onChange={console.log} /> // This will log the value and the event
37
+ * <Input onChange={setValue} /> // This will just change the value state
38
+ * ```
39
+ */
40
+ onChange: (value: TInput, event?: React.ChangeEvent<TElement>) => void;
35
41
  /** Fires once the enter key is pressed */
36
- onEnter: (value: string) => void;
42
+ onEnter: (value: TInput, event?: React.KeyboardEvent<TElement>) => void;
37
43
  /** Fires once the escape key is pressed */
38
- onEscape: (value: string) => void;
39
- /** The placeholder text when everything is cleared */
40
- placeholder: string;
41
- /** Clears the input value on enter */
42
- selfClear: boolean;
44
+ onEscape: (value: TInput, event?: React.KeyboardEvent<TElement>) => void;
43
45
  /**
44
46
  * Generally, input can handle its own state value. You might not NEED this.
45
47
  *
@@ -80,12 +82,20 @@ export type TextInputProps<TElement = HTMLInputElement> = Partial<{
80
82
  * )
81
83
  * ```
82
84
  */
83
- value: string;
84
- }> & BaseInputProps<TElement>;
85
- type Props = Partial<{
85
+ value: TInput;
86
+ }> & BoxProps<TElement>;
87
+ export type TextInputProps<TElement = HTMLInputElement> = Partial<{
88
+ /** The maximum length of the input value */
89
+ maxLength: number;
90
+ /** The placeholder text when everything is cleared */
91
+ placeholder: string;
86
92
  /** Ref of the input element */
87
- ref: RefObject<HTMLInputElement | null>;
88
- }> & BaseInputProps & TextInputProps;
93
+ ref: RefObject<TElement | null>;
94
+ /** Clears the input value on enter */
95
+ selfClear: boolean;
96
+ /** Allows to toggle on spellcheck on inputs */
97
+ spellcheck: boolean;
98
+ }> & BaseInputProps<TElement>;
89
99
  /**
90
100
  * ## Input
91
101
  *
@@ -94,5 +104,4 @@ type Props = Partial<{
94
104
  * - [View documentation on tgui core](https://tgstation.github.io/tgui-core/?path=/docs/components-input--docs)
95
105
  * - [View inherited Box props](https://tgstation.github.io/tgui-core/?path=/docs/components-box--docs)
96
106
  */
97
- export declare function Input(props: Props): import("react/jsx-runtime").JSX.Element;
98
- export {};
107
+ export declare function Input(props: TextInputProps): import("react/jsx-runtime").JSX.Element;
@@ -1 +1 @@
1
- import{jsx as e}from"react/jsx-runtime";import{KEY as t,isEscape as r}from"../common/keys.js";import{classes as n}from"../common/react.js";import{debounce as u}from"../common/timer.js";import{computeBoxClassName as o,computeBoxProps as m}from"../common/ui.js";import{useEffect as c,useRef as l,useState as a}from"react";let i=u(e=>e(),250);function p(u){let{autoFocus:p,autoSelect:f,className:s,disabled:d,expensive:g,fluid:v,maxLength:T,monospace:j,onBlur:y,onChange:I,onEnter:b,onEscape:h,onKeyDown:k,placeholder:x,ref:C,selfClear:D,spellcheck:E=!1,value:w,...B}=u,K=l(null),L=C??K,[N,q]=a(w??"");c(()=>{let e;return(p||f)&&(e=setTimeout(()=>{L.current?.focus(),f&&L.current?.select()},1)),()=>clearTimeout(e)},[]),c(()=>{L.current&&document.activeElement!==L.current&&w!==N&&q(w??"")},[w]);let z=m(B),A=n(["Input",d&&"Input--disabled",v&&"Input--fluid",j&&"Input--monospace",o(B),s]);return e("input",{...z,autoComplete:"off",className:A,disabled:d,maxLength:T,onBlur:()=>y?.(N),onChange:function(e){let t=e.currentTarget.value;q(t),g?i(()=>I?.(t)):I?.(t)},onKeyDown:function(e){if(k?.(e),e.key===t.Enter){e.preventDefault(),b?.(e.currentTarget.value),D&&q(""),e.currentTarget.blur();return}r(e.key)&&(e.preventDefault(),h?.(e.currentTarget.value),e.currentTarget.blur())},placeholder:x,ref:L,spellCheck:E,type:"text",value:N})}export{p as Input};
1
+ import{jsx as e}from"react/jsx-runtime";import{KEY as t,isEscape as r}from"../common/keys.js";import{classes as n}from"../common/react.js";import{inputDebounce as u}from"../common/timer.js";import{computeBoxClassName as o,computeBoxProps as m}from"../common/ui.js";import{useEffect as c,useRef as l,useState as a}from"react";function p(p){let{autoFocus:i,autoSelect:f,className:s,disabled:d,expensive:g,fluid:v,maxLength:T,monospace:y,onBlur:b,onChange:j,onEnter:I,onEscape:h,onKeyDown:k,placeholder:x,ref:C,selfClear:D,spellcheck:E=!1,value:w,...B}=p,K=l(null),L=C??K,[N,q]=a(w??"");c(()=>{let e;return(i||f)&&(e=setTimeout(()=>{L.current?.focus(),f&&L.current?.select()},1)),()=>clearTimeout(e)},[]),c(()=>{L.current&&document.activeElement!==L.current&&w!==N&&q(w??"")},[w]);let z=m(B),A=n(["Input",d&&"Input--disabled",v&&"Input--fluid",y&&"Input--monospace",o(B),s]);return e("input",{...z,autoComplete:"off",className:A,disabled:d,maxLength:T,onBlur:()=>b?.(N),onChange:function(e){let t=e.currentTarget.value;q(t),g?u("number"==typeof g?g:250)(()=>j?.(t,e)):j?.(t,e)},onKeyDown:function(e){if(k?.(e),e.key===t.Enter){e.preventDefault(),I?.(e.currentTarget.value,e),D&&q(""),e.currentTarget.blur();return}r(e.key)&&(e.preventDefault(),h?.(e.currentTarget.value,e),e.currentTarget.blur())},placeholder:x,ref:L,spellCheck:E,type:"text",value:N})}export{p as Input};
@@ -6,58 +6,9 @@ type Props = Partial<{
6
6
  maxValue: number;
7
7
  /** Min value. 0 by default. */
8
8
  minValue: number;
9
- /** Fires each time focus leaves the input, including if Esc or Enter are pressed */
10
- onBlur: (value: number) => void;
11
- /** Fires each time the input has been changed */
12
- onChange: (value: number) => void;
13
- /** Fires once the enter key is pressed */
14
- onEnter: (value: number) => void;
15
- /** Fires once the escape key is pressed */
16
- onEscape: (value: number) => void;
17
9
  /** Fires on input validation change */
18
10
  onValidationChange: (isValid: boolean) => void;
19
- /**
20
- * Generally, input can handle its own state value. You might not NEED this.
21
- *
22
- * Use this if you want to hold the value in the parent for external
23
- * manipulation. For instance:
24
- *
25
- * Clearing the input
26
- *
27
- * ```tsx
28
- * const [value, setValue] = useState(1);
29
- *
30
- * return (
31
- * <>
32
- * <Button onClick={() => act('inputVal', {inputVal: value})}>
33
- * Submit
34
- * </Button>
35
- * <RestrictedInput
36
- * value={value}
37
- * onChange={setValue} />
38
- * <Button onClick={() => setValue(1)}>
39
- * Clear
40
- * </Button>
41
- * </>
42
- * )
43
- * ```
44
- *
45
- * Updating the value from the backend
46
- *
47
- * ```tsx
48
- * const { data } = useBackend<Data>();
49
- * const { valveSetting } = data;
50
- *
51
- * return (
52
- * <RestrictedInput
53
- * value={valveSetting}
54
- * onEnter={(value) => act('submit', { valveSetting: value })}
55
- * />
56
- * )
57
- * ```
58
- */
59
- value: number;
60
- }> & BaseInputProps;
11
+ }> & BaseInputProps<HTMLInputElement, number>;
61
12
  /**
62
13
  * ## RestrictedInput
63
14
  *
@@ -1 +1 @@
1
- import{jsx as e}from"react/jsx-runtime";import{KEY as t,isEscape as r}from"../common/keys.js";import{classes as n}from"../common/react.js";import{debounce as u}from"../common/timer.js";import{computeBoxClassName as o,computeBoxProps as i}from"../common/ui.js";import{useEffect as m,useRef as c,useState as l}from"react";let a=u(e=>e(),250);function f(u){let{allowFloats:f,autoFocus:p,autoSelect:s,className:d,disabled:v,expensive:y,fluid:I,maxValue:b=1e4,minValue:j=0,monospace:k,onBlur:D,onChange:x,onEnter:C,onEscape:R,onKeyDown:g,onValidationChange:h,value:E,...N}=u,T=c(null),[w,B]=l(E??j),[K,M]=l(!0);function q(e){x&&(y?a(()=>x(e)):x(e))}m(()=>{let e;return(p||s)&&(e=setTimeout(()=>{T.current?.focus(),s&&T.current?.select()},1)),()=>clearTimeout(e)},[]),m(()=>{if(T.current){let e=T.current.validity.valid;K!==e&&(M(e),h?.(e))}},[w]),m(()=>{T.current&&document.activeElement!==T.current&&E!==w&&B(E??j)},[E]);let z=i(N),A=n(["Input","RestrictedInput",v&&"Input--disabled",I&&"Input--fluid",k&&"Input--monospace",o(N),d,!K&&"RestrictedInput--invalid"]);return e("input",{...z,autoComplete:"off",className:A,disabled:v,max:b,min:j,onBlur:function(e){D?.(w)},onChange:function(e){let t=Number(e.target.value);B(t),q(t)},onKeyDown:function(e){if(g?.(e),e.key===t.Enter){e.preventDefault(),C?.(w),T.current?.blur();return}if(r(e.key)){e.preventDefault(),R?.(w),T.current?.blur();return}if(e.key===t.Minus){e.preventDefault();let t=-1*w;B(t),q(t);return}},ref:T,spellCheck:!1,step:f?"any":"1",type:"number",value:w})}export{f as RestrictedInput};
1
+ import{jsx as e}from"react/jsx-runtime";import{KEY as t,isEscape as r}from"../common/keys.js";import{classes as n}from"../common/react.js";import{inputDebounce as u}from"../common/timer.js";import{computeBoxClassName as o,computeBoxProps as i}from"../common/ui.js";import{useEffect as m,useRef as c,useState as l}from"react";function f(f){let{allowFloats:p,autoFocus:a,autoSelect:s,className:d,disabled:v,expensive:y,fluid:b,maxValue:I=1e4,minValue:j=0,monospace:k,onBlur:D,onChange:x,onEnter:C,onEscape:R,onKeyDown:g,onValidationChange:h,value:E,...N}=f,T=c(null),[w,B]=l(E??j),[K,M]=l(!0);function q(e,t){x&&(y?u("number"==typeof y?y:250)(()=>x?.(e,t)):x(e,t))}m(()=>{let e;return(a||s)&&(e=setTimeout(()=>{T.current?.focus(),s&&T.current?.select()},1)),()=>clearTimeout(e)},[]),m(()=>{if(T.current){let e=T.current.validity.valid;K!==e&&(M(e),h?.(e))}},[w]),m(()=>{T.current&&document.activeElement!==T.current&&E!==w&&B(E??j)},[E]);let z=i(N),A=n(["Input","RestrictedInput",v&&"Input--disabled",b&&"Input--fluid",k&&"Input--monospace",o(N),d,!K&&"RestrictedInput--invalid"]);return e("input",{...z,autoComplete:"off",className:A,disabled:v,max:I,min:j,onBlur:function(e){D?.(w)},onChange:function(e){let t=Number(e.target.value);B(t),q(t,e)},onKeyDown:function(e){if(g?.(e),e.key===t.Enter){e.preventDefault(),C?.(w,e),T.current?.blur();return}if(r(e.key)){e.preventDefault(),R?.(w,e),T.current?.blur();return}if(e.key===t.Minus){e.preventDefault();let t=-1*w;B(t),q(t,e);return}},ref:T,spellCheck:!1,step:p?"any":"1",type:"number",value:w})}export{f as RestrictedInput};
@@ -1,10 +1,7 @@
1
- import type { RefObject } from 'react';
2
1
  import type { TextInputProps } from './Input';
3
2
  type Props = Partial<{
4
3
  /** Don't use tab for indent */
5
4
  dontUseTabForIndent: boolean;
6
- /** Ref to the textarea element. */
7
- ref: RefObject<HTMLTextAreaElement | null>;
8
5
  /**
9
6
  * Provides a Record with key: markupChar entries which can be used for
10
7
  * ctrl + key combinations to surround a selected text with the markup
@@ -1 +1 @@
1
- import{jsx as e}from"react/jsx-runtime";import{KEY as t,isEscape as r}from"../common/keys.js";import{classes as n}from"../common/react.js";import{computeBoxClassName as u,computeBoxProps as o}from"../common/ui.js";import{debounce as a}from"../common/timer.js";import{useEffect as c,useRef as l,useState as m}from"react";let i=a(e=>e(),250);function s(a){let{autoFocus:s,autoSelect:f,className:g,disabled:p,dontUseTabForIndent:T,expensive:v,fluid:y,maxLength:b,monospace:d,onBlur:k,onChange:$,onEnter:h,onEscape:x,onKeyDown:j,placeholder:D,ref:E,selfClear:I,spellcheck:K=!1,userMarkup:C,value:A,...w}=a,B=l(null),L=E??B,[N,q]=m(A??"");c(()=>{(s||f)&&setTimeout(()=>{L.current?.focus(),f&&L.current?.select()},1)},[]),c(()=>{L.current&&document.activeElement!==L.current&&A!==N&&q(A??"")},[A]);let z=o(w),F=n(["Input","TextArea",y&&"Input--fluid",d&&"Input--monospace",p&&"Input--disabled",u(w),g]);return e("textarea",{...z,autoComplete:"off",className:F,maxLength:b,onBlur:function(e){k?.(N)},onChange:function(e){let t=e.currentTarget.value;q(t),$&&(v?i(()=>$(t)):$(t))},onKeyDown:function(e){if(j?.(e),e.key===t.Enter&&!e.shiftKey){e.preventDefault(),h?.(e.currentTarget.value),I&&q(""),e.currentTarget.blur();return}if(r(e.key)){x?.(e.currentTarget.value),e.currentTarget.blur();return}if(!T&&e.key===t.Tab){e.preventDefault();let{value:t,selectionStart:r,selectionEnd:n}=e.currentTarget;q(`${t.substring(0,r)} ${t.substring(n)}`),e.currentTarget.selectionEnd=r+1,$?.(e.currentTarget.value);return}if(C&&(e.ctrlKey||e.metaKey)&&C[e.key]){e.preventDefault();let{selectionStart:t,selectionEnd:r,value:n}=e.currentTarget,u=C[e.key];q(`${n.substring(0,t)}${u}${n.substring(t,r)}${u}${n.substring(r)}`),e.currentTarget.selectionEnd=r+2*u.length,$?.(e.currentTarget.value);return}},placeholder:D,ref:L,spellCheck:K,value:N})}export{s as TextArea};
1
+ import{jsx as e}from"react/jsx-runtime";import{KEY as r,isEscape as t}from"../common/keys.js";import{classes as n}from"../common/react.js";import{computeBoxClassName as u,computeBoxProps as o}from"../common/ui.js";import{inputDebounce as a}from"../common/timer.js";import{useEffect as c,useRef as l,useState as m}from"react";function i(i){let{autoFocus:s,autoSelect:f,className:g,disabled:p,dontUseTabForIndent:T,expensive:y,fluid:b,maxLength:v,monospace:d,onBlur:k,onChange:$,onEnter:h,onEscape:x,onKeyDown:j,placeholder:D,ref:E,selfClear:I,spellcheck:K=!1,userMarkup:C,value:A,...w}=i,B=l(null),L=E??B,[N,q]=m(A??"");c(()=>{(s||f)&&setTimeout(()=>{L.current?.focus(),f&&L.current?.select()},1)},[]),c(()=>{L.current&&document.activeElement!==L.current&&A!==N&&q(A??"")},[A]);let z=o(w),F=n(["Input","TextArea",b&&"Input--fluid",d&&"Input--monospace",p&&"Input--disabled",u(w),g]);return e("textarea",{...z,autoComplete:"off",className:F,maxLength:v,onBlur:function(e){k?.(N)},onChange:function(e){let r=e.currentTarget.value;q(r),$&&(y?a("number"==typeof y?y:250)(()=>$?.(r,e)):$(r,e))},onKeyDown:function(e){if(j?.(e),e.key===r.Enter&&!e.shiftKey){e.preventDefault(),h?.(e.currentTarget.value,e),I&&q(""),e.currentTarget.blur();return}if(t(e.key)){x?.(e.currentTarget.value,e),e.currentTarget.blur();return}if(!T&&e.key===r.Tab){e.preventDefault();let{value:r,selectionStart:t,selectionEnd:n}=e.currentTarget;q(`${r.substring(0,t)} ${r.substring(n)}`),e.currentTarget.selectionEnd=t+1,$?.(e.currentTarget.value,e);return}if(C&&(e.ctrlKey||e.metaKey)&&C[e.key]){e.preventDefault();let{selectionStart:r,selectionEnd:t,value:n}=e.currentTarget,u=C[e.key];q(`${n.substring(0,r)}${u}${n.substring(r,t)}${u}${n.substring(t)}`),e.currentTarget.selectionEnd=t+2*u.length,$?.(e.currentTarget.value,e);return}},placeholder:D,ref:L,spellCheck:K,value:N})}export{i as TextArea};
package/package.json CHANGED
@@ -71,5 +71,5 @@
71
71
  "test": "bun test"
72
72
  },
73
73
  "type": "module",
74
- "version": "5.7.2"
74
+ "version": "5.9.0"
75
75
  }