From 6548bbb755526fb7968bbda0926af88e01566ae0 Mon Sep 17 00:00:00 2001
From: Dmitry <58977309+Mon4ik@users.noreply.github.com>
Date: Wed, 23 Apr 2025 19:45:32 +0300
Subject: [PATCH 01/28] rewrite: started porting from Typescript to Luau
- Frame
- Builders (more efficient, than `ExpandableComponent`)
But no Typescript (yet)
---
.gitignore | 12 +-
.neoconf.json | 7 +
.npmrc | 1 -
Makefile | 24 +
README.md | 106 ++-
aftman.toml | 9 +-
default.project.json | 6 +
package.json | 45 --
pnpm-lock.yaml | 710 --------------------
src/Builder.luau | 52 ++
src/Builders/FrameBuilder.luau | 10 +
src/Builders/GuiObjectBuilder.luau | 56 ++
src/Builders/TextBuilder.luau | 39 ++
src/Components/Frame.luau | 3 +
src/Utils.luau | 65 ++
src/components/Button.ts | 14 -
src/components/CanvasGroup.ts | 30 -
src/components/Frame.ts | 3 -
src/components/GridLayout.tsx | 40 --
src/components/Image.ts | 28 -
src/components/ListLayout.tsx | 38 --
src/components/ScrollingFrame.ts | 76 ---
src/components/Text.ts | 5 -
src/components/TextBox.ts | 24 -
src/helpers/BaseComponent.tsx | 152 -----
src/helpers/CalculateAspectRatio.ts | 26 -
src/helpers/ExpandableComponent.ts | 109 ---
src/helpers/Gradient.tsx | 64 --
src/helpers/TextComponent.ts | 62 --
src/helpers/index.ts | 10 -
src/index.ts | 13 -
src/init.luau | 5 +
src/stories/App.ts | 14 -
src/stories/Frame.story.luau | 39 ++
src/stories/basics/1_helloworld.story.tsx | 26 -
src/stories/basics/2_padding.story.tsx | 47 --
src/stories/basics/3_cornerRadius.story.tsx | 20 -
src/stories/basics/5_flexItem.story.tsx | 41 --
src/stories/examples/sidebar.story.tsx | 67 --
src/stories/examples/textBox.story.tsx | 36 -
src/stories/tests/bindings.story.tsx | 62 --
src/stories/tests/context.story.tsx | 57 --
src/stories/tests/gradients.story.tsx | 116 ----
src/stories/tests/refs.story.tsx | 42 --
src/stories/utils.ts | 66 --
src/utils.ts | 131 ----
story.project.json | 39 +-
stylua.toml | 3 +
tsconfig.json | 27 -
wally.lock | 98 +++
wally.toml | 12 +
51 files changed, 486 insertions(+), 2301 deletions(-)
create mode 100644 .neoconf.json
delete mode 100644 .npmrc
create mode 100644 Makefile
create mode 100644 default.project.json
delete mode 100644 package.json
delete mode 100644 pnpm-lock.yaml
create mode 100644 src/Builder.luau
create mode 100644 src/Builders/FrameBuilder.luau
create mode 100644 src/Builders/GuiObjectBuilder.luau
create mode 100644 src/Builders/TextBuilder.luau
create mode 100644 src/Components/Frame.luau
create mode 100644 src/Utils.luau
delete mode 100644 src/components/Button.ts
delete mode 100644 src/components/CanvasGroup.ts
delete mode 100644 src/components/Frame.ts
delete mode 100644 src/components/GridLayout.tsx
delete mode 100644 src/components/Image.ts
delete mode 100644 src/components/ListLayout.tsx
delete mode 100644 src/components/ScrollingFrame.ts
delete mode 100644 src/components/Text.ts
delete mode 100644 src/components/TextBox.ts
delete mode 100644 src/helpers/BaseComponent.tsx
delete mode 100644 src/helpers/CalculateAspectRatio.ts
delete mode 100644 src/helpers/ExpandableComponent.ts
delete mode 100644 src/helpers/Gradient.tsx
delete mode 100644 src/helpers/TextComponent.ts
delete mode 100644 src/helpers/index.ts
delete mode 100644 src/index.ts
create mode 100644 src/init.luau
delete mode 100644 src/stories/App.ts
create mode 100644 src/stories/Frame.story.luau
delete mode 100644 src/stories/basics/1_helloworld.story.tsx
delete mode 100644 src/stories/basics/2_padding.story.tsx
delete mode 100644 src/stories/basics/3_cornerRadius.story.tsx
delete mode 100644 src/stories/basics/5_flexItem.story.tsx
delete mode 100644 src/stories/examples/sidebar.story.tsx
delete mode 100644 src/stories/examples/textBox.story.tsx
delete mode 100644 src/stories/tests/bindings.story.tsx
delete mode 100644 src/stories/tests/context.story.tsx
delete mode 100644 src/stories/tests/gradients.story.tsx
delete mode 100644 src/stories/tests/refs.story.tsx
delete mode 100644 src/stories/utils.ts
delete mode 100644 src/utils.ts
create mode 100644 stylua.toml
delete mode 100644 tsconfig.json
create mode 100644 wally.lock
create mode 100644 wally.toml
diff --git a/.gitignore b/.gitignore
index f484755..356fdf8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,11 +1,7 @@
-/node_modules
-/out
-/include
+Packages/
+DevPackages/
+sourcemap.json
.DS_Store
-*.tsbuildinfo
*.log
-
-# development tarballs
-rbxts-better-react-components-*.tgz
-package.tgz
\ No newline at end of file
+*.old
diff --git a/.neoconf.json b/.neoconf.json
new file mode 100644
index 0000000..fa51a35
--- /dev/null
+++ b/.neoconf.json
@@ -0,0 +1,7 @@
+{
+ "luau-lsp": {
+ "sourcemap": {
+ "autogenerate": false
+ }
+ }
+}
diff --git a/.npmrc b/.npmrc
deleted file mode 100644
index d67f374..0000000
--- a/.npmrc
+++ /dev/null
@@ -1 +0,0 @@
-node-linker=hoisted
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..00e1ccd
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,24 @@
+install: install-dependencies patch-sourcemap
+serve:
+ rojo serve story.project.json
+
+#build: install-dependencies
+# rojo build
+
+# intermediate scripts
+
+install-dependencies: aftman.toml wally.toml wally.lock
+ aftman install
+ wally install
+
+patch-sourcemap: sourcemap.json Packages/* DevPackages/
+ wally-package-types --sourcemap dev-sourcemap.json Packages/
+ wally-package-types --sourcemap dev-sourcemap.json DevPackages/
+
+# target files/dirs:
+
+Packages: install-dependencies
+
+sourcemap.json: src/* story.project.json
+ rojo sourcemap story.project.json --output sourcemap.json
+
diff --git a/README.md b/README.md
index 0164bd5..20b326a 100644
--- a/README.md
+++ b/README.md
@@ -1,83 +1,61 @@
-# Better React Components
+# better-react-components
-
-
+Roblox's UI elements, but with builtin modifiers
-Roblox's ui elements, with builtin modifiers
+> ![NOTE]
+>
+> Currently, I am rewriting this library from Typescript to Lua.
+>
+> I'll still publish this library to NPM.
-Also see **[introduction](docs/1_Introduction.md)**
+## Setup guide
-## Example
+```
+Dear Future Me.
-
+Please, publish and write here, how to install this library from wally or npm
-
- better-react-components code
+Respectfully,
+ Past Me
+```
- ```
-
-
+1. Install Aftman and Make
+2. Run:
+ ```
+ make install # installs all toolchain, dependencies and patch sourcemap.json
+ make serve # starts rojo server
+ make build # builds .rbxmx (NOT IMPLEMENTED)
-
-
-
- ;
- ```
-
+ make patch-sourcemaps # patches sourcemaps. needed after installing wally dependencies
+ ```
-
-## Support
-
-### TODO
-
-- [ ] Upgrade ESLint to `9.*.*` version
-- [ ] Better documentation
+## Supported Components/Modifiers
### Components
-- [X] Frame
-- [X] ScrollableFrame
-- [X] Button
+- [ ] Frame
+- [ ] ScrollableFrame
+- [ ] Button
- [ ] ImageButton
-- [X] Image
-- [X] Text
-- [X] TextBox
-- [X] CanvasGroup
+- [ ] Image
+- [ ] Text
+- [ ] TextBox
+- [ ] CanvasGroup
### Modifiers
-- [X] UIAspectRatioConstraint
-- [X] UICorner
-- [X] UIGradient
-- [X] UIGridLayout [(see GridLayout)](src/components/GridLayout.tsx)
-- [X] UIListLayout [(see ListLayout)](src/components/ListLayout.tsx)
-- [X] UIFlexLayout [(see ListLayout)](src/components/ListLayout.tsx)
-- [X] UIPadding
+- [ ] UIAspectRatioConstraint
+- [ ] UICorner
+- [ ] UIGradient
+- [ ] UIGridLayout
+- [ ] UIListLayout
+- [ ] UIFlexLayout
+- [ ] UIPadding
- [ ] UIPageLayout
-- [X] UIScale
-- [X] UISizeConstraint
-- [X] UIStroke
+- [ ] UIScale
+- [ ] UISizeConstraint
+- [ ] UIStroke
- [ ] UITableLayout
-- [X] UITextSizeConstraint
-
-### Custom Modifiers
-
-- ~~[ ] FlowLayout [(view)](https://devforum.roblox.com/t/flow-flexbox-layout-for-lua/2614394)~~ (Removed due release of flex features to ListLayout. [Devforum](https://devforum.roblox.com/t/flex-features-for-uilistlayout-client-release/3096190) )
+- [ ] UITextSizeConstraint
diff --git a/aftman.toml b/aftman.toml
index e989d3b..74c521c 100644
--- a/aftman.toml
+++ b/aftman.toml
@@ -1,7 +1,4 @@
-# This file lists tools managed by Aftman, a cross-platform toolchain manager.
-# For more information, see https://github.com/LPGhatguy/aftman
-
-# To add a new tool, add an entry to this table.
[tools]
-rojo = "rojo-rbx/rojo@7.4.1"
-# rojo = "rojo-rbx/rojo@6.2.0"
\ No newline at end of file
+rojo = "rojo-rbx/rojo@7.4.4"
+wally = "UpliftGames/wally@0.3.2"
+wally-package-types = "JohnnyMorganz/wally-package-types@1.4.2"
diff --git a/default.project.json b/default.project.json
new file mode 100644
index 0000000..8a94842
--- /dev/null
+++ b/default.project.json
@@ -0,0 +1,6 @@
+{
+ "name": "better-react-components",
+ "tree": {
+ "$path": "src"
+ }
+}
diff --git a/package.json b/package.json
deleted file mode 100644
index ef9f84a..0000000
--- a/package.json
+++ /dev/null
@@ -1,45 +0,0 @@
-{
- "name": "@rbxts/better-react-components",
- "version": "2.9.1",
- "license": "MIT",
- "repository": {
- "type": "git",
- "url": "git+https://github.com/idkncc/better-react-components.git"
- },
- "bugs": {
- "url": "https://github.com/idkncc/better-react-components/issues"
- },
- "homepage": "https://github.com/idkncc/better-react-components#readme",
- "main": "out/init.lua",
- "typings": "out/index.d.ts",
- "files": [
- "out",
- "!out/*.tsbuildinfo",
- "!out/stories/**/*"
- ],
- "scripts": {
- "build": "pnpm clean && rbxtsc",
- "dev": "rbxtsc -w --type game --rojo story.project.json",
- "dev-serve": "rojo serve story.project.json",
- "lint": "eslint src",
- "clean": "rimraf out/"
- },
- "devDependencies": {
- "@rbxts/compiler-types": "3.0.0-types.0",
- "@rbxts/types": "^1.0.813",
- "rimraf": "^6.0.1",
- "roblox-ts": "3.0.0",
- "typescript": "^5.6.3"
- },
- "dependencies": {
- "@rbxts/object-utils": "^1.0.4",
- "@rbxts/pretty-react-hooks": "^0.6.0",
- "@rbxts/react": "^17.2.1",
- "@rbxts/react-roblox": "^17.2.1",
- "@rbxts/ripple": "^0.9.1",
- "@rbxts/services": "^1.5.5"
- },
- "publishConfig": {
- "access": "public"
- }
-}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
deleted file mode 100644
index 73e6307..0000000
--- a/pnpm-lock.yaml
+++ /dev/null
@@ -1,710 +0,0 @@
-lockfileVersion: '9.0'
-
-settings:
- autoInstallPeers: true
- excludeLinksFromLockfile: false
-
-importers:
-
- .:
- dependencies:
- '@rbxts/object-utils':
- specifier: ^1.0.4
- version: 1.0.4
- '@rbxts/pretty-react-hooks':
- specifier: ^0.6.0
- version: 0.6.0
- '@rbxts/react':
- specifier: ^17.2.1
- version: 17.2.1
- '@rbxts/react-roblox':
- specifier: ^17.2.1
- version: 17.2.1
- '@rbxts/ripple':
- specifier: ^0.9.1
- version: 0.9.1
- '@rbxts/services':
- specifier: ^1.5.5
- version: 1.5.5
- devDependencies:
- '@rbxts/compiler-types':
- specifier: 3.0.0-types.0
- version: 3.0.0-types.0
- '@rbxts/types':
- specifier: ^1.0.813
- version: 1.0.813
- rimraf:
- specifier: ^6.0.1
- version: 6.0.1
- roblox-ts:
- specifier: 3.0.0
- version: 3.0.0
- typescript:
- specifier: ^5.6.3
- version: 5.6.3
-
-packages:
-
- '@isaacs/cliui@8.0.2':
- resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
- engines: {node: '>=12'}
-
- '@rbxts/compiler-types@3.0.0-types.0':
- resolution: {integrity: sha512-VGOHJPoL7+56NTatMGqQj3K7xWuzEV+aP4QD5vZiHu+bcff3kiTmtoadaF6NkJrmwfFAvbsd4Dg764ZjWNceag==}
-
- '@rbxts/object-utils@1.0.4':
- resolution: {integrity: sha512-dLLhf022ipV+9i910sOE7kl9losKHoon0WgeerHqVMQA5EYsLUsVT2AxhJuhk8MiDn5oJ2GiFofE/LadY9TpJQ==}
-
- '@rbxts/pretty-react-hooks@0.6.0':
- resolution: {integrity: sha512-KPaJ9xvbE6UJ1ECe4bwHBM3iqQ+IYcn0QfHjyRNZgADrz6/An+2zpxydY4ACjawAqRYybV7jwd6MqCJJiXHjOA==}
-
- '@rbxts/react-roblox@17.2.1':
- resolution: {integrity: sha512-qKCz63iMl6fFq2SUXoMG6paAW8TGxsEyUwoRk6bojg7b3NzBqYMz5/eRcJsbPqMjwR56PWBhCOH3fdf4sOcFbw==}
-
- '@rbxts/react-vendor@17.2.1':
- resolution: {integrity: sha512-7DxFweCbhhso4M4tl1pO7Kil9SZrvOl1SoZ4lnwUfoxdHvSmWgeKgaUqd+ZS3/u1E8kRraqGQ56Q8zjUEEUzlA==}
-
- '@rbxts/react@17.2.1':
- resolution: {integrity: sha512-iu0RsVvfHroI7l+QXjwE0FiWV2rXoKMxuznDZ8vnx2BsFqrPnCqFjXuNeGYZwibibZC6jbyq7uKl+/8cz7XlsA==}
-
- '@rbxts/ripple@0.9.1':
- resolution: {integrity: sha512-gLjKYy+mJO67NoN/9d7/8kBy6+SNG1/09GNNnh89DYWT5iHYdxC0/XKbKrKZpx7Fcsz5iY9Sl6vOvSnFwFbQuw==}
-
- '@rbxts/services@1.5.5':
- resolution: {integrity: sha512-Hu7QH2ecefS60zpakKG3T2vgABydoOJqpSG7nXr59wFAbPk/cA+OcsntYPHUWyHAat0VFGZ5jNZLTLdiqfssvg==}
-
- '@rbxts/set-timeout@1.1.2':
- resolution: {integrity: sha512-P/A0IiH9wuZdSJYr4Us0MDFm61nvIFR0acfKFHLkcOsgvIgELC90Up9ugiSsaMEHRIcIcO5UjE39LuS3xTzQHw==}
-
- '@rbxts/types@1.0.813':
- resolution: {integrity: sha512-Qpsmqnl+TNdl5AYqKFkYHyUrv652r30qK6A3GObOyDz+cvn8i+HE61mO021oq0nu1FcA4pMHbYqLSbv2CMF9Ig==}
-
- '@roblox-ts/luau-ast@2.0.0':
- resolution: {integrity: sha512-cmMi093IdwBOLVxwuordhM8AmtbyTIyRpsTbB0D/JauidW4SXsQRQowSwWjHo4QP0DRJBXvOIlxtqEQi50uNzQ==}
-
- '@roblox-ts/path-translator@1.1.0':
- resolution: {integrity: sha512-D0akTmnNYqBw+ZIek5JxocT3BjmbgGOuOy0x1nIIxHBPNLGCpzseToY8jyYs/0mlvnN2xnSP/k8Tv+jvGOQSwQ==}
-
- '@roblox-ts/rojo-resolver@1.1.0':
- resolution: {integrity: sha512-QmvVryu1EeME+3QUoG5j/gHGJoJUaffCgZ92mhlG7cJSd1uyhgpY4CNWriZAwZJYkTlzd5Htkpn+18yDFbOFXA==}
-
- ajv@8.17.1:
- resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==}
-
- ansi-regex@5.0.1:
- resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
- engines: {node: '>=8'}
-
- ansi-regex@6.1.0:
- resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==}
- engines: {node: '>=12'}
-
- ansi-styles@4.3.0:
- resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
- engines: {node: '>=8'}
-
- ansi-styles@6.2.1:
- resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
- engines: {node: '>=12'}
-
- anymatch@3.1.3:
- resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
- engines: {node: '>= 8'}
-
- balanced-match@1.0.2:
- resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
-
- binary-extensions@2.3.0:
- resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
- engines: {node: '>=8'}
-
- brace-expansion@2.0.1:
- resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
-
- braces@3.0.3:
- resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
- engines: {node: '>=8'}
-
- chokidar@3.6.0:
- resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
- engines: {node: '>= 8.10.0'}
-
- cliui@8.0.1:
- resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
- engines: {node: '>=12'}
-
- color-convert@2.0.1:
- resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
- engines: {node: '>=7.0.0'}
-
- color-name@1.1.4:
- resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
-
- cross-spawn@7.0.3:
- resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
- engines: {node: '>= 8'}
-
- eastasianwidth@0.2.0:
- resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
-
- emoji-regex@8.0.0:
- resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
-
- emoji-regex@9.2.2:
- resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
-
- escalade@3.2.0:
- resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
- engines: {node: '>=6'}
-
- fast-deep-equal@3.1.3:
- resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
-
- fast-uri@3.0.3:
- resolution: {integrity: sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==}
-
- fill-range@7.1.1:
- resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
- engines: {node: '>=8'}
-
- foreground-child@3.3.0:
- resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==}
- engines: {node: '>=14'}
-
- fs-extra@11.2.0:
- resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==}
- engines: {node: '>=14.14'}
-
- fsevents@2.3.3:
- resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
- engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
- os: [darwin]
-
- function-bind@1.1.2:
- resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
-
- get-caller-file@2.0.5:
- resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
- engines: {node: 6.* || 8.* || >= 10.*}
-
- glob-parent@5.1.2:
- resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
- engines: {node: '>= 6'}
-
- glob@11.0.0:
- resolution: {integrity: sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==}
- engines: {node: 20 || >=22}
- hasBin: true
-
- graceful-fs@4.2.11:
- resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
-
- hasown@2.0.2:
- resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
- engines: {node: '>= 0.4'}
-
- is-binary-path@2.1.0:
- resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
- engines: {node: '>=8'}
-
- is-core-module@2.15.1:
- resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==}
- engines: {node: '>= 0.4'}
-
- is-extglob@2.1.1:
- resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
- engines: {node: '>=0.10.0'}
-
- is-fullwidth-code-point@3.0.0:
- resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
- engines: {node: '>=8'}
-
- is-glob@4.0.3:
- resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
- engines: {node: '>=0.10.0'}
-
- is-number@7.0.0:
- resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
- engines: {node: '>=0.12.0'}
-
- isexe@2.0.0:
- resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
-
- jackspeak@4.0.2:
- resolution: {integrity: sha512-bZsjR/iRjl1Nk1UkjGpAzLNfQtzuijhn2g+pbZb98HQ1Gk8vM9hfbxeMBP+M2/UUdwj0RqGG3mlvk2MsAqwvEw==}
- engines: {node: 20 || >=22}
-
- json-schema-traverse@1.0.0:
- resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
-
- jsonfile@6.1.0:
- resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==}
-
- kleur@4.1.5:
- resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==}
- engines: {node: '>=6'}
-
- lru-cache@11.0.1:
- resolution: {integrity: sha512-CgeuL5uom6j/ZVrg7G/+1IXqRY8JXX4Hghfy5YE0EhoYQWvndP1kufu58cmZLNIDKnRhZrXfdS9urVWx98AipQ==}
- engines: {node: 20 || >=22}
-
- minimatch@10.0.1:
- resolution: {integrity: sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==}
- engines: {node: 20 || >=22}
-
- minipass@7.1.2:
- resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
- engines: {node: '>=16 || 14 >=14.17'}
-
- normalize-path@3.0.0:
- resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
- engines: {node: '>=0.10.0'}
-
- package-json-from-dist@1.0.1:
- resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
-
- path-key@3.1.1:
- resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
- engines: {node: '>=8'}
-
- path-parse@1.0.7:
- resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
-
- path-scurry@2.0.0:
- resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==}
- engines: {node: 20 || >=22}
-
- picomatch@2.3.1:
- resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
- engines: {node: '>=8.6'}
-
- readdirp@3.6.0:
- resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
- engines: {node: '>=8.10.0'}
-
- require-directory@2.1.1:
- resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
- engines: {node: '>=0.10.0'}
-
- require-from-string@2.0.2:
- resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
- engines: {node: '>=0.10.0'}
-
- resolve@1.22.8:
- resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==}
- hasBin: true
-
- rimraf@6.0.1:
- resolution: {integrity: sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==}
- engines: {node: 20 || >=22}
- hasBin: true
-
- roblox-ts@3.0.0:
- resolution: {integrity: sha512-hwAC2frIFlLJOtHd6F+5opMEhBgfAMK9z5l1mP+bykLBbMO5cn1q5lIwhhXbeh9Pq07rlhF8uGHlmeRLPd/3AA==}
- hasBin: true
-
- shebang-command@2.0.0:
- resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
- engines: {node: '>=8'}
-
- shebang-regex@3.0.0:
- resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
- engines: {node: '>=8'}
-
- signal-exit@4.1.0:
- resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
- engines: {node: '>=14'}
-
- string-width@4.2.3:
- resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
- engines: {node: '>=8'}
-
- string-width@5.1.2:
- resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
- engines: {node: '>=12'}
-
- strip-ansi@6.0.1:
- resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
- engines: {node: '>=8'}
-
- strip-ansi@7.1.0:
- resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
- engines: {node: '>=12'}
-
- supports-preserve-symlinks-flag@1.0.0:
- resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
- engines: {node: '>= 0.4'}
-
- to-regex-range@5.0.1:
- resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
- engines: {node: '>=8.0'}
-
- typescript@5.5.3:
- resolution: {integrity: sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==}
- engines: {node: '>=14.17'}
- hasBin: true
-
- typescript@5.6.3:
- resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==}
- engines: {node: '>=14.17'}
- hasBin: true
-
- universalify@2.0.1:
- resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
- engines: {node: '>= 10.0.0'}
-
- which@2.0.2:
- resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
- engines: {node: '>= 8'}
- hasBin: true
-
- wrap-ansi@7.0.0:
- resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
- engines: {node: '>=10'}
-
- wrap-ansi@8.1.0:
- resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
- engines: {node: '>=12'}
-
- y18n@5.0.8:
- resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
- engines: {node: '>=10'}
-
- yargs-parser@21.1.1:
- resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
- engines: {node: '>=12'}
-
- yargs@17.7.2:
- resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
- engines: {node: '>=12'}
-
-snapshots:
-
- '@isaacs/cliui@8.0.2':
- dependencies:
- string-width: 5.1.2
- string-width-cjs: string-width@4.2.3
- strip-ansi: 7.1.0
- strip-ansi-cjs: strip-ansi@6.0.1
- wrap-ansi: 8.1.0
- wrap-ansi-cjs: wrap-ansi@7.0.0
-
- '@rbxts/compiler-types@3.0.0-types.0': {}
-
- '@rbxts/object-utils@1.0.4': {}
-
- '@rbxts/pretty-react-hooks@0.6.0':
- dependencies:
- '@rbxts/react': 17.2.1
- '@rbxts/react-roblox': 17.2.1
- '@rbxts/ripple': 0.9.1
- '@rbxts/services': 1.5.5
- '@rbxts/set-timeout': 1.1.2
-
- '@rbxts/react-roblox@17.2.1':
- dependencies:
- '@rbxts/react': 17.2.1
- '@rbxts/react-vendor': 17.2.1
-
- '@rbxts/react-vendor@17.2.1': {}
-
- '@rbxts/react@17.2.1':
- dependencies:
- '@rbxts/react-vendor': 17.2.1
-
- '@rbxts/ripple@0.9.1': {}
-
- '@rbxts/services@1.5.5': {}
-
- '@rbxts/set-timeout@1.1.2':
- dependencies:
- '@rbxts/services': 1.5.5
-
- '@rbxts/types@1.0.813': {}
-
- '@roblox-ts/luau-ast@2.0.0': {}
-
- '@roblox-ts/path-translator@1.1.0':
- dependencies:
- ajv: 8.17.1
- fs-extra: 11.2.0
-
- '@roblox-ts/rojo-resolver@1.1.0':
- dependencies:
- ajv: 8.17.1
- fs-extra: 11.2.0
-
- ajv@8.17.1:
- dependencies:
- fast-deep-equal: 3.1.3
- fast-uri: 3.0.3
- json-schema-traverse: 1.0.0
- require-from-string: 2.0.2
-
- ansi-regex@5.0.1: {}
-
- ansi-regex@6.1.0: {}
-
- ansi-styles@4.3.0:
- dependencies:
- color-convert: 2.0.1
-
- ansi-styles@6.2.1: {}
-
- anymatch@3.1.3:
- dependencies:
- normalize-path: 3.0.0
- picomatch: 2.3.1
-
- balanced-match@1.0.2: {}
-
- binary-extensions@2.3.0: {}
-
- brace-expansion@2.0.1:
- dependencies:
- balanced-match: 1.0.2
-
- braces@3.0.3:
- dependencies:
- fill-range: 7.1.1
-
- chokidar@3.6.0:
- dependencies:
- anymatch: 3.1.3
- braces: 3.0.3
- glob-parent: 5.1.2
- is-binary-path: 2.1.0
- is-glob: 4.0.3
- normalize-path: 3.0.0
- readdirp: 3.6.0
- optionalDependencies:
- fsevents: 2.3.3
-
- cliui@8.0.1:
- dependencies:
- string-width: 4.2.3
- strip-ansi: 6.0.1
- wrap-ansi: 7.0.0
-
- color-convert@2.0.1:
- dependencies:
- color-name: 1.1.4
-
- color-name@1.1.4: {}
-
- cross-spawn@7.0.3:
- dependencies:
- path-key: 3.1.1
- shebang-command: 2.0.0
- which: 2.0.2
-
- eastasianwidth@0.2.0: {}
-
- emoji-regex@8.0.0: {}
-
- emoji-regex@9.2.2: {}
-
- escalade@3.2.0: {}
-
- fast-deep-equal@3.1.3: {}
-
- fast-uri@3.0.3: {}
-
- fill-range@7.1.1:
- dependencies:
- to-regex-range: 5.0.1
-
- foreground-child@3.3.0:
- dependencies:
- cross-spawn: 7.0.3
- signal-exit: 4.1.0
-
- fs-extra@11.2.0:
- dependencies:
- graceful-fs: 4.2.11
- jsonfile: 6.1.0
- universalify: 2.0.1
-
- fsevents@2.3.3:
- optional: true
-
- function-bind@1.1.2: {}
-
- get-caller-file@2.0.5: {}
-
- glob-parent@5.1.2:
- dependencies:
- is-glob: 4.0.3
-
- glob@11.0.0:
- dependencies:
- foreground-child: 3.3.0
- jackspeak: 4.0.2
- minimatch: 10.0.1
- minipass: 7.1.2
- package-json-from-dist: 1.0.1
- path-scurry: 2.0.0
-
- graceful-fs@4.2.11: {}
-
- hasown@2.0.2:
- dependencies:
- function-bind: 1.1.2
-
- is-binary-path@2.1.0:
- dependencies:
- binary-extensions: 2.3.0
-
- is-core-module@2.15.1:
- dependencies:
- hasown: 2.0.2
-
- is-extglob@2.1.1: {}
-
- is-fullwidth-code-point@3.0.0: {}
-
- is-glob@4.0.3:
- dependencies:
- is-extglob: 2.1.1
-
- is-number@7.0.0: {}
-
- isexe@2.0.0: {}
-
- jackspeak@4.0.2:
- dependencies:
- '@isaacs/cliui': 8.0.2
-
- json-schema-traverse@1.0.0: {}
-
- jsonfile@6.1.0:
- dependencies:
- universalify: 2.0.1
- optionalDependencies:
- graceful-fs: 4.2.11
-
- kleur@4.1.5: {}
-
- lru-cache@11.0.1: {}
-
- minimatch@10.0.1:
- dependencies:
- brace-expansion: 2.0.1
-
- minipass@7.1.2: {}
-
- normalize-path@3.0.0: {}
-
- package-json-from-dist@1.0.1: {}
-
- path-key@3.1.1: {}
-
- path-parse@1.0.7: {}
-
- path-scurry@2.0.0:
- dependencies:
- lru-cache: 11.0.1
- minipass: 7.1.2
-
- picomatch@2.3.1: {}
-
- readdirp@3.6.0:
- dependencies:
- picomatch: 2.3.1
-
- require-directory@2.1.1: {}
-
- require-from-string@2.0.2: {}
-
- resolve@1.22.8:
- dependencies:
- is-core-module: 2.15.1
- path-parse: 1.0.7
- supports-preserve-symlinks-flag: 1.0.0
-
- rimraf@6.0.1:
- dependencies:
- glob: 11.0.0
- package-json-from-dist: 1.0.1
-
- roblox-ts@3.0.0:
- dependencies:
- '@roblox-ts/luau-ast': 2.0.0
- '@roblox-ts/path-translator': 1.1.0
- '@roblox-ts/rojo-resolver': 1.1.0
- chokidar: 3.6.0
- fs-extra: 11.2.0
- kleur: 4.1.5
- resolve: 1.22.8
- typescript: 5.5.3
- yargs: 17.7.2
-
- shebang-command@2.0.0:
- dependencies:
- shebang-regex: 3.0.0
-
- shebang-regex@3.0.0: {}
-
- signal-exit@4.1.0: {}
-
- string-width@4.2.3:
- dependencies:
- emoji-regex: 8.0.0
- is-fullwidth-code-point: 3.0.0
- strip-ansi: 6.0.1
-
- string-width@5.1.2:
- dependencies:
- eastasianwidth: 0.2.0
- emoji-regex: 9.2.2
- strip-ansi: 7.1.0
-
- strip-ansi@6.0.1:
- dependencies:
- ansi-regex: 5.0.1
-
- strip-ansi@7.1.0:
- dependencies:
- ansi-regex: 6.1.0
-
- supports-preserve-symlinks-flag@1.0.0: {}
-
- to-regex-range@5.0.1:
- dependencies:
- is-number: 7.0.0
-
- typescript@5.5.3: {}
-
- typescript@5.6.3: {}
-
- universalify@2.0.1: {}
-
- which@2.0.2:
- dependencies:
- isexe: 2.0.0
-
- wrap-ansi@7.0.0:
- dependencies:
- ansi-styles: 4.3.0
- string-width: 4.2.3
- strip-ansi: 6.0.1
-
- wrap-ansi@8.1.0:
- dependencies:
- ansi-styles: 6.2.1
- string-width: 5.1.2
- strip-ansi: 7.1.0
-
- y18n@5.0.8: {}
-
- yargs-parser@21.1.1: {}
-
- yargs@17.7.2:
- dependencies:
- cliui: 8.0.1
- escalade: 3.2.0
- get-caller-file: 2.0.5
- require-directory: 2.1.1
- string-width: 4.2.3
- y18n: 5.0.8
- yargs-parser: 21.1.1
diff --git a/src/Builder.luau b/src/Builder.luau
new file mode 100644
index 0000000..4a2735b
--- /dev/null
+++ b/src/Builder.luau
@@ -0,0 +1,52 @@
+local Packages = script.Parent.Parent
+
+local React = require(Packages.react)
+local Utils = require(script.Parent.Utils)
+
+local ComponentBuilder = {}
+ComponentBuilder.__index = ComponentBuilder
+
+--- Transformer is a function, that transforms user-friendly props to component props and children nodes
+export type Transformer
= (props: P) -> (OP, { React.ReactNode })
+
+export type ComponentBuilderData
= {
+ transformer: Transformer
,
+}
+
+export type ComponentBuilder
= typeof(setmetatable(
+ {} :: ComponentBuilderData
,
+ ComponentBuilder
+))
+
+function ComponentBuilder.new
(transformer: Transformer
): ComponentBuilder
+ local self = {
+ transformer = transformer,
+ }
+
+ return setmetatable(self, ComponentBuilder)
+end
+
+--- Expand
+function ComponentBuilder.expand
(
+ self: ComponentBuilder
,
+ transformer: Transformer
+): ComponentBuilder
+ return ComponentBuilder.new(function(props: P & NP)
+ local rbxProps, rbxChildren = self.transformer(props)
+ local rbxProps2, rbxChildren2 = transformer(props)
+
+ return Utils.Assign(rbxProps, rbxProps2), Utils.Assign(rbxChildren, rbxChildren2)
+ end)
+end
+
+function ComponentBuilder.build
(
+ self: ComponentBuilder
,
+ robloxComponent: string
+): (props: P) -> any
+ return React.forwardRef(function(props: React.ElementProps & P)
+ local outputProps, outputChildren = self.transformer(props)
+
+ return React.createElement(robloxComponent, outputProps, outputChildren, props.children)
+ end)
+end
+return ComponentBuilder
diff --git a/src/Builders/FrameBuilder.luau b/src/Builders/FrameBuilder.luau
new file mode 100644
index 0000000..32a6920
--- /dev/null
+++ b/src/Builders/FrameBuilder.luau
@@ -0,0 +1,10 @@
+local Packages = script.Parent.Parent.Parent
+
+local React = require(Packages.react)
+local ComponentBuilder = require(script.Parent.Parent.Builder)
+local Utils = require(script.Parent.Parent.Utils)
+local GuiObjectBuilder = require(script.Parent.GuiObjectBuilder)
+
+export type FrameProps = {}
+
+return GuiObjectBuilder -- frame doesn't add any new properties, so passthrough
diff --git a/src/Builders/GuiObjectBuilder.luau b/src/Builders/GuiObjectBuilder.luau
new file mode 100644
index 0000000..1919a9c
--- /dev/null
+++ b/src/Builders/GuiObjectBuilder.luau
@@ -0,0 +1,56 @@
+local Packages = script.Parent.Parent.Parent
+
+local React = require(Packages.react)
+local ComponentBuilder = require(script.Parent.Parent.Builder)
+local Utils = require(script.Parent.Parent.Utils)
+
+--- Border settings
+---
+--- NOTE: when building, it uses `UIStroke`, instead of `GuiObject`'s border properties
+export type Border = {
+ BorderColor: Utils.Color?,
+}
+
+export type GuiObjectProps = {
+ AnchorPoint: Utils.AnchorPoint?,
+ AutomaticSize: Enum.AutomaticSize?,
+ BackgroundColor: Utils.Color?,
+ BackgroundTransparency: number?,
+
+ --- Alias for `BackgroundTransparency = 1`
+ NoBackground: boolean?,
+
+ Position: UDim2?,
+ Size: UDim2?,
+
+ SizeConstraint: Enum.SizeConstraint?,
+ Visible: boolean?,
+
+ LayoutOrder: number?,
+ ZIndex: number?,
+
+ Border: Border?,
+}
+
+return ComponentBuilder.new(function(props: GuiObjectProps)
+ return {
+ AnchorPoint = props.AnchorPoint and Utils.ConvertAnchorPoint(props.AnchorPoint),
+ AutomaticSize = props.AutomaticSize,
+
+ BackgroundColor3 = props.BackgroundColor and Utils.ConvertColor(props.BackgroundColor),
+ BackgroundTransparency = props.NoBackground and 1 or props.BackgroundTransparency,
+
+ Position = props.Position,
+ Size = props.Size,
+
+ SizeConstraint = props.SizeConstraint,
+ LayoutOrder = props.LayoutOrder,
+ ZIndex = props.ZIndex,
+ }, {
+ Border = props.border
+ and React.createElement("UIBorder", {
+ Color = props.Border.BorderColor and Utils.ConvertColor(props.Border.BorderColor),
+ Thickness = props.Border.Thickness,
+ }),
+ }
+end)
diff --git a/src/Builders/TextBuilder.luau b/src/Builders/TextBuilder.luau
new file mode 100644
index 0000000..46c178d
--- /dev/null
+++ b/src/Builders/TextBuilder.luau
@@ -0,0 +1,39 @@
+local Packages = script.Parent.Parent.Parent
+
+local React = require(Packages.react)
+local ComponentBuilder = require(script.Parent.Parent.Builder)
+local Utils = require(script.Parent.Parent.Utils)
+local GuiObjectBuilder = require(script.Parent.GuiObjectBuilder)
+
+export type TextProps = {
+ Text: string?,
+
+ Font: Enum.Font?,
+ LineHeight: number?,
+ RichText: boolean?,
+ TextColor: Utils.Color?,
+ TextSize: Utils.TextSize?,
+ TextWrapped: boolean?,
+
+ TextXAlignment: Enum.TextXAlignment?,
+ TextYAlignment: Enum.TextYAlignment?,
+}
+
+--- Builder for text-based objects (`TextLabel`, `TextButton`, etc.)
+return GuiObjectBuilder:expand(function(props: TextProps)
+ return {
+ Text = props.Text,
+
+ FontFace = props.Font,
+ LineHeight = props.LineHeight,
+ RichText = props.RichText,
+ TextColor3 = Utils.ConvertColor(props.TextColor),
+ TextWrapped = props.TextWrapped,
+
+ TextSize = props.TextSize == "auto" and 1 or props.TextSize,
+ TextScaled = props.TextSize == "auto",
+
+ TextXAlignment = props.TextXAlignment,
+ TextYAlignment = props.TextYAlignment,
+ }, {}
+end)
diff --git a/src/Components/Frame.luau b/src/Components/Frame.luau
new file mode 100644
index 0000000..91cdbef
--- /dev/null
+++ b/src/Components/Frame.luau
@@ -0,0 +1,3 @@
+local FrameBuilder = require(script.Parent.Parent.Builders.FrameBuilder)
+
+return FrameBuilder:build("Frame")
diff --git a/src/Utils.luau b/src/Utils.luau
new file mode 100644
index 0000000..08ce8b8
--- /dev/null
+++ b/src/Utils.luau
@@ -0,0 +1,65 @@
+local Utils = {}
+
+--- User-friendly anchor points
+---
+--- center
+--- left | right
+--- | | |
+--- `tl`, `t`, `tr` – top
+--- `ml`, `m`, `mr` – middle
+--- `bl`, `b`, `br` – bottom
+export type AnchorPoint = "tl" | "t" | "tr" | "ml" | "m" | "mr" | "bl" | "b" | "br" | Vector2
+
+--- Color
+---
+--- It's either `Color3` or hexcode of color (e.g. `#FF0000`)
+export type Color = Color3 | string
+
+--- Text Size
+---
+--- `"auto"` enables `TextScaled` property. Otherwise sets TextSize
+export type TextSize = number | "auto"
+
+local AnchorPointMapping = setmetatable({
+ tl = Vector2.new(0, 0),
+ t = Vector2.new(0.5, 0),
+ tr = Vector2.new(1, 0),
+
+ ml = Vector2.new(0, 0.5),
+ m = Vector2.new(0.5, 0.5),
+ mr = Vector2.new(1, 0.5),
+
+ bl = Vector2.new(0, 1),
+ b = Vector2.new(0.5, 1),
+ br = Vector2.new(1, 1),
+}, {
+ __index = function()
+ error("Invalid anchor point.")
+ end,
+})
+
+function Utils.Assign(table1: T1, table2: T2): T1 & T2
+ for k, v in pairs(table2) do
+ table1[k] = v
+ end
+
+ return table1
+end
+
+function Utils.ConvertColor(value: Color3 | string): Color3
+ if typeof(value) == "string" then
+ return Color3.fromHex(value)
+ else
+ return value
+ end
+end
+
+function Utils.ConvertAnchorPoint(value: AnchorPoint): Vector2
+ if typeof(value) == "Vector2" then
+ return value
+ end
+
+ return AnchorPointMapping[value]
+end
+
+return Utils
diff --git a/src/components/Button.ts b/src/components/Button.ts
deleted file mode 100644
index 0d7ca33..0000000
--- a/src/components/Button.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import TextComponent, { TextComponentProps } from "../helpers/TextComponent";
-
-type ButtonProps = TextComponentProps & {
- autoButtonColor: boolean
-}
-
-export const ButtonComponent = TextComponent
- .expand(
- (props) => ({
- AutoButtonColor: props.autoButtonColor,
- }),
- );
-
-export const Button = ButtonComponent.build("textbutton");
diff --git a/src/components/CanvasGroup.ts b/src/components/CanvasGroup.ts
deleted file mode 100644
index 56146cc..0000000
--- a/src/components/CanvasGroup.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-import BaseComponent from "../helpers/BaseComponent";
-import { ColorOrHex, resolveColor3 } from "../utils";
-
-export interface CanvasGroupProps {
- /**
- * Color tint that applies to all descendants.
- *
- * `GroupColor3` property in Roblox
- */
- tintColor?: ColorOrHex,
-
- /**
- * Transparency that applies to all descendants.
- *
- * `GroupTransparency` property in Roblox
- */
- opacity?: number
-}
-
-/**
- * @see https://create.roblox.com/docs/reference/engine/classes/CanvasGroup
- */
-export const CanvasGroup = BaseComponent
- .expand(
- (props) => ({
- GroupColor3: resolveColor3(props.tintColor),
- GroupTransparency: props.opacity
- }),
- )
- .build("canvasgroup");
diff --git a/src/components/Frame.ts b/src/components/Frame.ts
deleted file mode 100644
index 9b8f740..0000000
--- a/src/components/Frame.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-import BaseComponent from "../helpers/BaseComponent";
-
-export const Frame = BaseComponent.build("frame");
diff --git a/src/components/GridLayout.tsx b/src/components/GridLayout.tsx
deleted file mode 100644
index ee3eda6..0000000
--- a/src/components/GridLayout.tsx
+++ /dev/null
@@ -1,40 +0,0 @@
-import React from "@rbxts/react";
-
-import type { BindingVariants } from "../utils";
-
-export type GridLayoutProps = BindingVariants<{
- cellPadding?: UDim2
- cellSize?: UDim2
- cellAspectRatio?: number
- cellAspectType?: Enum.AspectType
- cellAspectAxis?: Enum.DominantAxis
- startCorner?: Enum.StartCorner
- direction?: Enum.FillDirection
- horizontalAlign?: Enum.HorizontalAlignment
- verticalAlign?: Enum.VerticalAlignment,
- sortOrder?: Enum.SortOrder;
-}>
-
-export function GridLayout(props: GridLayoutProps) {
- return (
-
- {props.cellAspectRatio !== undefined
- ?
- : undefined}
-
- );
-}
diff --git a/src/components/Image.ts b/src/components/Image.ts
deleted file mode 100644
index 82e20e0..0000000
--- a/src/components/Image.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import { BaseComponent } from "../helpers";
-
-import { ColorOrHex, resolveColor3 } from "../utils";
-import { mapBinding } from "@rbxts/pretty-react-hooks";
-
-export interface ImageRect {
- offset: Vector2;
- size: Vector2;
-}
-
-export interface ImageProps {
- image?: string,
- imageColor?: ColorOrHex,
- imageTransparency?: number,
- imageRect?: ImageRect
-}
-
-export const ImageComponent = BaseComponent
- .expand((props) => ({
- Image: props.image,
- ImageColor3: resolveColor3(props.imageColor),
- ImageTransparency: props.imageTransparency,
-
- ImageRectOffset: mapBinding(props.imageRect, (rect) => rect?.offset ?? new Vector2()),
- ImageRectSize: mapBinding(props.imageRect, (rect) => rect?.size ?? new Vector2()),
- }));
-
-export const Image = ImageComponent.build("imagelabel");
diff --git a/src/components/ListLayout.tsx b/src/components/ListLayout.tsx
deleted file mode 100644
index 77eeb82..0000000
--- a/src/components/ListLayout.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-import React from "@rbxts/react";
-
-import { BindingVariants, resolveUDim } from "../utils";
-
-export type ListLayoutProps = BindingVariants<{
- padding?: number | UDim
- direction?: Enum.FillDirection
- order?: Enum.SortOrder
- horizontalAlign?: Enum.HorizontalAlignment
- verticalAlign?: Enum.VerticalAlignment
-
-
- flexWrap?: boolean
- flexAlignX?: Enum.UIFlexAlignment
- flexAlignY?: Enum.UIFlexAlignment
- flexAlignItems?: Enum.ItemLineAlignment
-}>
-
-export function ListLayout(props: ListLayoutProps) {
- return (
-
- );
-}
diff --git a/src/components/ScrollingFrame.ts b/src/components/ScrollingFrame.ts
deleted file mode 100644
index e84d9b0..0000000
--- a/src/components/ScrollingFrame.ts
+++ /dev/null
@@ -1,76 +0,0 @@
-import Object from "@rbxts/object-utils";
-import BaseComponent from "../helpers/BaseComponent";
-
-import { resolveColor3 } from "../utils";
-import { getBindingValue, mapBinding } from "@rbxts/pretty-react-hooks";
-
-import type { InstanceAttributes } from "@rbxts/react";
-
-export type ScrollingFrameProps = {
- automaticCanvasSize?: Enum.AutomaticSize
-
- canvasPosition?: Vector2
- canvasSize?: UDim2
-
- direction?: Enum.ScrollingDirection
-
- /* Horizontal Scrollbar inset */
- scrollbarInsetH?: Enum.ScrollBarInset | boolean
-
- /* Vertical Scrollbar inset */
- scrollbarInsetV?: Enum.ScrollBarInset | boolean
-
- scrollbar?: Scrollbar | false
-}
-
-export type Scrollbar = {
- topImage?: string
- midImage?: string
- bottomImage?: string
-
- imageColor?: Color3 | string
- imageTransparency?: number
-}
-
-export const ScrollingFrameComponent = BaseComponent
- .expand(
- (props) => Object.assign(
- {
- AutomaticCanvasSize: props.automaticCanvasSize,
-
- CanvasPosition: props.canvasPosition,
- CanvasSize: props.canvasSize,
-
- HorizontalScrollBarInset: mapBinding(
- props.scrollbarInsetH,
- (scrollbarInsetH) =>
- typeIs(scrollbarInsetH, "boolean") && scrollbarInsetH
- ? Enum.ScrollBarInset.Always
- : (scrollbarInsetH as Enum.ScrollBarInset) || Enum.ScrollBarInset.None,
- ),
- VerticalScrollBarInset: mapBinding(
- props.scrollbarInsetV,
- (scrollbarInsetV) =>
- typeIs(scrollbarInsetV, "boolean") && scrollbarInsetV
- ? Enum.ScrollBarInset.Always
- : (scrollbarInsetV as Enum.ScrollBarInset) || Enum.ScrollBarInset.None,
- ),
-
- ScrollingDirection: props.direction,
- ScrollingEnabled: mapBinding(props.scrollbar, (scrollbar) => !typeIs(scrollbar, "boolean")),
- } as InstanceAttributes,
-
- // scrollbar settings
- {
- TopImage: mapBinding(props.scrollbar, (scrollbar) => scrollbar && scrollbar.topImage),
- MidImage: mapBinding(props.scrollbar, (scrollbar) => scrollbar && scrollbar.midImage),
- BottomImage: mapBinding(props.scrollbar, (scrollbar) => scrollbar && scrollbar.bottomImage),
-
- ScrollBarImageColor3: mapBinding(props.scrollbar, (scrollbar) => scrollbar && getBindingValue(resolveColor3(scrollbar.imageColor))),
- ScrollBarImageTransparency: mapBinding(props.scrollbar, (scrollbar) => scrollbar && scrollbar.imageTransparency),
-
- } as InstanceAttributes,
- ),
- );
-
-export const ScrollingFrame = ScrollingFrameComponent.build("scrollingframe");
diff --git a/src/components/Text.ts b/src/components/Text.ts
deleted file mode 100644
index 77a345d..0000000
--- a/src/components/Text.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import TextComponent, { TextComponentProps } from "../helpers/TextComponent";
-
-export const Text = TextComponent
- .expand>()
- .build("textlabel");
diff --git a/src/components/TextBox.ts b/src/components/TextBox.ts
deleted file mode 100644
index d54784c..0000000
--- a/src/components/TextBox.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import TextComponent, { TextComponentProps } from "../helpers/TextComponent";
-
-import { resolveColor3 } from "../utils";
-
-type TextBoxProps = {
- placeholder?: string
- placeholderColor?: Color3 | string,
-
- textEditable?: boolean,
- clearTextOnFocus?: boolean
-}
-
-export const TextBoxComponent = TextComponent
- .expand & TextBoxProps>(
- (props) => ({
- PlaceholderText: props.placeholder,
- PlaceholderColor3: resolveColor3(props.placeholderColor),
-
- TextEditable: props.textEditable,
- ClearTextOnFocus: props.clearTextOnFocus,
- }),
- );
-
-export const TextBox = TextBoxComponent.build("textbox");
\ No newline at end of file
diff --git a/src/helpers/BaseComponent.tsx b/src/helpers/BaseComponent.tsx
deleted file mode 100644
index 818fb50..0000000
--- a/src/helpers/BaseComponent.tsx
+++ /dev/null
@@ -1,152 +0,0 @@
-import React from "@rbxts/react";
-import ExpandableComponent from "./ExpandableComponent";
-
-import { ColorOrHex, ResolvableAnchorPoint, resolveAnchorPoint, resolveUDim } from "../utils";
-import { getBaseColor, Gradient, GradientElement } from "./Gradient";
-
-import type { InstanceProps } from "@rbxts/react";
-
-export type BaseProps = {
- visible?: boolean,
-
- noBackground?: boolean
- background?: Gradient | ColorOrHex
- backgroundTransparency?: number
- gradientRotation: number
-
- border?: ColorOrHex | Gradient
- borderGradientRotation?: number
- borderMode?: Enum.ApplyStrokeMode
- borderSize?: number
- borderLineJoinMode?: Enum.LineJoinMode
- stroke?: InstanceProps
-
- position?: UDim2
- size?: UDim2,
- anchorPoint?: ResolvableAnchorPoint
- automaticSize?: Enum.AutomaticSize
-
- cornerRadius?: number | UDim
-
- aspectRatio?: number
- aspectType?: Enum.AspectType
- aspectAxis?: Enum.DominantAxis
-
- padding?: number | UDim
- paddingLeft?: number | UDim
- paddingRight?: number | UDim
- paddingTop?: number | UDim
- paddingBottom?: number | UDim
-
- minSize?: Vector2
- maxSize?: Vector2
-
- minTextSize?: number
- maxTextSize?: number
-
- scale?: number,
-
- layoutOrder?: number
- zIndex?: number
- sizeConstraint?: Enum.SizeConstraint
-
- // Flex
- flex?: InstanceProps
- flexMode?: Enum.UIFlexMode
-}
-
-export default new ExpandableComponent()
- .expand(
- // most basic props:
- (userProps) => ({
- Visible: userProps.visible,
-
- BackgroundColor3: getBaseColor(userProps.background),
- BackgroundTransparency: userProps.noBackground ? 1 : (userProps.backgroundTransparency ?? 0),
-
- AutomaticSize: userProps.automaticSize,
-
- Position: userProps.position,
- Size: userProps.size,
- AnchorPoint: resolveAnchorPoint(userProps.anchorPoint ?? new Vector2(0, 0)),
-
- BorderSizePixel: 0, // we use UIStroke instead
-
- LayoutOrder: userProps.layoutOrder,
- ZIndex: userProps.zIndex,
- SizeConstraint: userProps.sizeConstraint,
- }),
-
- // most basic modifiers:
- (userProps) => [
- userProps.cornerRadius !== undefined
- ?
- : undefined,
-
- // Aspect Ratio
- userProps.aspectRatio !== undefined
- ?
- : undefined,
-
- // Stroke (border)
- userProps.stroke !== undefined
- || userProps.border !== undefined || userProps.borderSize !== undefined || userProps.borderLineJoinMode !== undefined
- ? (
-
-
-
- )
- : undefined,
-
- // Padding
- userProps.padding !== undefined
- || userProps.paddingLeft !== undefined || userProps.paddingRight !== undefined
- || userProps.paddingTop !== undefined || userProps.paddingBottom !== undefined
- ?
- : undefined,
-
- // Size constraint
- userProps.minSize !== undefined || userProps.maxSize !== undefined
- ?
- : undefined,
-
- // Text Size constraint
- userProps.minTextSize !== undefined || userProps.maxTextSize !== undefined
- ?
- : undefined,
-
- // Scale
- userProps.scale !== undefined
- ?
- : undefined,
-
- // Flex item
- userProps.flex !== undefined || userProps.flexMode !== undefined
- ?
- : undefined,
-
- ,
- ],
- );
diff --git a/src/helpers/CalculateAspectRatio.ts b/src/helpers/CalculateAspectRatio.ts
deleted file mode 100644
index 59f05d0..0000000
--- a/src/helpers/CalculateAspectRatio.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-/**
- * Pass this function to GuiObject as ref to calculate aspect ratio
- *
- * @example
- * ```tsx
- *
- * ...
- *
- *
- * // In Output (some fraction):
- * // [CALC_ASPECT_RATIO](1): .875
- * ```
- */
-export function calculateAspectRatio(element: unknown) {
- if (typeIs(element, "Instance") && element.IsA("GuiObject")) {
- const sizes = (element as GuiObject).AbsoluteSize;
- const name = (element as GuiObject).Name;
-
- print(`[CALC_ASPECT_RATIO](${name}): ${sizes.X / sizes.Y}`);
- } else {
- error(`[CALC_ASPECT_RATIO]: Passed invalid argument. GuiObject expected, got ${typeOf(element)}`)
- }
-}
diff --git a/src/helpers/ExpandableComponent.ts b/src/helpers/ExpandableComponent.ts
deleted file mode 100644
index 0700bac..0000000
--- a/src/helpers/ExpandableComponent.ts
+++ /dev/null
@@ -1,109 +0,0 @@
-import React, { ForwardedRef, InstanceProps, ReactChild, ReactNode } from "@rbxts/react";
-import Object from "@rbxts/object-utils";
-
-import { BindingVariants as BindingVariantsUtils, flat, ReactProps } from "../utils";
-
-/** @deprecated import from `../utils`, not from here */
-export type BindingVariants = BindingVariantsUtils
-
-type PropBuilder = (userProps: BindingVariantsUtils
, context: C) => InstanceProps
-type ChildrenBuilder
= (userProps: BindingVariantsUtils
, context: C) => ReactNode[]
-type ContextBuilder
= (userProps: BindingVariantsUtils
) => C
-
-/**
- * Expandable component
- *
- * Generics:
- * - I: instance
- * - P: user props
- * - C: context (passed in builders)
- */
-export default class ExpandableComponent {
- private propsBuilders: PropBuilder
[];
- private childrenBuilders: ChildrenBuilder
[];
- private contextBuilders: ContextBuilder
[];
-
- constructor(
- propsBuilders: PropBuilder
[] = [],
- childrenBuilders: ChildrenBuilder
[] = [],
- contextBuilders: ContextBuilder
[] = [],
- ) {
- this.propsBuilders = propsBuilders;
- this.childrenBuilders = childrenBuilders;
- this.contextBuilders = contextBuilders;
- }
-
- expandContext(
- builder: ContextBuilder,
- ): ExpandableComponent {
- return new ExpandableComponent(
- this.propsBuilders,
- this.childrenBuilders,
- [...this.contextBuilders, builder] as ContextBuilder
[],
- );
- }
-
- expand(
- propBuilder?: PropBuilder,
- childrenBuilder?: ChildrenBuilder
,
- ): ExpandableComponent {
- return new ExpandableComponent(
- [...this.propsBuilders, propBuilder] as PropBuilder[],
- [...this.childrenBuilders, childrenBuilder] as ChildrenBuilder
[],
- this.contextBuilders,
- );
- }
-
- build(elementType: string) {
- return React.forwardRef((userProps: BindingVariantsUtils
>, ref) => {
- const context = this.buildContext(userProps);
- const props = this.buildProps(userProps, context, ref);
- const children = this.buildChildren(userProps, context);
-
- return React.createElement(elementType, props, ...children);
- });
- }
-
- private buildContext(userProps: BindingVariantsUtils
>): C {
- return Object.assign(
- {},
- ...this.contextBuilders
- .map((build) => build(userProps)),
- );
- }
-
- private buildProps(userProps: BindingVariantsUtils
>, context: C, ref: ForwardedRef): InstanceProps {
- const builtProps: InstanceProps[] = [];
-
- for (const build of this.propsBuilders) {
- const props = build(userProps, context);
- if (props !== undefined) {
- builtProps.push(props);
- }
- }
-
- return Object.assign(
- Object.assign(
- {},
- ...builtProps,
- ),
- {
- Event: userProps.event,
- Change: userProps.change,
- Tag: userProps.tag,
- ref: ref,
- },
- userProps.overrideRoblox as object,
- );
- }
-
- private buildChildren(userProps: BindingVariantsUtils>, context: C): React.ReactNode[] {
- const children = flat(
- this.childrenBuilders
- .map((build) => build(userProps, context).filterUndefined()),
- );
- if (userProps.children !== undefined) children.push(userProps.children as ReactChild);
-
- return children;
- }
-}
diff --git a/src/helpers/Gradient.tsx b/src/helpers/Gradient.tsx
deleted file mode 100644
index 6dd1d7a..0000000
--- a/src/helpers/Gradient.tsx
+++ /dev/null
@@ -1,64 +0,0 @@
-import React, { Binding } from "@rbxts/react";
-
-import { ColorOrHex, resolveColor3 } from "../utils";
-
-import { BindingOrValue, getBindingValue, mapBinding } from "@rbxts/pretty-react-hooks";
-
-export type Gradient = Array | Array | ColorSequence
-
-export function createColorSequence(value: Gradient): ColorSequence {
- if (typeIs(value, "ColorSequence")) {
- return value as ColorSequence;
- } else if (typeIs(value[0], "ColorSequenceKeypoint")) {
- return new ColorSequence(value as Array);
- } else {
- if (value.size() === 1) value = [value[0], value[0]];
-
- const keypointsCount = value.size();
- const step = 1 / (keypointsCount - 1);
-
- const seq: Array = [];
- let j = 0;
- for (let i = 0; i <= 1; i += step) {
- seq.push(new ColorSequenceKeypoint(
- i,
- getBindingValue(resolveColor3(value[j] as ColorOrHex)) ?? new Color3(),
- ));
- j++;
- }
-
- return new ColorSequence(seq);
- }
-}
-
-export type GradientElementProps = {
- color?: BindingOrValue
- rotation?: BindingOrValue
-}
-
-export function getBaseColor(color: BindingOrValue): Binding | undefined {
- if (typeIs(color, "nil")) return;
-
- return mapBinding(
- color,
- (value) =>
- typeIs(value, "string") || typeIs(value, "Color3") || typeIs(value, "nil")
- ? getBindingValue(resolveColor3(value))! // regular color
- : Color3.fromHex("#FFFFFF"), // gradient
- );
-}
-
-export function GradientElement(props: GradientElementProps) {
- const color = getBindingValue(props.color);
-
- return (
- !typeIs(color, "string") && !typeIs(color, "Color3") && !typeIs(color, "nil")
- // if not single color, make gradient
- ? , createColorSequence)}
- Rotation={props.rotation}
- />
- : <>>
- );
-}
diff --git a/src/helpers/TextComponent.ts b/src/helpers/TextComponent.ts
deleted file mode 100644
index 9dfefb0..0000000
--- a/src/helpers/TextComponent.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-import BaseComponent from "./BaseComponent";
-
-import { ColorOrHex, resolveColor3 } from "../utils";
-import { mapBinding } from "@rbxts/pretty-react-hooks";
-
-import type { InferEnumNames, InstanceEvent } from "@rbxts/react";
-
-export type TextComponentInstance = TextLabel | TextButton | TextBox
-export type TextComponentProps = {
- text?: string,
- textColor?: ColorOrHex
-
- textSize?: number | "AUTO"
-
- font?: Enum.Font | Font
- richText?: boolean
-
- textAlign?: Enum.TextXAlignment
- verticalTextAlign?: Enum.TextYAlignment
-
- /** @deprecated use `textAlign` (WILL BE REMOVED IN NEXT MAJOR VERSION!) */
- align?: Enum.TextXAlignment
- /** @deprecated use `verticalTextAlign` (WILL BE REMOVED IN NEXT MAJOR VERSION!) */
- verticalAlign?: Enum.TextYAlignment
-
- event?: InstanceEvent
-}
-
-export default BaseComponent
- .expand(
- (props) => ({
- Text: props.text,
- TextSize: mapBinding(
- props.textSize,
- (size) =>
- typeIs(size, "number")
- ? size
- : 0,
- ),
- TextScaled: mapBinding(
- props.textSize,
- (size) => size === "AUTO",
- ),
- TextColor3: resolveColor3(props.textColor),
-
- FontFace: mapBinding(
- props.font,
- (font) =>
- typeIs(font, "nil")
- ? Font.fromEnum(Enum.Font.Legacy)
- : typeIs(font, "Font")
- ? font // font
- : typeIs(font, "string")
- ? Font.fromEnum(Enum.Font[font as InferEnumNames]) // font enum key
- : Font.fromEnum(font), // font enum
- ),
- RichText: props.richText,
-
- TextXAlignment: props.textAlign ?? props.align,
- TextYAlignment: props.verticalTextAlign ?? props.verticalAlign,
- }),
- );
diff --git a/src/helpers/index.ts b/src/helpers/index.ts
deleted file mode 100644
index 2ef6369..0000000
--- a/src/helpers/index.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { calculateAspectRatio } from "./CalculateAspectRatio";
-
-import ExpandableComponent from "./ExpandableComponent";
-
-import BaseComponent from "./BaseComponent";
-import TextComponent from "./TextComponent";
-
-export { calculateAspectRatio }
-export { ExpandableComponent, BaseComponent, TextComponent };
-export * as Gradient from "./Gradient";
diff --git a/src/index.ts b/src/index.ts
deleted file mode 100644
index 5aa37d8..0000000
--- a/src/index.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-export { Button, ButtonComponent } from "./components/Button";
-export { CanvasGroup } from "./components/CanvasGroup";
-export { Frame } from "./components/Frame";
-export { ScrollingFrame } from "./components/ScrollingFrame";
-export { Image, ImageRect, ImageProps, ImageComponent } from "./components/Image";
-export { Text } from "./components/Text";
-export { TextBox, TextBoxComponent } from "./components/TextBox";
-
-export { GridLayout } from "./components/GridLayout";
-export { ListLayout } from "./components/ListLayout";
-
-export * from "./utils";
-export * as Helpers from "./helpers";
diff --git a/src/init.luau b/src/init.luau
new file mode 100644
index 0000000..6cf4348
--- /dev/null
+++ b/src/init.luau
@@ -0,0 +1,5 @@
+return {
+ hello = function()
+ print("Hello world, from better-react-components!")
+ end,
+}
diff --git a/src/stories/App.ts b/src/stories/App.ts
deleted file mode 100644
index 5cdd42c..0000000
--- a/src/stories/App.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import React from "@rbxts/react";
-
-import { Frame } from ".."; // @rbxts/better-react-components
-
-declare const _G: Record;
-_G.__DEV__ = true;
-
-export function App(props: { children: React.ReactNode }) {
- return React.createElement(
- Frame,
- { size: UDim2.fromScale(1, 1), noBackground: true },
- props.children,
- );
-}
diff --git a/src/stories/Frame.story.luau b/src/stories/Frame.story.luau
new file mode 100644
index 0000000..d97e228
--- /dev/null
+++ b/src/stories/Frame.story.luau
@@ -0,0 +1,39 @@
+local Packages = game:GetService("ReplicatedStorage").Packages
+local DevPackages = game:GetService("ReplicatedStorage").DevPackages
+
+local React = require(Packages.react)
+local ReactRoblox = require(Packages["react-roblox"])
+local UILabs = require(DevPackages["ui-labs"])
+
+local Frame = require(script.Parent.Parent.Components.Frame)
+
+local story = {
+ react = React,
+ reactRoblox = ReactRoblox,
+ controls = {
+ AnchorPoint = UILabs.EnumList({
+ TopLeft = "tl",
+ TopCenter = "t",
+ TopRight = "tr",
+ MiddleLeft = "ml",
+ MiddleCenter = "m",
+ MiddleRight = "mr",
+ BottomLeft = "bl",
+ BottomCenter = "b",
+ BottomRight = "br",
+ }, "MiddleCenter"),
+ BackgroundColor = Color3.fromHex("#FF0000"),
+ CornerRadius = 0
+ },
+ story = function(props)
+ return React.createElement(Frame, {
+ AnchorPoint = props.controls.AnchorPoint,
+ Position = UDim2.new(0.5, 0, 0.5, 0),
+ Size = UDim2.new(0.5, 0, 0.5, 0),
+ BackgroundColor = props.controls.BackgroundColor,
+ -- CornerRadius = props.controls.CornerRadius
+ })
+ end,
+}
+
+return story
diff --git a/src/stories/basics/1_helloworld.story.tsx b/src/stories/basics/1_helloworld.story.tsx
deleted file mode 100644
index 0da1176..0000000
--- a/src/stories/basics/1_helloworld.story.tsx
+++ /dev/null
@@ -1,26 +0,0 @@
-import React from "@rbxts/react";
-
-import { Text } from "../.."; // @rbxts/better-react-components
-import { App } from "../App";
-
-import { hoarcekat } from "@rbxts/pretty-react-hooks";
-import { CatppuccinLatte } from "../utils";
-
-export = hoarcekat(() => {
- return (
-
-
-
- );
-});
diff --git a/src/stories/basics/2_padding.story.tsx b/src/stories/basics/2_padding.story.tsx
deleted file mode 100644
index 7e209ae..0000000
--- a/src/stories/basics/2_padding.story.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-import React from "@rbxts/react";
-
-import { AnchorPoints, Frame, Text } from "../.."; // @rbxts/better-react-components
-
-import { hoarcekat } from "@rbxts/pretty-react-hooks";
-import { App } from "../App";
-
-export = hoarcekat(() => {
- return (
-
-
-
-
-
-
-
- );
-});
diff --git a/src/stories/basics/3_cornerRadius.story.tsx b/src/stories/basics/3_cornerRadius.story.tsx
deleted file mode 100644
index 25ff5f1..0000000
--- a/src/stories/basics/3_cornerRadius.story.tsx
+++ /dev/null
@@ -1,20 +0,0 @@
-import React from "@rbxts/react";
-
-import { AnchorPoints, Frame } from "../.."; // @rbxts/better-react-components
-import { hoarcekat } from "@rbxts/pretty-react-hooks";
-import { App } from "../App";
-
-export = hoarcekat(() => {
- return (
-
-
-
- );
-});
diff --git a/src/stories/basics/5_flexItem.story.tsx b/src/stories/basics/5_flexItem.story.tsx
deleted file mode 100644
index b371551..0000000
--- a/src/stories/basics/5_flexItem.story.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-import React, { useBinding } from "@rbxts/react";
-
-import { Frame, Helpers, ListLayout } from "../../index"; // @rbxts/better-react-components
-import { hoarcekat } from "@rbxts/pretty-react-hooks";
-import { App } from "../App";
-
-// const { calculateAspectRatio } = Helpers;
-
-export = hoarcekat(() => {
- return (
-
-
-
-
-
-
-
-
- );
-})
diff --git a/src/stories/examples/sidebar.story.tsx b/src/stories/examples/sidebar.story.tsx
deleted file mode 100644
index d749c09..0000000
--- a/src/stories/examples/sidebar.story.tsx
+++ /dev/null
@@ -1,67 +0,0 @@
-import React from "@rbxts/react";
-
-import { AnchorPoints, Button, Frame, ListLayout } from "../.."; // @rbxts/better-react-components
-import { App } from "../App";
-
-import { hoarcekat } from "@rbxts/pretty-react-hooks";
-import { CatppuccinLatte } from "../utils";
-
-function CoolButton(props: { text: string, onClick: () => void }) {
- return (
-
- );
-}
-
-export = hoarcekat(() => {
- return (
-
-
-
-
- print("Clicked on button #1")}
- />
-
- print("Clicked on button #2")}
- />
-
- print("Clicked on button #3")}
- />
-
-
- );
-});
diff --git a/src/stories/examples/textBox.story.tsx b/src/stories/examples/textBox.story.tsx
deleted file mode 100644
index d1ba617..0000000
--- a/src/stories/examples/textBox.story.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import React from "@rbxts/react";
-
-import { hoarcekat } from "@rbxts/pretty-react-hooks";
-
-import { App } from "../App";
-import { AnchorPoints, TextBox } from "../.."; // @rbxts/better-react-components
-import { CatppuccinLatte } from "../utils";
-
-
-export = hoarcekat(() => {
- return (
-
-
-
- );
-});
diff --git a/src/stories/tests/bindings.story.tsx b/src/stories/tests/bindings.story.tsx
deleted file mode 100644
index ec5ce2f..0000000
--- a/src/stories/tests/bindings.story.tsx
+++ /dev/null
@@ -1,62 +0,0 @@
-import React, { useBinding } from "@rbxts/react";
-
-import { Button, Frame, GridLayout, Text } from "../.."; // @rbxts/better-react-components
-
-import { hoarcekat } from "@rbxts/pretty-react-hooks";
-import { CatppuccinLatte } from "../utils";
-
-export = hoarcekat(() => {
- const [count, setCount] = useBinding(0);
-
- return (
-
-
-
-