tgui-core 3.2.0 → 4.0.1

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.
Files changed (37) hide show
  1. package/README.md +9 -6
  2. package/dist/common/collections.d.ts +0 -7
  3. package/dist/common/collections.js +1 -1
  4. package/dist/common/constants.d.ts +2 -2
  5. package/dist/common/constants.js +1 -1
  6. package/dist/common/events.d.ts +1 -2
  7. package/dist/common/format.d.ts +0 -1
  8. package/dist/common/format.js +1 -1
  9. package/dist/common/fp.d.ts +2 -3
  10. package/dist/common/fuzzysearch.d.ts +6 -2
  11. package/dist/common/fuzzysearch.js +1 -1
  12. package/dist/common/hotkeys.d.ts +6 -1
  13. package/dist/common/hotkeys.js +1 -1
  14. package/dist/common/http.d.ts +1 -3
  15. package/dist/common/react.d.ts +2 -9
  16. package/dist/common/react.js +1 -1
  17. package/dist/common/type-utils.js +1 -1
  18. package/dist/common/ui.d.ts +4 -4
  19. package/dist/components/Autofocus.d.ts +7 -2
  20. package/dist/components/Blink.d.ts +9 -22
  21. package/dist/components/Blink.js +1 -1
  22. package/dist/components/Box.d.ts +10 -6
  23. package/dist/components/Box.js +1 -1
  24. package/dist/components/Dialog.d.ts +6 -5
  25. package/dist/components/DmIcon.js +1 -1
  26. package/dist/components/Image.d.ts +5 -3
  27. package/dist/components/Image.js +1 -1
  28. package/dist/components/InfinitePlane.d.ts +2 -0
  29. package/dist/components/InfinitePlane.js +1 -1
  30. package/dist/components/LabeledList.d.ts +1 -3
  31. package/dist/components/Modal.d.ts +2 -2
  32. package/dist/components/NoticeBox.d.ts +1 -4
  33. package/dist/components/NoticeBox.js +1 -1
  34. package/dist/components/Popper.d.ts +2 -1
  35. package/dist/components/TrackOutsideClicks.d.ts +31 -9
  36. package/dist/components/TrackOutsideClicks.js +1 -1
  37. package/package.json +17 -16
package/README.md CHANGED
@@ -4,9 +4,12 @@ A collection of utilities and components for the [tgui](https://github.com/tgsta
4
4
 
5
5
  This package was built to help the various downstream SS13 servers stay up to date with TGUI without having to keep a local version of each file.
6
6
 
7
- You can view the code on [GitHub](https://github.com/tgstation/tgui-core).
7
+ ## Links
8
+ - [GitHub](https://github.com/tgstation/tgui-core)
9
+ - [npm](https://www.npmjs.com/package/tgui-core)
10
+ - [Storybook](https://tgstation.github.io/tgui-core/?path=/docs/components-animatednumber--docs)
8
11
 
9
- ## Installation
12
+ ## Usage
10
13
 
11
14
  (assuming you have a tgui folder, navigate to the specific package)
12
15
 
@@ -70,13 +73,13 @@ The release workflow will take care of setting the `package.json` version, build
70
73
 
71
74
  ### Development
72
75
 
73
- This project uses [pnpm](https://pnpm.io/installation) for its package manager.
76
+ This project uses [bun](https://bun.sh/docs/installation) for its package manager.
74
77
 
75
78
  To set up the repository:
76
- `pnpm install`
79
+ `bun install`
77
80
 
78
81
  To test your changes using [Storybook](https://storybook.js.org/docs) run:
79
- `pnpm run storybook`
82
+ `bun storybook`
80
83
 
81
84
  To run unit tests run
82
- `pnpm test`
85
+ `bun test`
@@ -7,11 +7,4 @@ type Zip<T extends unknown[][]> = {
7
7
  * the second elements of the given arrays, and so on.
8
8
  */
9
9
  export declare function zip<T extends unknown[][]>(...arr: T): Zip<T>;
10
- /**
11
- * Helper function for string compares with native sorts
12
- * @param a first string to compare
13
- * @param b second string to compare
14
- * @returns -1 for a < b, 1 for a > b and 0 otherwise
15
- */
16
- export declare function stringCompare(a: string, b: string): 1 | -1 | 0;
17
10
  export {};
@@ -1 +1 @@
1
- function r(...n){return Array(Math.max(...n.map(r=>r.length))).fill(void 0).map((r,t)=>n.map(r=>r[t]))}function n(r,n){return r<n?-1:+(r>n)}export{n as stringCompare,r as zip};
1
+ function a(...p){return Array(Math.max(...p.map(a=>a.length))).fill(void 0).map((a,r)=>p.map(a=>a[r]))}export{a as zip};
@@ -97,8 +97,8 @@ export declare const RADIO_CHANNELS: readonly [{
97
97
  }];
98
98
  export declare function getGasLabel(gasId: string, fallbackValue?: string): string;
99
99
  export declare function getGasColor(gasId: string): string;
100
- export declare const getGasFromId: (gasId: string) => Gas | undefined;
101
- export declare const getGasFromPath: (gasPath: string) => Gas | undefined;
100
+ export declare function getGasFromId(gasId: string): Gas | undefined;
101
+ export declare function getGasFromPath(gasPath: string): Gas | undefined;
102
102
  export declare const COMPONENT_COLORS: {
103
103
  readonly spectrum: readonly ["red", "orange", "yellow", "olive", "green", "teal", "blue", "violet", "purple", "pink", "brown", "grey", "gold"];
104
104
  readonly states: readonly ["", "good", "average", "bad", "black", "white"];
@@ -1 +1 @@
1
- let e=2,a=1,o=0,r=-1,l={damageType:{brute:"#e74c3c",burn:"#e67e22",oxy:"#3498db",toxin:"#2ecc71"},department:{captain:"#c06616",cargo:"#f39c12",centcom:"#00c100",engineering:"#f1c40f",medbay:"#3498db",other:"#c38312",science:"#9b59b6",security:"#e74c3c",service:"#7cc46a"},reagent:{acidicbuffer:"#fbc314",basicbuffer:"#3853a4"}},t=["average","bad","black","blue","brown","good","green","grey","label","olive","orange","pink","purple","red","teal","transparent","violet","white","yellow"],i=[{color:"#8f4a4b",freq:1213,name:"Syndicate"},{color:"#ff4444",freq:1215,name:"Red Team"},{color:"#3434fd",freq:1217,name:"Blue Team"},{color:"#34fd34",freq:1219,name:"Green Team"},{color:"#fdfd34",freq:1221,name:"Yellow Team"},{color:"#2681a5",freq:1337,name:"CentCom"},{color:"#b88646",freq:1347,name:"Supply"},{color:"#6ca729",freq:1349,name:"Service"},{color:"#c68cfa",freq:1351,name:"Science"},{color:"#fcdf03",freq:1353,name:"Command"},{color:"#57b8f0",freq:1355,name:"Medical"},{color:"#f37746",freq:1357,name:"Engineering"},{color:"#dd3535",freq:1359,name:"Security"},{color:"#d65d95",freq:1447,name:"AI Private"},{color:"#1ecc43",freq:1459,name:"Common"}],n=[{color:"blue",id:"o2",label:"O₂",name:"Oxygen",path:"/datum/gas/oxygen"},{color:"yellow",id:"n2",label:"N₂",name:"Nitrogen",path:"/datum/gas/nitrogen"},{color:"grey",id:"co2",label:"CO₂",name:"Carbon Dioxide",path:"/datum/gas/carbon_dioxide"},{color:"pink",id:"plasma",label:"Plasma",name:"Plasma",path:"/datum/gas/plasma"},{color:"lightsteelblue",id:"water_vapor",label:"H₂O",name:"Water Vapor",path:"/datum/gas/water_vapor"},{color:"teal",id:"hypernoblium",label:"Hyper-nob",name:"Hyper-noblium",path:"/datum/gas/hypernoblium"},{color:"bisque",id:"n2o",label:"N₂O",name:"Nitrous Oxide",path:"/datum/gas/nitrous_oxide"},{color:"brown",id:"no2",label:"Nitrium",name:"Nitrium",path:"/datum/gas/nitrium"},{color:"limegreen",id:"tritium",label:"Tritium",name:"Tritium",path:"/datum/gas/tritium"},{color:"mediumpurple",id:"bz",label:"BZ",name:"BZ",path:"/datum/gas/bz"},{color:"mediumslateblue",id:"pluoxium",label:"Pluoxium",name:"Pluoxium",path:"/datum/gas/pluoxium"},{color:"olive",id:"miasma",label:"Miasma",name:"Miasma",path:"/datum/gas/miasma"},{color:"paleturquoise",id:"freon",label:"Freon",name:"Freon",path:"/datum/gas/freon"},{color:"white",id:"hydrogen",label:"H₂",name:"Hydrogen",path:"/datum/gas/hydrogen"},{color:"salmon",id:"healium",label:"Healium",name:"Healium",path:"/datum/gas/healium"},{color:"greenyellow",id:"proto_nitrate",label:"Proto-Nitrate",name:"Proto Nitrate",path:"/datum/gas/proto_nitrate"},{color:"darkgreen",id:"zauker",label:"Zauker",name:"Zauker",path:"/datum/gas/zauker"},{color:"purple",id:"halon",label:"Halon",name:"Halon",path:"/datum/gas/halon"},{color:"aliceblue",id:"helium",label:"He",name:"Helium",path:"/datum/gas/helium"},{color:"maroon",id:"antinoblium",label:"Anti-Noblium",name:"Antinoblium",path:"/datum/gas/antinoblium"},{color:"brown",id:"nitrium",label:"Nitrium",name:"Nitrium",path:"/datum/gas/nitrium"}];function m(e,a){if(!e)return a||"None";let o=e.toLowerCase();for(let e=0;e<n.length;e++)if(n[e].id===o)return n[e].label;return a||"None"}function u(e){if(!e)return"black";let a=e.toLowerCase();for(let e=0;e<n.length;e++)if(n[e].id===a)return n[e].color;return"black"}let c=e=>{if(!e)return;let a=e.toLowerCase();for(let e=0;e<n.length;e++)if(n[e].id===a)return n[e]},d=e=>{if(e){for(let a=0;a<n.length;a++)if(n[a].path===e)return n[a]}},b={spectrum:["red","orange","yellow","olive","green","teal","blue","violet","purple","pink","brown","grey","gold"],states:["","good","average","bad","black","white"]};export{l as COLORS,b as COMPONENT_COLORS,t as CSS_COLORS,i as RADIO_CHANNELS,r as UI_CLOSE,o as UI_DISABLED,e as UI_INTERACTIVE,a as UI_UPDATE,u as getGasColor,c as getGasFromId,d as getGasFromPath,m as getGasLabel};
1
+ let e=2,a=1,o=0,r=-1,l={damageType:{brute:"#e74c3c",burn:"#e67e22",oxy:"#3498db",toxin:"#2ecc71"},department:{captain:"#c06616",cargo:"#f39c12",centcom:"#00c100",engineering:"#f1c40f",medbay:"#3498db",other:"#c38312",science:"#9b59b6",security:"#e74c3c",service:"#7cc46a"},reagent:{acidicbuffer:"#fbc314",basicbuffer:"#3853a4"}},t=["average","bad","black","blue","brown","good","green","grey","label","olive","orange","pink","purple","red","teal","transparent","violet","white","yellow"],i=[{color:"#8f4a4b",freq:1213,name:"Syndicate"},{color:"#ff4444",freq:1215,name:"Red Team"},{color:"#3434fd",freq:1217,name:"Blue Team"},{color:"#34fd34",freq:1219,name:"Green Team"},{color:"#fdfd34",freq:1221,name:"Yellow Team"},{color:"#2681a5",freq:1337,name:"CentCom"},{color:"#b88646",freq:1347,name:"Supply"},{color:"#6ca729",freq:1349,name:"Service"},{color:"#c68cfa",freq:1351,name:"Science"},{color:"#fcdf03",freq:1353,name:"Command"},{color:"#57b8f0",freq:1355,name:"Medical"},{color:"#f37746",freq:1357,name:"Engineering"},{color:"#dd3535",freq:1359,name:"Security"},{color:"#d65d95",freq:1447,name:"AI Private"},{color:"#1ecc43",freq:1459,name:"Common"}],n=[{color:"blue",id:"o2",label:"O₂",name:"Oxygen",path:"/datum/gas/oxygen"},{color:"yellow",id:"n2",label:"N₂",name:"Nitrogen",path:"/datum/gas/nitrogen"},{color:"grey",id:"co2",label:"CO₂",name:"Carbon Dioxide",path:"/datum/gas/carbon_dioxide"},{color:"pink",id:"plasma",label:"Plasma",name:"Plasma",path:"/datum/gas/plasma"},{color:"lightsteelblue",id:"water_vapor",label:"H₂O",name:"Water Vapor",path:"/datum/gas/water_vapor"},{color:"teal",id:"hypernoblium",label:"Hyper-nob",name:"Hyper-noblium",path:"/datum/gas/hypernoblium"},{color:"bisque",id:"n2o",label:"N₂O",name:"Nitrous Oxide",path:"/datum/gas/nitrous_oxide"},{color:"brown",id:"no2",label:"Nitrium",name:"Nitrium",path:"/datum/gas/nitrium"},{color:"limegreen",id:"tritium",label:"Tritium",name:"Tritium",path:"/datum/gas/tritium"},{color:"mediumpurple",id:"bz",label:"BZ",name:"BZ",path:"/datum/gas/bz"},{color:"mediumslateblue",id:"pluoxium",label:"Pluoxium",name:"Pluoxium",path:"/datum/gas/pluoxium"},{color:"olive",id:"miasma",label:"Miasma",name:"Miasma",path:"/datum/gas/miasma"},{color:"paleturquoise",id:"freon",label:"Freon",name:"Freon",path:"/datum/gas/freon"},{color:"white",id:"hydrogen",label:"H₂",name:"Hydrogen",path:"/datum/gas/hydrogen"},{color:"salmon",id:"healium",label:"Healium",name:"Healium",path:"/datum/gas/healium"},{color:"greenyellow",id:"proto_nitrate",label:"Proto-Nitrate",name:"Proto Nitrate",path:"/datum/gas/proto_nitrate"},{color:"darkgreen",id:"zauker",label:"Zauker",name:"Zauker",path:"/datum/gas/zauker"},{color:"purple",id:"halon",label:"Halon",name:"Halon",path:"/datum/gas/halon"},{color:"aliceblue",id:"helium",label:"He",name:"Helium",path:"/datum/gas/helium"},{color:"maroon",id:"antinoblium",label:"Anti-Noblium",name:"Antinoblium",path:"/datum/gas/antinoblium"},{color:"brown",id:"nitrium",label:"Nitrium",name:"Nitrium",path:"/datum/gas/nitrium"}];function m(e,a){if(!e)return a||"None";let o=e.toLowerCase();for(let e=0;e<n.length;e++)if(n[e].id===o)return n[e].label;return a||"None"}function u(e){if(!e)return"black";let a=e.toLowerCase();for(let e=0;e<n.length;e++)if(n[e].id===a)return n[e].color;return"black"}function c(e){if(!e)return;let a=e.toLowerCase();for(let e=0;e<n.length;e++)if(n[e].id===a)return n[e]}function d(e){if(e){for(let a=0;a<n.length;a++)if(n[a].path===e)return n[a]}}let b={spectrum:["red","orange","yellow","olive","green","teal","blue","violet","purple","pink","brown","grey","gold"],states:["","good","average","bad","black","white"]};export{l as COLORS,b as COMPONENT_COLORS,t as CSS_COLORS,i as RADIO_CHANNELS,r as UI_CLOSE,o as UI_DISABLED,e as UI_INTERACTIVE,a as UI_UPDATE,u as getGasColor,c as getGasFromId,d as getGasFromPath,m as getGasLabel};
@@ -1,4 +1,4 @@
1
- type Fn = (...args: any[]) => void;
1
+ import type { Fn } from './types';
2
2
  export declare class EventEmitter {
3
3
  private listeners;
4
4
  constructor();
@@ -30,4 +30,3 @@ export declare class KeyEvent {
30
30
  isUp(): boolean;
31
31
  toString(): string;
32
32
  }
33
- export {};
@@ -2,7 +2,6 @@ export declare function formatSiUnit(value: number, minBase1000?: number, unit?:
2
2
  export declare function formatPower(value: number, minBase1000?: number): string;
3
3
  export declare function formatEnergy(value: number, minBase1000?: number): string;
4
4
  export declare function formatMoney(value: number, precision?: number): string;
5
- export declare function formatDb(value: number): string;
6
5
  export declare function formatSiBaseTenUnit(value: number, minBase1000?: number, unit?: string): string;
7
6
  /**
8
7
  * Formats decisecond count into HH:MM:SS display by default
@@ -1 +1 @@
1
- let t=["f","p","n","μ","m"," ","k","M","G","T","P","E","Z","Y","R","Q","F","N","H"],r=t.indexOf(" ");function e(n,i=-r,o=""){if(!Number.isFinite(n))return n.toString();let a=Math.floor(Math.max(3*i,Math.floor(Math.log10(Math.abs(n))))/3),f=t[Math.min(a+r,t.length-1)],l=(n/1e3**a).toFixed(2);return l.endsWith(".00")?l=l.slice(0,-3):l.endsWith(".0")&&(l=l.slice(0,-2)),`${l} ${f.trim()}${o}`.trim()}function n(t,r=0){return e(t,r,"W")}function i(t,r=0){return e(t,r,"J")}function o(t,r=0){if(!Number.isFinite(t))return String(t);let e=Number(t.toFixed(r)),n=Math.abs(e).toString().split(".");n[0]=n[0].replace(/\B(?=(\d{3})+(?!\d))/g," ");let i=n.join(".");return e<0?`-${i}`:i}function a(t){let r=20*Math.log10(t),e=Math.abs(r);return e=e===Number.POSITIVE_INFINITY?"Inf":e.toFixed(2),`${r>=0?"+":"-"}${e} dB`}let f=["","\xb7 10\xb3","\xb7 10⁶","\xb7 10⁹","\xb7 10\xb9\xb2","\xb7 10\xb9⁵","\xb7 10\xb9⁸","\xb7 10\xb2\xb9","\xb7 10\xb2⁴","\xb7 10\xb2⁷","\xb7 10\xb3⁰","\xb7 10\xb3\xb3","\xb7 10\xb3⁶","\xb7 10\xb3⁹"];function l(t,r=0,e=""){if(!Number.isFinite(t))return"NaN";let n=Math.max(3*r,Math.floor(Math.log10(t))),i=Math.floor(n/3),o=f[i],a=Math.max(0,2-n%3),u=(t/1e3**i).toFixed(a);return`${u} ${o} ${e}`.trim()}function u(t,r="default"){let e=Math.floor(t/10),n=Math.floor(e/3600),i=Math.floor(e%3600/60),o=e%60;if("short"===r){let t=n>0?`${n}h`:"",r=i>0?`${i}m`:"",e=o>0?`${o}s`:"";return`${t}${r}${e}`}let a=String(n).padStart(2,"0"),f=String(i).padStart(2,"0"),l=String(o).padStart(2,"0");return`${a}:${f}:${l}`}export{a as formatDb,i as formatEnergy,o as formatMoney,n as formatPower,l as formatSiBaseTenUnit,e as formatSiUnit,u as formatTime};
1
+ let t=["f","p","n","μ","m"," ","k","M","G","T","P","E","Z","Y","R","Q","F","N","H"],r=t.indexOf(" ");function e(i,n=-r,o=""){if(!Number.isFinite(i))return i.toString();let a=Math.floor(Math.max(3*n,Math.floor(Math.log10(Math.abs(i))))/3),f=t[Math.min(a+r,t.length-1)],l=(i/1e3**a).toFixed(2);return l.endsWith(".00")?l=l.slice(0,-3):l.endsWith(".0")&&(l=l.slice(0,-2)),`${l} ${f.trim()}${o}`.trim()}function i(t,r=0){return e(t,r,"W")}function n(t,r=0){return e(t,r,"J")}function o(t,r=0){if(!Number.isFinite(t))return String(t);let e=Number(t.toFixed(r)),i=Math.abs(e).toString().split(".");i[0]=i[0].replace(/\B(?=(\d{3})+(?!\d))/g," ");let n=i.join(".");return e<0?`-${n}`:n}let a=["","\xb7 10\xb3","\xb7 10⁶","\xb7 10⁹","\xb7 10\xb9\xb2","\xb7 10\xb9⁵","\xb7 10\xb9⁸","\xb7 10\xb2\xb9","\xb7 10\xb2⁴","\xb7 10\xb2⁷","\xb7 10\xb3⁰","\xb7 10\xb3\xb3","\xb7 10\xb3⁶","\xb7 10\xb3⁹"];function f(t,r=0,e=""){if(!Number.isFinite(t))return"NaN";let i=Math.max(3*r,Math.floor(Math.log10(t))),n=Math.floor(i/3),o=a[n],l=Math.max(0,2-i%3),u=(t/1e3**n).toFixed(l);return`${u} ${o} ${e}`.trim()}function l(t,r="default"){let e=Math.floor(t/10),i=Math.floor(e/3600),n=Math.floor(e%3600/60),o=e%60;if("short"===r){let t=i>0?`${i}h`:"",r=n>0?`${n}m`:"",e=o>0?`${o}s`:"";return`${t}${r}${e}`}let a=String(i).padStart(2,"0"),f=String(n).padStart(2,"0"),u=String(o).padStart(2,"0");return`${a}:${f}:${u}`}export{n as formatEnergy,o as formatMoney,i as formatPower,f as formatSiBaseTenUnit,e as formatSiUnit,l as formatTime};
@@ -1,4 +1,4 @@
1
- type Func = (...args: any[]) => any;
1
+ import type { Fn } from './types';
2
2
  /**
3
3
  * Creates a function that returns the result of invoking the given
4
4
  * functions, where each successive invocation is supplied the return
@@ -15,5 +15,4 @@ type Func = (...args: any[]) => any;
15
15
  * const composedFunction2 = flow([add2, multiplyBy3], subtract5); // ((4 + 2) * 3) - 5 = 13
16
16
  *
17
17
  */
18
- export declare const flow: (...funcs: Array<Func | Func[]>) => (input: any, ...rest: any[]) => any;
19
- export {};
18
+ export declare const flow: (...funcs: Array<Fn | Fn[]>) => (input: any, ...rest: any[]) => any;
@@ -11,10 +11,14 @@ interface UseFuzzySearchProps<T> {
11
11
  getSearchString: (item: T) => string;
12
12
  }
13
13
  /**
14
- * A simple hook prooviding fuzzy searching - approximate rather
14
+ * ## useFuzzySearch
15
+ *
16
+ * A simple hook providing fuzzy searching - uses approximate rather
15
17
  * than exact pattern matching.
18
+ *
19
+ * - [View documentation on tgui core](https://tgstation.github.io/tgui-core/?path=/docs/hooks-usefuzzysearch--docs)
16
20
  */
17
- export declare function useFuzzySearch<T>({ searchArray, matchStrategy, getSearchString, }: UseFuzzySearchProps<T>): {
21
+ export declare function useFuzzySearch<T>(options: UseFuzzySearchProps<T>): {
18
22
  query: string;
19
23
  setQuery: (value: string) => void;
20
24
  results: T[];
@@ -1 +1 @@
1
- import*as t from"@nozbe/microfuzz";import*as e from"react";function r({searchArray:r,matchStrategy:a="smart",getSearchString:u}){let[o,i]=(0,e.useState)(""),[m,s]=(0,e.useState)([]),f=(0,e.useCallback)((0,t.default)(r,{getText:t=>[u(t)],strategy:a}),[r,u]);return{query:o,setQuery:function(t){if(i(t),""===t.trim())return void s([]);s(f(t).map(t=>t.item))},results:m}}export{r as useFuzzySearch};
1
+ import*as t from"@nozbe/microfuzz";import*as e from"react";function r(r){let{getSearchString:a,matchStrategy:u="smart",searchArray:o}=r,[i,m]=(0,e.useState)(""),[s,f]=(0,e.useState)([]),n=(0,e.useCallback)((0,t.default)(o,{getText:t=>[a(t)],strategy:u}),[o,a]);return{query:i,setQuery:function(t){if(m(t),""===t.trim())return void f([]);f(n(t).map(t=>t.item))},results:s}}export{r as useFuzzySearch};
@@ -9,7 +9,12 @@ export declare function acquireHotKey(keyCode: number): void;
9
9
  */
10
10
  export declare function releaseHotKey(keyCode: number): void;
11
11
  export declare function releaseHeldKeys(): void;
12
- export declare function setupHotKeys(): void;
12
+ export type KeyPassthroughConfig = {
13
+ keyUpVerb: string;
14
+ keyDownVerb: string;
15
+ verbParamsFn: (verb: string, keyCode: string) => string;
16
+ };
17
+ export declare function setupHotKeys(config?: KeyPassthroughConfig): void;
13
18
  export declare function startKeyPassthrough(): void;
14
19
  export declare function stopKeyPassthrough(): void;
15
20
  /**
@@ -1 +1 @@
1
- import*as e from"./events.js";import*as t from"./keycodes.js";let o={},n=[t.KEY_ESCAPE,t.KEY_ENTER,t.KEY_SPACE,t.KEY_TAB,t.KEY_CTRL,t.KEY_SHIFT,t.KEY_UP,t.KEY_DOWN,t.KEY_LEFT,t.KEY_RIGHT,t.KEY_F5],l={},r=[];function i(e){n.push(e)}function s(e){let t=n.indexOf(e);t>=0&&n.splice(t,1)}function a(){for(let e in l)l[e]&&(l[e]=!1,Byond.command(`${globalThis.ByondKeyUp} "${e}"`))}function d(){globalThis.ByondKeyUp||(globalThis.ByondKeyUp="KeyUp",globalThis.ByondKeyDown="KeyDown"),Byond.winget("default.*").then(e=>{let t={};for(let o in e){let n=o.split("."),l=n[1],r=n[2];l&&r&&(t[l]||(t[l]={}),t[l][r]=e[o])}let n=/\\"/g;function l(e){return e.substring(1,e.length-1).replace(n,'"')}for(let e in t){let n=t[e];o[l(n.name)]=l(n.command)}}),e.globalEvents.on("window-blur",()=>{a()}),f()}function f(){e.globalEvents.on("key",y)}function u(){e.globalEvents.off("key",y)}function y(e){for(let t of r)t(e);!function(e){var t;let r=String(e);if("Ctrl+F5"===r||"Ctrl+R"===r)return location.reload();if("Ctrl+F"===r||e.event.defaultPrevented||e.isModifierKey()||n.includes(e.code))return;let i=16===(t=e.code)?"Shift":17===t?"Ctrl":18===t?"Alt":33===t?"Northeast":34===t?"Southeast":35===t?"Southwest":36===t?"Northwest":37===t?"West":38===t?"North":39===t?"East":40===t?"South":45===t?"Insert":46===t?"Delete":t>=48&&t<=57||t>=65&&t<=90?String.fromCharCode(t):t>=96&&t<=105?`Numpad${t-96}`:t>=112&&t<=123?`F${t-111}`:188===t?",":189===t?"-":190===t?".":void 0;if(!i)return;let s=o[i];if(s)return Byond.command(s);if(e.isDown()&&!l[i]){l[i]=!0;let e=`${globalThis.ByondKeyDown} "${i}"`;return Byond.command(e)}if(e.isUp()&&l[i]){l[i]=!1;let e=`${globalThis.ByondKeyUp} "${i}"`;Byond.command(e)}}(e)}function K(e){r.push(e);let t=!1;return()=>{t||(t=!0,r.splice(r.indexOf(e),1))}}export{i as acquireHotKey,K as listenForKeyEvents,a as releaseHeldKeys,s as releaseHotKey,d as setupHotKeys,f as startKeyPassthrough,u as stopKeyPassthrough};
1
+ import*as e from"./events.js";import*as t from"./keycodes.js";let n={},o=[t.KEY_ESCAPE,t.KEY_ENTER,t.KEY_SPACE,t.KEY_TAB,t.KEY_CTRL,t.KEY_SHIFT,t.KEY_UP,t.KEY_DOWN,t.KEY_LEFT,t.KEY_RIGHT,t.KEY_F5],r={},l=[];function s(e){o.push(e)}function i(e){let t=o.indexOf(e);t>=0&&o.splice(t,1)}function a(){for(let e in r)r[e]&&(r[e]=!1,Byond.command(f.verbParamsFn(f.keyUpVerb,e)))}let f={keyDownVerb:"KeyDown",keyUpVerb:"KeyUp",verbParamsFn:(e,t)=>`${e} "${t}"`};function u(t){t&&(f=t),Byond.winget("default.*").then(e=>{let t={};for(let n in e){let o=n.split("."),r=o[1],l=o[2];r&&l&&(t[r]||(t[r]={}),t[r][l]=e[n])}let o=/\\"/g;function r(e){return e.substring(1,e.length-1).replace(o,'"')}for(let e in t){let o=t[e];n[r(o.name)]=r(o.command)}}),e.globalEvents.on("window-blur",()=>{a()}),d()}function d(){e.globalEvents.on("key",y)}function c(){e.globalEvents.off("key",y)}function y(e){for(let t of l)t(e);!function(e){var t;let l=String(e);if("Ctrl+F5"===l||"Ctrl+R"===l)return location.reload();if("Ctrl+F"===l||e.event.defaultPrevented||e.isModifierKey()||o.includes(e.code))return;let s=16===(t=e.code)?"Shift":17===t?"Ctrl":18===t?"Alt":33===t?"Northeast":34===t?"Southeast":35===t?"Southwest":36===t?"Northwest":37===t?"West":38===t?"North":39===t?"East":40===t?"South":45===t?"Insert":46===t?"Delete":t>=48&&t<=57||t>=65&&t<=90?String.fromCharCode(t):t>=96&&t<=105?`Numpad${t-96}`:t>=112&&t<=123?`F${t-111}`:188===t?",":189===t?"-":190===t?".":void 0;if(!s)return;let i=n[s];if(i)return Byond.command(i);if(e.isDown()&&!r[s]){r[s]=!0;let e=f.verbParamsFn(f.keyDownVerb,s);return Byond.command(e)}if(e.isUp()&&r[s]){r[s]=!1;let e=f.verbParamsFn(f.keyUpVerb,s);Byond.command(e)}}(e)}function E(e){l.push(e);let t=!1;return()=>{t||(t=!0,l.splice(l.indexOf(e),1))}}export{s as acquireHotKey,E as listenForKeyEvents,a as releaseHeldKeys,i as releaseHotKey,u as setupHotKeys,d as startKeyPassthrough,c as stopKeyPassthrough};
@@ -1,4 +1,2 @@
1
- /**
2
- * An equivalent to `fetch`, except will automatically retry.
3
- */
1
+ /** An equivalent to `fetch`, except will automatically retry. */
4
2
  export declare function fetchRetry(url: string, options?: RequestInit, retryTimer?: number): Promise<Response>;
@@ -2,22 +2,15 @@
2
2
  * Helper for conditionally adding/removing classes in React
3
3
  */
4
4
  export declare function classes(classNames: (string | BooleanLike)[]): string;
5
- /**
6
- * Normalizes children prop, so that it is always an array of VDom
7
- * elements.
8
- */
9
- export declare function normalizeChildren<T>(children: T | T[]): T[];
10
5
  /**
11
6
  * Shallowly checks if two objects are different.
12
7
  * Credit: https://github.com/developit/preact-compat
13
8
  */
14
9
  export declare function shallowDiffers(a: Record<string, any>, b: Record<string, any>): boolean;
15
10
  /**
16
- * A common case in tgui, when you pass a value conditionally, these are
11
+ * A common case in tgui when you pass a value conditionally. These are
17
12
  * the types that can fall through the condition.
18
13
  */
19
14
  export type BooleanLike = number | boolean | null | undefined;
20
- /**
21
- * A helper to determine whether the object is renderable by React.
22
- */
15
+ /** A helper to determine whether the object is renderable by React. */
23
16
  export declare function canRender(value: unknown): boolean;
@@ -1 +1 @@
1
- function r(r){let n="";for(let e=0;e<r.length;e++){let t=r[e];"string"==typeof t&&(n+=`${t} `)}return n}function n(r){return Array.isArray(r)?r.flat().filter(r=>r):"object"==typeof r?[r]:[]}function e(r,n){let e;for(e in r)if(!(e in n))return!0;for(e in n)if(r[e]!==n[e])return!0;return!1}function t(r){return null!=r&&"boolean"!=typeof r}export{t as canRender,r as classes,n as normalizeChildren,e as shallowDiffers};
1
+ function n(n){let e="";for(let r=0;r<n.length;r++){let t=n[r];"string"==typeof t&&(e+=`${t} `)}return e}function e(n,e){let r;for(r in n)if(!(r in e))return!0;for(r in e)if(n[r]!==e[r])return!0;return!1}function r(n){return null!=n&&"boolean"!=typeof n}export{r as canRender,n as classes,e as shallowDiffers};
@@ -1 +1 @@
1
- function e(e){let t={};for(let n in e)if(Array.isArray(e[n])){let r=e[n];if(e[n].length>0){t[n]=r[0];continue}t[n]="emptyarray"}else if("object"==typeof e[n]&&null!==e[n])t[n]="object (inspect) || Record<string, any>";else if("number"==typeof e[n]){let r=Number(e[n]);if(1===r||0===r){t[n]=`${r}, BooleanLike?`;continue}t[n]=e[n]}return t}export{e as getShallowTypes};
1
+ function e(e){let t={};for(let r in e)if(Array.isArray(e[r])){let n=e[r];if(e[r].length>0){t[r]=n[0];continue}t[r]="emptyarray"}else if("object"==typeof e[r]&&null!==e[r])t[r]="Record<string, sometype>";else if("number"==typeof e[r]){let n=Number(e[r]);if(1===n||0===n){t[r]=`${n}, BooleanLike?`;continue}t[r]=e[r]}return t}export{e as getShallowTypes};
@@ -9,7 +9,7 @@ export declare const unit: UnitMapper;
9
9
  * Same as `unit`, but half the size for integers numbers.
10
10
  */
11
11
  export declare const halfUnit: UnitMapper;
12
- export type StringStyleMap = {
12
+ export type StringStyleMap = Partial<{
13
13
  /** Align text inside the box. */
14
14
  align: string | BooleanLike;
15
15
  /** A direct mapping to `position` CSS property. */
@@ -94,9 +94,9 @@ export type StringStyleMap = {
94
94
  lineHeight: string | BooleanLike;
95
95
  /** Align text inside the box. */
96
96
  textAlign: string | BooleanLike;
97
- };
97
+ }>;
98
98
  export declare const stringStyleMap: Record<keyof StringStyleMap, any>;
99
- export type BooleanStyleMap = {
99
+ export type BooleanStyleMap = Partial<{
100
100
  /** Make text bold. */
101
101
  bold: boolean;
102
102
  /** Fill positioned parent. */
@@ -109,7 +109,7 @@ export type BooleanStyleMap = {
109
109
  nowrap: boolean;
110
110
  /** Preserves line-breaks and spacing in text. */
111
111
  preserveWhitespace: boolean;
112
- };
112
+ }>;
113
113
  export declare const booleanStyleMap: Record<keyof BooleanStyleMap, any>;
114
114
  export declare function computeBoxProps(props: any): Record<string, any>;
115
115
  export declare function computeBoxClassName<TElement = HTMLDivElement>(props: BoxProps<TElement>): string;
@@ -1,7 +1,12 @@
1
- import { type PropsWithChildren } from 'react';
1
+ import { type ReactNode } from 'react';
2
+ type Props = Partial<{
3
+ /** Optional child elements */
4
+ children: ReactNode;
5
+ }>;
2
6
  /**
3
7
  * ## Autofocus
4
8
  *
5
9
  * Used to force the window to steal focus on load. Children optional.
6
10
  */
7
- export declare function Autofocus(props: PropsWithChildren): import("react/jsx-runtime").JSX.Element;
11
+ export declare function Autofocus(props: Props): import("react/jsx-runtime").JSX.Element;
12
+ export {};
@@ -1,17 +1,13 @@
1
- import { Component, type PropsWithChildren } from 'react';
2
- type Props = Partial<{
3
- /**
4
- * The interval between blinks, in milliseconds.
5
- */
1
+ import { type ReactNode } from 'react';
2
+ type Props = {
3
+ /** Things that blink! */
4
+ children: ReactNode;
5
+ } & Partial<{
6
+ /** The interval between blinks, in milliseconds. */
6
7
  interval: number;
7
- /**
8
- * The time to wait before blinking again, in milliseconds.
9
- */
8
+ /** The time to wait before blinking again, in milliseconds. */
10
9
  time: number;
11
- }> & PropsWithChildren;
12
- type State = {
13
- hidden: boolean;
14
- };
10
+ }>;
15
11
  /**
16
12
  * ## Blink
17
13
  *
@@ -19,14 +15,5 @@ type State = {
19
15
  *
20
16
  * - [View documentation on tgui core](https://tgstation.github.io/tgui-core/?path=/docs/components-blink--docs)
21
17
  */
22
- export declare class Blink extends Component<Props, State> {
23
- interval: NodeJS.Timeout;
24
- timer: NodeJS.Timeout;
25
- constructor(props: any);
26
- createTimer(): void;
27
- componentDidMount(): void;
28
- componentDidUpdate(prevProps: any): void;
29
- componentWillUnmount(): void;
30
- render(): import("react/jsx-runtime").JSX.Element;
31
- }
18
+ export declare function Blink(props: Props): import("react/jsx-runtime").JSX.Element;
32
19
  export {};
@@ -1 +1 @@
1
- import*as t from"react/jsx-runtime";import*as e from"react";class i extends e.Component{interval;timer;constructor(t){super(t),this.state={hidden:!1}}createTimer(){let{interval:t=1e3,time:e=1e3}=this.props;clearInterval(this.interval),clearTimeout(this.timer),this.setState({hidden:!1}),this.interval=setInterval(()=>{this.setState({hidden:!0}),this.timer=setTimeout(()=>{this.setState({hidden:!1})},e)},t+e)}componentDidMount(){this.createTimer()}componentDidUpdate(t){(t.interval!==this.props.interval||t.time!==this.props.time)&&this.createTimer()}componentWillUnmount(){clearInterval(this.interval),clearTimeout(this.timer)}render(){return(0,t.jsx)("span",{style:{visibility:this.state.hidden?"hidden":"visible"},children:this.props.children})}}export{i as Blink};
1
+ import*as e from"react/jsx-runtime";import*as t from"react";function r(r){let{children:i,interval:s=1e3,time:n=1e3}=r,[l,a]=(0,t.useState)(!1);return(0,t.useEffect)(()=>{let e=setInterval(()=>{a(!0),setTimeout(()=>{a(!1)},n)},s+n);return()=>{clearInterval(e)}},[s,n]),(0,e.jsx)("span",{style:{visibility:l?"hidden":"visible"},children:i})}export{r as Blink};
@@ -1,7 +1,7 @@
1
1
  import { type CSSProperties, type KeyboardEventHandler, type MouseEventHandler, type ReactNode, type UIEventHandler } from 'react';
2
2
  import type { BooleanLike } from '../common/react';
3
3
  import { type BooleanStyleMap, type StringStyleMap } from '../common/ui';
4
- type EventHandlers<TElement = HTMLDivElement> = {
4
+ type EventHandlers<TElement = HTMLDivElement> = Partial<{
5
5
  onClick: MouseEventHandler<TElement>;
6
6
  onContextMenu: MouseEventHandler<TElement>;
7
7
  onDoubleClick: MouseEventHandler<TElement>;
@@ -13,9 +13,12 @@ type EventHandlers<TElement = HTMLDivElement> = {
13
13
  onMouseOver: MouseEventHandler<TElement>;
14
14
  onMouseUp: MouseEventHandler<TElement>;
15
15
  onScroll: UIEventHandler<TElement>;
16
- };
17
- type InternalProps = {
18
- /** The component used for the root node. */
16
+ }>;
17
+ type InternalProps = Partial<{
18
+ /**
19
+ * The component used for the root node.
20
+ * @default <div>
21
+ */
19
22
  as: string;
20
23
  /** The content of the component. */
21
24
  children: ReactNode;
@@ -48,8 +51,9 @@ type InternalProps = {
48
51
  * 3. This should be a static string with minimal interpolation. If you need more logic, prefer the props approach.
49
52
  */
50
53
  tw: string;
51
- };
52
- export type BoxProps<TElement = HTMLDivElement> = Partial<InternalProps & BooleanStyleMap & StringStyleMap & EventHandlers<TElement>>;
54
+ }>;
55
+ export interface BoxProps<TElement = HTMLDivElement> extends InternalProps, BooleanStyleMap, StringStyleMap, EventHandlers<TElement> {
56
+ }
53
57
  type DangerDoNotUse = {
54
58
  dangerouslySetInnerHTML?: {
55
59
  __html: any;
@@ -1 +1 @@
1
- import*as e from"react";import*as o from"../common/ui.js";function m(m){let{as:s="div",className:t,children:a,tw:r,...c}=m,u=(0,e.useMemo)(()=>t?`${t} ${(0,o.computeBoxClassName)(c)}`:(0,o.computeBoxClassName)(c),[t,c]),p=(0,e.useMemo)(()=>(0,o.computeBoxProps)({...c,...(0,o.computeTwClass)(r)}),[c,r]);return(0,e.createElement)(s,{...p,className:u},a)}export{m as Box};
1
+ import*as o from"react";import*as e from"../common/ui.js";function m(m){let{as:t="div",className:s,children:a,tw:r,...c}=m,p=s?`${s} ${(0,e.computeBoxClassName)(c)}`:(0,e.computeBoxClassName)(c),u=(0,e.computeBoxProps)({...c,...(0,e.computeTwClass)(r)});return(0,o.createElement)(t,{...u,className:p},a)}export{m as Box};
@@ -2,15 +2,16 @@ import type { ReactNode } from 'react';
2
2
  type DialogProps = {
3
3
  /** The content of the dialog. */
4
4
  children: ReactNode;
5
- /** The height of the dialog. */
6
- height?: string;
7
5
  /** The function to call when close is clicked */
8
6
  onClose: () => void;
9
7
  /** The title of the dialog. */
10
8
  title: ReactNode;
9
+ } & Partial<{
10
+ /** The height of the dialog. */
11
+ height: string;
11
12
  /** The width of the dialog. */
12
- width?: string;
13
- };
13
+ width: string;
14
+ }>;
14
15
  /**
15
16
  * ## Dialog
16
17
  *
@@ -31,7 +32,7 @@ export declare namespace Dialog {
31
32
  var Button: typeof DialogButton;
32
33
  }
33
34
  type DialogButtonProps = {
34
- children: any;
35
+ children: ReactNode;
35
36
  onClick: () => void;
36
37
  };
37
38
  declare function DialogButton(props: DialogButtonProps): import("react/jsx-runtime").JSX.Element;
@@ -1 +1 @@
1
- import*as T from"react/jsx-runtime";import*as r from"./Image.js";var S,e=((S={})[S.NORTH=1]="NORTH",S[S.SOUTH=2]="SOUTH",S[S.EAST=4]="EAST",S[S.WEST=8]="WEST",S[S.NORTHEAST=5]="NORTHEAST",S[S.NORTHWEST=9]="NORTHWEST",S[S.SOUTHEAST=6]="SOUTHEAST",S[S.SOUTHWEST=10]="SOUTHWEST",S);function t(S){let{className:e,direction:t=2,fallback:o,frame:E=1,icon_state:i,icon:m,movement:n=!1,...H}=S,O=Byond.iconRefMap?.[m];if(!O)return o;let a=`${O}?state=${i}&dir=${t}&movement=${!!n}&frame=${E}`;return(0,T.jsx)(r.Image,{fixErrors:!0,src:a,...H})}export{e as Direction,t as DmIcon};
1
+ import*as T from"react/jsx-runtime";import*as r from"./Image.js";var S,e=((S={})[S.NORTH=1]="NORTH",S[S.SOUTH=2]="SOUTH",S[S.EAST=4]="EAST",S[S.WEST=8]="WEST",S[S.NORTHEAST=5]="NORTHEAST",S[S.NORTHWEST=9]="NORTHWEST",S[S.SOUTHEAST=6]="SOUTHEAST",S[S.SOUTHWEST=10]="SOUTHWEST",S);function t(S){let{direction:e=2,fallback:t,frame:o=1,icon_state:E,icon:i,movement:m=!1,...n}=S,H=Byond.iconRefMap?.[i];if(!H)return t;let O=`${H}?state=${E}&dir=${e}&movement=${!!m}&frame=${o}`;return(0,T.jsx)(r.Image,{fixErrors:!0,src:O,...n})}export{e as Direction,t as DmIcon};
@@ -1,9 +1,11 @@
1
1
  import type { BoxProps } from './Box';
2
2
  type Props = Partial<{
3
- className: string;
4
- /** True is default, this fixes an ie thing */
3
+ /** True is default, this fixes DM icon rendering issues */
5
4
  fixBlur: boolean;
6
- /** False by default. Good if you're fetching images on UIs that do not auto update. This will attempt to fix the 'x' icon 5 times. */
5
+ /**
6
+ * False by default. Good if you're fetching images on UIs that do not auto
7
+ * update. This will attempt to fix the 'x' icon 5 times.
8
+ */
7
9
  fixErrors: boolean;
8
10
  /** Fill is default. */
9
11
  objectFit: 'contain' | 'cover';
@@ -1 +1 @@
1
- import*as e from"react/jsx-runtime";import*as A from"react";import*as t from"../common/ui.js";function r(r){let{fixBlur:o=!0,fixErrors:m=!1,objectFit:a="fill",src:i,...n}=r,s=(0,A.useRef)(0),u=(0,t.computeBoxProps)(n);return u.style={...u.style,"-ms-interpolation-mode":o?"nearest-neighbor":"auto",imageRendering:o?"pixelated":"auto",objectFit:a},(0,e.jsx)("img",{onError:e=>{if(m&&s.current<5){let A=e.currentTarget;setTimeout(()=>{A.src=`${i}?attempt=${s.current}`,s.current++},1e3)}},src:i||"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=",...u,alt:"dm icon"})}export{r as Image};
1
+ import*as A from"react/jsx-runtime";import*as e from"react";import*as r from"../common/ui.js";function t(t){let{fixBlur:o=!0,fixErrors:m=!1,objectFit:a="fill",src:i,...n}=t,s=(0,e.useRef)(0),c=(0,r.computeBoxProps)(n);return c.style={...c.style,imageRendering:o?"pixelated":"auto",objectFit:a},(0,A.jsx)("img",{onError:A=>{if(m&&s.current<5){let e=A.currentTarget;setTimeout(()=>{e.src=`${i}?attempt=${s.current}`,s.current++},1e3)}},src:i||"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=",...c,alt:"dm icon"})}export{t as Image};
@@ -10,6 +10,8 @@ type Props = {
10
10
  initialLeft: number;
11
11
  /** The initial top position of the image. */
12
12
  initialTop: number;
13
+ /** Padding applied to the right of the zoom controls */
14
+ zoomPadding: number;
13
15
  /** A callback function that is called when the background image is moved. */
14
16
  onBackgroundMoved: (newX: number, newY: number) => void;
15
17
  /** A callback function that is called when the zoom value changes. */
@@ -1 +1 @@
1
- import*as e from"react/jsx-runtime";import*as t from"react";import*as o from"../common/ui.js";import*as n from"./Button.js";import*as i from"./ProgressBar.js";import*as s from"./Stack.js";function r(n){let{backgroundImage:i,children:s,imageWidth:r,initialLeft:u=0,initialTop:c=0,onBackgroundMoved:l,onZoomChange:d,...m}=n,[p,f]=(0,t.useState)(0),[x,h]=(0,t.useState)(0),[j,g]=(0,t.useState)(0),[k,v]=(0,t.useState)(!1),[S,w]=(0,t.useState)(0),[b,M]=(0,t.useState)(1);function $(e){f(e.clientX-j),h(e.clientY-S),v(!0)}function B(e){if(!k)return;let t=e.clientX-p,o=e.clientY-x;l?.(t+u,o+c),g(t),w(o)}function y(){v(!1)}(0,t.useEffect)(()=>(window.addEventListener("mouseup",y),()=>{window.removeEventListener("mouseup",y)}),[]);let I=u+j,P=c+S;return(0,e.jsxs)("div",{...(0,o.computeBoxProps)({...m,style:{...m.style,height:"100%",overflow:"hidden",position:"relative",width:"100%"}}),children:[(0,e.jsx)("div",{onMouseDown:$,onMouseMove:B,style:{backgroundImage:`url("${i}")`,backgroundPosition:`${I}px ${P}px`,backgroundRepeat:"repeat",backgroundSize:`${b*r}px`,height:"100%",inset:0,position:"absolute",width:"100%"}}),(0,e.jsx)("div",{onMouseDown:$,onMouseMove:B,style:{height:"100%",inset:0,position:"absolute",transform:`translate(${I}px, ${P}px) scale(${b})`,transformOrigin:"top left",width:"100%"},children:s}),(0,e.jsx)(a,{onZoomClick:function(e){if("increase"===e&&b>=1.5||"decrease"===e&&b<=.5)return;let t=Math.round((b+("increase"===e?.1:-.1))*10)/10;M(t),d?.(t)},zoom:b})]})}function a(t){let{zoom:o,onZoomClick:r}=t;return(0,e.jsx)("div",{style:{left:5,position:"absolute",right:5,top:5},children:(0,e.jsxs)(s.Stack,{children:[(0,e.jsx)(s.Stack.Item,{children:(0,e.jsx)(n.Button,{disabled:o<=.5,icon:"minus",onClick:()=>r("decrease")})}),(0,e.jsx)(s.Stack.Item,{grow:!0,children:(0,e.jsxs)(i.ProgressBar,{maxValue:1.5,minValue:.5,value:o,children:[o,"x"]})}),(0,e.jsx)(s.Stack.Item,{children:(0,e.jsx)(n.Button,{disabled:o>=1.5,icon:"plus",onClick:()=>r("increase")})})]})})}export{r as InfinitePlane};
1
+ import*as e from"react/jsx-runtime";import*as t from"react";import*as o from"../common/ui.js";import*as n from"./Button.js";import*as i from"./ProgressBar.js";import*as s from"./Stack.js";function r(n){let{backgroundImage:i,children:s,imageWidth:r,zoomPadding:u=0,initialLeft:c=0,initialTop:l=0,onBackgroundMoved:d,onZoomChange:m,...p}=n,[f,x]=(0,t.useState)(0),[h,j]=(0,t.useState)(0),[g,v]=(0,t.useState)(0),[k,S]=(0,t.useState)(!1),[w,b]=(0,t.useState)(0),[M,$]=(0,t.useState)(1);function B(e){x(e.clientX-g),j(e.clientY-w),S(!0)}function y(e){if(!k)return;let t=e.clientX-f,o=e.clientY-h;d?.(t+c,o+l),v(t),b(o)}function I(){S(!1)}function P(e){if("increase"===e&&M>=1.5||"decrease"===e&&M<=.5)return;let t=Math.round((M+("increase"===e?.1:-.1))*10)/10;$(t),m?.(t)}(0,t.useEffect)(()=>(window.addEventListener("mouseup",I),()=>{window.removeEventListener("mouseup",I)}),[]);let Y=c+g,C=l+w;return(0,e.jsxs)("div",{...(0,o.computeBoxProps)({...p,style:{...p.style,height:"100%",overflow:"hidden",position:"relative",width:"100%"}}),children:[(0,e.jsx)("div",{onMouseDown:B,onMouseMove:y,onWheel:function(e){0!==e.deltaY&&(e.preventDefault(),P(e.deltaY>0?"increase":"decrease"))},style:{backgroundImage:`url("${i}")`,backgroundPosition:`${Y}px ${C}px`,backgroundRepeat:"repeat",backgroundSize:`${M*r}px`,height:"100%",inset:0,position:"absolute",width:"100%"}}),(0,e.jsx)("div",{onMouseDown:B,onMouseMove:y,style:{height:"100%",inset:0,position:"absolute",transform:`translate(${Y}px, ${C}px) scale(${M})`,transformOrigin:"top left",width:"100%"},children:s}),(0,e.jsx)(a,{padding:u,onZoomClick:P,zoom:M})]})}function a(t){let{zoom:o,padding:r,onZoomClick:a}=t;return(0,e.jsx)("div",{style:{left:5,position:"absolute",right:5+r,top:5},children:(0,e.jsxs)(s.Stack,{children:[(0,e.jsx)(s.Stack.Item,{children:(0,e.jsx)(n.Button,{disabled:o<=.5,icon:"minus",onClick:()=>a("decrease")})}),(0,e.jsx)(s.Stack.Item,{grow:!0,children:(0,e.jsxs)(i.ProgressBar,{maxValue:1.5,minValue:.5,value:o,children:[o,"x"]})}),(0,e.jsx)(s.Stack.Item,{children:(0,e.jsx)(n.Button,{disabled:o>=1.5,icon:"plus",onClick:()=>a("increase")})})]})})}export{r as InfinitePlane};
@@ -87,9 +87,7 @@ declare function LabeledListDivider(props: LabeledListDividerProps): import("rea
87
87
  * - [View documentation on tgui core](https://tgstation.github.io/tgui-core/?path=/docs/components-labeledlist--docs)
88
88
  */
89
89
  export declare namespace LabeledList {
90
- /**
91
- * Adds some empty space between LabeledList items.
92
- */
90
+ /** Adds some empty space between LabeledList items. */
93
91
  const Divider: typeof LabeledListDivider;
94
92
  const Item: typeof LabeledListItem;
95
93
  }
@@ -1,11 +1,11 @@
1
1
  import type { KeyboardEvent } from 'react';
2
2
  import type { BoxProps } from './Box';
3
- export type ModalProps = BoxProps & Partial<{
3
+ export type ModalProps = Partial<{
4
4
  /** Fires once the enter key is pressed */
5
5
  onEnter: (e: KeyboardEvent<HTMLInputElement>) => void;
6
6
  /** Fires once the escape key is pressed */
7
7
  onEscape: (e: KeyboardEvent<HTMLInputElement>) => void;
8
- }>;
8
+ }> & BoxProps;
9
9
  /**
10
10
  * ## Modal
11
11
  *
@@ -1,7 +1,7 @@
1
1
  import { type BoxProps } from './Box';
2
2
  type Props = ExclusiveProps & BoxProps;
3
3
  /** You MUST use only one or none */
4
- type NoticeType = 'info' | 'success' | 'warning' | 'danger';
4
+ type NoticeType = 'info' | 'success' | 'danger';
5
5
  type None = {
6
6
  [K in NoticeType]?: undefined;
7
7
  };
@@ -11,9 +11,6 @@ type ExclusiveProps = None | (Omit<None, 'info'> & {
11
11
  }) | (Omit<None, 'success'> & {
12
12
  /** Green notice */
13
13
  success: boolean;
14
- }) | (Omit<None, 'warning'> & {
15
- /** Orange notice */
16
- warning: boolean;
17
14
  }) | (Omit<None, 'danger'> & {
18
15
  /** Red notice */
19
16
  danger: boolean;
@@ -1 +1 @@
1
- import*as o from"react/jsx-runtime";import*as e from"../common/react.js";import*as t from"./Box.js";function c(c){let{className:s,color:r,info:i,success:x,warning:m,danger:a,...B}=c;return(0,o.jsx)(t.Box,{className:(0,e.classes)(["NoticeBox",r&&`NoticeBox--color--${r}`,i&&"NoticeBox--type--info",x&&"NoticeBox--type--success",a&&"NoticeBox--type--danger",s]),...B})}export{c as NoticeBox};
1
+ import*as o from"react/jsx-runtime";import*as e from"../common/react.js";import*as t from"./Box.js";function c(c){let{className:s,color:r,info:i,success:x,danger:m,...a}=c;return(0,o.jsx)(t.Box,{className:(0,e.classes)(["NoticeBox",r&&`NoticeBox--color--${r}`,i&&"NoticeBox--type--info",x&&"NoticeBox--type--success",m&&"NoticeBox--type--danger",s]),...a})}export{c as NoticeBox};
@@ -6,7 +6,8 @@ type Props = {
6
6
  /** Whether the popper is open */
7
7
  isOpen: boolean;
8
8
  } & Partial<{
9
- /** Base z-index of the popper div
9
+ /**
10
+ * Base z-index of the popper div
10
11
  * @default 5
11
12
  */
12
13
  baseZIndex: number;
@@ -1,12 +1,34 @@
1
- import { Component, type PropsWithChildren } from 'react';
1
+ import { type ReactElement } from 'react';
2
2
  type Props = {
3
+ /** The excluded element that CAN be clicked */
4
+ children: ReactElement<HTMLElement>;
5
+ /** Callback that fires whenever the user clicks something else */
3
6
  onOutsideClick: () => void;
4
- } & PropsWithChildren;
5
- export declare class TrackOutsideClicks extends Component<Props> {
6
- ref: import("react").RefObject<HTMLDivElement | null>;
7
- constructor(props: any);
8
- componentWillUnmount(): void;
9
- handleOutsideClick(event: MouseEvent): void;
10
- render(): import("react/jsx-runtime").JSX.Element;
11
- }
7
+ };
8
+ /**
9
+ * ## TrackOutsideClicks
10
+ *
11
+ * Allows you to track when the user clicks outside of a specific element.
12
+ *
13
+ * Example:
14
+ *
15
+ * ```tsx
16
+ * import { TrackOutsideClicks } from 'tgui-core/components';
17
+ *
18
+ * function MyComponent() {
19
+ * const [isOpen, setIsOpen] = useState(false);
20
+ *
21
+ * return (
22
+ * <TrackOutsideClicks onOutsideClick={() => setIsOpen(false)}>
23
+ * <div>
24
+ * Hello world!
25
+ * </div>
26
+ * </TrackOutsideClicks>
27
+ * );
28
+ * }
29
+ * ```
30
+ *
31
+ * - [View documentation on tgui core](https://tgstation.github.io/tgui-core/?path=/docs/components-trackoutsideclicks--docs)
32
+ */
33
+ export declare function TrackOutsideClicks(props: Props): import("react/jsx-runtime").JSX.Element;
12
34
  export {};
@@ -1 +1 @@
1
- import*as e from"react/jsx-runtime";import*as t from"react";class i extends t.Component{ref=(0,t.createRef)();constructor(e){super(e),this.handleOutsideClick=this.handleOutsideClick.bind(this),document.addEventListener("click",this.handleOutsideClick)}componentWillUnmount(){document.removeEventListener("click",this.handleOutsideClick)}handleOutsideClick(e){e.target instanceof Node&&this.ref.current&&!this.ref.current.contains(e.target)&&this.props.onOutsideClick()}render(){return(0,e.jsx)("div",{ref:this.ref,children:this.props.children})}}export{i as TrackOutsideClicks};
1
+ import*as e from"react/jsx-runtime";import*as t from"react";function r(r){let{children:n,onOutsideClick:c}=r,i=(0,t.createRef)();function o(e){e.target instanceof Node&&i.current&&!i.current.contains(e.target)&&c()}return(0,t.useEffect)(()=>(document.addEventListener("click",o),()=>{document.removeEventListener("click",o)}),[]),(0,e.jsx)("div",{ref:i,style:{userSelect:"none"},children:n})}export{r as TrackOutsideClicks};
package/package.json CHANGED
@@ -6,22 +6,23 @@
6
6
  },
7
7
  "description": "TGUI core component library",
8
8
  "devDependencies": {
9
- "@biomejs/biome": "2.0.0-beta.2",
10
- "@rsbuild/core": "^1.3.18",
9
+ "@biomejs/biome": "^2.0.0-beta.5",
10
+ "@rsbuild/core": "^1.3.20",
11
11
  "@rsbuild/plugin-react": "^1.3.1",
12
12
  "@rsbuild/plugin-sass": "^1.3.1",
13
- "@rslib/core": "^0.6.9",
13
+ "@rslib/core": "^0.7.1",
14
14
  "@storybook/addon-console": "^3.0.0",
15
- "@storybook/addon-essentials": "^8.6.12",
16
- "@storybook/blocks": "^8.6.12",
17
- "@storybook/react": "^8.6.12",
18
- "@storybook/theming": "^8.6.12",
19
- "@types/node": "^22.15.17",
20
- "@types/react": "^19.1.3",
21
- "@types/react-dom": "^19.1.3",
15
+ "@storybook/addon-essentials": "^8.6.14",
16
+ "@storybook/blocks": "^8.6.14",
17
+ "@storybook/react": "^8.6.14",
18
+ "@storybook/test": "^8.6.14",
19
+ "@storybook/theming": "^8.6.14",
20
+ "@types/bun": "^1.2.13",
21
+ "@types/react": "^19.1.4",
22
+ "@types/react-dom": "^19.1.5",
22
23
  "prettier": "^3.5.3",
23
- "sass": "^1.81.0",
24
- "storybook": "^8.6.12",
24
+ "sass": "^1.89.0",
25
+ "storybook": "^8.6.14",
25
26
  "storybook-addon-sass-postcss": "^0.3.2",
26
27
  "storybook-react-rsbuild": "^1.0.1",
27
28
  "typescript": "^5.8.3"
@@ -54,7 +55,7 @@
54
55
  ],
55
56
  "license": "MIT",
56
57
  "name": "tgui-core",
57
- "packageManager": "pnpm@10.10.0",
58
+ "packageManager": "bun@1.2.13",
58
59
  "peerDependencies": {
59
60
  "react": "^19.1.0",
60
61
  "react-dom": "^19.1.0"
@@ -64,13 +65,13 @@
64
65
  "url": "https://github.com/tgstation/tgui-core.git"
65
66
  },
66
67
  "scripts": {
67
- "build": "rslib build",
68
+ "build-rslib": "rslib build",
68
69
  "build-storybook": "storybook build",
69
70
  "lint": "biome check lib",
70
71
  "lint:fix": "prettier . --write && biome check . --fix",
71
72
  "storybook": "storybook dev -p 6006",
72
- "test": "node --experimental-strip-types --experimental-test-coverage --test ./tests/*.test.ts"
73
+ "test": "bun test"
73
74
  },
74
75
  "type": "module",
75
- "version": "3.2.0"
76
+ "version": "4.0.1"
76
77
  }